changeset 10847:f171925d2a2f

Branch merge
author Neale Ferguson <neale@sinenomine.net>
date Mon, 20 Jul 2009 13:07:46 -0400
parents 6a61805c1cb4 (current diff) 7fe254ca5fe8 (diff)
children a2bd8982b64a 375b9564710b
files usr/src/Makefile.lint usr/src/Targetdirs usr/src/cmd/Makefile usr/src/cmd/devfsadm/devfsadm.c usr/src/cmd/fm/modules/common/snmp-trapgen/Makefile usr/src/cmd/init/init.c usr/src/lib/libdevinfo/devinfo_devname.c usr/src/lib/libkmf/libkmf/common/generalop.c usr/src/lib/libproc/common/libproc.h usr/src/lib/smbsrv/libmlsvc/common/eventlog.h usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.h usr/src/tools/elfsign/Makefile usr/src/uts/Makefile.uts usr/src/uts/common/Makefile.files usr/src/uts/common/fs/dev/sdev_nsconfig_mod.c usr/src/uts/common/fs/fsflush.c usr/src/uts/common/nfs/nfs4.h usr/src/uts/common/os/main.c usr/src/uts/common/os/sunpm.c usr/src/uts/common/sys/Makefile usr/src/uts/common/sys/fs/dv_node.h usr/src/uts/common/sys/fs/sdev_node.h usr/src/uts/common/vm/page.h usr/src/uts/common/vm/vm_page.c usr/src/uts/common/vm/vm_pagelist.c usr/src/uts/intel/sdev_nsconfig_mod/Makefile usr/src/uts/sparc/sdev_nsconfig_mod/Makefile
diffstat 350 files changed, 25077 insertions(+), 8995 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/Targetdirs	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/Targetdirs	Mon Jul 20 13:07:46 2009 -0400
@@ -224,8 +224,8 @@
 	/etc/dbus-1 \
 	/etc/dbus-1/system.d \
 	/etc/saf \
-	/etc/sma \
-	/etc/sma/snmp \
+	/etc/net-snmp \
+	/etc/net-snmp/snmp \
 	/lib \
 	/lib/crypto \
 	/lib/inet \
--- a/usr/src/cmd/devfsadm/devfsadm.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/devfsadm/devfsadm.c	Mon Jul 20 13:07:46 2009 -0400
@@ -228,17 +228,12 @@
 	{"dsk", "rdsk", "term", NULL};
 
 /* Devname globals */
-static int devname_debug_msg = 1;
-static nvlist_t *devname_maps = NULL;
-static int devname_first_call = 1;
-static int load_devname_nsmaps = FALSE;
 static int lookup_door_fd = -1;
 static char *lookup_door_path;
 
 static void load_dev_acl(void);
 static void update_drvconf(major_t);
 static void check_reconfig_state(void);
-static void devname_setup_nsmaps(void);
 static int s_stat(const char *, struct stat *);
 
 static int is_blank(char *);
@@ -745,7 +740,7 @@
 		devlinktab_file = DEVLINKTAB_FILE;
 
 		while ((opt = getopt(argc, argv,
-		    "a:Cc:deIi:l:mnp:PR:r:sSt:vV:x:")) != EOF) {
+		    "a:Cc:deIi:l:np:PR:r:sSt:vV:x:")) != EOF) {
 			if (opt == 'I' || opt == 'P' || opt == 'S') {
 				if (public_mode)
 					usage();
@@ -798,9 +793,6 @@
 				/* specify an alternate module load path */
 				module_dirs = s_strdup(optarg);
 				break;
-			case 'm':
-				load_devname_nsmaps = TRUE;
-				break;
 			case 'n':
 				/* prevent driver loading and deferred attach */
 				load_attach_drv = FALSE;
@@ -909,12 +901,6 @@
 			devfsadm_exit(0);
 			/*NOTREACHED*/
 		}
-
-		if (load_devname_nsmaps == TRUE) {
-			devname_setup_nsmaps();
-			devfsadm_exit(0);
-			/*NOTREACHED*/
-		}
 	}
 
 
@@ -1339,8 +1325,6 @@
 	/* pass down the door name to kernel for door_ki_open */
 	if (devname_kcall(MODDEVNAME_LOOKUPDOOR, (void *)door_file) != 0)
 		err_print(DEVNAME_CONTACT_FAILED, strerror(errno));
-	else
-		devname_setup_nsmaps();
 
 	vprint(CHATTY_MID, "%spausing\n", fcn);
 	for (;;) {
@@ -8430,25 +8414,8 @@
 devname_kcall(int subcmd, void *args)
 {
 	int error = 0;
-	char *nvlbuf = NULL;
-	size_t nvlsize;
 
 	switch (subcmd) {
-	case MODDEVNAME_NSMAPS:
-		error = nvlist_pack((nvlist_t *)args, &nvlbuf, &nvlsize, 0, 0);
-		if (error) {
-			err_print("packing MODDEVNAME_NSMAPS failed\n");
-			break;
-		}
-		error = modctl(MODDEVNAME, subcmd, nvlbuf, nvlsize);
-		if (error) {
-			vprint(INFO_MID, "modctl(MODDEVNAME, "
-			    "MODDEVNAME_NSMAPS) failed - %s\n",
-			    strerror(errno));
-		}
-		free(nvlbuf);
-		nvlist_free(args);
-		break;
 	case MODDEVNAME_LOOKUPDOOR:
 		error = modctl(MODDEVNAME, subcmd, (uintptr_t)args);
 		if (error) {
@@ -8464,93 +8431,6 @@
 	return (error);
 }
 
-static void
-devname_setup_nsmaps(void)
-{
-	int error = 0;
-
-	if (devname_first_call) {
-		devname_first_call = 0;
-	}
-
-	error = di_devname_get_mapinfo(DEVNAME_MASTER_MAP, &devname_maps);
-
-	if (error) {
-		vprint(DEVNAME_MID, "devname_setup_nsmaps: non-existing/empty"
-		    "%s\n", DEVNAME_MASTER_MAP);
-	} else {
-		di_devname_print_mapinfo(devname_maps);
-
-		/* pass down the existing map names to kernel */
-		(void) devname_kcall(MODDEVNAME_NSMAPS, (void *)devname_maps);
-	}
-}
-
-static void
-devname_ns_services(uint8_t cmd, char *key, char *map)
-{
-	nvlist_t *nvl = NULL;
-	int32_t	error = 0;
-	sdev_door_res_t res;
-
-	vprint(DEVNAME_MID, "devname_ns_services: cmd %d key %s map %s\n",
-	    cmd, key, map);
-
-	switch (cmd) {
-	case DEVFSADMD_NS_LOOKUP:
-		vprint(DEVNAME_MID, "calling di_devname_get_mapent\n");
-		error = di_devname_get_mapent(key, map, &nvl);
-		if (nvl == NULL) {
-			error = DEVFSADM_NS_FAILED;
-			goto done;
-		}
-
-		if (error) {
-			nvlist_free(nvl);
-			goto done;
-		}
-
-		if (devname_debug_msg)
-			di_devname_print_mapinfo(nvl);
-
-		vprint(DEVNAME_MID, "calling di_devname_action_on_key for %d\n",
-		    cmd);
-		error = di_devname_action_on_key(nvl, cmd, key, (void *)&res);
-		nvlist_free(nvl);
-		break;
-	case DEVFSADMD_NS_READDIR:
-		vprint(DEVNAME_MID, "calling di_devname_get_mapinfo for cmd %d"
-		    "\n", cmd);
-		error = di_devname_get_mapinfo(map, &nvl);
-		if (nvl == NULL) {
-			error = DEVFSADM_NS_FAILED;
-			goto done;
-		}
-
-		if (error) {
-			nvlist_free(nvl);
-			goto done;
-		}
-
-		if (devname_debug_msg)
-			di_devname_print_mapinfo(nvl);
-
-		vprint(DEVNAME_MID, "calling di_devname_action_on_key\n");
-		error = di_devname_action_on_key(nvl, cmd, key, (void *)&res);
-		nvlist_free(nvl);
-		break;
-	default:
-		error = DEVFSADM_RUN_NOTSUP;
-		break;
-	}
-
-done:
-	vprint(DEVNAME_MID, "error %d\n", error);
-	res.devfsadm_error = error;
-	(void) door_return((char *)&res, sizeof (struct sdev_door_res),
-	    NULL, 0);
-}
-
 /* ARGSUSED */
 static void
 devname_lookup_handler(void *cookie, char *argp, size_t arg_size,
@@ -8560,7 +8440,6 @@
 	door_cred_t dcred;
 	struct dca_impl	dci;
 	uint8_t	cmd;
-	char *ns_map, *ns_name;
 	sdev_door_res_t res;
 	sdev_door_arg_t *args;
 
@@ -8582,19 +8461,6 @@
 
 	vprint(DEVNAME_MID, "devname_lookup_handler: cmd %d\n", cmd);
 	switch (cmd) {
-	case DEVFSADMD_NS_LOOKUP:
-	case DEVFSADMD_NS_READDIR:
-		ns_name = s_strdup(args->ns_hdl.ns_name);
-		ns_map = s_strdup(args->ns_hdl.ns_map);
-
-		vprint(DEVNAME_MID, " ns_name %s ns_map %s\n", ns_name, ns_map);
-		if (ns_name == NULL || ns_map == NULL) {
-			error = DEVFSADM_RUN_INVALID;
-			goto done;
-		}
-
-		devname_ns_services(cmd, ns_name, ns_map);
-		return;
 	case DEVFSADMD_RUN_ALL:
 		/*
 		 * run "devfsadm"
--- a/usr/src/cmd/devfsadm/devfsadm.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/devfsadm/devfsadm.h	Mon Jul 20 13:07:46 2009 -0400
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _DEVFSADM_H
 #define	_DEVFSADM_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <libdevinfo.h>
 #include <sys/devinfo_impl.h>
@@ -96,9 +94,6 @@
 #define	DEVFSADM_SERVICE_DOOR	"/etc/sysevent/devfsadm_event_channel"
 #define	DEVNAME_LOOKUP_DOOR	".devname_lookup_door"
 
-/* /dev device name binding rule locations */
-#define	DEVNAME_MASTER_MAP	"/etc/dev/devname_master"
-
 /* File of reserved devnames */
 #define	ENUMERATE_RESERVED "/etc/dev/reserved_devnames"
 
--- a/usr/src/cmd/devfsadm/devfsadm_impl.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/devfsadm/devfsadm_impl.h	Mon Jul 20 13:07:46 2009 -0400
@@ -18,7 +18,7 @@
  *
  * CDDL HEADER END
  *
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -71,7 +71,7 @@
 #include <sys/sysevent/dev.h>
 #include <libzonecfg.h>
 #include <device_info.h>
-#include <sys/fs/sdev_node.h>
+#include <sys/fs/sdev_impl.h>
 #include <sys/syscall.h>
 #include <rpcsvc/ypclnt.h>
 #include <sys/sysevent/eventdefs.h>
--- a/usr/src/cmd/drd/drd.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/drd/drd.c	Mon Jul 20 13:07:46 2009 -0400
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * sun4v DR daemon
  */
@@ -384,11 +382,19 @@
 		break;
 
 	case DRCTL_MEM_CONFIG_REQUEST:
+		(*drd_backend->mem_config_request)(rsrcs, nrsrc);
+		break;
+
 	case DRCTL_MEM_CONFIG_NOTIFY:
+		(*drd_backend->mem_config_notify)(rsrcs, nrsrc);
+		break;
+
 	case DRCTL_MEM_UNCONFIG_REQUEST:
+		(*drd_backend->mem_unconfig_request)(rsrcs, nrsrc);
+		break;
+
 	case DRCTL_MEM_UNCONFIG_NOTIFY:
-		drd_err("memory DR operations not supported yet");
-		DRD_DOOR_RETURN_ERR();
+		(*drd_backend->mem_unconfig_notify)(rsrcs, nrsrc);
 		break;
 
 	case DRCTL_IO_CONFIG_REQUEST:
--- a/usr/src/cmd/drd/drd.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/drd/drd.h	Mon Jul 20 13:07:46 2009 -0400
@@ -20,15 +20,13 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _DRD_H
 #define	_DRD_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -65,6 +63,10 @@
 	int (*io_config_notify)(drctl_rsrc_t *rsrc, int nrsrc);
 	int (*io_unconfig_request)(drctl_rsrc_t *rsrc, int nrsrc);
 	int (*io_unconfig_notify)(drctl_rsrc_t *rsrc, int nrsrc);
+	int (*mem_config_request)(drctl_rsrc_t *rsrcs, int nrsrc);
+	int (*mem_config_notify)(drctl_rsrc_t *rsrcs, int nrsrc);
+	int (*mem_unconfig_request)(drctl_rsrc_t *rsrcs, int nrsrc);
+	int (*mem_unconfig_notify)(drctl_rsrc_t *rsrcs, int nrsrc);
 } drd_backend_t;
 
 extern drd_backend_t drd_rcm_backend;
--- a/usr/src/cmd/drd/drd_rcm.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/drd/drd_rcm.c	Mon Jul 20 13:07:46 2009 -0400
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * RCM backend for the DR Daemon
  */
@@ -37,6 +35,7 @@
 #include <libnvpair.h>
 #include <librcm.h>
 #include <locale.h>
+#include <assert.h>
 
 #include "drd.h"
 
@@ -53,6 +52,10 @@
 static int drd_rcm_io_config_notify(drctl_rsrc_t *rsrc, int nrsrc);
 static int drd_rcm_io_unconfig_request(drctl_rsrc_t *rsrc, int nrsrc);
 static int drd_rcm_io_unconfig_notify(drctl_rsrc_t *rsrc, int nrsrc);
+static int drd_rcm_mem_config_request(drctl_rsrc_t *rsrcs, int nrsrc);
+static int drd_rcm_mem_config_notify(drctl_rsrc_t *rsrcs, int nrsrc);
+static int drd_rcm_mem_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc);
+static int drd_rcm_mem_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc);
 
 drd_backend_t drd_rcm_backend = {
 	drd_rcm_init,			/* init */
@@ -64,9 +67,17 @@
 	drd_rcm_io_config_request,	/* io_config_request */
 	drd_rcm_io_config_notify,	/* io_config_notify */
 	drd_rcm_io_unconfig_request,	/* io_unconfig_request */
-	drd_rcm_io_unconfig_notify	/* io_unconfig_notify */
+	drd_rcm_io_unconfig_notify,	/* io_unconfig_notify */
+	drd_rcm_mem_config_request,	/* mem_config_request */
+	drd_rcm_mem_config_notify,	/* mem_config_notify */
+	drd_rcm_mem_unconfig_request,	/* mem_unconfig_request */
+	drd_rcm_mem_unconfig_notify	/* mem_unconfig_notify */
 };
 
+typedef int (*rcm_op_t)(rcm_handle_t *, char *, uint_t, nvlist_t *,
+	rcm_info_t **);
+
+#define	RCM_MEM_ALL		"SUNW_memory"
 #define	RCM_CPU_ALL		"SUNW_cpu"
 #define	RCM_CPU			RCM_CPU_ALL"/cpu"
 #define	RCM_CPU_MAX_LEN		(32)
@@ -423,7 +434,7 @@
 	if (rv != RCM_SUCCESS) {
 		drd_dbg("RCM call failed: %d", rv);
 		/*
-		 * Since the capcity change was blocked, we
+		 * Since the capacity change was blocked, we
 		 * mark all CPUs as blocked. It is up to the
 		 * user to reframe the query so that it can
 		 * succeed.
@@ -1198,3 +1209,225 @@
 
 	return (table);
 }
+
+static void
+dump_mem_rsrc_list(char *prefix, drctl_rsrc_t *rsrcs, int nrsrc)
+{
+	int	idx;
+	char	*errstr;
+
+	/* just return if not debugging */
+	if (drd_debug == 0)
+		return;
+
+	if (prefix)
+		drd_dbg("%s", prefix);
+
+	for (idx = 0; idx < nrsrc; idx++) {
+
+		/* get a pointer to the error string */
+		errstr = (char *)(uintptr_t)rsrcs[idx].offset;
+
+		drd_dbg("  mem[%d]: addr=0x%llx, size=0x%llx"
+		    " status=%d, errstr='%s'", idx,
+		    rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size,
+		    rsrcs[idx].status, (errstr != NULL) ? errstr : "");
+	}
+}
+
+static int
+drd_rcm_mem_op(rcm_op_t op, uint64_t change)
+{
+	int		rv = -1;
+	int		pgsize;
+	long		oldpages;
+	long		newpages;
+	nvlist_t	*nvl = NULL;
+	rcm_info_t	*rinfo;
+
+	/* allocate an nvlist for the RCM call */
+	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
+		goto done;
+
+	if ((pgsize = sysconf(_SC_PAGE_SIZE)) == -1 ||
+	    (newpages = sysconf(_SC_PHYS_PAGES)) == -1)
+		goto done;
+
+	/*
+	 * If this is a notify add, the capacity change
+	 * was positive and the current page count reflects
+	 * the new capacity level.
+	 *
+	 * If this is a request del, the capacity change
+	 * is negative and the current page count will
+	 * reflect the old capacity level.
+	 */
+	assert(change % pgsize == 0);
+	if (change > 0) {
+		oldpages = newpages - (long)(change / pgsize);
+	} else {
+		assert(newpages >= change / pgsize);
+		oldpages = newpages;
+		newpages = oldpages + (long)(change / pgsize);
+	}
+
+	drd_dbg("oldpages=%lld newpages=%lld delta=%lld",
+	    oldpages, newpages, newpages - oldpages);
+
+	/* setup the nvlist for the RCM call */
+	if (nvlist_add_string(nvl, "state", "capacity") != 0 ||
+	    nvlist_add_int32(nvl, "page_size", pgsize) != 0 ||
+	    nvlist_add_int32(nvl, "old_pages", oldpages) != 0 ||
+	    nvlist_add_int32(nvl, "new_pages", newpages) != 0) {
+		goto done;
+	}
+
+	rv = (*op)(rcm_hdl, RCM_MEM_ALL, 0, nvl, &rinfo);
+	rv = (rv == RCM_SUCCESS) ? 0 : -1;
+
+done:
+	s_nvfree(nvl);
+
+	return (rv);
+}
+
+/*
+ * RCM clients can interpose only on removal of resources.
+ */
+static int
+drd_rcm_mem_config_request(drctl_rsrc_t *rsrcs, int nrsrc)
+{
+	int	idx;
+
+	drd_dbg("drd_rcm_mem_config_request...");
+
+	if ((rsrcs == NULL) || (nrsrc == 0))
+		return (0);
+	dump_mem_rsrc_list(NULL, rsrcs, nrsrc);
+
+	/*
+	 * There is no RCM operation to request the addition
+	 * of resources. So, by definition, the operation for
+	 * all the memory is allowed.
+	 */
+	for (idx = 0; idx < nrsrc; idx++)
+		rsrcs[idx].status = DRCTL_STATUS_ALLOW;
+
+	dump_mem_rsrc_list("returning:", rsrcs, nrsrc);
+
+	return (0);
+}
+
+static int
+drd_rcm_mem_config_notify(drctl_rsrc_t *rsrcs, int nrsrc)
+{
+	int		idx;
+	int		rv = -1;
+	uint64_t	change = 0;
+
+	drd_dbg("drd_rcm_mem_config_notify...");
+
+	if ((rsrcs == NULL) || (nrsrc == 0)) {
+		drd_err("mem_config_notify: mem list empty");
+		goto done;
+	}
+	dump_mem_rsrc_list(NULL, rsrcs, nrsrc);
+
+	for (idx = 0; idx < nrsrc; idx++) {
+		if (rsrcs[idx].status == DRCTL_STATUS_CONFIG_SUCCESS)
+			change += rsrcs[idx].res_mem_size;
+		drd_dbg("  idx=%d addr=0x%llx size=0x%llx",
+		    idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size);
+	}
+
+	rv = drd_rcm_mem_op(rcm_notify_capacity_change, change);
+done:
+	return (rv);
+}
+
+static int
+drd_rcm_mem_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc)
+{
+	int		rv = -1;
+	int		idx;
+	uint64_t	change = 0;
+
+	drd_dbg("drd_rcm_del_mem_request...");
+
+	if ((rsrcs == NULL) || (nrsrc == 0)) {
+		drd_err("mem_unconfig_request: mem list empty");
+		goto done;
+	}
+	dump_mem_rsrc_list(NULL, rsrcs, nrsrc);
+
+	for (idx = 0; idx < nrsrc; idx++) {
+		drd_dbg("  idx=%d addr=0x%llx size=0x%llx",
+		    idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size);
+		change += rsrcs[idx].res_mem_size;
+	}
+
+	rv = drd_rcm_mem_op(rcm_request_capacity_change, -change);
+
+	if (rv != RCM_SUCCESS) {
+		drd_dbg("RCM call failed: %d", rv);
+		/*
+		 * Since the capacity change was blocked, we
+		 * mark all mblocks as blocked. It is up to the
+		 * user to reframe the query so that it can
+		 * succeed.
+		 */
+		for (idx = 0; idx < nrsrc; idx++) {
+			rsrcs[idx].status = DRCTL_STATUS_DENY;
+		}
+
+		/* tack on message to first resource */
+		rsrcs[0].offset = (uintptr_t)strdup("unable to remove "
+		    "specified amount of memory");
+		drd_dbg("  unable to remove specified amount of memory");
+	} else {
+		for (idx = 0; idx < nrsrc; idx++)
+			rsrcs[idx].status = DRCTL_STATUS_ALLOW;
+		rv = 0;
+	}
+
+done:
+
+	dump_mem_rsrc_list("returning:", rsrcs, nrsrc);
+	return (rv);
+}
+
+static int
+drd_rcm_mem_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc)
+{
+	int		idx;
+	int		rv = -1;
+	uint64_t	change = 0;
+
+	drd_dbg("drd_rcm_mem_unconfig_notify...");
+
+	if ((rsrcs == NULL) || (nrsrc == 0)) {
+		drd_err("unconfig_mem_notify: mem list empty");
+		goto done;
+	}
+	dump_mem_rsrc_list(NULL, rsrcs, nrsrc);
+
+	/*
+	 * Filter out the memory that was configured.
+	 *
+	 * We need to notify RCM about a memory capacity change
+	 * only if the memory unconfigure request wasn't successful
+	 * because if both the RCM capacity delete request and the
+	 * memory unconfigure succeed, this notify would give a
+	 * memory capacity identical to the delete request.
+	 */
+	for (idx = 0; idx < nrsrc; idx++) {
+		if (rsrcs[idx].status != DRCTL_STATUS_CONFIG_SUCCESS)
+			change += rsrcs[idx].res_mem_size;
+		drd_dbg("  idx=%d addr=0x%llx size=0x%llx",
+		    idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size);
+	}
+
+	rv = drd_rcm_mem_op(rcm_notify_capacity_change, change);
+done:
+	return (rv);
+}
--- a/usr/src/cmd/fm/dicts/PCI.dict	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/fm/dicts/PCI.dict	Mon Jul 20 13:07:46 2009 -0400
@@ -1,5 +1,5 @@
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # CDDL HEADER START
@@ -21,8 +21,6 @@
 #
 # CDDL HEADER END
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
 # DO NOT EDIT -- this file is generated by the Event Registry.
 #
 
@@ -44,3 +42,5 @@
 fault.io.pci.device-interr-corr=13
 fault.io.pci.bus-linkerr-deg fault.io.pci.device-interr-deg=14
 fault.io.pci.device-interr-deg=15
+fault.io.pci.fw_corrupt=16
+fault.io.pci.fw_mismatch=17
--- a/usr/src/cmd/fm/dicts/PCI.po	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/fm/dicts/PCI.po	Mon Jul 20 13:07:46 2009 -0400
@@ -1,5 +1,5 @@
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # CDDL HEADER START
@@ -21,8 +21,6 @@
 #
 # CDDL HEADER END
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
 # DO NOT EDIT -- this file is generated by the Event Registry.
 #
 #
@@ -281,3 +279,35 @@
 msgstr "Degraded services provided by the device instances associated with this fault\n"
 msgid "PCI-8000-G3.action"
 msgstr "Schedule a repair procedure to replace the affected device.  Use fmadm faulty to identify the device or contact Sun for support.\n"
+#
+# code: PCI-8000-HR
+# keys: fault.io.pci.fw_corrupt
+#
+msgid "PCI-8000-HR.type"
+msgstr "Fault"
+msgid "PCI-8000-HR.severity"
+msgstr "Major"
+msgid "PCI-8000-HR.description"
+msgstr "A firmware corruption was detected for a PCI device.\n  Refer to %s for more information."
+msgid "PCI-8000-HR.response"
+msgstr "One or more device instances may be disabled.\n"
+msgid "PCI-8000-HR.impact"
+msgstr "Degraded services provided by the device instances associated with this fault.\n"
+msgid "PCI-8000-HR.action"
+msgstr "Use fmadm faulty to identify the device and then update the firmware to the latest version or schedule a repair procedure to replace the affected device. Contact Sun support for further information.\n"
+#
+# code: PCI-8000-J4
+# keys: fault.io.pci.fw_mismatch
+#
+msgid "PCI-8000-J4.type"
+msgstr "Fault"
+msgid "PCI-8000-J4.severity"
+msgstr "Major"
+msgid "PCI-8000-J4.description"
+msgstr "A firmware version mismatch was detected for a PCI device.\n  Refer to %s for more information."
+msgid "PCI-8000-J4.response"
+msgstr "One or more device instances may be disabled.\n"
+msgid "PCI-8000-J4.impact"
+msgstr "Degraded services provided by the device instances associated with this fault.\n"
+msgid "PCI-8000-J4.action"
+msgstr "Use fmadm faulty to identify the device and then update the firmware to the latest version. Contact Sun support for further information.\n"
--- a/usr/src/cmd/fm/dicts/PCIEX.dict	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/fm/dicts/PCIEX.dict	Mon Jul 20 13:07:46 2009 -0400
@@ -1,5 +1,5 @@
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # CDDL HEADER START
@@ -21,8 +21,6 @@
 #
 # CDDL HEADER END
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
 # DO NOT EDIT -- this file is generated by the Event Registry.
 #
 
@@ -50,3 +48,5 @@
 fault.io.pci.bus-linkerr-unaf fault.io.pciex.device-interr-unaf=19
 fault.io.pciex.device-interr-unaf=20
 fault.io.pciex.device-interr-deg=21
+fault.io.pciex.fw_corrupt=22
+fault.io.pciex.fw_mismatch=23
--- a/usr/src/cmd/fm/dicts/PCIEX.po	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/fm/dicts/PCIEX.po	Mon Jul 20 13:07:46 2009 -0400
@@ -1,5 +1,5 @@
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # CDDL HEADER START
@@ -21,8 +21,6 @@
 #
 # CDDL HEADER END
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
 # DO NOT EDIT -- this file is generated by the Event Registry.
 #
 #
@@ -120,7 +118,7 @@
 msgid "PCIEX-8000-5Y.impact"
 msgstr "Loss of services provided by the device instances associated with this fault\n"
 msgid "PCIEX-8000-5Y.action"
-msgstr "Ensure that the latest drivers and patches are installed. Otherwise schedule a repair procedure to replace the affected device(s).  Use fmadm faulty to identify the devices or contact Sun for support.\n"
+msgstr "Ensure that the latest drivers and patches are installed. Otherwise schedule a repair procedure to replace the affected device(s).  Use fmadm faulty to identify the devices or contact Sun for support."
 #
 # code: PCIEX-8000-6D
 # keys: fault.io.pci.device-invreq fault.io.pciex.device-interr
@@ -377,3 +375,35 @@
 msgstr "Degraded services provided by the device instances associated with this fault\n"
 msgid "PCIEX-8000-ND.action"
 msgstr "Schedule a repair procedure to replace the affected device.  Use fmadm faulty to identify the device or contact Sun for support.\n"
+#
+# code: PCIEX-8000-PY
+# keys: fault.io.pciex.fw_corrupt
+#
+msgid "PCIEX-8000-PY.type"
+msgstr "Fault"
+msgid "PCIEX-8000-PY.severity"
+msgstr "Major"
+msgid "PCIEX-8000-PY.description"
+msgstr "A firmware corruption was detected for a PCIEX device.\n  Refer to %s for more information."
+msgid "PCIEX-8000-PY.response"
+msgstr "One or more device instances may be disabled.\n"
+msgid "PCIEX-8000-PY.impact"
+msgstr "Degraded services provided by the device instances associated with this fault.\n"
+msgid "PCIEX-8000-PY.action"
+msgstr "Use fmadm faulty to identify the device and then update the firmware to the latest version or schedule a repair procedure to replace the affected device. Contact Sun support for further information.\n"
+#
+# code: PCIEX-8000-Q3
+# keys: fault.io.pciex.fw_mismatch
+#
+msgid "PCIEX-8000-Q3.type"
+msgstr "Fault"
+msgid "PCIEX-8000-Q3.severity"
+msgstr "Major"
+msgid "PCIEX-8000-Q3.description"
+msgstr "A firmware version mismatch was detected for a PCIEX device.\n  Refer to %s for more information."
+msgid "PCIEX-8000-Q3.response"
+msgstr "One or more device instances may be disabled.\n"
+msgid "PCIEX-8000-Q3.impact"
+msgstr "Degraded services provided by the device instances associated with this fault.\n"
+msgid "PCIEX-8000-Q3.action"
+msgstr "Use fmadm faulty to identify the device and then update the firmware to the latest version. Contact Sun support for further information.\n"
--- a/usr/src/cmd/fm/eversholt/files/common/pci.esc	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/fm/eversholt/files/common/pci.esc	Mon Jul 20 13:07:46 2009 -0400
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #pragma dictionary "PCI"
 
 #include <fm/topo_hc.h>
@@ -98,6 +96,10 @@
 
 event fault.io.pci.device-noresp@PCIFN, FITrate=PCI_DEV_FIT;
 
+event fault.io.pci.fw_corrupt@PCIFN, FITrate=PCI_DEV_FIT, retire=0;
+
+event fault.io.pci.fw_mismatch@PCIFN, FITrate=PCI_DEV_FIT, retire=0;
+
 /*
  * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  * A faulty hostbridge may cause:
@@ -328,6 +330,8 @@
 
 event ereport.io.pcix.oor@PCIFN{within(5s)};
 event ereport.io.pcix.unex-sc@PCIFN{within(5s)};
+event ereport.io.device.fw_corrupt@PCIFN{within(5s)};
+event ereport.io.device.fw_mismatch@PCIFN{within(5s)};
 event ereport.io.service.lost@PCIFN{within(5s)};
 event ereport.io.service.degraded@PCIFN{within(5s)};
 event ereport.io.service.unaffected@PCIFN{within(5s)};
@@ -359,6 +363,20 @@
     error.io.pcix.tx-oor@PCI_NOT_HB,
     error.io.pcix.rx-unex-sc@PCI_NOT_HB;
 
+prop fault.io.pci.fw_corrupt@PCIFN {IS_LEAF} (1)->
+    ereport.io.device.fw_corrupt@PCIFN;
+
+prop fault.io.pci.fw_corrupt@PCIFN {IS_LEAF} (0)->
+    ereport.io.service.lost@PCIFN,
+    ereport.io.service.degraded@PCIFN;
+
+prop fault.io.pci.fw_mismatch@PCIFN {IS_LEAF} (1)->
+    ereport.io.device.fw_mismatch@PCIFN;
+
+prop fault.io.pci.fw_mismatch@PCIFN {IS_LEAF} (0)->
+    ereport.io.service.lost@PCIFN,
+    ereport.io.service.degraded@PCIFN;
+
 prop fault.io.pci.device-invreq@pcibus/pcidev[fromdev]/pcifn {FD_IS_LEAF} (0)->
     error.io.pci.badreq-drw-u@PCI_NOT_HB,
     error.io.pci.badreq-pw-u@PCI_NOT_HB;
--- a/usr/src/cmd/fm/eversholt/files/common/pciex.esc	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/fm/eversholt/files/common/pciex.esc	Mon Jul 20 13:07:46 2009 -0400
@@ -110,6 +110,9 @@
 /*
  * define faults
  */
+event fault.io.pciex.fw_corrupt@PCIEXFN, FITrate=PCIEX_DEV_FIT, retire=0;
+event fault.io.pciex.fw_mismatch@PCIEXFN, FITrate=PCIEX_DEV_FIT, retire=0;
+
 event fault.io.pciex.device-interr@PCIEXFN, FITrate=PCIEX_DEV_FIT;
 
 event fault.io.pciex.device-interr-deg@PCIEXFN, FITrate=PCIEX_DEV_FIT, retire=0;
@@ -409,6 +412,8 @@
 event ereport.io.pciex.dl.rto@PCIEXFN/PCIEXFN{within(5s)};
 event ereport.io.pciex.dl.rnr@PCIEXFN/PCIEXFN{within(5s)};
 event ereport.io.pciex.pl.re@PCIEXFN/PCIEXFN{within(5s)};
+event ereport.io.device.fw_corrupt@PCIEXFN{within(5s)};
+event ereport.io.device.fw_mismatch@PCIEXFN{within(5s)};
 
 prop fault.io.pciex.device-noresp@PCIEXFN { IS_LF(PCIEXFN) } (1)->
     error.io.pciex.flt-nr-u@PCIEXFN;
@@ -512,6 +517,20 @@
     error.io.pciex.flt-mtlp-u@PCIEXFN,
     error.io.pciex.fatlink@PCIEXFN;
 
+prop fault.io.pciex.fw_corrupt@PCIEXFN { IS_LF(PCIEXFN) } (1)->
+    ereport.io.device.fw_corrupt@PCIEXFN;
+
+prop fault.io.pciex.fw_corrupt@PCIEXFN { IS_LF(PCIEXFN) } (0)->
+    ereport.io.service.lost@PCIEXFN,
+    ereport.io.service.degraded@PCIEXFN;
+
+prop fault.io.pciex.fw_mismatch@PCIEXFN { IS_LF(PCIEXFN) } (1)->
+    ereport.io.device.fw_mismatch@PCIEXFN;
+
+prop fault.io.pciex.fw_mismatch@PCIEXFN { IS_LF(PCIEXFN) } (0)->
+    ereport.io.service.lost@PCIEXFN,
+    ereport.io.service.degraded@PCIEXFN;
+
 /*
  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  * A faulty PCI Express downstream switch port may cause
--- a/usr/src/cmd/fm/modules/common/snmp-trapgen/Makefile	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/fm/modules/common/snmp-trapgen/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -28,10 +28,10 @@
 MODULE = snmp-trapgen
 CLASS = common
 SRCS = snmp.c
-SMASNMPCONFS = fmd-trapgen.conf
+NETSNMPCONFS = fmd-trapgen.conf
 
-ROOTSMASNMPDIR = $(ROOT)/etc/sma/snmp
-ROOTSMASNMPCONFS = $(SMASNMPCONFS:%=$(ROOTSMASNMPDIR)/%)
+ROOTNETSNMPDIR = $(ROOT)/etc/net-snmp/snmp
+ROOTNETSNMPCONFS = $(NETSNMPCONFS:%=$(ROOTNETSNMPDIR)/%)
 
 include ../../Makefile.plugin
 
@@ -42,9 +42,9 @@
 LINTFLAGS += -L$(ROOT)/usr/lib/fm
 LDLIBS += $(SNMPLIBS) -lfmd_msg
 
-$(ROOTSMASNMPCONFS) := FILEMODE = 0600
+$(ROOTNETSNMPCONFS) := FILEMODE = 0600
 
-$(ROOTSMASNMPDIR)/%: %
+$(ROOTNETSNMPDIR)/%: %
 	$(INS.file)
 
-install: $(ROOTSMASNMPCONFS)
+install: $(ROOTNETSNMPCONFS)
--- a/usr/src/cmd/fm/modules/common/snmp-trapgen/fmd-trapgen.conf	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/fm/modules/common/snmp-trapgen/fmd-trapgen.conf	Mon Jul 20 13:07:46 2009 -0400
@@ -20,15 +20,14 @@
 #
 
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
 #
 
 #
 # Supplemental configuration for the snmp-trapgen FMA module.  Normal
 # configuration of this module should be made via trap sink directives
-# in /etc/sma/snmp/snmpd.conf, not in this file.  See snmpd(4) and
+# in /etc/net-snmp/snmp/snmpd.conf, not in this file.  See snmpd(4) and
 # snmp_config(4).
 #
--- a/usr/src/cmd/fs.d/dev/mount.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/fs.d/dev/mount.c	Mon Jul 20 13:07:46 2009 -0400
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <limits.h>
 #include <stdio.h>
@@ -38,7 +36,7 @@
 #include <sys/stat.h>
 #include <sys/mount.h>
 #include <sys/mntent.h>
-#include <sys/fs/sdev_node.h>
+#include <sys/fs/sdev_impl.h>
 
 
 #define	READFLAG_RO	1
--- a/usr/src/cmd/idmap/idmap/idmap.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/idmap/idmap/idmap.c	Mon Jul 20 13:07:46 2009 -0400
@@ -34,7 +34,6 @@
 #include <sys/varargs.h>
 #include "idmap_engine.h"
 #include "idmap_priv.h"
-#include "idmap_impl.h"
 
 /* Initialization values for pids/rids: */
 
--- a/usr/src/cmd/idmap/idmapd/Makefile	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/idmap/idmapd/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -25,8 +25,21 @@
 
 PROG =		idmapd
 MANIFEST =	idmap.xml
-SERVEROBJS =	idmapd.o init.o dbutils.o rpc_svc.o server.o adutils.o\
-	idmap_config.o nldaputils.o
+SERVEROBJS =				\
+	directory_provider_builtin.o	\
+	directory_provider_nsswitch.o	\
+	directory_provider_ad.o		\
+	directory_server.o		\
+	adutils.o			\
+	dbutils.o			\
+	idmap_config.o			\
+	idmapd.o			\
+	init.o				\
+	nldaputils.o			\
+	rpc_svc.o			\
+	server.o			\
+	wksids.o
+
 SERVERSRCS =	$(SERVEROBJS:%.o=%.c)
 OBJS =		$(SERVEROBJS)
 SRCS =		$(SERVERSRCS)
@@ -42,8 +55,17 @@
 
 include ../../Makefile.cmd
 
+TEXT_DOMAIN =	SUNW_OST_OSLIB
+XGETTEXT =	$(GNUXGETTEXT)
+XGETFLAGS =	--foreign-user --strict -n -E --width=72 \
+		--omit-header --keyword=directoryError:2 \
+		--language=C --force-po
+
+C99MODE = $(C99_ENABLE)
 POFILE =	$(PROG)_all.po
 
+RPC_MSGOUT_OPT = -DRPC_MSGOUT=idmap_rpc_msgout
+
 ROOTMANIFESTDIR = $(ROOTSVCSYSTEM)
 $(ROOTMANIFEST) := FILEMODE= 444
 
@@ -55,7 +77,18 @@
 $(POFILE) := CPPFLAGS += $(INCS)
 
 CFLAGS += -v
-LDLIBS += -lsecdb -lsocket -lnsl -lidmap -lscf -lsldap -lldap -luuid -ladutils
+LDLIBS += -lsecdb \
+	-lsocket \
+	-lnsl \
+	-lidmap \
+	-lscf \
+	-lsldap \
+	-lldap \
+	-luuid \
+	-ladutils \
+	-lumem
+
+rpc_svc.o := CFLAGS += $(RPC_MSGOUT_OPT)
 
 $(PROG) := MAPFILES = $(MAPFILE.INT) $(MAPFILE.NGB)
 $(PROG) := LDFLAGS += $(MAPFILES:%=-M%)
@@ -65,7 +98,7 @@
 OWNER = root
 GROUP = sys
 
-lint_SRCS := CPPFLAGS += $(INCS) -D_REENTRANT
+lint_SRCS := CPPFLAGS += $(INCS) -D_REENTRANT $(RPC_MSGOUT_OPT)
 lint := LDLIBS += $(SQLITELINT)
 
 .KEEP_STATE:
--- a/usr/src/cmd/idmap/idmapd/adutils.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/idmap/idmapd/adutils.c	Mon Jul 20 13:07:46 2009 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -235,7 +235,7 @@
 	char *sid, rid_t rid, int sid_type, char *unixname)
 {
 	char *domain;
-	int err1, err2;
+	int err1;
 
 	assert(dn != NULL);
 
@@ -252,8 +252,7 @@
 
 	if (q->edomain != NULL) {
 		/* Check that this is the domain that we were looking for */
-		if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER,
-		    U8_UNICODE_LATEST, &err2) != 0 || err2 != 0)
+		if (!domain_eq(q->edomain, domain))
 			goto out;
 	}
 
--- a/usr/src/cmd/idmap/idmapd/dbutils.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/idmap/idmapd/dbutils.c	Mon Jul 20 13:07:46 2009 -0400
@@ -74,8 +74,6 @@
 
 #define	IS_EPHEMERAL(pid)	(pid > INT32_MAX && pid != SENTINEL_PID)
 
-#define	LOCALRID_MIN	1000
-
 
 typedef enum init_db_option {
 	FAIL_IF_CORRUPT = 0,
@@ -83,21 +81,6 @@
 } init_db_option_t;
 
 /*
- * Data structure to store well-known SIDs and
- * associated mappings (if any)
- */
-typedef struct wksids_table {
-	const char	*sidprefix;
-	uint32_t	rid;
-	const char	*domain;
-	const char	*winname;
-	int		is_wuser;
-	uid_t		pid;
-	int		is_user;
-	int		direction;
-} wksids_table_t;
-
-/*
  * Thread specific data to hold the database handles so that the
  * databases are not opened and closed for every request. It also
  * contains the sqlite busy handler structure.
@@ -131,12 +114,6 @@
 
 static pthread_key_t	idmap_tsd_key;
 
-static const wksids_table_t *find_wksid_by_pid(uid_t pid, int is_user);
-static const wksids_table_t *find_wksid_by_sid(const char *sid, int rid,
-    int type);
-static const wksids_table_t *find_wksid_by_name(const char *name,
-    const char *domain, int type);
-
 void
 idmap_tsd_destroy(void *key)
 {
@@ -1203,179 +1180,6 @@
 	rule->direction = direction;
 }
 
-
-/*
- * Table for well-known SIDs.
- *
- * Background:
- *
- * Some of the well-known principals are stored under:
- * cn=WellKnown Security Principals, cn=Configuration, dc=<forestRootDomain>
- * They belong to objectClass "foreignSecurityPrincipal". They don't have
- * "samAccountName" nor "userPrincipalName" attributes. Their names are
- * available in "cn" and "name" attributes. Some of these principals have a
- * second entry under CN=ForeignSecurityPrincipals,dc=<forestRootDomain> and
- * these duplicate entries have the stringified SID in the "name" and "cn"
- * attributes instead of the actual name.
- *
- * Those of the form S-1-5-32-X are Builtin groups and are stored in the
- * cn=builtin container (except, Power Users which is not stored in AD)
- *
- * These principals are and will remain constant. Therefore doing AD lookups
- * provides no benefit. Also, using hard-coded table (and thus avoiding AD
- * lookup) improves performance and avoids additional complexity in the
- * adutils.c code. Moreover these SIDs can be used when no Active Directory
- * is available (such as the CIFS server's "workgroup" mode).
- *
- * Notes:
- * 1. Currently we don't support localization of well-known SID names,
- * unlike Windows.
- *
- * 2. Other well-known SIDs i.e. S-1-5-<domain>-<w-k RID> are not stored
- * here. AD does have normal user/group objects for these objects and
- * can be looked up using the existing AD lookup code.
- *
- * 3. See comments above lookup_wksids_sid2pid() for more information
- * on how we lookup the wksids table.
- *
- * 4. If this table contains two entries for a particular Windows name,
- * so as to offer both UID and GID mappings, the preferred mapping (the
- * one that matches Windows usage) must be listed first.  That is the
- * entry that will be used when the caller specifies IDMAP_POSIXID
- * ("don't care") as the target.
- *
- * Entries here come from KB243330, MS-LSAT, and
- * http://technet.microsoft.com/en-us/library/cc755854.aspx
- * http://technet.microsoft.com/en-us/library/cc755925.aspx
- * http://msdn.microsoft.com/en-us/library/cc980032(PROT.10).aspx
- */
-static wksids_table_t wksids[] = {
-	/* S-1-0	Null Authority */
-	{"S-1-0", 0, "", "Nobody", 1, SENTINEL_PID, -1, 1},
-
-	/* S-1-1	World Authority */
-	{"S-1-1", 0, "", "Everyone", 0, SENTINEL_PID, -1, -1},
-
-	/* S-1-2	Local Authority */
-	{"S-1-2", 0, "", "Local", 0, SENTINEL_PID, -1, -1},
-	{"S-1-2", 1, "", "Console Logon", 0, SENTINEL_PID, -1, -1},
-
-	/* S-1-3	Creator Authority */
-	{"S-1-3", 0, "", "Creator Owner", 1, IDMAP_WK_CREATOR_OWNER_UID, 1, 0},
-	{"S-1-3", 1, "", "Creator Group", 0, IDMAP_WK_CREATOR_GROUP_GID, 0, 0},
-	{"S-1-3", 2, "", "Creator Owner Server", 1, SENTINEL_PID, -1, -1},
-	{"S-1-3", 3, "", "Creator Group Server", 0, SENTINEL_PID, -1, 1},
-	{"S-1-3", 4, "", "Owner Rights", 0, SENTINEL_PID, -1, -1},
-
-	/* S-1-4	Non-unique Authority */
-
-	/* S-1-5	NT Authority */
-	{"S-1-5", 1, "", "Dialup", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5", 2, "", "Network", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5", 3, "", "Batch", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5", 4, "", "Interactive", 0, SENTINEL_PID, -1, -1},
-	/* S-1-5-5-X-Y	Logon Session */
-	{"S-1-5", 6, "", "Service", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5", 7, "", "Anonymous Logon", 0, GID_NOBODY, 0, 0},
-	{"S-1-5", 7, "", "Anonymous Logon", 0, UID_NOBODY, 1, 0},
-	{"S-1-5", 8, "", "Proxy", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5", 9, "", "Enterprise Domain Controllers", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5", 10, "", "Self", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5", 11, "", "Authenticated Users", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5", 12, "", "Restricted", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5", 13, "", "Terminal Server Users", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5", 14, "", "Remote Interactive Logon", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5", 15, "", "This Organization", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5", 17, "", "IUSR", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5", 18, "", "Local System", 0, IDMAP_WK_LOCAL_SYSTEM_GID, 0, 0},
-	{"S-1-5", 19, "", "Local Service", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5", 20, "", "Network Service", 0, SENTINEL_PID, -1, -1},
-
-	/* S-1-5-21-<domain>	Machine-local definitions */
-	{NULL, 498, NULL, "Enterprise Read-only Domain Controllers", 0,
-	    SENTINEL_PID, -1, -1},
-	{NULL, 500, NULL, "Administrator", 1, SENTINEL_PID, 1, -1},
-	{NULL, 501, NULL, "Guest", 1, SENTINEL_PID, 1, -1},
-	{NULL, 502, NULL, "KRBTGT", 1, SENTINEL_PID, 1, -1},
-	{NULL, 512, NULL, "Domain Admins", 0, SENTINEL_PID, -1, -1},
-	{NULL, 513, NULL, "Domain Users", 0, SENTINEL_PID, -1, -1},
-	{NULL, 514, NULL, "Domain Guests", 0, SENTINEL_PID, -1, -1},
-	{NULL, 515, NULL, "Domain Computers", 0, SENTINEL_PID, -1, -1},
-	{NULL, 516, NULL, "Domain Controllers", 0, SENTINEL_PID, -1, -1},
-	{NULL, 517, NULL, "Cert Publishers", 0, SENTINEL_PID, -1, -1},
-	{NULL, 518, NULL, "Schema Admins", 0, SENTINEL_PID, -1, -1},
-	{NULL, 519, NULL, "Enterprise Admins", 0, SENTINEL_PID, -1, -1},
-	{NULL, 520, NULL, "Global Policy Creator Owners", 0,
-	    SENTINEL_PID, -1, -1},
-	{NULL, 533, NULL, "RAS and IAS Servers", 0, SENTINEL_PID, -1, -1},
-
-	/* S-1-5-32	BUILTIN */
-	{"S-1-5-32", 544, "BUILTIN", "Administrators", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 545, "BUILTIN", "Users", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 546, "BUILTIN", "Guests", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 547, "BUILTIN", "Power Users", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 548, "BUILTIN", "Account Operators", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 549, "BUILTIN", "Server Operators", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 550, "BUILTIN", "Print Operators", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 551, "BUILTIN", "Backup Operators", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 552, "BUILTIN", "Replicator", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 554, "BUILTIN", "Pre-Windows 2000 Compatible Access", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 555, "BUILTIN", "Remote Desktop Users", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 556, "BUILTIN", "Network Configuration Operators", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 557, "BUILTIN", "Incoming Forest Trust Builders", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 558, "BUILTIN", "Performance Monitor Users", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 559, "BUILTIN", "Performance Log Users", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 560, "BUILTIN", "Windows Authorization Access Group", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 561, "BUILTIN", "Terminal Server License Servers", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 562, "BUILTIN", "Distributed COM Users", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 568, "BUILTIN", "IIS_IUSRS", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 569, "BUILTIN", "Cryptographic Operators", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 573, "BUILTIN", "Event Log Readers", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5-32", 574, "BUILTIN", "Certificate Service DCOM Access", 0,
-	    SENTINEL_PID, -1, -1},
-
-	{"S-1-5", 33, "", "Write Restricted", 0, SENTINEL_PID, -1, -1},
-
-	/* S-1-5-64	NT Authority */
-	{"S-1-5-64", 10, "", "NTLM Authentication", 0, SENTINEL_PID, -1, -1},
-	{"S-1-5-64", 14, "", "SChannel Authentication", 0,
-	    SENTINEL_PID, -1, -1},
-	{"S-1-5-64", 21, "", "Digest Authentication", 0, SENTINEL_PID, -1, -1},
-
-	/* S-1-5-80-a-b-c-d NT Service */
-
-	{"S-1-5", 1000, "", "Other Organization", 0, SENTINEL_PID, -1, -1},
-
-	/* S-1-7 Internet$ */
-
-	/*
-	 * S-1-16	Mandatory Label
-	 * S-1-16-0	Untrusted Mandatory Level
-	 * S-1-16-4096	Low Mandatory Level
-	 * S-1-16-8192	Medium Mandatory Level
-	 * S-1-16-8448	Medium Plus Mandatory Level
-	 * S-1-16-12288	High Mandatory Level
-	 * S-1-16-16384	System Mandatory Level
-	 * S-1-16-20480	Protected Process Mandatory Level
-	 */
-};
-
 /*
  * Lookup well-known SIDs table either by winname or by SID.
  *
@@ -2634,8 +2438,8 @@
 		return (IDMAP_ERR_NOMAPPING);
 
 	/* Skip 1000 UIDs */
-	if (is_user && req->id1.idmap_id_u.uid >
-	    (INT32_MAX - LOCALRID_MIN))
+	if (is_user &&
+	    req->id1.idmap_id_u.uid + LOCALRID_UID_MIN > LOCALRID_UID_MAX)
 		return (IDMAP_ERR_NOMAPPING);
 
 	RDLOCK_CONFIG();
@@ -2652,8 +2456,8 @@
 	}
 	UNLOCK_CONFIG();
 	res->id.idmap_id_u.sid.rid =
-	    (is_user) ? req->id1.idmap_id_u.uid + LOCALRID_MIN :
-	    req->id1.idmap_id_u.gid + INT32_MAX + 1;
+	    (is_user) ? req->id1.idmap_id_u.uid + LOCALRID_UID_MIN :
+	    req->id1.idmap_id_u.gid + LOCALRID_GID_MIN;
 	res->direction = IDMAP_DIRECTION_BI;
 	if (res->id.idtype == IDMAP_SID)
 		res->id.idtype = is_user ? IDMAP_USID : IDMAP_GSID;
@@ -2702,24 +2506,24 @@
 
 	switch (res->id.idtype) {
 	case IDMAP_UID:
-		if (rid > INT32_MAX || rid < LOCALRID_MIN)
+		if (rid < LOCALRID_UID_MIN || rid > LOCALRID_UID_MAX)
 			return (IDMAP_ERR_ARG);
-		res->id.idmap_id_u.uid = rid - LOCALRID_MIN;
+		res->id.idmap_id_u.uid = rid - LOCALRID_UID_MIN;
 		break;
 	case IDMAP_GID:
-		if (rid <= INT32_MAX)
+		if (rid < LOCALRID_GID_MIN)
 			return (IDMAP_ERR_ARG);
-		res->id.idmap_id_u.gid = rid - INT32_MAX - 1;
+		res->id.idmap_id_u.gid = rid - LOCALRID_GID_MIN;
 		break;
 	case IDMAP_POSIXID:
-		if (rid > INT32_MAX) {
-			res->id.idmap_id_u.gid = rid - INT32_MAX - 1;
+		if (rid >= LOCALRID_GID_MIN) {
+			res->id.idmap_id_u.gid = rid - LOCALRID_GID_MIN;
 			res->id.idtype = IDMAP_GID;
-		} else if (rid < LOCALRID_MIN) {
-			return (IDMAP_ERR_ARG);
+		} else if (rid >= LOCALRID_UID_MIN) {
+			res->id.idmap_id_u.uid = rid - LOCALRID_UID_MIN;
+			res->id.idtype = IDMAP_UID;
 		} else {
-			res->id.idmap_id_u.uid = rid - LOCALRID_MIN;
-			res->id.idtype = IDMAP_UID;
+			return (IDMAP_ERR_ARG);
 		}
 		break;
 	default:
@@ -4851,161 +4655,3 @@
 	result.ids.ids_val = res;
 	return (ad_lookup_batch(state, &batch, &result));
 }
-
-/*
- * Find a wksid entry for the specified Windows name and domain, of the
- * specified type.
- *
- * Ignore entries intended only for U2W use.
- */
-static
-const
-wksids_table_t *
-find_wksid_by_name(const char *name, const char *domain, int type)
-{
-	int i;
-	char *myhostname;
-	int len;
-
-	RDLOCK_CONFIG();
-	len = strlen(_idmapdstate.hostname) + 1;
-	myhostname = alloca(len);
-	(void) memcpy(myhostname, _idmapdstate.hostname, len);
-	UNLOCK_CONFIG();
-
-	for (i = 0; i < NELEM(wksids); i++) {
-		/* Check to see if this entry yields the desired type */
-		switch (type) {
-		case IDMAP_UID:
-			if (wksids[i].is_user == 0)
-				continue;
-			break;
-		case IDMAP_GID:
-			if (wksids[i].is_user == 1)
-				continue;
-			break;
-		case IDMAP_POSIXID:
-			break;
-		default:
-			assert(FALSE);
-		}
-
-		if (strcasecmp(wksids[i].winname, name) != 0)
-			continue;
-
-		if (!EMPTY_STRING(domain)) {
-			const char *dom;
-
-			if (wksids[i].domain != NULL) {
-				dom = wksids[i].domain;
-			} else {
-				dom = myhostname;
-			}
-			if (strcasecmp(dom, domain) != 0) {
-				/* this is not our domain */
-				continue;
-			}
-		}
-
-		/*
-		 * We have a Windows name, so ignore entries that are only
-		 * usable for mapping UNIX->Windows.  (Note:  the current
-		 * table does not have any such entries.)
-		 */
-		if (wksids[i].direction == IDMAP_DIRECTION_U2W)
-			continue;
-
-		return (&wksids[i]);
-	}
-
-	return (NULL);
-}
-
-/*
- * Find a wksid entry for the specified SID, of the specified type.
- *
- * Ignore entries intended only for U2W use.
- */
-static
-const
-wksids_table_t *
-find_wksid_by_sid(const char *sid, int rid, int type)
-{
-	int i;
-	char *mymachinesid;
-	int len;
-
-	RDLOCK_CONFIG();
-	len = strlen(_idmapdstate.cfg->pgcfg.machine_sid) + 1;
-	mymachinesid = alloca(len);
-	(void) memcpy(mymachinesid, _idmapdstate.cfg->pgcfg.machine_sid, len);
-	UNLOCK_CONFIG();
-
-	for (i = 0; i < NELEM(wksids); i++) {
-		int sidcmp;
-
-		/* Check to see if this entry yields the desired type */
-		switch (type) {
-		case IDMAP_UID:
-			if (wksids[i].is_user == 0)
-				continue;
-			break;
-		case IDMAP_GID:
-			if (wksids[i].is_user == 1)
-				continue;
-			break;
-		case IDMAP_POSIXID:
-			break;
-		default:
-			assert(FALSE);
-		}
-
-		if (wksids[i].sidprefix != NULL) {
-			sidcmp = strcasecmp(wksids[i].sidprefix, sid);
-		} else {
-			sidcmp = strcasecmp(mymachinesid, sid);
-		}
-
-		if (sidcmp != 0)
-			continue;
-		if (wksids[i].rid != rid)
-			continue;
-
-		/*
-		 * We have a SID, so ignore entries that are only usable
-		 * for mapping UNIX->Windows.  (Note:  the current table
-		 * does not have any such entries.)
-		 */
-		if (wksids[i].direction == IDMAP_DIRECTION_U2W)
-			continue;
-
-		return (&wksids[i]);
-	}
-
-	return (NULL);
-}
-
-/*
- * Find a wksid entry for the specified pid, of the specified type.
- * Ignore entries that do not specify U2W mappings.
- */
-static
-const
-wksids_table_t *
-find_wksid_by_pid(uid_t pid, int is_user)
-{
-	int i;
-
-	if (pid == SENTINEL_PID)
-		return (NULL);
-
-	for (i = 0; i < NELEM(wksids); i++) {
-		if (wksids[i].pid == pid &&
-		    wksids[i].is_user == is_user &&
-		    (wksids[i].direction == IDMAP_DIRECTION_BI ||
-		    wksids[i].direction == IDMAP_DIRECTION_U2W)) {
-			return (&wksids[i]);
-		}
-	}
-	return (NULL);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/idmap/idmapd/directory_provider_ad.c	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,590 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Retrieve directory information for Active Directory users.
+ */
+
+#include <ldap.h>
+#include <lber.h>
+#include <pwd.h>
+#include <malloc.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <libadutils.h>
+#include <note.h>
+#include <assert.h>
+#include "directory.h"
+#include "directory_private.h"
+#include "idmapd.h"
+#include <rpcsvc/idmap_prot.h>
+#include "directory_server_impl.h"
+#include "miscutils.h"
+
+/*
+ * Information required by the function that handles the callback from LDAP
+ * when responses are received.
+ */
+struct cbinfo {
+	const char * const *attrs;
+	int nattrs;
+	directory_entry_rpc *entry;
+	const char *domain;
+};
+
+static void directory_provider_ad_cb(LDAP *ld, LDAPMessage **ldapres, int rc,
+    int qid, void *argp);
+static void directory_provider_ad_cb1(LDAP *ld, LDAPMessage *msg,
+    struct cbinfo *cbinfo);
+static directory_error_t bv_list_dav(directory_values_rpc *lvals,
+    struct berval **bv);
+static directory_error_t directory_provider_ad_lookup(
+    directory_entry_rpc *pent, const char * const * attrs, int nattrs,
+    const char *domain, const char *filter);
+static directory_error_t get_domain(LDAP *ld, LDAPMessage *ldapres,
+    char **domain);
+static directory_error_t directory_provider_ad_utils_error(char *func, int rc);
+
+#if	defined(DUMP_VALUES)
+static void dump_bv_list(const char *attr, struct berval **bv);
+#endif
+
+#define	MAX_EXTRA_ATTRS	1	/* sAMAccountName */
+
+/*
+ * Add an entry to a NULL-terminated list, if it's not already there.
+ * Assumes that the list has been allocated large enough for all additions,
+ * and prefilled with NULL.
+ */
+static
+void
+maybe_add_to_list(const char **list, const char *s)
+{
+	for (; *list != NULL; list++) {
+		if (strcaseeq(*list, s))
+			return;
+	}
+	*list = s;
+}
+
+/*
+ * Copy a counted attribute list to a NULL-terminated one.
+ * In the process, examine the requested attributes and augment
+ * the list as required to support any synthesized attributes
+ * requested.
+ */
+static
+const char **
+copy_and_augment_attr_list(char **req_list, int req_list_len)
+{
+	const char **new_list;
+	int i;
+
+	new_list =
+	    calloc(req_list_len + MAX_EXTRA_ATTRS + 1, sizeof (*new_list));
+	if (new_list == NULL)
+		return (NULL);
+
+	(void) memcpy(new_list, req_list, req_list_len * sizeof (char *));
+
+	for (i = 0; i < req_list_len; i++) {
+		const char *a = req_list[i];
+		/*
+		 * Note that you must update MAX_EXTRA_ATTRS above if you
+		 * add to this list.
+		 */
+		if (strcaseeq(a, "x-sun-canonicalName")) {
+			maybe_add_to_list(new_list, "sAMAccountName");
+			continue;
+		}
+		/* None needed for x-sun-provider */
+	}
+
+	return (new_list);
+}
+
+/*
+ * Retrieve information by name.
+ * Called indirectly through the Directory_provider_static structure.
+ */
+static
+directory_error_t
+directory_provider_ad_get(
+    directory_entry_rpc *del,
+    idmap_utf8str_list *ids,
+    char *types,
+    idmap_utf8str_list *attrs)
+{
+	int i;
+	const char **attrs2;
+	directory_error_t de = NULL;
+
+	/*
+	 * If we don't have any AD servers handy, we can't find anything.
+	 */
+	if (_idmapdstate.num_ads < 1) {
+		return (NULL);
+	}
+
+	RDLOCK_CONFIG()
+
+	/* 6835280 spurious lint error if the strlen is in the declaration */
+	int len = strlen(_idmapdstate.cfg->pgcfg.default_domain);
+	char default_domain[len + 1];
+	(void) strcpy(default_domain, _idmapdstate.cfg->pgcfg.default_domain);
+
+	UNLOCK_CONFIG();
+
+	/*
+	 * Turn our counted-array argument into a NULL-terminated array.
+	 * At the same time, add in any attributes that we need to support
+	 * any requested synthesized attributes.
+	 */
+	attrs2 = copy_and_augment_attr_list(attrs->idmap_utf8str_list_val,
+	    attrs->idmap_utf8str_list_len);
+	if (attrs2 == NULL)
+		goto nomem;
+
+	for (i = 0; i < ids->idmap_utf8str_list_len; i++) {
+		char *vw[3];
+		int type;
+
+		/*
+		 * Extract the type for this particular ID.
+		 * Advance to the next type, if it's there, else keep
+		 * using this type until we run out of IDs.
+		 */
+		type = *types;
+		if (*(types+1) != '\0')
+			types++;
+
+		/*
+		 * If this entry has already been handled, one way or another,
+		 * skip it.
+		 */
+		if (del[i].status != DIRECTORY_NOT_FOUND)
+			continue;
+
+		char *id = ids->idmap_utf8str_list_val[i];
+
+		/*
+		 * Allow for expanding every character to \xx, plus some
+		 * space for the query syntax.
+		 */
+		int id_len = strlen(id);
+		char filter[1000 + id_len*3];
+
+		if (type == DIRECTORY_ID_SID[0]) {
+			/*
+			 * Mildly surprisingly, AD appears to allow searching
+			 * based on text SIDs.  Must be a special case on the
+			 * server end.
+			 */
+			ldap_build_filter(filter, sizeof (filter),
+			    "(objectSid=%v)", NULL, NULL, NULL, id, NULL);
+
+			de = directory_provider_ad_lookup(&del[i], attrs2,
+			    attrs->idmap_utf8str_list_len, NULL, filter);
+			if (de != NULL) {
+				directory_entry_set_error(&del[i], de);
+				de = NULL;
+			}
+		} else {
+			int id_len = strlen(id);
+			char name[id_len + 1];
+			char domain[id_len + 1];
+
+			split_name(name, domain, id);
+
+			vw[0] = name;
+
+			if (streq(domain, "")) {
+				vw[1] = default_domain;
+			} else {
+				vw[1] = domain;
+			}
+
+			if (type == DIRECTORY_ID_USER[0])
+				vw[2] = "user";
+			else if (type == DIRECTORY_ID_GROUP[0])
+				vw[2] = "group";
+			else
+				vw[2] = "*";
+
+			/*
+			 * Try samAccountName.
+			 * Note that here we rely on checking the returned
+			 * distinguishedName to make sure that we found an
+			 * entry from the right domain, because there's no
+			 * attribute we can straightforwardly filter for to
+			 * match domain.
+			 *
+			 * Eventually we should perhaps also try
+			 * userPrincipalName.
+			 */
+			ldap_build_filter(filter, sizeof (filter),
+			    "(&(samAccountName=%v1)(objectClass=%v3))",
+			    NULL, NULL, NULL, NULL, vw);
+
+			de = directory_provider_ad_lookup(&del[i], attrs2,
+			    attrs->idmap_utf8str_list_len, vw[1], filter);
+			if (de != NULL) {
+				directory_entry_set_error(&del[i], de);
+				de = NULL;
+			}
+		}
+	}
+
+	de = NULL;
+
+	goto out;
+
+nomem:
+	de = directory_error("ENOMEM.AD",
+	    "Out of memory during AD lookup", NULL);
+out:
+	free(attrs2);
+	return (de);
+}
+
+/*
+ * Note that attrs is NULL terminated, and that nattrs is the number
+ * of attributes requested by the user... which might be fewer than are
+ * in attrs because of attributes that we need for our own processing.
+ */
+static
+directory_error_t
+directory_provider_ad_lookup(
+    directory_entry_rpc *pent,
+    const char * const * attrs,
+    int nattrs,
+    const char *domain,
+    const char *filter)
+{
+	adutils_ad_t *ad;
+	adutils_rc batchrc;
+	struct cbinfo cbinfo;
+	adutils_query_state_t *qs;
+	int rc;
+
+	/*
+	 * NEEDSWORK:  Should eventually handle other forests.
+	 * NEEDSWORK:  Should eventually handle non-GC attributes.
+	 */
+	ad = _idmapdstate.ads[0];
+
+	/* Stash away information for the callback function. */
+	cbinfo.attrs = attrs;
+	cbinfo.nattrs = nattrs;
+	cbinfo.entry = pent;
+	cbinfo.domain = domain;
+
+	rc = adutils_lookup_batch_start(ad, 1, directory_provider_ad_cb,
+	    &cbinfo, &qs);
+	if (rc != ADUTILS_SUCCESS) {
+		return (directory_provider_ad_utils_error(
+		    "adutils_lookup_batch_start", rc));
+	}
+
+	rc = adutils_lookup_batch_add(qs, filter, attrs, domain,
+	    NULL, &batchrc);
+	if (rc != ADUTILS_SUCCESS) {
+		adutils_lookup_batch_release(&qs);
+		return (directory_provider_ad_utils_error(
+		    "adutils_lookup_batch_add", rc));
+	}
+
+	rc = adutils_lookup_batch_end(&qs);
+	if (rc != ADUTILS_SUCCESS) {
+		return (directory_provider_ad_utils_error(
+		    "adutils_lookup_batch_end", rc));
+	}
+
+	if (batchrc != ADUTILS_SUCCESS) {
+		/*
+		 * NEEDSWORK:  We're consistently getting -9997 here.
+		 * What does it mean?
+		 */
+		return (NULL);
+	}
+
+	return (NULL);
+}
+
+/*
+ * Callback from the LDAP functions when they get responses.
+ * We don't really need (nor want) asynchronous handling, but it's
+ * what libadutils gives us.
+ */
+static
+void
+directory_provider_ad_cb(
+    LDAP *ld,
+    LDAPMessage **ldapres,
+    int rc,
+    int qid,
+    void *argp)
+{
+	NOTE(ARGUNUSED(rc, qid))
+	struct cbinfo *cbinfo = (struct cbinfo *)argp;
+	LDAPMessage *msg = *ldapres;
+
+	for (msg = ldap_first_entry(ld, msg);
+	    msg != NULL;
+	    msg = ldap_next_entry(ld, msg)) {
+		directory_provider_ad_cb1(ld, msg, cbinfo);
+	}
+}
+
+/*
+ * Process a single entry returned by an LDAP callback.
+ * Note that this performs a function roughly equivalent to the
+ * directory*Populate() functions in the other providers.
+ * Given an LDAP response, populate the directory entry for return to
+ * the caller.  This one differs primarily in that we're working directly
+ * with LDAP, so we don't have to do any attribute translation.
+ */
+static
+void
+directory_provider_ad_cb1(
+    LDAP *ld,
+    LDAPMessage *msg,
+    struct cbinfo *cbinfo)
+{
+	int nattrs = cbinfo->nattrs;
+	const char * const *attrs = cbinfo->attrs;
+	directory_entry_rpc *pent = cbinfo->entry;
+
+	int i;
+	directory_values_rpc *llvals;
+	directory_error_t de;
+	char *domain = NULL;
+
+	/*
+	 * We don't have a way to filter for entries from the right domain
+	 * in the LDAP query, so we check for it here.  Searches based on
+	 * samAccountName might yield results from the wrong domain.
+	 */
+	de = get_domain(ld, msg, &domain);
+	if (de != NULL)
+		goto err;
+
+	if (cbinfo->domain != NULL && !domain_eq(cbinfo->domain, domain))
+		goto out;
+
+	/*
+	 * If we've already found a match, error.
+	 */
+	if (pent->status != DIRECTORY_NOT_FOUND) {
+		de = directory_error("Duplicate.AD",
+		    "Multiple matching entries found", NULL);
+		goto err;
+	}
+
+	llvals = calloc(nattrs, sizeof (directory_values_rpc));
+	if (llvals == NULL)
+		goto nomem;
+
+	pent->directory_entry_rpc_u.attrs.attrs_val = llvals;
+	pent->directory_entry_rpc_u.attrs.attrs_len = nattrs;
+	pent->status = DIRECTORY_FOUND;
+
+	for (i = 0; i < nattrs; i++) {
+		struct berval **bv;
+		const char *a = attrs[i];
+		directory_values_rpc *val = &llvals[i];
+
+		bv = ldap_get_values_len(ld, msg, a);
+#if	defined(DUMP_VALUES)
+		dump_bv_list(attrs[i], bv);
+#endif
+		if (bv != NULL) {
+			de = bv_list_dav(val, bv);
+			ldap_value_free_len(bv);
+			if (de != NULL)
+				goto err;
+		} else if (strcaseeq(a, "x-sun-canonicalName")) {
+			bv = ldap_get_values_len(ld, msg, "sAMAccountName");
+			if (bv != NULL) {
+				int n = ldap_count_values_len(bv);
+				if (n > 0) {
+					char *tmp;
+					(void) asprintf(&tmp, "%.*s@%s",
+					    bv[0]->bv_len, bv[0]->bv_val,
+					    domain);
+					if (tmp == NULL)
+						goto nomem;
+					const char *ctmp = tmp;
+					de = str_list_dav(val, &ctmp, 1);
+					free(tmp);
+					if (de != NULL)
+						goto err;
+				}
+			}
+		} else if (strcaseeq(a, "x-sun-provider")) {
+			const char *provider = "LDAP-AD";
+			de = str_list_dav(val, &provider, 1);
+		}
+	}
+
+	goto out;
+
+nomem:
+	de = directory_error("ENOMEM.users",
+	    "No memory allocating return value for user lookup", NULL);
+
+err:
+	directory_entry_set_error(pent, de);
+	de = NULL;
+
+out:
+	free(domain);
+}
+
+/*
+ * Given a struct berval, populate a directory attribute value (which is a
+ * list of values).
+ * Note that here we populate the DAV with the exact bytes that LDAP returns.
+ * Back over in the client it appends a \0 so that strings are null
+ * terminated.
+ */
+static
+directory_error_t
+bv_list_dav(directory_values_rpc *lvals, struct berval **bv)
+{
+	directory_value_rpc *dav;
+	int n;
+	int i;
+
+	n = ldap_count_values_len(bv);
+
+	dav = calloc(n, sizeof (directory_value_rpc));
+	if (dav == NULL)
+		goto nomem;
+
+	lvals->directory_values_rpc_u.values.values_val = dav;
+	lvals->directory_values_rpc_u.values.values_len = n;
+	lvals->found = TRUE;
+
+	for (i = 0; i < n; i++) {
+		dav[i].directory_value_rpc_val =
+		    memdup(bv[i]->bv_val, bv[i]->bv_len);
+		if (dav[i].directory_value_rpc_val == NULL)
+			goto nomem;
+		dav[i].directory_value_rpc_len = bv[i]->bv_len;
+	}
+
+	return (NULL);
+
+nomem:
+	return (directory_error("ENOMEM.bv_list_dav",
+	    "Insufficient memory copying values"));
+}
+
+#if	defined(DUMP_VALUES)
+static
+void
+dump_bv_list(const char *attr, struct berval **bv)
+{
+	int i;
+
+	if (bv == NULL) {
+		(void) fprintf(stderr, "%s:  (empty)\n", attr);
+		return;
+	}
+	for (i = 0; bv[i] != NULL; i++) {
+		(void) fprintf(stderr, "%s[%d] =\n", attr, i);
+		dump(stderr, "    ", bv[i]->bv_val, bv[i]->bv_len);
+	}
+}
+#endif	/* DUMP_VALUES */
+
+/*
+ * Return the domain associated with the specified entry.
+ */
+static
+directory_error_t
+get_domain(
+    LDAP *ld,
+    LDAPMessage *msg,
+    char **domain)
+{
+	*domain = NULL;
+
+	char *dn = ldap_get_dn(ld, msg);
+	if (dn == NULL) {
+		char buf[100];	/* big enough for any int */
+		char *m;
+		char *s;
+		int err = ldap_get_lderrno(ld, &m, &s);
+		(void) snprintf(buf, sizeof (buf), "%d", err);
+
+		return directory_error("AD.get_domain.ldap_get_dn",
+		    "ldap_get_dn: %1 (%2)\n"
+		    "matched: %3\n"
+		    "error:   %4",
+		    ldap_err2string(err), buf,
+		    m == NULL ? "(null)" : m,
+		    s == NULL ? "(null)" : s,
+		    NULL);
+	}
+
+	*domain = adutils_dn2dns(dn);
+	if (*domain == NULL) {
+		directory_error_t de;
+
+		de = directory_error("Unknown.get_domain.adutils_dn2dns",
+		    "get_domain:  Unexpected error from adutils_dn2dns(%1)",
+		    dn, NULL);
+		free(dn);
+		return (de);
+	}
+	free(dn);
+
+	return (NULL);
+}
+
+/*
+ * Given an error report from libadutils, generate a directory_error_t.
+ */
+static
+directory_error_t
+directory_provider_ad_utils_error(char *func, int rc)
+{
+	char rcstr[100];	/* plenty for any int */
+	char code[100];		/* plenty for any int */
+	(void) snprintf(rcstr, sizeof (rcstr), "%d", rc);
+	(void) snprintf(code, sizeof (code), "ADUTILS.%d", rc);
+
+	return (directory_error(code,
+	    "Error %2 from adutils function %1", func, rcstr, NULL));
+}
+
+struct directory_provider_static directory_provider_ad = {
+	"AD",
+	directory_provider_ad_get,
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/idmap/idmapd/directory_provider_builtin.c	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,319 @@
+/*
+ * 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.
+ */
+
+/*
+ * Retrieve directory information for built-in users and groups
+ */
+
+#include <stdio.h>
+#include <limits.h>
+#include <sys/idmap.h>
+#include <sys/param.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <note.h>
+#include "idmapd.h"
+#include "directory.h"
+#include "directory_private.h"
+#include <rpcsvc/idmap_prot.h>
+#include "directory_server_impl.h"
+#include "miscutils.h"
+#include "sidutil.h"
+
+static directory_error_t sid_dav(directory_values_rpc *lvals,
+    const wksids_table_t *wksid);
+static directory_error_t directory_provider_builtin_populate(
+    directory_entry_rpc *pent, const wksids_table_t *wksid,
+    idmap_utf8str_list *attrs);
+
+/*
+ * Retrieve information by name.
+ * Called indirectly through the directory_provider_static structure.
+ */
+static
+directory_error_t
+directory_provider_builtin_get(
+    directory_entry_rpc *del,
+    idmap_utf8str_list *ids,
+    idmap_utf8str types,
+    idmap_utf8str_list *attrs)
+{
+	int i;
+
+	for (i = 0; i < ids->idmap_utf8str_list_len; i++) {
+		const wksids_table_t *wksid;
+		directory_error_t de;
+		int type;
+
+		/*
+		 * Extract the type for this particular ID.
+		 * Advance to the next type, if it's there, else keep
+		 * using this type until we run out of IDs.
+		 */
+		type = *types;
+		if (*(types+1) != '\0')
+			types++;
+
+		/*
+		 * If this entry has already been handled, one way or another,
+		 * skip it.
+		 */
+		if (del[i].status != DIRECTORY_NOT_FOUND)
+			continue;
+
+		char *id = ids->idmap_utf8str_list_val[i];
+
+		/*
+		 * End-to-end error injection point.
+		 * NEEDSWORK:  should probably eliminate this for production
+		 */
+		if (streq(id, " DEBUG BUILTIN ERROR ")) {
+			directory_entry_set_error(&del[i],
+			    directory_error("Directory_provider_builtin.debug",
+			    "Directory_provider_builtin:  artificial error",
+			    NULL));
+			continue;
+		}
+
+		if (type == DIRECTORY_ID_SID[0])
+			wksid = find_wk_by_sid(id);
+		else {
+			int idmap_id_type;
+			if (type == DIRECTORY_ID_NAME[0])
+				idmap_id_type = IDMAP_POSIXID;
+			else if (type == DIRECTORY_ID_USER[0])
+				idmap_id_type = IDMAP_UID;
+			else if (type == DIRECTORY_ID_GROUP[0])
+				idmap_id_type = IDMAP_GID;
+			else {
+				directory_entry_set_error(&del[i],
+				    directory_error("invalid_arg.id_type",
+				    "Invalid ID type \"%1\"",
+				    types, NULL));
+				continue;
+			}
+
+			int id_len = strlen(id);
+			char name[id_len + 1];
+			char domain[id_len + 1];
+
+			split_name(name, domain, id);
+
+			wksid = find_wksid_by_name(name, domain, idmap_id_type);
+		}
+
+		if (wksid == NULL)
+			continue;
+
+		de = directory_provider_builtin_populate(&del[i], wksid, attrs);
+		if (de != NULL) {
+			directory_entry_set_error(&del[i], de);
+			de = NULL;
+		}
+	}
+
+	return (NULL);
+}
+
+/*
+ * Given a well-known name entry and a list of attributes that were
+ * requested, populate the structure to return to the caller.
+ */
+static
+directory_error_t
+directory_provider_builtin_populate(
+    directory_entry_rpc *pent,
+    const wksids_table_t *wksid,
+    idmap_utf8str_list *attrs)
+{
+	int j;
+	directory_values_rpc *llvals;
+	int nattrs;
+
+	nattrs = attrs->idmap_utf8str_list_len;
+
+	llvals = calloc(nattrs, sizeof (directory_values_rpc));
+	if (llvals == NULL)
+		goto nomem;
+
+	pent->status = DIRECTORY_FOUND;
+	pent->directory_entry_rpc_u.attrs.attrs_val = llvals;
+	pent->directory_entry_rpc_u.attrs.attrs_len = nattrs;
+
+	for (j = 0; j < nattrs; j++) {
+		directory_values_rpc *val;
+		char *a;
+		directory_error_t de;
+
+		/*
+		 * We're going to refer to these a lot, so make a shorthand
+		 * copy.
+		 */
+		a = attrs->idmap_utf8str_list_val[j];
+		val = &llvals[j];
+
+		/*
+		 * Start by assuming no errors and that we don't have
+		 * the information.
+		 */
+		val->found = FALSE;
+		de = NULL;
+
+		if (strcaseeq(a, "uid")) {
+			de = str_list_dav(val, &wksid->winname, 1);
+		} else if (strcaseeq(a, "uidNumber")) {
+			if (wksid->pid != SENTINEL_PID && wksid->is_user) {
+				de = uint_list_dav(val, &wksid->pid, 1);
+			}
+		} else if (strcaseeq(a, "gidNumber")) {
+			if (wksid->pid != SENTINEL_PID && !wksid->is_user) {
+				de = uint_list_dav(val, &wksid->pid, 1);
+			}
+		} else if (strcaseeq(a, "displayName") || strcaseeq(a, "cn")) {
+			de = str_list_dav(val, &wksid->winname, 1);
+		} else if (strcaseeq(a, "distinguishedName")) {
+			char *container;
+			if (wksid->domain == NULL) {
+				container = "Users";
+			} else {
+				container = "Builtin";
+			}
+			RDLOCK_CONFIG();
+			char *dn;
+			(void) asprintf(&dn,
+			    "CN=%s,CN=%s,DC=%s",
+			    wksid->winname, container, _idmapdstate.hostname);
+			UNLOCK_CONFIG();
+			const char *cdn = dn;
+			de = str_list_dav(val, &cdn, 1);
+			free(dn);
+		} else if (strcaseeq(a, "objectClass")) {
+			if (wksid->is_wuser) {
+				static const char *objectClasses[] = {
+					"top",
+					"person",
+					"organizationalPerson",
+					"user",
+				};
+				de = str_list_dav(val, objectClasses,
+				    NELEM(objectClasses));
+			} else {
+				static const char *objectClasses[] = {
+					"top",
+					"group",
+				};
+				de = str_list_dav(val, objectClasses,
+				    NELEM(objectClasses));
+			}
+		} else if (strcaseeq(a, "objectSid")) {
+			de = sid_dav(val, wksid);
+		} else if (strcaseeq(a, "x-sun-canonicalName")) {
+			char *canon;
+
+			if (wksid->domain == NULL) {
+				RDLOCK_CONFIG();
+				(void) asprintf(&canon, "%s@%s",
+				    wksid->winname, _idmapdstate.hostname);
+				UNLOCK_CONFIG();
+			} else if (streq(wksid->domain, "")) {
+				canon = strdup(wksid->winname);
+			} else {
+				(void) asprintf(&canon, "%s@%s",
+				    wksid->winname, wksid->domain);
+			}
+
+			if (canon == NULL)
+				goto nomem;
+			const char *ccanon = canon;
+			de = str_list_dav(val, &ccanon, 1);
+			free(canon);
+		} else if (strcaseeq(a, "x-sun-provider")) {
+			const char *provider = "Builtin";
+			de = str_list_dav(val, &provider, 1);
+		}
+		if (de != NULL)
+			return (de);
+	}
+
+	return (NULL);
+
+nomem:
+	return (directory_error("ENOMEM.users",
+	    "No memory allocating return value for user lookup", NULL));
+}
+
+/*
+ * Given a well-known name structure, generate a binary-format SID.
+ * It's a bit perverse that we must take a text-format SID and turn it into
+ * a binary-format SID, only to have the caller probably turn it back into
+ * text format, but SIDs are carried across LDAP in binary format.
+ */
+static
+directory_error_t
+sid_dav(directory_values_rpc *lvals, const wksids_table_t *wksid)
+{
+	char *text_sid;
+	sid_t *sid;
+	directory_error_t de;
+
+	if (wksid->sidprefix == NULL) {
+		RDLOCK_CONFIG();
+		(void) asprintf(&text_sid, "%s-%d",
+		    _idmapdstate.cfg->pgcfg.machine_sid,
+		    wksid->rid);
+		UNLOCK_CONFIG();
+	} else {
+		(void) asprintf(&text_sid, "%s-%d",
+		    wksid->sidprefix, wksid->rid);
+	}
+
+	if (text_sid == NULL)
+		goto nomem;
+
+	sid = sid_fromstr(text_sid);
+	free(text_sid);
+
+	if (sid == NULL)
+		goto nomem;
+
+	sid_to_le(sid);
+
+	de = bin_list_dav(lvals, sid, 1, sid_len(sid));
+
+	sid_free(sid);
+
+	return (de);
+
+nomem:
+	return (directory_error("ENOMEM.sid_dav",
+	    "No memory allocating SID for user lookup", NULL));
+}
+
+struct directory_provider_static directory_provider_builtin = {
+	"builtin",
+	directory_provider_builtin_get,
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/idmap/idmapd/directory_provider_nsswitch.c	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,472 @@
+/*
+ * 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.
+ */
+
+/*
+ * Retrieve directory information for standard UNIX users/groups.
+ * (NB:  not just from files, but all nsswitch sources.)
+ */
+
+#include <pwd.h>
+#include <grp.h>
+#include <malloc.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <note.h>
+#include <errno.h>
+#include "idmapd.h"
+#include "directory.h"
+#include "directory_private.h"
+#include <rpcsvc/idmap_prot.h>
+#include "directory_server_impl.h"
+#include "miscutils.h"
+#include "sidutil.h"
+
+static directory_error_t machine_sid_dav(directory_values_rpc *lvals,
+    unsigned int rid);
+static directory_error_t directory_provider_nsswitch_populate(
+    directory_entry_rpc *pent, struct passwd *pwd, struct group *grp,
+    idmap_utf8str_list *attrs);
+
+/*
+ * Retrieve information by name.
+ * Called indirectly through the directory_provider_static structure.
+ */
+static
+directory_error_t
+directory_provider_nsswitch_get(
+    directory_entry_rpc *del,
+    idmap_utf8str_list *ids,
+    idmap_utf8str types,
+    idmap_utf8str_list *attrs)
+{
+	int i;
+
+	RDLOCK_CONFIG();
+
+	/* 6835280 spurious lint error if the strlen is in the declaration */
+	int host_name_len = strlen(_idmapdstate.hostname);
+	char my_host_name[host_name_len + 1];
+	(void) strcpy(my_host_name, _idmapdstate.hostname);
+
+	/* We use len later, so this is not merely a workaround for 6835280 */
+	int machine_sid_len = strlen(_idmapdstate.cfg->pgcfg.machine_sid);
+	char my_machine_sid[machine_sid_len + 1];
+	(void) strcpy(my_machine_sid, _idmapdstate.cfg->pgcfg.machine_sid);
+
+	UNLOCK_CONFIG();
+
+	for (i = 0; i < ids->idmap_utf8str_list_len; i++) {
+		struct passwd *pwd = NULL;
+		struct group *grp = NULL;
+		directory_error_t de;
+		int type;
+
+		/*
+		 * Extract the type for this particular ID.
+		 * Advance to the next type, if it's there, else keep
+		 * using this type until we run out of IDs.
+		 */
+		type = *types;
+		if (*(types+1) != '\0')
+			types++;
+
+		/*
+		 * If this entry has already been handled, one way or another,
+		 * skip it.
+		 */
+		if (del[i].status != DIRECTORY_NOT_FOUND)
+			continue;
+
+		char *id = ids->idmap_utf8str_list_val[i];
+
+		if (type == DIRECTORY_ID_SID[0]) {
+			/*
+			 * Is it our SID?
+			 * Check whether the first part matches, then a "-",
+			 * then a single RID.
+			 */
+			if (strncasecmp(id, my_machine_sid, machine_sid_len) !=
+			    0)
+				continue;
+			if (id[machine_sid_len] != '-')
+				continue;
+			char *p;
+			uint32_t rid =
+			    strtoul(id + machine_sid_len + 1, &p, 10);
+			if (*p != '\0')
+				continue;
+
+			if (rid < LOCALRID_UID_MIN) {
+				/* Builtin, not handled here */
+				continue;
+			}
+
+			if (rid <= LOCALRID_UID_MAX) {
+				/* User */
+				errno = 0;
+				pwd = getpwuid(rid - LOCALRID_UID_MIN);
+				if (pwd == NULL) {
+					if (errno == 0)		/* Not found */
+						continue;
+					char buf[40];
+					int err = errno;
+					(void) snprintf(buf, sizeof (buf),
+					    "%d", err);
+					directory_entry_set_error(&del[i],
+					    directory_error("errno.getpwuid",
+					    "getpwuid: %2 (%1)",
+					    buf, strerror(err), NULL));
+					continue;
+				}
+			} else if (rid >= LOCALRID_GID_MIN &&
+			    rid <= LOCALRID_GID_MAX) {
+				/* Group */
+				errno = 0;
+				grp = getgrgid(rid - LOCALRID_GID_MIN);
+				if (grp == NULL) {
+					if (errno == 0)		/* Not found */
+						continue;
+					char buf[40];
+					int err = errno;
+					(void) snprintf(buf, sizeof (buf),
+					    "%d", err);
+					directory_entry_set_error(&del[i],
+					    directory_error("errno.getgrgid",
+					    "getgrgid: %2 (%1)",
+					    buf, strerror(err), NULL));
+					continue;
+				}
+			} else
+				continue;
+
+		} else {
+			int id_len = strlen(id);
+			char name[id_len + 1];
+			char domain[id_len + 1];
+
+			split_name(name, domain, id);
+
+			if (domain[0] != '\0') {
+				if (!domain_eq(domain, my_host_name))
+					continue;
+			}
+
+			/*
+			 * If the caller has requested user or group
+			 * information specifically, we only set one of
+			 * pwd or grp.
+			 * If the caller has requested either type, we try
+			 * both in the hopes of getting one.
+			 * Note that directory_provider_nsswitch_populate
+			 * considers it to be an error if both are set.
+			 */
+			if (type != DIRECTORY_ID_GROUP[0]) {
+				/* prep for not found / error case */
+				errno = 0;
+
+				pwd = getpwnam(name);
+				if (pwd == NULL && errno != 0) {
+					char buf[40];
+					int err = errno;
+					(void) snprintf(buf, sizeof (buf),
+					    "%d", err);
+					directory_entry_set_error(&del[i],
+					    directory_error("errno.getpwnam",
+					    "getpwnam: %2 (%1)",
+					    buf, strerror(err), NULL));
+					continue;
+				}
+			}
+
+			if (type != DIRECTORY_ID_USER[0]) {
+				/* prep for not found / error case */
+				errno = 0;
+
+				grp = getgrnam(name);
+				if (grp == NULL && errno != 0) {
+					char buf[40];
+					int err = errno;
+					(void) snprintf(buf, sizeof (buf),
+					    "%d", err);
+					directory_entry_set_error(&del[i],
+					    directory_error("errno.getgrnam",
+					    "getgrnam: %2 (%1)",
+					    buf, strerror(err), NULL));
+					continue;
+				}
+			}
+		}
+
+		/*
+		 * Didn't find it, don't populate the structure.
+		 * Another provider might populate it.
+		 */
+		if (pwd == NULL && grp == NULL)
+			continue;
+
+		de = directory_provider_nsswitch_populate(&del[i], pwd, grp,
+		    attrs);
+		if (de != NULL) {
+			directory_entry_set_error(&del[i], de);
+			de = NULL;
+			continue;
+		}
+	}
+
+	return (NULL);
+}
+
+/*
+ * Given a pwd structure or a grp structure, and a list of attributes that
+ * were requested, populate the structure to return to the caller.
+ */
+static
+directory_error_t
+directory_provider_nsswitch_populate(
+    directory_entry_rpc *pent,
+    struct passwd *pwd,
+    struct group *grp,
+    idmap_utf8str_list *attrs)
+{
+	int j;
+	directory_values_rpc *llvals;
+	int nattrs;
+
+	/*
+	 * If it wasn't for this case, everything would be a lot simpler.
+	 * UNIX allows users and groups with the same name.  Windows doesn't.
+	 */
+	if (pwd != NULL && grp != NULL) {
+		return directory_error("Ambiguous.Name",
+		    "Ambiguous name, is both a user and a group",
+		    NULL);
+	}
+
+	nattrs = attrs->idmap_utf8str_list_len;
+
+	llvals = calloc(nattrs, sizeof (directory_values_rpc));
+	if (llvals == NULL)
+		goto nomem;
+
+	pent->directory_entry_rpc_u.attrs.attrs_val = llvals;
+	pent->directory_entry_rpc_u.attrs.attrs_len = nattrs;
+	pent->status = DIRECTORY_FOUND;
+
+	for (j = 0; j < nattrs; j++) {
+		directory_values_rpc *val;
+		char *a;
+		directory_error_t de;
+
+		/*
+		 * We're going to refer to these a lot, so make a shorthand
+		 * copy.
+		 */
+		a = attrs->idmap_utf8str_list_val[j];
+		val = &llvals[j];
+
+		/*
+		 * Start by assuming no errors and that we don't have
+		 * the information
+		 */
+		val->found = FALSE;
+		de = NULL;
+
+		if (pwd != NULL) {
+			/*
+			 * Handle attributes for user entries.
+			 */
+			if (strcaseeq(a, "cn")) {
+				const char *p = pwd->pw_name;
+				de = str_list_dav(val, &p, 1);
+			} else if (strcaseeq(a, "objectClass")) {
+				static const char *objectClasses[] = {
+					"top",
+					"posixAccount",
+				};
+				de = str_list_dav(val, objectClasses,
+				    NELEM(objectClasses));
+			} else if (strcaseeq(a, "gidNumber")) {
+				de = uint_list_dav(val, &pwd->pw_gid, 1);
+			} else if (strcaseeq(a, "objectSid")) {
+				de = machine_sid_dav(val,
+				    pwd->pw_uid + LOCALRID_UID_MIN);
+			} else if (strcaseeq(a, "displayName")) {
+				const char *p = pwd->pw_gecos;
+				de = str_list_dav(val, &p, 1);
+			} else if (strcaseeq(a, "distinguishedName")) {
+				char *dn;
+				RDLOCK_CONFIG();
+				(void) asprintf(&dn,
+				    "uid=%s,ou=people,dc=%s",
+				    pwd->pw_name, _idmapdstate.hostname);
+				UNLOCK_CONFIG();
+				if (dn == NULL)
+					goto nomem;
+				const char *cdn = dn;
+				de = str_list_dav(val, &cdn, 1);
+				free(dn);
+			} else if (strcaseeq(a, "uid")) {
+				const char *p = pwd->pw_name;
+				de = str_list_dav(val, &p, 1);
+			} else if (strcaseeq(a, "uidNumber")) {
+				de = uint_list_dav(val, &pwd->pw_uid, 1);
+			} else if (strcaseeq(a, "gecos")) {
+				const char *p = pwd->pw_gecos;
+				de = str_list_dav(val, &p, 1);
+			} else if (strcaseeq(a, "homeDirectory")) {
+				const char *p = pwd->pw_dir;
+				de = str_list_dav(val, &p, 1);
+			} else if (strcaseeq(a, "loginShell")) {
+				const char *p = pwd->pw_shell;
+				de = str_list_dav(val, &p, 1);
+			} else if (strcaseeq(a, "x-sun-canonicalName")) {
+				char *canon;
+				RDLOCK_CONFIG();
+				(void) asprintf(&canon, "%s@%s",
+				    pwd->pw_name, _idmapdstate.hostname);
+				UNLOCK_CONFIG();
+				if (canon == NULL)
+					goto nomem;
+				const char *ccanon = canon;
+				de = str_list_dav(val, &ccanon, 1);
+				free(canon);
+			} else if (strcaseeq(a, "x-sun-provider")) {
+				const char *provider = "UNIX-passwd";
+				de = str_list_dav(val, &provider, 1);
+			}
+		} else if (grp != NULL)  {
+			/*
+			 * Handle attributes for group entries.
+			 */
+			if (strcaseeq(a, "cn")) {
+				const char *p = grp->gr_name;
+				de = str_list_dav(val, &p, 1);
+			} else if (strcaseeq(a, "objectClass")) {
+				static const char *objectClasses[] = {
+					"top",
+					"posixGroup",
+				};
+				de = str_list_dav(val, objectClasses,
+				    NELEM(objectClasses));
+			} else if (strcaseeq(a, "gidNumber")) {
+				de = uint_list_dav(val, &grp->gr_gid, 1);
+			} else if (strcaseeq(a, "objectSid")) {
+				de = machine_sid_dav(val,
+				    grp->gr_gid + LOCALRID_GID_MIN);
+			} else if (strcaseeq(a, "displayName")) {
+				const char *p = grp->gr_name;
+				de = str_list_dav(val, &p, 1);
+			} else if (strcaseeq(a, "distinguishedName")) {
+				char *dn;
+				RDLOCK_CONFIG();
+				(void) asprintf(&dn,
+				    "cn=%s,ou=group,dc=%s",
+				    grp->gr_name, _idmapdstate.hostname);
+				UNLOCK_CONFIG();
+				if (dn == NULL)
+					goto nomem;
+				const char *cdn = dn;
+				de = str_list_dav(val, &cdn, 1);
+				free(dn);
+			} else if (strcaseeq(a, "memberUid")) {
+				/*
+				 * NEEDSWORK:  There is probably a non-cast
+				 * way to do this, but I don't immediately
+				 * see it.
+				 */
+				const char * const *members =
+				    (const char * const *)grp->gr_mem;
+				de = str_list_dav(val, members, 0);
+			} else if (strcaseeq(a, "x-sun-canonicalName")) {
+				char *canon;
+				RDLOCK_CONFIG();
+				(void) asprintf(&canon, "%s@%s",
+				    grp->gr_name, _idmapdstate.hostname);
+				UNLOCK_CONFIG();
+				if (canon == NULL)
+					goto nomem;
+				const char *ccanon = canon;
+				de = str_list_dav(val, &ccanon, 1);
+				free(canon);
+			} else if (strcaseeq(a, "x-sun-provider")) {
+				const char *provider = "UNIX-group";
+				de = str_list_dav(val, &provider, 1);
+			}
+		}
+
+		if (de != NULL)
+			return (de);
+	}
+
+	return (NULL);
+
+nomem:
+	return (directory_error("ENOMEM.users",
+	    "No memory allocating return value for user lookup", NULL));
+}
+
+/*
+ * Populate a directory attribute value with a SID based on our machine SID
+ * and the specified RID.
+ *
+ * It's a bit perverse that we must take a text-format SID and turn it into
+ * a binary-format SID, only to have the caller probably turn it back into
+ * text format, but SIDs are carried across LDAP in binary format.
+ */
+static
+directory_error_t
+machine_sid_dav(directory_values_rpc *lvals, unsigned int rid)
+{
+	sid_t *sid;
+	directory_error_t de;
+
+	RDLOCK_CONFIG();
+	int len = strlen(_idmapdstate.cfg->pgcfg.machine_sid);
+	char buf[len + 100];	/* 100 is enough space for any RID */
+	(void) snprintf(buf, sizeof (buf), "%s-%u",
+	    _idmapdstate.cfg->pgcfg.machine_sid, rid);
+	UNLOCK_CONFIG();
+
+	sid = sid_fromstr(buf);
+	if (sid == NULL)
+		goto nomem;
+
+	sid_to_le(sid);
+
+	de = bin_list_dav(lvals, sid, 1, sid_len(sid));
+	sid_free(sid);
+	return (de);
+
+nomem:
+	return (directory_error("ENOMEM.machine_sid_dav",
+	    "Out of memory allocating return value for lookup", NULL));
+}
+
+struct directory_provider_static directory_provider_nsswitch = {
+	"files",
+	directory_provider_nsswitch_get,
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/idmap/idmapd/directory_server.c	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,292 @@
+/*
+ * 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.
+ */
+
+/*
+ * Server-side support for directory information lookup functions.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <netdb.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <string.h>
+#include <note.h>
+#include "idmapd.h"
+#include "directory.h"
+#include "directory_private.h"
+#include <rpcsvc/idmap_prot.h>
+#include "directory_library_impl.h"
+#include "directory_server_impl.h"
+#include "sized_array.h"
+#include "miscutils.h"
+
+/*
+ * Here's a list of all of the modules that provide directory
+ * information.  In the fullness of time this should probably be
+ * a plugin-able switch mechanism.
+ * Note that the list is in precedence order.
+ */
+extern struct directory_provider_static directory_provider_builtin;
+extern struct directory_provider_static directory_provider_nsswitch;
+extern struct directory_provider_static directory_provider_ad;
+struct directory_provider_static *providers[] = {
+	&directory_provider_builtin,
+	&directory_provider_nsswitch,
+	&directory_provider_ad,
+};
+
+/*
+ * This is the entry point for all directory lookup service requests.
+ */
+bool_t
+directory_get_common_1_svc(
+    idmap_utf8str_list ids,
+    idmap_utf8str types,
+    idmap_utf8str_list attrs,
+    directory_results_rpc *result,
+    struct svc_req *req)
+{
+	NOTE(ARGUNUSED(req))
+	int nids;
+	directory_entry_rpc *entries;
+	directory_error_t de;
+	int i;
+
+	nids = ids.idmap_utf8str_list_len;
+
+	entries = (directory_entry_rpc *)
+	    calloc(nids, sizeof (directory_entry_rpc));
+	if (entries == NULL)
+		goto nomem;
+	result->directory_results_rpc_u.entries.entries_val = entries;
+	result->directory_results_rpc_u.entries.entries_len = nids;
+	result->failed = FALSE;
+
+	for (i = 0; i < nids; i++) {
+		if (strlen(ids.idmap_utf8str_list_val[i]) >
+		    IDMAP_MAX_NAME_LEN) {
+			directory_entry_set_error(&entries[i],
+			    directory_error("invalid_arg.id.too_long",
+			    "Identifier too long", NULL));
+		}
+	}
+
+	for (i = 0; i < NELEM(providers); i++) {
+		de = providers[i]->get(entries, &ids, types,
+		    &attrs);
+		if (de != NULL)
+			goto err;
+	}
+
+	return (TRUE);
+
+nomem:
+	de = directory_error("ENOMEM.get_common",
+	    "Insufficient memory retrieving directory data", NULL);
+
+err:
+	xdr_free(xdr_directory_results_rpc, (char *)result);
+	result->failed = TRUE;
+	return (
+	    directory_error_to_rpc(&result->directory_results_rpc_u.err, de));
+}
+
+/*
+ * Split name into {domain, name}.
+ * Suggest allocating name and domain on the stack, same size as id,
+ * using variable length arrays.
+ */
+void
+split_name(char *name, char *domain, char *id)
+{
+	char *p;
+
+	if ((p = strchr(id, '@')) != NULL) {
+		(void) strlcpy(name, id, p - id + 1);
+		(void) strcpy(domain, p + 1);
+	} else if ((p = strchr(id, '\\')) != NULL) {
+		(void) strcpy(name, p + 1);
+		(void) strlcpy(domain, id, p - id + 1);
+	} else {
+		(void) strcpy(name, id);
+		(void) strcpy(domain, "");
+	}
+}
+
+/*
+ * Given a list of strings, return a set of directory attribute values.
+ *
+ * Mark that the attribute was found.
+ *
+ * Note that the terminating \0 is *not* included in the result, because
+ * that's the way that strings come from LDAP.
+ * (Note also that the client side stuff adds in a terminating \0.)
+ *
+ * Note that on error the array may have been partially populated and will
+ * need to be cleaned up by the caller.  This is normally not a problem
+ * because the caller will need to clean up several such arrays.
+ */
+directory_error_t
+str_list_dav(directory_values_rpc *lvals, const char * const *str_list, int n)
+{
+	directory_value_rpc *dav;
+	int i;
+
+	if (n == 0) {
+		for (n = 0; str_list[n] != NULL; n++)
+			/* LOOP */;
+	}
+
+	dav = calloc(n, sizeof (directory_value_rpc));
+	if (dav == NULL)
+		goto nomem;
+
+	lvals->directory_values_rpc_u.values.values_val = dav;
+	lvals->directory_values_rpc_u.values.values_len = n;
+	lvals->found = TRUE;
+
+	for (i = 0; i < n; i++) {
+		int len;
+
+		len = strlen(str_list[i]);
+		dav[i].directory_value_rpc_val = memdup(str_list[i], len);
+		if (dav[i].directory_value_rpc_val == NULL)
+			goto nomem;
+		dav[i].directory_value_rpc_len = len;
+	}
+
+	return (NULL);
+
+nomem:
+	return (directory_error("ENOMEM.str_list_dav",
+	    "Insufficient memory copying values"));
+}
+
+/*
+ * Given a list of unsigned integers, return a set of string directory
+ * attribute values.
+ *
+ * Mark that the attribute was found.
+ *
+ * Note that the terminating \0 is *not* included in the result, because
+ * that's the way that strings come from LDAP.
+ * (Note also that the client side stuff adds in a terminating \0.)
+ *
+ * Note that on error the array may have been partially populated and will
+ * need to be cleaned up by the caller.  This is normally not a problem
+ * because the caller will need to clean up several such arrays.
+ */
+directory_error_t
+uint_list_dav(directory_values_rpc *lvals, const unsigned int *array, int n)
+{
+	directory_value_rpc *dav;
+	int i;
+
+	dav = calloc(n, sizeof (directory_value_rpc));
+	if (dav == NULL)
+		goto nomem;
+
+	lvals->directory_values_rpc_u.values.values_val = dav;
+	lvals->directory_values_rpc_u.values.values_len = n;
+	lvals->found = TRUE;
+
+	for (i = 0; i < n; i++) {
+		char buf[100];	/* larger than any integer */
+		int len;
+
+		(void) snprintf(buf, sizeof (buf), "%u", array[i]);
+
+		len = strlen(buf);
+		dav[i].directory_value_rpc_val = memdup(buf, len);
+		if (dav[i].directory_value_rpc_val == NULL)
+			goto nomem;
+		dav[i].directory_value_rpc_len = len;
+	}
+
+	return (NULL);
+
+nomem:
+	return (directory_error("ENOMEM.uint_list_dav",
+	    "Insufficient memory copying values"));
+}
+
+/*
+ * Given a list of fixed-length binary chunks, return a set of binary
+ * directory attribute values.
+ *
+ * Mark that the attribute was found.
+ *
+ * Note that on error the array may have been partially populated and will
+ * need to be cleaned up by the caller.  This is normally not a problem
+ * because the caller will need to clean up several such arrays.
+ */
+directory_error_t
+bin_list_dav(directory_values_rpc *lvals, const void *array, int n, size_t sz)
+{
+	directory_value_rpc *dav;
+	char *inbuf = (char *)array;
+	int i;
+
+	dav = calloc(n, sizeof (directory_value_rpc));
+	if (dav == NULL)
+		goto nomem;
+
+	lvals->directory_values_rpc_u.values.values_val = dav;
+	lvals->directory_values_rpc_u.values.values_len = n;
+	lvals->found = TRUE;
+
+	for (i = 0; i < n; i++) {
+		dav[i].directory_value_rpc_val = memdup(inbuf, sz);
+		if (dav[i].directory_value_rpc_val == NULL)
+			goto nomem;
+		dav[i].directory_value_rpc_len = sz;
+		inbuf += sz;
+	}
+
+	return (NULL);
+
+nomem:
+	return (directory_error("ENOMEM.bin_list_dav",
+	    "Insufficient memory copying values"));
+}
+
+/*
+ * Set up to return an error on a particular directory entry.
+ * Note that the caller need not (and in fact must not) free
+ * the directory_error_t; it will be freed when the directory entry
+ * list is freed.
+ */
+void
+directory_entry_set_error(directory_entry_rpc *ent, directory_error_t de)
+{
+	xdr_free(xdr_directory_entry_rpc, (char *)&ent);
+	ent->status = DIRECTORY_ERROR;
+	(void) directory_error_to_rpc(&ent->directory_entry_rpc_u.err, de);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/idmap/idmapd/directory_server_impl.h	Mon Jul 20 13:07:46 2009 -0400
@@ -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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DIRECTORY_SERVER_IMPL_H
+#define	_DIRECTORY_SERVER_IMPL_H
+
+/*
+ * Internal implementation details for the server side of directory lookup.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Functions to populate Directory Attribute Value lists.
+ */
+directory_error_t str_list_dav(directory_values_rpc *lvals,
+    const char * const *str_list, int n);
+directory_error_t uint_list_dav(directory_values_rpc *lvals,
+    const unsigned int *uint_list, int n);
+directory_error_t bin_list_dav(directory_values_rpc *lvals,
+    const void *array, int n, size_t sz);
+
+/*
+ * Split a name@domain into name, domain.  Recommend allocating the
+ * destination buffers the same size as the input, on the stack,
+ * using variable length arrays.
+ */
+void split_name(char *name, char *domain, char *id);
+
+/*
+ * Insert a directory_error_t into a directory entry to be returned.
+ * Caller MUST NOT free the directory_error_t.
+ */
+void directory_entry_set_error(directory_entry_rpc *ent,
+    directory_error_t de);
+
+/*
+ * This is the structure by which a provider supplies its entry points.
+ * The name is not currently used.
+ */
+struct directory_provider_static {
+	char *name;
+	directory_error_t (*get)(
+	    directory_entry_rpc *ret,
+	    idmap_utf8str_list *ids,
+	    idmap_utf8str types,
+	    idmap_utf8str_list *attrs);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DIRECTORY_SERVER_IMPL_H */
--- a/usr/src/cmd/idmap/idmapd/idmap_config.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/idmap/idmapd/idmap_config.c	Mon Jul 20 13:07:46 2009 -0400
@@ -696,7 +696,6 @@
 	int		num_df1 = 0;
 	int		num_df2 = 0;
 	boolean_t	match;
-	int		err;
 
 	for (i = 0; df1[i].domain[0] != '\0'; i++)
 		if (df1[i].trusted)
@@ -714,10 +713,8 @@
 			match = B_FALSE;
 			for (j = 0; df2[j].domain[0] != '\0'; j++) {
 				if (df2[j].trusted &&
-				    u8_strcmp(df1[i].domain, df2[i].domain, 0,
-				    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err)
-				    == 0 && err == 0 &&
-				    strcmp(df1[i].sid, df2[i].sid) == 0) {
+				    domain_eq(df1[i].domain, df2[j].domain) &&
+				    strcmp(df1[i].sid, df2[j].sid) == 0) {
 					match = B_TRUE;
 					break;
 				}
@@ -756,10 +753,10 @@
 				    (*new)[j].forest_name) == 0 &&
 				    ad_disc_compare_ds(
 				    (*value)[i].global_catalog,
-				    (*new)[i].global_catalog) == 0 &&
+				    (*new)[j].global_catalog) == 0 &&
 				    compare_trusteddomainsinforest(
 				    (*value)[i].domains_in_forest,
-				    (*new)[i].domains_in_forest) == 0) {
+				    (*new)[j].domains_in_forest) == 0) {
 					match = B_TRUE;
 					break;
 				}
@@ -1274,7 +1271,6 @@
 	char *forestname;
 	int num_trusteddomains;
 	boolean_t new_forest;
-	int err;
 	char *trusteddomain;
 	idmap_ad_disc_ds_t *globalcatalog;
 	idmap_trustedforest_t *trustedforests;
@@ -1368,11 +1364,8 @@
 				/* Mark the domain as trusted */
 				for (l = 0;
 				    domainsinforest[l].domain[0] != '\0'; l++) {
-					if (u8_strcmp(trusteddomain,
-					    domainsinforest[l].domain, 0,
-					    U8_STRCMP_CI_LOWER,
-					    U8_UNICODE_LATEST, &err) == 0 &&
-					    err == 0) {
+					if (domain_eq(trusteddomain,
+					    domainsinforest[l].domain)) {
 						domainsinforest[l].trusted =
 						    TRUE;
 						break;
@@ -1420,11 +1413,8 @@
 			/* Mark the domain as trusted */
 			for (l = 0; domainsinforest[l].domain[0] != '\0';
 			    l++) {
-				if (u8_strcmp(trusteddomain,
-				    domainsinforest[l].domain, 0,
-				    U8_STRCMP_CI_LOWER,
-				    U8_UNICODE_LATEST, &err) == 0 &&
-				    err == 0) {
+				if (domain_eq(trusteddomain,
+				    domainsinforest[l].domain)) {
 					domainsinforest[l].trusted = TRUE;
 					break;
 				}
@@ -1434,6 +1424,8 @@
 		if (j > 0) {
 			pgcfg->num_trusted_forests = j;
 			pgcfg->trusted_forests = trustedforests;
+		} else {
+			free(trustedforests);
 		}
 	}
 
--- a/usr/src/cmd/idmap/idmapd/idmapd.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/idmap/idmapd/idmapd.c	Mon Jul 20 13:07:46 2009 -0400
@@ -59,12 +59,6 @@
 static void	init_idmapd();
 static void	fini_idmapd();
 
-
-#define	_RPCSVC_CLOSEDOWN 120
-
-int _rpcsvcstate = _IDLE;	/* Set when a request is serviced */
-int _rpcsvccount = 0;		/* Number of requests being serviced */
-mutex_t _svcstate_lock;		/* lock for _rpcsvcstate, _rpcsvccount */
 idmapd_state_t	_idmapdstate;
 
 SVCXPRT *xprt = NULL;
--- a/usr/src/cmd/idmap/idmapd/idmapd.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/idmap/idmapd/idmapd.h	Mon Jul 20 13:07:46 2009 -0400
@@ -47,15 +47,9 @@
 extern "C" {
 #endif
 
-/* States a server can be in wrt request */
-#define	_IDLE	0
-#define	_SERVED	1
-
 #define	SENTINEL_PID	UINT32_MAX
 #define	CHECK_NULL(s)	(s != NULL ? s : "null")
 
-extern int _rpcsvcstate;	/* set when a request is serviced */
-extern int _rpcsvccount;	/* number of requests being serviced */
 extern mutex_t _svcstate_lock;	/* lock for _rpcsvcstate, _rpcsvccount */
 
 typedef enum idmap_namemap_mode {
@@ -154,6 +148,21 @@
 	const char	*msg;
 } msg_table_t;
 
+/*
+ * Data structure to store well-known SIDs and
+ * associated mappings (if any)
+ */
+typedef struct wksids_table {
+	const char	*sidprefix;
+	uint32_t	rid;
+	const char	*domain;
+	const char	*winname;
+	int		is_wuser;
+	uid_t		pid;
+	int		is_user;
+	int		direction;
+} wksids_table_t;
+
 #define	IDMAPD_SEARCH_TIMEOUT		3   /* seconds */
 #define	IDMAPD_LDAP_OPEN_TIMEOUT	1   /* secs; initial, w/ exp backoff */
 
@@ -221,6 +230,14 @@
 #define	IS_REQUEST_GID(request) \
 	((request).id1.idtype == IDMAP_GID)
 
+/*
+ * Local RID ranges
+ */
+#define	LOCALRID_UID_MIN	1000U
+#define	LOCALRID_UID_MAX	((uint32_t)INT32_MAX)
+#define	LOCALRID_GID_MIN	(((uint32_t)INT32_MAX) + 1)
+#define	LOCALRID_GID_MAX	UINT32_MAX
+
 typedef idmap_retcode (*update_list_res_cb)(void *, const char **, uint64_t);
 typedef int (*list_svc_cb)(void *, int, char **, char **);
 
@@ -286,6 +303,13 @@
 extern void	idmap_log_syslog(boolean_t);
 extern void	idmap_log_degraded(boolean_t);
 
+extern const wksids_table_t *find_wksid_by_pid(uid_t pid, int is_user);
+extern const wksids_table_t *find_wksid_by_sid(const char *sid, int rid,
+    int type);
+extern const wksids_table_t *find_wksid_by_name(const char *name,
+    const char *domain, int type);
+extern const wksids_table_t *find_wk_by_sid(char *sid);
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/cmd/idmap/idmapd/rpc_svc.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/idmap/idmapd/rpc_svc.c	Mon Jul 20 13:07:46 2009 -0400
@@ -24,73 +24,152 @@
  */
 
 /*
- * RPC service routines
- * It was initially generated using rpcgen.
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ * Edit idmap_prot.x and rebuild this file with
+ * rpcgen -CMNm -o idmap_prot_svc.c.new ../../../uts/common/rpcsvc/idmap_prot.x
+ * then merge as required.  A recent version of rpcgen is needed to
+ * produce this exact file; when the revised rpcgen is available in the
+ * build environment this file can be built automatically.
  */
 
-#include "idmapd.h"
-#include <rpcsvc/idmap_prot.h>
-#include <stdlib.h>
+#include "../../../uts/common/rpcsvc/idmap_prot.h"
+#include <stdio.h>
+#include <stdlib.h> /* getenv, exit */
 #include <signal.h>
-#include <rpc/xdr.h>
-#include <rpc/rpc.h>
-#include <string.h>
-#include <thread.h>
-#include <synch.h>
+#include <rpc/pmap_clnt.h> /* for pmap_unset */
+#include <string.h> /* strcmp */
+#include <unistd.h> /* setsid */
+#include <sys/types.h>
+#include <memory.h>
+#include <stropts.h>
+#include <sys/resource.h> /* rlimit */
+#include <syslog.h>
+
+#ifndef SIG_PF
+#define	SIG_PF void(*)(int)
+#endif
+
+#ifdef DEBUG
+#define	RPC_SVC_FG
+#endif
+
+#define	_RPCSVC_CLOSEDOWN 120
+extern int _rpcpmstart;		/* Started by a port monitor ? */
+
+/* States a server can be in wrt request */
 
+#define	_IDLE 0
+#define	_SERVED 1
+
+/* LINTED static unused if no main */
+static int _rpcsvcstate = _IDLE;	/* Set when a request is serviced */
+static int _rpcsvccount = 0;		/* Number of requests being serviced */
+mutex_t _svcstate_lock;		/* lock for _rpcsvcstate, _rpcsvccount */
+
+#if	defined(RPC_MSGOUT)
+extern void RPC_MSGOUT(const char *, ...);
+#else	/* defined(RPC_MSGOUT) */
+static void
+RPC_MSGOUT(const char *fmt, char *msg)
+{
+#ifdef RPC_SVC_FG
+	if (_rpcpmstart)
+		syslog(LOG_ERR, fmt, msg);
+	else {
+		(void) fprintf(stderr, fmt, msg);
+		(void) putc('\n', stderr);
+	}
+#else
+	syslog(LOG_ERR, fmt, msg);
+#endif
+}
+#endif	/* defined(RPC_MSGOUT) */
 
 /* ARGSUSED */
 int
-_idmap_null_1(void  *argp, void *result, struct svc_req *rqstp)
+_idmap_null_1(
+    void  *argp,
+    void *result,
+    struct svc_req *rqstp)
 {
 	return (idmap_null_1_svc(result, rqstp));
 }
 
 int
-_idmap_get_mapped_ids_1(idmap_mapping_batch  *argp, idmap_ids_res *result,
-		struct svc_req *rqstp)
+_idmap_get_mapped_ids_1(
+    idmap_mapping_batch  *argp,
+    idmap_ids_res *result,
+    struct svc_req *rqstp)
 {
 	return (idmap_get_mapped_ids_1_svc(*argp, result, rqstp));
 }
 
 int
-_idmap_list_mappings_1(idmap_list_mappings_1_argument *argp,
-		idmap_mappings_res *result, struct svc_req *rqstp)
+_idmap_list_mappings_1(
+    idmap_list_mappings_1_argument *argp,
+    idmap_mappings_res *result,
+    struct svc_req *rqstp)
 {
-	return (idmap_list_mappings_1_svc(argp->lastrowid,
-	    argp->limit, argp->flag, result, rqstp));
+	return (idmap_list_mappings_1_svc(
+	    argp->lastrowid,
+	    argp->limit,
+	    argp->flag,
+	    result, rqstp));
 }
 
 int
-_idmap_list_namerules_1(idmap_list_namerules_1_argument *argp,
-		idmap_namerules_res *result, struct svc_req *rqstp)
+_idmap_list_namerules_1(
+    idmap_list_namerules_1_argument *argp,
+    idmap_namerules_res *result,
+    struct svc_req *rqstp)
 {
-	return (idmap_list_namerules_1_svc(argp->rule, argp->lastrowid,
-	    argp->limit, result, rqstp));
+	return (idmap_list_namerules_1_svc(
+	    argp->rule,
+	    argp->lastrowid,
+	    argp->limit,
+	    result, rqstp));
 }
 
 int
-_idmap_update_1(idmap_update_batch  *argp, idmap_update_res *res,
-		struct svc_req *rqstp)
+_idmap_update_1(
+    idmap_update_batch  *argp,
+    idmap_update_res *result,
+    struct svc_req *rqstp)
 {
-	return (idmap_update_1_svc(*argp, res, rqstp));
+	return (idmap_update_1_svc(*argp, result, rqstp));
 }
 
 int
-_idmap_get_mapped_id_by_name_1(idmap_mapping  *argp,
-		idmap_mappings_res *result, struct svc_req *rqstp)
+_idmap_get_mapped_id_by_name_1(
+    idmap_mapping  *argp,
+    idmap_mappings_res *result,
+    struct svc_req *rqstp)
 {
 	return (idmap_get_mapped_id_by_name_1_svc(*argp, result, rqstp));
 }
 
 int
-_idmap_get_prop_1(idmap_prop_type  *argp,
-		idmap_prop_res *result, struct svc_req *rqstp)
+_idmap_get_prop_1(
+    idmap_prop_type  *argp,
+    idmap_prop_res *result,
+    struct svc_req *rqstp)
 {
 	return (idmap_get_prop_1_svc(*argp, result, rqstp));
 }
 
-
+int
+_directory_get_common_1(
+    directory_get_common_1_argument *argp,
+    directory_results_rpc *result,
+    struct svc_req *rqstp)
+{
+	return (directory_get_common_1_svc(
+	    argp->ids,
+	    argp->types,
+	    argp->attrs,
+	    result, rqstp));
+}
 
 void
 idmap_prog_1(struct svc_req *rqstp, register SVCXPRT *transp)
@@ -102,6 +181,7 @@
 		idmap_update_batch idmap_update_1_arg;
 		idmap_mapping idmap_get_mapped_id_by_name_1_arg;
 		idmap_prop_type idmap_get_prop_1_arg;
+		directory_get_common_1_argument directory_get_common_1_arg;
 	} argument;
 	union {
 		idmap_ids_res idmap_get_mapped_ids_1_res;
@@ -110,6 +190,7 @@
 		idmap_update_res idmap_update_1_res;
 		idmap_mappings_res idmap_get_mapped_id_by_name_1_res;
 		idmap_prop_res idmap_get_prop_1_res;
+		directory_results_rpc directory_get_common_1_res;
 	} result;
 	bool_t retval;
 	xdrproc_t _xdr_argument, _xdr_result;
@@ -120,61 +201,84 @@
 	(void) mutex_unlock(&_svcstate_lock);
 	switch (rqstp->rq_proc) {
 	case IDMAP_NULL:
-		_xdr_argument = (xdrproc_t)xdr_void;
-		_xdr_result = (xdrproc_t)xdr_void;
+		_xdr_argument = (xdrproc_t)
+		    xdr_void;
+		_xdr_result = (xdrproc_t)
+		    xdr_void;
 		local = (bool_t (*) (char *,  void *,  struct svc_req *))
 		    _idmap_null_1;
 		break;
 
 	case IDMAP_GET_MAPPED_IDS:
-		_xdr_argument = (xdrproc_t)xdr_idmap_mapping_batch;
-		_xdr_result = (xdrproc_t)xdr_idmap_ids_res;
+		_xdr_argument = (xdrproc_t)
+		    xdr_idmap_mapping_batch;
+		_xdr_result = (xdrproc_t)
+		    xdr_idmap_ids_res;
 		local = (bool_t (*) (char *,  void *,  struct svc_req *))
 		    _idmap_get_mapped_ids_1;
 		break;
 
 	case IDMAP_LIST_MAPPINGS:
-		_xdr_argument = (xdrproc_t)xdr_idmap_list_mappings_1_argument;
-		_xdr_result = (xdrproc_t)xdr_idmap_mappings_res;
+		_xdr_argument = (xdrproc_t)
+		    xdr_idmap_list_mappings_1_argument;
+		_xdr_result = (xdrproc_t)
+		    xdr_idmap_mappings_res;
 		local = (bool_t (*) (char *,  void *,  struct svc_req *))
 		    _idmap_list_mappings_1;
 		break;
 
 	case IDMAP_LIST_NAMERULES:
-		_xdr_argument = (xdrproc_t)xdr_idmap_list_namerules_1_argument;
-		_xdr_result = (xdrproc_t)xdr_idmap_namerules_res;
+		_xdr_argument = (xdrproc_t)
+		    xdr_idmap_list_namerules_1_argument;
+		_xdr_result = (xdrproc_t)
+		    xdr_idmap_namerules_res;
 		local = (bool_t (*) (char *,  void *,  struct svc_req *))
 		    _idmap_list_namerules_1;
 		break;
 
 	case IDMAP_UPDATE:
-		_xdr_argument = (xdrproc_t)xdr_idmap_update_batch;
-		_xdr_result = (xdrproc_t)xdr_idmap_update_res;
+		_xdr_argument = (xdrproc_t)
+		    xdr_idmap_update_batch;
+		_xdr_result = (xdrproc_t)
+		    xdr_idmap_update_res;
 		local = (bool_t (*) (char *,  void *,  struct svc_req *))
 		    _idmap_update_1;
 		break;
 
 	case IDMAP_GET_MAPPED_ID_BY_NAME:
-		_xdr_argument = (xdrproc_t)xdr_idmap_mapping;
-		_xdr_result = (xdrproc_t)xdr_idmap_mappings_res;
+		_xdr_argument = (xdrproc_t)
+		    xdr_idmap_mapping;
+		_xdr_result = (xdrproc_t)
+		    xdr_idmap_mappings_res;
 		local = (bool_t (*) (char *,  void *,  struct svc_req *))
 		    _idmap_get_mapped_id_by_name_1;
 		break;
 
 	case IDMAP_GET_PROP:
-		_xdr_argument = (xdrproc_t)xdr_idmap_prop_type;
-		_xdr_result = (xdrproc_t)xdr_idmap_prop_res;
+		_xdr_argument = (xdrproc_t)
+		    xdr_idmap_prop_type;
+		_xdr_result = (xdrproc_t)
+		    xdr_idmap_prop_res;
 		local = (bool_t (*) (char *,  void *,  struct svc_req *))
 		    _idmap_get_prop_1;
 		break;
 
+	case DIRECTORY_GET_COMMON:
+		_xdr_argument = (xdrproc_t)
+		    xdr_directory_get_common_1_argument;
+		_xdr_result = (xdrproc_t)
+		    xdr_directory_results_rpc;
+		local = (bool_t (*) (char *,  void *,  struct svc_req *))
+		    _directory_get_common_1;
+		break;
+
 	default:
 		svcerr_noproc(transp);
 		(void) mutex_lock(&_svcstate_lock);
 		_rpcsvccount--;
 		_rpcsvcstate = _SERVED;
 		(void) mutex_unlock(&_svcstate_lock);
-		return;
+		return; /* CSTYLED */
 	}
 	(void) memset((char *)&argument, 0, sizeof (argument));
 	if (!svc_getargs(transp, _xdr_argument, (caddr_t)&argument)) {
@@ -183,27 +287,28 @@
 		_rpcsvccount--;
 		_rpcsvcstate = _SERVED;
 		(void) mutex_unlock(&_svcstate_lock);
-		return;
+		return; /* CSTYLED */
 	}
 	retval = (bool_t)(*local)((char *)&argument, (void *)&result, rqstp);
-	if (_xdr_result && retval > 0 && !svc_sendreply(transp, _xdr_result,
-	    (char *)&result)) {
+	if (_xdr_result && retval > 0 &&
+	    !svc_sendreply(transp, _xdr_result, (char *)&result)) {
 		svcerr_systemerr(transp);
 	}
 	if (!svc_freeargs(transp, _xdr_argument, (caddr_t)&argument)) {
-		idmapdlog(LOG_ERR,
-		    "unable to free RPC arguments");
+		RPC_MSGOUT("%s",
+		    "unable to free arguments");
 		exit(1);
 	}
 	if (_xdr_result != NULL) {
 		if (!idmap_prog_1_freeresult(transp, _xdr_result,
 		    (caddr_t)&result))
-			idmapdlog(LOG_ERR,
-			    "unable to free RPC results");
+			RPC_MSGOUT("%s",
+			    "unable to free results");
 
 	}
 	(void) mutex_lock(&_svcstate_lock);
 	_rpcsvccount--;
 	_rpcsvcstate = _SERVED;
 	(void) mutex_unlock(&_svcstate_lock);
+	return; /* CSTYLED */
 }
--- a/usr/src/cmd/idmap/idmapd/server.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/idmap/idmapd/server.c	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -44,6 +44,7 @@
 #include <auth_attr.h>
 #include <secdb.h>
 #include <sys/u8_textprep.h>
+#include <note.h>
 
 #define	_VALIDATE_LIST_CB_DATA(col, val, siz)\
 	retcode = validate_list_cb_data(cb_data, argc, argv, col,\
@@ -1097,3 +1098,20 @@
 	(void) xdr_free(xdr_result, result);
 	return (TRUE);
 }
+
+/*
+ * This function is called by rpc_svc.c when it encounters an error.
+ */
+NOTE(PRINTFLIKE(1))
+void
+idmap_rpc_msgout(const char *fmt, ...)
+{
+	va_list va;
+	char buf[1000];
+
+	va_start(va, fmt);
+	(void) vsnprintf(buf, sizeof (buf), fmt, va);
+	va_end(va);
+
+	idmapdlog(LOG_ERR, "idmap RPC:  %s", buf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/idmap/idmapd/wksids.c	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,407 @@
+/*
+ * 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.
+ */
+
+/*
+ * Information about well-known (builtin) names, and functions to retrieve
+ * information about them.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include "idmapd.h"
+#include "miscutils.h"
+
+/*
+ * Table for well-known SIDs.
+ *
+ * Background:
+ *
+ * Some of the well-known principals are stored under:
+ * cn=WellKnown Security Principals, cn=Configuration, dc=<forestRootDomain>
+ * They belong to objectClass "foreignSecurityPrincipal". They don't have
+ * "samAccountName" nor "userPrincipalName" attributes. Their names are
+ * available in "cn" and "name" attributes. Some of these principals have a
+ * second entry under CN=ForeignSecurityPrincipals,dc=<forestRootDomain> and
+ * these duplicate entries have the stringified SID in the "name" and "cn"
+ * attributes instead of the actual name.
+ *
+ * Those of the form S-1-5-32-X are Builtin groups and are stored in the
+ * cn=builtin container (except, Power Users which is not stored in AD)
+ *
+ * These principals are and will remain constant. Therefore doing AD lookups
+ * provides no benefit. Also, using hard-coded table (and thus avoiding AD
+ * lookup) improves performance and avoids additional complexity in the
+ * adutils.c code. Moreover these SIDs can be used when no Active Directory
+ * is available (such as the CIFS server's "workgroup" mode).
+ *
+ * Notes:
+ * 1. Currently we don't support localization of well-known SID names,
+ * unlike Windows.
+ *
+ * 2. Other well-known SIDs i.e. S-1-5-<domain>-<w-k RID> are not stored
+ * here. AD does have normal user/group objects for these objects and
+ * can be looked up using the existing AD lookup code.
+ *
+ * 3. See comments above lookup_wksids_sid2pid() for more information
+ * on how we lookup the wksids table.
+ *
+ * 4. If this table contains two entries for a particular Windows name,
+ * so as to offer both UID and GID mappings, the preferred mapping (the
+ * one that matches Windows usage) must be listed first.  That is the
+ * entry that will be used when the caller specifies IDMAP_POSIXID
+ * ("don't care") as the target.
+ *
+ * Entries here come from KB243330, MS-LSAT, and
+ * http://technet.microsoft.com/en-us/library/cc755854.aspx
+ * http://technet.microsoft.com/en-us/library/cc755925.aspx
+ * http://msdn.microsoft.com/en-us/library/cc980032(PROT.10).aspx
+ */
+static wksids_table_t wksids[] = {
+	/* S-1-0	Null Authority */
+	{"S-1-0", 0, "", "Nobody", 1, SENTINEL_PID, -1, 1},
+
+	/* S-1-1	World Authority */
+	{"S-1-1", 0, "", "Everyone", 0, SENTINEL_PID, -1, -1},
+
+	/* S-1-2	Local Authority */
+	{"S-1-2", 0, "", "Local", 0, SENTINEL_PID, -1, -1},
+	{"S-1-2", 1, "", "Console Logon", 0, SENTINEL_PID, -1, -1},
+
+	/* S-1-3	Creator Authority */
+	{"S-1-3", 0, "", "Creator Owner", 1, IDMAP_WK_CREATOR_OWNER_UID, 1, 0},
+	{"S-1-3", 1, "", "Creator Group", 0, IDMAP_WK_CREATOR_GROUP_GID, 0, 0},
+	{"S-1-3", 2, "", "Creator Owner Server", 1, SENTINEL_PID, -1, -1},
+	{"S-1-3", 3, "", "Creator Group Server", 0, SENTINEL_PID, -1, 1},
+	{"S-1-3", 4, "", "Owner Rights", 0, SENTINEL_PID, -1, -1},
+
+	/* S-1-4	Non-unique Authority */
+
+	/* S-1-5	NT Authority */
+	{"S-1-5", 1, "", "Dialup", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5", 2, "", "Network", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5", 3, "", "Batch", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5", 4, "", "Interactive", 0, SENTINEL_PID, -1, -1},
+	/* S-1-5-5-X-Y	Logon Session */
+	{"S-1-5", 6, "", "Service", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5", 7, "", "Anonymous Logon", 0, GID_NOBODY, 0, 0},
+	{"S-1-5", 7, "", "Anonymous Logon", 0, UID_NOBODY, 1, 0},
+	{"S-1-5", 8, "", "Proxy", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5", 9, "", "Enterprise Domain Controllers", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5", 10, "", "Self", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5", 11, "", "Authenticated Users", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5", 12, "", "Restricted", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5", 13, "", "Terminal Server Users", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5", 14, "", "Remote Interactive Logon", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5", 15, "", "This Organization", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5", 17, "", "IUSR", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5", 18, "", "Local System", 0, IDMAP_WK_LOCAL_SYSTEM_GID, 0, 0},
+	{"S-1-5", 19, "", "Local Service", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5", 20, "", "Network Service", 0, SENTINEL_PID, -1, -1},
+
+	/* S-1-5-21-<domain>	Machine-local definitions */
+	{NULL, 498, NULL, "Enterprise Read-only Domain Controllers", 0,
+	    SENTINEL_PID, -1, -1},
+	{NULL, 500, NULL, "Administrator", 1, SENTINEL_PID, 1, -1},
+	{NULL, 501, NULL, "Guest", 1, SENTINEL_PID, 1, -1},
+	{NULL, 502, NULL, "KRBTGT", 1, SENTINEL_PID, 1, -1},
+	{NULL, 512, NULL, "Domain Admins", 0, SENTINEL_PID, -1, -1},
+	{NULL, 513, NULL, "Domain Users", 0, SENTINEL_PID, -1, -1},
+	{NULL, 514, NULL, "Domain Guests", 0, SENTINEL_PID, -1, -1},
+	{NULL, 515, NULL, "Domain Computers", 0, SENTINEL_PID, -1, -1},
+	{NULL, 516, NULL, "Domain Controllers", 0, SENTINEL_PID, -1, -1},
+	{NULL, 517, NULL, "Cert Publishers", 0, SENTINEL_PID, -1, -1},
+	{NULL, 518, NULL, "Schema Admins", 0, SENTINEL_PID, -1, -1},
+	{NULL, 519, NULL, "Enterprise Admins", 0, SENTINEL_PID, -1, -1},
+	{NULL, 520, NULL, "Global Policy Creator Owners", 0,
+	    SENTINEL_PID, -1, -1},
+	{NULL, 533, NULL, "RAS and IAS Servers", 0, SENTINEL_PID, -1, -1},
+
+	/* S-1-5-32	BUILTIN */
+	{"S-1-5-32", 544, "BUILTIN", "Administrators", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 545, "BUILTIN", "Users", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 546, "BUILTIN", "Guests", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 547, "BUILTIN", "Power Users", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 548, "BUILTIN", "Account Operators", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 549, "BUILTIN", "Server Operators", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 550, "BUILTIN", "Print Operators", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 551, "BUILTIN", "Backup Operators", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 552, "BUILTIN", "Replicator", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 554, "BUILTIN", "Pre-Windows 2000 Compatible Access", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 555, "BUILTIN", "Remote Desktop Users", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 556, "BUILTIN", "Network Configuration Operators", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 557, "BUILTIN", "Incoming Forest Trust Builders", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 558, "BUILTIN", "Performance Monitor Users", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 559, "BUILTIN", "Performance Log Users", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 560, "BUILTIN", "Windows Authorization Access Group", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 561, "BUILTIN", "Terminal Server License Servers", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 562, "BUILTIN", "Distributed COM Users", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 568, "BUILTIN", "IIS_IUSRS", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 569, "BUILTIN", "Cryptographic Operators", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 573, "BUILTIN", "Event Log Readers", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5-32", 574, "BUILTIN", "Certificate Service DCOM Access", 0,
+	    SENTINEL_PID, -1, -1},
+
+	{"S-1-5", 33, "", "Write Restricted", 0, SENTINEL_PID, -1, -1},
+
+	/* S-1-5-64	NT Authority */
+	{"S-1-5-64", 10, "", "NTLM Authentication", 0, SENTINEL_PID, -1, -1},
+	{"S-1-5-64", 14, "", "SChannel Authentication", 0,
+	    SENTINEL_PID, -1, -1},
+	{"S-1-5-64", 21, "", "Digest Authentication", 0, SENTINEL_PID, -1, -1},
+
+	/* S-1-5-80-a-b-c-d NT Service */
+
+	{"S-1-5", 1000, "", "Other Organization", 0, SENTINEL_PID, -1, -1},
+
+	/* S-1-7 Internet$ */
+
+	/*
+	 * S-1-16	Mandatory Label
+	 * S-1-16-0	Untrusted Mandatory Level
+	 * S-1-16-4096	Low Mandatory Level
+	 * S-1-16-8192	Medium Mandatory Level
+	 * S-1-16-8448	Medium Plus Mandatory Level
+	 * S-1-16-12288	High Mandatory Level
+	 * S-1-16-16384	System Mandatory Level
+	 * S-1-16-20480	Protected Process Mandatory Level
+	 */
+};
+
+/*
+ * Find a wksid entry for the specified Windows name and domain, of the
+ * specified type.
+ *
+ * Ignore entries intended only for U2W use.
+ */
+const
+wksids_table_t *
+find_wksid_by_name(const char *name, const char *domain, int type)
+{
+	int i;
+
+	RDLOCK_CONFIG();
+	int len = strlen(_idmapdstate.hostname);
+	char my_host_name[len + 1];
+	(void) strcpy(my_host_name, _idmapdstate.hostname);
+	UNLOCK_CONFIG();
+
+	for (i = 0; i < NELEM(wksids); i++) {
+		/* Check to see if this entry yields the desired type */
+		switch (type) {
+		case IDMAP_UID:
+			if (wksids[i].is_user == 0)
+				continue;
+			break;
+		case IDMAP_GID:
+			if (wksids[i].is_user == 1)
+				continue;
+			break;
+		case IDMAP_POSIXID:
+			break;
+		default:
+			assert(FALSE);
+		}
+
+		if (strcasecmp(wksids[i].winname, name) != 0)
+			continue;
+
+		if (!EMPTY_STRING(domain)) {
+			const char *dom;
+
+			if (wksids[i].domain != NULL) {
+				dom = wksids[i].domain;
+			} else {
+				dom = my_host_name;
+			}
+			if (strcasecmp(dom, domain) != 0)
+				continue;
+		}
+
+		/*
+		 * We have a Windows name, so ignore entries that are only
+		 * usable for mapping UNIX->Windows.  (Note:  the current
+		 * table does not have any such entries.)
+		 */
+		if (wksids[i].direction == IDMAP_DIRECTION_U2W)
+			continue;
+
+		return (&wksids[i]);
+	}
+
+	return (NULL);
+}
+
+/*
+ * Find a wksid entry for the specified SID, of the specified type.
+ *
+ * Ignore entries intended only for U2W use.
+ */
+const
+wksids_table_t *
+find_wksid_by_sid(const char *sid, int rid, int type)
+{
+	int i;
+
+	RDLOCK_CONFIG();
+	int len = strlen(_idmapdstate.cfg->pgcfg.machine_sid);
+	char my_machine_sid[len + 1];
+	(void) strcpy(my_machine_sid, _idmapdstate.cfg->pgcfg.machine_sid);
+	UNLOCK_CONFIG();
+
+	for (i = 0; i < NELEM(wksids); i++) {
+		int sidcmp;
+
+		/* Check to see if this entry yields the desired type */
+		switch (type) {
+		case IDMAP_UID:
+			if (wksids[i].is_user == 0)
+				continue;
+			break;
+		case IDMAP_GID:
+			if (wksids[i].is_user == 1)
+				continue;
+			break;
+		case IDMAP_POSIXID:
+			break;
+		default:
+			assert(FALSE);
+		}
+
+		if (wksids[i].sidprefix != NULL) {
+			sidcmp = strcasecmp(wksids[i].sidprefix, sid);
+		} else {
+			sidcmp = strcasecmp(my_machine_sid, sid);
+		}
+
+		if (sidcmp != 0)
+			continue;
+		if (wksids[i].rid != rid)
+			continue;
+
+		/*
+		 * We have a SID, so ignore entries that are only usable
+		 * for mapping UNIX->Windows.  (Note:  the current table
+		 * does not have any such entries.)
+		 */
+		if (wksids[i].direction == IDMAP_DIRECTION_U2W)
+			continue;
+
+		return (&wksids[i]);
+	}
+
+	return (NULL);
+}
+
+/*
+ * Find a wksid entry for the specified pid, of the specified type.
+ * Ignore entries that do not specify U2W mappings.
+ */
+const
+wksids_table_t *
+find_wksid_by_pid(uid_t pid, int is_user)
+{
+	int i;
+
+	if (pid == SENTINEL_PID)
+		return (NULL);
+
+	for (i = 0; i < NELEM(wksids); i++) {
+		if (wksids[i].pid == pid &&
+		    wksids[i].is_user == is_user &&
+		    (wksids[i].direction == IDMAP_DIRECTION_BI ||
+		    wksids[i].direction == IDMAP_DIRECTION_U2W)) {
+			return (&wksids[i]);
+		}
+	}
+	return (NULL);
+}
+
+/*
+ * It is probably a bug that both this and find_wksid_by_sid exist,
+ * but for now the distinction is primarily that one takes {machinesid,rid}
+ * and the other takes a full SID.
+ */
+const
+wksids_table_t *
+find_wk_by_sid(char *sid)
+{
+	int i;
+
+	RDLOCK_CONFIG();
+	int len = strlen(_idmapdstate.cfg->pgcfg.machine_sid);
+	char my_machine_sid[len + 1];
+	(void) strcpy(my_machine_sid, _idmapdstate.cfg->pgcfg.machine_sid);
+	UNLOCK_CONFIG();
+
+	for (i = 0; i < NELEM(wksids); i++) {
+		int len;
+		const char *prefix;
+		char *p;
+		unsigned long rid;
+
+		if (wksids[i].sidprefix == NULL)
+			prefix = my_machine_sid;
+		else
+			prefix = wksids[i].sidprefix;
+
+		len = strlen(prefix);
+
+		/*
+		 * Check to see whether the SID we're looking for starts
+		 * with this prefix, then a -, then a single RID, and it's
+		 * the right RID.
+		 */
+		if (strncasecmp(sid, prefix, len) != 0)
+			continue;
+		if (sid[len] != '-')
+			continue;
+		rid = strtoul(sid + len + 1, &p, 10);
+		if (*p != '\0')
+			continue;
+
+		if (rid != wksids[i].rid)
+			continue;
+
+		return (&wksids[i]);
+	}
+	return (NULL);
+}
--- a/usr/src/cmd/init/init.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/init/init.c	Mon Jul 20 13:07:46 2009 -0400
@@ -939,10 +939,10 @@
 
 	console(B_FALSE, "Requesting maintenance mode\n"
 	    "(See /lib/svc/share/README for additional information.)\n");
-	(void) sigset(SIGCLD, SIG_DFL);
+	(void) sighold(SIGCLD);
 	while ((su_process = efork(M_OFF, NULLPROC, NOCLEANUP)) == NO_ROOM)
 		(void) pause();
-	(void) sigset(SIGCLD, childeath);
+	(void) sigrelse(SIGCLD);
 	if (su_process == NULLPROC) {
 		int fd;
 
@@ -1394,7 +1394,7 @@
 	/*
 	 * Spawn a child process to execute this command.
 	 */
-	(void) sigset(SIGCLD, SIG_DFL);
+	(void) sighold(SIGCLD);
 	oprocess = process;
 	while ((process = efork(cmd->c_action, oprocess, modes)) == NO_ROOM)
 		(void) pause();
@@ -1453,7 +1453,7 @@
 
 	st_write();
 
-	(void) sigset(SIGCLD, childeath);
+	(void) sigrelse(SIGCLD);
 }
 
 /*
@@ -1890,10 +1890,10 @@
 {
 	struct PROC_TABLE	*process;
 
-	(void) sigset(SIGCLD, SIG_DFL);
+	(void) sighold(SIGCLD);
 	while ((process = efork(M_OFF, NULLPROC, 0)) == NO_ROOM)
 		(void) pause();
-	(void) sigset(SIGCLD, childeath);
+	(void) sigrelse(SIGCLD);
 
 	if (process == NULLPROC) {
 		/*
@@ -2080,7 +2080,7 @@
 			 * until after there has been an chance to check it.
 			 */
 			if (process = findpslot(&cmd)) {
-				(void) sigset(SIGCLD, SIG_DFL);
+				(void) sighold(SIGCLD);
 				(void) snprintf(svc_aux, SVC_AUX_SIZE,
 				    INITTAB_ENTRY_ID_STR_FORMAT, cmd.c_id);
 				(void) snprintf(init_svc_fmri, SVC_FMRI_SIZE,
@@ -2098,7 +2098,7 @@
 				    (NAMED|NOCLEANUP))) == NO_ROOM;
 				    /* CSTYLED */)
 					;
-				(void) sigset(SIGCLD, childeath);
+				(void) sigrelse(SIGCLD);
 
 				if (process == NULLPROC) {
 					maxfiles = ulimit(UL_GDESLIM, 0);
@@ -2355,22 +2355,14 @@
  * to do and return, otherwise the child will be waited for.
  */
 static void
-childeath_single()
+childeath_single(pid_t pid, int status)
 {
 	struct PROC_TABLE	*process;
 	struct pidlist		*pp;
-	pid_t			pid;
-	int			status;
 
 	/*
-	 * Perform wait to get the process id of the child that died and
-	 * then scan the process table to see if we are interested in
-	 * this process. NOTE: if a super-user sends the SIGCLD signal
-	 * to init, the following wait will not immediately return and
-	 * init will be inoperative until one of its child really does die.
+	 * Scan the process table to see if we are interested in this process.
 	 */
-	pid = wait(&status);
-
 	for (process = proc_table;
 	    (process < proc_table + num_proc); process++) {
 		if ((process->p_flags & (LIVING|OCCUPIED)) ==
@@ -2425,11 +2417,11 @@
 static void
 childeath(int signo)
 {
-	siginfo_t info;
-
-	while ((waitid(P_ALL, (id_t)0, &info, WEXITED|WNOHANG|WNOWAIT) == 0) &&
-	    info.si_pid != 0)
-		childeath_single();
+	pid_t pid;
+	int status;
+
+	while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+		childeath_single(pid, status);
 }
 
 static void
@@ -2448,13 +2440,8 @@
  * otherwise it searches for a free slot.  Regardless of how it was called,
  * it returns the pointer to the proc_table entry
  *
- * The SIGCLD handler is set to default (SIG_DFL) before calling efork().
- * This relies on the somewhat obscure SVR2 SIGCLD/SIG_DFL semantic
- * implied by the use of signal(3c).  While the meaning of SIG_DFL for
- * SIGCLD is nominally to ignore the signal, once the signal disposition
- * is set to childeath(), the kernel will post a SIGCLD if a child
- * exited during the period the disposition was SIG_DFL.  It acts more
- * like a signal block.
+ * The SIGCLD signal is blocked (held) before calling efork()
+ * and is unblocked (released) after efork() returns.
  *
  * Ideally, this should be rewritten to use modern signal semantics.
  */
@@ -2464,7 +2451,6 @@
 	pid_t	childpid;
 	struct PROC_TABLE *proc;
 	int		i;
-	void (*oldroutine)();
 	/*
 	 * Freshen up the proc_table, removing any entries for dead processes
 	 * that don't have NOCLEANUP set.  Perform the necessary accounting.
@@ -2494,13 +2480,13 @@
 		setimer(5);
 
 		/*
-		 * Wait for some children to die.  Since efork() is normally
-		 * called with SIGCLD in the default state, reset it to catch
-		 * so that child death signals can come in.
+		 * Wait for some children to die.  Since efork()
+		 * is always called with SIGCLD blocked, unblock
+		 * it here so that child death signals can come in.
 		 */
-		oldroutine = sigset(SIGCLD, childeath);
+		(void) sigrelse(SIGCLD);
 		(void) pause();
-		(void) sigset(SIGCLD, oldroutine);
+		(void) sighold(SIGCLD);
 		setimer(0);
 	}
 
@@ -2851,7 +2837,7 @@
 	 * '/', thus when a ' ', '\t', '\n', or '\0' is found, "ptr" will
 	 * point to the last element of the pathname.
 	 */
-	for (ptr = string; *string != ' ' && *string != '\t' && 
+	for (ptr = string; *string != ' ' && *string != '\t' &&
 	    *string != '\n' && *string != '\0'; string++) {
 		if (*string == '/')
 			ptr = string+1;
@@ -3765,7 +3751,7 @@
 	pid_t	pid;
 	short	status;
 
-	(void) sigset(SIGCLD, SIG_DFL);
+	(void) sighold(SIGCLD);
 	Gchild = 0;	/* Note - Safe to do this here since no SIGCLDs */
 	(void) sighold(SIGPOLL);
 	savep = p = Plhead;
@@ -3795,7 +3781,7 @@
 		p = p->pl_next;
 	}
 	(void) sigrelse(SIGPOLL);
-	(void) sigset(SIGCLD, childeath);
+	(void) sigrelse(SIGCLD);
 }
 
 
@@ -4420,8 +4406,8 @@
 		    "Template activation failed; not starting \"%s\" in "
 		    "proper contract.\n", cline);
 
-	/* Hold SIGCHLD so we can wait if necessary. */
-	(void) sighold(SIGCHLD);
+	/* Hold SIGCLD so we can wait if necessary. */
+	(void) sighold(SIGCLD);
 
 	while ((pid = fork()) < 0) {
 		if (errno == EPERM) {
@@ -4491,7 +4477,7 @@
 	if (old_ctid != 0)
 		(void) ct_pr_tmpl_set_transfer(tmpl, 0);
 
-	(void) sigrelse(SIGCHLD);
+	(void) sigrelse(SIGCLD);
 
 	return (0);
 }
--- a/usr/src/cmd/iscsi/iscsitgtd/mgmt_scf.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/iscsi/iscsitgtd/mgmt_scf.c	Mon Jul 20 13:07:46 2009 -0400
@@ -1119,15 +1119,19 @@
 }
 
 /*
- * this function tries to convert configuration in files into scf
- * it loads xml conf into node tree then dump them to scf with
- * mgmt_config_save2scf()
- * this function has 3 return values:
- * CONVERT_OK: successfully converted
- * CONVERT_INIT_NEW: configuration files dont exist, created a new scf entry
- * CONVERT_FAIL: some error occurred in conversion and no scf entry created.
- *               In this case, user have to check files manually and try
- *               conversion again.
+ * Convert legacy (XML) configuration files into an equivalent SCF
+ * representation.
+ *
+ * Read the XML from disk, translate the XML into a tree of nodes of
+ * type tgt_node_t, and write the in-memory tree to SCF's persistent
+ * data-store using mgmt_config_save2scf().
+ *
+ * Return Values:
+ * CONVERT_OK:	     successfully converted
+ * CONVERT_INIT_NEW: configuration files don't exist; created an SCF entry
+ * CONVERT_FAIL: some conversion error occurred; no SCF entry created.
+ *		 In this case, user has to manually check files and try
+ *		 conversion again.
  */
 convert_ret_t
 mgmt_convert_conf()
@@ -1146,17 +1150,21 @@
 	if (h == NULL)
 		return (CONVERT_FAIL);
 
-	/* check main config in pgroup iscsitgt */
+	/*
+	 * Check if the "iscsitgt" PropertyGroup has already been added
+	 * to the "iscsitgt" SMF Service.  If so, then we have already
+	 * converted the legacy configuration files (and there is no work
+	 * to do).
+	 */
 	if (scf_service_get_pg(h->t_service, "iscsitgt", h->t_pg) == 0) {
 		ret = CONVERT_OK;
 		goto done;
 	}
 
-	/* check the conf files */
 	if (access(config_file, R_OK) != 0) {
 		/*
-		 * if there is no configuration file, initialize
-		 * an empty scf entry
+		 * then the Main Config file is not present; initialize
+		 * SCF Properties to default values.
 		 */
 		if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) {
 			ret = CONVERT_INIT_NEW;
@@ -1210,6 +1218,8 @@
 		r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd, NULL, NULL, 0);
 
 	if (r != NULL) {
+		int is_target_config;
+
 		n = xmlTextReaderRead(r);
 		while (n == 1) {
 			if (tgt_node_process(r, &node) == False) {
@@ -1225,30 +1235,53 @@
 
 		main_config = node;
 
+		/*
+		 * Initialize the Base Directory (global) variable by
+		 * using the value specified in the XML_ELEMENT_BASEDIR
+		 * XML tag.  If a tag is not specified, use a default.
+		 */
 		(void) tgt_find_value_str(node, XML_ELEMENT_BASEDIR,
 		    &target_basedir);
 
 		if (target_basedir == NULL)
 			target_basedir = strdup(DEFAULT_TARGET_BASEDIR);
 
-		/* Now convert targets' config if possible */
-		if (xml_fd != -1)
+		if (xml_fd != -1) {
 			(void) close(xml_fd);
+			xml_fd = -1;
+		}
 		(void) xmlTextReaderClose(r);
 		xmlFreeTextReader(r);
 		xmlCleanupParser();
-		r = NULL;
-		xml_fd = -1;
-		node = NULL;
 
+		/*
+		 * If a Target Config file is present, read and translate
+		 * its XML representation into a tree of tgt_node_t.
+		 * Merge that tree with the tree of tgt_node_t rooted at
+		 * 'main_config'.  The merged tree will then be archived
+		 * using an SCF representation.
+		 */
 		(void) snprintf(path, MAXPATHLEN, "%s/%s",
 		    target_basedir, "config.xml");
 
-		if ((xml_fd = open(path, O_RDONLY)) >= 0)
+		if ((xml_fd = open(path, O_RDONLY)) >= 0) {
+			is_target_config = 1;
 			r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd,
 			    NULL, NULL, 0);
+		} else {
+			is_target_config = 0;
+			r = NULL;
+		}
 
 		if (r != NULL) {
+			/* then the Target Config file is available. */
+
+			node = NULL;
+
+			/*
+			 * Create a tree of tgt_node_t rooted at 'node' by
+			 * processing each XML Tag in the file.
+			 */
 			n = xmlTextReaderRead(r);
 			while (n == 1) {
 				if (tgt_node_process(r, &node) == False) {
@@ -1262,8 +1295,11 @@
 				goto done;
 			}
 
-			/* now combine main_config and node */
-			if (node) {
+			/*
+			 * Merge the tree at 'node' into the tree rooted at
+			 * 'main_config'.
+			 */
+			if (node != NULL) {
 				next = NULL;
 				while ((next = tgt_node_next(node,
 				    XML_ELEMENT_TARG, next)) != NULL) {
@@ -1272,59 +1308,77 @@
 				}
 				tgt_node_free(node);
 			}
+		}
 
-			if (mgmt_config_save2scf() != True) {
-				syslog(LOG_ERR, "Converting config failed");
-				if (xml_fd != -1)
-					(void) close(xml_fd);
-				(void) xmlTextReaderClose(r);
-				xmlFreeTextReader(r);
-				xmlCleanupParser();
-				ret = CONVERT_FAIL;
-				goto done;
+		/*
+		 * Iterate over the in-memory tree rooted at 'main_config'
+		 * and write a representation of the appropriate nodes to
+		 * SCF's persistent data-store.
+		 */
+		if (mgmt_config_save2scf() != True) {
+			syslog(LOG_ERR, "Converting config failed");
+			if (xml_fd != -1) {
+				(void) close(xml_fd);
+				xml_fd = -1;
 			}
+			(void) xmlTextReaderClose(r);
+			xmlFreeTextReader(r);
+			xmlCleanupParser();
+			ret = CONVERT_FAIL;
+			goto done;
+		}
 
-			/* Copy files into backup dir */
-			(void) snprintf(path, sizeof (path), "%s/backup",
-			    target_basedir);
-			if ((mkdir(path, 0755) == -1) && (errno != EEXIST)) {
-				syslog(LOG_ERR, "Creating backup dir failed");
-				ret = CONVERT_FAIL;
-				goto done;
-			}
-			backup(config_file, NULL);
+		/*
+		 * Move the configuration files into a well-known backup
+		 * directory.  This allows a user to restore their
+		 * configuration, if they choose.
+		 */
+		(void) snprintf(path, sizeof (path), "%s/backup",
+		    target_basedir);
+		if ((mkdir(path, 0755) == -1) && (errno != EEXIST)) {
+			syslog(LOG_ERR, "Creating backup dir failed");
+			ret = CONVERT_FAIL;
+			goto done;
+		}
+		/* Save the Main Config file. */
+		backup(config_file, NULL);
+
+		/* Save the Target Config file, if it was present. */
+		if (is_target_config != 0) {
 			(void) snprintf(path, MAXPATHLEN, "%s/%s",
 			    target_basedir, "config.xml");
 			backup(path, NULL);
-
+		}
 
-			while ((next = tgt_node_next(main_config,
-			    XML_ELEMENT_TARG, next)) != NULL) {
-				if (tgt_find_value_str(next, XML_ELEMENT_INAME,
-				    &target) == False) {
-					continue;
-				}
-				(void) snprintf(path, MAXPATHLEN, "%s/%s",
-				    target_basedir, target);
-				if (mgmt_convert_param(path, next)
-				    != True) {
-					ret = CONVERT_FAIL;
-					goto done;
-				}
-				free(target);
+		/*
+		 * For each tgt_node_t node in 'main_config' whose value is
+		 * an iSCSI Name as defined in the RFC (3720) standard (eg,
+		 * "iqn.1986..."), read its XML-encoded attributes from a
+		 * flat-file and write an equivalent representation to SCF's
+		 * data-store.
+		 */
+		while ((next = tgt_node_next(main_config,
+		    XML_ELEMENT_TARG, next)) != NULL) {
+			if (tgt_find_value_str(next, XML_ELEMENT_INAME,
+			    &target) == False) {
+				continue;
 			}
-
-			ret = CONVERT_OK;
-			syslog(LOG_NOTICE, "Conversion succeeded");
+			(void) snprintf(path, MAXPATHLEN, "%s/%s",
+			    target_basedir, target);
+			if (mgmt_convert_param(path, next)
+			    != True) {
+				ret = CONVERT_FAIL;
+				goto done;
+			}
+			free(target);
+		}
 
-			(void) xmlTextReaderClose(r);
-			xmlFreeTextReader(r);
-			xmlCleanupParser();
-		} else {
-			syslog(LOG_ERR, "Reading targets config failed");
-			ret = CONVERT_FAIL;
-			goto done;
-		}
+		ret = CONVERT_OK;
+		syslog(LOG_NOTICE, "Conversion succeeded");
+
+		(void) xmlTextReaderClose(r);
+		xmlFreeTextReader(r);
+		xmlCleanupParser();
 	} else {
 		syslog(LOG_ERR, "Reading main config failed");
 		ret = CONVERT_FAIL;
--- a/usr/src/cmd/mdb/intel/modules/Makefile	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/mdb/intel/modules/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -19,11 +19,12 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 SUBDIRS = mdb_kb \
 	generic_cpu \
-	amd_opteron
+	amd_opteron \
+	sata
 
 include ../../Makefile.subdirs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/intel/modules/sata/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include $(SRC)/Makefile.master
+SUBDIRS =		ia32
+$(BUILD64)SUBDIRS += 	$(MACH64)
+include ../../../Makefile.subdirs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/intel/modules/sata/amd64/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+MODULE = sata.so
+MDBTGT = kvm
+
+MODSRCS = sata.c
+
+include ../../../../../Makefile.cmd
+include ../../../../../Makefile.cmd.64
+include ../../../Makefile.amd64
+include ../../../../Makefile.module
+
+CPPFLAGS += -I$(SRC)/cmd/mdb/common
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/intel/modules/sata/ia32/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+MODULE = sata.so
+MDBTGT = kvm
+
+MODSRCS = sata.c
+
+include ../../../../../Makefile.cmd
+include ../../../Makefile.ia32
+include ../../../../Makefile.module
+
+CPPFLAGS += -I$(SRC)/cmd/mdb/common
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/intel/modules/sata/sata.c	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,286 @@
+/*
+ * 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 <sys/mdb_modapi.h>
+#include <mdb/mdb_ks.h>
+#include <sys/modctl.h>
+#include <note.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/ddidmareq.h>
+#include <sys/devops.h>
+#include <time.h>
+#include <sys/varargs.h>
+#include <sys/sata/sata_hba.h>
+
+/*
+ * SATA trace debug walker/dcmd code
+ */
+
+/*
+ * Initialize the sata_trace_dmsg_t walker by either using the given starting
+ * address, or reading the value of the kernel's sata_debug_rbuf pointer.
+ * We also allocate a sata_trace_dmsg_t for storage, and save this using the
+ * walk_data pointer.
+ */
+static int
+sata_dmsg_walk_i(mdb_walk_state_t *wsp)
+{
+	uintptr_t rbuf_addr;
+	sata_trace_rbuf_t rbuf;
+
+	if (wsp->walk_addr == NULL) {
+		if (mdb_readvar(&rbuf_addr, "sata_debug_rbuf") == -1) {
+			mdb_warn("failed to read 'sata_debug_rbuf'");
+			return (WALK_ERR);
+		}
+
+		if (mdb_vread(&rbuf, sizeof (sata_trace_rbuf_t), rbuf_addr)
+		    == -1) {
+			mdb_warn("failed to read sata_trace_rbuf_t at %p",
+			    rbuf_addr);
+			return (WALK_ERR);
+		}
+
+		wsp->walk_addr = (uintptr_t)(sata_trace_dmsg_t *)rbuf.dmsgh;
+	}
+
+	/*
+	 * Save ptr to head of ring buffer to prevent looping.
+	 */
+	wsp->walk_arg = (void *)wsp->walk_addr;
+	wsp->walk_data = mdb_alloc(sizeof (sata_trace_dmsg_t), UM_SLEEP);
+	return (WALK_NEXT);
+}
+
+/*
+ * At each step, read a sata_trace_dmsg_t into our private storage, and then
+ * invoke the callback function.  We terminate when we reach a NULL next
+ * pointer.
+ */
+static int
+sata_dmsg_walk_s(mdb_walk_state_t *wsp)
+{
+	int status;
+
+	if (wsp->walk_addr == NULL)
+		return (WALK_DONE);
+
+	if (mdb_vread(wsp->walk_data, sizeof (sata_trace_dmsg_t),
+	    wsp->walk_addr) == -1) {
+		mdb_warn("failed to read sata_trace_dmsg_t at %p",
+		    wsp->walk_addr);
+		return (WALK_ERR);
+	}
+
+	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
+	    wsp->walk_cbdata);
+
+	wsp->walk_addr =
+	    (uintptr_t)(((sata_trace_dmsg_t *)wsp->walk_data)->next);
+
+	/*
+	 * If we've looped then we're done.
+	 */
+	if (wsp->walk_addr == (uintptr_t)wsp->walk_arg)
+		wsp->walk_addr = NULL;
+
+	return (status);
+}
+
+/*
+ * The walker's fini function is invoked at the end of each walk.  Since we
+ * dynamically allocated a sata_trace_dmsg_t in sata_dmsg_walk_i, we must
+ * free it now.
+ */
+static void
+sata_dmsg_walk_f(mdb_walk_state_t *wsp)
+{
+	mdb_free(wsp->walk_data, sizeof (sata_trace_dmsg_t));
+}
+
+/*
+ * This routine is used by the sata_dmsg_dump dcmd to dump content of
+ * SATA trace ring buffer.
+ */
+int
+sata_dmsg_dump(sata_trace_dmsg_t *addr, int print_pathname, uint_t *printed)
+{
+	sata_trace_dmsg_t	dmsg, *dmsgh = addr;
+	struct dev_info		dev;
+	char			drivername[MODMAXNAMELEN];
+	char			pathname[MAXPATHLEN];
+	char			merge[1024];
+
+	while (addr != NULL) {
+		if (mdb_vread(&dmsg, sizeof (dmsg), (uintptr_t)addr) !=
+		    sizeof (dmsg)) {
+			mdb_warn("failed to read message pointer in kernel");
+			return (DCMD_ERR);
+		}
+
+		if (dmsg.dip != NULL) {
+			if ((mdb_vread(&dev, sizeof (struct dev_info),
+			    (uintptr_t)dmsg.dip)) == -1) {
+				(void) mdb_snprintf(merge, sizeof (merge),
+				    "[%Y:%03d:%03d:%03d] : %s",
+				    dmsg.timestamp.tv_sec,
+				    (int)dmsg.timestamp.tv_nsec/1000000,
+				    (int)(dmsg.timestamp.tv_nsec/1000)%1000,
+				    (int)dmsg.timestamp.tv_nsec%1000,
+				    dmsg.buf);
+			} else {
+				(void) mdb_devinfo2driver((uintptr_t)dmsg.dip,
+				    drivername, sizeof (drivername));
+				(void) mdb_snprintf(merge, sizeof (merge),
+				    "[%Y:%03d:%03d:%03d] %s%d: %s",
+				    dmsg.timestamp.tv_sec,
+				    (int)dmsg.timestamp.tv_nsec/1000000,
+				    (int)(dmsg.timestamp.tv_nsec/1000)%1000,
+				    (int)dmsg.timestamp.tv_nsec%1000,
+				    drivername,
+				    dev.devi_instance,
+				    dmsg.buf);
+
+				if (print_pathname == TRUE) {
+					(void) mdb_ddi_pathname(
+					    (uintptr_t)dmsg.dip, pathname,
+					    sizeof (pathname));
+					mdb_printf("\n[%s]", pathname);
+				}
+			}
+		} else {
+			(void) mdb_snprintf(merge, sizeof (merge),
+			    "[%Y:%03d:%03d:%03d] : %s",
+			    dmsg.timestamp.tv_sec,
+			    (int)dmsg.timestamp.tv_nsec/1000000,
+			    (int)(dmsg.timestamp.tv_nsec/1000)%1000,
+			    (int)dmsg.timestamp.tv_nsec%1000,
+			    dmsg.buf);
+		}
+
+		mdb_printf("%s", merge);
+
+		if (printed != NULL) {
+			(*printed)++;
+		}
+
+		if (((addr = dmsg.next) == NULL) || (dmsg.next == dmsgh)) {
+			break;
+		}
+	}
+
+	return (DCMD_OK);
+}
+
+/*
+ * 1. Process flag passed to sata_dmsg_dump dcmd.
+ * 2. Obtain SATA trace ring buffer pointer.
+ * 3. Pass SATA trace ring buffer pointer to sata_dmsg_dump()
+ *    to dump content of SATA trace ring buffer.
+ */
+int
+sata_rbuf_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+	sata_trace_rbuf_t	rbuf;
+	uint_t		printed = 0; /* have we printed anything? */
+	int		print_pathname = FALSE;
+	int		rval = DCMD_OK;
+
+	if (argc > 1) {
+		return (DCMD_USAGE);
+	}
+
+	if (mdb_getopts(argc, argv,
+	    'a', MDB_OPT_SETBITS, TRUE, &print_pathname) != argc) {
+		return (DCMD_USAGE);
+	}
+
+	/*
+	 * If ring buffer address not provided try to obtain
+	 * it using sata_debug_rbuf global.
+	 */
+	if ((addr == NULL) || !(flags & DCMD_ADDRSPEC)) {
+		if (mdb_readvar(&addr, "sata_debug_rbuf") == -1) {
+			mdb_warn("Failed to read 'sata_debug_rbuf'.");
+			return (DCMD_ERR);
+		}
+	}
+
+	if (mdb_vread(&rbuf, sizeof (rbuf), addr) != sizeof (rbuf)) {
+		mdb_warn("Failed to read ring buffer in kernel.");
+		return (DCMD_ERR);
+	}
+
+	if (rbuf.dmsgh == NULL) {
+		mdb_printf("The sata trace ring buffer is empty.\n");
+		return (DCMD_OK);
+	}
+
+	rval = sata_dmsg_dump((sata_trace_dmsg_t *)rbuf.dmsgh,
+	    print_pathname, &printed);
+
+	if (rval != DCMD_OK) {
+		return (rval);
+	}
+
+	if (printed == 0) {
+		mdb_warn("Failed to read sata trace ring buffer.");
+		return (DCMD_ERR);
+	}
+
+	return (rval);
+}
+
+/*
+ * MDB module linkage information:
+ *
+ * We declare a list of structures describing our dcmds, a list of structures
+ * describing our walkers, and a function named _mdb_init to return a pointer
+ * to our module information.
+ */
+
+static const mdb_dcmd_t dcmds[] = {
+	{ "sata_dmsg_dump", "[-a]", "Dump sata trace debug messages",
+	    sata_rbuf_dump },
+	{ NULL }
+};
+
+static const mdb_walker_t walkers[] = {
+	{ "sata_dmsg",
+	    "walk ring buffer containing sata trace debug messages",
+	    sata_dmsg_walk_i, sata_dmsg_walk_s, sata_dmsg_walk_f },
+	{ NULL }
+};
+
+static const mdb_modinfo_t modinfo = {
+	MDB_API_VERSION, dcmds, walkers
+};
+
+const mdb_modinfo_t *
+_mdb_init(void)
+{
+	return (&modinfo);
+}
--- a/usr/src/cmd/print/selector/Makefile	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/print/selector/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -19,21 +19,22 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
 include ../../Makefile.cmd
 
 SBINPROG =	print-service
+BINPROG =	desktop-print-management-applet
 LPBINLINKS =	lp lpstat cancel enable disable
 LPRBINLINKS =	lpr lpq lprm lpc
-DESKTOPLINKS =  desktop-print-management desktop-print-management-applet
-DESKTOPLINKS += desktop-print-management-prefs
+DESKTOPLINKS =  desktop-print-management desktop-print-management-prefs
 BINLINKS =	$(LPBINLINKS) $(LPRBINLINKS) $(DESKTOPLINKS)
 SBINLINKS =	accept reject lpmove lpadmin
 
 ROOTUSRSBINPROG =	$(SBINPROG:%=$(ROOTUSRSBIN)/%)
+ROOTUSRBINPROG =	$(BINPROG:%=$(ROOTBIN)/%)
 ROOTUSRBINLINKS =	$(BINLINKS:%=$(ROOTBIN)/%)
 ROOTUSRSBINLINKS =	$(SBINLINKS:%=$(ROOTUSRSBIN)/%)
 
@@ -50,5 +51,5 @@
 
 all check clean clobber lint:
 
-install:	$(ROOTUSRSBINPROG) $(ROOTUSRBINLINKS) $(ROOTUSRSBINLINKS)
+install:	$(ROOTUSRSBINPROG) $(ROOTUSRBINPROG) $(ROOTUSRBINLINKS) $(ROOTUSRSBINLINKS)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/print/selector/desktop-print-management-applet	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,81 @@
+#!/usr/perl5/bin/perl
+#
+# 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.
+#
+#
+
+my $SVC_CUPS_SCHEDULER = 'cups/scheduler';
+my $SVCPROP = '/usr/bin/svcprop';
+
+sub svcprop {
+        local ($fmri, $property) = @_;
+        my $FH;
+
+        open($FH, "$SVCPROP -C -p $property $fmri 2>/dev/null |");
+        $result = <$FH>;
+        close($FH);
+
+        return ($result);
+}
+
+sub print_service {
+        my $service;
+
+        $service = svcprop("$SVC_CUPS_SCHEDULER:default", "general/active");
+        ($service =~ /true/) && ($service = 'cups') || ($service = 'lp');
+
+        return ($service);
+}
+
+sub kill_running_applets {
+        # cups applet daemon
+        system("pkill -f '/system-config-printer/applet.py'");
+        # lp applet daemon
+        system("pkill ospm-applet");
+}
+
+my $pid;
+
+sub handle_signal {
+        kill_running_applets ();
+}
+$SIG{USR1} = \&handle_signal;
+
+
+$SIG{CHLD} = 'IGNORE';
+my $service;
+$service =  print_service();
+$pid = fork();
+if ($pid) {
+        waitpid($pid, 0);
+        exec('/usr/bin/desktop-print-management-applet');
+}
+else {
+        if ($service eq 'lp') {
+                exec('/usr/lib/lp/bin/desktop-print-management-applet');
+        }
+        else {
+                exec('/usr/lib/cups/bin/desktop-print-management-applet');
+        }
+}
+
--- a/usr/src/cmd/print/selector/print-service	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/print/selector/print-service	Mon Jul 20 13:07:46 2009 -0400
@@ -19,10 +19,9 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
 #
 
 #
@@ -242,6 +241,7 @@
 		svcadm("enable", $SVC_CUPS_SCHEDULER, $SVC_CUPS_LPD);
 		svccfg("cups/scheduler:default",
 			"setprop general/active = boolean: true");
+		system("pkill -USR1 -f '/desktop-print-management-applet'"); 
 	} else {
 		print("disabling CUPS services...\n");
 		svcadm("disable", $SVC_CUPS_SCHEDULER, $SVC_CUPS_LPD);
@@ -251,6 +251,7 @@
 		(-f '/etc/lp/printers.conf') &&
 			rename('/etc/lp/printers.conf', '/etc/printers.conf');
 		svccfg("cups/scheduler:default", "delprop general/active");
+		system("pkill -USR1 -f '/desktop-print-management-applet'"); 
 	}
 
 	# import the new print queue configuration (if migrating)
--- a/usr/src/cmd/psrset/psrset.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/psrset/psrset.c	Mon Jul 20 13:07:46 2009 -0400
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * psrset - create and manage processor sets
  */
@@ -44,7 +41,6 @@
 #include <procfs.h>
 #include <libproc.h>
 #include <stdarg.h>
-#include <priv.h>
 
 #if !defined(TEXT_DOMAIN)		/* should be defined by cc -D */
 #define	TEXT_DOMAIN 	"SYS_TEST"	/* Use this only if it wasn't */
@@ -107,14 +103,10 @@
 	exit(ERR_FAIL);
 }
 
-static prpriv_t *orig_priv;
-
 static struct ps_prochandle *
 grab_proc(id_t pid)
 {
 	int ret;
-	prpriv_t *new_priv;
-	priv_set_t *eff_set, *perm_set;
 	struct ps_prochandle *Pr;
 
 	if ((Pr = Pgrab(pid, 0, &ret)) == NULL) {
@@ -124,66 +116,6 @@
 		return (NULL);
 	}
 
-	/*
-	 * If target process does not have required PRIV_SYS_RES_CONFIG
-	 * privilege, assign it temporarily to that process' effective
-	 * and permitted sets so that it can call pset_bind(2).
-	 */
-	if ((new_priv = proc_get_priv(pid)) == NULL) {
-		warn(gettext("unable to get privileges for process %d: %s\n"),
-		    pid, strerror(errno));
-		errors = ERR_FAIL;
-		Prelease(Pr, 0);
-		return (NULL);
-	}
-
-	if (Pcreate_agent(Pr) != 0) {
-		warn(gettext("cannot control process %d\n"), (int)pid);
-		errors = ERR_FAIL;
-		Prelease(Pr, 0);
-		free(new_priv);
-		return (NULL);
-	}
-
-	eff_set = (priv_set_t *)&new_priv->pr_sets[new_priv->pr_setsize *
-	    priv_getsetbyname(PRIV_EFFECTIVE)];
-	perm_set = (priv_set_t *)&new_priv->pr_sets[new_priv->pr_setsize *
-	    priv_getsetbyname(PRIV_PERMITTED)];
-	if (!priv_ismember(eff_set, PRIV_SYS_RES_CONFIG)) {
-		/*
-		 * Save original privileges
-		 */
-		if ((orig_priv = proc_get_priv(pid)) == NULL) {
-			warn(gettext("unable to get privileges for "
-			    "process %d: %s\n"), pid, strerror(errno));
-			errors = ERR_FAIL;
-			Pdestroy_agent(Pr);
-			Prelease(Pr, 0);
-			free(new_priv);
-			return (NULL);
-		}
-		(void) priv_addset(eff_set, PRIV_SYS_RES_CONFIG);
-		(void) priv_addset(perm_set, PRIV_SYS_RES_CONFIG);
-		/*
-		 * We don't want to leave a process with elevated privileges,
-		 * so make sure the process dies if we exit unexpectedly.
-		 */
-		if (Psetflags(Pr, PR_KLC) != 0 ||
-		    Psetpriv(Pr, new_priv) != 0) {
-			warn(gettext("unable to set process privileges for "
-			    "process %d: %s\n"), pid, strerror(errno));
-			(void) Punsetflags(Pr, PR_KLC);
-			free(new_priv);
-			free(orig_priv);
-			Pdestroy_agent(Pr);
-			Prelease(Pr, 0);
-			orig_priv = NULL;
-			errors = ERR_FAIL;
-			return (NULL);
-		}
-	}
-	free(new_priv);
-
 	return (Pr);
 }
 
@@ -192,28 +124,6 @@
 {
 	if (Pr == NULL)
 		return;
-	if (orig_priv != NULL) {
-		if (Psetpriv(Pr, orig_priv) != 0) {
-			/*
-			 * If this fails, we can't leave a process with
-			 * elevated privileges, so we have to release the
-			 * process from libproc, knowing that it will
-			 * be killed (since we set the PR_KLC flag).
-			 */
-			Pdestroy_agent(Pr);
-			warn(gettext("cannot relinquish privileges for "
-			    "process %d.  The process was killed\n"),
-			    Ppsinfo(Pr)->pr_pid);
-			errors = ERR_FAIL;
-		} else {
-			(void) Punsetflags(Pr, PR_KLC);
-			Pdestroy_agent(Pr);
-		}
-		free(orig_priv);
-		orig_priv = NULL;
-	} else {
-		Pdestroy_agent(Pr);
-	}
 	Prelease(Pr, 0);
 }
 
@@ -351,29 +261,30 @@
 	if (old == PS_NONE) {
 		if (new == PS_NONE)
 			(void) printf(gettext("%s id %s: was not bound, "
-				"now not bound\n"), proclwp, pidstr);
+			    "now not bound\n"), proclwp, pidstr);
 		else
 			(void) printf(gettext("%s id %s: was not bound, "
-				"now %d\n"), proclwp, pidstr, new);
+			    "now %d\n"), proclwp, pidstr, new);
 	} else {
 		if (new == PS_NONE)
 			(void) printf(gettext("%s id %s: was %d, "
-				"now not bound\n"), proclwp, pidstr, old);
+			    "now not bound\n"), proclwp, pidstr, old);
 		else
 			(void) printf(gettext("%s id %s: was %d, "
-				"now %d\n"), proclwp, pidstr, old, new);
+			    "now %d\n"), proclwp, pidstr, old, new);
 	}
 }
 
 static void
-bind_lwp(struct ps_prochandle *Pr, id_t pid, id_t lwpid, psetid_t pset)
+bind_lwp(id_t pid, id_t lwpid, psetid_t pset)
 {
 	psetid_t old_pset;
 
-	if (pr_pset_bind(Pr, pset, P_LWPID, lwpid, &old_pset) < 0) {
+	if (pset_bind_lwp(pset, lwpid, pid, &old_pset) != 0) {
 		bind_err(pset, pid, lwpid, errno);
 		errors = ERR_FAIL;
-	} else {
+	}
+	if (errors != ERR_FAIL) {
 		if (qflag)
 			query_out(pid, lwpid, old_pset);
 		else
@@ -621,22 +532,22 @@
 usage(void)
 {
 	(void) fprintf(stderr, gettext(
-		"usage: \n"
-		"\t%1$s -c [-F] [processor_id ...]\n"
-		"\t%1$s -d processor_set_id ...\n"
-		"\t%1$s -n processor_set_id\n"
-		"\t%1$s -f processor_set_id\n"
-		"\t%1$s -e processor_set_id command [argument(s)...]\n"
-		"\t%1$s -a [-F] processor_set_id processor_id ...\n"
-		"\t%1$s -r [-F] processor_id ...\n"
-		"\t%1$s -p [processorid ...]\n"
-		"\t%1$s -b processor_set_id pid[/lwpids] ...\n"
-		"\t%1$s -u pid[/lwpids] ...\n"
-		"\t%1$s -q [pid[/lwpids] ...]\n"
-		"\t%1$s -U [processor_set_id] ...\n"
-		"\t%1$s -Q [processor_set_id] ...\n"
-		"\t%1$s [-i] [processor_set_id ...]\n"),
-		progname);
+	    "usage: \n"
+	    "\t%1$s -c [-F] [processor_id ...]\n"
+	    "\t%1$s -d processor_set_id ...\n"
+	    "\t%1$s -n processor_set_id\n"
+	    "\t%1$s -f processor_set_id\n"
+	    "\t%1$s -e processor_set_id command [argument(s)...]\n"
+	    "\t%1$s -a [-F] processor_set_id processor_id ...\n"
+	    "\t%1$s -r [-F] processor_id ...\n"
+	    "\t%1$s -p [processorid ...]\n"
+	    "\t%1$s -b processor_set_id pid[/lwpids] ...\n"
+	    "\t%1$s -u pid[/lwpids] ...\n"
+	    "\t%1$s -q [pid[/lwpids] ...]\n"
+	    "\t%1$s -U [processor_set_id] ...\n"
+	    "\t%1$s -Q [processor_set_id] ...\n"
+	    "\t%1$s [-i] [processor_set_id ...]\n"),
+	    progname);
 	return (ERR_USAGE);
 }
 
@@ -699,7 +610,7 @@
 			continue;
 		found++;
 		if (bflag || uflag)
-			bind_lwp(Pr, pid, lwp->pr_lwpid, pset);
+			bind_lwp(pid, lwp->pr_lwpid, pset);
 		else if (binding != PBIND_NONE)
 			query_out(pid, lwp->pr_lwpid, binding);
 	}
@@ -960,7 +871,7 @@
 			pid = (id_t)strtol(*argv, &errptr, 10);
 			if (errno != 0 ||
 			    (errptr != NULL && *errptr != '\0' &&
-				*errptr != '/')) {
+			    *errptr != '/')) {
 				warn(gettext("invalid process ID: %s\n"),
 				    *argv);
 				continue;
--- a/usr/src/cmd/stmfadm/stmfadm.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/stmfadm/stmfadm.c	Mon Jul 20 13:07:46 2009 -0400
@@ -126,13 +126,15 @@
 #define	COMPANY_ID		    "OUI"
 #define	BLOCK_SIZE		    "BLK"
 #define	SERIAL_NUMBER		    "SERIAL"
+#define	MGMT_URL		    "MGMT-URL"
 
 #define	MODIFY_HELP "\n"\
 "Description: Modify properties of a logical unit. \n" \
 "Valid properties for -p, --lu-prop are: \n" \
-"     alias - alias for logical unit (up to 255 chars)\n" \
-"     wcd   - write cache disabled (true, false)\n" \
-"     wp    - write protect (true, false)\n\n" \
+"     alias    - alias for logical unit (up to 255 chars)\n" \
+"     mgmt-url - Management URL address\n" \
+"     wcd      - write cache disabled (true, false)\n" \
+"     wp       - write protect (true, false)\n\n" \
 "-f alters the meaning of the operand to be a file name\n" \
 "rather than a LU name. This allows for modification\n" \
 "of a logical unit that is not yet imported into stmf\n"
@@ -140,17 +142,18 @@
 #define	CREATE_HELP "\n"\
 "Description: Create a logical unit. \n" \
 "Valid properties for -p, --lu-prop are: \n" \
-"     alias - alias for logical unit (up to 255 chars)\n" \
-"     blk   - block size in bytes in 2^n\n" \
-"     guid  - 32 ascii hex characters in NAA format \n" \
-"     meta  - separate meta data file name\n" \
-"     oui   - organizational unique identifier\n" \
-"             6 ascii hex characters of valid format\n" \
-"     pid   - product identifier (up to 16 chars)\n" \
-"     serial- serial number (up to 252 chars)\n" \
-"     vid   - vendor identifier (up to 8 chars)\n" \
-"     wp    - write protect (true, false)\n" \
-"     wcd   - write cache disabled (true, false)\n"
+"     alias    - alias for logical unit (up to 255 chars)\n" \
+"     blk      - block size in bytes in 2^n\n" \
+"     guid     - 32 ascii hex characters in NAA format \n" \
+"     meta     - separate meta data file name\n" \
+"     mgmt-url - Management URL address\n" \
+"     oui      - organizational unique identifier\n" \
+"                6 ascii hex characters of valid format\n" \
+"     pid      - product identifier (up to 16 chars)\n" \
+"     serial   - serial number (up to 252 chars)\n" \
+"     vid      - vendor identifier (up to 8 chars)\n" \
+"     wcd      - write cache disabled (true, false)\n" \
+"     wp       - write protect (true, false)\n"
 #define	ADD_VIEW_HELP "\n"\
 "Description: Add a view entry to a logical unit. \n" \
 "A view entry is comprised of three elements; the \n" \
@@ -991,14 +994,7 @@
 		switch (options->optval) {
 			case 'p':
 				prop = strtok_r(options->optarg, "=", &lasts);
-				if ((propVal = strtok_r(NULL, "=", &lasts))
-				    == NULL) {
-					(void) fprintf(stderr, "%s: %s: %s\n",
-					    cmdName, options->optarg,
-					gettext("invalid property specifier"
-					    "- prop=val\n"));
-					return (1);
-				}
+				propVal = strtok_r(NULL, "=", &lasts);
 				ret = convertCharToPropId(prop, &propId);
 				if (ret != 0) {
 					(void) fprintf(stderr, "%s: %s: %s\n",
@@ -1007,8 +1003,22 @@
 					    prop);
 					return (1);
 				}
-				if (callModify(fname, &inGuid, propId, propVal,
-				    prop) != 0) {
+				if (propVal ==  NULL &&
+				    propId != STMF_LU_PROP_MGMT_URL) {
+					(void) fprintf(stderr, "%s: %s: %s\n",
+					    cmdName, options->optarg,
+					    gettext("invalid property specifier"
+					    "- prop=val\n"));
+					return (1);
+				}
+				if (propVal ==  NULL) {
+					ret = callModify(fname, &inGuid, propId,
+					    "", prop);
+				} else {
+					ret = callModify(fname, &inGuid, propId,
+					    propVal, prop);
+				}
+				if (ret != 0) {
 					return (1);
 				}
 				break;
@@ -1270,6 +1280,8 @@
 		*propId = STMF_LU_PROP_COMPANY_ID;
 	} else if (strcasecmp(prop, META_FILE) == 0) {
 		*propId = STMF_LU_PROP_META_FILENAME;
+	} else if (strcasecmp(prop, MGMT_URL) == 0) {
+		*propId = STMF_LU_PROP_MGMT_URL;
 	} else {
 		return (1);
 	}
@@ -2092,6 +2104,18 @@
 		ret++;
 	}
 
+	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_MGMT_URL, propVal,
+	    &propValSize);
+	(void) printf(PROPS_FORMAT, "Management URL");
+	if (stmfRet == STMF_STATUS_SUCCESS) {
+		(void) printf("%s\n", propVal);
+	} else if (stmfRet == STMF_ERROR_NO_PROP) {
+		(void) printf("not set\n");
+	} else {
+		(void) printf("<error retrieving property>\n");
+		ret++;
+	}
+
 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_VID, propVal,
 	    &propValSize);
 	(void) printf(PROPS_FORMAT, "Vendor ID");
--- a/usr/src/cmd/svc/profile/generic_limited_net.xml	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/svc/profile/generic_limited_net.xml	Mon Jul 20 13:07:46 2009 -0400
@@ -169,7 +169,7 @@
     <instance name='default' enabled='false' />
   </service>
 
-  <service name='application/management/sma' version='1' type='service'>
+  <service name='application/management/net-snmp' version='1' type='service'>
     <instance name='default' enabled='false' />
   </service>
   <service name='application/management/seaport' version='1' type='service'>
--- a/usr/src/cmd/svc/profile/generic_open.xml	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/svc/profile/generic_open.xml	Mon Jul 20 13:07:46 2009 -0400
@@ -140,7 +140,7 @@
     <instance name='default' enabled='true'/>
   </service>
 
-  <service name='application/management/sma' version='1' type='service'>
+  <service name='application/management/net-snmp' version='1' type='service'>
     <instance name='default' enabled='true' />
   </service>
   <service name='application/management/seaport' version='1' type='service'>
--- a/usr/src/cmd/svr4pkg/libinst/pkgdbmerg.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/svr4pkg/libinst/pkgdbmerg.c	Mon Jul 20 13:07:46 2009 -0400
@@ -99,7 +99,7 @@
 static int	do_like_ent(VFP_T *vfpo, struct cfextra *el_ent,
 		    struct cfent *cf_ent, int ctrl);
 static int	do_new_ent(VFP_T *vfpo, struct cfextra *el_ent, int ctrl);
-static int	typechg(struct cfent *el_ent, struct cfent *cf_ent,
+static int	typechg(struct cfent *el_ent, char *curftype,
 		    struct mergstat *mstat);
 
 static void	set_change(struct cfextra *el_ent);
@@ -549,6 +549,40 @@
 		 * about this later. Note that noconflict means NO conflict
 		 * at the file level. Even rogue files count.
 		 */
+		char myftype = '?';
+		int n = 0;
+
+		/* Get the existing file type on disk */
+		eval_ftype(el_ent->server_path, el_ent->cf_ent.ftype, &myftype);
+
+		/* Do the right thing if types are different */
+		n = typechg(&(el_ent->cf_ent), &myftype, &(el_ent->mstat));
+		switch (n) {
+			case TYPE_OK:
+					break;
+
+			/* This is an allowable change. */
+			case TYPE_WARNING:
+					el_ent->mstat.contchg = 1;
+					break;
+
+			/* Not allowed, but leaving it as is is OK. */
+			case TYPE_IGNORED:
+					break;
+
+			/* Future analysis will reveal if this is OK. */
+			case TYPE_REPLACE:
+					el_ent->mstat.replace = 1;
+					break;
+
+			/* Kill it before it does any damage. */
+			case TYPE_FATAL:
+					logerr(gettext(MSG_TYPE_ERR));
+					quit(99);
+
+			default:
+				break;
+		}
 		el_ent->mstat.shared = 1;
 		el_ent->mstat.rogue = 1;
 		set_change(el_ent);
@@ -725,20 +759,20 @@
  *	TYPE_FATAL	something awful happened
  */
 static int
-typechg(struct cfent *el_ent, struct cfent *cf_ent, struct mergstat *mstat)
+typechg(struct cfent *el_ent, char *curftype, struct mergstat *mstat)
 {
 	int	i, etype, itype, retcode;
 
 	/* If they are identical, return OK */
-	if (cf_ent->ftype == el_ent->ftype)
+	if (*curftype == el_ent->ftype)
 		return (TYPE_OK);
 
 	/*
 	 * If package database entry is ambiguous, set it to the new entity's
 	 * ftype
 	 */
-	if (cf_ent->ftype == BADFTYPE) {
-		cf_ent->ftype = el_ent->ftype;
+	if (*curftype == BADFTYPE) {
+		*curftype = el_ent->ftype;
 		return (TYPE_OK); /* do nothing; not really different */
 	}
 
@@ -751,7 +785,7 @@
 	 * exclusive directory, this is very dangerous. We will continue, but
 	 * we will deny the conversion.
 	 */
-	if (el_ent->ftype == 'x' && cf_ent->ftype == 'd') {
+	if (el_ent->ftype == 'x' && *curftype == 'd') {
 		logerr(gettext(WRN_TOEXCL), el_ent->path);
 		return (TYPE_IGNORED);
 	}
@@ -768,7 +802,7 @@
 
 	/* Set itype to that in the package database. */
 	for (i = 0; types[i]; ++i) {
-		if (strchr(types[i], cf_ent->ftype)) {
+		if (strchr(types[i], *curftype)) {
 			itype = i+1;
 			break;
 		}
@@ -792,36 +826,36 @@
 
 	/* allow change, but warn user of possible problems */
 	switch (itype) {
-	    case 1:
-		logerr(gettext(WRN_NOTFILE), el_ent->path);
-		break;
+		case 1:
+			logerr(gettext(WRN_NOTFILE), el_ent->path);
+			break;
 
-	    case 2:
-		logerr(gettext(WRN_NOTSYMLN), el_ent->path);
-		break;
+		case 2:
+			logerr(gettext(WRN_NOTSYMLN), el_ent->path);
+			break;
 
-	    case 3:
-		logerr(gettext(WRN_NOTLINK), el_ent->path);
-		break;
+		case 3:
+			logerr(gettext(WRN_NOTLINK), el_ent->path);
+			break;
 
-	    case 4:
-		logerr(gettext(WRN_NOTDIR), el_ent->path);
-		break;
+		case 4:
+			logerr(gettext(WRN_NOTDIR), el_ent->path);
+			break;
 
-	    case 5:
-		logerr(gettext(WRN_NOTCHAR), el_ent->path);
-		break;
+		case 5:
+			logerr(gettext(WRN_NOTCHAR), el_ent->path);
+			break;
 
-	    case 6:
-		logerr(gettext(WRN_NOTBLOCK), el_ent->path);
-		break;
+		case 6:
+			logerr(gettext(WRN_NOTBLOCK), el_ent->path);
+			break;
 
-	    case 7:
-		logerr(gettext(WRN_NOTPIPE), el_ent->path);
-		break;
+		case 7:
+			logerr(gettext(WRN_NOTPIPE), el_ent->path);
+			break;
 
-	    default:
-		break;
+		default:
+			break;
 	}
 	return (retcode);
 }
@@ -867,7 +901,8 @@
 	 * can't figure it 'til later (d -> s) or fatal (a hook for later).
 	 */
 	if (cf_ent->ftype != el_ent->cf_ent.ftype) {
-		n = typechg(&(el_ent->cf_ent), cf_ent, &(el_ent->mstat));
+		n = typechg(&(el_ent->cf_ent), &(cf_ent->ftype),
+		    &(el_ent->mstat));
 
 		switch (n) {
 		    case TYPE_OK:
--- a/usr/src/cmd/zic/README	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/zic/README	Mon Jul 20 13:07:46 2009 -0400
@@ -9,7 +9,7 @@
 The zoneinfo files track the Olson public source provided at
 ftp://elsie.nci.nih.gov/pub/, therefore zoneinfo files may be added and
 removed as the Solaris source is updated.  The current Solaris release of
-the zoneinfo files is based on tzdata2009i.tar.gz.
+the zoneinfo files is based on tzdata2009j.tar.gz.
 
 The /usr/share/lib/zoneinfo/GMT[+-]* timezones listed below have been
 removed from the release.  Replace usage of the
--- a/usr/src/cmd/zic/asia	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/zic/asia	Mon Jul 20 13:07:46 2009 -0400
@@ -1,5 +1,5 @@
 # <pre>
-# @(#)asia	8.34
+# @(#)asia	8.35
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
@@ -165,9 +165,12 @@
 # http://www.timeanddate.com/news/time/bangladesh-daylight-saving-2009.html
 # </a>
 
-# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
-Rule	Bang	2009	only	-	Jan	1	0:00	0	-
-Rule	Bang	2009	only	-	Jun	20	0:00	1:00	S
+# From A. N. M. Kamrus Saadat (2009-06-15):
+# Finally we've got the official mail regarding DST start time where DST start 
+# time is mentioned as Jun 19 2009, 23:00 from BTRC (Bangladesh 
+# Telecommunication Regulatory Commission). 
+#
+# No DST end date has been announced yet.
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Dhaka	6:01:40 -	LMT	1890
@@ -176,8 +179,8 @@
 			5:30	-	IST	1942 Sep
 			6:30	-	BURT	1951 Sep 30
 			6:00	-	DACT	1971 Mar 26 # Dacca Time
-			6:00	-	BDT	2009 # Bangladesh Time
-			6:00	Bang	BD%sT
+			6:00	-	BDT	2009 Jun 19 23:00 # Bangladesh Time
+			6:00	1:00	BDST
 
 # Bhutan
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
--- a/usr/src/cmd/zoneadmd/zcons.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/zoneadmd/zcons.c	Mon Jul 20 13:07:46 2009 -0400
@@ -108,7 +108,6 @@
 
 #include <syslog.h>
 #include <sys/modctl.h>
-#include <sys/fs/sdev_node.h>
 
 #include "zoneadmd.h"
 
--- a/usr/src/cmd/zpool/zpool_main.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/zpool/zpool_main.c	Mon Jul 20 13:07:46 2009 -0400
@@ -3540,6 +3540,7 @@
 		(void) printf(gettext(" 14  passthrough-x aclinherit\n"));
 		(void) printf(gettext(" 15  user/group space accounting\n"));
 		(void) printf(gettext(" 16  stmf property support\n"));
+		(void) printf(gettext(" 17  Triple-parity RAID-Z\n"));
 		(void) printf(gettext("For more information on a particular "
 		    "version, including supported releases, see:\n\n"));
 		(void) printf("http://www.opensolaris.org/os/community/zfs/"
--- a/usr/src/cmd/zpool/zpool_vdev.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/zpool/zpool_vdev.c	Mon Jul 20 13:07:46 2009 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -67,6 +67,7 @@
 #include <libdiskmgt.h>
 #include <libintl.h>
 #include <libnvpair.h>
+#include <limits.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
@@ -1093,19 +1094,34 @@
 }
 
 static const char *
-is_grouping(const char *type, int *mindev)
+is_grouping(const char *type, int *mindev, int *maxdev)
 {
-	if (strcmp(type, "raidz") == 0 || strcmp(type, "raidz1") == 0) {
+	if (strncmp(type, "raidz", 5) == 0) {
+		const char *p = type + 5;
+		char *end;
+		long nparity;
+
+		if (*p == '\0') {
+			nparity = 1;
+		} else if (*p == '0') {
+			return (NULL); /* no zero prefixes allowed */
+		} else {
+			errno = 0;
+			nparity = strtol(p, &end, 10);
+			if (errno != 0 || nparity < 1 || nparity >= 255 ||
+			    *end != '\0')
+				return (NULL);
+		}
+
 		if (mindev != NULL)
-			*mindev = 2;
+			*mindev = nparity + 1;
+		if (maxdev != NULL)
+			*maxdev = 255;
 		return (VDEV_TYPE_RAIDZ);
 	}
 
-	if (strcmp(type, "raidz2") == 0) {
-		if (mindev != NULL)
-			*mindev = 3;
-		return (VDEV_TYPE_RAIDZ);
-	}
+	if (maxdev != NULL)
+		*maxdev = INT_MAX;
 
 	if (strcmp(type, "mirror") == 0) {
 		if (mindev != NULL)
@@ -1144,7 +1160,7 @@
 construct_spec(int argc, char **argv)
 {
 	nvlist_t *nvroot, *nv, **top, **spares, **l2cache;
-	int t, toplevels, mindev, nspares, nlogs, nl2cache;
+	int t, toplevels, mindev, maxdev, nspares, nlogs, nl2cache;
 	const char *type;
 	uint64_t is_log;
 	boolean_t seen_logs;
@@ -1166,7 +1182,7 @@
 		 * If it's a mirror or raidz, the subsequent arguments are
 		 * its leaves -- until we encounter the next mirror or raidz.
 		 */
-		if ((type = is_grouping(argv[0], &mindev)) != NULL) {
+		if ((type = is_grouping(argv[0], &mindev, &maxdev)) != NULL) {
 			nvlist_t **child = NULL;
 			int c, children = 0;
 
@@ -1223,7 +1239,7 @@
 			}
 
 			for (c = 1; c < argc; c++) {
-				if (is_grouping(argv[c], NULL) != NULL)
+				if (is_grouping(argv[c], NULL, NULL) != NULL)
 					break;
 				children++;
 				child = realloc(child,
@@ -1243,6 +1259,13 @@
 				return (NULL);
 			}
 
+			if (children > maxdev) {
+				(void) fprintf(stderr, gettext("invalid vdev "
+				    "specification: %s supports no more than "
+				    "%d devices\n"), argv[0], maxdev);
+				return (NULL);
+			}
+
 			argc -= c;
 			argv += c;
 
--- a/usr/src/cmd/ztest/ztest.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/cmd/ztest/ztest.c	Mon Jul 20 13:07:46 2009 -0400
@@ -479,7 +479,7 @@
 			zopt_raidz = MAX(1, value);
 			break;
 		case 'R':
-			zopt_raidz_parity = MIN(MAX(value, 1), 2);
+			zopt_raidz_parity = MIN(MAX(value, 1), 3);
 			break;
 		case 'd':
 			zopt_datasets = MAX(1, value);
--- a/usr/src/common/smbsrv/smb_xdr_utils.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/common/smbsrv/smb_xdr_utils.c	Mon Jul 20 13:07:46 2009 -0400
@@ -30,57 +30,6 @@
 #endif /* _KERNEL */
 #include <smbsrv/smb_xdr.h>
 #include <sys/socket.h>
-#ifdef _KERNEL
-/*
- * xdr_vector():
- *
- * XDR a fixed length array. Unlike variable-length arrays,
- * the storage of fixed length arrays is static and unfreeable.
- * > basep: base of the array
- * > size: size of the array
- * > elemsize: size of each element
- * > xdr_elem: routine to XDR each element
- */
-#define	LASTUNSIGNED ((uint_t)0-1)
-bool_t
-xdr_vector(XDR *xdrs, char *basep, uint_t nelem,
-	uint_t elemsize, xdrproc_t xdr_elem)
-{
-	uint_t i;
-	char *elptr;
-
-	elptr = basep;
-	for (i = 0; i < nelem; i++) {
-		if (!(*xdr_elem)(xdrs, elptr, LASTUNSIGNED))
-			return (FALSE);
-		elptr += elemsize;
-	}
-	return (TRUE);
-}
-
-/*
- * XDR an unsigned char
- */
-bool_t
-xdr_u_char(XDR *xdrs, uchar_t *cp)
-{
-	int i;
-
-	switch (xdrs->x_op) {
-	case XDR_ENCODE:
-		i = (*cp);
-		return (XDR_PUTINT32(xdrs, &i));
-	case XDR_DECODE:
-		if (!XDR_GETINT32(xdrs, &i))
-			return (FALSE);
-		*cp = (uchar_t)i;
-		return (TRUE);
-	case XDR_FREE:
-		return (TRUE);
-	}
-	return (FALSE);
-}
-#endif /* _KERNEL */
 
 bool_t
 xdr_smb_dr_string_t(xdrs, objp)
@@ -160,45 +109,44 @@
 }
 
 /*
- * Encode an opipe context structure into a buffer.
+ * Encode an smb_netuserinfo_t into a buffer.
  */
 int
-smb_opipe_context_encode(smb_opipe_context_t *ctx, uint8_t *buf,
-    uint32_t buflen, uint_t *pbytes_encoded)
+smb_netuserinfo_encode(smb_netuserinfo_t *info, uint8_t *buf,
+    uint32_t buflen, uint_t *nbytes)
 {
 	XDR xdrs;
 	int rc = 0;
 
 	xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_ENCODE);
 
-	if (!smb_opipe_context_xdr(&xdrs, ctx))
+	if (!smb_netuserinfo_xdr(&xdrs, info))
 		rc = -1;
 
-	if (pbytes_encoded != NULL)
-		*pbytes_encoded = xdr_getpos(&xdrs);
-
+	if (nbytes != NULL)
+		*nbytes = xdr_getpos(&xdrs);
 	xdr_destroy(&xdrs);
 	return (rc);
 }
 
 /*
- * Decode an XDR buffer into an opipe context structure.
+ * Decode an XDR buffer into an smb_netuserinfo_t.
  */
 int
-smb_opipe_context_decode(smb_opipe_context_t *ctx, uint8_t *buf,
-    uint32_t buflen, uint_t *pbytes_decoded)
+smb_netuserinfo_decode(smb_netuserinfo_t *info, uint8_t *buf,
+    uint32_t buflen, uint_t *nbytes)
 {
 	XDR xdrs;
 	int rc = 0;
 
 	xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_DECODE);
 
-	bzero(ctx, sizeof (smb_opipe_context_t));
-	if (!smb_opipe_context_xdr(&xdrs, ctx))
+	bzero(info, sizeof (smb_netuserinfo_t));
+	if (!smb_netuserinfo_xdr(&xdrs, info))
 		rc = -1;
 
-	if (pbytes_decoded != NULL)
-		*pbytes_decoded = xdr_getpos(&xdrs);
+	if (nbytes != NULL)
+		*nbytes = xdr_getpos(&xdrs);
 	xdr_destroy(&xdrs);
 	return (rc);
 }
@@ -219,32 +167,175 @@
 	return (TRUE);
 }
 
+/*
+ * XDR encode/decode for smb_netuserinfo_t.
+ */
 bool_t
-smb_opipe_context_xdr(XDR *xdrs, smb_opipe_context_t *objp)
+smb_netuserinfo_xdr(XDR *xdrs, smb_netuserinfo_t *objp)
 {
-	if (!xdr_uint64_t(xdrs, &objp->oc_session_id))
+	if (!xdr_uint64_t(xdrs, &objp->ui_session_id))
+		return (FALSE);
+	if (!xdr_uint16_t(xdrs, &objp->ui_uid))
+		return (FALSE);
+	if (!xdr_uint16_t(xdrs, &objp->ui_domain_len))
+		return (FALSE);
+	if (!xdr_string(xdrs, &objp->ui_domain, ~0))
+		return (FALSE);
+	if (!xdr_uint16_t(xdrs, &objp->ui_account_len))
 		return (FALSE);
-	if (!xdr_uint16_t(xdrs, &objp->oc_uid))
+	if (!xdr_string(xdrs, &objp->ui_account, ~0))
+		return (FALSE);
+	if (!xdr_uint16_t(xdrs, &objp->ui_workstation_len))
 		return (FALSE);
-	if (!xdr_uint16_t(xdrs, &objp->oc_domain_len))
+	if (!xdr_string(xdrs, &objp->ui_workstation, ~0))
+		return (FALSE);
+	if (!xdr_smb_inaddr_t(xdrs, &objp->ui_ipaddr))
 		return (FALSE);
-	if (!xdr_string(xdrs, &objp->oc_domain, ~0))
+	if (!xdr_int32_t(xdrs, &objp->ui_native_os))
+		return (FALSE);
+	if (!xdr_int64_t(xdrs, &objp->ui_logon_time))
 		return (FALSE);
-	if (!xdr_uint16_t(xdrs, &objp->oc_account_len))
+	if (!xdr_uint32_t(xdrs, &objp->ui_numopens))
+		return (FALSE);
+	if (!xdr_uint32_t(xdrs, &objp->ui_flags))
 		return (FALSE);
-	if (!xdr_string(xdrs, &objp->oc_account, ~0))
+	return (TRUE);
+}
+
+/*
+ * Encode an smb_netconnectinfo_t into a buffer.
+ */
+int
+smb_netconnectinfo_encode(smb_netconnectinfo_t *info, uint8_t *buf,
+    uint32_t buflen, uint_t *nbytes)
+{
+	XDR xdrs;
+	int rc = 0;
+
+	xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_ENCODE);
+
+	if (!smb_netconnectinfo_xdr(&xdrs, info))
+		rc = -1;
+
+	if (nbytes != NULL)
+		*nbytes = xdr_getpos(&xdrs);
+	xdr_destroy(&xdrs);
+	return (rc);
+}
+
+/*
+ * Decode an XDR buffer into an smb_netconnectinfo_t.
+ */
+int
+smb_netconnectinfo_decode(smb_netconnectinfo_t *info, uint8_t *buf,
+    uint32_t buflen, uint_t *nbytes)
+{
+	XDR xdrs;
+	int rc = 0;
+
+	xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_DECODE);
+
+	bzero(info, sizeof (smb_netconnectinfo_t));
+	if (!smb_netconnectinfo_xdr(&xdrs, info))
+		rc = -1;
+
+	if (nbytes != NULL)
+		*nbytes = xdr_getpos(&xdrs);
+	xdr_destroy(&xdrs);
+	return (rc);
+}
+
+/*
+ * XDR encode/decode for smb_netconnectinfo_t.
+ */
+bool_t
+smb_netconnectinfo_xdr(XDR *xdrs, smb_netconnectinfo_t *objp)
+{
+	if (!xdr_uint32_t(xdrs, &objp->ci_id))
 		return (FALSE);
-	if (!xdr_uint16_t(xdrs, &objp->oc_workstation_len))
+	if (!xdr_uint32_t(xdrs, &objp->ci_type))
+		return (FALSE);
+	if (!xdr_uint32_t(xdrs, &objp->ci_numopens))
+		return (FALSE);
+	if (!xdr_uint32_t(xdrs, &objp->ci_numusers))
 		return (FALSE);
-	if (!xdr_string(xdrs, &objp->oc_workstation, ~0))
+	if (!xdr_uint32_t(xdrs, &objp->ci_time))
+		return (FALSE);
+	if (!xdr_uint32_t(xdrs, &objp->ci_namelen))
+		return (FALSE);
+	if (!xdr_uint32_t(xdrs, &objp->ci_sharelen))
+		return (FALSE);
+	if (!xdr_string(xdrs, &objp->ci_username, MAXNAMELEN))
 		return (FALSE);
-	if (!xdr_smb_inaddr_t(xdrs, &objp->oc_ipaddr))
-		return (FALSE);
-	if (!xdr_int32_t(xdrs, &objp->oc_native_os))
+	if (!xdr_string(xdrs, &objp->ci_share, MAXNAMELEN))
 		return (FALSE);
-	if (!xdr_int64_t(xdrs, &objp->oc_logon_time))
+	return (TRUE);
+}
+
+/*
+ * Encode an smb_netfileinfo_t into a buffer.
+ */
+int
+smb_netfileinfo_encode(smb_netfileinfo_t *info, uint8_t *buf,
+    uint32_t buflen, uint_t *nbytes)
+{
+	XDR xdrs;
+	int rc = 0;
+
+	xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_ENCODE);
+
+	if (!smb_netfileinfo_xdr(&xdrs, info))
+		rc = -1;
+
+	if (nbytes != NULL)
+		*nbytes = xdr_getpos(&xdrs);
+	xdr_destroy(&xdrs);
+	return (rc);
+}
+
+/*
+ * Decode an XDR buffer into an smb_netfileinfo_t.
+ */
+int
+smb_netfileinfo_decode(smb_netfileinfo_t *info, uint8_t *buf,
+    uint32_t buflen, uint_t *nbytes)
+{
+	XDR xdrs;
+	int rc = 0;
+
+	xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_DECODE);
+
+	bzero(info, sizeof (smb_netfileinfo_t));
+	if (!smb_netfileinfo_xdr(&xdrs, info))
+		rc = -1;
+
+	if (nbytes != NULL)
+		*nbytes = xdr_getpos(&xdrs);
+	xdr_destroy(&xdrs);
+	return (rc);
+}
+
+/*
+ * XDR encode/decode for smb_netfileinfo_t.
+ */
+bool_t
+smb_netfileinfo_xdr(XDR *xdrs, smb_netfileinfo_t *objp)
+{
+	if (!xdr_uint16_t(xdrs, &objp->fi_fid))
 		return (FALSE);
-	if (!xdr_uint32_t(xdrs, &objp->oc_flags))
+	if (!xdr_uint32_t(xdrs, &objp->fi_uniqid))
+		return (FALSE);
+	if (!xdr_uint32_t(xdrs, &objp->fi_permissions))
+		return (FALSE);
+	if (!xdr_uint32_t(xdrs, &objp->fi_numlocks))
+		return (FALSE);
+	if (!xdr_uint32_t(xdrs, &objp->fi_pathlen))
+		return (FALSE);
+	if (!xdr_uint32_t(xdrs, &objp->fi_namelen))
+		return (FALSE);
+	if (!xdr_string(xdrs, &objp->fi_path, MAXPATHLEN))
+		return (FALSE);
+	if (!xdr_string(xdrs, &objp->fi_username, MAXNAMELEN))
 		return (FALSE);
 	return (TRUE);
 }
--- a/usr/src/grub/capability	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/grub/capability	Mon Jul 20 13:07:46 2009 -0400
@@ -40,7 +40,7 @@
 # This file and the associated version are Solaris specific and are
 # not a part of the open source distribution of GRUB.
 #
-VERSION=9
+VERSION=10
 dboot
 xVM
 zfs
--- a/usr/src/grub/grub-0.97/stage2/zfs-include/zfs.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/grub/grub-0.97/stage2/zfs-include/zfs.h	Mon Jul 20 13:07:46 2009 -0400
@@ -27,7 +27,7 @@
 /*
  * On-disk version number.
  */
-#define	SPA_VERSION			16ULL
+#define	SPA_VERSION			17ULL
 
 /*
  * The following are configuration names used in the nvlist describing a pool's
--- a/usr/src/lib/fm/libfmd_snmp/Makefile	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/fm/libfmd_snmp/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -19,10 +19,9 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
 #
 
 include ../../Makefile.lib
@@ -36,11 +35,11 @@
 
 MIBFILES = SUN-FM-MIB.mib
 
-ROOTSMAMIBDIR = $(ROOT)/etc/sma/snmp/mibs
-ROOTMIBS = $(MIBFILES:%=$(ROOTSMAMIBDIR)/%)
+ROOTNETSNMPMIBDIR = $(ROOT)/etc/net-snmp/snmp/mibs
+ROOTMIBS = $(MIBFILES:%=$(ROOTNETSNMPMIBDIR)/%)
 
 $(ROOTMIBS) := FILEMODE = 0644
-$(ROOTSMAMIBDIR) := DIRMODE = 0755
+$(ROOTNETSNMPMIBDIR) := DIRMODE = 0755
 
 all := TARGET = all
 clean := TARGET = clean
@@ -56,17 +55,17 @@
 
 install_h: $(ROOTFMHDRS)
 
-install_mibs: $(ROOTSMAMIBDIR) $(ROOTMIBS)
+install_mibs: $(ROOTNETSNMPMIBDIR) $(ROOTMIBS)
 
 check: $(CHECKHDRS)
 
 $(SUBDIRS): FRC
 	@cd $@; pwd; $(MAKE) $(TARGET)
 
-$(ROOTSMAMIBDIR):
+$(ROOTNETSNMPMIBDIR):
 	$(INS.dir)
 
-$(ROOTSMAMIBDIR)/%: mibs/%
+$(ROOTNETSNMPMIBDIR)/%: mibs/%
 	$(INS.file)
 
 FRC:
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip_amd.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip_amd.c	Mon Jul 20 13:07:46 2009 -0400
@@ -137,9 +137,9 @@
 	 * This "generic" topology is adequate for all of family 0xf and
 	 * for revisions A, B and C of family 0x10 (for the list of models
 	 * in each revision, refer to usr/src/uts/i86pc/os/cpuid_subr.c).
-	 * We cover all family 0x10 models, till model 6.
+	 * We cover all family 0x10 models, till model 8.
 	 */
-	if (family > 0x10 || (family == 0x10 && model > 6))
+	if (family > 0x10 || (family == 0x10 && model > 8))
 		return (1);
 
 	if (topo_node_range_create(mod, mcnode, CHAN_NODE_NAME, 0,
--- a/usr/src/lib/libadutils/common/addisc.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libadutils/common/addisc.c	Mon Jul 20 13:07:46 2009 -0400
@@ -314,7 +314,6 @@
 	int		num_td1;
 	int		num_td2;
 	boolean_t	match;
-	int 		err;
 
 	for (i = 0; td1[i].domain[0] != '\0'; i++)
 		continue;
@@ -330,9 +329,7 @@
 	for (i = 0; i < num_td1; i++) {
 		match = B_FALSE;
 		for (j = 0; j < num_td2; j++) {
-			if (u8_strcmp(td1[i].domain, td2[j].domain, 0,
-			    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 &&
-			    err == 0) {
+			if (domain_eq(td1[i].domain, td2[j].domain)) {
 				match = B_TRUE;
 				break;
 			}
@@ -373,7 +370,6 @@
 	int		num_df1;
 	int		num_df2;
 	boolean_t	match;
-	int		err;
 
 	for (i = 0; df1[i].domain[0] != '\0'; i++)
 		continue;
@@ -389,9 +385,7 @@
 	for (i = 0; i < num_df1; i++) {
 		match = B_FALSE;
 		for (j = 0; j < num_df2; j++) {
-			if (u8_strcmp(df1[i].domain, df2[j].domain, 0,
-			    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 &&
-			    err == 0 &&
+			if (domain_eq(df1[i].domain, df2[j].domain) &&
 			    strcmp(df1[i].sid, df2[j].sid) == 0) {
 				match = B_TRUE;
 				break;
@@ -1077,7 +1071,7 @@
 
 	if (ndomains < nresults) {
 		ad_disc_domainsinforest_t *tmp;
-		tmp = realloc(domains, (ndomains+1) * sizeof (*domains));
+		tmp = realloc(domains, (ndomains + 1) * sizeof (*domains));
 		if (tmp == NULL)
 			goto err;
 		domains = tmp;
@@ -1241,8 +1235,8 @@
 
 	/* Eat any trailing dot */
 	len = strlen(dname);
-	if (len > 0 && dname[len-1] == '.')
-		dname[len-1] = '\0';
+	if (len > 0 && dname[len - 1] == '.')
+		dname[len - 1] = '\0';
 
 	update_item(&ctx->domain_name, dname, AD_STATE_AUTO, ttl);
 
--- a/usr/src/lib/libadutils/common/adutils.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libadutils/common/adutils.c	Mon Jul 20 13:07:46 2009 -0400
@@ -863,12 +863,10 @@
 adutils_lookup_check_domain(adutils_query_state_t *qs, const char *domain)
 {
 	adutils_ad_t *ad = qs->qadh->owner;
-	int i, err;
+	int i;
 
 	for (i = 0; i < ad->num_known_domains; i++) {
-		if (u8_strcmp(domain, ad->known_domains[i].name, 0,
-		    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 &&
-		    err == 0)
+		if (domain_eq(domain, ad->known_domains[i].name))
 			return (1);
 	}
 
@@ -1116,7 +1114,7 @@
 	char		*attr = NULL, *dn = NULL, *domain = NULL;
 	adutils_entry_t	*ep;
 	adutils_attr_t	*ap;
-	int		i, j, b, err = 0, ret = -2;
+	int		i, j, b, ret = -2;
 
 	*entry = NULL;
 
@@ -1128,8 +1126,7 @@
 		return (-2);
 	}
 	if (q->edomain != NULL) {
-		if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER,
-		    U8_UNICODE_LATEST, &err) != 0 || err != 0) {
+		if (!domain_eq(q->edomain, domain)) {
 			ldap_memfree(dn);
 			free(domain);
 			return (-1);
@@ -1560,7 +1557,7 @@
  */
 adutils_rc
 adutils_lookup_batch_add(adutils_query_state_t *state,
-	const char *filter, const char **attrs, const char *edomain,
+	const char *filter, const char * const *attrs, const char *edomain,
 	adutils_result_t **result, adutils_rc *rc)
 {
 	adutils_rc	retcode = ADUTILS_SUCCESS;
@@ -1675,3 +1672,12 @@
 		return (rc);
 	return (brc);
 }
+
+boolean_t
+domain_eq(const char *a, const char *b)
+{
+	int err;
+
+	return (u8_strcmp(a, b, 0, U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err)
+	    == 0 && err == 0);
+}
--- a/usr/src/lib/libadutils/common/libadutils.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libadutils/common/libadutils.h	Mon Jul 20 13:07:46 2009 -0400
@@ -164,7 +164,7 @@
 				void *ldap_res_search_argp,
 				adutils_query_state_t **state);
 extern adutils_rc	adutils_lookup_batch_add(adutils_query_state_t *state,
-				const char *filter, const char **attrs,
+				const char *filter, const char * const *attrs,
 				const char *edomain, adutils_result_t **result,
 				adutils_rc *rc);
 extern adutils_rc	adutils_lookup_batch_end(
@@ -181,6 +181,8 @@
 				const char *sid);
 extern void		adutils_set_logger(adutils_logger logger);
 
+extern boolean_t	domain_eq(const char *a, const char *b);
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/lib/libadutils/common/mapfile-vers	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libadutils/common/mapfile-vers	Mon Jul 20 13:07:46 2009 -0400
@@ -80,6 +80,7 @@
 	ad_disc_get_SiteName;
 	ad_disc_get_TrustedDomains;
 	ad_disc_get_DomainsInForest;
+	domain_eq;
     local:
 	*;
 };
--- a/usr/src/lib/libc/common/sys/_pset.s	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libc/common/sys/_pset.s	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -32,7 +32,7 @@
  * _pset(int subcode, long arg1, long arg2, long arg3, long arg4)
  *
  * Syscall entry point for pset_create, pset_assign, pset_destroy,
- * pset_bind, and pset_info.
+ * pset_bind, pset_bind_lwp and pset_info.
  */
 	SYSCALL2_RVAL1(_pset,pset)
 	RETC
--- a/usr/src/lib/libc/port/llib-lc	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libc/port/llib-lc	Mon Jul 20 13:07:46 2009 -0400
@@ -1347,6 +1347,8 @@
 int pset_assign_forced(psetid_t pset, processorid_t cpu, psetid_t *opset);
 int pset_info(psetid_t pset, int *type, u_int *numcpus, processorid_t *cpulist);
 int pset_bind(psetid_t pset, idtype_t idtype, id_t id, psetid_t *opset);
+int pset_bind_lwp(psetid_t pset, id_t id, pid_t, psetid_t *opset);
+  
 
 /* rctlsys.c */
 int getrctl(const char *name, rctlblk_t *old_rblk, rctlblk_t *new_rblk,
--- a/usr/src/lib/libc/port/mapfile-vers	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libc/port/mapfile-vers	Mon Jul 20 13:07:46 2009 -0400
@@ -1605,6 +1605,7 @@
 	__priv_bracket;
 	__priv_relinquish;
 	pset_assign_forced;
+	pset_bind_lwp;
 	_psignal;
 	_pthread_setcleanupinit;
 	__putwchar_xpg5;
--- a/usr/src/lib/libc/port/sys/psetsys.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libc/port/sys/psetsys.c	Mon Jul 20 13:07:46 2009 -0400
@@ -20,22 +20,10 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#pragma weak _pset_create = pset_create
-#pragma weak _pset_destroy = pset_destroy
-#pragma weak _pset_assign = pset_assign
-#pragma weak _pset_info = pset_info
-#pragma weak _pset_bind = pset_bind
-#pragma weak _pset_getloadavg = pset_getloadavg
-#pragma weak _pset_list = pset_list
-#pragma weak _pset_setattr = pset_setattr
-#pragma weak _pset_getattr = pset_getattr
-
 #include "lint.h"
 #include <sys/types.h>
 #include <sys/procset.h>
@@ -84,6 +72,12 @@
 	return (_pset(PSET_BIND, pset, idtype, id, opset));
 }
 
+int
+pset_bind_lwp(psetid_t pset, id_t id, pid_t pid, psetid_t *opset)
+{
+	return (_pset(PSET_BIND_LWP, pset, id, pid, opset));
+}
+
 /*
  * Get the per-processor-set load average.
  */
--- a/usr/src/lib/libdevinfo/Makefile.com	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libdevinfo/Makefile.com	Mon Jul 20 13:07:46 2009 -0400
@@ -19,17 +19,15 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 LIBRARY=	libdevinfo.a
 VERS=		.1
 
 OBJECTS=	devfsinfo.o devinfo.o devinfo_prop_decode.o devinfo_devlink.o \
-		devinfo_devperm.o devfsmap.o devinfo_devname.o \
+		devinfo_devperm.o devfsmap.o devinfo_profile.o \
 		devinfo_finddev.o devinfo_dli.o devinfo_dim.o \
 		devinfo_realpath.o devinfo_retire.o
 		
--- a/usr/src/lib/libdevinfo/devinfo_devname.c	Tue Jul 14 11:18:27 2009 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,701 +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 2006 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#include <stdio.h>
-#include <strings.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <libnvpair.h>
-#include <libdevinfo.h>
-#include <syslog.h>
-#include <sys/param.h>
-#include <errno.h>
-#include <assert.h>
-#include <sys/systeminfo.h>
-#include <sys/modctl.h>
-#include <sys/fs/sdev_node.h>
-
-
-#define	LINEMAX		1024
-#define	SPC		" \t\n"
-#define	QUOTES		"\'\""
-
-/*
- * This is for local file supports of DBNR configurations.
- */
-static int di_devname_getmapent_files(char *, char *, nvlist_t **);
-static int di_devname_get_mapinfo_files(char *, nvlist_t **);
-static int parse_mapinfo_file(FILE *, nvlist_t **);
-static FILE *open_local_map(char *);
-static void unquote(char *, char *);
-
-static int msglog = 1;
-typedef enum {
-	DBG_ERR = 1,
-	DBG_INFO,
-	DBG_STEP,
-	DBG_ALL
-} debug_level_t;
-static int devname_debug = 1;
-static void dprintf(debug_level_t, const char *, ...);
-
-extern int isspace(int);
-
-/* exported interfaces */
-void di_devname_print_mapinfo(nvlist_t *);
-int di_devname_get_mapinfo(char *, nvlist_t **);
-int di_devname_get_mapent(char *, char *, nvlist_t **);
-int di_devname_action_on_key(nvlist_t *, uint8_t, char *, void *);
-
-/*
- * Returns 0 and the valid maplist, otherwise errno.
- */
-int
-di_devname_get_mapinfo_files(char *mapname, nvlist_t **maplist)
-{
-	FILE *fp;
-	int rval = 0;
-	nvlist_t *nvl = NULL;
-
-	fp = open_local_map(mapname);
-	if (fp == NULL) {
-		dprintf(DBG_INFO, "di_devname_get_mapinfo_files: file %s does"
-		    "not exist\n", mapname);
-		return (ENOENT);
-	}
-
-	rval = parse_mapinfo_file(fp, &nvl);
-	if (rval == 0) {
-		*maplist = nvl;
-	}
-	(void) fclose(fp);
-
-	return (rval);
-}
-
-static FILE *
-open_local_map(char *mapname)
-{
-	char filename[LINEMAX];
-
-	if (*mapname != '/') {
-		(void) snprintf(filename, sizeof (filename), "/etc/dev/%s",
-		    mapname);
-	} else {
-		(void) snprintf(filename, sizeof (filename), "%s", mapname);
-	}
-
-	return (fopen(filename, "r"));
-}
-
-static void
-unquote(char *str, char *qbuf)
-{
-	register int escaped, inquote, quoted;
-	register char *ip, *bp, *qp;
-	char buf[LINEMAX];
-
-	escaped = inquote = quoted = 0;
-
-	for (ip = str, bp = buf, qp = qbuf; *ip; ip++) {
-		if (!escaped) {
-			if (*ip == '\\') {
-				escaped = 1;
-				quoted ++;
-				continue;
-			} else if (*ip == '"') {
-				inquote = !inquote;
-				quoted ++;
-				continue;
-			}
-		}
-
-		*bp++ = *ip;
-		*qp++ = (inquote || escaped) ? '^' : ' ';
-		escaped = 0;
-	}
-	*bp = '\0';
-	*qp = '\0';
-	if (quoted)
-		(void) strcpy(str, buf);
-}
-
-/*
- * gets the qualified characters in *p into w, which has space allocated
- * already
- */
-static int
-getword(char *w, char *wq, char **p, char **pq, char delim, int wordsz)
-{
-	char *tmp = w;
-	char *tmpq = wq;
-	int count = wordsz;
-
-	if (wordsz <= 0) {
-		return (-1);
-	}
-
-	while ((delim == ' ' ? isspace(**p) : **p == delim) && **pq == ' ') {
-		(*p)++;
-		(*pq)++;
-	}
-
-	while (**p &&
-		!((delim == ' ' ? isspace(**p) : **p == delim) &&
-			**pq == ' ')) {
-		if (--count <= 0) {
-			*tmp = '\0';
-			*tmpq = '\0';
-			dprintf(DBG_INFO, "maximum word length %d exceeded\n",
-				wordsz);
-			return (-1);
-		}
-		*w++ = *(*p)++;
-		*wq++ = *(*pq)++;
-	}
-	*w = '\0';
-	*wq = '\0';
-	return (0);
-}
-
-static int
-parse_mapinfo_file(FILE *fp, nvlist_t **ret_nvlp)
-{
-	int error = 0;
-	nvlist_t *nvl = NULL, *attrs = NULL;
-	char line[LINEMAX], lineq[LINEMAX];
-	char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1];
-	char *lp, *lq;
-
-	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
-		return (EFAULT);
-	}
-
-	while (fgets(line, sizeof (line), fp)) {
-		char *name, *key, *val;
-
-		lp = (char *)line;
-		lq = (char *)lineq;
-		unquote(lp, lq);
-		if ((getword(word, wordq, &lp, &lq, ' ',
-		    sizeof (word)) == -1) || (word[0] == '\0'))
-			continue;
-
-		if (word[0] == '#')
-			continue;
-
-		name = strtok(line, SPC);
-		if (name == NULL)
-			continue;
-
-		(void) dprintf(DBG_INFO, "get a line for %s\n", name);
-		key = strtok(NULL, "=");
-		if (key == NULL) {
-			(void) dprintf(DBG_INFO, "no attributes specified for "
-			    "%s\n", name);
-			continue;
-		}
-
-		attrs = NULL;
-		if (nvlist_alloc(&attrs, NV_UNIQUE_NAME, 0) != 0) {
-			error = EFAULT;
-			goto fail1;
-		}
-
-		while (key && *key) {
-			char *rest;
-			rest = strtok(NULL, "\n");
-			if (rest == NULL) {
-				(void) dprintf(DBG_INFO, "no value for key "
-				    "%s\n", key);
-				break;
-			}
-			if (rest[0] == ';') {
-				val = strdup("devname_null");
-				rest++;
-			} else {
-				val = strtok(rest, ";");
-				rest = strtok(NULL, "");
-			}
-			(void) dprintf(DBG_INFO, "parse_map_info: one entry "
-			    "key=%s val=%s\n", key, val);
-			if (nvlist_add_string(attrs, key, val) != 0) {
-				error = EFAULT;
-				goto fail;
-			}
-
-			key = strtok(rest, "=");
-		}
-		(void) dprintf(DBG_INFO, "parse_map_info: add entry name=%s\n",
-		    name);
-		if (nvlist_add_nvlist(nvl, name, attrs) != 0) {
-			error = EFAULT;
-			goto fail;
-		}
-	}
-
-done:
-	*ret_nvlp = nvl;
-	return (0);
-
-fail:
-	nvlist_free(attrs);
-fail1:
-	nvlist_free(nvl);
-	return (error);
-}
-
-void
-di_devname_print_mapinfo(nvlist_t *nvl)
-{
-	char *name, *key, *val;
-	nvlist_t *attrs;
-	nvpair_t *nvp, *kvp;
-
-	nvp = nvlist_next_nvpair(nvl, NULL);
-	while (nvp) {
-		name = nvpair_name(nvp);
-		(void) nvpair_value_nvlist(nvp, &attrs);
-		(void) printf("name = %s, binding attributes:\n", name);
-		kvp = nvlist_next_nvpair(attrs, NULL);
-		while (kvp) {
-			key = nvpair_name(kvp);
-			(void) nvpair_value_string(kvp, &val);
-			(void) printf("\t%s = %s\n", key, val);
-			kvp = nvlist_next_nvpair(attrs, kvp);
-		}
-		nvp = nvlist_next_nvpair(nvl, nvp);
-	}
-}
-
-static int
-action_mklink(char *target, char *source)
-{
-	(void) dprintf(DBG_INFO, "mklink for source %s target %s\n",
-	    source, target);
-	return (symlink(source, target));
-}
-
-static struct actions {
-	char *key;
-	devname_spec_t spec;
-	int (*action)(char *, char *);
-} actions[] = {
-	{"devices-path", DEVNAME_NS_PATH, action_mklink},
-	{"dev-path", DEVNAME_NS_DEV, action_mklink},
-	{NULL, DEVNAME_NS_NONE, NULL}
-};
-
-static int
-action_on_key(uint_t cmd, char *dir_name, char *devname, nvpair_t *attr,
-    uint32_t  *nsmapcount, char **devfsadm_link, devname_spec_t *devfsadm_spec)
-{
-	int i = 0;
-	int error = 0;
-	char *attrname, *attrval;
-	int len = 0;
-	char *path = NULL;
-
-	attrname = nvpair_name(attr);
-	(void) nvpair_value_string(attr, &attrval);
-	(void) dprintf(DBG_INFO, "key = %s; value = %s\n", attrname, attrval);
-
-	while (actions[i].key) {
-		if (strcmp(actions[i].key, attrname) == 0) {
-			switch (cmd) {
-			case DEVFSADMD_NS_READDIR:
-				len = strlen(dir_name) + strlen(devname) + 2;
-				path = malloc(len);
-				(void) snprintf(path, len, "%s/%s", dir_name,
-				    devname);
-				error = actions[i].action(path, attrval);
-				free(path);
-				if (error) {
-					(void) dprintf(DBG_INFO, "action "
-					    "failed %d\n", error);
-					return (error);
-				} else {
-					(*nsmapcount)++;
-					(void) dprintf(DBG_INFO,
-					    "mapcount %d\n", *nsmapcount);
-				}
-				break;
-			case DEVFSADMD_NS_LOOKUP:
-				*devfsadm_link = strdup(attrval);
-				*devfsadm_spec = actions[i].spec;
-				break;
-			default:
-				break;
-			}
-		}
-		i++;
-	}
-	return (0);
-}
-
-int
-di_devname_action_on_key(nvlist_t *map, uint8_t cmd, char *dir_name, void *hdl)
-{
-	char *name = NULL;
-	nvpair_t *entry;
-	nvlist_t *attrs;
-	int32_t error = 0;
-	uint32_t ns_mapcount = 0;
-	char *devfsadm_link = NULL;
-	devname_spec_t devfsadm_spec = DEVNAME_NS_NONE;
-	sdev_door_res_t *resp;
-
-	entry = nvlist_next_nvpair(map, NULL);
-	while (entry) {
-		nvpair_t *attr;
-		name = nvpair_name(entry);
-		(void) dprintf(DBG_INFO, "di_devname_action_on_key: name %s\n",
-		    name);
-		(void) nvpair_value_nvlist(entry, &attrs);
-
-		attr = nvlist_next_nvpair(attrs, NULL);
-		while (attr) {
-			error = action_on_key(cmd, dir_name, name, attr,
-			    &ns_mapcount, &devfsadm_link, &devfsadm_spec);
-
-			/* do not continue if encountered the first error */
-			if (error) {
-				(void) dprintf(DBG_INFO, "error %d\n", error);
-				return ((int32_t)error);
-			}
-			attr = nvlist_next_nvpair(attrs, attr);
-		}
-		entry = nvlist_next_nvpair(map, entry);
-	}
-
-	resp = (sdev_door_res_t *)hdl;
-	(void) dprintf(DBG_INFO, "cmd is %d\n", cmd);
-	switch (cmd) {
-	case DEVFSADMD_NS_READDIR:
-		resp->ns_rdr_hdl.ns_mapcount = (uint32_t)ns_mapcount;
-		(void) dprintf(DBG_INFO, "mapcount is %d\n", ns_mapcount);
-		break;
-	case DEVFSADMD_NS_LOOKUP:
-		if (devfsadm_link && devfsadm_spec != DEVNAME_NS_NONE) {
-			(void) dprintf(DBG_INFO, "devfsadm_link is %s\n",
-			    devfsadm_link);
-			(void) snprintf(resp->ns_lkp_hdl.devfsadm_link,
-			    strlen(devfsadm_link) + 1, "%s", devfsadm_link);
-			resp->ns_lkp_hdl.devfsadm_spec = devfsadm_spec;
-		} else {
-			(void) dprintf(DBG_INFO, "error out\n");
-			return (1);
-		}
-		break;
-	default:
-		(void) dprintf(DBG_INFO, "error NOTSUP out\n");
-		return (ENOTSUP);
-	}
-
-	return (0);
-}
-
-
-static nvlist_t *
-getent_mapinfo_file(FILE *fp, char *match)
-{
-	nvlist_t *nvl, *attrs;
-	char line[LINEMAX], lineq[LINEMAX];
-	char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1];
-	int count = 0;
-	char *lp, *lq;
-
-	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
-		return (NULL);
-
-	while (fgets(line, sizeof (line), fp)) {
-		char *name, *key, *val;
-
-		if (line[0] == '#')
-			continue;
-
-		dprintf(DBG_INFO, "getent_mapinfo_file: get a line %s\n", line);
-		lp = (char *)line;
-		lq = (char *)lineq;
-		unquote(lp, lq);
-		if ((getword(word, wordq, &lp, &lq, ' ', sizeof (word))
-			== -1) || (word[0] == '\0'))
-			continue;
-
-		name = strtok(line, SPC);
-		if (name == NULL)
-			continue;
-
-		dprintf(DBG_INFO, "macthing with the key %s match %s\n",
-		    name, match);
-		/* bypass the non-related entries */
-		if (strcmp(name, match) != 0)
-			continue;
-
-		/* get a matched entry */
-		key = strtok(NULL, "=");
-		if (key == NULL) {
-			(void) dprintf(DBG_INFO, "no attributes specified "
-			    "for %s\n", name);
-			goto fail1;
-		}
-
-		attrs = NULL;
-		if (nvlist_alloc(&attrs, NV_UNIQUE_NAME, 0) != 0)
-			goto fail1;
-		while (key && *key) {
-			char *rest;
-			rest = strtok(NULL, "\n");
-			if (rest == NULL) {
-				(void) dprintf(DBG_INFO, "no value for key "
-				    "%s\n", key);
-				goto fail;
-			}
-			if (rest[0] == ';') {
-				val = strdup("devname_null");
-				rest++;
-			} else {
-				val = strtok(rest, ";");
-				rest = strtok(NULL, "");
-			}
-			(void) dprintf(DBG_INFO, "found entry %s %s for %s\n",
-			    key, val, name);
-			if (nvlist_add_string(attrs, key, val) != 0)
-				goto fail;
-
-			key = strtok(rest, "=");
-		}
-		(void) dprintf(DBG_INFO, "adding nvlist for %s\n", name);
-		if (nvlist_add_nvlist(nvl, name, attrs) != 0)
-			goto fail;
-		count++;
-		break;
-	}
-
-	if (count == 0)
-		goto fail1;
-
-	return (nvl);
-
-fail:
-	nvlist_free(attrs);
-fail1:
-	nvlist_free(nvl);
-	errno = EFAULT;
-	return (NULL);
-}
-
-static int
-di_devname_getmapent_files(char *key, char *mapname, nvlist_t **map)
-{
-	FILE *fp;
-	int rval = 0;
-	nvlist_t *nvl = NULL;
-
-	fp = open_local_map(mapname);
-	if (fp == NULL)
-		return (1);
-
-	nvl = getent_mapinfo_file(fp, key);
-	if (nvl != NULL) {
-		*map = nvl;
-	} else {
-		rval = errno;
-	}
-	(void) fclose(fp);
-
-	return (rval);
-}
-
-int
-di_devname_get_mapent(char *key, char *mapname, nvlist_t **map)
-{
-	dprintf(DBG_INFO, "di_devname_get_mapent: called for %s in %s\n",
-	    key, mapname);
-
-	return (di_devname_getmapent_files(key, mapname, map));
-
-}
-
-int
-di_devname_get_mapinfo(char *mapname, nvlist_t **maps)
-{
-	dprintf(DBG_INFO, "di_devname_get_mapinfo: called for %s\n", mapname);
-
-	return (di_devname_get_mapinfo_files(mapname, maps));
-}
-
-static void
-debug_print(debug_level_t msglevel, const char *fmt, va_list ap)
-{
-	if (devname_debug < msglevel)
-		return;
-
-	/* Print a distinctive label for error msgs */
-	if (msglevel == DBG_ERR) {
-		(void) fprintf(stderr, "[ERROR]: ");
-	}
-
-	if (msglog == TRUE) {
-		(void) vsyslog(LOG_NOTICE, fmt, ap);
-	} else {
-		(void) vfprintf(stderr, fmt, ap);
-	}
-}
-
-/* ARGSUSED */
-/* PRINTFLIKE2 */
-static void
-dprintf(debug_level_t msglevel, const char *fmt, ...)
-{
-	va_list ap;
-
-	assert(msglevel > 0);
-
-	if (!devname_debug)
-		return;
-
-	va_start(ap, fmt);
-	debug_print(msglevel, fmt, ap);
-	va_end(ap);
-}
-
-
-/*
- * Private interfaces for non-global /dev profile
- */
-
-/*
- * Allocate opaque data structure for passing profile to the kernel for
- * the given mount point.
- *
- * Note that this interface returns an empty, initialized, profile.
- * It does not return what may have been previously committed.
- */
-int
-di_prof_init(const char *mountpt, di_prof_t *profp)
-{
-	nvlist_t	*nvl;
-
-	if (nvlist_alloc(&nvl, 0, 0))
-		return (-1);
-
-	if (nvlist_add_string(nvl, SDEV_NVNAME_MOUNTPT, mountpt)) {
-		nvlist_free(nvl);
-		return (-1);
-	}
-
-	*profp = (di_prof_t)nvl;
-	return (0);
-}
-
-/*
- * Free space allocated by di_prof_init().
- */
-void
-di_prof_fini(di_prof_t prof)
-{
-	nvlist_free((nvlist_t *)prof);
-}
-
-/*
- * Sends profile to the kernel.
- */
-int
-di_prof_commit(di_prof_t prof)
-{
-	char	*buf = NULL;
-	size_t	buflen = 0;
-	int	rv;
-
-	if (nvlist_pack((nvlist_t *)prof, &buf, &buflen, NV_ENCODE_NATIVE, 0))
-		return (-1);
-	rv = modctl(MODDEVNAME, MODDEVNAME_PROFILE, buf, buflen);
-	free(buf);
-	return (rv);
-}
-
-/*
- * Add a device or directory to profile's include list.
- *
- * Note that there is no arbitration between conflicting
- * include and exclude profile entries, most recent
- * is the winner.
- */
-int
-di_prof_add_dev(di_prof_t prof, const char *dev)
-{
-	if (nvlist_add_string((nvlist_t *)prof, SDEV_NVNAME_INCLUDE, dev))
-		return (-1);
-	return (0);
-}
-
-/*
- * Add a device or directory to profile's exclude list.
- * This can effectively remove a previously committed device.
- */
-int
-di_prof_add_exclude(di_prof_t prof, const char *dev)
-{
-	if (nvlist_add_string((nvlist_t *)prof, SDEV_NVNAME_EXCLUDE, dev))
-		return (-1);
-	return (0);
-}
-
-/*
- * Add a symlink to profile.
- */
-int
-di_prof_add_symlink(di_prof_t prof, const char *linkname, const char *target)
-{
-	nvlist_t	*nvl = (nvlist_t *)prof;
-	char		*syml[2];
-
-	syml[0] = (char *)linkname;	/* 1st entry must be the symlink */
-	syml[1] = (char *)target;	/* 2nd entry must be the target */
-	if (nvlist_add_string_array(nvl, SDEV_NVNAME_SYMLINK, syml, 2))
-		return (-1);
-	return (0);
-}
-
-/*
- * Add a name mapping to profile.
- */
-int
-di_prof_add_map(di_prof_t prof, const char *source, const char *target)
-{
-	nvlist_t	*nvl = (nvlist_t *)prof;
-	char		*map[2];
-
-	map[0] = (char *)source;	/* 1st entry must be the source */
-	map[1] = (char *)target;	/* 2nd entry must be the target */
-	if (nvlist_add_string_array(nvl, SDEV_NVNAME_MAP, map, 2))
-		return (-1);
-	return (0);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libdevinfo/devinfo_profile.c	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,153 @@
+/*
+ * 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 <stdio.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <libnvpair.h>
+#include <libdevinfo.h>
+#include <syslog.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/systeminfo.h>
+#include <sys/modctl.h>
+#include <sys/fs/sdev_impl.h>
+
+/*
+ * Private interfaces for non-global /dev profile
+ */
+
+/*
+ * Allocate opaque data structure for passing profile to the kernel for
+ * the given mount point.
+ *
+ * Note that this interface returns an empty, initialized, profile.
+ * It does not return what may have been previously committed.
+ */
+int
+di_prof_init(const char *mountpt, di_prof_t *profp)
+{
+	nvlist_t	*nvl;
+
+	if (nvlist_alloc(&nvl, 0, 0))
+		return (-1);
+
+	if (nvlist_add_string(nvl, SDEV_NVNAME_MOUNTPT, mountpt)) {
+		nvlist_free(nvl);
+		return (-1);
+	}
+
+	*profp = (di_prof_t)nvl;
+	return (0);
+}
+
+/*
+ * Free space allocated by di_prof_init().
+ */
+void
+di_prof_fini(di_prof_t prof)
+{
+	nvlist_free((nvlist_t *)prof);
+}
+
+/*
+ * Sends profile to the kernel.
+ */
+int
+di_prof_commit(di_prof_t prof)
+{
+	char	*buf = NULL;
+	size_t	buflen = 0;
+	int	rv;
+
+	if (nvlist_pack((nvlist_t *)prof, &buf, &buflen, NV_ENCODE_NATIVE, 0))
+		return (-1);
+	rv = modctl(MODDEVNAME, MODDEVNAME_PROFILE, buf, buflen);
+	free(buf);
+	return (rv);
+}
+
+/*
+ * Add a device or directory to profile's include list.
+ *
+ * Note that there is no arbitration between conflicting
+ * include and exclude profile entries, most recent
+ * is the winner.
+ */
+int
+di_prof_add_dev(di_prof_t prof, const char *dev)
+{
+	if (nvlist_add_string((nvlist_t *)prof, SDEV_NVNAME_INCLUDE, dev))
+		return (-1);
+	return (0);
+}
+
+/*
+ * Add a device or directory to profile's exclude list.
+ * This can effectively remove a previously committed device.
+ */
+int
+di_prof_add_exclude(di_prof_t prof, const char *dev)
+{
+	if (nvlist_add_string((nvlist_t *)prof, SDEV_NVNAME_EXCLUDE, dev))
+		return (-1);
+	return (0);
+}
+
+/*
+ * Add a symlink to profile.
+ */
+int
+di_prof_add_symlink(di_prof_t prof, const char *linkname, const char *target)
+{
+	nvlist_t	*nvl = (nvlist_t *)prof;
+	char		*syml[2];
+
+	syml[0] = (char *)linkname;	/* 1st entry must be the symlink */
+	syml[1] = (char *)target;	/* 2nd entry must be the target */
+	if (nvlist_add_string_array(nvl, SDEV_NVNAME_SYMLINK, syml, 2))
+		return (-1);
+	return (0);
+}
+
+/*
+ * Add a name mapping to profile.
+ */
+int
+di_prof_add_map(di_prof_t prof, const char *source, const char *target)
+{
+	nvlist_t	*nvl = (nvlist_t *)prof;
+	char		*map[2];
+
+	map[0] = (char *)source;	/* 1st entry must be the source */
+	map[1] = (char *)target;	/* 2nd entry must be the target */
+	if (nvlist_add_string_array(nvl, SDEV_NVNAME_MAP, map, 2))
+		return (-1);
+	return (0);
+}
--- a/usr/src/lib/libdevinfo/libdevinfo.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libdevinfo/libdevinfo.h	Mon Jul 20 13:07:46 2009 -0400
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_LIBDEVINFO_H
 #define	_LIBDEVINFO_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -487,14 +485,6 @@
 extern void di_dli_close(int);
 
 /*
- * Private interface for parsing devname binding info
- */
-extern void di_devname_print_mapinfo(nvlist_t *);
-extern int di_devname_get_mapinfo(char *, nvlist_t **);
-extern int di_devname_get_mapent(char *, char *, nvlist_t **);
-extern int di_devname_action_on_key(nvlist_t *, uint8_t, char *, void *);
-
-/*
  * Private interface for parsing path_to_inst binding file
  */
 extern int devfs_parse_binding_file(const char *,
--- a/usr/src/lib/libdevinfo/mapfile-vers	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libdevinfo/mapfile-vers	Mon Jul 20 13:07:46 2009 -0400
@@ -187,10 +187,6 @@
 	di_devlink_type;
 	di_devlink_update;
 	di_devlink_walk;
-	di_devname_action_on_key;
-	di_devname_get_mapent;
-	di_devname_get_mapinfo;
-	di_devname_print_mapinfo;
 	di_devperm_login;
 	di_devperm_logout;
 	di_dim_fini;
--- a/usr/src/lib/libelfsign/common/elfcertlib.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libelfsign/common/elfcertlib.c	Mon Jul 20 13:07:46 2009 -0400
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <limits.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -221,7 +219,7 @@
 	cert->c_verified = E_UNCHECKED;
 
 	/*
-	 * If the cert we are loading it the trust anchor (ie the CA) then
+	 * If the cert we are loading is the trust anchor (ie the CA) then
 	 * we mark it as such in cert.  This is so that we don't attempt
 	 * to verify it later.  The CA is always implicitly verified.
 	 */
@@ -473,12 +471,13 @@
 		algid = KMF_ALGID_RSA;
 
 	/*
-	 * We tell KMF to use the OpenSSL verification
-	 * APIs here to avoid a circular dependency with
-	 * kcfd and libpkcs11.
+	 * We tell KMF to use the PKCS11 verification APIs
+	 * here to prevent the use of OpenSSL and to keep
+	 * all validation within the FIPS-140 boundary for
+	 * the Cryptographic Framework.
 	 */
 	rv = KMF_VerifyDataWithCert(ess->es_kmfhandle,
-	    KMF_KEYSTORE_OPENSSL, algid,
+	    KMF_KEYSTORE_PK11TOKEN, algid,
 	    &indata, &insig, &cert->c_cert.certificate);
 
 	return ((rv == KMF_OK));
--- a/usr/src/lib/libidmap/Makefile	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libidmap/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -25,15 +25,18 @@
 
 include $(SRC)/lib/Makefile.lib
 
-HDRS =		idmap.h
+HDRS =		idmap.h directory.h
 HDRDIR =	common
 
 SUBDIRS	=	$(MACH)
 $(BUILD64)SUBDIRS += $(MACH64)
 
 POFILE =	libidmap.po
-MSGFILES =	`$(GREP) -l gettext common/*.[ch]`
-XGETFLAGS =	-a
+MSGFILES:sh =	echo common/*.[ch]
+XGETTEXT =	$(GNUXGETTEXT)
+XGETFLAGS =	--foreign-user --strict -n -E --width=72 \
+		--omit-header --keyword=directoryError:2 \
+		--language=C --force-po
 
 all := 		TARGET = all
 clean :=	TARGET = clean
@@ -49,7 +52,7 @@
 
 check:		$(CHECKHDRS)
 
-$(POFILE):	pofile_MSGFILES
+$(POFILE):	$(MSGFILES)
 		$(BUILDPO.msgfiles)
 
 _msg:		$(MSGDOMAINPOFILE)
--- a/usr/src/lib/libidmap/Makefile.com	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libidmap/Makefile.com	Mon Jul 20 13:07:46 2009 -0400
@@ -26,11 +26,24 @@
 
 LIBRARY =	libidmap.a
 VERS =		.1
-OBJECTS =	idmap_xdr.o utils.o idmap_api.o namemaps.o idmap_cache.o
-LINT_OBJECTS =	utils.o idmap_api.o namemaps.o idmap_cache.o
+LINT_OBJECTS =	\
+	directory_client.o	\
+	directory_error.o	\
+	directory_helper.o		\
+	directory_rpc_clnt.o	\
+	sidutil.o		\
+	sized_array.o		\
+	idmap_api.o		\
+	idmap_cache.o		\
+	miscutils.o		\
+	namemaps.o		\
+	utils.o
+
+OBJECTS = $(LINT_OBJECTS)	\
+	idmap_xdr.o
 
 include ../../Makefile.lib
-
+C99MODE = $(C99_ENABLE)
 
 LIBS =		$(DYNLIB) $(LINTLIB)
 LDLIBS +=	-lc -lldap -lsldap -lavl -ladutils -lnsl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/directory.h	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+#ifndef _DIRECTORY_H
+#define	_DIRECTORY_H
+
+/*
+ * A suite of functions for retrieving information about objects
+ * in a directory service.
+ *
+ * Currently it is limited to retrieving SIDs from names, and vice
+ * versa.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+/*
+ * This bitmap is a distillation of the objectClass attribute,
+ * reporting those classes that Solaris finds "interesting".
+ *
+ * All undefined bits are reserved and must be ignored.
+ */
+#define	DIRECTORY_CLASS_USER	0x0000000000000001
+#define	DIRECTORY_CLASS_GROUP	0x0000000000000002
+
+/*
+ * Opaque pointer to a directory search context.
+ */
+typedef struct directory *directory_t;
+
+/*
+ * Opaque pointer to a structure that describes an error.
+ * Note that NULL means no error.
+ */
+typedef struct directory_error *directory_error_t;
+
+/*
+ * Initialize a directory query session, returning in *d a directory_t
+ * that should be used for query transactions.
+ */
+directory_error_t directory_open(directory_t *d);
+
+/*
+ * Tear down a directory query session.
+ * There is an argument that this should return a directory_error_t, but
+ * then what state would the directory_t be in, and what should you do
+ * if you were doing the directory_close as a result of encountering an error?
+ *
+ * Does nothing if d==NULL.
+ */
+void directory_close(directory_t d);
+
+/*
+ * All directory_t functions return NULL on success or a pointer to a
+ * directory_error_t structure on failure.  The caller must call
+ * directory_error_free() on any non-NULL directory_error_t structures returned.
+ *
+ * Strings returned from the directory_error functions are are
+ * invalidated when the directory_error_t itself is freed.
+ */
+
+directory_error_t directory_error(const char *code, const char *fmt, ...);
+
+/*
+ * Determines whether this directory_error_t is an instance of the
+ * particular error, or a subclass of that error.
+ */
+boolean_t directory_error_is_instance_of(directory_error_t de,
+    char *error_string);
+
+/*
+ * Returns a printable version of this directory_error_t, suitable for
+ * human consumption.
+ *
+ * The string returned is valid as long as the directory_error_t itself is
+ * valid, and is freed when the directory_error_t is freed.
+ */
+const char *directory_error_printable(directory_error_t de);
+
+/*
+ * Returns the error code for the particular error, as a string.
+ * Note that this function should not normally be used to answer
+ * the question "did error X happen", since the value returned
+ * could be a subclass of X.  directory_error_is_instance_of is intended
+ * to answer that question.  This function is more appropriate for
+ * logging, where one would want to log the error code and the list
+ * of parameters so as to allow structured analysis of the error
+ * after the fact.
+ *
+ * The string returned is valid as long as the directory_error_t itself is
+ * valid, and is freed when the directory_error_t is freed.
+ */
+const char *directory_error_code(directory_error_t de);
+
+/*
+ * Returns one of the parameters of the directory_error_t, or NULL if
+ * the parameter does not exist.
+ *
+ * Note that by definition error subclasses have initial parameters
+ * the same as their superclasses.
+ *
+ * The string returned is valid as long as the directory_error_t itself is
+ * valid, and is freed when the directory_error_t is freed.
+ */
+const char *directory_error_param(directory_error_t de, int param);
+
+/*
+ * Frees the memory (if any) allocated for the directory_error_t.
+ * This frees all strings that might have been derived from this
+ * directory_error_t through directory_error_code, directory_error_printable,
+ * et cetera.
+ *
+ * Does nothing if de==NULL.
+ */
+void directory_error_free(directory_error_t de);
+
+/*
+ * Utility functions to look up a SID given a name, and vice versa.
+ * Caller must free() the result (sid or name, respectively).
+ */
+directory_error_t directory_sid_from_name(directory_t d, char *name, char **sid,
+    uint64_t *classes);
+directory_error_t directory_sid_from_user_name(directory_t d, char *name,
+    char **sid);
+directory_error_t directory_sid_from_group_name(directory_t d, char *name,
+    char **sid);
+directory_error_t directory_name_from_sid(directory_t d, char *sid, char **name,
+    uint64_t *classes);
+directory_error_t directory_canon_from_name(directory_t d, char *name,
+    char **canon, uint64_t *classes);
+directory_error_t directory_canon_from_user_name(directory_t d, char *name,
+    char **canon);
+directory_error_t directory_canon_from_group_name(directory_t d, char *name,
+    char **canon);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DIRECTORY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/directory_client.c	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,366 @@
+/*
+ * 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.
+ */
+
+/*
+ * Directory lookup functions.  These are shims that translate from the API
+ * into the RPC protocol.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <netdb.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <string.h>
+#include "directory.h"
+#include "directory_private.h"
+#include <rpcsvc/idmap_prot.h>
+#include "directory_library_impl.h"
+#include "sized_array.h"
+
+static directory_error_t copy_directory_attribute_value(
+    directory_attribute_value_t *dav,
+    directory_values_rpc *dav_rpc);
+static directory_error_t copy_directory_entry(directory_entry_t *ent,
+    directory_entry_rpc *ent_rpc);
+static void directory_results_free(directory_results_rpc *dr);
+static directory_datum_t directory_datum(void *data, size_t len);
+static void directory_datum_free(directory_datum_t d);
+
+/*
+ * This is the actual implementation of the opaque directory_t structure.
+ */
+struct directory {
+	CLIENT	*client;
+};
+
+/*
+ * Set up a directory search context.
+ */
+directory_error_t
+directory_open(directory_t *ret)
+{
+	directory_t d;
+	directory_error_t de;
+	char host[] = "localhost";
+
+	*ret = NULL;
+
+	d = calloc(1, sizeof (*d));
+	if (d == NULL)
+		goto nomem;
+
+	d->client = clnt_door_create(IDMAP_PROG, IDMAP_V1, 0);
+	if (d->client == NULL) {
+		de = directory_error("clnt_create.directory_open",
+		    "Error: %1",
+		    clnt_spcreateerror(host),
+		    NULL);
+		goto err;
+	}
+
+	*ret = d;
+	return (NULL);
+
+nomem:
+	de = directory_error("ENOMEM.directory_open",
+	    "Insufficient memory setting up directory access", NULL);
+err:
+	directory_close(d);
+	return (de);
+}
+
+/*
+ * Tear down a directory search context.
+ *
+ * Does nothing if d==NULL.
+ */
+void
+directory_close(directory_t d)
+{
+	if (d == NULL)
+		return;
+
+	if (d->client != NULL)
+		clnt_destroy(d->client);
+
+	free(d);
+}
+
+/*
+ * Given a list of identifiers, a list of their types, and a list of attributes,
+ * return the information.
+ */
+directory_error_t
+directory_get_v(
+    directory_t d,
+    directory_entry_list_t *ret,
+    char **ids,
+    int nids,
+    char *types,
+    char **attr_list)
+{
+	int nattrs;
+	directory_entry_list_t del;
+	directory_error_t de;
+	directory_results_rpc dr;
+	idmap_utf8str_list sl_ids;
+	idmap_utf8str_list sl_attrs;
+	directory_entry_rpc *users;
+	int i;
+	enum clnt_stat cs;
+
+	*ret = NULL;
+	del = NULL;
+
+	if (nids == 0) {
+		for (nids = 0; ids[nids] != NULL; nids++)
+			/* LOOP */;
+	}
+
+	for (nattrs = 0; attr_list[nattrs] != NULL; nattrs++)
+		/* LOOP */;
+
+	sl_ids.idmap_utf8str_list_len = nids;
+	sl_ids.idmap_utf8str_list_val = ids;
+	sl_attrs.idmap_utf8str_list_len = nattrs;
+	sl_attrs.idmap_utf8str_list_val = attr_list;
+
+	(void) memset(&dr, 0, sizeof (dr));
+	cs = directory_get_common_1(sl_ids, types, sl_attrs, &dr, d->client);
+	if (cs != RPC_SUCCESS) {
+		char errbuf[100];	/* well long enough for any integer */
+		(void) sprintf(errbuf, "%d", cs);
+		de = directory_error("RPC.Get_common",
+		    "Get_common RPC (%1)%2", errbuf,
+		    clnt_sperror(d->client, ""), NULL);
+		goto err;
+	}
+
+	if (dr.failed) {
+		de = directory_error_from_rpc(
+		    &dr.directory_results_rpc_u.err);
+		goto err;
+	}
+
+	assert(dr.directory_results_rpc_u.entries.entries_len == nids);
+
+	users = dr.directory_results_rpc_u.entries.entries_val;
+
+	del = sized_array(nids, sizeof (directory_entry_t));
+
+	for (i = 0; i < nids; i++) {
+		de = copy_directory_entry(&del[i], &users[i]);
+		if (de != NULL)
+			goto err;
+	}
+
+	directory_results_free(&dr);
+
+	*ret = del;
+	return (NULL);
+
+err:
+	directory_results_free(&dr);
+	directory_free(del);
+	return (de);
+}
+
+/*
+ * Free the results from a directory_get_*() request.
+ */
+void
+directory_free(directory_entry_list_t del)
+{
+	directory_entry_t *ent;
+	directory_attribute_value_t dav;
+	int i;
+	int j;
+	int k;
+
+	if (del == NULL)
+		return;
+
+	/* For each directory entry returned */
+	for (i = 0; i < sized_array_n(del); i++) {
+		ent = &del[i];
+
+		if (ent->attrs != NULL) {
+			/* For each attribute */
+			for (j = 0; j < sized_array_n(ent->attrs); j++) {
+				dav = ent->attrs[j];
+				if (dav != NULL) {
+					for (k = 0; k < sized_array_n(dav); k++)
+						directory_datum_free(dav[k]);
+
+					sized_array_free(dav);
+				}
+			}
+			sized_array_free(ent->attrs);
+		}
+
+		directory_error_free(ent->err);
+	}
+
+	sized_array_free(del);
+}
+
+/*
+ * Create a directory datum.  Note that we allocate an extra byte and
+ * zero it, so that strings get null-terminated.  Return NULL on error.
+ */
+static
+directory_datum_t
+directory_datum(void *data, size_t len)
+{
+	void *p;
+
+	p = sized_array(len + 1, 1);
+	if (p == NULL)
+		return (NULL);
+	(void) memcpy(p, data, len);
+	*((char *)p + len) = '\0';
+	return (p);
+}
+
+/*
+ * Return the size of a directory_datum_t.  Note that this does not include
+ * the terminating \0, so it represents the value as returned by LDAP.
+ */
+size_t
+directory_datum_len(directory_datum_t d)
+{
+	/*
+	 * Deduct the terminal \0, so that binary data gets the
+	 * expected length.
+	 */
+	return (sized_array_n(d) - 1);
+}
+
+static
+void
+directory_datum_free(directory_datum_t d)
+{
+	sized_array_free(d);
+}
+
+/*
+ * Unmarshall an RPC directory entry into an API directory entry.
+ */
+static
+directory_error_t
+copy_directory_entry(
+    directory_entry_t *ent,
+    directory_entry_rpc *ent_rpc)
+{
+	int nattrs;
+	int i;
+	directory_error_t de;
+
+	/* If the entry wasn't found, leave the entry attrs and err NULL. */
+	if (ent_rpc->status == DIRECTORY_NOT_FOUND)
+		return (NULL);
+
+	if (ent_rpc->status == DIRECTORY_ERROR) {
+		ent->err = directory_error_from_rpc(
+		    &ent_rpc->directory_entry_rpc_u.err);
+		return (NULL);
+	}
+
+	nattrs = ent_rpc->directory_entry_rpc_u.attrs.attrs_len;
+
+	ent->attrs = sized_array(nattrs, sizeof (directory_attribute_value_t));
+	if (ent->attrs == NULL) {
+		return (directory_error("ENOMEM.copy_directory_entry",
+		    "Insufficient memory copying directory entry", NULL));
+	}
+	for (i = 0; i < nattrs; i++) {
+		de = copy_directory_attribute_value(&ent->attrs[i],
+		    &ent_rpc->directory_entry_rpc_u.attrs.attrs_val[i]);
+		if (de != NULL)
+			return (de);
+	}
+
+	return (NULL);
+}
+
+/*
+ * Unmarshall an RPC directory attribute value into the API equivalent.
+ *
+ * Note that on error some entries may have been copied, and so
+ * the caller needs to clean up dav.  This is normally not a problem
+ * since the caller will have called this function several times and
+ * will need to clean up the results from the other calls too.
+ */
+static
+directory_error_t
+copy_directory_attribute_value(
+    directory_attribute_value_t *dav,
+    directory_values_rpc *dav_rpc)
+{
+	int i;
+	int nvals;
+	directory_value_rpc *vals;
+
+	/* If it wasn't found, leave the corresponding entry NULL */
+	if (!dav_rpc->found)
+		return (NULL);
+
+	nvals = dav_rpc->directory_values_rpc_u.values.values_len;
+	*dav = sized_array(nvals + 1, sizeof (directory_datum_t));
+	if (*dav == NULL) {
+		return (directory_error("ENOMEM.copy_directory_attribute_value",
+		    "Insufficient memory copying directory entry", NULL));
+	}
+
+	vals = dav_rpc->directory_values_rpc_u.values.values_val;
+	for (i = 0; i < nvals; i++) {
+		(*dav)[i] = directory_datum(vals[i].directory_value_rpc_val,
+		    vals[i].directory_value_rpc_len);
+		if ((*dav)[i] == NULL) {
+			return (directory_error(
+			    "ENOMEM.copy_directory_attribute_value",
+			    "Insufficient memory copying directory entry",
+			    NULL));
+		}
+	}
+
+	return (NULL);
+}
+
+/*
+ * Free the results of a directory RPC request.
+ */
+static
+void
+directory_results_free(directory_results_rpc *dr)
+{
+	xdr_free(xdr_directory_results_rpc, (char *)&dr);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/directory_error.c	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,498 @@
+/*
+ * 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.
+ */
+
+/*
+ * Error handling support for directory lookup.
+ * Actually, this is intended to be a very generic and extensible error
+ * reporting mechanism.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <thread.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <malloc.h>
+#include <string.h>
+#include <ctype.h>
+#include <syslog.h>
+#include <idmap_impl.h>
+#include <rpcsvc/idmap_prot.h>
+#include <libintl.h>
+#include "directory.h"
+
+/*
+ * This is the actual implementation of the opaque directory_error_t structure.
+ */
+struct directory_error {
+	/*
+	 * True if this directory_error_t is statically allocated.  Used to
+	 * handle out of memory errors during error reporting.
+	 */
+	boolean_t	is_static;
+
+	/*
+	 * The error code.  This is a locale-independent string that
+	 * represents the precise error (to some level of granularity)
+	 * that occurred.  Internationalization processing could map it
+	 * to an message.  Errors may be subclassed by appending a dot
+	 * and a name for the subclass.
+	 *
+	 * Note that this code plus the parameters allows for structured
+	 * processing of error results.
+	 */
+	char		*code;
+
+	/*
+	 * The default (in the absence of internationalization) format for
+	 * the error message.  %n interposes params[n - 1].
+	 */
+	char		*fmt;
+
+	/*
+	 * Parameters to the error message.  Note that subclasses are
+	 * required to have the same initial parameters as their superclasses,
+	 * so that code that processes the superclass can work on the subclass.
+	 */
+	int		nparams;
+	char		**params;
+
+	/*
+	 * Cached printable form (that is, with params[] interpolated into
+	 * fmt) of the error message.  Created when requested.
+	 */
+	char		*printable;
+};
+
+static directory_error_t directory_error_internal_error(int err);
+
+/*
+ * For debugging, reference count of directory_error instances still in
+ * existence.  When the system is idle, this should be zero.
+ * Note that no attempt is made to make this MT safe, so it is not reliable
+ * in an MT environment.
+ */
+static int directory_errors_outstanding = 0;
+
+/*
+ * Free the specified directory_error_t.  Note that this invalidates all strings
+ * returned based on it.
+ *
+ * Does nothing when de==NULL.
+ */
+void
+directory_error_free(directory_error_t de)
+{
+	int i;
+
+	if (de == NULL)
+		return;
+
+	/* Don't free our internal static directory_error_ts! */
+	if (de->is_static)
+		return;
+
+	free(de->code);
+	de->code = NULL;
+	free(de->fmt);
+	de->fmt = NULL;
+
+	/* Free parameters, if any */
+	if (de->params != NULL) {
+		for (i = 0; i < de->nparams; i++) {
+			free(de->params[i]);
+			de->params[i] = NULL;
+		}
+		free(de->params);
+		de->params = NULL;
+	}
+
+	/* Free cached printable */
+	free(de->printable);
+	de->printable = NULL;
+
+	free(de);
+
+	directory_errors_outstanding--;
+}
+
+/*
+ * de = directory_error(code, fmt [, arg1 ... ]);
+ * Code, fmt, and arguments must be strings and will be copied.
+ */
+directory_error_t
+directory_error(const char *code, const char *fmt, ...)
+{
+	directory_error_t de = NULL;
+	va_list va;
+	int i;
+
+	de = calloc(1, sizeof (*de));
+	if (de == NULL)
+		goto nomem;
+
+	directory_errors_outstanding++;
+
+	de->is_static = B_FALSE;
+
+	de->code = strdup(code);
+	if (de->code == NULL)
+		goto nomem;
+
+	de->fmt = strdup(fmt);
+	if (de->fmt == NULL)
+		goto nomem;
+
+	/* Count our parameters */
+	va_start(va, fmt);
+	for (i = 0; va_arg(va, char *) != NULL; i++)
+		/* LOOP */;
+	va_end(va);
+
+	de->nparams = i;
+
+	/*
+	 * Note that we do not copy the terminating NULL because we have
+	 * a count.
+	 */
+	de->params = calloc(de->nparams, sizeof (char *));
+	if (de->params == NULL)
+		goto nomem;
+
+	va_start(va, fmt);
+	for (i = 0; i < de->nparams; i++) {
+		de->params[i] = strdup((char *)va_arg(va, char *));
+		if (de->params[i] == NULL) {
+			va_end(va);
+			goto nomem;
+		}
+	}
+	va_end(va);
+
+	return (de);
+
+nomem:;
+	int err = errno;
+	directory_error_free(de);
+	return (directory_error_internal_error(err));
+}
+
+/*
+ * Transform a directory_error returned by RPC into a directory_error_t.
+ */
+directory_error_t
+directory_error_from_rpc(directory_error_rpc *de_rpc)
+{
+	directory_error_t de;
+	int i;
+
+	de = calloc(1, sizeof (*de));
+	if (de == NULL)
+		goto nomem;
+
+	directory_errors_outstanding++;
+
+	de->is_static = B_FALSE;
+	de->code = strdup(de_rpc->code);
+	if (de->code == NULL)
+		goto nomem;
+	de->fmt = strdup(de_rpc->fmt);
+	if (de->fmt == NULL)
+		goto nomem;
+
+	de->nparams = de_rpc->params.params_len;
+
+	de->params = calloc(de->nparams, sizeof (char *));
+	if (de->params == NULL)
+		goto nomem;
+
+	for (i = 0; i < de->nparams; i++) {
+		de->params[i] = strdup(de_rpc->params.params_val[i]);
+		if (de->params[i] == NULL)
+			goto nomem;
+	}
+
+	return (de);
+
+nomem:;
+	int err = errno;
+	directory_error_free(de);
+	return (directory_error_internal_error(err));
+}
+
+/*
+ * Convert a directory_error_t into a directory_error to send over RPC.
+ *
+ * Returns TRUE on successful conversion, FALSE on failure.
+ *
+ * Frees the directory_error_t.
+ *
+ * Note that most functions in this suite return boolean_t, as defined
+ * by types.h.  This function is intended to be used directly as the
+ * return value from an RPC service function, and so it returns bool_t.
+ */
+bool_t
+directory_error_to_rpc(directory_error_rpc *de_rpc, directory_error_t de)
+{
+	int i;
+	idmap_utf8str *params;
+
+	de_rpc->code = strdup(de->code);
+	if (de_rpc->code == NULL)
+		goto nomem;
+
+	de_rpc->fmt = strdup(de->fmt);
+	if (de_rpc->fmt == NULL)
+		goto nomem;
+
+	params = calloc(de->nparams, sizeof (idmap_utf8str));
+	if (params == NULL)
+		goto nomem;
+	de_rpc->params.params_val = params;
+	de_rpc->params.params_len = de->nparams;
+
+	for (i = 0; i < de->nparams; i++) {
+		params[i] = strdup(de->params[i]);
+		if (params[i] == NULL)
+			goto nomem;
+	}
+
+	directory_error_free(de);
+	return (TRUE);
+
+nomem:
+	logger(LOG_ERR, "Warning:  failed to convert error for RPC\n"
+	    "Original error:  %s\n"
+	    "Conversion error:  %s\n",
+	    strerror(errno),
+	    directory_error_printable(de));
+	directory_error_free(de);
+	return (FALSE);
+}
+
+/*
+ * Determines whether this directory_error_t is an instance of the
+ * particular error, or a subclass of that error.
+ */
+boolean_t
+directory_error_is_instance_of(directory_error_t de, char *code)
+{
+	int len;
+
+	if (de == NULL || de->code == NULL)
+		return (B_FALSE);
+
+	len = strlen(code);
+
+	if (strncasecmp(de->code, code, len) != 0)
+		return (B_FALSE);
+
+	if (de->code[len] == '\0' || de->code[len] == '.')
+		return (B_TRUE);
+
+	return (B_FALSE);
+}
+
+/*
+ * Expand the directory_error_t in de into buf, returning the size of the
+ * resulting string including terminating \0.  If buf is NULL, just
+ * return the size.
+ *
+ * Return -1 if there are no substitutions, so that the caller can
+ * avoid memory allocation.
+ */
+static
+int
+directory_error_expand(char *buf, directory_error_t de)
+{
+	int bufsiz;
+	boolean_t has_subst;
+	const char *p;
+	char c;
+	long n;
+	const char *s;
+	char *newp;
+
+	bufsiz = 0;
+	has_subst = B_FALSE;
+
+	for (p = dgettext(TEXT_DOMAIN, de->fmt); *p != '\0'; ) {
+		c = *p++;
+		if (c == '%') {
+			has_subst = B_TRUE;
+			if (isdigit(*p)) {
+				n = strtol(p, &newp, 10);
+				p = newp;
+				if (de->params == NULL ||
+				    n < 1 ||
+				    n > de->nparams)
+					s = dgettext(TEXT_DOMAIN, "(missing)");
+				else
+					s = de->params[n - 1];
+				if (buf != NULL)
+					(void) strcpy(buf + bufsiz, s);
+				bufsiz += strlen(s);
+				continue;
+			}
+		}
+		if (buf != NULL)
+			buf[bufsiz] = c;
+		bufsiz++;
+	}
+
+	if (buf != NULL)
+		buf[bufsiz] = '\0';
+	bufsiz++;
+
+	return (has_subst ? bufsiz : -1);
+}
+
+/*
+ * Returns a printable version of this directory_error_t, suitable for
+ * human consumption.
+ *
+ * The value returned is valid as long as the directory_error_t is valid,
+ * and is freed when the directory_error_t is freed.
+ */
+const char *
+directory_error_printable(directory_error_t de)
+{
+	char *s;
+	int bufsiz;
+
+	if (de->printable != NULL)
+		return (de->printable);
+
+	bufsiz = directory_error_expand(NULL, de);
+
+	/*
+	 * Short circuit case to avoid memory allocation when there is
+	 * no parameter substitution.
+	 */
+	if (bufsiz < 0)
+		return (dgettext(TEXT_DOMAIN, de->fmt));
+
+	s = malloc(bufsiz);
+	if (s == NULL) {
+		return (dgettext(TEXT_DOMAIN,
+		    "Out of memory while expanding directory_error_t"));
+	}
+
+	(void) directory_error_expand(s, de);
+
+	/*
+	 * Stash the expansion away for later free, and to short-circuit
+	 * repeated expansions.
+	 */
+	de->printable = s;
+
+	return (de->printable);
+}
+
+/*
+ * Returns the error code for the particular error, as a string.
+ * Note that this function should not normally be used to answer
+ * the question "did error X happen", since the value returned
+ * could be a subclass of X.  directory_error_is_instance_of is intended
+ * to answer that question.
+ *
+ * The value returned is valid as long as the directory_error_t is valid,
+ * and is freed when the directory_error_t is freed.
+ */
+const char *
+directory_error_code(directory_error_t de)
+{
+	return (de->code);
+}
+
+/*
+ * Returns one of the parameters of the directory_error_t, or NULL if
+ * the parameter does not exist.
+ *
+ * Note that it is required that error subclasses have initial parameters
+ * the same as their superclasses.
+ *
+ * The value returned is valid as long as the directory_error_t is valid,
+ * and is freed when the directory_error_t is freed.
+ */
+const char *
+directory_error_param(directory_error_t de, int param)
+{
+	if (param >= de->nparams)
+		return (NULL);
+	return (de->params[param]);
+}
+
+/*
+ * Here are some (almost) constant directory_error_t structures
+ * for use in reporting errors encountered while creating a
+ * directory_error_t structure.  Unfortunately, the original error
+ * report is lost.
+ */
+#define	gettext(x)	x	/* let xgettext see these messages */
+static struct directory_error directory_error_ENOMEM = {
+	B_TRUE,
+	"ENOMEM.directory_error_t",
+	gettext("Out of memory while creating a directory_error_t"),
+	0, NULL,
+	NULL,
+};
+
+static struct directory_error directory_error_EAGAIN = {
+	B_TRUE,
+	"EAGAIN.directory_error_t",
+	gettext("Out of resources while creating a directory_error_t"),
+	0, NULL,
+	NULL,
+};
+
+/* 40 is big enough for even 128 bits */
+static char directory_error_unknown_errno[40] = "0";
+static char *directory_error_unknown_params[] = {
+    directory_error_unknown_errno
+};
+static struct directory_error directory_error_unknown = {
+	B_TRUE,
+	"Unknown.directory_error_t",
+	gettext("Unknown error (%1) while creating a directory_error_t"),
+	1, directory_error_unknown_params,
+	NULL,
+};
+#undef	gettext
+
+static
+directory_error_t
+directory_error_internal_error(int err)
+{
+	switch (err) {
+	case ENOMEM:	return (&directory_error_ENOMEM);
+	case EAGAIN:	return (&directory_error_EAGAIN);
+	default:
+		/* Pray that we don't have a reentrancy problem ... */
+		(void) sprintf(directory_error_unknown_errno, "%u", err);
+		return (&directory_error_unknown);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/directory_helper.c	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,302 @@
+/*
+ * 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.
+ */
+
+/*
+ * Some helper routines for directory lookup.  These offer functions that
+ * you could implement yourself on top of the generic routines, but since
+ * they're a common request we implement them here.  (Well, OK, we cheat a bit
+ * and call an internal routine to do the dirty work to reduce code
+ * duplication, but you could still implement them using the generic routines.)
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <libadutils.h>
+#include <rpcsvc/idmap_prot.h>
+#include "directory.h"
+#include "directory_private.h"
+#include "directory_library_impl.h"
+#include "miscutils.h"
+#include "sidutil.h"
+
+/*
+ * Given a username, return a text-form SID.
+ *
+ * The SID must be free()ed by the caller.
+ *
+ * d, if non-NULL, specifies an existing directory-search context.
+ * If NULL, a temporary one will be created.
+ */
+directory_error_t
+directory_sid_from_name_common(
+    directory_t d,
+    char *name,
+    char *type,
+    char **sid,
+    uint64_t *classes)
+{
+	directory_t d1 = NULL;
+	static char *attrs[] = {
+		"objectSid",
+		"objectClass",
+		NULL,
+	};
+	directory_entry_t *ret_list = NULL;
+	directory_error_t de;
+	struct ret_sid {
+		sid_t **objectSid;
+		char **objectClass;
+	} *ret_sid;
+
+	/* Prep for error cases. */
+	*sid = NULL;
+	if (classes != NULL)
+		*classes = 0;
+
+	if (d == NULL) {
+		de = directory_open(&d1);
+		if (de != NULL)
+			goto out;
+	} else {
+		d1 = d;
+	}
+
+	de = directory_get_v(d1, &ret_list, &name, 1, type, attrs);
+	if (de != NULL)
+		goto out;
+	if (ret_list[0].err != NULL) {
+		de = ret_list[0].err;
+		ret_list[0].err = NULL;
+		goto out;
+	}
+
+	ret_sid = (struct ret_sid *)ret_list[0].attrs;
+	if (ret_sid == NULL)
+		goto out;
+
+	if (ret_sid->objectSid != NULL &&
+	    ret_sid->objectSid[0] != NULL) {
+		char text_sid[SID_STRSZ+1];
+		sid_from_le(ret_sid->objectSid[0]);
+		sid_tostr(ret_sid->objectSid[0], text_sid);
+		*sid = strdup(text_sid);
+		if (*sid == NULL)
+			goto nomem;
+	}
+
+	if (ret_sid->objectClass != NULL &&
+	    classes != NULL)
+		*classes = class_bitmap(ret_sid->objectClass);
+
+	goto out;
+
+nomem:
+	de = directory_error("ENOMEM.directory_sid_from_name_common",
+	    "Insufficient memory retrieving data about SID", NULL);
+
+out:
+	directory_free(ret_list);
+	if (d == NULL)
+		directory_close(d1);
+	return (de);
+}
+
+directory_error_t
+directory_sid_from_name(
+    directory_t d,
+    char *name,
+    char **sid,
+    uint64_t *classes)
+{
+	return (directory_sid_from_name_common(d, name, DIRECTORY_ID_NAME, sid,
+	    classes));
+}
+
+directory_error_t
+directory_sid_from_user_name(directory_t d, char *name, char **sid)
+{
+	return (directory_sid_from_name_common(d, name, DIRECTORY_ID_USER, sid,
+	    NULL));
+}
+
+directory_error_t
+directory_sid_from_group_name(directory_t d, char *name, char **sid)
+{
+	return (directory_sid_from_name_common(d, name, DIRECTORY_ID_GROUP, sid,
+	    NULL));
+}
+
+/*
+ * Given a name or text-format SID, return a user@domain.
+ *
+ * The user@domain returned must be free()ed by the caller.
+ *
+ * Returns NULL and sets *name to NULL if no error occurred but the specified
+ * entity does not exist.
+ *
+ * d, if non-NULL, specifies an existing directory-search context.
+ * If NULL, a temporary one will be created.
+ */
+static
+directory_error_t
+directory_canon_common(
+    directory_t d,
+    char *id,
+    char *id_type,
+    char **canon,
+    uint64_t *classes)
+{
+	directory_t d1 = NULL;
+	directory_entry_t *ret_list = NULL;
+	directory_error_t de;
+	/*
+	 * Attributes required to generate a canonical name, in named-list and
+	 * structure form.
+	 */
+	static char *attrs[] = {
+		"x-sun-canonicalName",
+		"objectClass",
+		NULL,
+	};
+
+	struct canon_name_ret {
+		char **x_sun_canonicalName;
+		char **objectClass;
+	} *ret_name;
+
+	/* Prep for error cases. */
+	*canon = NULL;
+	if (classes != NULL)
+		*classes = 0;
+
+	if (d == NULL) {
+		de = directory_open(&d1);
+		if (de != NULL)
+			goto out;
+	} else {
+		d1 = d;
+	}
+
+	de = directory_get_v(d1, &ret_list, &id, 1, id_type, attrs);
+	if (de != NULL)
+		goto out;
+	if (ret_list[0].err != NULL) {
+		de = ret_list[0].err;
+		ret_list[0].err = NULL;
+		goto out;
+	}
+
+	ret_name = (struct canon_name_ret *)ret_list[0].attrs;
+	if (ret_name == NULL)
+		goto out;
+
+	if (ret_name->x_sun_canonicalName != NULL &&
+	    ret_name->x_sun_canonicalName[0] != NULL) {
+		*canon = strdup(ret_name->x_sun_canonicalName[0]);
+		if (*canon == NULL)
+			goto nomem;
+	}
+
+	if (ret_name->objectClass != NULL &&
+	    classes != NULL)
+		*classes = class_bitmap(ret_name->objectClass);
+
+	goto out;
+
+nomem:
+	de = directory_error("ENOMEM.directory_canon_common",
+	    "Insufficient memory retrieving data about name", NULL);
+
+out:
+	directory_free(ret_list);
+	if (d == NULL)
+		directory_close(d1);
+	return (de);
+}
+
+directory_error_t
+directory_name_from_sid(
+    directory_t d,
+    char *sid,
+    char **canon,
+    uint64_t *classes)
+{
+	return (directory_canon_common(d, sid, DIRECTORY_ID_SID, canon,
+	    classes));
+}
+
+directory_error_t
+directory_canon_from_name(
+    directory_t d,
+    char *name,
+    char **canon,
+    uint64_t *classes)
+{
+	return (directory_canon_common(d, name, DIRECTORY_ID_NAME, canon,
+	    classes));
+}
+
+directory_error_t
+directory_canon_from_user_name(directory_t d, char *name, char **canon)
+{
+	return (
+	    directory_canon_common(d, name, DIRECTORY_ID_USER, canon, NULL));
+}
+
+directory_error_t
+directory_canon_from_group_name(directory_t d, char *name, char **canon)
+{
+	return (
+	    directory_canon_common(d, name, DIRECTORY_ID_GROUP, canon, NULL));
+}
+
+boolean_t
+is_in_list(char **list, char *val)
+{
+	for (; *list != NULL; list++) {
+		if (strcaseeq(*list, val))
+			return (B_TRUE);
+	}
+	return (B_FALSE);
+}
+
+uint64_t
+class_bitmap(char **objectClass)
+{
+	uint64_t ret = 0;
+
+	for (; *objectClass != NULL; objectClass++) {
+		if (strcaseeq(*objectClass, "user") ||
+		    strcaseeq(*objectClass, "posixAccount"))
+			ret |= DIRECTORY_CLASS_USER;
+
+		if (strcaseeq(*objectClass, "group") ||
+		    strcaseeq(*objectClass, "posixGroup"))
+			ret |= DIRECTORY_CLASS_GROUP;
+	}
+
+	return (ret);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/directory_library_impl.h	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,50 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DIRECTORY_LIBRARY_IMPL_H
+#define	_DIRECTORY_LIBRARY_IMPL_H
+
+/*
+ * Internal implementation of the client side of directory lookup.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+directory_error_t directory_error_from_rpc(directory_error_rpc *de_rpc);
+bool_t directory_error_to_rpc(directory_error_rpc *de_rpc,
+    directory_error_t de);
+
+
+directory_error_t directory_get_v(directory_t d, directory_entry_list_t *ret,
+    char **ids, int nids, char *types, char **attr_list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DIRECTORY_LIBRARY_IMPL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/directory_private.h	Mon Jul 20 13:07:46 2009 -0400
@@ -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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DIRECTORY_PRIVATE_H
+#define	_DIRECTORY_PRIVATE_H
+
+/*
+ * A suite of functions for retrieving information about objects
+ * in a directory service.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+#define	DIRECTORY_ID_NAME	"n"
+#define	DIRECTORY_ID_USER	"u"
+#define	DIRECTORY_ID_GROUP	"g"
+#define	DIRECTORY_ID_SID	"s"
+
+/*
+ * Structure of the returned data.
+ * Note that this is constructed from the bottom up; what is returned is
+ * a directory_entry_list_t.
+ */
+typedef void *directory_datum_t;
+typedef directory_datum_t *directory_attribute_value_t;
+typedef struct {
+	directory_attribute_value_t *attrs;
+	directory_error_t err;
+} directory_entry_t;
+typedef directory_entry_t *directory_entry_list_t;
+
+/*
+ * Retrieve information about a user or group.  By way of analogy to exec(2),
+ * the _v variants accept a list of attributes as an array, while
+ * the _l variants accept the attribute list as arguments.
+ * All variations accept a list of identifiers, and return a
+ * directory_entry_list_t in the same order.  The length of the list of user
+ * identifiers can be specified either explicitly, or by a terminating
+ * NULL if the associated count is zero.  Attributes are returned in the
+ * order they were requested, with missing attributes yielding NULL
+ * entries.
+ */
+directory_error_t directory_get_v(directory_t d, directory_entry_list_t *ret,
+    char **ids, int nids, char *types, char **attrlist);
+
+directory_error_t directory_get_l(directory_t d, directory_entry_list_t *ret,
+    char **ids, int nids, char *types, char *attr1, ...);
+
+/*
+ * Free the data structure returned by directory_get_by*().
+ *
+ * Does nothing if list==NULL.
+ */
+void directory_free(directory_entry_list_t list);
+
+/* Return the number of bytes in a directory_datum_t */
+size_t directory_datum_len(directory_datum_t d);
+
+/*
+ * Search a list, case-insensitively, for a string
+ */
+boolean_t is_in_list(char **list, char *value);
+
+/*
+ * Examine an objectClass list and distill it into a bitmap of "interesting"
+ * classes.
+ */
+uint64_t class_bitmap(char **objectClass);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DIRECTORY_PRIVATE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/directory_rpc_clnt.c	Mon Jul 20 13:07:46 2009 -0400
@@ -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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * RPC shims for directory lookup.  Originally generated using rpcgen.
+ */
+
+#include <memory.h> /* for memset */
+#include <rpcsvc/idmap_prot.h>
+#ifndef _KERNEL
+#include <stdio.h>
+#include <stdlib.h> /* getenv, exit */
+#endif /* !_KERNEL */
+
+/* Default timeout can be changed using clnt_control() */
+static struct timeval TIMEOUT = { 25, 0 };
+
+enum clnt_stat
+directory_get_common_1(
+    idmap_utf8str_list ids,
+    idmap_utf8str types,
+    idmap_utf8str_list attrs,
+    directory_results_rpc *clnt_res,
+    CLIENT *clnt)
+{
+	directory_get_common_1_argument arg;
+	arg.ids = ids;
+	arg.attrs = attrs;
+	arg.types = types;
+	return (clnt_call(clnt, DIRECTORY_GET_COMMON,
+	    (xdrproc_t)xdr_directory_get_common_1_argument, (caddr_t)&arg,
+	    (xdrproc_t)xdr_directory_results_rpc, (caddr_t)clnt_res,
+	    TIMEOUT));
+}
--- a/usr/src/lib/libidmap/common/idmap_api.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libidmap/common/idmap_api.c	Mon Jul 20 13:07:46 2009 -0400
@@ -2072,9 +2072,9 @@
 
 	for (i = 0; stattable[i].msg; i++) {
 		if (stattable[i].retcode == status)
-			return (gettext(stattable[i].msg));
+			return (dgettext(TEXT_DOMAIN, stattable[i].msg));
 	}
-	return (gettext("Unknown error"));
+	return (dgettext(TEXT_DOMAIN, "Unknown error"));
 }
 
 
--- a/usr/src/lib/libidmap/common/idmap_impl.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libidmap/common/idmap_impl.h	Mon Jul 20 13:07:46 2009 -0400
@@ -134,6 +134,7 @@
 extern idmap_stat idmap_get_prop_str(idmap_handle_t *, idmap_prop_type,
     char **);
 
+extern idmap_logger logger;
 
 #ifdef __cplusplus
 }
--- a/usr/src/lib/libidmap/common/llib-lidmap	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libidmap/common/llib-lidmap	Mon Jul 20 13:07:46 2009 -0400
@@ -19,13 +19,17 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /* LINTLIBRARY */
 /* PROTOLIB1 */
 
 #include "idmap_impl.h"
+#include "miscutils.h"
+#include "directory.h"
+#include "directory_private.h"
+#include "sized_array.h"
+#include "directory_library_impl.h"
+#include "sidutil.h"
--- a/usr/src/lib/libidmap/common/mapfile-vers	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libidmap/common/mapfile-vers	Mon Jul 20 13:07:46 2009 -0400
@@ -40,70 +40,105 @@
 
 SUNWprivate {
     global:
-	xdr_idmap_retcode;
+	directory_canon_from_group_name;
+	directory_canon_from_name;
+	directory_canon_from_user_name;
+	directory_close;
+	directory_error;
+	directory_error_code;
+	directory_error_free;
+	directory_error_from_rpc;
+	directory_error_is_instance_of;
+	directory_error_param;
+	directory_error_printable;
+	directory_error_to_rpc;
+	directory_free;
+	directory_get_v;
+	directory_name_from_sid;
+	directory_open;
+	directory_sid_from_group_name;
+	directory_sid_from_name;
+	directory_sid_from_user_name;
+	idmap_cache_get_data;
+	idmap_fini;
+	idmap_fini_namemaps;
+	idmap_free;
+	idmap_getext_gidbysid;
+	idmap_getext_pidbysid;
+	idmap_getext_sidbygid;
+	idmap_getext_sidbyuid;
+	idmap_getext_uidbysid;
+	idmap_getgidbywinname;
+	idmap_getuidbywinname;
+	idmap_getwinnamebygid;
+	idmap_getwinnamebyuid;
+	idmap_get_create;
+	idmap_get_destroy;
+	idmap_get_gidbysid;
+	idmap_get_mappings;
+	idmap_get_namemap;
+	idmap_get_pidbysid;
+	idmap_get_sidbygid;
+	idmap_get_sidbyuid;
+	idmap_get_u2w_mapping;
+	idmap_get_uidbysid;
+	idmap_get_w2u_mapping;
+	idmap_info_cpy;
+	idmap_info_free;
+	idmap_info_mov;
+	idmap_init;
+	idmap_init_namemaps;
+	idmap_iter_destroy;
+	idmap_iter_mappings;
+	idmap_iter_namerules;
+	idmap_iter_next_mapping;
+	idmap_iter_next_namerule;
+	idmap_namerule_cpy;
+	idmap_set_logger;
+	idmap_set_namemap;
+	idmap_stat2string;
+	idmap_stat4prot;
+	idmap_string2stat;
+	idmap_udt_add_namerule;
+	idmap_udt_commit;
+	idmap_udt_create;
+	idmap_udt_destroy;
+	idmap_udt_flush_namerules;
+	idmap_udt_get_conflict_rule;
+	idmap_udt_get_error_index;
+	idmap_udt_get_error_rule;
+	idmap_udt_rm_namerule;
+	idmap_unset_namemap;
+	memdup;
+	sid_free;
+	sid_from_le;
+	sid_fromstr;
+	sid_len;
+	sid_to_le;
+	sid_tostr;
+	sized_array;
+	sized_array_free;
+	sized_array_n;
+	strcaseeq;
+	streq;
+	strndup;
+	xdr_directory_entry_rpc;
+	xdr_directory_get_common_1_argument;
+	xdr_directory_results_rpc;
+	xdr_idmap_ids_res;
+	xdr_idmap_id_res;
+	xdr_idmap_list_mappings_1_argument;
+	xdr_idmap_list_namerules_1_argument;
+	xdr_idmap_mapping;
+	xdr_idmap_mappings_res;
+	xdr_idmap_mapping_batch;
 	xdr_idmap_namerule;
 	xdr_idmap_namerules_res;
-	xdr_idmap_ids_res;
-	xdr_idmap_mapping_batch;
-	xdr_idmap_list_mappings_1_argument;
-	xdr_idmap_mappings_res;
-	xdr_idmap_update_batch;
-	xdr_idmap_list_namerules_1_argument;
-	xdr_idmap_mapping;
-	xdr_idmap_id_res;
-	xdr_idmap_update_res;
 	xdr_idmap_prop_res;
 	xdr_idmap_prop_type;
-	idmap_init;
-	idmap_fini;
-	idmap_free;
-	idmap_stat2string;
-	idmap_string2stat;
-	idmap_stat4prot;
-	idmap_iter_namerules;
-	idmap_iter_next_namerule;
-	idmap_iter_mappings;
-	idmap_iter_next_mapping;
-	idmap_iter_destroy;
-	idmap_get_create;
-	idmap_get_uidbysid;
-	idmap_get_gidbysid;
-	idmap_get_pidbysid;
-	idmap_get_sidbyuid;
-	idmap_get_sidbygid;
-	idmap_get_mappings;
-	idmap_get_destroy;
-	idmap_get_w2u_mapping;
-	idmap_get_u2w_mapping;
-	idmap_udt_add_namerule;
-	idmap_udt_rm_namerule;
-	idmap_udt_destroy;
-	idmap_udt_commit;
-	idmap_udt_create;
-	idmap_udt_get_error_index;
-	idmap_udt_get_error_rule;
-	idmap_udt_get_conflict_rule;
-	idmap_udt_flush_namerules;
-	idmap_getwinnamebyuid;
-	idmap_getwinnamebygid;
-	idmap_getuidbywinname;
-	idmap_getgidbywinname;
-	idmap_namerule_cpy;
-	idmap_info_free;
-	idmap_info_cpy;
-	idmap_info_mov;
-	idmap_getext_sidbygid;
-	idmap_getext_uidbysid;
-	idmap_getext_pidbysid;
-	idmap_getext_gidbysid;
-	idmap_getext_sidbyuid;
-	idmap_set_namemap;
-	idmap_unset_namemap;
-	idmap_get_namemap;
-	idmap_init_namemaps;
-	idmap_fini_namemaps;
-	idmap_cache_get_data;
-	idmap_set_logger;
+	xdr_idmap_retcode;
+	xdr_idmap_update_batch;
+	xdr_idmap_update_res;
     local:
 	*;
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/miscutils.c	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+/*
+ * Miscellaneous utility functions not specifically related to
+ * the application.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <ctype.h>
+#include "miscutils.h"
+
+/* Return true if strings are equal */
+boolean_t
+streq(const char *a, const char *b)
+{
+	return (strcmp(a, b) == 0);
+}
+
+/* Return true if strings are equal, case-insensitively */
+boolean_t
+strcaseeq(const char *a, const char *b)
+{
+	return (strcasecmp(a, b) == 0);
+}
+
+/* Return true if string a Begins With string b */
+boolean_t
+strbw(const char *a, const char *b)
+{
+	return (strncmp(a, b, strlen(b)) == 0);
+}
+
+/*
+ * Duplicate up to n bytes of a string.  Kind of sort of like
+ * strdup(strlcpy(s, n)).
+ */
+char *
+strndup(const char *s, int n)
+{
+	int len;
+	char *p;
+
+	len = strnlen(s, n);
+	p = malloc(len + 1);
+	if (p == NULL)
+		return (NULL);
+
+	if (len > 0)
+		(void) memcpy(p, s, len);
+	p[len] = '\0';
+
+	return (p);
+}
+
+/*
+ * Duplicate a block of memory.  Combines malloc with memcpy, much as
+ * strdup combines malloc, strlen, and strcpy.
+ */
+void *
+memdup(const void *buf, size_t sz)
+{
+	void *p;
+
+	p = malloc(sz);
+	if (p == NULL)
+		return (NULL);
+	(void) memcpy(p, buf, sz);
+	return (p);
+}
+
+/*
+ * Dump a block of memory in hex+ascii, for debugging
+ */
+void
+dump(FILE *out, const char *prefix, const void *buf, size_t len)
+{
+	const unsigned char *p = buf;
+	int i;
+
+	for (i = 0; i < len; i += 16) {
+		int j;
+
+		(void) fprintf(out, "%s", prefix);
+		for (j = 0; j < 16 && i + j < len; j++) {
+			(void) fprintf(out, "%2.2x ", p[i + j]);
+		}
+		for (; j < 16; j++) {
+			(void) fprintf(out, "   ");
+		}
+		for (j = 0; j < 16 && i + j < len; j++) {
+			(void) fprintf(out, "%c",
+			    isprint(p[i + j]) ? p[i + j] : '.');
+		}
+		(void) fprintf(out, "\n");
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/miscutils.h	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,51 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MISCUTILS_H
+#define	_MISCUTILS_H
+
+/*
+ * Miscellaneous functions and macros not directly related to the application.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define	NELEM(a)	(sizeof (a) / sizeof ((a)[0]))
+
+boolean_t strcaseeq(const char *a, const char *b);
+boolean_t streq(const char *a, const char *b);
+char *strndup(const char *s, int n);
+boolean_t strbw(const char *a, const char *b);
+void *memdup(const void *buf, size_t sz);
+void dump(FILE *out, const char *prefix, const void *buf, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MISCUTILS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/sidutil.c	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,189 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * This is an extract from usr/src/common/smbsrv/smb_sid.c,
+ * with functions renamed as part of a tentative plan for convergence.
+ */
+#ifndef _KERNEL
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <syslog.h>
+#else /* _KERNEL */
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#endif /* _KERNEL */
+
+#include <sidutil.h>
+
+/*
+ * sid_len
+ *
+ * Returns the number of bytes required to hold the sid.
+ */
+int
+sid_len(sid_t *sid)
+{
+	if (sid == NULL)
+		return (0);
+
+	return (sizeof (sid_t) - sizeof (uint32_t)
+	    + (sid->sid_subauthcnt * sizeof (uint32_t)));
+}
+
+/*
+ * sid_tostr
+ *
+ * Fill in the passed buffer with the string form of the given
+ * binary sid.
+ */
+void
+sid_tostr(sid_t *sid, char *strsid)
+{
+	char *p = strsid;
+	int i;
+
+	if (sid == NULL || strsid == NULL)
+		return;
+
+	(void) sprintf(p, "S-%d-", sid->sid_revision);
+	while (*p)
+		p++;
+
+	for (i = 0; i < NT_SID_AUTH_MAX; ++i) {
+		if (sid->sid_authority[i] != 0 || i == NT_SID_AUTH_MAX - 1) {
+			(void) sprintf(p, "%d", sid->sid_authority[i]);
+			while (*p)
+				p++;
+		}
+	}
+
+	for (i = 0; i < sid->sid_subauthcnt && i < NT_SID_SUBAUTH_MAX; ++i) {
+		(void) sprintf(p, "-%u", sid->sid_subauth[i]);
+		while (*p)
+			p++;
+	}
+}
+
+/*
+ * sid_fromstr
+ *
+ * Converts a SID in string form to a SID structure. There are lots of
+ * simplifying assumptions in here. The memory for the SID is allocated
+ * as if it was the largest possible SID; the caller is responsible for
+ * freeing the memory when it is no longer required. We assume that the
+ * string starts with "S-1-" and that the authority is held in the last
+ * byte, which should be okay for most situations. It also assumes the
+ * sub-authorities are in decimal format.
+ *
+ * On success, a pointer to a SID is returned. Otherwise a null pointer
+ * is returned.
+ */
+sid_t *
+sid_fromstr(char *sidstr)
+{
+	sid_t *sid;
+	char *p;
+	int size;
+	uint8_t i;
+
+	if (sidstr == NULL)
+		return (NULL);
+
+	if (strncmp(sidstr, "S-1-", 4) != 0)
+		return (NULL);
+
+	size = sizeof (sid_t) + (NT_SID_SUBAUTH_MAX * sizeof (uint32_t));
+
+	if ((sid = malloc(size)) == NULL)
+		return (NULL);
+
+	bzero(sid, size);
+	sid->sid_revision = NT_SID_REVISION;
+	sid->sid_authority[5] = atoi(&sidstr[4]);
+
+	for (i = 0, p = &sidstr[5]; i < NT_SID_SUBAUTH_MAX && *p; ++i) {
+		while (*p && *p == '-')
+			++p;
+
+		if (*p < '0' || *p > '9') {
+			free(sid);
+			return (NULL);
+		}
+
+		sid->sid_subauth[i] = strtoul(p, NULL, 10);
+
+		while (*p && *p != '-')
+			++p;
+	}
+
+	sid->sid_subauthcnt = i;
+	return (sid);
+}
+
+void
+sid_free(sid_t *sid)
+{
+#ifdef _KERNEL
+	if (sid == NULL)
+		return;
+
+	kmem_free(sid, sid_len(sid));
+#else
+	free(sid);
+#endif
+}
+
+void
+sid_to_le(sid_t *sid)
+{
+	int i;
+
+	for (i = 0; i < sid->sid_subauthcnt && i < NT_SID_SUBAUTH_MAX; ++i) {
+		uint32_t v = sid->sid_subauth[i];
+		uint8_t *p = (uint8_t *)&sid->sid_subauth[i];
+
+		p[0] = v & 0xff;
+		p[1] = (v >> 8) & 0xff;
+		p[2] = (v >> 16) & 0xff;
+		p[3] = (v >> 24) & 0xff;
+	}
+}
+
+void
+sid_from_le(sid_t *sid)
+{
+	int i;
+
+	for (i = 0; i < sid->sid_subauthcnt && i < NT_SID_SUBAUTH_MAX; ++i) {
+		uint32_t v;
+		uint8_t *p = (uint8_t *)&sid->sid_subauth[i];
+
+		v = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+
+		sid->sid_subauth[i] = v;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/sidutil.h	Mon Jul 20 13:07:46 2009 -0400
@@ -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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SIDUTIL_H
+#define	_SIDUTIL_H
+
+/*
+ * Security Identifier (SID) interface definition.
+ *
+ * This is an extract from uts/common/smbsrv/smb_sid.h, with functions
+ * renamed as part of a tentative plan for convergence.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Common definition for a SID.
+ */
+#define	NT_SID_REVISION		1
+#define	NT_SID_AUTH_MAX		6
+#define	NT_SID_SUBAUTH_MAX	15
+
+#if	!defined(ANY_SIZE_ARRAY)
+#define	ANY_SIZE_ARRAY	1
+#endif
+
+/*
+ * Security Identifier (SID)
+ *
+ * The security identifier (SID) uniquely identifies a user, group or
+ * a domain. It consists of a revision number, the identifier authority,
+ * and a list of sub-authorities. The revision number is currently 1.
+ * The identifier authority identifies which system issued the SID. The
+ * sub-authorities of a domain SID uniquely identify a domain. A user
+ * or group SID consists of a domain SID with the user or group id
+ * appended. The user or group id (also known as a relative id (RID)
+ * uniquely identifies a user within a domain. A user or group SID
+ * uniquely identifies a user or group across all domains. The SidType
+ * values identify the various types of SID.
+ *
+ *      1   1   1   1   1   1
+ *      5   4   3   2   1   0   9   8   7   6   5   4   3   2   1   0
+ *   +---------------------------------------------------------------+
+ *   |      SubAuthorityCount        |Reserved1 (SBZ)|   Revision    |
+ *   +---------------------------------------------------------------+
+ *   |                   IdentifierAuthority[0]                      |
+ *   +---------------------------------------------------------------+
+ *   |                   IdentifierAuthority[1]                      |
+ *   +---------------------------------------------------------------+
+ *   |                   IdentifierAuthority[2]                      |
+ *   +---------------------------------------------------------------+
+ *   |                                                               |
+ *   +- -  -  -  -  -  -  -  SubAuthority[]  -  -  -  -  -  -  -  - -+
+ *   |                                                               |
+ *   +---------------------------------------------------------------+
+ *
+ */
+/*
+ * Note: NT defines the Identifier Authority as a separate
+ * structure (SID_IDENTIFIER_AUTHORITY) containing a literal
+ * definition of a 6 byte vector but the effect is the same
+ * as defining it as a member value.
+ */
+typedef struct sid {
+	uint8_t sid_revision;
+	uint8_t sid_subauthcnt;
+	uint8_t sid_authority[NT_SID_AUTH_MAX];
+	uint32_t sid_subauth[ANY_SIZE_ARRAY];
+} sid_t;
+
+/*
+ * The maximum size of a SID in string format
+ */
+#define	SID_STRSZ		256
+
+/* Given a SID, return its length in bytes. */
+int sid_len(sid_t *);
+
+/* Given a dynamically allocated SID (e.g. from sid_fromstr), free it. */
+void sid_free(sid_t *);
+
+/* Translate a binary-format SID into the supplied SID_STRSZ buffer. */
+void sid_tostr(sid_t *, char *);
+
+/* Translate a text-format SID into an allocated binary-format SID. */
+sid_t *sid_fromstr(char *);
+
+/* In-place, translate a host-order SID into MS-native little endian. */
+void sid_to_le(sid_t *);
+
+/* In-place, translate a MS-native little endian SID into host order. */
+void sid_from_le(sid_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SIDUTIL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/sized_array.c	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,122 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Much like calloc, but with functions to report the size of the
+ * allocation given only the pointer.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <malloc.h>
+#include "sized_array.h"
+
+/*
+ * Assumes that int is at least 32 bits and that nothing needs more than
+ * 8-byte alignment.
+ */
+
+/* COOKIE provides some bad-pointer protection. */
+#define	COOKIE	"SACOOKIE"
+
+struct sized_array {
+	int	n;
+	int	sz;
+#if	defined(COOKIE)
+	char	cookie[8];
+#endif
+};
+
+
+void *
+sized_array(size_t n, size_t sz)
+{
+	struct sized_array *sa;
+	size_t total;
+
+	total = sizeof (struct sized_array) + n*sz;
+
+	sa = malloc(total);
+
+	if (sa == NULL)
+		return (NULL);
+
+	(void) memset(sa, 0, total);
+
+	sa->n = n;
+	sa->sz = sz;
+
+#if	defined(COOKIE)
+	(void) memcpy(sa->cookie, COOKIE, sizeof (sa->cookie));
+#endif
+
+	return ((void *)(sa + 1));
+}
+
+void
+sized_array_free(void *p)
+{
+	struct sized_array *sa;
+
+	if (p == NULL)
+		return;
+
+	sa = ((struct sized_array *)p)-1;
+
+#if	defined(COOKIE)
+	assert(memcmp(sa->cookie, COOKIE, sizeof (sa->cookie)) == 0);
+#endif
+
+	free(sa);
+}
+
+size_t
+sized_array_n(void *p)
+{
+	struct sized_array *sa;
+
+	sa = ((struct sized_array *)p)-1;
+
+#if	defined(COOKIE)
+	assert(memcmp(sa->cookie, COOKIE, sizeof (sa->cookie)) == 0);
+#endif
+
+	return (sa->n);
+}
+
+size_t
+sized_array_sz(void *p)
+{
+	struct sized_array *sa;
+
+	sa = ((struct sized_array *)p)-1;
+
+#if	defined(COOKIE)
+	assert(memcmp(sa->cookie, COOKIE, sizeof (sa->cookie)) == 0);
+#endif
+
+	return (sa->sz);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/sized_array.h	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#ifndef _SIZED_ARRAY_H
+#define	_SIZED_ARRAY_H
+
+/*
+ * Like calloc, but with mechanisms to get the size of the allocated
+ * area given only the pointer.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *sized_array(size_t n, size_t sz);
+void sized_array_free(void *p);
+size_t sized_array_n(void *p);
+size_t sized_array_sz(void *p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SIZED_ARRAY_H */
--- a/usr/src/lib/libkmf/libkmf/common/certop.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libkmf/libkmf/common/certop.c	Mon Jul 20 13:07:46 2009 -0400
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <stdio.h>
 #include <link.h>
 #include <fcntl.h>
@@ -955,12 +953,14 @@
  * where we want to force this operation to happen in
  * a specific keystore.
  * For example:
- *    libelfsign verifies signatures on crypto libraries.
- *    We cannot use libpkcs11 functions to verify the pkcs11
- *    libraries because it results in a circular dependency.
- *    So, when libelfsign is verifying library sigs, it
- *    always forces the operation to happen in OpenSSL
- *    to avoid the circular dependency.
+ *    libelfsign.so.1 verifies signatures on crypto libraries.
+ *    We must use pkcs11 functions to verify the pkcs11
+ *    plugins in order to keep the validation within the
+ *    Cryptographic Framework's FIPS-140 boundary. To avoid
+ *    a circular dependency, pksc11_softtoken.so.1 is
+ *    interposed by libkcfd.so.1 via kcfd, which prevents
+ *    libpkcs11.so.1's interfaces from being used when libkmf.so.1
+ *    is called from kcfd.
  */
 static KMF_RETURN
 plugin_verify_data_with_cert(KMF_HANDLE_T handle,
@@ -976,8 +976,6 @@
 	/*
 	 * If NSS, use PKCS#11, we are not accessing the database(s),
 	 * we just prefer the "verify" operation from the crypto framework.
-	 * The OpenSSL version is unique in order to avoid a dependency loop
-	 * with the kcfd(1M) process.
 	 */
 	if (kstype == KMF_KEYSTORE_NSS)
 		kstype = KMF_KEYSTORE_PK11TOKEN;
@@ -3109,9 +3107,8 @@
 
 /*
  * Use a signer cert to verify another certificate's signature.
- * This code forces the use of the OPENSSL mechanism
- * for the verify operation to avoid a circular dependency
- * with libelfsign when it attempts to verify the PKCS#11 libraries.
+ * This code forces the use of the PKCS11 mechanism for the verify
+ * operation for the Cryptographic Framework's FIPS-140 boundary.
  */
 static KMF_RETURN
 verify_cert_with_cert(KMF_HANDLE_T handle,
@@ -3172,11 +3169,10 @@
 	}
 
 	/*
-	 * To avoid recursion with kcfd consumer and libpkcs11,
-	 * do the certificate verification using the OpenSSL
-	 * plugin algorithms instead of the crypto framework.
+	 * Force use of PKCS11 API for kcfd/libelfsign.  This is
+	 * required for the Cryptographic Framework's FIPS-140 boundary.
 	 */
-	ret = plugin_verify_data_with_cert(handle, KMF_KEYSTORE_OPENSSL,
+	ret = plugin_verify_data_with_cert(handle, KMF_KEYSTORE_PK11TOKEN,
 	    algid, &data_to_verify, &signature,	SignerCertData);
 
 cleanup:
--- a/usr/src/lib/libkmf/libkmf/common/generalop.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libkmf/libkmf/common/generalop.c	Mon Jul 20 13:07:46 2009 -0400
@@ -19,13 +19,11 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <stdio.h>
 #include <dlfcn.h>
 #include <link.h>
@@ -329,7 +327,13 @@
 		free(p);
 		return (KMF_ERR_MEMORY);
 	}
-	p->dldesc = dlopen(path, RTLD_LAZY | RTLD_GROUP | RTLD_PARENT);
+	/*
+	 * Do not use RTLD_GROUP here, or this will cause a circular
+	 * dependency when kmf_pkcs11.so.1 gets its PKCS#11 functions
+	 * from libpkcs11.so.1 when kmf is used via libelfsign.so.1
+	 * called from kcfd.
+	 */
+	p->dldesc = dlopen(path, RTLD_LAZY | RTLD_PARENT);
 	if (p->dldesc == NULL) {
 		free(p->path);
 		free(p);
--- a/usr/src/lib/libpkg/common/isdir.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libpkg/common/isdir.c	Mon Jul 20 13:07:46 2009 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -40,6 +40,7 @@
 #include <string.h>
 #include "pkglocale.h"
 #include "pkglibmsgs.h"
+#include "pkglib.h"
 
 /*
  * Defines for cpio/compression checks.
@@ -77,6 +78,7 @@
 int isdir(char *path);
 int isfile(char *dir, char *file);
 int iscpio(char *path, int *iscomp);
+int eval_ftype(char *path, char ftype, char *myftype);
 
 /*
  * Name:	isdir
@@ -389,3 +391,83 @@
 
 	(void) fclose(fp);
 }
+
+/*
+ * Name:	eval_ftype
+ * Description: Evaluate the target's file type
+ * Arguments:	path      - Path on filesystem
+ *		ftype     - Type to be changed to
+ *		myftype   - Address into which current
+ *			    type of target will be stored
+ * Returns:	int
+ *			0	 - Success
+ *			VE_EXIST - Path does not exist
+ *			VE_FTYPE - Path file type is not recognized,
+ *				   is not supported,
+ *				   or is not what is expected
+ */
+int
+eval_ftype(char *path, char ftype, char *myftype)
+{
+	struct stat status;
+	int retcode = 0;
+	int statError = 0;
+
+	/* If we are to process symlinks the old way then we follow the link */
+	if (nonABI_symlinks()) {
+		if ((ftype == 's') ? lstat(path, &status) :
+		    stat(path, &status)) {
+			(void) reperr(pkg_gt(ERR_EXIST));
+			retcode = VE_EXIST;
+			*myftype = '?';
+			statError++;
+		}
+	/* If not then we inspect the target of the link */
+	} else {
+		if (lstat(path, &status) == -1) {
+			reperr(pkg_gt(ERR_EXIST));
+			retcode = VE_EXIST;
+			*myftype = '?';
+			statError++;
+		}
+	}
+	if (!statError) {
+		/* determining actual type of existing object */
+		switch (status.st_mode & S_IFMT) {
+			case S_IFLNK:
+					*myftype = 's';
+					break;
+
+			case S_IFIFO:
+					*myftype = 'p';
+					break;
+
+			case S_IFCHR:
+					*myftype = 'c';
+					break;
+
+			case S_IFDIR:
+					*myftype = 'd';
+					break;
+
+			case S_IFBLK:
+					*myftype = 'b';
+					break;
+
+			case S_IFREG:
+			case 0:
+					*myftype = 'f';
+					break;
+
+			case S_IFDOOR:
+					*myftype = 'D';
+					break;
+
+			default:
+					*myftype = '?';
+					return (VE_FTYPE);
+		}
+		retcode = 0;
+	}
+	return (retcode);
+}
--- a/usr/src/lib/libpkg/common/mapfile-vers	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libpkg/common/mapfile-vers	Mon Jul 20 13:07:46 2009 -0400
@@ -89,6 +89,7 @@
 	epclose;
 	epopen;
 	esystem;
+	eval_ftype;
 	find_ca_certs;
 	find_cl_certs;
 	find_key_cert_pair;
--- a/usr/src/lib/libpkg/common/pkglib.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libpkg/common/pkglib.h	Mon Jul 20 13:07:46 2009 -0400
@@ -499,10 +499,12 @@
 extern void	ds_putinfo(char *buf);
 extern void	ds_skiptoend(char *device);
 extern void	ecleanup(void);
+extern int	eval_ftype(char *path, char ftype, char *myftype);
 /*PRINTFLIKE1*/
 extern void	logerr(char *fmt, ...);
 extern int	mappath(int flag, char *path);
 extern int	mapvar(int flag, char *varname);
+extern void	reperr(char *fmt, ...);
 /*PRINTFLIKE1*/
 extern void	progerr(char *fmt, ...);
 extern void	pkgerr(PKG_ERR *);
@@ -626,6 +628,7 @@
 extern int	isPathRemote();
 extern int	iscpio();
 extern int	isdir();
+extern int	eval_ftype();
 extern int	isfile();
 extern int	pkgexecl();
 extern int	pkgexecv();
@@ -653,6 +656,7 @@
 extern void	ds_skiptoend();
 extern void	ecleanup();
 extern void	logerr();
+extern void	reperr();
 extern int	mappath();
 extern int	mapvar();
 extern void	progerr();
--- a/usr/src/lib/libpkg/common/verify.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libpkg/common/verify.c	Mon Jul 20 13:07:46 2009 -0400
@@ -85,7 +85,7 @@
 } CHECKSUM_T;
 
 /*PRINTFLIKE1*/
-static void
+void
 reperr(char *fmt, ...)
 {
 	char	*pt;
@@ -392,7 +392,6 @@
 	int		uid, gid;
 	int		dochown;
 	int		retcode;
-	int		statError = 0;
 	int		targ_is_dir = 0;	/* replacing a directory */
 	char		myftype;
 	char		buf[PATH_MAX];
@@ -491,62 +490,19 @@
 
 	retcode = 0;
 
-	/* If we are to process symlinks the old way then we follow the link */
-	if (nonABI_symlinks()) {
-		if ((*ftype == 's') ? lstat(path, &status) :
-			stat(path, &status)) {
-			reperr(pkg_gt(ERR_EXIST));
-			retcode = VE_EXIST;
-			myftype = '?';
-			statError++;
-		}
-	/* If not then we inspect the target of the link */
-	} else {
-		if ((n = lstat(path, &status)) == -1) {
-			reperr(pkg_gt(ERR_EXIST));
-			retcode = VE_EXIST;
-			myftype = '?';
-			statError++;
-		}
-	}
-	if (!statError) {
-		/* determining actual type of existing object */
-		switch (status.st_mode & S_IFMT) {
-		    case S_IFLNK:
-			myftype = 's';
-			break;
+	/* Evaluate the file type of existing object */
+	retcode = eval_ftype(path, *ftype, &myftype);
 
-		    case S_IFIFO:
-			myftype = 'p';
-			break;
-
-		    case S_IFCHR:
-			myftype = 'c';
-			break;
-
-		    case S_IFDIR:
-			myftype = 'd';
-			targ_is_dir = 1;
-			break;
+	/*
+	 * If path file type is not recognized, is not supported or
+	 * is not what is expected, return
+	 */
+	if (retcode == VE_FTYPE)
+		return (retcode);
 
-		    case S_IFBLK:
-			myftype = 'b';
-			break;
-
-		    case S_IFREG:
-		    case 0:
-			myftype = 'f';
-			break;
-
-		    case S_IFDOOR:
-			myftype = 'D';
-			break;
-
-		    default:
-			reperr(pkg_gt(ERR_UNKNOWN));
-			return (VE_FTYPE);
-		}
-	}
+	/* If existing type is Directory, then set flag */
+	if (myftype == 'd')
+		targ_is_dir = 1;
 
 	if (setval) {
 		/*
--- a/usr/src/lib/libproc/common/libproc.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libproc/common/libproc.h	Mon Jul 20 13:07:46 2009 -0400
@@ -359,8 +359,6 @@
 			int, int, int, void *, int *);
 extern	int	pr_processor_bind(struct ps_prochandle *,
 			idtype_t, id_t, int, int *);
-extern	int	pr_pset_bind(struct ps_prochandle *,
-			int, idtype_t, id_t, int *);
 
 /*
  * Function prototypes for accessing per-LWP register information.
--- a/usr/src/lib/libproc/common/llib-lproc	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libproc/common/llib-lproc	Mon Jul 20 13:07:46 2009 -0400
@@ -22,7 +22,7 @@
 /* PROTOLIB1 */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #include "libproc.h"
@@ -304,7 +304,6 @@
 
 /* pr_pbind.c */
 int	pr_processor_bind(struct ps_prochandle *Pr, idtype_t, id_t, int, int *);
-int	pr_pset_bind(struct ps_prochandle *Pr, int, idtype_t, id_t, int *);
 
 /* pr_rename.c */
 int	pr_rename(struct ps_prochandle *Pr, const char *old, const char *new);
--- a/usr/src/lib/libproc/common/mapfile-vers	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libproc/common/mapfile-vers	Mon Jul 20 13:07:46 2009 -0400
@@ -220,7 +220,6 @@
 	proc_walk;
 	pr_open;
 	pr_processor_bind;
-	pr_pset_bind;
 	pr_rename;
 	pr_setitimer;
 	pr_setprojrctl;
--- a/usr/src/lib/libproc/common/pr_pbind.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libproc/common/pr_pbind.c	Mon Jul 20 13:07:46 2009 -0400
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/procset.h>
 #include <sys/processor.h>
@@ -90,66 +87,3 @@
 	}
 	return (rval.sys_rval1);
 }
-
-int
-pr_pset_bind(struct ps_prochandle *Pr, int pset, idtype_t idtype, id_t id,
-    int *opset)
-{
-	sysret_t rval;			/* return value */
-	argdes_t argd[5];		/* arg descriptors */
-	argdes_t *adp = &argd[0];	/* first argument */
-	int error;
-
-	if (Pr == NULL)		/* no subject process */
-		return (pset_bind(pset, idtype, id, opset));
-
-	adp->arg_value = PSET_BIND;	/* PSET_BIND */
-	adp->arg_object = NULL;
-	adp->arg_type = AT_BYVAL;
-	adp->arg_inout = AI_INPUT;
-	adp->arg_size = 0;
-	adp++;
-
-	adp->arg_value = pset;		/* pset */
-	adp->arg_object = NULL;
-	adp->arg_type = AT_BYVAL;
-	adp->arg_inout = AI_INPUT;
-	adp->arg_size = 0;
-	adp++;
-
-	adp->arg_value = idtype;	/* idtype */
-	adp->arg_object = NULL;
-	adp->arg_type = AT_BYVAL;
-	adp->arg_inout = AI_INPUT;
-	adp->arg_size = 0;
-	adp++;
-
-	adp->arg_value = id;		/* id */
-	adp->arg_object = NULL;
-	adp->arg_type = AT_BYVAL;
-	adp->arg_inout = AI_INPUT;
-	adp->arg_size = 0;
-	adp++;
-
-	if (opset == NULL) {
-		adp->arg_value = 0;	/* opset */
-		adp->arg_object = NULL;
-		adp->arg_type = AT_BYVAL;
-		adp->arg_inout = AI_INPUT;
-		adp->arg_size = 0;
-	} else {
-		adp->arg_value = 0;
-		adp->arg_object = opset;
-		adp->arg_type = AT_BYREF;
-		adp->arg_inout = AI_INOUT;
-		adp->arg_size = sizeof (int);
-	}
-
-	error = Psyscall(Pr, &rval, SYS_pset, 5, &argd[0]);
-
-	if (error) {
-		errno = (error < 0)? ENOSYS : error;
-		return (-1);
-	}
-	return (rval.sys_rval1);
-}
--- a/usr/src/lib/libstmf/common/libstmf.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libstmf/common/libstmf.h	Mon Jul 20 13:07:46 2009 -0400
@@ -129,6 +129,7 @@
 	STMF_LU_PROP_FILENAME,
 	STMF_LU_PROP_GUID,
 	STMF_LU_PROP_META_FILENAME,
+	STMF_LU_PROP_MGMT_URL,
 	STMF_LU_PROP_NEW,
 	STMF_LU_PROP_SIZE,
 	STMF_LU_PROP_WRITE_PROTECT,
--- a/usr/src/lib/libstmf/common/libstmf_impl.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libstmf/common/libstmf_impl.h	Mon Jul 20 13:07:46 2009 -0400
@@ -55,6 +55,8 @@
 	uint32_t    companyId;
 	boolean_t   luAliasValid;
 	char	    luAlias[256];
+	boolean_t   luMgmtUrlValid;
+	char	    luMgmtUrl[1024];
 	boolean_t   vidValid;
 	char	    vid[8];
 	boolean_t   pidValid;
--- a/usr/src/lib/libstmf/common/stmf.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/libstmf/common/stmf.c	Mon Jul 20 13:07:46 2009 -0400
@@ -1078,6 +1078,7 @@
 	int metaFileNameLen = 0;
 	int serialNumLen = 0;
 	int luAliasLen = 0;
+	int luMgmtUrlLen = 0;
 	int sluBufSize = 0;
 	int bufOffset = 0;
 	int fd = 0;
@@ -1117,6 +1118,11 @@
 		sluBufSize += luAliasLen + 1;
 	}
 
+	if (disk->luMgmtUrlValid) {
+		luMgmtUrlLen = strlen(disk->luMgmtUrl);
+		sluBufSize += luMgmtUrlLen + 1;
+	}
+
 	/*
 	 * 8 is the size of the buffer set aside for
 	 * concatenation of variable length fields
@@ -1161,6 +1167,14 @@
 		bufOffset += luAliasLen + 1;
 	}
 
+	if (disk->luMgmtUrlValid) {
+		sbdLu->slu_mgmt_url_valid = 1;
+		sbdLu->slu_mgmt_url_off = bufOffset;
+		bcopy(disk->luMgmtUrl, &(sbdLu->slu_buf[bufOffset]),
+		    luMgmtUrlLen + 1);
+		bufOffset += luMgmtUrlLen + 1;
+	}
+
 	if (disk->luSizeValid) {
 		sbdLu->slu_lu_size_valid = 1;
 		sbdLu->slu_lu_size = disk->luSize;
@@ -1665,6 +1679,7 @@
 	switch (prop) {
 		case STMF_LU_PROP_ALIAS:
 		case STMF_LU_PROP_SIZE:
+		case STMF_LU_PROP_MGMT_URL:
 		case STMF_LU_PROP_WRITE_PROTECT:
 		case STMF_LU_PROP_WRITE_CACHE_DISABLE:
 			return (STMF_STATUS_SUCCESS);
@@ -1680,6 +1695,7 @@
 {
 	int ret = STMF_STATUS_SUCCESS;
 	int luAliasLen = 0;
+	int luMgmtUrlLen = 0;
 	int mluBufSize = 0;
 	int bufOffset = 0;
 	int fd = 0;
@@ -1710,6 +1726,11 @@
 		mluBufSize += luAliasLen + 1;
 	}
 
+	if (disk->luMgmtUrlValid) {
+		luMgmtUrlLen = strlen(disk->luMgmtUrl);
+		mluBufSize += luMgmtUrlLen + 1;
+	}
+
 	/*
 	 * 8 is the size of the buffer set aside for
 	 * concatenation of variable length fields
@@ -1732,6 +1753,14 @@
 		bufOffset += luAliasLen + 1;
 	}
 
+	if (disk->luMgmtUrlValid) {
+		sbdLu->mlu_mgmt_url_valid = 1;
+		sbdLu->mlu_mgmt_url_off = bufOffset;
+		bcopy(disk->luMgmtUrl, &(sbdLu->mlu_buf[bufOffset]),
+		    luMgmtUrlLen + 1);
+		bufOffset += luMgmtUrlLen + 1;
+	}
+
 	if (disk->luSizeValid) {
 		sbdLu->mlu_lu_size_valid = 1;
 		sbdLu->mlu_lu_size = disk->luSize;
@@ -2123,6 +2152,16 @@
 		    diskLu->serialNum, sbdProps->slp_serial_size);
 	}
 
+	if (sbdProps->slp_mgmt_url_valid) {
+		diskLu->luMgmtUrlValid = B_TRUE;
+		if (strlcpy(diskLu->luMgmtUrl,
+		    (char *)&(sbdProps->slp_buf[sbdProps->slp_mgmt_url_off]),
+		    sizeof (diskLu->luMgmtUrl)) >=
+		    sizeof (diskLu->luMgmtUrl)) {
+			return (STMF_STATUS_ERROR);
+		}
+	}
+
 	if (sbdProps->slp_alias_valid) {
 		diskLu->luAliasValid = B_TRUE;
 		if (strlcpy(diskLu->luAlias,
@@ -2250,6 +2289,16 @@
 				return (STMF_ERROR_INVALID_ARG);
 			}
 			break;
+		case STMF_LU_PROP_MGMT_URL:
+			if (diskLu->luMgmtUrlValid == B_FALSE) {
+				return (STMF_ERROR_NO_PROP);
+			}
+			if ((reqLen = strlcpy(propVal, diskLu->luMgmtUrl,
+			    *propLen)) >= *propLen) {
+				*propLen = reqLen + 1;
+				return (STMF_ERROR_INVALID_ARG);
+			}
+			break;
 		case STMF_LU_PROP_GUID:
 			if (diskLu->luGuidValid == B_FALSE) {
 				return (STMF_ERROR_NO_PROP);
@@ -2463,6 +2512,14 @@
 			}
 			diskLu->luMetaFileNameValid = B_TRUE;
 			break;
+		case STMF_LU_PROP_MGMT_URL:
+			if ((strlcpy(diskLu->luMgmtUrl, propVal,
+			    sizeof (diskLu->luMgmtUrl))) >=
+			    sizeof (diskLu->luMgmtUrl)) {
+				return (STMF_ERROR_INVALID_PROPSIZE);
+			}
+			diskLu->luMgmtUrlValid = B_TRUE;
+			break;
 		case STMF_LU_PROP_PID:
 			if ((propSize = strlen(propVal)) >
 			    sizeof (diskLu->pid)) {
@@ -3076,9 +3133,8 @@
 	}
 	(*groupList)->cnt = stmfIoctl.stmf_obuf_nentries;
 	for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) {
-		bcopy(iGroupList->name, (*groupList)->name[i],
+		bcopy(iGroupList[i].name, (*groupList)->name[i],
 		    sizeof (stmfGroupName));
-		iGroupList++;
 	}
 
 done:
@@ -3224,10 +3280,9 @@
 	(*groupProps)->cnt = stmfIoctl.stmf_obuf_nentries;
 	for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) {
 		(*groupProps)->name[i].identLength =
-		    iGroupMembers->ident_size;
-		bcopy(iGroupMembers->ident, (*groupProps)->name[i].ident,
-		    iGroupMembers->ident_size);
-		iGroupMembers++;
+		    iGroupMembers[i].ident_size;
+		bcopy(iGroupMembers[i].ident, (*groupProps)->name[i].ident,
+		    iGroupMembers[i].ident_size);
 	}
 
 done:
--- a/usr/src/lib/pkcs11/Makefile	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/pkcs11/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -35,7 +35,8 @@
 
 SUBDIRS = \
 	libpkcs11	\
-	libsoftcrypto
+	libsoftcrypto   \
+	libkcfd
 
 #
 # The PKCS11 TPM provider is only available for x86.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pkcs11/libkcfd/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,47 @@
+#
+# 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.
+#
+# lib/pkcs11/libkcfd/Makefile
+#
+
+include $(SRC)/lib/Makefile.lib
+
+SUBDIRS=	$(MACH)
+
+all	:=	TARGET= all
+clean	:=	TARGET= clean
+clobber	:=	TARGET= clobber
+install	:=	TARGET= install
+
+.KEEP_STATE:
+
+all clean clobber install: $(SUBDIRS)
+
+check lint install_h:
+
+$(SUBDIRS):	FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pkcs11/libkcfd/Makefile.com	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,40 @@
+#
+# 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.
+#
+# lib/pkcs11/libkcfd/Makefile.com
+#
+
+LIBRARY = libkcfd.a
+VERS = .1
+
+include $(SRC)/lib/Makefile.rootfs
+
+LIBS +=		$(LINTLIB)
+
+#
+# Identify that this library is an interposer. This identification
+# ensures that runtime symbol lookup resolves to this library
+# (before libpkcs11.so.1) regardless of dependency link order.
+# This library should only be linked to by kcfd.
+#
+DYNFLAGS	+= $(ZINTERPOSE) -R/usr/lib/security
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pkcs11/libkcfd/README	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,37 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+This is a filter library that's used exclusively by kcfd;
+it's 32-bit-only because kcfd is 32-bit-only.
+
+libkcfd forces interposition of pkcs11_softtoken.so.1 into libkmf
+when used by kcfd as part of the Cryptographic Framework's FIPS-140
+project, to ensure that only pkcs11_softtoken.so.1 is used for
+validation of the FIPS-140 boundary.
+
+libelfsign could not be the interposer, because it would prevent
+the elfsign(1) command from accessing actual PKCS#11 tokens when using
+the -T option.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pkcs11/libkcfd/common/llib-lkcfd	Mon Jul 20 13:07:46 2009 -0400
@@ -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
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved. 
+ * Use is subject to license terms.
+ */
+
+/*
+ * usr/src/lib/pkcs11/libkcfd
+ * EMPTY library
+ */
+
+#include <security/cryptoki.h>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pkcs11/libkcfd/common/mapfile-vers	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,112 @@
+#
+# 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.
+#
+
+#
+# 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
+#
+
+SUNW_1.1 {
+    global:
+	C_CancelFunction = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_CloseAllSessions = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_CloseSession = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_CopyObject = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_CreateObject = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_Decrypt = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_DecryptDigestUpdate = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_DecryptFinal = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_DecryptInit = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_DecryptUpdate = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_DecryptVerifyUpdate = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_DeriveKey = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_DestroyObject = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_Digest = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_DigestEncryptUpdate = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_DigestFinal = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_DigestInit = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_DigestKey = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_DigestUpdate = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_Encrypt = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_EncryptFinal = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_EncryptInit = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_EncryptUpdate = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_Finalize = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_FindObjects = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_FindObjectsFinal = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_FindObjectsInit = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_GenerateKey = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_GenerateKeyPair = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_GenerateRandom = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_GetAttributeValue = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_GetFunctionList = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_GetFunctionStatus = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_GetInfo = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_GetMechanismInfo = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_GetMechanismList = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_GetObjectSize = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_GetOperationState = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_GetSessionInfo = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_GetSlotInfo = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_GetSlotList = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_GetTokenInfo = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_Initialize = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_InitPIN = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_InitToken = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_Login = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_Logout = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_OpenSession = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_SeedRandom = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_SetAttributeValue = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_SetOperationState = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_SetPIN = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_Sign = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_SignEncryptUpdate = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_SignFinal = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_SignInit = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_SignRecover = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_SignRecoverInit = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_UnwrapKey = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_Verify = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_VerifyFinal = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_VerifyInit = FUNCTION FILTER pkcs11_softtoken.so.1;
+    	C_VerifyRecover = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_VerifyRecoverInit = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_VerifyUpdate = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_WaitForSlotEvent = FUNCTION FILTER pkcs11_softtoken.so.1;
+	C_WrapKey = FUNCTION FILTER pkcs11_softtoken.so.1;
+    local:
+	*;
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pkcs11/libkcfd/i386/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# lib/pkcs11/libkcfd/i386/Makefile
+#
+
+include $(SRC)/lib/Makefile.filter.com
+include ../Makefile.com
+
+install: all $(ROOTLIBDIR) .WAIT $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
+
+include $(SRC)/lib/Makefile.filter.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pkcs11/libkcfd/sparc/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# lib/pkcs11/libkcfd/sparc/Makefile
+#
+
+include $(SRC)/lib/Makefile.filter.com
+include ../Makefile.com
+
+install: all $(ROOTLIBDIR) .WAIT $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
+
+include	$(SRC)/lib/Makefile.filter.targ
--- a/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h	Mon Jul 20 13:07:46 2009 -0400
@@ -245,7 +245,7 @@
 
 typedef struct ndr_pipe {
 	int			np_fid;
-	smb_opipe_context_t	np_ctx;
+	smb_netuserinfo_t	np_user;
 	char			*np_buf;
 	struct uio		np_uio;
 	iovec_t			np_iov;
@@ -516,7 +516,6 @@
 int ndr_pipe_close(int);
 int ndr_pipe_read(int, uint8_t *, uint32_t *, uint32_t *);
 int ndr_pipe_write(int, uint8_t *, uint32_t);
-int ndr_pipe_getinfo(int, ndr_pipe_info_t *);
 
 int ndr_generic_call_stub(ndr_xa_t *);
 
--- a/usr/src/lib/smbsrv/libmlrpc/common/mapfile-vers	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlrpc/common/mapfile-vers	Mon Jul 20 13:07:46 2009 -0400
@@ -67,7 +67,6 @@
 	ndr_mbtowc;
 	ndr_native_os;
         ndr_params;
-	ndr_pipe_getinfo;
 	ndr_pipe_open;
 	ndr_pipe_close;
 	ndr_pipe_read;
--- a/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c	Mon Jul 20 13:07:46 2009 -0400
@@ -89,7 +89,7 @@
 		return (ENOMEM);
 	}
 
-	if (smb_opipe_context_decode(&np->np_ctx, data, datalen, NULL) == -1) {
+	if (smb_netuserinfo_decode(&np->np_user, data, datalen, NULL) == -1) {
 		ndr_pipe_release(np);
 		(void) mutex_unlock(&ndr_pipe_lock);
 		return (EINVAL);
@@ -257,37 +257,6 @@
 }
 
 /*
- * Return information about the specified pipe.
- */
-int
-ndr_pipe_getinfo(int ndx, ndr_pipe_info_t *npi)
-{
-	ndr_pipe_t *np;
-
-	if ((ndx < 0) || (ndx >= NDR_PIPE_MAX) || (npi == NULL))
-		return (-1);
-
-	(void) mutex_lock(&ndr_pipe_lock);
-	np = &ndr_pipe_table[ndx];
-
-	if (np->np_fid == 0) {
-		(void) mutex_unlock(&ndr_pipe_lock);
-		return (-1);
-	}
-
-	npi->npi_fid = np->np_fid;
-	npi->npi_permissions = FILE_READ_DATA | FILE_WRITE_DATA | FILE_EXECUTE;
-	npi->npi_num_locks = 0;
-	(void) snprintf(npi->npi_username, MAXNAMELEN, "%s\\%s",
-	    np->np_ctx.oc_domain, np->np_ctx.oc_account);
-	(void) snprintf(npi->npi_pathname, MAXPATHLEN, "%s",
-	    np->np_binding->service->sec_addr_port);
-
-	(void) mutex_unlock(&ndr_pipe_lock);
-	return (0);
-}
-
-/*
  * Must be called with ndr_pipe_lock held.
  */
 static ndr_pipe_t *
@@ -365,9 +334,9 @@
 		ndr_pipe_rewind(np);
 		ndr_pipe_flush(np);
 		free(np->np_buf);
-		free(np->np_ctx.oc_domain);
-		free(np->np_ctx.oc_account);
-		free(np->np_ctx.oc_workstation);
+		free(np->np_user.ui_domain);
+		free(np->np_user.ui_account);
+		free(np->np_user.ui_workstation);
 		bzero(np, sizeof (ndr_pipe_t));
 	}
 }
@@ -412,9 +381,9 @@
 boolean_t
 ndr_is_admin(ndr_xa_t *xa)
 {
-	smb_opipe_context_t *ctx = &xa->pipe->np_ctx;
+	smb_netuserinfo_t *ctx = &xa->pipe->np_user;
 
-	return (ctx->oc_flags & SMB_ATF_ADMIN);
+	return (ctx->ui_flags & SMB_ATF_ADMIN);
 }
 
 /*
@@ -426,18 +395,18 @@
 boolean_t
 ndr_is_poweruser(ndr_xa_t *xa)
 {
-	smb_opipe_context_t *ctx = &xa->pipe->np_ctx;
+	smb_netuserinfo_t *ctx = &xa->pipe->np_user;
 
-	return ((ctx->oc_flags & SMB_ATF_ADMIN) ||
-	    (ctx->oc_flags & SMB_ATF_POWERUSER));
+	return ((ctx->ui_flags & SMB_ATF_ADMIN) ||
+	    (ctx->ui_flags & SMB_ATF_POWERUSER));
 }
 
 int32_t
 ndr_native_os(ndr_xa_t *xa)
 {
-	smb_opipe_context_t *ctx = &xa->pipe->np_ctx;
+	smb_netuserinfo_t *ctx = &xa->pipe->np_user;
 
-	return (ctx->oc_native_os);
+	return (ctx->ui_native_os);
 }
 
 /*
--- a/usr/src/lib/smbsrv/libmlsvc/common/eventlog.h	Tue Jul 14 11:18:27 2009 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +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.
- */
-
-#ifndef _eventlog_H
-#define	_eventlog_H
-
-#include <netdb.h>
-#include <smbsrv/libsmb.h>
-#include <smbsrv/ndl/eventlog.ndl>
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-#define	LOGR_NMSGMASK	1023
-
-typedef struct logr_entry {
-	struct timeval	le_timestamp;			/* Time of log entry */
-	int		le_pri;				/* Message priority */
-	char		le_hostname[MAXHOSTNAMELEN];	/* Log hostname */
-	char		le_msg[LOGR_MAXENTRYLEN];	/* Log message text */
-} logr_entry_t;
-
-typedef struct logr_info {
-	logr_entry_t	li_entry[LOGR_NMSGMASK+1];	/* Array of log entry */
-	int		li_idx;				/* Index */
-} logr_info_t;
-
-typedef struct logr_read_data {
-	int		rd_tot_recnum;		/* Total no. of record read */
-	int		rd_last_sentrec;	/* Last sentence read */
-	char		rd_first_read;		/* First sentence read */
-	logr_info_t	*rd_log;		/* Log information read */
-} logr_read_data_t;
-
-/* This structure provides the context for eventlog calls from clients. */
-typedef struct logr_context {
-	logr_read_data_t *lc_cached_read_data;
-	char *lc_source_name;
-} logr_context_t;
-
-int logr_syslog_snapshot(logr_info_t *);
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif	/* _eventlog_H */
--- a/usr/src/lib/smbsrv/libmlsvc/common/eventlog_svc.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/eventlog_svc.c	Mon Jul 20 13:07:46 2009 -0400
@@ -29,15 +29,15 @@
 #include <sys/utsname.h>
 #include <unistd.h>
 #include <strings.h>
-
 #include <smbsrv/libsmb.h>
 #include <smbsrv/libmlrpc.h>
 #include <smbsrv/ntstatus.h>
 #include <smbsrv/nmpipes.h>
 #include <smbsrv/libmlsvc.h>
-#include "eventlog.h"
+#include <smbsrv/ndl/eventlog.ndl>
 #include <smbsrv/nterror.h>
 
+
 #define	LOGR_FWD		+1
 #define	LOGR_REW		-1
 #define	LOGR_RECORD_SIGNATURE	0x654C664C
@@ -162,8 +162,6 @@
 	logr_stub_table			/* stub_table */
 };
 
-static int logr_get_snapshot(logr_context_t *);
-
 /*
  * logr_initialize
  *
@@ -175,6 +173,13 @@
 logr_initialize(void)
 {
 	(void) ndr_svc_register(&logr_service);
+	logr_init();
+}
+
+void
+logr_finalize(void)
+{
+	logr_fini();
 }
 
 /*
@@ -222,12 +227,12 @@
 }
 
 /*
- * logr_mgr_hdalloc
+ * logr_hdalloc
  *
  * Handle allocation wrapper to setup the local manager context.
  */
 static ndr_hdid_t *
-logr_hdalloc(ndr_xa_t *mxa)
+logr_hdalloc(ndr_xa_t *mxa, char *logname)
 {
 	logr_context_t *ctx;
 
@@ -235,8 +240,13 @@
 		return (NULL);
 	bzero(ctx, sizeof (logr_context_t));
 
-	ctx->lc_source_name = strdup("eventlog");
-	if ((ctx->lc_source_name != NULL) && (logr_get_snapshot(ctx) < 0)) {
+	ctx->lc_source_name = strdup(logname);
+	if (ctx->lc_source_name == NULL) {
+		free(ctx);
+		return (NULL);
+	}
+
+	if (logr_get_snapshot(ctx) != 0) {
 		free(ctx->lc_source_name);
 		free(ctx);
 		return (NULL);
@@ -287,16 +297,22 @@
 	ndr_handle_t *hd;
 	char *log_name = NULL;
 
-	if (param->log_name.length != 0)
-		log_name = (char *)param->log_name.str;
-
-	if ((log_name == NULL) || strcasecmp(log_name, "System") != 0) {
+	if (!ndr_is_admin(mxa)) {
 		bzero(&param->handle, sizeof (logr_handle_t));
 		param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
 		return (NDR_DRC_OK);
 	}
 
-	id = logr_hdalloc(mxa);
+	if (param->log_name.length != 0)
+		log_name = (char *)param->log_name.str;
+
+	if (!logr_is_supported(log_name)) {
+		bzero(&param->handle, sizeof (logr_handle_t));
+		param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+		return (NDR_DRC_OK);
+	}
+
+	id = logr_hdalloc(mxa, log_name);
 	if (id && ((hd = logr_hdlookup(mxa, id)) != NULL)) {
 		hd->nh_data_free = logr_context_data_free;
 		bcopy(id, &param->handle, sizeof (logr_handle_t));
@@ -310,42 +326,6 @@
 }
 
 /*
- * logr_get_snapshot
- *
- * Allocate memory and make a copy, as a snapshot, from system log.
- */
-static int
-logr_get_snapshot(logr_context_t *ctx)
-{
-	logr_read_data_t *data = NULL;
-
-	ctx->lc_cached_read_data = malloc(sizeof (logr_read_data_t));
-	if (ctx->lc_cached_read_data != NULL) {
-		data = ctx->lc_cached_read_data;
-
-		data->rd_log = (logr_info_t *)malloc(sizeof (logr_info_t));
-		if (data->rd_log == NULL) {
-			free(data);
-			return (-1);
-		}
-		bzero(data->rd_log, sizeof (logr_info_t));
-
-		data->rd_tot_recnum = logr_syslog_snapshot(data->rd_log);
-		if (data->rd_tot_recnum < 0) {
-			free(data->rd_log);
-			free(data);
-			return (-1);
-		}
-
-		data->rd_first_read = 1;
-
-		return (0);
-	}
-
-	return (-1);
-}
-
-/*
  * logr_s_EventLogQueryCount
  *
  * take a snapshot from system log, assign it to the given handle.
--- a/usr/src/lib/smbsrv/libmlsvc/common/eventlog_syslog.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/eventlog_syslog.c	Mon Jul 20 13:07:46 2009 -0400
@@ -32,11 +32,13 @@
 #include <string.h>
 #include <strings.h>
 #include <stdarg.h>
+#include <dlfcn.h>
 #include <sys/synch.h>
 #include <sys/stat.h>
 #include <sys/errno.h>
 #include <ctype.h>
-#include "eventlog.h"
+#include <smbsrv/ndl/eventlog.ndl>
+#include <smbsrv/libmlsvc.h>
 
 typedef enum {
 	LOGR_MONTH = 0,
@@ -77,6 +79,12 @@
 	char		ln_logline[LOGR_MAXENTRYLEN];
 } logr_syslog_node_t;
 
+static void *logr_interposer_hdl = NULL;
+static struct {
+	boolean_t (*logr_op_supported)(char *);
+	int (*logr_op_snapshot)(logr_context_t *);
+} logr_interposer_ops;
+
 /*
  * Set the syslog timestamp.
  *
@@ -289,12 +297,12 @@
  * provided by the caller. Returns the number of entries in
  * the log.
  */
-int
-logr_syslog_snapshot(logr_info_t *loginfo)
+static int
+logr_syslog_snapshot(char *logname, logr_info_t *loginfo)
 {
 	FILE *fp;
 
-	if (loginfo == NULL)
+	if ((loginfo == NULL) || (!logr_is_supported(logname)))
 		return (-1);
 
 	if ((fp = fopen("/var/adm/messages", "r")) == 0)
@@ -311,3 +319,107 @@
 
 	return (LOGR_NMSGMASK+1);
 }
+
+/*
+ * logr_is_supported
+ *
+ * Determines if a given log is supported or not.
+ * Returns B_TRUE on success, B_FALSE on failure.
+ */
+boolean_t
+logr_is_supported(char *log_name)
+{
+	if (log_name == NULL)
+		return (B_FALSE);
+
+	if (logr_interposer_ops.logr_op_supported != NULL)
+		return (logr_interposer_ops.logr_op_supported(log_name));
+
+	if (strcasecmp(log_name, LOGR_SYSTEM_LOG) != 0)
+		return (B_FALSE);
+
+	return (B_TRUE);
+}
+
+/*
+ * logr_get_snapshot
+ *
+ * Allocate memory and make a copy, as a snapshot, from system log.
+ * Returns 0 on success, -1 on failure.
+ */
+int
+logr_get_snapshot(logr_context_t *ctx)
+{
+	logr_read_data_t *data = NULL;
+
+	if (logr_interposer_ops.logr_op_snapshot != NULL)
+		return (logr_interposer_ops.logr_op_snapshot(ctx));
+
+	ctx->lc_cached_read_data = malloc(sizeof (logr_read_data_t));
+	if (ctx->lc_cached_read_data != NULL) {
+		data = ctx->lc_cached_read_data;
+
+		data->rd_log = (logr_info_t *)malloc(sizeof (logr_info_t));
+		if (data->rd_log == NULL) {
+			free(data);
+			return (-1);
+		}
+		bzero(data->rd_log, sizeof (logr_info_t));
+
+		data->rd_tot_recnum = logr_syslog_snapshot(ctx->lc_source_name,
+		    data->rd_log);
+		if (data->rd_tot_recnum < 0) {
+			free(data->rd_log);
+			free(data);
+			return (-1);
+		}
+
+		data->rd_first_read = 1;
+
+		return (0);
+	}
+
+	return (-1);
+}
+
+/*
+ * logr_init
+ *
+ * Initializes the Eventlog service.
+ * Checks to see if a event log utility library
+ * is interposed. If yes then it'll initializes logr_interposer_ops
+ * structure with function pointers from this library.
+ */
+void
+logr_init(void)
+{
+	logr_interposer_hdl = smb_dlopen();
+	if (logr_interposer_hdl == NULL)
+		return;
+
+	bzero((void *)&logr_interposer_ops, sizeof (logr_interposer_ops));
+
+	logr_interposer_ops.logr_op_supported =
+	    (boolean_t (*)())dlsym(logr_interposer_hdl, "logr_is_supported");
+
+	logr_interposer_ops.logr_op_snapshot =
+	    (int (*)())dlsym(logr_interposer_hdl, "logr_get_snapshot");
+
+	if (logr_interposer_ops.logr_op_supported == NULL ||
+	    logr_interposer_ops.logr_op_snapshot == NULL)
+		logr_fini();
+}
+
+/*
+ * logr_fini
+ *
+ * Finalizes the Eventlog service.
+ * Closes handle to interposed library.
+ */
+void
+logr_fini(void)
+{
+	smb_dlclose(logr_interposer_hdl);
+	logr_interposer_hdl = NULL;
+	bzero((void *)&logr_interposer_ops, sizeof (logr_interposer_ops));
+}
--- a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h	Mon Jul 20 13:07:46 2009 -0400
@@ -26,12 +26,15 @@
 #ifndef	_LIBMLSVC_H
 #define	_LIBMLSVC_H
 
+#include <uuid/uuid.h>
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/uio.h>
 #include <sys/ksynch.h>
 #include <stdio.h>
 #include <string.h>
+#include <netdb.h>
+#include <libuutil.h>
 #include <smbsrv/wintypes.h>
 #include <smbsrv/hash_table.h>
 #include <smbsrv/smb_token.h>
@@ -59,12 +62,9 @@
 extern boolean_t smb_domain_getinfo(smb_domain_t *);
 
 
-extern uint64_t mlsvc_get_num_users(void);
-extern int mlsvc_get_user_list(smb_ulist_t *);
 extern void dssetup_clear_domain_info(void);
 extern int mlsvc_init(void);
 extern void mlsvc_fini(void);
-extern int mlsvc_set_share(int, char *, char *);
 extern DWORD mlsvc_netlogon(char *, char *);
 extern DWORD mlsvc_join(smb_domain_t *, char *, char *);
 
@@ -126,6 +126,21 @@
 } ms_luid_t;
 
 /*
+ * Information about a server as reported by NetServerGetInfo.
+ * The SV_PLATFORM and SV_TYPE definitions are in srvsvc.ndl.
+ */
+typedef struct srvsvc_server_info {
+	uint32_t	sv_platform_id;
+	char		*sv_name;
+	uint32_t	sv_version_major;
+	uint32_t	sv_version_minor;
+	uint32_t	sv_type;
+	char		*sv_comment;
+} srvsvc_server_info_t;
+
+int srvsvc_net_server_getinfo(char *, char *, srvsvc_server_info_t *);
+
+/*
  * A client_t is created while binding a client connection to hold the
  * context for calls made using that connection.
  *
@@ -137,11 +152,14 @@
 	ndr_hdid_t			handle;
 	ndr_client_t			*clnt;
 	int				remote_os;
+	srvsvc_server_info_t		svinfo;
 } mlsvc_handle_t;
 
 int ndr_rpc_bind(mlsvc_handle_t *, char *, char *, char *, const char *);
 void ndr_rpc_unbind(mlsvc_handle_t *);
 int ndr_rpc_call(mlsvc_handle_t *, int, void *);
+void ndr_rpc_server_setinfo(mlsvc_handle_t *, const srvsvc_server_info_t *);
+void ndr_rpc_server_getinfo(mlsvc_handle_t *, srvsvc_server_info_t *);
 int ndr_rpc_server_os(mlsvc_handle_t *);
 void *ndr_rpc_malloc(mlsvc_handle_t *, size_t);
 ndr_heap_t *ndr_rpc_get_heap(mlsvc_handle_t *);
@@ -151,6 +169,108 @@
 void ndr_inherit_handle(mlsvc_handle_t *, mlsvc_handle_t *);
 void ndr_rpc_status(mlsvc_handle_t *, int, uint32_t);
 
+/* SVCCTL service */
+/*
+ * Calculate the wide-char equivalent string length required to
+ * store a string - including the terminating null wide-char.
+ */
+#define	SVCCTL_WNSTRLEN(S)	((strlen((S)) + 1) * sizeof (mts_wchar_t))
+
+/* An AVL-storable node representing each service in the SCM database. */
+typedef struct svcctl_svc_node {
+	uu_avl_node_t		sn_node;
+	char			*sn_name;	/* Service Name (Key) */
+	char			*sn_fmri;	/* Display Name (FMRI) */
+	char			*sn_desc;	/* Description */
+	char			*sn_state;	/* State */
+} svcctl_svc_node_t;
+
+/* This structure provides context for each svcctl_s_OpenManager call. */
+typedef struct svcctl_manager_context {
+	scf_handle_t		*mc_scf_hdl;	  /* SCF handle */
+	scf_propertygroup_t	*mc_scf_gpg;	  /* Property group */
+	scf_property_t		*mc_scf_gprop;	  /* Property */
+	scf_value_t		*mc_scf_gval;	  /* Value */
+	uint32_t		mc_scf_numsvcs;   /* Number of SMF services */
+	ssize_t			mc_scf_max_fmri_len;  /* Max FMRI length */
+	ssize_t			mc_scf_max_value_len; /* Max Value length */
+	uint32_t		mc_bytes_needed;  /* Number of bytes needed */
+	uu_avl_pool_t		*mc_svcs_pool;	  /* AVL pool */
+	uu_avl_t		*mc_svcs;	  /* AVL tree of SMF services */
+} svcctl_manager_context_t;
+
+/* This structure provides context for each svcctl_s_OpenService call. */
+typedef struct svcctl_service_context {
+	ndr_hdid_t		*sc_mgrid;	/* Manager ID */
+	char			*sc_svcname;    /* Service Name */
+} svcctl_service_context_t;
+
+typedef enum {
+	SVCCTL_MANAGER_CONTEXT = 0,
+	SVCCTL_SERVICE_CONTEXT
+} svcctl_context_type_t;
+
+/* This structure provides abstraction for service and manager context call. */
+typedef struct svcctl_context {
+	svcctl_context_type_t	c_type;
+	union {
+		svcctl_manager_context_t *uc_mgr;
+		svcctl_service_context_t *uc_svc;
+		void *uc_cp;
+	} c_ctx;
+} svcctl_context_t;
+
+/* Service Control Manager (SCM) functions */
+void svcctl_init(void);
+void svcctl_fini(void);
+int svcctl_scm_init(svcctl_manager_context_t *);
+void svcctl_scm_fini(svcctl_manager_context_t *);
+int svcctl_scm_scf_handle_init(svcctl_manager_context_t *);
+void svcctl_scm_scf_handle_fini(svcctl_manager_context_t *);
+int svcctl_scm_refresh(svcctl_manager_context_t *);
+uint32_t svcctl_scm_enum_services(svcctl_manager_context_t *, uint8_t *,
+    size_t, uint32_t *, boolean_t);
+uint32_t svcctl_scm_validate_service(svcctl_manager_context_t *, char *);
+svcctl_svc_node_t *svcctl_scm_find_service(svcctl_manager_context_t *, char *);
+uint32_t svcctl_scm_map_status(const char *);
+
+/* LOGR service */
+#define	LOGR_APPLICATION_LOG		"Application"
+#define	LOGR_SECURITY_LOG		"Security"
+#define	LOGR_SYSTEM_LOG			"System"
+#define	LOGR_NMSGMASK			1023
+#define	LOGR_MAXMSGLEN			800
+
+typedef struct logr_entry {
+	struct timeval	le_timestamp;			/* Time of log entry */
+	int		le_pri;				/* Message priority */
+	char		le_hostname[MAXHOSTNAMELEN];	/* Log hostname */
+	char		le_msg[LOGR_MAXMSGLEN];		/* Log message text */
+} logr_entry_t;
+
+typedef struct logr_info {
+	logr_entry_t	li_entry[LOGR_NMSGMASK+1];	/* Array of log entry */
+	int		li_idx;				/* Index */
+} logr_info_t;
+
+typedef struct logr_read_data {
+	int		rd_tot_recnum;		/* Total no. of record read */
+	int		rd_last_sentrec;	/* Last sentence read */
+	char		rd_first_read;		/* First sentence read */
+	logr_info_t	*rd_log;		/* Log information read */
+} logr_read_data_t;
+
+/* This structure provides the context for eventlog calls from clients. */
+typedef struct logr_context {
+	logr_read_data_t *lc_cached_read_data;
+	char *lc_source_name;
+} logr_context_t;
+
+void logr_init(void);
+void logr_fini(void);
+boolean_t logr_is_supported(char *);
+int logr_get_snapshot(logr_context_t *);
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers	Mon Jul 20 13:07:46 2009 -0400
@@ -41,15 +41,12 @@
 SUNWprivate {
     global:
 	dssetup_clear_domain_info;
-	mlsvc_get_num_users;
-	mlsvc_get_user_list;
 	mlsvc_fini;
 	mlsvc_init;
 	mlsvc_join;
 	mlsvc_lookup_name;
 	mlsvc_lookup_sid;
 	mlsvc_netlogon;
-	mlsvc_set_share;
 	smb_autohome_add;
 	smb_autohome_remove;
 	smb_domain_getinfo;
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h	Mon Jul 20 13:07:46 2009 -0400
@@ -47,6 +47,9 @@
 void msgsvcsend_initialize(void);
 void spoolss_initialize(void);
 
+void logr_finalize(void);
+void svcctl_finalize(void);
+
 int netr_open(char *, char *, mlsvc_handle_t *);
 int netr_close(mlsvc_handle_t *);
 DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD);
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c	Mon Jul 20 13:07:46 2009 -0400
@@ -170,6 +170,36 @@
 }
 
 /*
+ * Set information about the remote RPC server in the handle.
+ */
+void
+ndr_rpc_server_setinfo(mlsvc_handle_t *handle,
+    const srvsvc_server_info_t *svinfo)
+{
+	bcopy(svinfo, &handle->svinfo, sizeof (srvsvc_server_info_t));
+	handle->svinfo.sv_name = NULL;
+	handle->svinfo.sv_comment = NULL;
+
+	if (svinfo->sv_version_major > 4)
+		handle->remote_os = NATIVE_OS_WIN2000;
+	else
+		handle->remote_os = NATIVE_OS_WINNT;
+
+	smb_tracef("NdrRpcServerSetInfo: %s (version %d.%d)",
+	    svinfo->sv_name ? svinfo->sv_name : "<unknown>",
+	    svinfo->sv_version_major, svinfo->sv_version_minor);
+}
+
+/*
+ * Get information about the remote RPC server from the handle.
+ */
+void
+ndr_rpc_server_getinfo(mlsvc_handle_t *handle, srvsvc_server_info_t *svinfo)
+{
+	bcopy(&handle->svinfo, svinfo, sizeof (srvsvc_server_info_t));
+}
+
+/*
  * Returns the Native-OS of the RPC server.
  */
 int
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c	Mon Jul 20 13:07:46 2009 -0400
@@ -82,6 +82,8 @@
 mlsvc_fini(void)
 {
 	smb_logon_fini();
+	svcctl_finalize();
+	logr_finalize();
 }
 
 /*ARGSUSED*/
@@ -100,43 +102,3 @@
 	/*NOTREACHED*/
 	return (NULL);
 }
-
-uint64_t
-mlsvc_get_num_users(void)
-{
-	uint32_t n_users = 0;
-
-	(void) smb_kmod_get_usernum(&n_users);
-	return ((uint64_t)n_users);
-}
-
-/*
- * The calling function must free the output parameter 'users'.
- */
-int
-mlsvc_get_user_list(smb_ulist_t *ulist)
-{
-	return (smb_kmod_get_userlist(ulist));
-}
-
-/*
- * Downcall to the kernel that is executed upon share enable and disable.
- */
-int
-mlsvc_set_share(int shrop, char *path, char *name)
-{
-	int rc;
-
-	switch (shrop) {
-	case SMB_SHROP_ADD:
-		rc = smb_kmod_share(path, name);
-		break;
-	case SMB_SHROP_DELETE:
-		rc = smb_kmod_unshare(path, name);
-		break;
-	default:
-		rc = EINVAL;
-		break;
-	}
-	return (rc);
-}
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c	Mon Jul 20 13:07:46 2009 -0400
@@ -518,7 +518,7 @@
 lsarpc_s_GetConnectedUser(void *arg, ndr_xa_t *mxa)
 {
 	struct mslsa_GetConnectedUser *param = arg;
-	smb_opipe_context_t *ctx = &mxa->pipe->np_ctx;
+	smb_netuserinfo_t *user = &mxa->pipe->np_user;
 	DWORD status = NT_STATUS_SUCCESS;
 	smb_domain_t di;
 	int rc1;
@@ -546,8 +546,9 @@
 		return (NDR_DRC_OK);
 	}
 
-	rc1 = NDR_MSTRING(mxa, ctx->oc_account, (ndr_mstring_t *)param->owner);
-	rc2 = NDR_MSTRING(mxa, ctx->oc_domain,
+	rc1 = NDR_MSTRING(mxa, user->ui_account,
+	    (ndr_mstring_t *)param->owner);
+	rc2 = NDR_MSTRING(mxa, user->ui_domain,
 	    (ndr_mstring_t *)param->domain->name);
 
 	if (rc1 == -1 || rc2 == -1)
--- a/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -118,19 +118,27 @@
 /*
  * netr_open
  *
- * Open an anonymous session to the NETLOGON pipe on a domain
- * controller and bind to the NETR RPC interface. We store the
- * remote server's native OS type - we may need it due to
- * differences between versions of Windows.
+ * Open an anonymous session to the NETLOGON pipe on a domain controller
+ * and bind to the NETR RPC interface.
+ *
+ * We store the remote server information, which is used to drive Windows
+ * version specific behavior.
  */
 int
 netr_open(char *server, char *domain, mlsvc_handle_t *netr_handle)
 {
+	srvsvc_server_info_t svinfo;
 	char *user = smbrdr_ipc_get_user();
 
+	if (srvsvc_net_server_getinfo(server, domain, &svinfo) < 0)
+		return (-1);
+
 	if (ndr_rpc_bind(netr_handle, server, domain, user, "NETR") < 0)
 		return (-1);
 
+	ndr_rpc_server_setinfo(netr_handle, &svinfo);
+	free(svinfo.sv_name);
+	free(svinfo.sv_comment);
 	return (0);
 }
 
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c	Mon Jul 20 13:07:46 2009 -0400
@@ -406,7 +406,7 @@
 	smb_shr_cache_unlock();
 
 	/* call kernel to take a hold on the shared file system */
-	rc = mlsvc_set_share(SMB_SHROP_ADD, si->shr_path, si->shr_name);
+	rc = smb_kmod_share(si->shr_path, si->shr_name);
 
 	if (rc == 0) {
 		smb_shr_publish(si->shr_name, si->shr_container);
@@ -483,7 +483,7 @@
 	smb_shr_unpublish(sharename, container);
 
 	/* call kernel to release the hold on the shared file system */
-	(void) mlsvc_set_share(SMB_SHROP_DELETE, path, sharename);
+	(void) smb_kmod_unshare(path, sharename);
 
 	return (NERR_Success);
 }
--- a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_clnt.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_clnt.c	Mon Jul 20 13:07:46 2009 -0400
@@ -347,6 +347,52 @@
 	return (0);
 }
 
+int
+srvsvc_net_server_getinfo(char *server, char *domain,
+    srvsvc_server_info_t *svinfo)
+{
+	mlsvc_handle_t handle;
+	struct mslm_NetServerGetInfo arg;
+	struct mslm_SERVER_INFO_101 *sv101;
+	int len, opnum, rc;
+	char *user = smbrdr_ipc_get_user();
+
+	if (srvsvc_open(server, domain, user, &handle) != 0)
+		return (-1);
+
+	opnum = SRVSVC_OPNUM_NetServerGetInfo;
+	bzero(&arg, sizeof (arg));
+
+	len = strlen(server) + 4;
+	arg.servername = ndr_rpc_malloc(&handle, len);
+	if (arg.servername == NULL)
+		return (-1);
+
+	(void) snprintf((char *)arg.servername, len, "\\\\%s", server);
+	arg.level = 101;
+
+	rc = ndr_rpc_call(&handle, opnum, &arg);
+	if ((rc != 0) || (arg.status != 0)) {
+		srvsvc_close(&handle);
+		return (-1);
+	}
+
+	sv101 = arg.result.bufptr.bufptr101;
+
+	bzero(svinfo, sizeof (srvsvc_server_info_t));
+	svinfo->sv_platform_id = sv101->sv101_platform_id;
+	svinfo->sv_version_major = sv101->sv101_version_major;
+	svinfo->sv_version_minor = sv101->sv101_version_minor;
+	svinfo->sv_type = sv101->sv101_type;
+	if (sv101->sv101_name)
+		svinfo->sv_name = strdup((char *)sv101->sv101_name);
+	if (sv101->sv101_comment)
+		svinfo->sv_comment = strdup((char *)sv101->sv101_comment);
+
+	srvsvc_close(&handle);
+	return (0);
+}
+
 /*
  * Synchronize the local system clock with the domain controller.
  */
@@ -490,6 +536,7 @@
 srvsvc_net_test(char *server, char *domain, char *netname)
 {
 	smb_domain_t di;
+	srvsvc_server_info_t svinfo;
 
 	(void) smb_tracef("%s %s %s", server, domain, netname);
 
@@ -498,6 +545,17 @@
 		domain = di.d_info.di_nbname;
 	}
 
+	if (srvsvc_net_server_getinfo(server, domain, &svinfo) == 0) {
+		smb_tracef("NetServerGetInfo: %s %s (%d.%d) id=%d type=0x%08x",
+		    svinfo.sv_name ? svinfo.sv_name : "NULL",
+		    svinfo.sv_comment ? svinfo.sv_comment : "NULL",
+		    svinfo.sv_version_major, svinfo.sv_version_minor,
+		    svinfo.sv_platform_id, svinfo.sv_type);
+
+		free(svinfo.sv_name);
+		free(svinfo.sv_comment);
+	}
+
 	(void) srvsvc_net_share_get_info(server, domain, netname);
 #if 0
 	/*
--- a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c	Mon Jul 20 13:07:46 2009 -0400
@@ -65,26 +65,8 @@
 #define	SRVSVC_CONNECT_ENUM_SHARE	1
 #define	SRVSVC_CONNECT_ENUM_WKSTN	2
 
-#define	SMB_SRVSVC_MAXBUFLEN	(8 * 1024 * 1024)
-#define	SMB_SRVSVC_MAXPREFLEN	((uint32_t)(-1))
-
-/*
- * prefmaxlen:    Client specified response buffer limit.
- * resume_handle: Cookie used to track enumeration across multiple calls.
- * n_total:       Total number of entries.
- * n_enum:        Number of entries to enumerate (derived from prefmaxlen).
- * n_skip:        Number of entries to skip (from incoming resume handle).
- * n_read:        Number of objects returned for current enumeration request.
- */
-typedef struct srvsvc_enum {
-	uint32_t se_level;
-	uint32_t se_prefmaxlen;
-	uint32_t se_resume_handle;
-	uint32_t se_n_total;
-	uint32_t se_n_enum;
-	uint32_t se_n_skip;
-	uint32_t se_n_read;
-} srvsvc_enum_t;
+#define	SMB_SRVSVC_MAXBUFLEN		(8 * 1024 * 1024)
+#define	SMB_SRVSVC_MAXPREFLEN		((uint32_t)(-1))
 
 typedef struct srvsvc_sd {
 	uint8_t *sd_buf;
@@ -112,46 +94,45 @@
 	struct mslm_NetShareInfo_1501 nsg_info1501;
 } srvsvc_netshare_getinfo_t;
 
-static DWORD srvsvc_s_NetConnectEnumLevel0(ndr_xa_t *,
-    srvsvc_NetConnectInfo0_t *);
-static DWORD srvsvc_s_NetConnectEnumLevel1(ndr_xa_t *,
-    srvsvc_NetConnectInfo1_t *);
-
-static DWORD srvsvc_NetFileEnum2(ndr_xa_t *,
-    struct mslm_NetFileEnum *);
-static DWORD srvsvc_NetFileEnum3(ndr_xa_t *,
-    struct mslm_NetFileEnum *);
-
-static DWORD mlsvc_NetSessionEnumLevel0(struct mslm_infonres *, DWORD,
-    ndr_xa_t *);
-static DWORD mlsvc_NetSessionEnumLevel1(struct mslm_infonres *, DWORD,
-    ndr_xa_t *);
-static DWORD mlsvc_NetSessionEnumLevel2(struct mslm_infonres *, DWORD,
-    ndr_xa_t *);
-static DWORD mlsvc_NetSessionEnumLevel10(struct mslm_infonres *, DWORD,
-    ndr_xa_t *);
-static DWORD mlsvc_NetSessionEnumLevel502(struct mslm_infonres *, DWORD,
-    ndr_xa_t *);
-
-static DWORD mlsvc_NetShareEnumLevel0(ndr_xa_t *,
-    struct mslm_infonres *, srvsvc_enum_t *, int);
-static DWORD mlsvc_NetShareEnumLevel1(ndr_xa_t *,
-    struct mslm_infonres *, srvsvc_enum_t *, int);
-static DWORD mlsvc_NetShareEnumLevel2(ndr_xa_t *,
-    struct mslm_infonres *, srvsvc_enum_t *, int);
-static DWORD mlsvc_NetShareEnumLevel501(ndr_xa_t *,
-    struct mslm_infonres *, srvsvc_enum_t *, int);
-static DWORD mlsvc_NetShareEnumLevel502(ndr_xa_t *,
-    struct mslm_infonres *, srvsvc_enum_t *, int);
-static DWORD mlsvc_NetShareEnumCommon(ndr_xa_t *,
-    srvsvc_enum_t *, smb_share_t *, void *);
-static boolean_t srvsvc_add_autohome(ndr_xa_t *, srvsvc_enum_t *,
-    void *);
+typedef struct mslm_infonres srvsvc_infonres_t;
+typedef struct mslm_NetConnectEnum srvsvc_NetConnectEnum_t;
+
+static uint32_t srvsvc_netconnectenum_level0(ndr_xa_t *, smb_svcenum_t *,
+    srvsvc_NetConnectEnum_t *);
+static uint32_t srvsvc_netconnectenum_level1(ndr_xa_t *, smb_svcenum_t *,
+    srvsvc_NetConnectEnum_t *);
+static uint32_t srvsvc_netconnectenum_common(ndr_xa_t *,
+    srvsvc_NetConnectInfo_t *, smb_netsvc_t *, smb_svcenum_t *);
+
+static DWORD srvsvc_NetFileEnum2(ndr_xa_t *, struct mslm_NetFileEnum *,
+    smb_svcenum_t *se);
+static DWORD srvsvc_NetFileEnum3(ndr_xa_t *, struct mslm_NetFileEnum *,
+    smb_svcenum_t *se);
+
+static uint32_t srvsvc_NetSessionEnumCommon(ndr_xa_t *, srvsvc_infonres_t *,
+    smb_netsvc_t *, smb_svcenum_t *);
+
+static DWORD mlsvc_NetShareEnumLevel0(ndr_xa_t *, srvsvc_infonres_t *,
+    smb_svcenum_t *, int);
+static DWORD mlsvc_NetShareEnumLevel1(ndr_xa_t *, srvsvc_infonres_t *,
+    smb_svcenum_t *, int);
+static DWORD mlsvc_NetShareEnumLevel2(ndr_xa_t *, srvsvc_infonres_t *,
+    smb_svcenum_t *, int);
+static DWORD mlsvc_NetShareEnumLevel501(ndr_xa_t *, srvsvc_infonres_t *,
+    smb_svcenum_t *, int);
+static DWORD mlsvc_NetShareEnumLevel502(ndr_xa_t *, srvsvc_infonres_t *,
+    smb_svcenum_t *, int);
+static DWORD mlsvc_NetShareEnumCommon(ndr_xa_t *, smb_svcenum_t *,
+    smb_share_t *, void *);
+static boolean_t srvsvc_add_autohome(ndr_xa_t *, smb_svcenum_t *, void *);
 static char *srvsvc_share_mkpath(ndr_xa_t *, char *);
 static uint32_t srvsvc_share_getsd(ndr_xa_t *, smb_share_t *, srvsvc_sd_t *);
 
 static int srvsvc_netconnect_qualifier(const char *);
-static uint32_t srvsvc_estimate_objcnt(uint32_t, uint32_t, uint32_t);
+static void srvsvc_estimate_limit(smb_svcenum_t *, uint32_t);
+static uint32_t srvsvc_open_sessions(void);
+static uint32_t srvsvc_open_connections(uint32_t, const char *);
+static uint32_t srvsvc_open_files(void);
 
 static uint32_t srvsvc_modify_share(smb_share_t *,
     srvsvc_netshare_setinfo_t *);
@@ -224,112 +205,222 @@
 static int
 srvsvc_s_NetConnectEnum(void *arg, ndr_xa_t *mxa)
 {
-	struct mslm_NetConnectEnum *param = arg;
-	srvsvc_NetConnectInfo0_t *info0;
-	srvsvc_NetConnectInfo1_t *info1;
-	char *qualifier;
-	int qualtype;
-	DWORD status = ERROR_SUCCESS;
+	srvsvc_NetConnectEnum_t		*param = arg;
+	smb_netsvc_t			*ns;
+	smb_svcenum_t			se;
+	char				*qualifier;
+	int				qualtype;
+	DWORD				status = ERROR_SUCCESS;
 
 	if (!ndr_is_poweruser(mxa)) {
-		bzero(param, sizeof (struct mslm_NetConnectEnum));
-		param->status = ERROR_ACCESS_DENIED;
-		return (NDR_DRC_OK);
+		status = ERROR_ACCESS_DENIED;
+		goto srvsvc_netconnectenum_error;
 	}
 
 	qualifier = (char *)param->qualifier;
 	qualtype = srvsvc_netconnect_qualifier(qualifier);
-
 	if (qualtype == SRVSVC_CONNECT_ENUM_NULL) {
-		bzero(param, sizeof (struct mslm_NetConnectEnum));
-		param->status = NERR_NetNameNotFound;
+		status = NERR_NetNameNotFound;
+		goto srvsvc_netconnectenum_error;
+	}
+
+	param->total_entries = srvsvc_open_connections(qualtype, qualifier);
+	if (param->total_entries == 0) {
+		bzero(param, sizeof (srvsvc_NetConnectEnum_t));
+		param->status = ERROR_SUCCESS;
 		return (NDR_DRC_OK);
 	}
 
+	bzero(&se, sizeof (smb_svcenum_t));
+	se.se_type = SMB_SVCENUM_TYPE_TREE;
+	se.se_level = param->info.level;
+	se.se_ntotal = param->total_entries;
+	se.se_nlimit = se.se_ntotal;
+
+	if (param->pref_max_len == SMB_SRVSVC_MAXPREFLEN ||
+	    param->pref_max_len > SMB_SRVSVC_MAXBUFLEN)
+		se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN;
+	else
+		se.se_prefmaxlen = param->pref_max_len;
+
+	if (param->resume_handle) {
+		se.se_resume = *param->resume_handle;
+		se.se_nskip = se.se_resume;
+		*param->resume_handle = 0;
+	}
+
 	switch (param->info.level) {
 	case 0:
-		info0 = NDR_NEW(mxa, srvsvc_NetConnectInfo0_t);
-		if (info0 == NULL) {
-			status = ERROR_NOT_ENOUGH_MEMORY;
-			break;
-		}
-
-		bzero(info0, sizeof (srvsvc_NetConnectInfo0_t));
-		param->info.ru.info0 = info0;
-
-		status = srvsvc_s_NetConnectEnumLevel0(mxa, info0);
-
-		param->total_entries = info0->entries_read;
-		param->resume_handle = NULL;
+		status = srvsvc_netconnectenum_level0(mxa, &se, param);
 		break;
-
 	case 1:
-		info1 = NDR_NEW(mxa, srvsvc_NetConnectInfo1_t);
-		if (info1 == NULL) {
-			status = ERROR_NOT_ENOUGH_MEMORY;
-			break;
-		}
-
-		bzero(info1, sizeof (srvsvc_NetConnectInfo1_t));
-		param->info.ru.info1 = info1;
-
-		status = srvsvc_s_NetConnectEnumLevel1(mxa, info1);
-
-		param->total_entries = info1->entries_read;
-		param->resume_handle = NULL;
+		status = srvsvc_netconnectenum_level1(mxa, &se, param);
 		break;
-
 	case 50:
 		status = ERROR_NOT_SUPPORTED;
 		break;
-
 	default:
 		status = ERROR_INVALID_LEVEL;
 		break;
 	}
 
 	if (status != ERROR_SUCCESS)
-		bzero(param, sizeof (struct mslm_NetConnectEnum));
-
+		goto srvsvc_netconnectenum_error;
+
+	if ((ns = smb_kmod_enum_init(&se)) == NULL) {
+		status = ERROR_NOT_ENOUGH_MEMORY;
+		goto srvsvc_netconnectenum_error;
+	}
+
+	status = srvsvc_netconnectenum_common(mxa, &param->info, ns, &se);
+	smb_kmod_enum_fini(ns);
+
+	if (status != ERROR_SUCCESS)
+		goto srvsvc_netconnectenum_error;
+
+	if (param->resume_handle &&
+	    param->pref_max_len != SMB_SRVSVC_MAXPREFLEN) {
+		if (se.se_resume < param->total_entries) {
+			*param->resume_handle = se.se_resume;
+			status = ERROR_MORE_DATA;
+		}
+	}
+
+	param->status = status;
+	return (NDR_DRC_OK);
+
+srvsvc_netconnectenum_error:
+	bzero(param, sizeof (srvsvc_NetConnectEnum_t));
 	param->status = status;
 	return (NDR_DRC_OK);
 }
 
-static DWORD
-srvsvc_s_NetConnectEnumLevel0(ndr_xa_t *mxa, srvsvc_NetConnectInfo0_t *info0)
+/*
+ * Allocate memory and estimate the number of objects that can
+ * be returned for NetConnectEnum level 0.
+ */
+static uint32_t
+srvsvc_netconnectenum_level0(ndr_xa_t *mxa, smb_svcenum_t *se,
+    srvsvc_NetConnectEnum_t *param)
 {
-	srvsvc_NetConnectInfoBuf0_t *ci0;
-
-	ci0 = NDR_NEW(mxa, srvsvc_NetConnectInfoBuf0_t);
+	srvsvc_NetConnectInfo0_t	*info0;
+	srvsvc_NetConnectInfoBuf0_t	*ci0;
+
+	if ((info0 = NDR_NEW(mxa, srvsvc_NetConnectInfo0_t)) == NULL)
+		return (ERROR_NOT_ENOUGH_MEMORY);
+
+	bzero(info0, sizeof (srvsvc_NetConnectInfo0_t));
+	param->info.ru.info0 = info0;
+
+	srvsvc_estimate_limit(se, sizeof (srvsvc_NetConnectInfoBuf0_t));
+	if (se->se_nlimit == 0)
+		return (NERR_BufTooSmall);
+
+	do {
+		ci0 = NDR_NEWN(mxa, srvsvc_NetConnectInfoBuf0_t, se->se_nlimit);
+		if (ci0 == NULL)
+			se->se_nlimit >>= 1;
+	} while ((se->se_nlimit > 0) && (ci0 == NULL));
+
 	if (ci0 == NULL)
 		return (ERROR_NOT_ENOUGH_MEMORY);
 
-	ci0->coni0_id = 0x17;
-
 	info0->ci0 = ci0;
-	info0->entries_read = 1;
+	info0->entries_read = 0;
 	return (ERROR_SUCCESS);
 }
 
-static DWORD
-srvsvc_s_NetConnectEnumLevel1(ndr_xa_t *mxa, srvsvc_NetConnectInfo1_t *info1)
+/*
+ * Allocate memory and estimate the number of objects that can
+ * be returned for NetConnectEnum level 1.
+ */
+static uint32_t
+srvsvc_netconnectenum_level1(ndr_xa_t *mxa, smb_svcenum_t *se,
+    srvsvc_NetConnectEnum_t *param)
 {
-	srvsvc_NetConnectInfoBuf1_t *ci1;
-
-	ci1 = NDR_NEW(mxa, srvsvc_NetConnectInfoBuf1_t);
+	srvsvc_NetConnectInfo1_t	*info1;
+	srvsvc_NetConnectInfoBuf1_t	*ci1;
+
+	if ((info1 = NDR_NEW(mxa, srvsvc_NetConnectInfo1_t)) == NULL)
+		return (ERROR_NOT_ENOUGH_MEMORY);
+
+	bzero(info1, sizeof (srvsvc_NetConnectInfo1_t));
+	param->info.ru.info1 = info1;
+
+	srvsvc_estimate_limit(se,
+	    sizeof (srvsvc_NetConnectInfoBuf1_t) + MAXNAMELEN);
+	if (se->se_nlimit == 0)
+		return (NERR_BufTooSmall);
+
+	do {
+		ci1 = NDR_NEWN(mxa, srvsvc_NetConnectInfoBuf1_t, se->se_nlimit);
+		if (ci1 == NULL)
+			se->se_nlimit >>= 1;
+	} while ((se->se_nlimit > 0) && (ci1 == NULL));
+
 	if (ci1 == NULL)
 		return (ERROR_NOT_ENOUGH_MEMORY);
 
-	ci1->coni1_id = 0x17;
-	ci1->coni1_type = STYPE_IPC;
-	ci1->coni1_num_opens = 1;
-	ci1->coni1_num_users = 1;
-	ci1->coni1_time = 16;
-	ci1->coni1_username = (uint8_t *)NDR_STRDUP(mxa, "Administrator");
-	ci1->coni1_netname = (uint8_t *)NDR_STRDUP(mxa, "IPC$");
-
 	info1->ci1 = ci1;
-	info1->entries_read = 1;
+	info1->entries_read = 0;
+	return (ERROR_SUCCESS);
+}
+
+/*
+ * Request a list of connections from the kernel and set up
+ * the connection information to be returned to the client.
+ */
+static uint32_t
+srvsvc_netconnectenum_common(ndr_xa_t *mxa, srvsvc_NetConnectInfo_t *info,
+    smb_netsvc_t *ns, smb_svcenum_t *se)
+{
+	srvsvc_NetConnectInfo0_t	*info0;
+	srvsvc_NetConnectInfo1_t	*info1;
+	srvsvc_NetConnectInfoBuf0_t	*ci0;
+	srvsvc_NetConnectInfoBuf1_t	*ci1;
+	smb_netsvcitem_t		*item;
+	smb_netconnectinfo_t		*tree;
+
+	if (smb_kmod_enum(ns) != 0)
+		return (ERROR_INTERNAL_ERROR);
+
+	info0 = info->ru.info0;
+	ci0 = info0->ci0;
+
+	info1 = info->ru.info1;
+	ci1 = info1->ci1;
+
+	item = list_head(&ns->ns_list);
+	while (item != NULL) {
+		tree = &item->nsi_un.nsi_tree;
+
+		switch (se->se_level) {
+		case 0:
+			ci0->coni0_id = tree->ci_id;
+			++ci0;
+			++info0->entries_read;
+			break;
+		case 1:
+			ci1->coni1_id = tree->ci_id;
+			ci1->coni1_type = tree->ci_type;
+			ci1->coni1_num_opens = tree->ci_numopens;
+			ci1->coni1_num_users = tree->ci_numusers;
+			ci1->coni1_time = tree->ci_time;
+			ci1->coni1_username = (uint8_t *)
+			    NDR_STRDUP(mxa, tree->ci_username);
+			ci1->coni1_netname = (uint8_t *)
+			    NDR_STRDUP(mxa, tree->ci_share);
+			++ci1;
+			++info1->entries_read;
+			break;
+		default:
+			return (ERROR_INVALID_LEVEL);
+		}
+
+		++se->se_resume;
+		item = list_next(&ns->ns_list, item);
+	}
+
 	return (ERROR_SUCCESS);
 }
 
@@ -361,6 +452,45 @@
 	}
 }
 
+static uint32_t
+srvsvc_open_sessions(void)
+{
+	smb_opennum_t	opennum;
+
+	bzero(&opennum, sizeof (smb_opennum_t));
+	if (smb_kmod_get_open_num(&opennum) != 0)
+		return (0);
+
+	return (opennum.open_users);
+}
+
+static uint32_t
+srvsvc_open_connections(uint32_t qualtype, const char *qualifier)
+{
+	smb_opennum_t	opennum;
+
+	bzero(&opennum, sizeof (smb_opennum_t));
+	opennum.qualtype = qualtype;
+	(void) strlcpy(opennum.qualifier, qualifier, MAXNAMELEN);
+
+	if (smb_kmod_get_open_num(&opennum) != 0)
+		return (0);
+
+	return (opennum.open_trees);
+}
+
+static uint32_t
+srvsvc_open_files(void)
+{
+	smb_opennum_t	opennum;
+
+	bzero(&opennum, sizeof (smb_opennum_t));
+	if (smb_kmod_get_open_num(&opennum) != 0)
+		return (0);
+
+	return (opennum.open_files);
+}
+
 /*
  * srvsvc_s_NetFileEnum
  *
@@ -416,8 +546,9 @@
 static int
 srvsvc_s_NetFileEnum(void *arg, ndr_xa_t *mxa)
 {
-	struct mslm_NetFileEnum *param = arg;
-	DWORD status;
+	struct mslm_NetFileEnum	*param = arg;
+	smb_svcenum_t		se;
+	DWORD			status;
 
 	if (!ndr_is_admin(mxa)) {
 		bzero(param, sizeof (struct mslm_NetFileEnum));
@@ -425,13 +556,37 @@
 		return (NDR_DRC_OK);
 	}
 
+	if ((param->total_entries = srvsvc_open_files()) == 0) {
+		bzero(param, sizeof (struct mslm_NetFileEnum));
+		param->status = ERROR_SUCCESS;
+		return (NDR_DRC_OK);
+	}
+
+	bzero(&se, sizeof (smb_svcenum_t));
+	se.se_type = SMB_SVCENUM_TYPE_FILE;
+	se.se_level = param->info.switch_value;
+	se.se_ntotal = param->total_entries;
+	se.se_nlimit = se.se_ntotal;
+
+	if (param->pref_max_len == SMB_SRVSVC_MAXPREFLEN ||
+	    param->pref_max_len > SMB_SRVSVC_MAXBUFLEN)
+		se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN;
+	else
+		se.se_prefmaxlen = param->pref_max_len;
+
+	if (param->resume_handle) {
+		se.se_resume = *param->resume_handle;
+		se.se_nskip = se.se_resume;
+		*param->resume_handle = 0;
+	}
+
 	switch (param->info.switch_value) {
 	case 2:
-		status = srvsvc_NetFileEnum2(mxa, param);
+		status = srvsvc_NetFileEnum2(mxa, param, &se);
 		break;
 
 	case 3:
-		status = srvsvc_NetFileEnum3(mxa, param);
+		status = srvsvc_NetFileEnum3(mxa, param, &se);
 		break;
 
 	case 50:
@@ -449,92 +604,144 @@
 		return (NDR_DRC_OK);
 	}
 
-	if (param->resume_handle)
-		*param->resume_handle = 0;
-
-	param->status = ERROR_SUCCESS;
+	if (param->resume_handle &&
+	    param->pref_max_len != SMB_SRVSVC_MAXPREFLEN) {
+		if (se.se_resume < param->total_entries) {
+			*param->resume_handle = se.se_resume;
+			status = ERROR_MORE_DATA;
+		}
+	}
+
+	param->status = status;
 	return (NDR_DRC_OK);
 }
 
 /*
  * Build level 2 file information.
  *
+ * SMB fids are 16-bit values but this interface expects 32-bit file ids.
+ * So we use the uniqid here.
+ *
  * On success, the caller expects that the info2, fi2 and entries_read
  * fields have been set up.
  */
 static DWORD
-srvsvc_NetFileEnum2(ndr_xa_t *mxa, struct mslm_NetFileEnum *param)
+srvsvc_NetFileEnum2(ndr_xa_t *mxa, struct mslm_NetFileEnum *param,
+    smb_svcenum_t *se)
 {
-	struct mslm_NetFileInfoBuf2 *fi2;
-	ndr_pipe_info_t pi;
-	uint32_t entries_read = 0;
-	int i;
+	struct mslm_NetFileInfoBuf2	*fi2;
+	smb_netsvc_t			*ns;
+	smb_netsvcitem_t		*item;
+	smb_netfileinfo_t		*ofile;
+	uint32_t			entries_read = 0;
 
 	param->info.ru.info2 = NDR_NEW(mxa, struct mslm_NetFileInfo2);
 	if (param->info.ru.info2 == NULL)
 		return (ERROR_NOT_ENOUGH_MEMORY);
 
-	fi2 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf2, 128);
+	srvsvc_estimate_limit(se, sizeof (struct mslm_NetFileInfoBuf2));
+	if (se->se_nlimit == 0)
+		return (NERR_BufTooSmall);
+
+	do {
+		fi2 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf2, se->se_nlimit);
+		if (fi2 == NULL)
+			se->se_nlimit >>= 1;
+	} while ((se->se_nlimit > 0) && (fi2 == NULL));
+
 	if (fi2 == NULL)
 		return (ERROR_NOT_ENOUGH_MEMORY);
 
 	param->info.ru.info2->fi2 = fi2;
 
-	for (i = 0; i < 128; ++i) {
-		if (ndr_pipe_getinfo(i, &pi) == -1)
-			continue;
-
-		fi2->fi2_id = pi.npi_fid;
+	if ((ns = smb_kmod_enum_init(se)) == NULL)
+		return (ERROR_NOT_ENOUGH_MEMORY);
+
+	if (smb_kmod_enum(ns) != 0) {
+		smb_kmod_enum_fini(ns);
+		return (ERROR_INTERNAL_ERROR);
+	}
+
+	item = list_head(&ns->ns_list);
+	while (item != NULL) {
+		ofile = &item->nsi_un.nsi_ofile;
+		fi2->fi2_id = ofile->fi_uniqid;
 
 		++entries_read;
 		++fi2;
+		item = list_next(&ns->ns_list, item);
 	}
 
+	se->se_resume += entries_read;
 	param->info.ru.info2->entries_read = entries_read;
-	param->total_entries = entries_read;
+	smb_kmod_enum_fini(ns);
 	return (ERROR_SUCCESS);
 }
 
 /*
  * Build level 3 file information.
  *
+ * SMB fids are 16-bit values but this interface expects 32-bit file ids.
+ * So we use the uniqid here.
+ *
  * On success, the caller expects that the info3, fi3 and entries_read
  * fields have been set up.
  */
 static DWORD
-srvsvc_NetFileEnum3(ndr_xa_t *mxa, struct mslm_NetFileEnum *param)
+srvsvc_NetFileEnum3(ndr_xa_t *mxa, struct mslm_NetFileEnum *param,
+    smb_svcenum_t *se)
 {
-	struct mslm_NetFileInfoBuf3 *fi3;
-	ndr_pipe_info_t pi;
-	uint32_t entries_read = 0;
-	int i;
+	struct mslm_NetFileInfoBuf3	*fi3;
+	smb_netsvc_t			*ns;
+	smb_netsvcitem_t		*item;
+	smb_netfileinfo_t		*ofile;
+	uint32_t			entries_read = 0;
 
 	param->info.ru.info3 = NDR_NEW(mxa, struct mslm_NetFileInfo3);
 	if (param->info.ru.info3 == NULL)
 		return (ERROR_NOT_ENOUGH_MEMORY);
 
-	fi3 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf3, 128);
+	srvsvc_estimate_limit(se,
+	    sizeof (struct mslm_NetFileInfoBuf3) + MAXNAMELEN);
+	if (se->se_nlimit == 0)
+		return (NERR_BufTooSmall);
+
+	do {
+		fi3 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf3, se->se_nlimit);
+		if (fi3 == NULL)
+			se->se_nlimit >>= 1;
+	} while ((se->se_nlimit > 0) && (fi3 == NULL));
+
 	if (fi3 == NULL)
 		return (ERROR_NOT_ENOUGH_MEMORY);
 
 	param->info.ru.info3->fi3 = fi3;
 
-	for (i = 0; i < 128; ++i) {
-		if (ndr_pipe_getinfo(i, &pi) == -1)
-			continue;
-
-		fi3->fi3_id = pi.npi_fid;
-		fi3->fi3_permissions = pi.npi_permissions;
-		fi3->fi3_num_locks = pi.npi_num_locks;
+	if ((ns = smb_kmod_enum_init(se)) == NULL)
+		return (ERROR_NOT_ENOUGH_MEMORY);
+
+	if (smb_kmod_enum(ns) != 0) {
+		smb_kmod_enum_fini(ns);
+		return (ERROR_INTERNAL_ERROR);
+	}
+
+	item = list_head(&ns->ns_list);
+	while (item != NULL) {
+		ofile = &item->nsi_un.nsi_ofile;
+		fi3->fi3_id = ofile->fi_uniqid;
+		fi3->fi3_permissions = ofile->fi_permissions;
+		fi3->fi3_num_locks = ofile->fi_numlocks;
 		fi3->fi3_pathname = (uint8_t *)
-		    NDR_STRDUP(mxa, pi.npi_pathname);
+		    NDR_STRDUP(mxa, ofile->fi_path);
 		fi3->fi3_username = (uint8_t *)
-		    NDR_STRDUP(mxa, pi.npi_username);
+		    NDR_STRDUP(mxa, ofile->fi_username);
 
 		++entries_read;
 		++fi3;
+		item = list_next(&ns->ns_list, item);
 	}
 
+	se->se_resume += entries_read;
 	param->info.ru.info3->entries_read = entries_read;
 	param->total_entries = entries_read;
 	return (ERROR_SUCCESS);
@@ -544,32 +751,56 @@
  * srvsvc_s_NetFileClose
  *
  * NetFileClose forces a file to close. This function can be used when
- * an error prevents closure by any other means.  Use NetFileClose with
+ * an error prevents closure by other means.  Use NetFileClose with
  * caution because it does not flush data, cached on a client, to the
  * file before closing the file.
  *
+ * SMB fids are 16-bit values but this interface expects 32-bit file ids.
+ * So we use the uniqid here.
+ *
  * Return Values
  * ERROR_SUCCESS            Operation succeeded.
  * ERROR_ACCESS_DENIED      Operation denied.
  * NERR_FileIdNotFound      No open file with the specified id.
  *
- * Note: MSDN suggests that the error code should be ERROR_FILE_NOT_FOUND
- * but network captures using NT show NERR_FileIdNotFound.
- * The NetFileClose2 MSDN page has the right error code.
+ * Note: MSDN suggests ERROR_FILE_NOT_FOUND for NetFileClose but network
+ * captures using NT show NERR_FileIdNotFound, which is consistent with
+ * the NetFileClose2 page on MSDN.
  */
 static int
 srvsvc_s_NetFileClose(void *arg, ndr_xa_t *mxa)
 {
+	static struct {
+		int errnum;
+		int nerr;
+	} errmap[] = {
+		0,	ERROR_SUCCESS,
+		EACCES,	ERROR_ACCESS_DENIED,
+		EPERM,	ERROR_ACCESS_DENIED,
+		EINVAL,	ERROR_INVALID_PARAMETER,
+		ENOMEM,	ERROR_NOT_ENOUGH_MEMORY,
+		ENOENT,	NERR_FileIdNotFound
+	};
+
 	struct mslm_NetFileClose *param = arg;
+	int		i;
+	int		rc;
 
 	if (!ndr_is_admin(mxa)) {
-		bzero(param, sizeof (struct mslm_NetFileClose));
 		param->status = ERROR_ACCESS_DENIED;
 		return (NDR_DRC_OK);
 	}
 
-	bzero(param, sizeof (struct mslm_NetFileClose));
-	param->status = ERROR_SUCCESS;
+	rc = smb_kmod_file_close(param->file_id);
+
+	for (i = 0; i < (sizeof (errmap) / sizeof (errmap[0])); ++i) {
+		if (rc == errmap[i].errnum) {
+			param->status = errmap[i].nerr;
+			return (NDR_DRC_OK);
+		}
+	}
+
+	param->status = ERROR_INTERNAL_ERROR;
 	return (NDR_DRC_OK);
 }
 
@@ -1059,393 +1290,222 @@
 static int
 srvsvc_s_NetSessionEnum(void *arg, ndr_xa_t *mxa)
 {
-	struct mslm_NetSessionEnum *param = arg;
-	struct mslm_infonres *infonres;
-	DWORD status;
-	DWORD n_sessions;
-
-	infonres = NDR_NEW(mxa, struct mslm_infonres);
-	if (infonres == NULL) {
-		bzero(param, sizeof (struct mslm_NetSessionEnum));
-		param->status = ERROR_NOT_ENOUGH_MEMORY;
+	struct mslm_NetSessionEnum	*param = arg;
+	srvsvc_infonres_t		*info;
+	smb_netsvc_t			*ns;
+	smb_svcenum_t			se;
+	DWORD				status = ERROR_SUCCESS;
+
+	if (!ndr_is_admin(mxa)) {
+		status = ERROR_ACCESS_DENIED;
+		goto srvsvc_netsessionenum_error;
+	}
+
+	if ((info = NDR_NEW(mxa, srvsvc_infonres_t)) == NULL) {
+		status = ERROR_NOT_ENOUGH_MEMORY;
+		goto srvsvc_netsessionenum_error;
+	}
+
+	info->entriesread = 0;
+	info->entries = NULL;
+	param->result.level = param->level;
+	param->result.bufptr.p = info;
+
+	if ((param->total_entries = srvsvc_open_sessions()) == 0) {
+		param->resume_handle = NULL;
+		param->status = ERROR_SUCCESS;
 		return (NDR_DRC_OK);
 	}
 
-	infonres->entriesread = 0;
-	infonres->entries = NULL;
-	param->result.level = param->level;
-	param->result.bufptr.p = infonres;
-	param->total_entries = 0;
-	param->resume_handle = NULL;
-	param->status = ERROR_SUCCESS;
-
-	if ((n_sessions = (DWORD) mlsvc_get_num_users()) == 0)
-		return (NDR_DRC_OK);
+	bzero(&se, sizeof (smb_svcenum_t));
+	se.se_type = SMB_SVCENUM_TYPE_USER;
+	se.se_level = param->level;
+	se.se_ntotal = param->total_entries;
+	se.se_nlimit = se.se_ntotal;
+
+	if (param->resume_handle) {
+		se.se_resume = *param->resume_handle;
+		se.se_nskip = se.se_resume;
+		*param->resume_handle = 0;
+	}
 
 	switch (param->level) {
 	case 0:
-		status = mlsvc_NetSessionEnumLevel0(infonres, n_sessions, mxa);
-		break;
-
-	case 1:
-		status = mlsvc_NetSessionEnumLevel1(infonres, n_sessions, mxa);
+		info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_0,
+		    se.se_nlimit);
 		break;
-
-	case 2:
-		status = mlsvc_NetSessionEnumLevel2(infonres, n_sessions, mxa);
+	case 1:
+		info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_1,
+		    se.se_nlimit);
 		break;
-
-	case 10:
-		status = mlsvc_NetSessionEnumLevel10(infonres, n_sessions, mxa);
+	case 2:
+		info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_2,
+		    se.se_nlimit);
 		break;
-
+	case 10:
+		info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_10,
+		    se.se_nlimit);
+		break;
 	case 502:
-		status = mlsvc_NetSessionEnumLevel502(infonres, n_sessions,
-		    mxa);
+		info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_502,
+		    se.se_nlimit);
 		break;
-
 	default:
-		status = ERROR_INVALID_LEVEL;
-		break;
-	}
-
-	if (status != 0) {
 		bzero(param, sizeof (struct mslm_NetSessionEnum));
-		param->status = status;
+		param->status = ERROR_INVALID_LEVEL;
 		return (NDR_DRC_OK);
 	}
 
-	param->total_entries = infonres->entriesread;
+	if (info->entries == NULL) {
+		status = ERROR_NOT_ENOUGH_MEMORY;
+		goto srvsvc_netsessionenum_error;
+	}
+
+	if ((ns = smb_kmod_enum_init(&se)) == NULL) {
+		status = ERROR_NOT_ENOUGH_MEMORY;
+		goto srvsvc_netsessionenum_error;
+	}
+
+	status = srvsvc_NetSessionEnumCommon(mxa, info, ns, &se);
+	smb_kmod_enum_fini(ns);
+
+	if (status != ERROR_SUCCESS)
+		goto srvsvc_netsessionenum_error;
+
+	if (param->resume_handle &&
+	    param->pref_max_len != SMB_SRVSVC_MAXPREFLEN) {
+		if (se.se_resume < param->total_entries) {
+			*param->resume_handle = se.se_resume;
+			status = ERROR_MORE_DATA;
+		}
+	}
+
+	param->total_entries = info->entriesread;
+	param->status = status;
+	return (NDR_DRC_OK);
+
+srvsvc_netsessionenum_error:
+	bzero(param, sizeof (struct mslm_NetSessionEnum));
 	param->status = status;
 	return (NDR_DRC_OK);
 }
 
-/*
- * mlsvc_NetSessionEnumLevel0
- *
- * Build the level 0 session information.
- */
-static DWORD
-mlsvc_NetSessionEnumLevel0(struct mslm_infonres *infonres, DWORD n_sessions,
-    ndr_xa_t *mxa)
+static uint32_t
+srvsvc_NetSessionEnumCommon(ndr_xa_t *mxa, srvsvc_infonres_t *info,
+    smb_netsvc_t *ns, smb_svcenum_t *se)
 {
-	struct mslm_SESSION_INFO_0 *info0;
-	smb_ulist_t *ulist;
-	smb_opipe_context_t *user;
-	char *workstation;
-	char ipaddr_buf[INET6_ADDRSTRLEN];
-	int i;
-
-	ulist = smb_ulist_alloc();
-	if (ulist == NULL)
-		return (ERROR_NOT_ENOUGH_MEMORY);
-
-	if (mlsvc_get_user_list(ulist) != 0) {
-		smb_ulist_free(ulist);
-		return (ERROR_NOT_ENOUGH_MEMORY);
-	}
-
-	if (ulist->ul_cnt < n_sessions)
-		n_sessions = ulist->ul_cnt;
-
-	info0 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_0, n_sessions);
-	if (info0 == NULL) {
-		smb_ulist_free(ulist);
-		return (ERROR_NOT_ENOUGH_MEMORY);
-	}
-
-	user = ulist->ul_users;
-	for (i = 0; i < n_sessions; ++i, user++) {
-		workstation = user->oc_workstation;
+	struct mslm_SESSION_INFO_0	*info0 = info->entries;
+	struct mslm_SESSION_INFO_1	*info1 = info->entries;
+	struct mslm_SESSION_INFO_2	*info2 = info->entries;
+	struct mslm_SESSION_INFO_10	*info10 = info->entries;
+	struct mslm_SESSION_INFO_502	*info502 = info->entries;
+	smb_netsvcitem_t		*item;
+	smb_netuserinfo_t		*user;
+	char				*workstation;
+	char				account[MAXNAMELEN];
+	char				ipaddr_buf[INET6_ADDRSTRLEN];
+	uint32_t			logon_time;
+	uint32_t			flags;
+	uint32_t			entries_read = 0;
+
+	if (smb_kmod_enum(ns) != 0)
+		return (ERROR_INTERNAL_ERROR);
+
+	item = list_head(&ns->ns_list);
+	while (item != NULL) {
+		user = &item->nsi_un.nsi_user;
+
+		workstation = user->ui_workstation;
 		if (workstation == NULL || *workstation == '\0') {
-			(void) smb_inet_ntop(&user->oc_ipaddr,
-			    ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
-			workstation = ipaddr_buf;
-		}
-
-		info0[i].sesi0_cname = NDR_STRDUP(mxa, workstation);
-		if (info0[i].sesi0_cname == NULL) {
-			smb_ulist_free(ulist);
-			return (ERROR_NOT_ENOUGH_MEMORY);
-		}
-	}
-
-	smb_ulist_free(ulist);
-	infonres->entriesread = n_sessions;
-	infonres->entries = info0;
-	return (ERROR_SUCCESS);
-}
-
-/*
- * mlsvc_NetSessionEnumLevel1
- *
- * Build the level 1 session information.
- */
-static DWORD
-mlsvc_NetSessionEnumLevel1(struct mslm_infonres *infonres, DWORD n_sessions,
-    ndr_xa_t *mxa)
-{
-	struct mslm_SESSION_INFO_1 *info1;
-	smb_ulist_t *ulist;
-	smb_opipe_context_t *user;
-	char *workstation;
-	char account[MAXNAMELEN];
-	char ipaddr_buf[INET6_ADDRSTRLEN];
-	int i;
-
-	ulist = smb_ulist_alloc();
-	if (ulist == NULL)
-		return (ERROR_NOT_ENOUGH_MEMORY);
-
-	if (mlsvc_get_user_list(ulist) != 0) {
-		smb_ulist_free(ulist);
-		return (ERROR_NOT_ENOUGH_MEMORY);
-	}
-
-	if (ulist->ul_cnt < n_sessions)
-		n_sessions = ulist->ul_cnt;
-
-	info1 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_1, n_sessions);
-	if (info1 == NULL) {
-		smb_ulist_free(ulist);
-		return (ERROR_NOT_ENOUGH_MEMORY);
-	}
-
-	user = ulist->ul_users;
-	for (i = 0; i < n_sessions; ++i, user++) {
-		workstation = user->oc_workstation;
-		if (workstation == NULL || *workstation == '\0') {
-			(void) smb_inet_ntop(&user->oc_ipaddr,
-			    ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
+			(void) smb_inet_ntop(&user->ui_ipaddr, ipaddr_buf,
+			    SMB_IPSTRLEN(user->ui_ipaddr.a_family));
 			workstation = ipaddr_buf;
 		}
 
 		(void) snprintf(account, MAXNAMELEN, "%s\\%s",
-		    user->oc_domain, user->oc_account);
-
-		info1[i].sesi1_cname = NDR_STRDUP(mxa, workstation);
-		info1[i].sesi1_uname = NDR_STRDUP(mxa, account);
-
-		if (info1[i].sesi1_cname == NULL ||
-		    info1[i].sesi1_uname == NULL) {
-			smb_ulist_free(ulist);
-			return (ERROR_NOT_ENOUGH_MEMORY);
+		    user->ui_domain, user->ui_account);
+
+		logon_time = time(0) - user->ui_logon_time;
+		flags = (user->ui_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0;
+
+		switch (se->se_level) {
+		case 0:
+			info0->sesi0_cname = NDR_STRDUP(mxa, workstation);
+			if (info0->sesi0_cname == NULL)
+				return (ERROR_NOT_ENOUGH_MEMORY);
+			++info0;
+			break;
+
+		case 1:
+			info1->sesi1_cname = NDR_STRDUP(mxa, workstation);
+			info1->sesi1_uname = NDR_STRDUP(mxa, account);
+
+			if (info1->sesi1_cname == NULL ||
+			    info1->sesi1_uname == NULL)
+				return (ERROR_NOT_ENOUGH_MEMORY);
+
+			info1->sesi1_nopens = user->ui_numopens;
+			info1->sesi1_time = logon_time;
+			info1->sesi1_itime = 0;
+			info1->sesi1_uflags = flags;
+			++info1;
+			break;
+
+		case 2:
+			info2->sesi2_cname = NDR_STRDUP(mxa, workstation);
+			info2->sesi2_uname = NDR_STRDUP(mxa, account);
+
+			if (info2->sesi2_cname == NULL ||
+			    info2->sesi2_uname == NULL)
+				return (ERROR_NOT_ENOUGH_MEMORY);
+
+			info2->sesi2_nopens = user->ui_numopens;
+			info2->sesi2_time = logon_time;
+			info2->sesi2_itime = 0;
+			info2->sesi2_uflags = flags;
+			info2->sesi2_cltype_name = (uint8_t *)"";
+			++info2;
+			break;
+
+		case 10:
+			info10->sesi10_cname = NDR_STRDUP(mxa, workstation);
+			info10->sesi10_uname = NDR_STRDUP(mxa, account);
+
+			if (info10->sesi10_cname == NULL ||
+			    info10->sesi10_uname == NULL)
+				return (ERROR_NOT_ENOUGH_MEMORY);
+
+			info10->sesi10_time = logon_time;
+			info10->sesi10_itime = 0;
+			++info10;
+			break;
+
+		case 502:
+			info502->sesi502_cname = NDR_STRDUP(mxa, workstation);
+			info502->sesi502_uname = NDR_STRDUP(mxa, account);
+
+			if (info502->sesi502_cname == NULL ||
+			    info502->sesi502_uname == NULL)
+				return (ERROR_NOT_ENOUGH_MEMORY);
+
+			info502->sesi502_nopens = user->ui_numopens;
+			info502->sesi502_time = logon_time;
+			info502->sesi502_itime = 0;
+			info502->sesi502_uflags = flags;
+			info502->sesi502_cltype_name = (uint8_t *)"";
+			info502->sesi502_transport = (uint8_t *)"";
+			++info502;
+			break;
+
+		default:
+			return (ERROR_INVALID_LEVEL);
 		}
 
-		info1[i].sesi1_nopens = 1;
-		info1[i].sesi1_time = time(0) - user->oc_logon_time;
-		info1[i].sesi1_itime = 0;
-		info1[i].sesi1_uflags =
-		    (user->oc_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0;
-	}
-
-	smb_ulist_free(ulist);
-	infonres->entriesread = n_sessions;
-	infonres->entries = info1;
-	return (ERROR_SUCCESS);
-}
-
-/*
- * mlsvc_NetSessionEnumLevel2
- *
- * Build the level 2 session information.
- */
-static DWORD
-mlsvc_NetSessionEnumLevel2(struct mslm_infonres *infonres, DWORD n_sessions,
-    ndr_xa_t *mxa)
-{
-	struct mslm_SESSION_INFO_2 *info2;
-	smb_ulist_t *ulist;
-	smb_opipe_context_t *user;
-	char *workstation;
-	char account[MAXNAMELEN];
-	char ipaddr_buf[INET6_ADDRSTRLEN];
-	int i;
-
-	if ((ulist = smb_ulist_alloc()) == NULL)
-		return (ERROR_NOT_ENOUGH_MEMORY);
-
-	if (mlsvc_get_user_list(ulist) != 0) {
-		smb_ulist_free(ulist);
-		return (ERROR_NOT_ENOUGH_MEMORY);
-	}
-
-	if (ulist->ul_cnt < n_sessions)
-		n_sessions = ulist->ul_cnt;
-
-	info2 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_2, n_sessions);
-	if (info2 == NULL) {
-		smb_ulist_free(ulist);
-		return (ERROR_NOT_ENOUGH_MEMORY);
-	}
-
-	user = ulist->ul_users;
-	for (i = 0; i < n_sessions; ++i, user++) {
-		workstation = user->oc_workstation;
-		if (workstation == NULL || *workstation == '\0') {
-			(void) smb_inet_ntop(&user->oc_ipaddr,
-			    ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
-			workstation = ipaddr_buf;
-		}
-
-		(void) snprintf(account, MAXNAMELEN, "%s\\%s",
-		    user->oc_domain, user->oc_account);
-
-		info2[i].sesi2_cname = NDR_STRDUP(mxa, workstation);
-		info2[i].sesi2_uname = NDR_STRDUP(mxa, account);
-
-		if (info2[i].sesi2_cname == NULL ||
-		    info2[i].sesi2_uname == NULL) {
-			smb_ulist_free(ulist);
-			return (ERROR_NOT_ENOUGH_MEMORY);
-		}
-
-		info2[i].sesi2_nopens = 1;
-		info2[i].sesi2_time = time(0) - user->oc_logon_time;
-		info2[i].sesi2_itime = 0;
-		info2[i].sesi2_uflags =
-		    (user->oc_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0;
-		info2[i].sesi2_cltype_name = (uint8_t *)"";
+		++entries_read;
+		item = list_next(&ns->ns_list, item);
 	}
 
-	smb_ulist_free(ulist);
-	infonres->entriesread = n_sessions;
-	infonres->entries = info2;
-	return (ERROR_SUCCESS);
-}
-
-/*
- * mlsvc_NetSessionEnumLevel10
- *
- * Build the level 10 session information.
- */
-static DWORD
-mlsvc_NetSessionEnumLevel10(struct mslm_infonres *infonres, DWORD n_sessions,
-    ndr_xa_t *mxa)
-{
-	struct mslm_SESSION_INFO_10 *info10;
-	smb_ulist_t *ulist;
-	smb_opipe_context_t *user;
-	char *workstation;
-	char account[MAXNAMELEN];
-	char ipaddr_buf[INET6_ADDRSTRLEN];
-	int i;
-
-	if ((ulist = smb_ulist_alloc()) == NULL)
-		return (ERROR_NOT_ENOUGH_MEMORY);
-
-	if (mlsvc_get_user_list(ulist) != 0) {
-		smb_ulist_free(ulist);
-		return (ERROR_NOT_ENOUGH_MEMORY);
-	}
-
-	if (ulist->ul_cnt < n_sessions)
-		n_sessions = ulist->ul_cnt;
-
-	info10 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_10, n_sessions);
-	if (info10 == NULL) {
-		smb_ulist_free(ulist);
-		return (ERROR_NOT_ENOUGH_MEMORY);
-	}
-
-	user = ulist->ul_users;
-	for (i = 0; i < n_sessions; ++i, user++) {
-		workstation = user->oc_workstation;
-		if (workstation == NULL || *workstation == '\0') {
-			(void) smb_inet_ntop(&user->oc_ipaddr,
-			    ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
-			workstation = ipaddr_buf;
-		}
-
-		(void) snprintf(account, MAXNAMELEN, "%s\\%s",
-		    user->oc_domain, user->oc_account);
-
-		info10[i].sesi10_cname = NDR_STRDUP(mxa, workstation);
-		info10[i].sesi10_uname = NDR_STRDUP(mxa, account);
-
-		if (info10[i].sesi10_cname == NULL ||
-		    info10[i].sesi10_uname == NULL) {
-			smb_ulist_free(ulist);
-			return (ERROR_NOT_ENOUGH_MEMORY);
-		}
-
-		info10[i].sesi10_time = time(0) - user->oc_logon_time;
-		info10[i].sesi10_itime = 0;
-	}
-
-	smb_ulist_free(ulist);
-	infonres->entriesread = n_sessions;
-	infonres->entries = info10;
-	return (ERROR_SUCCESS);
-}
-
-/*
- * mlsvc_NetSessionEnumLevel502
- *
- * Build the level 502 session information.
- */
-static DWORD
-mlsvc_NetSessionEnumLevel502(struct mslm_infonres *infonres, DWORD n_sessions,
-    ndr_xa_t *mxa)
-{
-	struct mslm_SESSION_INFO_502 *info502;
-	smb_ulist_t *ulist;
-	smb_opipe_context_t *user;
-	char *workstation;
-	char account[MAXNAMELEN];
-	char ipaddr_buf[INET6_ADDRSTRLEN];
-	int i;
-
-	if ((ulist = smb_ulist_alloc()) == NULL)
-		return (ERROR_NOT_ENOUGH_MEMORY);
-
-	if (mlsvc_get_user_list(ulist) != 0) {
-		smb_ulist_free(ulist);
-		return (ERROR_NOT_ENOUGH_MEMORY);
-	}
-
-	if (ulist->ul_cnt < n_sessions)
-		n_sessions = ulist->ul_cnt;
-
-	info502 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_502, n_sessions);
-	if (info502 == NULL) {
-		smb_ulist_free(ulist);
-		return (ERROR_NOT_ENOUGH_MEMORY);
-	}
-
-	user = ulist->ul_users;
-	for (i = 0; i < n_sessions; ++i, user++) {
-		workstation = user->oc_workstation;
-		if (workstation == NULL || *workstation == '\0') {
-			(void) smb_inet_ntop(&user->oc_ipaddr,
-			    ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
-			workstation = ipaddr_buf;
-		}
-
-		(void) snprintf(account, MAXNAMELEN, "%s\\%s",
-		    user->oc_domain, user->oc_account);
-
-		info502[i].sesi502_cname = NDR_STRDUP(mxa, workstation);
-		info502[i].sesi502_uname = NDR_STRDUP(mxa, account);
-
-		if (info502[i].sesi502_cname == NULL ||
-		    info502[i].sesi502_uname == NULL) {
-			smb_ulist_free(ulist);
-			return (ERROR_NOT_ENOUGH_MEMORY);
-		}
-
-		info502[i].sesi502_nopens = 1;
-		info502[i].sesi502_time = time(0) - user->oc_logon_time;
-		info502[i].sesi502_itime = 0;
-		info502[i].sesi502_uflags =
-		    (user->oc_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0;
-		info502[i].sesi502_cltype_name = (uint8_t *)"";
-		info502[i].sesi502_transport = (uint8_t *)"";
-	}
-
-	smb_ulist_free(ulist);
-	infonres->entriesread = n_sessions;
-	infonres->entries = info502;
+	info->entriesread = entries_read;
 	return (ERROR_SUCCESS);
 }
 
@@ -1456,29 +1516,58 @@
  * On NT only members of the Administrators or Account Operators
  * local groups are permitted to use NetSessionDel.
  *
+ * If unc_clientname is NULL, all sessions associated with the
+ * specified user will be disconnected.
+ *
+ * If username is NULL, all sessions from the specified client
+ * will be disconnected.
+ *
  * Return Values
- * If the function succeeds, the return value is NERR_Success/
- * ERROR_SUCCESS. If the function fails, the return value can be
- * one of the following error codes:
+ * On success, the return value is NERR_Success/ERROR_SUCCESS.
+ * On failure, the return value can be one of the following errors:
  *
  * ERROR_ACCESS_DENIED 		The user does not have access to the
- * 							requested information.
+ * 				requested information.
  * ERROR_INVALID_PARAMETER	The specified parameter is invalid.
  * ERROR_NOT_ENOUGH_MEMORY	Insufficient memory is available.
  * NERR_ClientNameNotFound	A session does not exist with that
- *                          computer name.
+ *				computer name.
  */
 static int
 srvsvc_s_NetSessionDel(void *arg, ndr_xa_t *mxa)
 {
+	static struct {
+		int errnum;
+		int nerr;
+	} errmap[] = {
+		0,	ERROR_SUCCESS,
+		EACCES,	ERROR_ACCESS_DENIED,
+		EPERM,	ERROR_ACCESS_DENIED,
+		EINVAL,	ERROR_INVALID_PARAMETER,
+		ENOMEM,	ERROR_NOT_ENOUGH_MEMORY,
+		ENOENT,	NERR_ClientNameNotFound
+	};
+
 	struct mslm_NetSessionDel *param = arg;
-
-	if (!ndr_is_poweruser(mxa)) {
+	int	i;
+	int	rc;
+
+	if (!ndr_is_admin(mxa)) {
 		param->status = ERROR_ACCESS_DENIED;
 		return (NDR_DRC_OK);
 	}
 
-	param->status = ERROR_ACCESS_DENIED;
+	rc = smb_kmod_session_close((char *)param->unc_clientname,
+	    (char *)param->username);
+
+	for (i = 0; i < (sizeof (errmap) / sizeof (errmap[0])); ++i) {
+		if (rc == errmap[i].errnum) {
+			param->status = errmap[i].nerr;
+			return (NDR_DRC_OK);
+		}
+	}
+
+	param->status = ERROR_INTERNAL_ERROR;
 	return (NDR_DRC_OK);
 }
 
@@ -1853,25 +1942,30 @@
 }
 
 /*
- * srvsvc_estimate_objcnt
+ * srvsvc_estimate_limit
  *
  * Estimate the number of objects that will fit in prefmaxlen.
+ * nlimit is adjusted here.
  */
-static uint32_t
-srvsvc_estimate_objcnt(uint32_t prefmaxlen, uint32_t n_obj, uint32_t obj_size)
+static void
+srvsvc_estimate_limit(smb_svcenum_t *se, uint32_t obj_size)
 {
 	DWORD max_cnt;
 
-	if (obj_size == 0)
-		return (0);
-
-	if ((max_cnt = (prefmaxlen / obj_size)) == 0)
-		return (0);
-
-	if (n_obj > max_cnt)
-		n_obj = max_cnt;
-
-	return (n_obj);
+	if (obj_size == 0) {
+		se->se_nlimit = 0;
+		return;
+	}
+
+	if ((max_cnt = (se->se_prefmaxlen / obj_size)) == 0) {
+		se->se_nlimit = 0;
+		return;
+	}
+
+	if (se->se_ntotal > max_cnt)
+		se->se_nlimit = max_cnt;
+	else
+		se->se_nlimit = se->se_ntotal;
 }
 
 /*
@@ -1890,11 +1984,11 @@
 srvsvc_s_NetShareEnum(void *arg, ndr_xa_t *mxa)
 {
 	struct mslm_NetShareEnum *param = arg;
-	struct mslm_infonres *infonres;
-	srvsvc_enum_t se;
+	srvsvc_infonres_t *infonres;
+	smb_svcenum_t se;
 	DWORD status;
 
-	infonres = NDR_NEW(mxa, struct mslm_infonres);
+	infonres = NDR_NEW(mxa, srvsvc_infonres_t);
 	if (infonres == NULL) {
 		bzero(param, sizeof (struct mslm_NetShareEnum));
 		param->status = ERROR_NOT_ENOUGH_MEMORY;
@@ -1906,9 +2000,11 @@
 	param->result.level = param->level;
 	param->result.bufptr.p = infonres;
 
-	bzero(&se, sizeof (srvsvc_enum_t));
+	bzero(&se, sizeof (smb_svcenum_t));
+	se.se_type = SMB_SVCENUM_TYPE_SHARE;
 	se.se_level = param->level;
-	se.se_n_total = smb_shr_count();
+	se.se_ntotal = smb_shr_count();
+	se.se_nlimit = se.se_ntotal;
 
 	if (param->prefmaxlen == SMB_SRVSVC_MAXPREFLEN ||
 	    param->prefmaxlen > SMB_SRVSVC_MAXBUFLEN)
@@ -1917,8 +2013,9 @@
 		se.se_prefmaxlen = param->prefmaxlen;
 
 	if (param->resume_handle) {
-		se.se_resume_handle = *param->resume_handle;
-		se.se_n_skip = se.se_resume_handle;
+		se.se_resume = *param->resume_handle;
+		se.se_nskip = se.se_resume;
+		*param->resume_handle = 0;
 	}
 
 	switch (param->level) {
@@ -1953,24 +2050,20 @@
 		return (NDR_DRC_OK);
 	}
 
-	if (se.se_n_enum == 0) {
-		if (param->resume_handle)
-			*param->resume_handle = 0;
+	if (se.se_nlimit == 0) {
 		param->status = ERROR_SUCCESS;
 		return (NDR_DRC_OK);
 	}
 
 	if (param->resume_handle &&
 	    param->prefmaxlen != SMB_SRVSVC_MAXPREFLEN) {
-		if (se.se_resume_handle < se.se_n_total) {
-			*param->resume_handle = se.se_resume_handle;
+		if (se.se_resume < se.se_ntotal) {
+			*param->resume_handle = se.se_resume;
 			status = ERROR_MORE_DATA;
-		} else {
-			*param->resume_handle = 0;
 		}
 	}
 
-	param->totalentries = se.se_n_total;
+	param->totalentries = se.se_ntotal;
 	param->status = status;
 	return (NDR_DRC_OK);
 }
@@ -1996,11 +2089,11 @@
 srvsvc_s_NetShareEnumSticky(void *arg, ndr_xa_t *mxa)
 {
 	struct mslm_NetShareEnum *param = arg;
-	struct mslm_infonres *infonres;
-	srvsvc_enum_t se;
+	srvsvc_infonres_t *infonres;
+	smb_svcenum_t se;
 	DWORD status;
 
-	infonres = NDR_NEW(mxa, struct mslm_infonres);
+	infonres = NDR_NEW(mxa, srvsvc_infonres_t);
 	if (infonres == NULL) {
 		bzero(param, sizeof (struct mslm_NetShareEnum));
 		param->status = ERROR_NOT_ENOUGH_MEMORY;
@@ -2012,9 +2105,11 @@
 	param->result.level = param->level;
 	param->result.bufptr.p = infonres;
 
-	bzero(&se, sizeof (srvsvc_enum_t));
+	bzero(&se, sizeof (smb_svcenum_t));
+	se.se_type = SMB_SVCENUM_TYPE_SHARE;
 	se.se_level = param->level;
-	se.se_n_total = smb_shr_count();
+	se.se_ntotal = smb_shr_count();
+	se.se_nlimit = se.se_ntotal;
 
 	if (param->prefmaxlen == SMB_SRVSVC_MAXPREFLEN ||
 	    param->prefmaxlen > SMB_SRVSVC_MAXBUFLEN)
@@ -2023,8 +2118,9 @@
 		se.se_prefmaxlen = param->prefmaxlen;
 
 	if (param->resume_handle) {
-		se.se_resume_handle = *param->resume_handle;
-		se.se_n_skip = se.se_resume_handle;
+		se.se_resume = *param->resume_handle;
+		se.se_nskip = se.se_resume;
+		*param->resume_handle = 0;
 	}
 
 	switch (param->level) {
@@ -2056,24 +2152,20 @@
 		return (NDR_DRC_OK);
 	}
 
-	if (se.se_n_enum == 0) {
-		if (param->resume_handle)
-			*param->resume_handle = 0;
+	if (se.se_nlimit == 0) {
 		param->status = ERROR_SUCCESS;
 		return (NDR_DRC_OK);
 	}
 
 	if (param->resume_handle &&
 	    param->prefmaxlen != SMB_SRVSVC_MAXPREFLEN) {
-		if (se.se_resume_handle < se.se_n_total) {
-			*param->resume_handle = se.se_resume_handle;
+		if (se.se_resume < se.se_ntotal) {
+			*param->resume_handle = se.se_resume;
 			status = ERROR_MORE_DATA;
-		} else {
-			*param->resume_handle = 0;
 		}
 	}
 
-	param->totalentries = se.se_n_total;
+	param->totalentries = se.se_ntotal;
 	param->status = status;
 	return (NDR_DRC_OK);
 }
@@ -2082,33 +2174,33 @@
  * NetShareEnum Level 0
  */
 static DWORD
-mlsvc_NetShareEnumLevel0(ndr_xa_t *mxa,
-    struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
+mlsvc_NetShareEnumLevel0(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
+    smb_svcenum_t *se, int sticky)
 {
 	struct mslm_NetShareInfo_0 *info0;
 	smb_shriter_t iterator;
 	smb_share_t *si;
 	DWORD status;
 
-	se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
-	    se->se_n_total, sizeof (struct mslm_NetShareInfo_0) + MAXNAMELEN);
-	if (se->se_n_enum == 0)
+	srvsvc_estimate_limit(se,
+	    sizeof (struct mslm_NetShareInfo_0) + MAXNAMELEN);
+	if (se->se_nlimit == 0)
 		return (ERROR_SUCCESS);
 
-	info0 = NDR_NEWN(mxa, struct mslm_NetShareInfo_0, se->se_n_enum);
+	info0 = NDR_NEWN(mxa, struct mslm_NetShareInfo_0, se->se_nlimit);
 	if (info0 == NULL)
 		return (ERROR_NOT_ENOUGH_MEMORY);
 
 	smb_shr_iterinit(&iterator);
 
-	se->se_n_read = 0;
+	se->se_nitems = 0;
 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
-		if (se->se_n_skip > 0) {
-			--se->se_n_skip;
+		if (se->se_nskip > 0) {
+			--se->se_nskip;
 			continue;
 		}
 
-		++se->se_resume_handle;
+		++se->se_resume;
 
 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
 			continue;
@@ -2116,8 +2208,8 @@
 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
 			continue;
 
-		if (se->se_n_read >= se->se_n_enum) {
-			se->se_n_read = se->se_n_enum;
+		if (se->se_nitems >= se->se_nlimit) {
+			se->se_nitems = se->se_nlimit;
 			break;
 		}
 
@@ -2125,15 +2217,15 @@
 		if (status != ERROR_SUCCESS)
 			break;
 
-		++se->se_n_read;
+		++se->se_nitems;
 	}
 
-	if (se->se_n_read < se->se_n_enum) {
+	if (se->se_nitems < se->se_nlimit) {
 		if (srvsvc_add_autohome(mxa, se, (void *)info0))
-			++se->se_n_read;
+			++se->se_nitems;
 	}
 
-	infonres->entriesread = se->se_n_read;
+	infonres->entriesread = se->se_nitems;
 	infonres->entries = info0;
 	return (ERROR_SUCCESS);
 }
@@ -2142,33 +2234,33 @@
  * NetShareEnum Level 1
  */
 static DWORD
-mlsvc_NetShareEnumLevel1(ndr_xa_t *mxa,
-    struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
+mlsvc_NetShareEnumLevel1(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
+    smb_svcenum_t *se, int sticky)
 {
 	struct mslm_NetShareInfo_1 *info1;
 	smb_shriter_t iterator;
 	smb_share_t *si;
 	DWORD status;
 
-	se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
-	    se->se_n_total, sizeof (struct mslm_NetShareInfo_1) + MAXNAMELEN);
-	if (se->se_n_enum == 0)
+	srvsvc_estimate_limit(se,
+	    sizeof (struct mslm_NetShareInfo_1) + MAXNAMELEN);
+	if (se->se_nlimit == 0)
 		return (ERROR_SUCCESS);
 
-	info1 = NDR_NEWN(mxa, struct mslm_NetShareInfo_1, se->se_n_enum);
+	info1 = NDR_NEWN(mxa, struct mslm_NetShareInfo_1, se->se_nlimit);
 	if (info1 == NULL)
 		return (ERROR_NOT_ENOUGH_MEMORY);
 
 	smb_shr_iterinit(&iterator);
 
-	se->se_n_read = 0;
+	se->se_nitems = 0;
 	while ((si = smb_shr_iterate(&iterator)) != 0) {
-		if (se->se_n_skip > 0) {
-			--se->se_n_skip;
+		if (se->se_nskip > 0) {
+			--se->se_nskip;
 			continue;
 		}
 
-		++se->se_resume_handle;
+		++se->se_resume;
 
 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
 			continue;
@@ -2176,8 +2268,8 @@
 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
 			continue;
 
-		if (se->se_n_read >= se->se_n_enum) {
-			se->se_n_read = se->se_n_enum;
+		if (se->se_nitems >= se->se_nlimit) {
+			se->se_nitems = se->se_nlimit;
 			break;
 		}
 
@@ -2185,15 +2277,15 @@
 		if (status != ERROR_SUCCESS)
 			break;
 
-		++se->se_n_read;
+		++se->se_nitems;
 	}
 
-	if (se->se_n_read < se->se_n_enum) {
+	if (se->se_nitems < se->se_nlimit) {
 		if (srvsvc_add_autohome(mxa, se, (void *)info1))
-			++se->se_n_read;
+			++se->se_nitems;
 	}
 
-	infonres->entriesread = se->se_n_read;
+	infonres->entriesread = se->se_nitems;
 	infonres->entries = info1;
 	return (ERROR_SUCCESS);
 }
@@ -2202,33 +2294,33 @@
  * NetShareEnum Level 2
  */
 static DWORD
-mlsvc_NetShareEnumLevel2(ndr_xa_t *mxa,
-    struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
+mlsvc_NetShareEnumLevel2(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
+    smb_svcenum_t *se, int sticky)
 {
 	struct mslm_NetShareInfo_2 *info2;
 	smb_shriter_t iterator;
 	smb_share_t *si;
 	DWORD status;
 
-	se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
-	    se->se_n_total, sizeof (struct mslm_NetShareInfo_2) + MAXNAMELEN);
-	if (se->se_n_enum == 0)
+	srvsvc_estimate_limit(se,
+	    sizeof (struct mslm_NetShareInfo_2) + MAXNAMELEN);
+	if (se->se_nlimit == 0)
 		return (ERROR_SUCCESS);
 
-	info2 = NDR_NEWN(mxa, struct mslm_NetShareInfo_2, se->se_n_enum);
+	info2 = NDR_NEWN(mxa, struct mslm_NetShareInfo_2, se->se_nlimit);
 	if (info2 == NULL)
 		return (ERROR_NOT_ENOUGH_MEMORY);
 
 	smb_shr_iterinit(&iterator);
 
-	se->se_n_read = 0;
+	se->se_nitems = 0;
 	while ((si = smb_shr_iterate(&iterator)) != 0) {
-		if (se->se_n_skip > 0) {
-			--se->se_n_skip;
+		if (se->se_nskip > 0) {
+			--se->se_nskip;
 			continue;
 		}
 
-		++se->se_resume_handle;
+		++se->se_resume;
 
 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
 			continue;
@@ -2236,8 +2328,8 @@
 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
 			continue;
 
-		if (se->se_n_read >= se->se_n_enum) {
-			se->se_n_read = se->se_n_enum;
+		if (se->se_nitems >= se->se_nlimit) {
+			se->se_nitems = se->se_nlimit;
 			break;
 		}
 
@@ -2245,15 +2337,15 @@
 		if (status != ERROR_SUCCESS)
 			break;
 
-		++se->se_n_read;
+		++se->se_nitems;
 	}
 
-	if (se->se_n_read < se->se_n_enum) {
+	if (se->se_nitems < se->se_nlimit) {
 		if (srvsvc_add_autohome(mxa, se, (void *)info2))
-			++se->se_n_read;
+			++se->se_nitems;
 	}
 
-	infonres->entriesread = se->se_n_read;
+	infonres->entriesread = se->se_nitems;
 	infonres->entries = info2;
 	return (ERROR_SUCCESS);
 }
@@ -2262,34 +2354,34 @@
  * NetShareEnum Level 501
  */
 static DWORD
-mlsvc_NetShareEnumLevel501(ndr_xa_t *mxa,
-    struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
+mlsvc_NetShareEnumLevel501(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
+    smb_svcenum_t *se, int sticky)
 {
 	struct mslm_NetShareInfo_501 *info501;
 	smb_shriter_t iterator;
 	smb_share_t *si;
 	DWORD status;
 
-	se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
-	    se->se_n_total, sizeof (struct mslm_NetShareInfo_501) + MAXNAMELEN);
-	if (se->se_n_enum == 0)
+	srvsvc_estimate_limit(se,
+	    sizeof (struct mslm_NetShareInfo_501) + MAXNAMELEN);
+	if (se->se_nlimit == 0)
 		return (ERROR_SUCCESS);
 
 	info501 = NDR_NEWN(mxa, struct mslm_NetShareInfo_501,
-	    se->se_n_enum);
+	    se->se_nlimit);
 	if (info501 == NULL)
 		return (ERROR_NOT_ENOUGH_MEMORY);
 
 	smb_shr_iterinit(&iterator);
 
-	se->se_n_read = 0;
+	se->se_nitems = 0;
 	while ((si = smb_shr_iterate(&iterator)) != 0) {
-		if (se->se_n_skip > 0) {
-			--se->se_n_skip;
+		if (se->se_nskip > 0) {
+			--se->se_nskip;
 			continue;
 		}
 
-		++se->se_resume_handle;
+		++se->se_resume;
 
 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
 			continue;
@@ -2297,8 +2389,8 @@
 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
 			continue;
 
-		if (se->se_n_read >= se->se_n_enum) {
-			se->se_n_read = se->se_n_enum;
+		if (se->se_nitems >= se->se_nlimit) {
+			se->se_nitems = se->se_nlimit;
 			break;
 		}
 
@@ -2306,15 +2398,15 @@
 		if (status != ERROR_SUCCESS)
 			break;
 
-		++se->se_n_read;
+		++se->se_nitems;
 	}
 
-	if (se->se_n_read < se->se_n_enum) {
+	if (se->se_nitems < se->se_nlimit) {
 		if (srvsvc_add_autohome(mxa, se, (void *)info501))
-			++se->se_n_read;
+			++se->se_nitems;
 	}
 
-	infonres->entriesread = se->se_n_read;
+	infonres->entriesread = se->se_nitems;
 	infonres->entries = info501;
 	return (ERROR_SUCCESS);
 }
@@ -2323,34 +2415,34 @@
  * NetShareEnum Level 502
  */
 static DWORD
-mlsvc_NetShareEnumLevel502(ndr_xa_t *mxa,
-    struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
+mlsvc_NetShareEnumLevel502(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
+    smb_svcenum_t *se, int sticky)
 {
 	struct mslm_NetShareInfo_502 *info502;
 	smb_shriter_t iterator;
 	smb_share_t *si;
 	DWORD status;
 
-	se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
-	    se->se_n_total, sizeof (struct mslm_NetShareInfo_502) + MAXNAMELEN);
-	if (se->se_n_enum == 0)
+	srvsvc_estimate_limit(se,
+	    sizeof (struct mslm_NetShareInfo_502) + MAXNAMELEN);
+	if (se->se_nlimit == 0)
 		return (ERROR_SUCCESS);
 
 	info502 = NDR_NEWN(mxa, struct mslm_NetShareInfo_502,
-	    se->se_n_enum);
+	    se->se_nlimit);
 	if (info502 == NULL)
 		return (ERROR_NOT_ENOUGH_MEMORY);
 
 	smb_shr_iterinit(&iterator);
 
-	se->se_n_read = 0;
+	se->se_nitems = 0;
 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
-		if (se->se_n_skip > 0) {
-			--se->se_n_skip;
+		if (se->se_nskip > 0) {
+			--se->se_nskip;
 			continue;
 		}
 
-		++se->se_resume_handle;
+		++se->se_resume;
 
 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
 			continue;
@@ -2358,8 +2450,8 @@
 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
 			continue;
 
-		if (se->se_n_read >= se->se_n_enum) {
-			se->se_n_read = se->se_n_enum;
+		if (se->se_nitems >= se->se_nlimit) {
+			se->se_nitems = se->se_nlimit;
 			break;
 		}
 
@@ -2367,15 +2459,15 @@
 		if (status != ERROR_SUCCESS)
 			break;
 
-		++se->se_n_read;
+		++se->se_nitems;
 	}
 
-	if (se->se_n_read < se->se_n_enum) {
+	if (se->se_nitems < se->se_nlimit) {
 		if (srvsvc_add_autohome(mxa, se, (void *)info502))
-			++se->se_n_read;
+			++se->se_nitems;
 	}
 
-	infonres->entriesread = se->se_n_read;
+	infonres->entriesread = se->se_nitems;
 	infonres->entries = info502;
 	return (ERROR_SUCCESS);
 }
@@ -2396,7 +2488,7 @@
  *	ERROR_INVALID_LEVEL
  */
 static DWORD
-mlsvc_NetShareEnumCommon(ndr_xa_t *mxa, srvsvc_enum_t *se,
+mlsvc_NetShareEnumCommon(ndr_xa_t *mxa, smb_svcenum_t *se,
     smb_share_t *si, void *infop)
 {
 	struct mslm_NetShareInfo_0 *info0;
@@ -2409,7 +2501,7 @@
 	uint8_t *comment;
 	uint8_t *passwd;
 	uint8_t *path;
-	int i = se->se_n_read;
+	int i = se->se_nitems;
 
 	netname = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
 	comment = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
@@ -2487,10 +2579,10 @@
  * share to avoid duplicates.
  */
 static boolean_t
-srvsvc_add_autohome(ndr_xa_t *mxa, srvsvc_enum_t *se, void *infop)
+srvsvc_add_autohome(ndr_xa_t *mxa, smb_svcenum_t *se, void *infop)
 {
-	smb_opipe_context_t *ctx = &mxa->pipe->np_ctx;
-	char *username = ctx->oc_account;
+	smb_netuserinfo_t *user = &mxa->pipe->np_user;
+	char *username = user->ui_account;
 	smb_share_t si;
 	DWORD status;
 
@@ -2580,8 +2672,8 @@
 /*
  * srvsvc_s_NetShareDel
  *
- * Delete a share. Only the administrator, or a member of the domain
- * administrators group, is allowed to delete shares.
+ * Delete a share.  Only members of the Administrators, Server Operators
+ * or Power Users local groups are allowed to delete shares.
  *
  * This interface is used by the rmtshare command from the NT resource
  * kit. Rmtshare allows a client to add or remove shares on a server
--- a/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c	Mon Jul 20 13:07:46 2009 -0400
@@ -30,7 +30,6 @@
  * of Solaris SMF service are displayed on the Server/Connection Manager
  * Windows client.
  */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
@@ -40,9 +39,12 @@
 #include <libscf.h>
 #include <libscf_priv.h>
 #include <time.h>
+#include <dlfcn.h>
 #include <sys/types.h>
-
-#include "svcctl_scm.h"
+#include <smbsrv/winsvc.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/ndl/svcctl.ndl>
+#include <smbsrv/libmlsvc.h>
 
 #define	LEGACY_UNKNOWN	"unknown"
 #define	SVC_NAME_PROP	"name"
@@ -51,6 +53,12 @@
 #define	EMPTY_OK	0x01
 #define	MULTI_OK	0x02
 
+static void *svcctl_scm_interposer_hdl = NULL;
+static struct {
+	int (*svcctl_op_scm_init)(svcctl_manager_context_t *);
+	int (*svcctl_op_scf_init)(svcctl_manager_context_t *);
+} svcctl_scm_ops;
+
 /*
  * svcctl_scm_avl_nodecmp
  *
@@ -659,7 +667,7 @@
  *
  * Calculates bytes needed to enumerate SMF services.
  */
-void
+static void
 svcctl_scm_bytes_needed(svcctl_manager_context_t *mgr_ctx)
 {
 	int bytes_needed = 0, svc_enum_status_size = 0;
@@ -761,6 +769,10 @@
 svcctl_scm_refresh(svcctl_manager_context_t *mgr_ctx)
 {
 	svcctl_scm_fini(mgr_ctx);
+
+	if (svcctl_scm_ops.svcctl_op_scm_init != NULL)
+		return (svcctl_scm_ops.svcctl_op_scm_init(mgr_ctx));
+
 	return (svcctl_scm_init(mgr_ctx));
 }
 
@@ -772,6 +784,10 @@
 int
 svcctl_scm_scf_handle_init(svcctl_manager_context_t *mgr_ctx)
 {
+	if (svcctl_scm_ops.svcctl_op_scf_init != NULL)
+		return (svcctl_scm_ops.
+		    svcctl_op_scf_init(mgr_ctx));
+
 	mgr_ctx->mc_scf_hdl = scf_handle_create(SCF_VERSION);
 	if (mgr_ctx->mc_scf_hdl == NULL)
 		return (-1);
@@ -810,8 +826,11 @@
 	scf_value_destroy(mgr_ctx->mc_scf_gval);
 	scf_property_destroy(mgr_ctx->mc_scf_gprop);
 	scf_pg_destroy(mgr_ctx->mc_scf_gpg);
-	(void) scf_handle_unbind(mgr_ctx->mc_scf_hdl);
-	scf_handle_destroy(mgr_ctx->mc_scf_hdl);
+
+	if (mgr_ctx->mc_scf_hdl != NULL) {
+		(void) scf_handle_unbind(mgr_ctx->mc_scf_hdl);
+		scf_handle_destroy(mgr_ctx->mc_scf_hdl);
+	}
 }
 
 /*
@@ -829,6 +848,9 @@
 	assert(mgr_ctx->mc_svcs_pool == NULL);
 	assert(mgr_ctx->mc_svcs == NULL);
 
+	if (svcctl_scm_ops.svcctl_op_scm_init != NULL)
+		return (svcctl_scm_ops.svcctl_op_scm_init(mgr_ctx));
+
 	mgr_ctx->mc_svcs_pool = uu_avl_pool_create("smf_svcs_pool",
 	    sizeof (svcctl_svc_node_t), offsetof(svcctl_svc_node_t, sn_node),
 	    svcctl_scm_avl_nodecmp, UU_AVL_DEBUG);
@@ -890,3 +912,47 @@
 	mgr_ctx->mc_svcs_pool = NULL;
 	mgr_ctx->mc_svcs = NULL;
 }
+
+/*
+ * svcctl_init
+ *
+ * Initializes the SVCCTL service.
+ * Initializes handle and ops structure to interposed library.
+ */
+void
+svcctl_init(void)
+{
+	svcctl_scm_interposer_hdl = smb_dlopen();
+	if (svcctl_scm_interposer_hdl == NULL)
+		return;
+
+	bzero((void *)&svcctl_scm_ops,
+	    sizeof (svcctl_scm_ops));
+
+	svcctl_scm_ops.svcctl_op_scm_init =
+	    (int (*)())dlsym(svcctl_scm_interposer_hdl, "svcctl_scm_init");
+
+	svcctl_scm_ops.svcctl_op_scf_init =
+	    (int (*)())dlsym(svcctl_scm_interposer_hdl,
+	    "svcctl_scm_scf_handle_init");
+
+	if (svcctl_scm_ops.svcctl_op_scm_init == NULL ||
+	    svcctl_scm_ops.svcctl_op_scf_init == NULL)
+		svcctl_fini();
+
+}
+
+/*
+ * svcctl_fini
+ *
+ * Finalizes the SVCCTL service.
+ * Closes handle to interposed library.
+ */
+void
+svcctl_fini(void)
+{
+	smb_dlclose(svcctl_scm_interposer_hdl);
+	svcctl_scm_interposer_hdl = NULL;
+	bzero((void *)&svcctl_scm_ops,
+	    sizeof (svcctl_scm_ops));
+}
--- a/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.h	Tue Jul 14 11:18:27 2009 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +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.
- */
-
-#ifndef	_SVCCTL_H
-#define	_SVCCTL_H
-
-#include <libuutil.h>
-#include <smbsrv/libsmb.h>
-#include <smbsrv/libmlrpc.h>
-#include <smbsrv/libmlsvc.h>
-#include <smbsrv/nterror.h>
-#include <smbsrv/winsvc.h>
-#include <smbsrv/ndl/svcctl.ndl>
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-/*
- * Calculate the wide-char equivalent string length required to
- * store a string - including the terminating null wide-char.
- */
-#define	SVCCTL_WNSTRLEN(S)	((strlen((S)) + 1) * sizeof (mts_wchar_t))
-
-/* An AVL-storable node representing each service in the SCM database. */
-typedef struct svcctl_svc_node {
-	uu_avl_node_t		sn_node;
-	char			*sn_name;	/* Service Name (Key) */
-	char			*sn_fmri;	/* Display Name (FMRI) */
-	char			*sn_desc;	/* Description */
-	char			*sn_state;	/* State */
-} svcctl_svc_node_t;
-
-/* This structure provides context for each svcctl_s_OpenManager call. */
-typedef struct svcctl_manager_context {
-	scf_handle_t		*mc_scf_hdl;	  /* SCF handle */
-	scf_propertygroup_t	*mc_scf_gpg;	  /* Property group */
-	scf_property_t		*mc_scf_gprop;	  /* Property */
-	scf_value_t		*mc_scf_gval;	  /* Value */
-	uint32_t		mc_scf_numsvcs;   /* Number of SMF services */
-	ssize_t			mc_scf_max_fmri_len;  /* Max FMRI length */
-	ssize_t			mc_scf_max_value_len; /* Max Value length */
-	uint32_t		mc_bytes_needed;  /* Number of bytes needed */
-	uu_avl_pool_t		*mc_svcs_pool;	  /* AVL pool */
-	uu_avl_t		*mc_svcs;	  /* AVL tree of SMF services */
-} svcctl_manager_context_t;
-
-/* This structure provides context for each svcctl_s_OpenService call. */
-typedef struct svcctl_service_context {
-	ndr_hdid_t		*sc_mgrid;	/* Manager ID */
-	char			*sc_svcname;    /* Service Name */
-} svcctl_service_context_t;
-
-typedef enum {
-	SVCCTL_MANAGER_CONTEXT = 0,
-	SVCCTL_SERVICE_CONTEXT
-} svcctl_context_type_t;
-
-/* This structure provides abstraction for service and manager context call. */
-typedef struct svcctl_context {
-	svcctl_context_type_t	c_type;
-	union {
-		svcctl_manager_context_t *uc_mgr;
-		svcctl_service_context_t *uc_svc;
-		void *uc_cp;
-	} c_ctx;
-} svcctl_context_t;
-
-/* Service Control Manager (SCM) functions */
-int svcctl_scm_init(svcctl_manager_context_t *);
-void svcctl_scm_fini(svcctl_manager_context_t *);
-int svcctl_scm_scf_handle_init(svcctl_manager_context_t *);
-void svcctl_scm_scf_handle_fini(svcctl_manager_context_t *);
-int svcctl_scm_refresh(svcctl_manager_context_t *);
-void svcctl_scm_bytes_needed(svcctl_manager_context_t *);
-uint32_t svcctl_scm_enum_services(svcctl_manager_context_t *, uint8_t *,
-    size_t, uint32_t *, boolean_t);
-uint32_t svcctl_scm_validate_service(svcctl_manager_context_t *, char *);
-svcctl_svc_node_t *svcctl_scm_find_service(svcctl_manager_context_t *, char *);
-uint32_t svcctl_scm_map_status(const char *);
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif	/* _SVCCTL_H */
--- a/usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c	Mon Jul 20 13:07:46 2009 -0400
@@ -37,7 +37,10 @@
 #include <smbsrv/ntstatus.h>
 #include <smbsrv/nmpipes.h>
 #include <smbsrv/ntifs.h>
-#include "svcctl_scm.h"
+#include <smbsrv/winsvc.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/ndl/svcctl.ndl>
+#include <smbsrv/libmlsvc.h>
 
 #define	SVCCTL_SECURITY_BUFSIZE		256
 #define	SVCCTL_ENUMSERVICES_MINBUFSIZE	1024
@@ -120,6 +123,13 @@
 svcctl_initialize(void)
 {
 	(void) ndr_svc_register(&svcctl_service);
+	svcctl_init();
+}
+
+void
+svcctl_finalize(void)
+{
+	svcctl_fini();
 }
 
 /*
--- a/usr/src/lib/smbsrv/libsmb/Makefile.com	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libsmb/Makefile.com	Mon Jul 20 13:07:46 2009 -0400
@@ -79,7 +79,7 @@
 INCS += -I$(SRC)/common/smbsrv
 
 LDLIBS +=	$(MACH_LDLIBS)
-LDLIBS +=	-lscf -lmd -lnsl -lpkcs11 -lsec -lsocket -lresolv
+LDLIBS +=	-lscf -lmd -luuid -lnsl -lpkcs11 -lsec -lsocket -lresolv
 LDLIBS +=	-lidmap -lavl -lc
 CPPFLAGS +=	$(INCS) -D_REENTRANT
 
--- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h	Mon Jul 20 13:07:46 2009 -0400
@@ -41,6 +41,7 @@
 #include <libscf.h>
 #include <libshare.h>
 #include <sqlite/sqlite.h>
+#include <uuid/uuid.h>
 
 #include <smbsrv/string.h>
 #include <smbsrv/smb_idmap.h>
@@ -65,7 +66,6 @@
 #define	SMB_CCACHE_PATH SMB_VARRUN_DIR "/" SMB_CCACHE_FILE
 
 
-
 /* Max value length of all SMB properties */
 #define	MAX_VALUE_BUFLEN	512
 
@@ -272,9 +272,6 @@
 extern int smb_chk_hostaccess(smb_inaddr_t *, char *);
 
 extern int smb_getnameinfo(smb_inaddr_t *, char *, int, int);
-extern smb_ulist_t *smb_ulist_alloc(void);
-extern void smb_ulist_free(smb_ulist_t *);
-extern void smb_ulist_cleanup(smb_ulist_t *);
 
 void smb_trace(const char *s);
 void smb_tracef(const char *fmt, ...);
@@ -848,8 +845,24 @@
 void smb_kmod_unbind(void);
 int smb_kmod_share(char *, char *);
 int smb_kmod_unshare(char *, char *);
-int smb_kmod_get_usernum(uint32_t *);
-int smb_kmod_get_userlist(smb_ulist_t *);
+int smb_kmod_get_open_num(smb_opennum_t *);
+int smb_kmod_enum(smb_netsvc_t *);
+smb_netsvc_t *smb_kmod_enum_init(smb_svcenum_t *);
+void smb_kmod_enum_fini(smb_netsvc_t *);
+int smb_kmod_session_close(const char *, const char *);
+int smb_kmod_file_close(uint32_t);
+
+/*
+ * Interposer library validation
+ */
+#define	SMBEX_VERSION	1
+#define	SMBEX_KEY	"82273fdc-e32a-18c3-3f78-827929dc23ea"
+typedef struct smbex_version {
+	uint32_t v_version;
+	uuid_t v_uuid;
+} smbex_version_t;
+void *smb_dlopen(void);
+void smb_dlclose(void *);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers	Mon Jul 20 13:07:46 2009 -0400
@@ -147,6 +147,8 @@
 	smb_ctxbuf_init;
 	smb_ctxbuf_len;
 	smb_ctxbuf_printf;
+	smb_dlclose;
+	smb_dlopen;
 	smb_dr_clnt_call;
 	smb_dr_clnt_cleanup;
 	smb_dr_clnt_setup;
@@ -219,10 +221,14 @@
 	smb_inet_iszero;
 	smb_inet_ntop;
 	smb_kmod_bind;
-        smb_kmod_get_userlist;
-        smb_kmod_get_usernum;
+	smb_kmod_enum;
+	smb_kmod_enum_init;
+	smb_kmod_enum_fini;
+	smb_kmod_file_close;
+        smb_kmod_get_open_num;
 	smb_kmod_nbtlisten;
 	smb_kmod_nbtreceive;
+	smb_kmod_session_close;
 	smb_kmod_setcfg;
 	smb_kmod_setgmtoff;
 	smb_kmod_share;
@@ -275,6 +281,12 @@
 	smb_msgbuf_term;
 	smb_msgbuf_used;
 	smb_msgbuf_word_align;
+	smb_netconnectinfo_decode;
+	smb_netconnectinfo_encode;
+	smb_netfileinfo_decode;
+	smb_netfileinfo_encode;
+	smb_netuserinfo_decode;
+	smb_netuserinfo_encode;
 	smb_nic_addhost;
 	smb_nic_delhost;
 	smb_nic_is_local;
@@ -289,9 +301,6 @@
 	smb_opipe_hdr_encode;
 	smb_opipe_hdr_decode;
 	smb_opipe_hdr_xdr;
-	smb_opipe_context_encode;
-	smb_opipe_context_decode;
-	smb_opipe_context_xdr;
 	smb_priv_getbyname;
 	smb_priv_getbyvalue;
 	smb_priv_presentable_ids;
@@ -348,8 +357,6 @@
 	smb_tonetbiosname;
 	smb_trace;
 	smb_tracef;
-	smb_ulist_alloc;
-	smb_ulist_free;
 	smb_update_netlogon_seqnum;
 	smb_wka_fini;
 	smb_wka_get_domain;
--- a/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c	Mon Jul 20 13:07:46 2009 -0400
@@ -181,83 +181,213 @@
 }
 
 int
-smb_kmod_get_usernum(uint32_t *punum)
+smb_kmod_get_open_num(smb_opennum_t *opennum)
 {
-	smb_ioc_usernum_t ioc;
+	smb_ioc_opennum_t ioc;
 	int rc;
 
-	ioc.num = 0;
-	rc = smb_kmod_ioctl(SMB_IOC_USER_NUMBER, &ioc.hdr, sizeof (ioc));
-	if (rc == 0)
-		*punum = ioc.num;
+	bzero(&ioc, sizeof (ioc));
+	ioc.qualtype = opennum->qualtype;
+	(void) strlcpy(ioc.qualifier, opennum->qualifier, MAXNAMELEN);
+
+	rc = smb_kmod_ioctl(SMB_IOC_NUMOPEN, &ioc.hdr, sizeof (ioc));
+	if (rc == 0) {
+		opennum->open_users = ioc.open_users;
+		opennum->open_trees = ioc.open_trees;
+		opennum->open_files = ioc.open_files;
+	}
+
+	return (rc);
+}
+
+/*
+ * Initialization for an smb_kmod_enum request.  If this call succeeds,
+ * smb_kmod_enum_fini() must be called later to deallocate resources.
+ */
+smb_netsvc_t *
+smb_kmod_enum_init(smb_svcenum_t *request)
+{
+	smb_netsvc_t		*ns;
+	smb_svcenum_t		*svcenum;
+	smb_ioc_svcenum_t	*ioc;
+	uint32_t		ioclen;
+
+	if ((ns = calloc(1, sizeof (smb_netsvc_t))) == NULL)
+		return (NULL);
+
+	ioclen = sizeof (smb_ioc_svcenum_t) + SMB_IOC_DATA_SIZE;
+	if ((ioc = malloc(ioclen)) == NULL) {
+		free(ns);
+		return (NULL);
+	}
+
+	bzero(ioc, ioclen);
+	svcenum = &ioc->svcenum;
+	svcenum->se_type   = request->se_type;
+	svcenum->se_level  = request->se_level;
+	svcenum->se_bavail = SMB_IOC_DATA_SIZE;
+	svcenum->se_nlimit = request->se_nlimit;
+	svcenum->se_nskip = request->se_nskip;
+	svcenum->se_buflen = SMB_IOC_DATA_SIZE;
+
+	list_create(&ns->ns_list, sizeof (smb_netsvcitem_t),
+	    offsetof(smb_netsvcitem_t, nsi_lnd));
+
+	ns->ns_ioc = ioc;
+	ns->ns_ioclen = ioclen;
+	return (ns);
+}
+
+/*
+ * Cleanup resources allocated via smb_kmod_enum_init and smb_kmod_enum.
+ */
+void
+smb_kmod_enum_fini(smb_netsvc_t *ns)
+{
+	list_t			*lst;
+	smb_netsvcitem_t	*item;
+	smb_netuserinfo_t	*user;
+	smb_netconnectinfo_t	*tree;
+	smb_netfileinfo_t	*ofile;
+	uint32_t		se_type;
+
+	if (ns == NULL)
+		return;
+
+	lst = &ns->ns_list;
+	se_type = ns->ns_ioc->svcenum.se_type;
+
+	while ((item = list_head(lst)) != NULL) {
+		list_remove(lst, item);
 
+		switch (se_type) {
+		case SMB_SVCENUM_TYPE_USER:
+			user = &item->nsi_un.nsi_user;
+			free(user->ui_domain);
+			free(user->ui_account);
+			free(user->ui_workstation);
+			break;
+		case SMB_SVCENUM_TYPE_TREE:
+			tree = &item->nsi_un.nsi_tree;
+			free(tree->ci_username);
+			free(tree->ci_share);
+			break;
+		case SMB_SVCENUM_TYPE_FILE:
+			ofile = &item->nsi_un.nsi_ofile;
+			free(ofile->fi_path);
+			free(ofile->fi_username);
+			break;
+		default:
+			break;
+		}
+	}
+
+	list_destroy(&ns->ns_list);
+	free(ns->ns_items);
+	free(ns->ns_ioc);
+	free(ns);
+}
+
+/*
+ * Enumerate users, connections or files.
+ */
+int
+smb_kmod_enum(smb_netsvc_t *ns)
+{
+	smb_ioc_svcenum_t	*ioc;
+	uint32_t		ioclen;
+	smb_svcenum_t		*svcenum;
+	smb_netsvcitem_t	*items;
+	smb_netuserinfo_t	*user;
+	smb_netconnectinfo_t	*tree;
+	smb_netfileinfo_t	*ofile;
+	uint8_t			*data;
+	uint32_t		len;
+	uint32_t		se_type;
+	uint_t			nbytes;
+	int			i;
+	int			rc;
+
+	ioc = ns->ns_ioc;
+	ioclen = ns->ns_ioclen;
+	rc = smb_kmod_ioctl(SMB_IOC_SVCENUM, &ioc->hdr, ioclen);
+	if (rc != 0)
+		return (rc);
+
+	svcenum = &ioc->svcenum;
+	items = calloc(svcenum->se_nitems, sizeof (smb_netsvcitem_t));
+	if (items == NULL)
+		return (ENOMEM);
+
+	ns->ns_items = items;
+	se_type = ns->ns_ioc->svcenum.se_type;
+	data = svcenum->se_buf;
+	len = svcenum->se_bused;
+
+	for (i = 0; i < svcenum->se_nitems; ++i) {
+		switch (se_type) {
+		case SMB_SVCENUM_TYPE_USER:
+			user = &items->nsi_un.nsi_user;
+			rc = smb_netuserinfo_decode(user, data, len, &nbytes);
+			break;
+		case SMB_SVCENUM_TYPE_TREE:
+			tree = &items->nsi_un.nsi_tree;
+			rc = smb_netconnectinfo_decode(tree, data, len,
+			    &nbytes);
+			break;
+		case SMB_SVCENUM_TYPE_FILE:
+			ofile = &items->nsi_un.nsi_ofile;
+			rc = smb_netfileinfo_decode(ofile, data, len, &nbytes);
+			break;
+		default:
+			rc = -1;
+			break;
+		}
+
+		if (rc != 0)
+			return (EINVAL);
+
+		list_insert_tail(&ns->ns_list, items);
+
+		++items;
+		data += nbytes;
+		len -= nbytes;
+	}
+
+	return (0);
+}
+
+/*
+ * A NULL pointer is a wildcard indicator, which we pass on
+ * as an empty string (by virtue of the bzero).
+ */
+int
+smb_kmod_session_close(const char *client, const char *username)
+{
+	smb_ioc_session_t ioc;
+	int rc;
+
+	bzero(&ioc, sizeof (ioc));
+
+	if (client != NULL)
+		(void) strlcpy(ioc.client, client, MAXNAMELEN);
+	if (username != NULL)
+		(void) strlcpy(ioc.username, username, MAXNAMELEN);
+
+	rc = smb_kmod_ioctl(SMB_IOC_SESSION_CLOSE, &ioc.hdr, sizeof (ioc));
 	return (rc);
 }
 
 int
-smb_kmod_get_userlist(smb_ulist_t *ulist)
+smb_kmod_file_close(uint32_t uniqid)
 {
-	smb_opipe_context_t	*ctx;
-	smb_ioc_ulist_t		*ioc;
-	uint32_t		ioc_len;
-	uint8_t			*data;
-	uint32_t		data_len;
-	uint32_t		unum;
-	int			rc;
-
-	smb_ulist_cleanup(ulist);
-
-	rc = smb_kmod_get_usernum(&unum);
-	if ((rc != 0) || (unum == 0))
-		return (rc);
-
-	ioc_len = sizeof (smb_ioc_ulist_t) + SMB_IOC_DATA_SIZE;
-	ioc = malloc(ioc_len);
-	if (ioc == NULL)
-		return (ENOMEM);
-
-	ctx = malloc(sizeof (smb_opipe_context_t) * unum);
-	if (ctx == NULL) {
-		free(ioc);
-		return (ENOMEM);
-	}
-	ulist->ul_users = ctx;
+	smb_ioc_fileid_t ioc;
+	int rc;
 
-	while (ulist->ul_cnt < unum) {
-		ioc->cookie = ulist->ul_cnt;
-		ioc->data_len = SMB_IOC_DATA_SIZE;
-		rc = smb_kmod_ioctl(SMB_IOC_USER_LIST, &ioc->hdr,
-		    ioc_len);
-		if (rc != 0)
-			break;
-
-		if ((ulist->ul_cnt + ioc->num) > unum)
-			ioc->num = unum - ulist->ul_cnt;
-
-		if (ioc->num == 0)
-			break;
+	bzero(&ioc, sizeof (ioc));
+	ioc.uniqid = uniqid;
 
-		data = ioc->data;
-		data_len = ioc->data_len;
-		while (ioc->num > 0) {
-			uint_t	bd = 0;
-
-			rc = smb_opipe_context_decode(ctx, data, data_len, &bd);
-			if (rc != 0)
-				break;
-
-			ctx++;
-			ioc->num--;
-			ulist->ul_cnt++;
-			data += bd;
-			data_len -= bd;
-		}
-	}
-
-	if (rc != 0)
-		smb_ulist_cleanup(ulist);
-
-	free(ioc);
+	rc = smb_kmod_ioctl(SMB_IOC_FILE_CLOSE, &ioc.hdr, sizeof (ioc));
 	return (rc);
 }
 
--- a/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c	Mon Jul 20 13:07:46 2009 -0400
@@ -45,8 +45,6 @@
 #define	SMB_PASSTEMP	"/var/smb/ptmp"
 #define	SMB_PASSLCK	"/var/smb/.pwd.lock"
 
-#define	SMB_LIB_ALT	"/usr/lib/smbsrv/libsmb_pwd.so"
-
 #define	SMB_PWD_DISABLE	"*DIS*"
 #define	SMB_PWD_BUFSIZE 256
 
@@ -172,11 +170,9 @@
 		smb_lucache_update();
 	}
 
-	smb_pwd_hdl = dlopen(SMB_LIB_ALT, RTLD_NOW | RTLD_LOCAL);
-	if (smb_pwd_hdl == NULL) {
-		/* No library is interposed */
+	smb_pwd_hdl = smb_dlopen();
+	if (smb_pwd_hdl == NULL)
 		return;
-	}
 
 	bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops));
 
@@ -212,7 +208,7 @@
 	    smb_pwd_ops.pwop_iteropen == NULL ||
 	    smb_pwd_ops.pwop_iterclose == NULL ||
 	    smb_pwd_ops.pwop_iterate == NULL) {
-		(void) dlclose(smb_pwd_hdl);
+		smb_dlclose(smb_pwd_hdl);
 		smb_pwd_hdl = NULL;
 
 		/* If error or function(s) are missing, use original lib */
@@ -230,11 +226,9 @@
 smb_pwd_fini(void)
 {
 	smb_lucache_destroy();
-
-	if (smb_pwd_hdl) {
-		(void) dlclose(smb_pwd_hdl);
-		smb_pwd_hdl = NULL;
-	}
+	smb_dlclose(smb_pwd_hdl);
+	smb_pwd_hdl = NULL;
+	bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops));
 }
 
 /*
--- a/usr/src/lib/smbsrv/libsmb/common/smb_util.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_util.c	Mon Jul 20 13:07:46 2009 -0400
@@ -26,6 +26,7 @@
 #include <ctype.h>
 #include <stdio.h>
 #include <string.h>
+#include <strings.h>
 #include <stdlib.h>
 #include <pthread.h>
 #include <sys/varargs.h>
@@ -37,9 +38,12 @@
 #include <sys/systeminfo.h>
 #include <sys/utsname.h>
 #include <libzfs.h>
+#include <dlfcn.h>
 #include <smbsrv/string.h>
 #include <smbsrv/libsmb.h>
 
+#define	SMB_LIB_ALT	"/usr/lib/smbsrv/libsmbex.so"
+
 static uint_t smb_make_mask(char *, uint_t);
 static boolean_t smb_netmatch(struct netbuf *, char *);
 static boolean_t smb_netgroup_match(struct nd_hostservlist *, char *, int);
@@ -755,6 +759,64 @@
 }
 
 /*
+ * smb_dlopen
+ *
+ * Check to see if an interposer library exists.  If it exists
+ * and reports a valid version number and key (UUID), return
+ * a handle to the library.  Otherwise, return NULL.
+ */
+void *
+smb_dlopen(void)
+{
+	uuid_t uuid;
+	void *interposer_hdl;
+	typedef int (*smbex_versionfn_t)(smbex_version_t *);
+	smbex_versionfn_t getversion;
+	smbex_version_t *version;
+
+	bzero(&uuid, sizeof (uuid_t));
+	if (uuid_parse(SMBEX_KEY, uuid) < 0)
+		return (NULL);
+
+	interposer_hdl = dlopen(SMB_LIB_ALT, RTLD_NOW | RTLD_LOCAL);
+	if (interposer_hdl == NULL)
+		return (NULL);
+
+	bzero(&getversion, sizeof (smbex_versionfn_t));
+	getversion = (smbex_versionfn_t)dlsym(interposer_hdl,
+	    "smbex_get_version");
+	if ((getversion == NULL) ||
+	    (version = malloc(sizeof (smbex_version_t))) == NULL) {
+		(void) dlclose(interposer_hdl);
+		return (NULL);
+	}
+	bzero(version, sizeof (smbex_version_t));
+
+	if ((getversion(version) != 0) ||
+	    (version->v_version != SMBEX_VERSION) ||
+	    (uuid_compare(version->v_uuid, uuid) != 0)) {
+		free(version);
+		(void) dlclose(interposer_hdl);
+		return (NULL);
+	}
+
+	free(version);
+	return (interposer_hdl);
+}
+
+/*
+ * smb_dlclose
+ *
+ * Closes handle to the interposed library.
+ */
+void
+smb_dlclose(void *handle)
+{
+	if (handle)
+		(void) dlclose(handle);
+}
+
+/*
  * Returns the hostname given the IP address.  Wrapper for getnameinfo.
  */
 int
@@ -782,47 +844,3 @@
 	return (getnameinfo((struct sockaddr *)sp, salen,
 	    hostname, hostlen, NULL, 0, flags));
 }
-
-smb_ulist_t *
-smb_ulist_alloc(void)
-{
-	smb_ulist_t *ulist;
-
-	ulist = malloc(sizeof (smb_ulist_t));
-	if (ulist != NULL) {
-		ulist->ul_cnt = 0;
-		ulist->ul_users = NULL;
-	}
-	return (ulist);
-}
-
-void
-smb_ulist_free(smb_ulist_t *ulist)
-{
-	if (ulist != NULL) {
-		smb_ulist_cleanup(ulist);
-		free(ulist);
-	}
-}
-
-void
-smb_ulist_cleanup(smb_ulist_t *ulist)
-{
-	smb_opipe_context_t *ctx;
-
-	if (ulist->ul_users != NULL) {
-		ctx = ulist->ul_users;
-		while (ulist->ul_cnt != 0) {
-			free(ctx->oc_domain);
-			free(ctx->oc_account);
-			free(ctx->oc_workstation);
-			ctx->oc_domain = NULL;
-			ctx->oc_account = NULL;
-			ctx->oc_workstation = NULL;
-			ulist->ul_cnt--;
-			ctx++;
-		}
-		free(ulist->ul_users);
-		ulist->ul_users = NULL;
-	}
-}
--- a/usr/src/lib/sun_fc/common/TgtFCHBAPort.cc	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/lib/sun_fc/common/TgtFCHBAPort.cc	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -401,6 +401,7 @@
 	fctio_t		fctio;
 	// fc_hba_adapter_port_stats_t	fc_port_stat;
 	uint64_t	en_portWWN;
+	uint64_t	DestPortID;
 
 	// Validate the arguments
 	if (pRspBuffer == NULL ||
@@ -417,13 +418,14 @@
 
 	/* The destWWN is either the adapter port or a discovered port. */
 	memset(&fctio, 0, sizeof (fctio));
-	fctio.fctio_cmd = FCTIO_GET_ADAPTER_PORT_STATS;
+	fctio.fctio_cmd = FCTIO_GET_LINK_STATUS;
 	fctio.fctio_ibuf = (uint64_t)(uintptr_t)&en_portWWN;
 	fctio.fctio_ilen = (uint32_t)(sizeof (en_portWWN));
 	if (portWWN != destWWN) {
 	    attrs = getDiscoveredAttributes(destWWN, tmp);
-	    fctio.fctio_abuf = (uint64_t)(uintptr_t)&attrs.PortFcId;
-	    fctio.fctio_alen = (uint32_t)(sizeof (attrs.PortFcId));
+	    DestPortID = (uint64_t)attrs.PortFcId;
+	    fctio.fctio_abuf = (uint64_t)(uintptr_t)&DestPortID;
+	    fctio.fctio_alen = (uint32_t)(sizeof (DestPortID));
 	}
 	fctio.fctio_xfer = FCTIO_XFER_READ;
 	fctio.fctio_flags = 0;
--- a/usr/src/pkgdefs/Makefile	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -159,6 +159,7 @@
 	SUNWrwn	\
 	SUNWsi3124 \
 	SUNWtpm \
+	SUNWuath \
 	SUNWural \
 	SUNWurtw \
 	SUNWvia823x \
--- a/usr/src/pkgdefs/SUNWckr/prototype_com	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/SUNWckr/prototype_com	Mon Jul 20 13:07:46 2009 -0400
@@ -150,5 +150,4 @@
 f manifest var/svc/manifest/system/fmd.xml 0444 root sys
 f manifest var/svc/manifest/system/intrd.xml 0444 root sys
 f manifest var/svc/manifest/system/scheduler.xml 0444 root sys
-d none kernel/devname 755 root sys
 d none kernel/kiconv 755 root sys
--- a/usr/src/pkgdefs/SUNWckr/prototype_i386	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/SUNWckr/prototype_i386	Mon Jul 20 13:07:46 2009 -0400
@@ -63,7 +63,6 @@
 f none kernel/crypto/sha2 755 root sys
 f none kernel/crypto/swrand 755 root sys
 f none kernel/dacf/net_dacf 755 root sys
-f none kernel/devname/sdev_nsconfig_mod 755 root sys
 f none kernel/drv/aggr 755 root sys
 f none kernel/drv/arp 755 root sys
 f none kernel/drv/acpi_drv 755 root sys
@@ -291,8 +290,6 @@
 f none kernel/crypto/amd64/swrand 755 root sys
 d none kernel/dacf/amd64 755 root sys
 f none kernel/dacf/amd64/net_dacf 755 root sys
-d none kernel/devname/amd64 755 root sys
-f none kernel/devname/amd64/sdev_nsconfig_mod 755 root sys
 d none kernel/drv/amd64 755 root sys
 f none kernel/drv/amd64/aggr 755 root sys
 f none kernel/drv/amd64/arp 755 root sys
--- a/usr/src/pkgdefs/SUNWckr/prototype_sparc	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/SUNWckr/prototype_sparc	Mon Jul 20 13:07:46 2009 -0400
@@ -262,8 +262,6 @@
 l none kernel/sys/sparcv9/rpcmod=../../../kernel/strmod/sparcv9/rpcmod
 f none kernel/sys/sparcv9/semsys 755 root sys
 f none kernel/sys/sparcv9/shmsys 755 root sys
-d none kernel/devname/sparcv9 755 root sys
-f none kernel/devname/sparcv9/sdev_nsconfig_mod 755 root sys
 d none kernel/kiconv/sparcv9 755 root sys
 f none kernel/kiconv/sparcv9/kiconv_emea 755 root sys
 f none kernel/kiconv/sparcv9/kiconv_ja 755 root sys
--- a/usr/src/pkgdefs/SUNWcslr/prototype_com	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/SUNWcslr/prototype_com	Mon Jul 20 13:07:46 2009 -0400
@@ -97,6 +97,7 @@
 f none lib/libintl.so.1 755 root bin
 s none lib/libipmp.so=./libipmp.so.1
 f none lib/libipmp.so.1 755 root bin
+f none lib/libkcfd.so.1 755 root bin
 s none lib/libkmf.so=libkmf.so.1
 f none lib/libkmf.so.1 755 root bin
 s none lib/libkmfberder.so=libkmfberder.so.1
--- a/usr/src/pkgdefs/SUNWfmd/depend	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/SUNWfmd/depend	Mon Jul 20 13:07:46 2009 -0400
@@ -34,6 +34,6 @@
 P SUNWcsd	Core Solaris Devices
 P SUNWcsl	Core Solaris Libraries
 P SUNWfmdr	Fault Management Daemon and Utilities (Root)
-P SUNWsmagt     System Management Agent files and libraries
+P SUNWnet-snmp-core     Net-SNMP Agent files and libraries
 P SUNWlxmlr     The XML library (Root)
 P SUNWzfsr      ZFS (Root)
--- a/usr/src/pkgdefs/SUNWfmdr/prototype_com	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/SUNWfmdr/prototype_com	Mon Jul 20 13:07:46 2009 -0400
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -33,11 +33,11 @@
 d none etc 755 root sys
 d none etc/fm 755 root sys
 d none etc/fm/fmd 755 root sys
-d none etc/sma 755 root bin
-d none etc/sma/snmp 755 root bin
-f none etc/sma/snmp/fmd-trapgen.conf 600 root bin
-d none etc/sma/snmp/mibs 755 root bin
-f none etc/sma/snmp/mibs/SUN-FM-MIB.mib 644 root bin
+d none etc/net-snmp 755 root bin
+d none etc/net-snmp/snmp 755 root bin
+f none etc/net-snmp/snmp/fmd-trapgen.conf 600 root bin
+d none etc/net-snmp/snmp/mibs 755 root bin
+f none etc/net-snmp/snmp/mibs/SUN-FM-MIB.mib 644 root bin
 d none kernel 755 root sys
 d none kernel/drv 755 root sys
 f none kernel/drv/fm.conf 644 root sys
--- a/usr/src/pkgdefs/SUNWhea/prototype_com	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/SUNWhea/prototype_com	Mon Jul 20 13:07:46 2009 -0400
@@ -861,7 +861,6 @@
 f none usr/include/sys/fs/cachefs_ioctl.h 644 root bin
 f none usr/include/sys/fs/decomp.h 644 root bin
 f none usr/include/sys/fs/dv_node.h 644 root bin
-f none usr/include/sys/fs/sdev_node.h 644 root bin
 f none usr/include/sys/fs/sdev_impl.h 644 root bin
 f none usr/include/sys/fs/fifonode.h 644 root bin
 f none usr/include/sys/fs/hsfs_isospec.h 644 root bin
--- a/usr/src/pkgdefs/SUNWldomr.v/prototype_sparc	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/SUNWldomr.v/prototype_sparc	Mon Jul 20 13:07:46 2009 -0400
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #
@@ -75,6 +75,7 @@
 d none platform/sun4v/kernel/misc/sparcv9 755 root sys
 f none platform/sun4v/kernel/misc/sparcv9/dr_cpu 755 root sys
 f none platform/sun4v/kernel/misc/sparcv9/dr_io 755 root sys
+f none platform/sun4v/kernel/misc/sparcv9/dr_mem 755 root sys
 f none platform/sun4v/kernel/misc/sparcv9/ds 755 root sys
 f none platform/sun4v/kernel/misc/sparcv9/fault_iso 755 root sys
 f none platform/sun4v/kernel/misc/sparcv9/ldc 755 root sys
--- a/usr/src/pkgdefs/SUNWlibsasl/pkginfo.tmpl	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/SUNWlibsasl/pkginfo.tmpl	Mon Jul 20 13:07:46 2009 -0400
@@ -1,9 +1,7 @@
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 #
 # This required package information file describes characteristics of the
@@ -11,7 +9,7 @@
 # and package architecture.
 #
 PKG="SUNWlibsasl"
-NAME="SASL v2"
+NAME="Simple Authentication and Security Layer (SASL) v2 shared library and plugins"
 ARCH="ISA"
 VERSION="ONVERS,REV=0.0.0"
 SUNW_PRODNAME="SunOS"
@@ -19,7 +17,7 @@
 SUNW_PKGTYPE="usr"
 MAXINST="1000"
 CATEGORY="system"
-DESC="Simple Authentication and Security Layer shared library and plugins"
+DESC="Simple Authentication and Security Layer (SASL) v2 shared library and plugins"
 VENDOR="Sun Microsystems, Inc."
 HOTLINE="Please contact your local service provider"
 EMAIL=""
--- a/usr/src/pkgdefs/SUNWmdb/prototype_i386	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/SUNWmdb/prototype_i386	Mon Jul 20 13:07:46 2009 -0400
@@ -82,6 +82,7 @@
 f none usr/lib/mdb/kvm/amd64/ptm.so 555 root sys
 f none usr/lib/mdb/kvm/amd64/random.so 555 root sys
 f none usr/lib/mdb/kvm/amd64/s1394.so 555 root sys
+f none usr/lib/mdb/kvm/amd64/sata.so 555 root sys
 f none usr/lib/mdb/kvm/amd64/scsi_vhci.so 555 root sys
 f none usr/lib/mdb/kvm/amd64/sctp.so 555 root sys
 f none usr/lib/mdb/kvm/amd64/sd.so 555 root sys
@@ -117,6 +118,7 @@
 f none usr/lib/mdb/kvm/ptm.so 555 root sys
 f none usr/lib/mdb/kvm/random.so 555 root sys
 f none usr/lib/mdb/kvm/s1394.so 555 root sys
+f none usr/lib/mdb/kvm/sata.so 555 root sys
 f none usr/lib/mdb/kvm/scsi_vhci.so 555 root sys
 f none usr/lib/mdb/kvm/sctp.so 555 root sys
 f none usr/lib/mdb/kvm/sd.so 555 root sys
--- a/usr/src/pkgdefs/SUNWmdbr/prototype_i386	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/SUNWmdbr/prototype_i386	Mon Jul 20 13:07:46 2009 -0400
@@ -51,6 +51,7 @@
 f none kernel/kmdb/amd64/ptm 555 root sys
 f none kernel/kmdb/amd64/random 555 root sys
 f none kernel/kmdb/amd64/s1394 555 root sys
+f none kernel/kmdb/amd64/sata 555 root sys
 f none kernel/kmdb/amd64/scsi_vhci 555 root sys
 f none kernel/kmdb/amd64/sctp 555 root sys
 f none kernel/kmdb/amd64/sd 555 root sys
@@ -85,6 +86,7 @@
 f none kernel/kmdb/ptm 555 root sys
 f none kernel/kmdb/random 555 root sys
 f none kernel/kmdb/s1394 555 root sys
+f none kernel/kmdb/sata 555 root sys
 f none kernel/kmdb/scsi_vhci 555 root sys
 f none kernel/kmdb/sctp 555 root sys
 f none kernel/kmdb/sd 555 root sys
--- a/usr/src/pkgdefs/SUNWpcu/prototype_com	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/SUNWpcu/prototype_com	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # This required package information file contains a list of package contents.
@@ -46,7 +46,7 @@
 f none usr/bin/lpset 4511 root lp
 f none usr/bin/lptest 555 root lp
 s none usr/bin/desktop-print-management=../sbin/print-service
-s none usr/bin/desktop-print-management-applet=../sbin/print-service
+f none usr/bin/desktop-print-management-applet 0555 root bin
 s none usr/bin/desktop-print-management-prefs=../sbin/print-service
 d none usr/lib 0755 root bin
 d none usr/lib/lp 0755 root lp
--- a/usr/src/pkgdefs/SUNWsacom/Makefile	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/SUNWsacom/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -20,10 +20,9 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
 #
 
 include ../Makefile.com
@@ -36,7 +35,7 @@
 	( chmod 666 depend; \
 	echo "P SUNWmibii     Solstice Enterprise Agents SNMP daemon" >> depend; \
 	echo "P SUNWsasnm     Solstice Enterprise Agents Simple Network Management Protocol" >> depend; \
-	echo "P SUNWsmmgr     System Management Agent Startup scripts" >> depend; \
+	echo "P SUNWnet-snmp-mgr     Net-SNMP Agent configuration files and Startup scripts" >> depend; \
 	echo "P SUNWlibC      SPARCompilers Bundled libC" >> depend; \
 	chmod 444 depend )
 
--- a/usr/src/pkgdefs/SUNWstmfu/Makefile	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/SUNWstmfu/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -27,8 +27,6 @@
 
 .KEEP_STATE:
 
-DATAFILES += depend
-
 all: $(FILES)
 install: all pkg
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWstmfu/depend	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,50 @@
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# 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
+#
+# This package information file defines software dependencies associated
+# with the pkg.  You can define three types of pkg dependencies with this file:
+#	 P indicates a prerequisite for installation
+#	 I indicates an incompatible package
+#	 R indicates a reverse dependency
+# <pkg.abbr> see pkginfo(4), PKG parameter
+# <name> see pkginfo(4), NAME parameter
+# <version> see pkginfo(4), VERSION parameter
+# <arch> see pkginfo(4), ARCH parameter
+# <type> <pkg.abbr> <name>
+# 	(<arch>)<version>
+# 	(<arch>)<version>
+# 	...
+# <type> <pkg.abbr> <name>
+# ...
+#
+
+P SUNWcar	Core Architecture, (Root)
+P SUNWcakr	Core Solaris Kernel Architecture (Root)
+P SUNWkvm	Core Architecture, (Kvm)
+P SUNWcsr	Core Solaris, (Root)
+P SUNWckr	Core Solaris Kernel (Root)
+P SUNWcnetr	Core Solaris Network Infrastructure (Root)
+P SUNWcsu	Core Solaris, (Usr)
+P SUNWcsd	Core Solaris Devices
+P SUNWcsl	Core Solaris Libraries
+P SUNWlibmsr	Math & Microtasking Libraries (Root)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWuath/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,38 @@
+#
+# 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 ../Makefile.com
+
+LICENSEFILES = \
+	../../uts/common/io/uath/THIRDPARTYLICENSE \
+	../../uts/common/io/uath/uath_fw/LICENSE
+CDDL =
+
+.KEEP_STATE:
+
+all: $(FILES) depend postinstall postremove
+install: all pkg
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWuath/depend	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,50 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# This package information file defines software dependencies associated
+# with the pkg.  You can define three types of pkg dependencies with this file:
+#	 P indicates a prerequisite for installation
+#	 I indicates an incompatible package
+#	 R indicates a reverse dependency
+# <pkg.abbr> see pkginfo(4), PKG parameter
+# <name> see pkginfo(4), NAME parameter
+# <version> see pkginfo(4), VERSION parameter
+# <arch> see pkginfo(4), ARCH parameter
+# <type> <pkg.abbr> <name>
+# 	(<arch>)<version>
+# 	(<arch>)<version>
+# 	...
+# <type> <pkg.abbr> <name>
+# ...
+
+P SUNWcar	Core Architecture, (Root)
+P SUNWcakr	Core Solaris Kernel Architecture (Root)
+P SUNWkvm	Core Architecture, (Kvm)
+P SUNWcsr	Core Solaris, (Root)
+P SUNWckr	Core Solaris Kernel (Root)
+P SUNWcnetr	Core Solaris Network Infrastructure (Root)
+P SUNWcsu	Core Solaris, (Usr)
+P SUNWcsd	Core Solaris Devices
+P SUNWcsl	Core Solaris Libraries
+P SUNWusb	USB Device Drivers
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWuath/pkginfo.tmpl	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+#
+
+PKG="SUNWuath"
+NAME="Atheros AR5523 USB IEEE802.11b/g Wireless Network Driver"
+ARCH="ISA"
+VERSION="ONVERS,REV=0.0.0"
+SUNW_PRODNAME="SunOS"
+SUNW_PRODVERS="RELEASE/VERSION"
+SUNW_PKGVERS="1.0"
+SUNW_PKGTYPE="root"
+MAXINST="1000"
+CATEGORY="system"
+VENDOR="Sun Microsystems, Inc."
+DESC="Atheros AR5523 USB IEEE802.11b/g Wireless Network Driver"
+CLASSES="none"
+HOTLINE="Please contact your local service provider"
+EMAIL=""
+BASEDIR=/
+SUNW_PKG_ALLZONES="true"
+SUNW_PKG_HOLLOW="true"
+SUNW_PKG_THISZONE="false"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWuath/postinstall	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,91 @@
+#! /usr/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+# Driver info
+DRV=uath
+DRVALIAS='"usbcf3,2" "usbcf3,3" "usb1385,4251" "usb1385,4252"'
+
+BASEDIR=${BASEDIR:-/}
+
+# Function: check_add_drv()
+#
+# This function will check if add_drv has been executed.
+# If not simply calls add_drv. Otherwise adds entries to
+# driver_aliases, driver_classes and minor_perm if necessary.
+# The syntax of this function is the same as add_drv. 
+
+check_add_drv()
+{
+	CMD="add_drv"
+
+	ALIAS=""
+	ALIASDIR="${BASEDIR}"/etc/driver_aliases
+	while getopts i:b: opt 2>/dev/null; do
+		case "$opt" in
+		i)	CMD="${CMD} -i ${OPTARG}"
+			ALIAS=`echo ${OPTARG} | /usr/bin/sed -e "s/'//g"`
+			;;
+		b)	if [ "${OPTARG}" != "/" ]; then
+				# On a client
+				# modify the sytem files and touch
+				# /reconfigure for reconfigure reboot
+				CMD="${CMD} -b \"${OPTARG}\""
+			fi
+			;;
+		\?)	echo "check_add_drv(): Unknown option $opt"
+			return
+			;;
+		esac
+	done
+	shift `/usr/bin/expr ${OPTIND} - 1`
+	DRIVER=$1
+	CMD="${CMD} ${DRIVER}"
+
+	# Make sure add_drv has not been previously executed
+	# before attempting to add the driver
+	/usr/bin/egrep -s "^${DRIVER}[ 	]" "$BASEDIR"/etc/name_to_major
+
+	if [ $? -ne 0 ]; then
+		eval ${CMD}
+		if [ $? -ne 0 ]; then
+			echo "Failed add_drv ${DRIVER}!\n" >&2
+			exit 1
+		fi
+	else
+		# Add driver entry if necessary
+		if [ -n "${ALIAS}" ]; then
+			for i in ${ALIAS}; do
+				/usr/bin/egrep -s "^${DRIVER}[ 	]+$i" ${ALIASDIR}
+				if [ $? -ne 0 ]; then
+					echo "${DRIVER} $i" >> ${ALIASDIR}
+				fi
+			done
+		fi
+	fi
+}
+
+check_add_drv -b "${BASEDIR}" -i "'${DRVALIAS}'" ${DRV}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWuath/postremove	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,39 @@
+#! /usr/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+DRV=uath
+BD=${BASEDIR:-/}
+if grep -w $DRV $BD/etc/name_to_major > /dev/null 2>&1
+then
+        rem_drv -b ${BD} $DRV
+        if [ $? -ne 0 ]
+        then
+                exit 1
+        fi
+fi
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWuath/prototype_com	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,46 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+#!search <pathname pathname ...>        # where to find pkg objects
+#!include <filename>                    # include another 'prototype' file
+#!default <mode> <owner> <group>        # default used if not specified on entry
+#!<param>=<value>                       # puts parameter in pkg environment
+
+#
+# SUNWuath
+#
+
+i pkginfo
+i copyright
+i depend
+i postinstall
+i postremove
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWuath/prototype_i386	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,55 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+#!search <pathname pathname ...>        # where to find pkg objects
+#!include <filename>                    # include another 'prototype' file
+#!default <mode> <owner> <group>        # default used if not specified on entry
+#!<param>=<value>                       # puts parameter in pkg environment
+
+#
+# SUNWuath
+#
+
+# Include ISA independent files (prototype_com)
+#
+!include prototype_com
+
+# uath ieee80211a/b/g wifi driver
+d none kernel 0755 root sys
+d none kernel/drv 0755 root sys
+f none kernel/drv/uath 0755 root sys
+d none kernel/misc 0755 root sys
+f none kernel/misc/uathfw 0755 root sys
+d none kernel/drv/amd64 0755 root sys
+f none kernel/drv/amd64/uath 0755 root sys
+d none kernel/misc/amd64 0755 root sys
+f none kernel/misc/amd64/uathfw 0755 root sys
--- a/usr/src/pkgdefs/common_files/i.minorperm_i386	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/common_files/i.minorperm_i386	Mon Jul 20 13:07:46 2009 -0400
@@ -123,6 +123,7 @@
 clone:rum		0600 root sys 0666 root sys	/dev/rum
 clone:rwd		0600 root sys 0666 root sys	/dev/rwd
 clone:rwn		0600 root sys 0666 root sys	/dev/rwn
+clone:uath		0600 root sys 0666 root sys	/dev/uath
 clone:ural		0600 root sys 0666 root sys	/dev/ural
 clone:urtw		0600 root sys 0666 root sys	/dev/urtw
 clone:wpi		0600 root sys 0666 root sys	/dev/wpi
@@ -154,6 +155,7 @@
 rum:*			0600 root sys 0666 root sys	/dev/rum*
 rwd:*			0600 root sys 0666 root sys	/dev/rwd*
 rwn:*			0600 root sys 0666 root sys	/dev/rwn*
+uath:*			0600 root sys 0666 root sys	/dev/uath*
 ural:*			0600 root sys 0666 root sys	/dev/ural*
 urtw:*			0600 root sys 0666 root sys	/dev/urtw*
 wpi:*			0600 root sys 0666 root sys	/dev/wpi*
@@ -312,6 +314,7 @@
 clone:rum
 clone:rwd
 clone:rwn
+clone:uath
 clone:ural
 clone:urtw
 clone:wpi
@@ -343,6 +346,7 @@
 rum:*
 rwd:*
 rwn:*
+uath:*
 ural:*
 urtw:*
 wpi:*
--- a/usr/src/pkgdefs/etc/exception_list_i386	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/etc/exception_list_i386	Mon Jul 20 13:07:46 2009 -0400
@@ -67,6 +67,9 @@
 usr/lib/llib-lsoftcrypto		i386
 usr/lib/llib-lsoftcrypto.ln		i386
 usr/lib/amd64/llib-lsoftcrypto.ln	i386
+lib/llib-lkcfd				i386
+lib/llib-lkcfd.ln			i386
+lib/libkcfd.so				i386
 #
 # The following files are used by the DHCP service, the
 # standalone's DHCP implementation, and the kernel (nfs_dlboot).
@@ -1256,3 +1259,6 @@
 # Private idmap RPC protocol
 usr/include/rpcsvc/idmap_prot.h		i386
 usr/include/rpcsvc/idmap_prot.x		i386
+
+# Private idmap directory API
+usr/include/directory.h			i386
--- a/usr/src/pkgdefs/etc/exception_list_sparc	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/pkgdefs/etc/exception_list_sparc	Mon Jul 20 13:07:46 2009 -0400
@@ -56,6 +56,9 @@
 usr/lib/llib-lsoftcrypto		sparc
 usr/lib/llib-lsoftcrypto.ln		sparc
 usr/lib/sparcv9/llib-lsoftcrypto.ln	sparc
+lib/llib-lkcfd.ln			sparc
+lib/llib-lkcfd				sparc
+lib/libkcfd.so				sparc
 #
 # The following files are used by libdhcpsvc, the
 # standalone's DHCP implementation, and the kernel (nfs_dlboot).
@@ -1355,3 +1358,6 @@
 # Private idmap RPC protocol
 usr/include/rpcsvc/idmap_prot.h		sparc
 usr/include/rpcsvc/idmap_prot.x		sparc
+
+# Private idmap directory API
+usr/include/directory.h			sparc
--- a/usr/src/tools/elfsign/Makefile	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/tools/elfsign/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -20,9 +20,7 @@
 #
 
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -53,17 +51,6 @@
 CPPFLAGS +=	-I$(SRC)/lib/libcryptoutil/common
 LDFLAGS +=	-L/lib -lmd -lelf -lkmf -lcryptoutil -lc
 
-#
-# While the gate builds a libelfsign.so linked staticly against
-# pksc11_softtoken, the tools version of libelfsign is dynamically linked
-# against the build machines pkcs11_softtoken.so.
-#
-SOFTTOKENDIR =	/usr/lib/security
-SOFTTOKENLIB =	pkcs11_softtoken.so
-LDFLAGS +=	-R $(SOFTTOKENDIR) $(SOFTTOKENDIR)/$(SOFTTOKENLIB)
-
-MKDIR=	mkdir
-
 .KEEP_STATE:
 
 all:	$(PROG) $(SHFILES)
--- a/usr/src/tools/opensolaris/license-list	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/tools/opensolaris/license-list	Mon Jul 20 13:07:46 2009 -0400
@@ -168,6 +168,8 @@
 usr/src/uts/common/io/rwn/THIRDPARTYLICENSE
 usr/src/uts/common/io/rwn/fw-rt2860/LICENSE
 usr/src/uts/common/io/sfe/THIRDPARTYLICENSE
+usr/src/uts/common/io/uath/THIRDPARTYLICENSE
+usr/src/uts/common/io/uath/uath_fw/LICENSE
 usr/src/uts/common/io/ural/THIRDPARTYLICENSE
 usr/src/uts/common/io/urtw/THIRDPARTYLICENSE
 usr/src/uts/common/io/usb/clients/hwa1480_fw/i1480/LICENSE
--- a/usr/src/tools/scripts/bfu.sh	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/tools/scripts/bfu.sh	Mon Jul 20 13:07:46 2009 -0400
@@ -6053,6 +6053,8 @@
 
 	find $root/kernel/drv -name zvol 2> /dev/null | xargs rm -f
 	rm -f $root/kernel/drv/zvol.conf
+	rm -rf $root/kernel/devname
+	rm -f $usr/include/sys/fs/sdev_node.h
 
 	#
 	# Remove /usr/lib/old_libthread since support for it has
--- a/usr/src/tools/scripts/check_rtime.pl	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/tools/scripts/check_rtime.pl	Mon Jul 20 13:07:46 2009 -0400
@@ -182,7 +182,7 @@
 	/usr/sfw/lib.*\ from\ .*libgthread-2\.0\.so\.0 |	# non-OSNet
 	/usr/X11/lib.*\ from\ .*libgthread-2\.0\.so\.0 |	# non-OSNet
 	/usr/sfw/lib.*\ from\ .*libcrypto\.so\.0\.9\.8 |	# non-OSNet
-	/usr/sfw/lib.*\ from\ .*libnetsnmp\.so\.5 |		# non-OSNet
+	/usr/sfw/lib.*\ from\ .*libnetsnmp\.so\.15 |		# non-OSNet
 	/usr/sfw/lib.*\ from\ .*libgcc_s\.so\.1 |		# non-OSNet
 	/usr.*\ from\ .*tst\.gcc\.exe |				# gcc built
 	/usr/postgres/8.3/lib.*\ from\ .*libpq\.so\.5 |		# non-OSNET
@@ -197,10 +197,10 @@
 	/lib.*\ of\ .*/lib/picl/plugins/ |			# picl
 	/lib.*\ of\ .*libcimapi\.so |				# non-OSNET
 	/lib.*\ of\ .*libjvm\.so |				# non-OSNET
-	/lib.*\ of\ .*libnetsnmp\.so\.5 |			# non-OSNET
-	/lib.*\ of\ .*libnetsnmpagent\.so\.5 |			# non-OSNET
-	/lib.*\ of\ .*libnetsnmpmibs\.so\.5 |			# non-OSNET
-	/lib.*\ of\ .*libnetsnmphelpers\.so\.5 |		# non-OSNET
+	/lib.*\ of\ .*libnetsnmp\.so\.15 |			# non-OSNET
+	/lib.*\ of\ .*libnetsnmpagent\.so\.15 |			# non-OSNET
+	/lib.*\ of\ .*libnetsnmpmibs\.so\.15 |			# non-OSNET
+	/lib.*\ of\ .*libnetsnmphelpers\.so\.15 |		# non-OSNET
 	/lib.*\ of\ .*libnspr4\.so |				# non-OSNET
 	/lib.*\ of\ .*libsoftokn3\.so |				# non-OSNET
 	/lib.*\ of\ .*libspmicommon\.so\.1 |			# non-OSNET
@@ -209,7 +209,9 @@
 	/lib.*\ of\ .*libxml2\.so\.2 |				# non-OSNET
 	/lib.*\ of\ .*libxslt\.so\.1 |				# non-OSNET
 	/lib.*\ of\ .*libpq\.so\.4 |				# non-OSNET
-	/lib.*\ of\ .*libpython2\.4\.so\.1\.0 			# non-OSNET
+	/lib.*\ of\ .*libpython2\.4\.so\.1\.0 |			# non-OSNET
+	/lib.*\ of\ .*kcfd |					# interposer
+	/libpkcs11\.so\.1;\.*\ of\ .*libkmf\.so\.1		# interposed
 }x;
 
 # Define any files that should only have unused (ldd -u) processing.
--- a/usr/src/uts/Makefile.targ	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/Makefile.targ	Mon Jul 20 13:07:46 2009 -0400
@@ -207,9 +207,6 @@
 $(ROOT_MAC_DIR)/%:	$(OBJS_DIR)/% $(ROOT_MOD_DIR) $(ROOT_MAC_DIR) FRC
 	$(INS.file)
 
-$(ROOT_DEVNAME_DIR)/%:	$(OBJS_DIR)/% $(ROOT_DEVNAME_DIR) FRC
-	$(INS.file)
-
 $(USR_DRV_DIR)/%:	$(OBJS_DIR)/% $(USR_DRV_DIR) FRC
 	$(INS.file)
 
@@ -237,9 +234,6 @@
 $(USR_PCBE_DIR)/%:	$(OBJS_DIR)/% $(USR_PCBE_DIR) FRC
 	$(INS.file)
 
-$(USR_DEVNAME_DIR)/%:	$(OBJS_DIR)/% $(USR_DEVNAME_DIR) FRC
-	$(INS.file)
-
 $(USR_DTRACE_DIR)/%:	$(OBJS_DIR)/% $(USR_DTRACE_DIR) FRC
 	$(INS.file)
 
--- a/usr/src/uts/Makefile.uts	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/Makefile.uts	Mon Jul 20 13:07:46 2009 -0400
@@ -462,7 +462,6 @@
 ROOT_DACF_DIR_32	= $(ROOT_MOD_DIR)/dacf
 ROOT_CRYPTO_DIR_32	= $(ROOT_MOD_DIR)/crypto
 ROOT_MAC_DIR_32		= $(ROOT_MOD_DIR)/mac
-ROOT_DEVNAME_DIR_32	= $(ROOT_MOD_DIR)/devname
 ROOT_KICONV_DIR_32	= $(ROOT_MOD_DIR)/kiconv
 
 ROOT_KERN_DIR_64	= $(ROOT_MOD_DIR)/$(SUBDIR64)
@@ -489,7 +488,6 @@
 ROOT_DACF_DIR_64	= $(ROOT_MOD_DIR)/dacf/$(SUBDIR64)
 ROOT_CRYPTO_DIR_64	= $(ROOT_MOD_DIR)/crypto/$(SUBDIR64)
 ROOT_MAC_DIR_64		= $(ROOT_MOD_DIR)/mac/$(SUBDIR64)
-ROOT_DEVNAME_DIR_64	= $(ROOT_MOD_DIR)/devname/$(SUBDIR64)
 ROOT_KICONV_DIR_64	= $(ROOT_MOD_DIR)/kiconv/$(SUBDIR64)
 
 ROOT_KERN_DIR		= $(ROOT_KERN_DIR_$(CLASS))
@@ -516,7 +514,6 @@
 ROOT_DACF_DIR		= $(ROOT_DACF_DIR_$(CLASS))
 ROOT_CRYPTO_DIR		= $(ROOT_CRYPTO_DIR_$(CLASS))
 ROOT_MAC_DIR		= $(ROOT_MAC_DIR_$(CLASS))
-ROOT_DEVNAME_DIR	= $(ROOT_DEVNAME_DIR_$(CLASS))
 ROOT_KICONV_DIR		= $(ROOT_KICONV_DIR_$(CLASS))
 
 ROOT_MOD_DIRS_32	= $(ROOT_BRAND_DIR_32) $(ROOT_DRV_DIR_32)
@@ -533,7 +530,7 @@
 ROOT_MOD_DIRS_32	+= $(ROOT_CPU_DIR_32) $(ROOT_FONT_DIR_32)
 ROOT_MOD_DIRS_32	+= $(ROOT_TOD_DIR_32) $(ROOT_DACF_DIR_32)
 ROOT_MOD_DIRS_32	+= $(ROOT_CRYPTO_DIR_32) $(ROOT_MAC_DIR_32)
-ROOT_MOD_DIRS_32	+= $(ROOT_DEVNAME_DIR_32) $(ROOT_KICONV_DIR_32)
+ROOT_MOD_DIRS_32	+= $(ROOT_KICONV_DIR_32)
 
 USR_MOD_DIR		= $(ROOT)/usr/kernel
 
@@ -547,7 +544,6 @@
 USR_MISC_DIR_32		= $(USR_MOD_DIR)/misc
 USR_DACF_DIR_32		= $(USR_MOD_DIR)/dacf
 USR_PCBE_DIR_32		= $(USR_MOD_DIR)/pcbe
-USR_DEVNAME_DIR_32	= $(USR_MOD_DIR)/devname
 USR_DTRACE_DIR_32	= $(USR_MOD_DIR)/dtrace
 USR_BRAND_DIR_32	= $(USR_MOD_DIR)/brand
 
@@ -561,7 +557,6 @@
 USR_MISC_DIR_64		= $(USR_MOD_DIR)/misc/$(SUBDIR64)
 USR_DACF_DIR_64		= $(USR_MOD_DIR)/dacf/$(SUBDIR64)
 USR_PCBE_DIR_64		= $(USR_MOD_DIR)/pcbe/$(SUBDIR64)
-USR_DEVNAME_DIR_64	= $(USR_MOD_DIR)/devname/$(SUBDIR64)
 USR_DTRACE_DIR_64	= $(USR_MOD_DIR)/dtrace/$(SUBDIR64)
 USR_BRAND_DIR_64	= $(USR_MOD_DIR)/brand/$(SUBDIR64)
 
@@ -575,7 +570,6 @@
 USR_MISC_DIR		= $(USR_MISC_DIR_$(CLASS))
 USR_DACF_DIR		= $(USR_DACF_DIR_$(CLASS))
 USR_PCBE_DIR		= $(USR_PCBE_DIR_$(CLASS))
-USR_DEVNAME_DIR		= $(USR_DEVNAME_DIR_$(CLASS))
 USR_DTRACE_DIR		= $(USR_DTRACE_DIR_$(CLASS))
 USR_BRAND_DIR		= $(USR_BRAND_DIR_$(CLASS))
 
@@ -583,7 +577,7 @@
 USR_MOD_DIRS_32		+= $(USR_FS_DIR_32) $(USR_SCHED_DIR_32)
 USR_MOD_DIRS_32		+= $(USR_STRMOD_DIR_32) $(USR_SYS_DIR_32)
 USR_MOD_DIRS_32		+= $(USR_MISC_DIR_32) $(USR_DACF_DIR_32)
-USR_MOD_DIRS_32		+= $(USR_PCBE_DIR_32) $(USR_DEVNAME_DIR_32)
+USR_MOD_DIRS_32		+= $(USR_PCBE_DIR_32)
 USR_MOD_DIRS_32		+= $(USR_DTRACE_DIR_32) $(USR_BRAND_DIR_32)
 
 #
@@ -635,7 +629,7 @@
 		 $(MMU_KMODS) $(DACF_KMODS) $(EXPORT_KMODS) $(IPP_KMODS) \
 		 $(CRYPTO_KMODS) $(PCBE_KMODS) \
 		 $(DRV_KMODS_$(CLASS)) $(MISC_KMODS_$(CLASS)) $(MAC_KMODS) \
-		 $(DEVNAME_KMODS) $(BRAND_KMODS) $(KICONV_KMODS) \
+		 $(BRAND_KMODS) $(KICONV_KMODS) \
 		 $(SOCKET_KMODS)
 
 KMODS = $(GENUNIX_KMODS) $(PARALLEL_KMODS)
@@ -649,7 +643,7 @@
 LINT_KMODS = $(DRV_KMODS) $(EXEC_KMODS) $(FS_KMODS) $(SCHED_KMODS) \
 	  $(TOD_KMODS) $(STRMOD_KMODS) $(SYS_KMODS) $(MISC_KMODS) \
 	  $(MACH_KMODS) $(GSS_KMODS) $(DACF_KMODS) $(IPP_KMODS) \
-	  $(CRYPTO_KMODS) $(PCBE_KMODS) $(DEVNAME_KMODS) \
+	  $(CRYPTO_KMODS) $(PCBE_KMODS) \
 	  $(DRV_KMODS_$(CLASS)) $(MISC_KMODS_$(CLASS)) $(MAC_KMODS) \
 	  $(BRAND_KMODS) $(KICONV_KMODS) $(SOCKET_KMODS)
 
--- a/usr/src/uts/common/Makefile.files	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/Makefile.files	Mon Jul 20 13:07:46 2009 -0400
@@ -1005,8 +1005,6 @@
 
 SI3124_OBJS += si3124.o
 
-NSCONFIG_DEVNAME_OBJS += sdev_nsconfig_mod.o
-
 AHCI_OBJS += ahci.o
 
 PCIIDE_OBJS += pci-ide.o
@@ -1733,6 +1731,10 @@
 
 RWN_OBJS += rt2860.o
 
+UATH_OBJS += uath.o
+
+UATHFW_OBJS += uathfw_mod.o
+
 URAL_OBJS += ural.o
 
 RTW_OBJS += rtw.o smc93cx6.o rtwphy.o rtwphyio.o
--- a/usr/src/uts/common/Makefile.rules	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/Makefile.rules	Mon Jul 20 13:07:46 2009 -0400
@@ -1003,6 +1003,14 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/uath/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/uath/uath_fw/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:                $(UTSBASE)/common/io/ural/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -2121,6 +2129,12 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/softmac/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/uath/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/uath/uath_fw/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:              $(UTSBASE)/common/io/ural/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- a/usr/src/uts/common/dtrace/sdt_subr.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/dtrace/sdt_subr.c	Mon Jul 20 13:07:46 2009 -0400
@@ -1085,6 +1085,15 @@
 	    "fc_port_info_t *" },
 	{ "fc", "xfer-done", 4, 4, "stmf_data_buf_t *",
 	    "fc_xferinfo_t *" },
+	{ "fc", "rscn-receive", 0, 0, "fct_i_local_port_t *",
+	    "conninfo_t *" },
+	{ "fc", "rscn-receive", 1, 1, "int", "int"},
+	{ "fc", "abts-receive", 0, 0, "fct_cmd_t *",
+	    "conninfo_t *" },
+	{ "fc", "abts-receive", 1, 1, "fct_i_local_port_t *",
+	    "fc_port_info_t *" },
+	{ "fc", "abts-receive", 2, 2, "fct_i_remote_port_t *",
+	    "fc_port_info_t *" },
 
 
 	{ NULL }
--- a/usr/src/uts/common/fs/dev/sdev_comm.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/dev/sdev_comm.c	Mon Jul 20 13:07:46 2009 -0400
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * routines to invoke user level name lookup services
  */
@@ -59,7 +57,6 @@
 #include <sys/fs/snode.h>
 #include <sys/fs/dv_node.h>
 #include <sys/fs/sdev_impl.h>
-#include <sys/fs/sdev_node.h>
 #include <sys/sunndi.h>
 #include <sys/sunddi.h>
 #include <sys/sunmdi.h>
@@ -77,7 +74,6 @@
 static kmutex_t devfsadm_lock;
 static kcondvar_t devfsadm_cv;
 
-int devname_nsmaps_loaded = 0;
 static int dev_node_wait_timeout = DEV_NODE_WAIT_TIMEOUT;
 static int dev_devfsadm_startup =  DEV_DEVFSADM_STARTUP;
 
@@ -89,19 +85,9 @@
 static int		sdev_upcall_door_revoked = 0;
 static int		sdev_door_upcall_filename_size;
 
-static void sdev_devfsadmd_nsrdr(sdev_nsrdr_work_t *);
 static int sdev_devfsadm_revoked(void);
 static int sdev_ki_call_devfsadmd(sdev_door_arg_t *, sdev_door_res_t *);
 
-/*
- * nsmap_readdir processing thread
- */
-static uint_t			sdev_nsrdr_thread_created = 0;
-static kmutex_t			sdev_nsrdr_thread_lock;
-static kcondvar_t		sdev_nsrdr_thread_cv;
-static sdev_nsrdr_work_t	*sdev_nsrdr_thread_workq = NULL;
-static sdev_nsrdr_work_t	*sdev_nsrdr_thread_tail = NULL;
-
 void
 sdev_devfsadm_lockinit(void)
 {
@@ -164,7 +150,7 @@
 			} else if ((rv == -1) &&
 			    (ddi_get_lbolt() >= expire)) {
 				sdcmn_err6(("%s: wait time is up\n",
-					dv->sdev_name));
+				    dv->sdev_name));
 				break;
 			}
 			sdcmn_err6(("%s: wait "
@@ -463,16 +449,13 @@
 }
 
 int
-devname_filename_register(int cmd, char *name)
+devname_filename_register(char *name)
 {
 	int error = 0;
 	char *strbuf;
 	char *namep;
 	int n;
 
-	ASSERT(cmd == MODDEVNAME_LOOKUPDOOR ||
-	    cmd == MODDEVNAME_DEVFSADMNODE);
-
 	strbuf = kmem_zalloc(MOD_MAXPATH, KM_SLEEP);
 
 	if (copyinstr(name, strbuf, MOD_MAXPATH, 0)) {
@@ -480,272 +463,20 @@
 		error = EFAULT;
 	} else {
 		sdcmn_err6(("file %s is registering\n", strbuf));
-		switch (cmd) {
-		case MODDEVNAME_LOOKUPDOOR:
-			/* handling the daemon re-start situations */
-			n = strlen(strbuf) + 1;
-			namep = i_ddi_strdup(strbuf, KM_SLEEP);
-			mutex_enter(&devfsadm_lock);
-			sdev_release_door();
-			sdev_door_upcall_filename_size = n;
-			sdev_door_upcall_filename = namep;
-			sdcmn_err6(("size %d file name %s\n",
-			    sdev_door_upcall_filename_size,
-			    sdev_door_upcall_filename));
-			cv_broadcast(&devfsadm_cv);
-			mutex_exit(&devfsadm_lock);
-			break;
-		case MODDEVNAME_DEVFSADMNODE:
-			break;
-		}
+		/* handling the daemon re-start situations */
+		n = strlen(strbuf) + 1;
+		namep = i_ddi_strdup(strbuf, KM_SLEEP);
+		mutex_enter(&devfsadm_lock);
+		sdev_release_door();
+		sdev_door_upcall_filename_size = n;
+		sdev_door_upcall_filename = namep;
+		sdcmn_err6(("size %d file name %s\n",
+		    sdev_door_upcall_filename_size,
+		    sdev_door_upcall_filename));
+		cv_broadcast(&devfsadm_cv);
+		mutex_exit(&devfsadm_lock);
 	}
 
 	kmem_free(strbuf, MOD_MAXPATH);
 	return (error);
 }
-static void
-sdev_nsrdr_thread(void)
-{
-	sdev_nsrdr_work_t *work;
-
-	for (;;) {
-		mutex_enter(&sdev_nsrdr_thread_lock);
-		if (sdev_nsrdr_thread_workq == NULL) {
-			cv_wait(&sdev_nsrdr_thread_cv, &sdev_nsrdr_thread_lock);
-		}
-		work = sdev_nsrdr_thread_workq;
-		sdev_nsrdr_thread_workq = work->next;
-		if (sdev_nsrdr_thread_tail == work)
-			sdev_nsrdr_thread_tail = work->next;
-		mutex_exit(&sdev_nsrdr_thread_lock);
-		sdev_devfsadmd_nsrdr(work);
-	}
-	/*NOTREACHED*/
-}
-
-int
-devname_nsmaps_register(char *nvlbuf, size_t nvlsize)
-{
-	int error = 0;
-	nvlist_t *nvl, *attrs;
-	nvpair_t *nvp = NULL;
-	nvpair_t *kvp = NULL;
-	char *buf;
-	char *key;
-	char *dirname = NULL;
-	char *dirmodule = NULL;
-	char *dirmap = NULL;
-	char *orig_module;
-	char *orig_map;
-	int len = 0;
-	char *tmpmap;
-	int mapcount = 0;
-
-	buf = kmem_zalloc(nvlsize, KM_SLEEP);
-	if ((error = ddi_copyin(nvlbuf, buf, nvlsize, 0)) != 0) {
-		kmem_free(buf, nvlsize);
-		return (error);
-	}
-
-	ASSERT(buf);
-	sdcmn_err6(("devname_nsmaps_register: nsmap buf %p\n", (void *)buf));
-	nvl = NULL;
-	error = nvlist_unpack(buf, nvlsize, &nvl, KM_SLEEP);
-	kmem_free(buf, nvlsize);
-	if (error || (nvl == NULL))
-		return (error);
-
-	/* invalidate all the nsmaps */
-	mutex_enter(&devname_nsmaps_lock);
-	sdev_invalidate_nsmaps();
-	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
-	    nvp = nvlist_next_nvpair(nvl, nvp)) {
-		dirname = nvpair_name(nvp);
-		if (dirname == NULL) {
-			nvlist_free(nvl);
-			mutex_exit(&devname_nsmaps_lock);
-			return (-1);
-		}
-
-		sdcmn_err6(("dirname %s\n", dirname));
-		(void) nvpair_value_nvlist(nvp, &attrs);
-		for (kvp = nvlist_next_nvpair(attrs, NULL); kvp;
-		    kvp = nvlist_next_nvpair(attrs, kvp)) {
-			key = nvpair_name(kvp);
-			sdcmn_err6(("key %s\n", key));
-			if (strcmp(key, "module") == 0) {
-				(void) nvpair_value_string(kvp, &orig_module);
-				sdcmn_err6(("module %s\n", orig_module));
-				dirmodule = i_ddi_strdup(orig_module, KM_SLEEP);
-				if (strcmp(dirmodule, "devname_null") == 0)
-					dirmodule = NULL;
-			}
-
-			if (strcmp(key, "nsconfig") == 0) {
-				(void) nvpair_value_string(kvp, &orig_map);
-				sdcmn_err6(("dirmap %s\n", orig_map));
-				dirmap = i_ddi_strdup(orig_map, KM_SLEEP);
-				if (strcmp(dirmap, "devname_null") == 0)
-					dirmap = NULL;
-				else if (dirmap[0] != '/') {
-					len = strlen(dirmap) +
-					    strlen(ETC_DEV_DIR) + 2;
-					tmpmap = i_ddi_strdup(dirmap, KM_SLEEP);
-					(void) snprintf(dirmap, len, "%s/%s",
-					    ETC_DEV_DIR, tmpmap);
-					kmem_free(tmpmap, strlen(tmpmap) + 1);
-				}
-			}
-		}
-
-		if (dirmodule == NULL && dirmap == NULL) {
-			nvlist_free(nvl);
-			mutex_exit(&devname_nsmaps_lock);
-			return (-1);
-		}
-
-		sdcmn_err6(("sdev_nsmaps_register: dir %s module %s map %s\n",
-		    dirname, dirmodule, dirmap));
-		sdev_insert_nsmap(dirname, dirmodule, dirmap);
-		mapcount++;
-	}
-
-	if (mapcount > 0)
-		devname_nsmaps_loaded = 1;
-
-	/* clean up obsolete nsmaps */
-	sdev_validate_nsmaps();
-	mutex_exit(&devname_nsmaps_lock);
-	if (nvl)
-		nvlist_free(nvl);
-
-	if (sdev_nsrdr_thread_created) {
-		return (0);
-	}
-
-	mutex_init(&sdev_nsrdr_thread_lock, NULL, MUTEX_DEFAULT, NULL);
-	cv_init(&sdev_nsrdr_thread_cv, NULL, CV_DEFAULT, NULL);
-	(void) thread_create(NULL, 0, (void (*)())sdev_nsrdr_thread, NULL, 0,
-	    &p0, TS_RUN, minclsyspri);
-	sdev_nsrdr_thread_created = 1;
-
-	return (0);
-}
-
-void
-sdev_dispatch_to_nsrdr_thread(struct sdev_node *ddv, char *dir_map,
-    devname_rdr_result_t *result)
-{
-	sdev_nsrdr_work_t *new_work;
-
-	new_work = kmem_zalloc(sizeof (sdev_nsrdr_work_t), KM_SLEEP);
-	new_work->dir_name = i_ddi_strdup(ddv->sdev_name, KM_SLEEP);
-	new_work->dir_map = i_ddi_strdup(dir_map, KM_SLEEP);
-	new_work->dir_dv = ddv;
-	new_work->result = &result;
-	mutex_enter(&sdev_nsrdr_thread_lock);
-	if (sdev_nsrdr_thread_workq == NULL) {
-		sdev_nsrdr_thread_workq = new_work;
-		sdev_nsrdr_thread_tail = new_work;
-		new_work->next = NULL;
-	} else {
-		sdev_nsrdr_thread_tail->next = new_work;
-		sdev_nsrdr_thread_tail = new_work;
-		new_work->next = NULL;
-	}
-	cv_signal(&sdev_nsrdr_thread_cv);
-	mutex_exit(&sdev_nsrdr_thread_lock);
-}
-
-static void
-sdev_devfsadmd_nsrdr(sdev_nsrdr_work_t *work)
-{
-	int32_t error;
-	struct sdev_door_arg *argp;
-	struct sdev_door_res res;
-	struct sdev_node *ddv = work->dir_dv;
-	uint32_t mapcount;
-
-	argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP);
-	argp->devfsadm_cmd = DEVFSADMD_NS_READDIR;
-
-	(void) snprintf(argp->ns_hdl.ns_name,
-	    strlen(work->dir_dv->sdev_path) + 1, "%s", work->dir_dv->sdev_path);
-	(void) snprintf(argp->ns_hdl.ns_map, strlen(work->dir_map) + 1, "%s",
-	    work->dir_map);
-
-	sdcmn_err6(("sdev_devfsadmd_nsrdr: ns_name %s, ns_map %s\n",
-	    argp->ns_hdl.ns_name, argp->ns_hdl.ns_map));
-	error = sdev_ki_call_devfsadmd(argp, &res);
-	sdcmn_err6(("sdev_devfsadmd_nsrdr error %d\n", error));
-	if (error == 0) {
-		error = res.devfsadm_error;
-		if (error) {
-			goto out;
-		}
-
-		mapcount = (uint32_t)res.ns_rdr_hdl.ns_mapcount;
-		sdcmn_err6(("nsmapcount %d\n", mapcount));
-		if (mapcount > 0) {
-			struct devname_nsmap *map =
-			    ddv->sdev_mapinfo;
-			ASSERT(map && map->dir_map);
-			rw_enter(&map->dir_lock, RW_WRITER);
-			map->dir_maploaded = 1;
-			rw_exit(&map->dir_lock);
-		}
-	}
-
-out:
-	mutex_enter(&ddv->sdev_lookup_lock);
-	SDEV_UNBLOCK_OTHERS(ddv, SDEV_READDIR);
-	mutex_exit(&ddv->sdev_lookup_lock);
-
-	kmem_free(argp, sizeof (sdev_door_arg_t));
-}
-
-
-int
-devname_nsmap_lookup(devname_lkp_arg_t *args, devname_lkp_result_t **result)
-{
-	int32_t error = 0;
-	struct sdev_door_arg *argp;
-	struct sdev_door_res resp;
-	char *link;
-	devname_spec_t spec;
-
-	argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP);
-	argp->devfsadm_cmd = DEVFSADMD_NS_LOOKUP;
-
-	(void) snprintf(argp->ns_hdl.ns_name, strlen(args->devname_name) + 1,
-	    "%s", args->devname_name);
-	(void) snprintf(argp->ns_hdl.ns_map, strlen(args->devname_map) + 1,
-	    "%s", args->devname_map);
-
-	error = sdev_ki_call_devfsadmd(argp, &resp);
-	if (error == 0) {
-		error = resp.devfsadm_error;
-		sdcmn_err6(("devfsadm: error %d\n", error));
-		if (error) {
-			goto done;
-		}
-		link = resp.ns_lkp_hdl.devfsadm_link;
-		if (link == NULL) {
-			error = ENOENT;
-			goto done;
-		}
-		spec = resp.ns_lkp_hdl.devfsadm_spec;
-		sdcmn_err6(("devfsadm_link %s spec %d\n",
-		    link, (int)spec));
-
-
-		(*result)->devname_spec = (devname_spec_t)spec;
-		(*result)->devname_link = i_ddi_strdup(link, KM_SLEEP);
-	} else {
-		(*result)->devname_spec = DEVNAME_NS_NONE;
-		(*result)->devname_link = NULL;
-	}
-done:
-	kmem_free(argp, sizeof (sdev_door_arg_t));
-	return (error);
-}
--- a/usr/src/uts/common/fs/dev/sdev_ncache.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/dev/sdev_ncache.c	Mon Jul 20 13:07:46 2009 -0400
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * negative cache handling for the /dev fs
  */
@@ -54,7 +52,7 @@
 #include <sys/mount.h>
 #include <sys/fs/snode.h>
 #include <sys/fs/dv_node.h>
-#include <sys/fs/sdev_node.h>
+#include <sys/fs/sdev_impl.h>
 #include <sys/sunndi.h>
 #include <sys/sunmdi.h>
 #include <sys/ddi.h>
@@ -195,9 +193,9 @@
 			kmem_free(*p, strlen(*p)+1);
 		}
 		kmem_free(dp->nvp_paths,
-			dp->nvp_npaths * sizeof (char *));
+		    dp->nvp_npaths * sizeof (char *));
 		kmem_free(dp->nvp_expirecnts,
-			dp->nvp_npaths * sizeof (int));
+		    dp->nvp_npaths * sizeof (int));
 	}
 
 	kmem_free(dp, sizeof (nvp_devname_t));
@@ -297,7 +295,7 @@
 	rval = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP);
 	if (rval != 0) {
 		nvf_error("%s: nvlist alloc error %d\n",
-			nvf_cache_name(fd), rval);
+		    nvf_cache_name(fd), rval);
 		return (DDI_FAILURE);
 	}
 
@@ -308,7 +306,7 @@
 		rval = nvlist_alloc(&sub_nvl, NV_UNIQUE_NAME, KM_SLEEP);
 		if (rval != 0) {
 			nvf_error("%s: nvlist alloc error %d\n",
-				nvf_cache_name(fd), rval);
+			    nvf_cache_name(fd), rval);
 			sub_nvl = NULL;
 			goto err;
 		}
@@ -706,7 +704,7 @@
 	    !SDEV_IS_NO_NCACHE(dv) &&
 	    ((failed_flags & SLF_NO_NCACHE) == 0) &&
 	    ((sdev_reconfig_boot &&
-		(sdev_boot_state != SDEV_BOOT_STATE_COMPLETE)) ||
+	    (sdev_boot_state != SDEV_BOOT_STATE_COMPLETE)) ||
 	    (!sdev_reconfig_boot && ((failed_flags & SLF_REBUILT))))) {
 			sdev_nc_addname(sdev_ncache,
 			    dv, nm, NCN_SRC_CURRENT|NCN_ACTIVE);
@@ -818,7 +816,7 @@
 	n = strlen(dv->sdev_path) + strlen(nm) + 2;
 	lp->ncn_name = kmem_alloc(n, KM_SLEEP);
 	(void) sprintf(lp->ncn_name, "%s/%s",
-		dv->sdev_path, nm);
+	    dv->sdev_path, nm);
 	lp->ncn_flags = flags;
 	lp->ncn_expirecnt = sdev_nc_expirecnt;
 	sdev_nc_insertnode(ncl, lp);
--- a/usr/src/uts/common/fs/dev/sdev_nsconfig_mod.c	Tue Jul 14 11:18:27 2009 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,198 +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 2006 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-/*
- * this module implements the devname_ops to fetch
- * a specific entry from a /etc/dev/devname_map file or
- * a name service map.
- */
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/errno.h>
-#include <sys/stat.h>
-#include <sys/cmn_err.h>
-#include <sys/sunddi.h>
-#include <sys/sunndi.h>
-#include <sys/modctl.h>
-#include <sys/debug.h>
-#include <sys/fs/sdev_impl.h>
-#include <sys/fs/sdev_node.h>
-
-static int devname_lookup(char *, devname_handle_t *, struct cred *);
-static int devname_remove(devname_handle_t *);
-static int devname_rename(devname_handle_t *, char *);
-static int devname_readdir(devname_handle_t *, struct cred *);
-static int devname_getattr(devname_handle_t *, struct vattr *,
-    struct cred *);
-static void devname_inactive(devname_handle_t *, struct cred *);
-
-static struct devname_ops devname_ops = {
-	DEVNOPS_REV,		/* devnops_rev, */
-	devname_lookup,		/* devnops_lookup */
-	devname_remove,		/* devnops_remove */
-	devname_rename,		/* devnops_rename */
-	devname_getattr,	/* devnops_getattr */
-	devname_readdir,	/* devname_readdir */
-	devname_inactive	/* devname_inactive */
-};
-
-/*
- * Module linkage information for the kernel.
- */
-static struct modldev modldev = {
-	&mod_devfsops,
-	"devname name service mod 1.0",
-	&devname_ops,
-};
-
-static struct modlinkage modlinkage = {
-	MODREV_1, &modldev, NULL
-};
-
-int
-_init(void)
-{
-	return (mod_install(&modlinkage));
-}
-
-int
-_fini(void)
-{
-	return (mod_remove(&modlinkage));
-}
-
-int
-_info(struct modinfo *modinfop)
-{
-	return (mod_info(&modlinkage, modinfop));
-}
-
-/*ARGSUSED2*/
-static int
-devname_lookup(char *nm, devname_handle_t *dhl, struct cred *cred)
-{
-	int error = 0;
-	char *dir = NULL;
-	devname_lkp_arg_t *args = NULL;
-	devname_lkp_result_t *result = NULL;
-	struct devname_nsmap *map = NULL;
-
-	args = kmem_zalloc(sizeof (struct devname_lkp_arg), KM_SLEEP);
-	if (args == NULL) {
-		error = ENOENT;
-		goto errout;
-	}
-
-	args->devname_name = i_ddi_strdup(nm, KM_SLEEP);
-	error = devname_get_dir_path(dhl, &dir);
-	if (error) {
-		error = ENOENT;
-		goto errout;
-	}
-
-	args->devname_dir = i_ddi_strdup(dir, KM_SLEEP);
-	error = devname_get_dir_nsmap(dhl, &map);
-	if (map && map->dir_map)
-		args->devname_map = i_ddi_strdup(map->dir_map, KM_SLEEP);
-
-	result = kmem_zalloc(sizeof (struct devname_lkp_result), KM_SLEEP);
-	if (result == NULL) {
-		error = ENOENT;
-		goto errout;
-	}
-
-
-	error = devname_nsmap_lookup(args, &result);
-	if (error) {
-		error = ENOENT;
-		goto errout;
-	}
-
-	devname_set_nodetype(dhl, (void *)result->devname_link,
-	    (int)result->devname_spec);
-
-errout:
-	if (args->devname_name)
-		kmem_free(args->devname_name, strlen(args->devname_name) + 1);
-	if (args->devname_dir)
-		kmem_free(args->devname_dir, strlen(args->devname_dir) + 1);
-	if (args->devname_map)
-		kmem_free(args->devname_map, strlen(args->devname_map) + 1);
-	if (args)
-		kmem_free(args, sizeof (struct devname_lkp_arg));
-	if (result)
-		kmem_free(result, sizeof (struct devname_lkp_result));
-	return (error);
-}
-
-/*ARGSUSED*/
-static int
-devname_readdir(devname_handle_t *hdl, struct cred *cred)
-{
-	char *entry;
-	char *dir;
-
-	(void) devname_get_name(hdl, &entry);
-	(void) devname_get_dir_name(hdl, &dir);
-
-	/* do not waste to do the map check */
-	return (0);
-}
-
-/*ARGSUSED*/
-static int
-devname_remove(devname_handle_t *hdl)
-{
-	char *entry;
-
-	(void) devname_get_name(hdl, &entry);
-	return (EROFS);
-}
-
-/*ARGSUSED*/
-static int
-devname_rename(devname_handle_t *ohdl, char *new_name)
-{
-	char *oname;
-
-	(void) devname_get_name(ohdl, &oname);
-	return (ENOTSUP);
-}
-
-/*ARGSUSED*/
-static int
-devname_getattr(devname_handle_t *hdl, vattr_t *vap, struct cred *cred)
-{
-	return (0);
-}
-
-/*ARGSUSED*/
-static void
-devname_inactive(devname_handle_t *hdl, struct cred *cred)
-{
-}
--- a/usr/src/uts/common/fs/dev/sdev_subr.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/dev/sdev_subr.c	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -55,7 +55,6 @@
 #include <sys/fs/snode.h>
 #include <sys/fs/dv_node.h>
 #include <sys/fs/sdev_impl.h>
-#include <sys/fs/sdev_node.h>
 #include <sys/sunndi.h>
 #include <sys/sunmdi.h>
 #include <sys/conf.h>
@@ -151,17 +150,9 @@
 kmem_cache_t	*sdev_node_cache;	/* sdev_node cache */
 int		devtype;		/* fstype */
 
-struct devname_ops *devname_ns_ops;	/* default name service directory ops */
-kmutex_t devname_nsmaps_lock;	/* protect devname_nsmaps */
-
 /* static */
-static struct devname_nsmap *devname_nsmaps = NULL;
-				/* contents from /etc/dev/devname_master */
-static int devname_nsmaps_invalidated = 0; /* "devfsadm -m" has run */
-
 static struct vnodeops *sdev_get_vop(struct sdev_node *);
 static void sdev_set_no_nocache(struct sdev_node *);
-static int sdev_get_moduleops(struct sdev_node *);
 static fs_operation_def_t *sdev_merge_vtab(const fs_operation_def_t []);
 static void sdev_free_vtab(fs_operation_def_t *);
 
@@ -335,10 +326,8 @@
 	cv_init(&dv->sdev_lookup_cv, NULL, CV_DEFAULT, NULL);
 	if (SDEV_IS_GLOBAL(ddv)) {
 		dv->sdev_flags |= SDEV_GLOBAL;
-		dv->sdev_mapinfo = NULL;
 		dhl = &(dv->sdev_handle);
 		dhl->dh_data = dv;
-		dhl->dh_spec = DEVNAME_NS_NONE;
 		dhl->dh_args = NULL;
 		sdev_set_no_nocache(dv);
 		dv->sdev_gdir_gen = 0;
@@ -380,7 +369,6 @@
 		dv->sdev_flags &= ~SDEV_PERSIST;
 		dv->sdev_flags &= ~SDEV_DYNAMIC;
 		vn_setops(vp, sdev_get_vop(dv)); /* from internal vtab */
-		error = sdev_get_moduleops(dv); /* from plug-in module */
 		ASSERT(dv->sdev_dotdot);
 		ASSERT(SDEVTOV(dv->sdev_dotdot)->v_type == VDIR);
 		vp->v_rdev = SDEVTOV(dv->sdev_dotdot)->v_rdev;
@@ -484,8 +472,6 @@
 	mutex_init(&dv->sdev_lookup_lock, NULL, MUTEX_DEFAULT, NULL);
 	cv_init(&dv->sdev_lookup_cv, NULL, CV_DEFAULT, NULL);
 	if (strcmp(dv->sdev_name, "/dev") == 0) {
-		mutex_init(&devname_nsmaps_lock, NULL, MUTEX_DEFAULT, NULL);
-		dv->sdev_mapinfo = NULL;
 		dv->sdev_flags = SDEV_BUILD|SDEV_GLOBAL|SDEV_PERSIST;
 		bzero(&dv->sdev_handle, sizeof (dv->sdev_handle));
 		dv->sdev_gdir_gen = 0;
@@ -509,84 +495,6 @@
 	return (dv);
 }
 
-/*
- *  1. load the module
- *  2. modload invokes sdev_module_register, which in turn sets
- *     the dv->sdev_mapinfo->dir_ops
- *
- * note: locking order:
- *	dv->sdev_contents -> map->dir_lock
- */
-static int
-sdev_get_moduleops(struct sdev_node *dv)
-{
-	int error = 0;
-	struct devname_nsmap *map = NULL;
-	char *module;
-	char *path;
-	int load = 1;
-
-	ASSERT(SDEVTOV(dv)->v_type == VDIR);
-
-	if (devname_nsmaps == NULL)
-		return (0);
-
-	if (!sdev_nsmaps_loaded() && !sdev_nsmaps_reloaded())
-		return (0);
-
-
-	path = dv->sdev_path;
-	if ((map = sdev_get_nsmap_by_dir(path, 0))) {
-		rw_enter(&map->dir_lock, RW_READER);
-		if (map->dir_invalid) {
-			if (map->dir_module && map->dir_newmodule &&
-			    (strcmp(map->dir_module,
-			    map->dir_newmodule) == 0)) {
-				load = 0;
-			}
-			sdev_replace_nsmap(map, map->dir_newmodule,
-			    map->dir_newmap);
-		}
-
-		module = map->dir_module;
-		if (module && load) {
-			sdcmn_err6(("sdev_get_moduleops: "
-			    "load module %s", module));
-			rw_exit(&map->dir_lock);
-			error = modload("devname", module);
-			sdcmn_err6(("sdev_get_moduleops: error %d\n", error));
-			if (error < 0) {
-				return (-1);
-			}
-		} else if (module == NULL) {
-			/*
-			 * loading the module ops for name services
-			 */
-			if (devname_ns_ops == NULL) {
-				sdcmn_err6((
-				    "sdev_get_moduleops: modload default\n"));
-				error = modload("devname", DEVNAME_NSCONFIG);
-				sdcmn_err6((
-				    "sdev_get_moduleops: error %d\n", error));
-				if (error < 0) {
-					return (-1);
-				}
-			}
-
-			if (!rw_tryupgrade(&map->dir_lock)) {
-				rw_exit(&map->dir_lock);
-				rw_enter(&map->dir_lock, RW_WRITER);
-			}
-			ASSERT(devname_ns_ops);
-			map->dir_ops = devname_ns_ops;
-			rw_exit(&map->dir_lock);
-		}
-	}
-
-	dv->sdev_mapinfo = map;
-	return (0);
-}
-
 /* directory dependent vop table */
 struct sdev_vop_table {
 	char *vt_name;				/* subdirectory name */
@@ -1419,25 +1327,6 @@
 }
 
 /*
- * loopback into sdev_lookup()
- */
-static struct vnode *
-devname_find_by_devpath(char *devpath, struct vattr *vattr)
-{
-	int error = 0;
-	struct vnode *vp;
-
-	error = lookupname(devpath, UIO_SYSSPACE, NO_FOLLOW, NULLVPP, &vp);
-	if (error) {
-		return (NULL);
-	}
-
-	if (vattr)
-		(void) VOP_GETATTR(vp, vattr, 0, kcred, NULL);
-	return (vp);
-}
-
-/*
  * the junction between devname and devfs
  */
 static struct vnode *
@@ -1838,92 +1727,6 @@
 	return (error);
 }
 
-static int
-sdev_call_modulelookup(struct sdev_node *ddv, struct sdev_node **dvp, char *nm,
-    int (*fn)(char *, devname_handle_t *, struct cred *), struct cred *cred)
-{
-	struct vnode *rvp = NULL;
-	int error = 0;
-	struct vattr *vap;
-	devname_spec_t spec;
-	devname_handle_t *hdl;
-	void *args = NULL;
-	struct sdev_node *dv = *dvp;
-
-	ASSERT(dv && ddv);
-	hdl = &(dv->sdev_handle);
-	ASSERT(hdl->dh_data == dv);
-	mutex_enter(&dv->sdev_lookup_lock);
-	SDEV_BLOCK_OTHERS(dv, SDEV_LOOKUP);
-	mutex_exit(&dv->sdev_lookup_lock);
-	error = (*fn)(nm, hdl, cred);
-	if (error) {
-		return (error);
-	}
-
-	spec = hdl->dh_spec;
-	args = hdl->dh_args;
-	ASSERT(args);
-
-	switch (spec) {
-	case DEVNAME_NS_PATH:
-		/*
-		 * symlink of:
-		 *	/dev/dir/nm -> /device/...
-		 */
-		rvp = devname_configure_by_path((char *)args, NULL);
-		break;
-	case DEVNAME_NS_DEV:
-		/*
-		 * symlink of:
-		 *	/dev/dir/nm -> /dev/...
-		 */
-		rvp = devname_find_by_devpath((char *)args, NULL);
-		break;
-	default:
-		if (args)
-			kmem_free((char *)args, strlen(args) + 1);
-		return (ENOENT);
-
-	}
-
-	if (rvp == NULL) {
-		if (args)
-			kmem_free((char *)args, strlen(args) + 1);
-		return (ENOENT);
-	} else {
-		vap = sdev_getdefault_attr(VLNK);
-		ASSERT(RW_READ_HELD(&ddv->sdev_contents));
-		/*
-		 * Could sdev_mknode return a different dv_node
-		 * once the lock is dropped?
-		 */
-		if (!rw_tryupgrade(&ddv->sdev_contents)) {
-			rw_exit(&ddv->sdev_contents);
-			rw_enter(&ddv->sdev_contents, RW_WRITER);
-		}
-		error = sdev_mknode(ddv, nm, &dv, vap, NULL, args, cred,
-		    SDEV_READY);
-		rw_downgrade(&ddv->sdev_contents);
-		if (error) {
-			if (args)
-				kmem_free((char *)args, strlen(args) + 1);
-			return (error);
-		} else {
-			mutex_enter(&dv->sdev_lookup_lock);
-			SDEV_UNBLOCK_OTHERS(dv, SDEV_LOOKUP);
-			mutex_exit(&dv->sdev_lookup_lock);
-			error = 0;
-		}
-	}
-
-	if (args)
-		kmem_free((char *)args, strlen(args) + 1);
-
-	*dvp = dv;
-	return (0);
-}
-
 /*
  *  Support for specialized device naming construction mechanisms
  */
@@ -2129,9 +1932,6 @@
 	struct sdev_node *dv = NULL;
 	int	retried = 0;
 	int	error = 0;
-	struct devname_nsmap *map = NULL;
-	struct devname_ops *dirops = NULL;
-	int (*fn)(char *, devname_handle_t *, struct cred *) = NULL;
 	struct vattr vattr;
 	char *lookup_thread = curproc->p_user.u_comm;
 	int failed_flags = 0;
@@ -2356,16 +2156,10 @@
 		failed_flags |= SLF_NO_NCACHE;
 	}
 
-	if (SDEV_IS_GLOBAL(ddv)) {
-		map = sdev_get_map(ddv, 1);
-		dirops = map ? map->dir_ops : NULL;
-		fn = dirops ? dirops->devnops_lookup : NULL;
-	}
-
 	/*
 	 * (b1) invoking devfsadm once per life time for devfsadm nodes
 	 */
-	if ((fn == NULL) && !callback) {
+	if (!callback) {
 
 		if (sdev_reconfig_boot || !i_ddi_io_initialized() ||
 		    SDEV_IS_DYNAMIC(ddv) || SDEV_IS_NO_NCACHE(dv) ||
@@ -2424,15 +2218,7 @@
 	 *
 	 *	note: module vnode ops take precedence than the build-in ones
 	 */
-	if (fn) {
-		error = sdev_call_modulelookup(ddv, &dv, nm, fn, cred);
-		if (error) {
-			SD_TRACE_FAILED_LOOKUP(ddv, nm, retried);
-			goto notfound;
-		} else {
-			goto found;
-		}
-	} else if (callback) {
+	if (callback) {
 		error = sdev_call_dircallback(ddv, &dv, nm, callback,
 		    flags, cred);
 		if (error == 0) {
@@ -2493,11 +2279,6 @@
 		}
 	}
 
-	if ((SDEVTOV(dv)->v_type == VDIR) && SDEV_IS_GLOBAL(dv)) {
-		rw_enter(&dv->sdev_contents, RW_READER);
-		(void) sdev_get_map(dv, 1);
-		rw_exit(&dv->sdev_contents);
-	}
 	rw_exit(&ddv->sdev_contents);
 	rv = sdev_to_vp(dv, vpp);
 	sdcmn_err3(("devname_lookup_func: returning vp %p v_count %d state %d "
@@ -2743,9 +2524,6 @@
 	offset_t	diroff;
 	offset_t	soff;
 	int		this_reclen;
-	struct devname_nsmap	*map = NULL;
-	struct devname_ops	*dirops = NULL;
-	int (*fn)(devname_handle_t *, struct cred *) = NULL;
 	int (*vtor)(struct sdev_node *) = NULL;
 	struct vattr attr;
 	timestruc_t now;
@@ -2783,32 +2561,8 @@
 		goto get_cache;
 
 	if (SDEV_IS_GLOBAL(ddv)) {
-		map = sdev_get_map(ddv, 0);
-		dirops = map ? map->dir_ops : NULL;
-		fn = dirops ? dirops->devnops_readdir : NULL;
-
-		if (map && map->dir_map) {
-			/*
-			 * load the name mapping rule database
-			 * through invoking devfsadm and symlink
-			 * all the entries in the map
-			 */
-			devname_rdr_result_t rdr_result;
-			int do_thread = 0;
-
-			rw_enter(&map->dir_lock, RW_READER);
-			do_thread = map->dir_maploaded ? 0 : 1;
-			rw_exit(&map->dir_lock);
-
-			if (do_thread) {
-				mutex_enter(&ddv->sdev_lookup_lock);
-				SDEV_BLOCK_OTHERS(ddv, SDEV_READDIR);
-				mutex_exit(&ddv->sdev_lookup_lock);
-
-				sdev_dispatch_to_nsrdr_thread(ddv,
-				    map->dir_map, &rdr_result);
-			}
-		} else if ((sdev_boot_state == SDEV_BOOT_STATE_COMPLETE) &&
+
+		if ((sdev_boot_state == SDEV_BOOT_STATE_COMPLETE) &&
 		    !sdev_reconfig_boot && (flags & SDEV_BROWSE) &&
 		    !SDEV_IS_DYNAMIC(ddv) && !SDEV_IS_NO_NCACHE(ddv) &&
 		    ((moddebug & MODDEBUG_FINI_EBUSY) == 0) &&
@@ -2937,19 +2691,6 @@
 			}
 		}
 
-		/*
-		 * call back into the module for the validity/bookkeeping
-		 * of this entry
-		 */
-		if (fn) {
-			error = (*fn)(&(dv->sdev_handle), cred);
-			if (error) {
-				sdcmn_err4(("sdev_readdir: module did not "
-				    "validate %s\n", dv->sdev_name));
-				continue;
-			}
-		}
-
 		namelen = strlen(dv->sdev_name);
 		reclen = DIRENT64_RECLEN(namelen);
 		if (outcount + reclen > alloc_count) {
@@ -3279,306 +3020,6 @@
 	return (error);
 }
 
-void
-sdev_update_newnsmap(struct devname_nsmap *map, char *module, char *mapname)
-{
-	rw_enter(&map->dir_lock, RW_WRITER);
-	if (module) {
-		ASSERT(map->dir_newmodule == NULL);
-		map->dir_newmodule = i_ddi_strdup(module, KM_SLEEP);
-	}
-	if (mapname) {
-		ASSERT(map->dir_newmap == NULL);
-		map->dir_newmap = i_ddi_strdup(mapname, KM_SLEEP);
-	}
-
-	map->dir_invalid = 1;
-	rw_exit(&map->dir_lock);
-}
-
-void
-sdev_replace_nsmap(struct devname_nsmap *map, char *module, char *mapname)
-{
-	char *old_module = NULL;
-	char *old_map = NULL;
-
-	ASSERT(RW_LOCK_HELD(&map->dir_lock));
-	if (!rw_tryupgrade(&map->dir_lock)) {
-		rw_exit(&map->dir_lock);
-		rw_enter(&map->dir_lock, RW_WRITER);
-	}
-
-	old_module = map->dir_module;
-	if (module) {
-		if (old_module && strcmp(old_module, module) != 0) {
-			kmem_free(old_module, strlen(old_module) + 1);
-		}
-		map->dir_module = module;
-		map->dir_newmodule = NULL;
-	}
-
-	old_map = map->dir_map;
-	if (mapname) {
-		if (old_map && strcmp(old_map, mapname) != 0) {
-			kmem_free(old_map, strlen(old_map) + 1);
-		}
-
-		map->dir_map = mapname;
-		map->dir_newmap = NULL;
-	}
-	map->dir_maploaded = 0;
-	map->dir_invalid = 0;
-	rw_downgrade(&map->dir_lock);
-}
-
-/*
- * dir_name should have at least one attribute,
- *	dir_module
- *	or dir_map
- *	or both
- * caller holds the devname_nsmaps_lock
- */
-void
-sdev_insert_nsmap(char *dir_name, char *dir_module, char *dir_map)
-{
-	struct devname_nsmap *map;
-	int len = 0;
-
-	ASSERT(dir_name);
-	ASSERT(dir_module || dir_map);
-	ASSERT(MUTEX_HELD(&devname_nsmaps_lock));
-
-	if (map = sdev_get_nsmap_by_dir(dir_name, 1)) {
-		sdev_update_newnsmap(map, dir_module, dir_map);
-		return;
-	}
-
-	map = (struct devname_nsmap *)kmem_zalloc(sizeof (*map), KM_SLEEP);
-	map->dir_name = i_ddi_strdup(dir_name, KM_SLEEP);
-	if (dir_module) {
-		map->dir_module = i_ddi_strdup(dir_module, KM_SLEEP);
-	}
-
-	if (dir_map) {
-		if (dir_map[0] != '/') {
-			len = strlen(ETC_DEV_DIR) + strlen(dir_map) + 2;
-			map->dir_map = kmem_zalloc(len, KM_SLEEP);
-			(void) snprintf(map->dir_map, len, "%s/%s", ETC_DEV_DIR,
-			    dir_map);
-		} else {
-			map->dir_map = i_ddi_strdup(dir_map, KM_SLEEP);
-		}
-	}
-
-	map->dir_ops = NULL;
-	map->dir_maploaded = 0;
-	map->dir_invalid = 0;
-	rw_init(&map->dir_lock, NULL, RW_DEFAULT, NULL);
-
-	map->next = devname_nsmaps;
-	map->prev = NULL;
-	if (devname_nsmaps) {
-		devname_nsmaps->prev = map;
-	}
-	devname_nsmaps = map;
-}
-
-struct devname_nsmap *
-sdev_get_nsmap_by_dir(char *dir_path, int locked)
-{
-	struct devname_nsmap *map = NULL;
-
-	if (!locked)
-		mutex_enter(&devname_nsmaps_lock);
-	for (map = devname_nsmaps; map; map = map->next) {
-		sdcmn_err6(("sdev_get_nsmap_by_dir: dir %s\n", map->dir_name));
-		if (strcmp(map->dir_name, dir_path) == 0) {
-			if (!locked)
-				mutex_exit(&devname_nsmaps_lock);
-			return (map);
-		}
-	}
-	if (!locked)
-		mutex_exit(&devname_nsmaps_lock);
-	return (NULL);
-}
-
-struct devname_nsmap *
-sdev_get_nsmap_by_module(char *mod_name)
-{
-	struct devname_nsmap *map = NULL;
-
-	mutex_enter(&devname_nsmaps_lock);
-	for (map = devname_nsmaps; map; map = map->next) {
-		sdcmn_err7(("sdev_get_nsmap_by_module: module %s\n",
-		    map->dir_module));
-		if (map->dir_module && strcmp(map->dir_module, mod_name) == 0) {
-			mutex_exit(&devname_nsmaps_lock);
-			return (map);
-		}
-	}
-	mutex_exit(&devname_nsmaps_lock);
-	return (NULL);
-}
-
-void
-sdev_invalidate_nsmaps()
-{
-	struct devname_nsmap *map = NULL;
-
-	ASSERT(MUTEX_HELD(&devname_nsmaps_lock));
-
-	if (devname_nsmaps == NULL)
-		return;
-
-	for (map = devname_nsmaps; map; map = map->next) {
-		rw_enter(&map->dir_lock, RW_WRITER);
-		map->dir_invalid = 1;
-		rw_exit(&map->dir_lock);
-	}
-	devname_nsmaps_invalidated = 1;
-}
-
-
-int
-sdev_nsmaps_loaded()
-{
-	int ret = 0;
-
-	mutex_enter(&devname_nsmaps_lock);
-	if (devname_nsmaps_loaded)
-		ret = 1;
-
-	mutex_exit(&devname_nsmaps_lock);
-	return (ret);
-}
-
-int
-sdev_nsmaps_reloaded()
-{
-	int ret = 0;
-
-	mutex_enter(&devname_nsmaps_lock);
-	if (devname_nsmaps_invalidated)
-		ret = 1;
-
-	mutex_exit(&devname_nsmaps_lock);
-	return (ret);
-}
-
-static void
-sdev_free_nsmap(struct devname_nsmap *map)
-{
-	ASSERT(map);
-	if (map->dir_name)
-		kmem_free(map->dir_name, strlen(map->dir_name) + 1);
-	if (map->dir_module)
-		kmem_free(map->dir_module, strlen(map->dir_module) + 1);
-	if (map->dir_map)
-		kmem_free(map->dir_map, strlen(map->dir_map) + 1);
-	rw_destroy(&map->dir_lock);
-	kmem_free(map, sizeof (*map));
-}
-
-void
-sdev_validate_nsmaps()
-{
-	struct devname_nsmap *map = NULL;
-	struct devname_nsmap *oldmap = NULL;
-
-	ASSERT(MUTEX_HELD(&devname_nsmaps_lock));
-	map = devname_nsmaps;
-	while (map) {
-		rw_enter(&map->dir_lock, RW_READER);
-		if ((map->dir_invalid == 1) && (map->dir_newmodule == NULL) &&
-		    (map->dir_newmap == NULL)) {
-			oldmap = map;
-			rw_exit(&map->dir_lock);
-			if (map->prev)
-				map->prev->next = oldmap->next;
-			if (map == devname_nsmaps)
-				devname_nsmaps = oldmap->next;
-
-			map = oldmap->next;
-			if (map)
-				map->prev = oldmap->prev;
-			sdev_free_nsmap(oldmap);
-			oldmap = NULL;
-		} else {
-			rw_exit(&map->dir_lock);
-			map = map->next;
-		}
-	}
-	devname_nsmaps_invalidated = 0;
-}
-
-static int
-sdev_map_is_invalid(struct devname_nsmap *map)
-{
-	int ret = 0;
-
-	ASSERT(map);
-	rw_enter(&map->dir_lock, RW_READER);
-	if (map->dir_invalid)
-		ret = 1;
-	rw_exit(&map->dir_lock);
-	return (ret);
-}
-
-static int
-sdev_check_map(struct devname_nsmap *map)
-{
-	struct devname_nsmap *mapp;
-
-	mutex_enter(&devname_nsmaps_lock);
-	if (devname_nsmaps == NULL) {
-		mutex_exit(&devname_nsmaps_lock);
-		return (1);
-	}
-
-	for (mapp = devname_nsmaps; mapp; mapp = mapp->next) {
-		if (mapp == map) {
-			mutex_exit(&devname_nsmaps_lock);
-			return (0);
-		}
-	}
-
-	mutex_exit(&devname_nsmaps_lock);
-	return (1);
-
-}
-
-struct devname_nsmap *
-sdev_get_map(struct sdev_node *dv, int validate)
-{
-	struct devname_nsmap *map;
-	int error;
-
-	ASSERT(RW_READ_HELD(&dv->sdev_contents));
-	map = dv->sdev_mapinfo;
-	if (map && sdev_check_map(map)) {
-		if (!rw_tryupgrade(&dv->sdev_contents)) {
-			rw_exit(&dv->sdev_contents);
-			rw_enter(&dv->sdev_contents, RW_WRITER);
-		}
-		dv->sdev_mapinfo = NULL;
-		rw_downgrade(&dv->sdev_contents);
-		return (NULL);
-	}
-
-	if (validate && (!map || (map && sdev_map_is_invalid(map)))) {
-		if (!rw_tryupgrade(&dv->sdev_contents)) {
-			rw_exit(&dv->sdev_contents);
-			rw_enter(&dv->sdev_contents, RW_WRITER);
-		}
-		error = sdev_get_moduleops(dv);
-		if (!error)
-			map = dv->sdev_mapinfo;
-		rw_downgrade(&dv->sdev_contents);
-	}
-	return (map);
-}
-
 extern int sdev_vnodeops_tbl_size;
 
 /*
@@ -3619,115 +3060,6 @@
 	kmem_free(new, sdev_vnodeops_tbl_size);
 }
 
-void
-devname_get_vnode(devname_handle_t *hdl, vnode_t **vpp)
-{
-	struct sdev_node *dv = hdl->dh_data;
-
-	ASSERT(dv);
-
-	rw_enter(&dv->sdev_contents, RW_READER);
-	*vpp = SDEVTOV(dv);
-	rw_exit(&dv->sdev_contents);
-}
-
-int
-devname_get_path(devname_handle_t *hdl, char **path)
-{
-	struct sdev_node *dv = hdl->dh_data;
-
-	ASSERT(dv);
-
-	rw_enter(&dv->sdev_contents, RW_READER);
-	*path = dv->sdev_path;
-	rw_exit(&dv->sdev_contents);
-	return (0);
-}
-
-int
-devname_get_name(devname_handle_t *hdl, char **entry)
-{
-	struct sdev_node *dv = hdl->dh_data;
-
-	ASSERT(dv);
-	rw_enter(&dv->sdev_contents, RW_READER);
-	*entry = dv->sdev_name;
-	rw_exit(&dv->sdev_contents);
-	return (0);
-}
-
-void
-devname_get_dir_vnode(devname_handle_t *hdl, vnode_t **vpp)
-{
-	struct sdev_node *dv = hdl->dh_data->sdev_dotdot;
-
-	ASSERT(dv);
-
-	rw_enter(&dv->sdev_contents, RW_READER);
-	*vpp = SDEVTOV(dv);
-	rw_exit(&dv->sdev_contents);
-}
-
-int
-devname_get_dir_path(devname_handle_t *hdl, char **path)
-{
-	struct sdev_node *dv = hdl->dh_data->sdev_dotdot;
-
-	ASSERT(dv);
-	rw_enter(&dv->sdev_contents, RW_READER);
-	*path = dv->sdev_path;
-	rw_exit(&dv->sdev_contents);
-	return (0);
-}
-
-int
-devname_get_dir_name(devname_handle_t *hdl, char **entry)
-{
-	struct sdev_node *dv = hdl->dh_data->sdev_dotdot;
-
-	ASSERT(dv);
-	rw_enter(&dv->sdev_contents, RW_READER);
-	*entry = dv->sdev_name;
-	rw_exit(&dv->sdev_contents);
-	return (0);
-}
-
-int
-devname_get_dir_nsmap(devname_handle_t *hdl, struct devname_nsmap **map)
-{
-	struct sdev_node *dv = hdl->dh_data->sdev_dotdot;
-
-	ASSERT(dv);
-	rw_enter(&dv->sdev_contents, RW_READER);
-	*map = dv->sdev_mapinfo;
-	rw_exit(&dv->sdev_contents);
-	return (0);
-}
-
-int
-devname_get_dir_handle(devname_handle_t *hdl, devname_handle_t **dir_hdl)
-{
-	struct sdev_node *dv = hdl->dh_data->sdev_dotdot;
-
-	ASSERT(dv);
-	rw_enter(&dv->sdev_contents, RW_READER);
-	*dir_hdl = &(dv->sdev_handle);
-	rw_exit(&dv->sdev_contents);
-	return (0);
-}
-
-void
-devname_set_nodetype(devname_handle_t *hdl, void *args, int spec)
-{
-	struct sdev_node *dv = hdl->dh_data;
-
-	ASSERT(dv);
-	rw_enter(&dv->sdev_contents, RW_WRITER);
-	hdl->dh_spec = (devname_spec_t)spec;
-	hdl->dh_args = (void *)i_ddi_strdup((char *)args, KM_SLEEP);
-	rw_exit(&dv->sdev_contents);
-}
-
 /*
  * a generic setattr() function
  *
@@ -3841,6 +3173,7 @@
 /*
  * a generic inactive() function
  */
+/*ARGSUSED*/
 void
 devname_inactive_func(struct vnode *vp, struct cred *cred,
     void (*callback)(struct vnode *))
@@ -3849,9 +3182,6 @@
 	struct sdev_node *dv = VTOSDEV(vp);
 	struct sdev_node *ddv = dv->sdev_dotdot;
 	int state;
-	struct devname_nsmap *map = NULL;
-	struct devname_ops *dirops = NULL;
-	void (*fn)(devname_handle_t *, struct cred *) = NULL;
 
 	rw_enter(&ddv->sdev_contents, RW_WRITER);
 	state = dv->sdev_state;
@@ -3872,12 +3202,6 @@
 	 */
 	if (clean) {
 		ASSERT(ddv);
-		if (SDEV_IS_GLOBAL(dv)) {
-			map = ddv->sdev_mapinfo;
-			dirops = map ? map->dir_ops : NULL;
-			if (dirops && (fn = dirops->devnops_inactive))
-				(*fn)(&(dv->sdev_handle), cred);
-		}
 
 		ddv->sdev_nlink--;
 		if (vp->v_type == VDIR) {
--- a/usr/src/uts/common/fs/dev/sdev_vfsops.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/dev/sdev_vfsops.c	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -52,7 +52,6 @@
 #include <sys/mkdev.h>
 #include <fs/fs_subr.h>
 #include <sys/fs/sdev_impl.h>
-#include <sys/fs/sdev_node.h>
 #include <sys/fs/snode.h>
 #include <sys/fs/dv_node.h>
 #include <sys/sunndi.h>
@@ -466,26 +465,6 @@
 	return (0);
 }
 
-int
-sdev_module_register(char *mod_name, struct devname_ops *dev_ops)
-{
-	struct devname_nsmap *map = NULL;
-
-	if (strcmp(mod_name, DEVNAME_NSCONFIG) == 0) {
-		devname_ns_ops = dev_ops;
-		return (0);
-	}
-
-	map = sdev_get_nsmap_by_module(mod_name);
-	if (map == NULL)
-		return (EFAULT);
-
-	rw_enter(&map->dir_lock, RW_WRITER);
-	map->dir_ops = dev_ops;
-	rw_exit(&map->dir_lock);
-	return (0);
-}
-
 static void
 sdev_insert_mntinfo(struct sdev_data *data)
 {
--- a/usr/src/uts/common/fs/dev/sdev_vnops.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/dev/sdev_vnops.c	Mon Jul 20 13:07:46 2009 -0400
@@ -70,7 +70,6 @@
 #include <fs/fs_subr.h>
 #include <sys/fs/dv_node.h>
 #include <sys/fs/sdev_impl.h>
-#include <sys/fs/sdev_node.h>
 
 /*ARGSUSED*/
 static int
@@ -208,18 +207,11 @@
 	int			error = 0;
 	struct sdev_node	*dv = VTOSDEV(vp);
 	struct sdev_node	*parent = dv->sdev_dotdot;
-	struct devname_nsmap *map = NULL;
-	struct devname_ops	*dirops = NULL;
-	int (*fn)(devname_handle_t *, struct vattr *, struct cred *);
 
 	ASSERT(parent);
 
 	rw_enter(&parent->sdev_contents, RW_READER);
 	ASSERT(dv->sdev_attr || dv->sdev_attrvp);
-	if (SDEV_IS_GLOBAL(dv) && (dv->sdev_state != SDEV_ZOMBIE)) {
-		map = sdev_get_map(parent, 0);
-		dirops = map ? map->dir_ops : NULL;
-	}
 
 	/*
 	 * search order:
@@ -230,10 +222,6 @@
 		rw_exit(&parent->sdev_contents);
 		error = VOP_GETATTR(dv->sdev_attrvp, vap, flags, cr, ct);
 		sdev_vattr_merge(dv, vap);
-	} else if (dirops && (fn = dirops->devnops_getattr)) {
-		sdev_vattr_merge(dv, vap);
-		rw_exit(&parent->sdev_contents);
-		error = (*fn)(&(dv->sdev_handle), vap, cr);
 	} else {
 		ASSERT(dv->sdev_attr);
 		*vap = *dv->sdev_attr;
@@ -522,9 +510,6 @@
 	struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp);
 	struct vnode *vp = NULL;
 	struct sdev_node *dv = NULL;
-	struct devname_nsmap *map = NULL;
-	struct devname_ops *dirops = NULL;
-	int (*fn)(devname_handle_t *);
 	int len;
 	int bkstore = 0;
 
@@ -573,18 +558,6 @@
 		return (error);
 	}
 
-	/* the module may record/reject removing a device node */
-	map = sdev_get_map(parent, 0);
-	dirops = map ? map->dir_ops : NULL;
-	if (dirops && ((fn = dirops->devnops_remove) != NULL)) {
-		error = (*fn)(&(dv->sdev_handle));
-		if (error) {
-			rw_exit(&parent->sdev_contents);
-			VN_RELE(vp);
-			return (error);
-		}
-	}
-
 	/*
 	 * sdev_dirdelete does the real job of:
 	 *  - make sure no open ref count
@@ -653,12 +626,6 @@
 	struct vnode 		*nvp = NULL;	/* destination vnode */
 	int			samedir = 0;	/* set if odvp == ndvp */
 	struct vnode		*realvp;
-	int			len;
-	char			nnm_path[MAXPATHLEN];
-	struct devname_nsmap 	*omap = NULL;
-	struct devname_ops	*odirops = NULL;
-	int (*fn)(devname_handle_t *, char *);
-	int (*rmfn)(devname_handle_t *);
 	int error = 0;
 	dev_t fsid;
 	int bkstore = 0;
@@ -782,30 +749,6 @@
 	fromdv = VTOSDEV(ovp);
 	ASSERT(fromdv);
 
-	/* check with the plug-in modules for the source directory */
-	rw_enter(&fromparent->sdev_contents, RW_READER);
-	omap = sdev_get_map(fromparent, 0);
-	rw_exit(&fromparent->sdev_contents);
-	odirops = omap ? omap->dir_ops : NULL;
-	if (odirops && ((fn = odirops->devnops_rename) != NULL)) {
-		if (samedir) {
-			error = (*fn)(&(fromdv->sdev_handle), nnm);
-		} else {
-			len = strlen(nnm) + strlen(toparent->sdev_name) + 2;
-			(void) snprintf(nnm_path, len, "%s/%s",
-			    toparent->sdev_name, nnm);
-			error = (*fn)(&(fromdv->sdev_handle), nnm);
-		}
-
-		if (error) {
-			mutex_exit(&sdev_lock);
-			sdcmn_err2(("sdev_rename: DBNR doesn't "
-			    "allow rename, error %d", error));
-			VN_RELE(ovp);
-			return (error);
-		}
-	}
-
 	/* destination file exists */
 	if (nvp) {
 		todv = VTOSDEV(nvp);
@@ -826,11 +769,6 @@
 		return (error);
 	}
 
-	/* notify the DBNR module the node is going away */
-	if (odirops && ((rmfn = odirops->devnops_remove) != NULL)) {
-		(void) (*rmfn)(&(fromdv->sdev_handle));
-	}
-
 	/*
 	 * unlink from source
 	 */
--- a/usr/src/uts/common/fs/fsflush.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/fsflush.c	Mon Jul 20 13:07:46 2009 -0400
@@ -125,7 +125,9 @@
 	ulong_t		nlocked = 0;
 	ulong_t		nmodified = 0;
 	ulong_t		ncoalesce = 0;
+	ulong_t		cnt;
 	int		mod;
+	int		fspage = 1;
 	u_offset_t	offset;
 	uint_t		szc;
 
@@ -135,8 +137,7 @@
 
 	static ulong_t	nscan = 0;
 	static pgcnt_t	last_total_pages = 0;
-	static void	*pp_cookie = NULL;
-	static page_t	*pp;
+	static page_t	*pp = NULL;
 uint8_t key;
 #define GET_KEY(p,k)                            \
         __asm__ ("      lgr     1,%1\n"         \
@@ -152,11 +153,8 @@
 		nscan = (last_total_pages * (tune.t_fsflushr))/v.v_autoup;
 	}
 
-	/*
-	 * On first time through initialize the cookie used for page_t scans
-	 */
-	if (pp_cookie == NULL)
-		pp = page_next_scan_init(&pp_cookie);
+	if (pp == NULL)
+		pp = memsegs->pages;
 
 	pcount = 0;
 	while (pcount < nscan) {
@@ -165,9 +163,19 @@
 		 * move to the next page, skipping over large pages
 		 * and issuing prefetches.
 		 */
-		pp = page_next_scan_large(pp, &pcount, &pp_cookie);
+		if (pp->p_szc && fspage == 0) {
+			pfn_t pfn;
+
+			pfn  = page_pptonum(pp);
+			cnt = page_get_pagecnt(pp->p_szc);
+			cnt -= pfn & (cnt - 1);
+		} else
+			cnt = 1;
+
+		pp = page_nextn(pp, cnt);
 		prefetch_page_r((void *)pp);
 		ASSERT(pp != NULL);
+		pcount += cnt;
 
 		/*
 		 * Do a bunch of dirty tests (ie. no locking) to determine
@@ -176,6 +184,7 @@
 		 */
 		++nexamined;
 		if (PP_ISSWAP(pp)) {
+			fspage = 0;
 			coal_page = NULL;
 			continue;
 		}
@@ -189,6 +198,7 @@
 			 * skip pages with a file system identity or that
 			 * are already maximum size
 			 */
+			fspage = 0;
 			szc = pp->p_szc;
 			if (pp->p_vnode != NULL || szc == fsf_npgsz - 1) {
 				coal_page = NULL;
@@ -238,8 +248,10 @@
 		if (PP_ISKAS(pp) ||
 		    PAGE_LOCKED(pp) ||
 		    pp->p_lckcnt != 0 ||
-		    pp->p_cowcnt != 0)
+		    pp->p_cowcnt != 0) {
+			fspage = 0;
 			continue;
+		}
 
 
 		/*
@@ -259,13 +271,17 @@
 		    PP_ISFREE(pp) ||
 		    vp == NULL ||
 		    PP_ISKAS(pp) ||
-		    pp->p_lckcnt != 0 ||
-		    pp->p_cowcnt != 0 ||
 		    (vp->v_flag & VISSWAP) != 0) {
 			page_unlock(pp);
+			fspage = 0;
+			continue;
+		}
+		if (pp->p_lckcnt != 0 || pp->p_cowcnt != 0) {
+			page_unlock(pp);
 			continue;
 		}
 
+		fspage = 1;
 		ASSERT(vp->v_type != VCHR);
 
 		/*
@@ -293,6 +309,7 @@
 
 			(void) VOP_PUTPAGE(vp, offset, PAGESIZE, B_ASYNC,
 			    kcred, NULL);
+
 			VN_RELE(vp);
 		} else {
 
--- a/usr/src/uts/common/fs/nfs/nfs4_srv.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv.c	Mon Jul 20 13:07:46 2009 -0400
@@ -6676,6 +6676,21 @@
 		rfs4_recall_deleg(fp, FALSE, sp->rs_owner->ro_client);
 		delay(NFS4_DELEGATION_CONFLICT_DELAY);
 		rfs4_dbe_lock(sp->rs_dbe);
+
+		/* if state closed while lock was dropped */
+		if (sp->rs_closed) {
+			if (dmodes || amodes)
+				(void) rfs4_unshare(sp);
+			rfs4_dbe_unlock(sp->rs_dbe);
+			rfs4_file_rele(fp);
+			/* Not a fully formed open; "close" it */
+			if (screate == TRUE)
+				rfs4_state_close(sp, FALSE, FALSE, cs->cr);
+			rfs4_state_rele(sp);
+			resp->status = NFS4ERR_OLD_STATEID;
+			return;
+		}
+
 		rfs4_dbe_lock(fp->rf_dbe);
 		/* Let's see if the delegation was returned */
 		if (rfs4_check_recall(sp, access)) {
@@ -6743,6 +6758,7 @@
 			fflags |= FWRITE;
 		vn_open_upgrade(cs->vp, fflags);
 	}
+	sp->rs_opened = TRUE;
 
 	if (dmodes & OPEN4_SHARE_DENY_READ)
 		fp->rf_deny_read++;
@@ -8183,35 +8199,6 @@
 	int fflags = 0;
 
 	/*
-	 * Decrement the count for each access and deny bit that this
-	 * state has contributed to the file. If the file counts go to zero
-	 * clear the appropriate bit in the appropriate mask.
-	 */
-
-	if (sp->rs_share_access & OPEN4_SHARE_ACCESS_READ) {
-		fp->rf_access_read--;
-		fflags |= FREAD;
-		if (fp->rf_access_read == 0)
-			fp->rf_share_access &= ~OPEN4_SHARE_ACCESS_READ;
-	}
-	if (sp->rs_share_access & OPEN4_SHARE_ACCESS_WRITE) {
-		fp->rf_access_write--;
-		fflags |= FWRITE;
-		if (fp->rf_access_write == 0)
-			fp->rf_share_access &= ~OPEN4_SHARE_ACCESS_WRITE;
-	}
-	if (sp->rs_share_deny & OPEN4_SHARE_DENY_READ) {
-		fp->rf_deny_read--;
-		if (fp->rf_deny_read == 0)
-			fp->rf_share_deny &= ~OPEN4_SHARE_DENY_READ;
-	}
-	if (sp->rs_share_deny & OPEN4_SHARE_DENY_WRITE) {
-		fp->rf_deny_write--;
-		if (fp->rf_deny_write == 0)
-			fp->rf_share_deny &= ~OPEN4_SHARE_DENY_WRITE;
-	}
-
-	/*
 	 * If this call is part of the larger closing down of client
 	 * state then it is just easier to release all locks
 	 * associated with this client instead of going through each
@@ -8280,7 +8267,41 @@
 	if (sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID)
 		(void) rfs4_unshare(sp);
 
-	(void) VOP_CLOSE(fp->rf_vp, fflags, 1, (offset_t)0, cr, NULL);
+	if (sp->rs_opened) {
+		/*
+		 * Decrement the count for each access and deny bit that this
+		 * state has contributed to the file.
+		 * If the file counts go to zero
+		 * clear the appropriate bit in the appropriate mask.
+		 */
+		if (sp->rs_share_access & OPEN4_SHARE_ACCESS_READ) {
+			fp->rf_access_read--;
+			fflags |= FREAD;
+			if (fp->rf_access_read == 0)
+				fp->rf_share_access &= ~OPEN4_SHARE_ACCESS_READ;
+		}
+		if (sp->rs_share_access & OPEN4_SHARE_ACCESS_WRITE) {
+			fp->rf_access_write--;
+			fflags |= FWRITE;
+			if (fp->rf_access_write == 0)
+				fp->rf_share_access &=
+				    ~OPEN4_SHARE_ACCESS_WRITE;
+		}
+		if (sp->rs_share_deny & OPEN4_SHARE_DENY_READ) {
+			fp->rf_deny_read--;
+			if (fp->rf_deny_read == 0)
+				fp->rf_share_deny &= ~OPEN4_SHARE_DENY_READ;
+		}
+		if (sp->rs_share_deny & OPEN4_SHARE_DENY_WRITE) {
+			fp->rf_deny_write--;
+			if (fp->rf_deny_write == 0)
+				fp->rf_share_deny &= ~OPEN4_SHARE_DENY_WRITE;
+		}
+
+		(void) VOP_CLOSE(fp->rf_vp, fflags, 1, (offset_t)0, cr, NULL);
+
+		sp->rs_opened = FALSE;
+	}
 }
 
 /*
--- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c	Mon Jul 20 13:07:46 2009 -0400
@@ -414,7 +414,7 @@
 		    sizeof (op->fqi.fq_last_comp),
 		    "%s%s", cur_node->od_name, pn->pn_sname);
 
-		op->fqi.fq_dnode = cur_node->dir_snode;
+		op->fqi.fq_dnode = cur_node->n_dnode;
 		smb_node_ref(op->fqi.fq_dnode);
 	} else {
 		if (rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path,
--- a/usr/src/uts/common/fs/smbsrv/smb_delete.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c	Mon Jul 20 13:07:46 2009 -0400
@@ -519,7 +519,7 @@
 	if (SMB_TREE_SUPPORTS_CATIA(sr))
 		flags |= SMB_CATIA;
 
-	rc = smb_fsop_remove(sr, sr->user_cr, node->dir_snode,
+	rc = smb_fsop_remove(sr, sr->user_cr, node->n_dnode,
 	    node->od_name, flags);
 	if (rc != 0) {
 		if (rc == ENOENT)
--- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c	Mon Jul 20 13:07:46 2009 -0400
@@ -694,7 +694,7 @@
 	sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
 
 	if (dnode->flags & NODE_XATTR_DIR) {
-		rc = smb_vop_stream_remove(dnode->dir_snode->vp,
+		rc = smb_vop_stream_remove(dnode->n_dnode->vp,
 		    name, flags, cr);
 	} else if (smb_is_stream_name(name)) {
 		smb_stream_parse_name(name, fname, sname);
@@ -1453,7 +1453,7 @@
 	faccess &= sr->tid_tree->t_access;
 
 	if (acl_check) {
-		dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL;
+		dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL;
 		error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp,
 		    cr);
 	} else {
@@ -2297,7 +2297,7 @@
 	}
 
 	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) {
-		dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL;
+		dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL;
 		smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp,
 		    cr);
 		return;
--- a/usr/src/uts/common/fs/smbsrv/smb_init.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_init.c	Mon Jul 20 13:07:46 2009 -0400
@@ -245,14 +245,20 @@
 	case SMB_IOC_UNSHARE:
 		rc = smb_server_share_unexport(&ioc->ioc_share);
 		break;
-	case SMB_IOC_USER_NUMBER:
-		rc = smb_server_user_number(&ioc->ioc_unum);
+	case SMB_IOC_NUMOPEN:
+		rc = smb_server_numopen(&ioc->ioc_opennum);
 		copyout = B_TRUE;
 		break;
-	case SMB_IOC_USER_LIST:
-		rc = smb_server_user_list(&ioc->ioc_ulist);
+	case SMB_IOC_SVCENUM:
+		rc = smb_server_enum(&ioc->ioc_svcenum);
 		copyout = B_TRUE;
 		break;
+	case SMB_IOC_SESSION_CLOSE:
+		rc = smb_server_session_close(&ioc->ioc_session);
+		break;
+	case SMB_IOC_FILE_CLOSE:
+		rc = smb_server_file_close(&ioc->ioc_fileid);
+		break;
 	default:
 		rc = ENOTTY;
 		break;
--- a/usr/src/uts/common/fs/smbsrv/smb_lock.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_lock.c	Mon Jul 20 13:07:46 2009 -0400
@@ -52,7 +52,22 @@
 static void smb_lock_destroy(smb_lock_t *);
 static void smb_lock_free(smb_lock_t *);
 
+/*
+ * Return the number of range locks on the specified node.
+ */
+uint32_t
+smb_lock_get_lock_count(smb_node_t *node)
+{
+	uint32_t	count;
 
+	SMB_NODE_VALID(node);
+
+	smb_llist_enter(&node->n_lock_list, RW_READER);
+	count = smb_llist_get_count(&node->n_ofile_list);
+	smb_llist_exit(&node->n_lock_list);
+
+	return (count);
+}
 
 /*
  * smb_unlock_range
--- a/usr/src/uts/common/fs/smbsrv/smb_node.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_node.c	Mon Jul 20 13:07:46 2009 -0400
@@ -153,7 +153,7 @@
 #define	VALIDATE_DIR_NODE(_dir_, _node_) \
     ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
     ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
-    ASSERT((_dir_)->dir_snode != (_node_));
+    ASSERT((_dir_)->n_dnode != (_node_));
 
 static kmem_cache_t	*smb_node_cache = NULL;
 static boolean_t	smb_node_initialized = B_FALSE;
@@ -246,7 +246,7 @@
  * or newly created.
  *
  * If an smb_node needs to be created, a reference is also taken on the
- * dir_snode (if passed in).
+ * dnode (if passed in).
  *
  * See smb_node_release() for details on the release of these references.
  */
@@ -259,8 +259,8 @@
     cred_t		*cred,
     vnode_t		*vp,
     char		*od_name,
-    smb_node_t		*dir_snode,
-    smb_node_t		*unnamed_node)
+    smb_node_t		*dnode,
+    smb_node_t		*unode)
 {
 	smb_llist_t		*node_hdr;
 	smb_node_t		*node;
@@ -277,8 +277,8 @@
 	 * it with the list lock held.
 	 */
 
-	if (unnamed_node)
-		unnamed_vp = unnamed_node->vp;
+	if (unode)
+		unnamed_vp = unode->vp;
 
 	/*
 	 * This getattr is performed on behalf of the server
@@ -323,14 +323,13 @@
 				case SMB_NODE_STATE_AVAILABLE:
 					/* The node was found. */
 					node->n_refcnt++;
-					if ((node->dir_snode == NULL) &&
-					    (dir_snode != NULL) &&
+					if ((node->n_dnode == NULL) &&
+					    (dnode != NULL) &&
 					    (strcmp(od_name, "..") != 0) &&
 					    (strcmp(od_name, ".") != 0)) {
-						VALIDATE_DIR_NODE(dir_snode,
-						    node);
-						node->dir_snode = dir_snode;
-						smb_node_ref(dir_snode);
+						VALIDATE_DIR_NODE(dnode, node);
+						node->n_dnode = dnode;
+						smb_node_ref(dnode);
 					}
 
 					smb_node_audit(node);
@@ -371,17 +370,17 @@
 	if (op)
 		node->flags |= smb_is_executable(op->fqi.fq_last_comp);
 
-	if (dir_snode) {
-		smb_node_ref(dir_snode);
-		node->dir_snode = dir_snode;
-		ASSERT(dir_snode->dir_snode != node);
-		ASSERT((dir_snode->vp->v_xattrdir) ||
-		    (dir_snode->vp->v_type == VDIR));
+	if (dnode) {
+		smb_node_ref(dnode);
+		node->n_dnode = dnode;
+		ASSERT(dnode->n_dnode != node);
+		ASSERT((dnode->vp->v_xattrdir) ||
+		    (dnode->vp->v_type == VDIR));
 	}
 
-	if (unnamed_node) {
-		smb_node_ref(unnamed_node);
-		node->unnamed_stream_node = unnamed_node;
+	if (unode) {
+		smb_node_ref(unode);
+		node->n_unode = unode;
 	}
 
 	DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
@@ -472,8 +471,8 @@
  * then the caller with the local variable should call smb_node_release()
  * directly.
  *
- * smb_node_release() itself will call smb_node_release() on a node's dir_snode,
- * as smb_node_lookup() takes a hold on dir_snode.
+ * smb_node_release() itself will call smb_node_release() on a node's n_dnode,
+ * as smb_node_lookup() takes a hold on dnode.
  */
 void
 smb_node_release(smb_node_t *node)
@@ -499,16 +498,16 @@
 			 */
 			smb_node_delete_on_close(node);
 
-			if (node->dir_snode) {
-				ASSERT(node->dir_snode->n_magic ==
+			if (node->n_dnode) {
+				ASSERT(node->n_dnode->n_magic ==
 				    SMB_NODE_MAGIC);
-				smb_node_release(node->dir_snode);
+				smb_node_release(node->n_dnode);
 			}
 
-			if (node->unnamed_stream_node) {
-				ASSERT(node->unnamed_stream_node->n_magic ==
+			if (node->n_unode) {
+				ASSERT(node->n_unode->n_magic ==
 				    SMB_NODE_MAGIC);
-				smb_node_release(node->unnamed_stream_node);
+				smb_node_release(node->n_unode);
 			}
 
 			smb_node_free(node);
@@ -529,7 +528,7 @@
 	int		rc = 0;
 	uint32_t	flags = 0;
 
-	d_snode = node->dir_snode;
+	d_snode = node->n_dnode;
 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
 		flags = node->n_delete_on_close_flags;
@@ -570,9 +569,9 @@
 	case SMB_NODE_STATE_AVAILABLE:
 	case SMB_NODE_STATE_OPLOCK_GRANTED:
 	case SMB_NODE_STATE_OPLOCK_BREAKING:
-		ret_node->dir_snode = to_dnode;
+		ret_node->n_dnode = to_dnode;
 		mutex_exit(&ret_node->n_mutex);
-		ASSERT(to_dnode->dir_snode != ret_node);
+		ASSERT(to_dnode->n_dnode != ret_node);
 		ASSERT((to_dnode->vp->v_xattrdir) ||
 		    (to_dnode->vp->v_type == VDIR));
 		smb_node_release(from_dnode);
@@ -956,10 +955,9 @@
 	node->n_orig_uid = 0;
 	node->readonly_creator = NULL;
 	node->waiting_event = 0;
-	node->what = 0;
 	node->n_open_count = 0;
-	node->dir_snode = NULL;
-	node->unnamed_stream_node = NULL;
+	node->n_dnode = NULL;
+	node->n_unode = NULL;
 	node->delete_on_close_cred = NULL;
 	node->n_delete_on_close_flags = 0;
 
--- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c	Mon Jul 20 13:07:46 2009 -0400
@@ -164,10 +164,14 @@
 #include <smbsrv/smb_kproto.h>
 #include <smbsrv/smb_fsops.h>
 
-/* Static functions defined further down this file. */
-static void smb_ofile_delete(smb_ofile_t *of);
-static smb_ofile_t *smb_ofile_close_and_next(smb_ofile_t *of);
+static boolean_t smb_ofile_is_open_locked(smb_ofile_t *);
+static void smb_ofile_delete(smb_ofile_t *);
+static smb_ofile_t *smb_ofile_close_and_next(smb_ofile_t *);
 static void smb_ofile_set_close_attrs(smb_ofile_t *, uint32_t);
+static int smb_ofile_netinfo_encode(smb_ofile_t *, uint8_t *, size_t,
+    uint32_t *);
+static int smb_ofile_netinfo_init(smb_ofile_t *, smb_netfileinfo_t *);
+static void smb_ofile_netinfo_fini(smb_netfileinfo_t *);
 
 /*
  * smb_ofile_open
@@ -277,6 +281,7 @@
 	smb_llist_enter(&tree->t_ofile_list, RW_WRITER);
 	smb_llist_insert_tail(&tree->t_ofile_list, of);
 	smb_llist_exit(&tree->t_ofile_list);
+	atomic_inc_32(&tree->t_open_files);
 	atomic_inc_32(&tree->t_server->sv_open_files);
 	atomic_inc_32(&of->f_session->s_file_cnt);
 
@@ -328,6 +333,7 @@
 			if (of->f_node->flags & NODE_FLAGS_NOTIFY_CHANGE)
 				smb_process_file_notify_change_queue(of);
 		}
+		atomic_dec_32(&of->f_tree->t_open_files);
 		atomic_dec_32(&of->f_tree->t_server->sv_open_files);
 
 		mutex_enter(&of->f_mutex);
@@ -409,6 +415,70 @@
 }
 
 /*
+ * If the enumeration request is for ofile data, handle it here.
+ * Otherwise, return.
+ *
+ * This function should be called with a hold on the ofile.
+ */
+int
+smb_ofile_enum(smb_ofile_t *of, smb_svcenum_t *svcenum)
+{
+	uint8_t *pb;
+	uint_t nbytes;
+	int rc;
+
+	ASSERT(of);
+	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+	ASSERT(of->f_refcnt);
+
+	if (svcenum->se_type != SMB_SVCENUM_TYPE_FILE)
+		return (0);
+
+	if (svcenum->se_nskip > 0) {
+		svcenum->se_nskip--;
+		return (0);
+	}
+
+	if (svcenum->se_nitems >= svcenum->se_nlimit) {
+		svcenum->se_nitems = svcenum->se_nlimit;
+		return (0);
+	}
+
+	pb = &svcenum->se_buf[svcenum->se_bused];
+
+	rc = smb_ofile_netinfo_encode(of, pb, svcenum->se_bavail,
+	    &nbytes);
+	if (rc == 0) {
+		svcenum->se_bavail -= nbytes;
+		svcenum->se_bused += nbytes;
+		svcenum->se_nitems++;
+	}
+
+	return (rc);
+}
+
+/*
+ * Take a reference on an open file.
+ */
+boolean_t
+smb_ofile_hold(smb_ofile_t *of)
+{
+	ASSERT(of);
+	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+
+	mutex_enter(&of->f_mutex);
+
+	if (smb_ofile_is_open_locked(of)) {
+		of->f_refcnt++;
+		mutex_exit(&of->f_mutex);
+		return (B_TRUE);
+	}
+
+	mutex_exit(&of->f_mutex);
+	return (B_FALSE);
+}
+
+/*
  * smb_ofile_release
  *
  */
@@ -487,6 +557,71 @@
 }
 
 /*
+ * smb_ofile_lookup_by_uniqid
+ *
+ * Find the open file whose uniqid matches the one specified in the request.
+ */
+smb_ofile_t *
+smb_ofile_lookup_by_uniqid(smb_tree_t *tree, uint32_t uniqid)
+{
+	smb_llist_t	*of_list;
+	smb_ofile_t	*of;
+
+	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+	of_list = &tree->t_ofile_list;
+	smb_llist_enter(of_list, RW_READER);
+	of = smb_llist_head(of_list);
+
+	while (of) {
+		ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+		ASSERT(of->f_tree == tree);
+
+		if (of->f_uniqid == uniqid) {
+			if (smb_ofile_hold(of)) {
+				smb_llist_exit(of_list);
+				return (of);
+			}
+		}
+
+		of = smb_llist_next(of_list, of);
+	}
+
+	smb_llist_exit(of_list);
+	return (NULL);
+}
+
+/*
+ * Disallow NetFileClose on certain ofiles to avoid side-effects.
+ * Closing a tree root is not allowed: use NetSessionDel or NetShareDel.
+ * Closing SRVSVC connections is not allowed because this NetFileClose
+ * request may depend on this ofile.
+ */
+boolean_t
+smb_ofile_disallow_fclose(smb_ofile_t *of)
+{
+	ASSERT(of);
+	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+	ASSERT(of->f_refcnt);
+
+	switch (of->f_ftype) {
+	case SMB_FTYPE_DISK:
+		ASSERT(of->f_tree);
+		return (of->f_node == of->f_tree->t_snode);
+
+	case SMB_FTYPE_MESG_PIPE:
+		ASSERT(of->f_pipe);
+		if (utf8_strcasecmp(of->f_pipe->p_name, "SRVSVC") == 0)
+			return (B_TRUE);
+		break;
+	default:
+		break;
+	}
+
+	return (B_FALSE);
+}
+
+/*
  * smb_ofile_set_flags
  *
  * Return value:
@@ -588,14 +723,12 @@
 boolean_t
 smb_ofile_is_open(smb_ofile_t *of)
 {
-	boolean_t	rc = B_FALSE;
+	boolean_t	rc;
 
 	SMB_OFILE_VALID(of);
 
 	mutex_enter(&of->f_mutex);
-	if (of->f_state == SMB_OFILE_STATE_OPEN) {
-		rc = B_TRUE;
-	}
+	rc = smb_ofile_is_open_locked(of);
 	mutex_exit(&of->f_mutex);
 	return (rc);
 }
@@ -674,6 +807,27 @@
 /* *************************** Static Functions ***************************** */
 
 /*
+ * Determine whether or not an ofile is open.
+ * This function must be called with the mutex held.
+ */
+static boolean_t
+smb_ofile_is_open_locked(smb_ofile_t *of)
+{
+	switch (of->f_state) {
+	case SMB_OFILE_STATE_OPEN:
+		return (B_TRUE);
+
+	case SMB_OFILE_STATE_CLOSING:
+	case SMB_OFILE_STATE_CLOSED:
+		return (B_FALSE);
+
+	default:
+		ASSERT(0);
+		return (B_FALSE);
+	}
+}
+
+/*
  * smb_ofile_set_close_attrs
  *
  * Updates timestamps, size and readonly bit.
@@ -1038,3 +1192,107 @@
 	of->f_flags |= SMB_OFLAGS_SET_DELETE_ON_CLOSE;
 	mutex_exit(&of->f_mutex);
 }
+
+/*
+ * Encode open file information into a buffer; needed in user space to
+ * support RPC requests.
+ */
+static int
+smb_ofile_netinfo_encode(smb_ofile_t *of, uint8_t *buf, size_t buflen,
+    uint32_t *nbytes)
+{
+	smb_netfileinfo_t	fi;
+	int			rc;
+
+	rc = smb_ofile_netinfo_init(of, &fi);
+	if (rc == 0) {
+		rc = smb_netfileinfo_encode(&fi, buf, buflen, nbytes);
+		smb_ofile_netinfo_fini(&fi);
+	}
+
+	return (rc);
+}
+
+static int
+smb_ofile_netinfo_init(smb_ofile_t *of, smb_netfileinfo_t *fi)
+{
+	smb_user_t	*user;
+	smb_tree_t	*tree;
+	smb_node_t	*node;
+	char		*path;
+	char		*buf;
+	int		rc;
+
+	ASSERT(of);
+	user = of->f_user;
+	tree = of->f_tree;
+	ASSERT(user);
+	ASSERT(tree);
+
+	buf = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+
+	switch (of->f_ftype) {
+	case SMB_FTYPE_DISK:
+		node = of->f_node;
+		ASSERT(node);
+
+		fi->fi_permissions = of->f_granted_access;
+		fi->fi_numlocks = smb_lock_get_lock_count(node);
+
+		path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+
+		if (node != tree->t_snode) {
+			rc = vnodetopath(tree->t_snode->vp, node->vp, path,
+			    MAXPATHLEN, kcred);
+			if (rc == 0)
+				(void) strsubst(path, '/', '\\');
+			else
+				(void) strlcpy(path, node->od_name, MAXPATHLEN);
+		}
+
+		(void) snprintf(buf, MAXPATHLEN, "%s:%s", tree->t_sharename,
+		    path);
+		kmem_free(path, MAXPATHLEN);
+		break;
+
+	case SMB_FTYPE_MESG_PIPE:
+		ASSERT(of->f_pipe);
+
+		fi->fi_permissions = FILE_READ_DATA | FILE_WRITE_DATA |
+		    FILE_EXECUTE;
+		fi->fi_numlocks = 0;
+		(void) snprintf(buf, MAXPATHLEN, "\\PIPE\\%s",
+		    of->f_pipe->p_name);
+		break;
+
+	default:
+		kmem_free(buf, MAXPATHLEN);
+		return (-1);
+	}
+
+	fi->fi_fid = of->f_fid;
+	fi->fi_uniqid = of->f_uniqid;
+	fi->fi_pathlen = strlen(buf) + 1;
+	fi->fi_path = smb_kstrdup(buf, fi->fi_pathlen);
+	kmem_free(buf, MAXPATHLEN);
+
+	fi->fi_namelen = user->u_domain_len + user->u_name_len + 2;
+	fi->fi_username = kmem_alloc(fi->fi_namelen, KM_SLEEP);
+	(void) snprintf(fi->fi_username, fi->fi_namelen, "%s\\%s",
+	    user->u_domain, user->u_name);
+	return (0);
+}
+
+static void
+smb_ofile_netinfo_fini(smb_netfileinfo_t *fi)
+{
+	if (fi == NULL)
+		return;
+
+	if (fi->fi_path)
+		kmem_free(fi->fi_path, fi->fi_pathlen);
+	if (fi->fi_username)
+		kmem_free(fi->fi_username, fi->fi_namelen);
+
+	bzero(fi, sizeof (smb_netfileinfo_t));
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_opipe.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_opipe.c	Mon Jul 20 13:07:46 2009 -0400
@@ -143,13 +143,14 @@
  * The full pipe path will be in the form \\PIPE\\SERVICE.  The first part
  * can be assumed, so all we need here are the service names.
  *
- * Returns a pointer to the pipe name (without any leading \'s) on sucess.
+ * Returns a pointer to the pipe name (without any leading \'s) on success.
  * Otherwise returns a null pointer.
  */
 static char *
 smb_opipe_lookup(const char *path)
 {
 	static char *named_pipes[] = {
+		"lsass",
 		"LSARPC",
 		"NETLOGON",
 		"SAMR",
@@ -188,14 +189,14 @@
 static int
 smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe)
 {
-	smb_opipe_context_t *ctx = &opipe->p_context;
+	smb_netuserinfo_t *userinfo = &opipe->p_user;
 	smb_user_t *user = sr->uid_user;
 	uint8_t *buf = opipe->p_doorbuf;
 	uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE;
 	uint32_t len;
 
-	smb_user_context_init(user, ctx);
-	len = xdr_sizeof(smb_opipe_context_xdr, ctx);
+	smb_user_netinfo_init(user, userinfo);
+	len = xdr_sizeof(smb_netuserinfo_xdr, userinfo);
 
 	bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t));
 	opipe->p_hdr.oh_magic = SMB_OPIPE_HDR_MAGIC;
@@ -208,7 +209,7 @@
 	buf += len;
 	buflen -= len;
 
-	if (smb_opipe_context_encode(ctx, buf, buflen, NULL) == -1)
+	if (smb_netuserinfo_encode(userinfo, buf, buflen, NULL) == -1)
 		return (-1);
 
 	return (smb_opipe_door_call(opipe));
@@ -266,7 +267,7 @@
 		kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE);
 	}
 
-	smb_user_context_fini(&opipe->p_context);
+	smb_user_netinfo_fini(&opipe->p_user);
 	smb_opipe_exit(opipe);
 	cv_destroy(&opipe->p_cv);
 	mutex_destroy(&opipe->p_mutex);
@@ -620,48 +621,3 @@
 	opipe->p_hdr.oh_resid = hdr.oh_resid;
 	return (0);
 }
-
-void
-smb_user_context_init(smb_user_t *user, smb_opipe_context_t *ctx)
-{
-	smb_session_t *session;
-
-	ASSERT(user);
-	ASSERT(user->u_domain);
-	ASSERT(user->u_name);
-
-	session = user->u_session;
-	ASSERT(session);
-	ASSERT(session->workstation);
-
-	ctx->oc_session_id = session->s_kid;
-	ctx->oc_native_os = session->native_os;
-	ctx->oc_ipaddr = session->ipaddr;
-	ctx->oc_uid = user->u_uid;
-	ctx->oc_logon_time = user->u_logon_time;
-	ctx->oc_flags = user->u_flags;
-
-	ctx->oc_domain_len = user->u_domain_len;
-	ctx->oc_domain = smb_kstrdup(user->u_domain, ctx->oc_domain_len);
-
-	ctx->oc_account_len = user->u_name_len;
-	ctx->oc_account = smb_kstrdup(user->u_name, ctx->oc_account_len);
-
-	ctx->oc_workstation_len = strlen(session->workstation) + 1;
-	ctx->oc_workstation = smb_kstrdup(session->workstation,
-	    ctx->oc_workstation_len);
-}
-
-void
-smb_user_context_fini(smb_opipe_context_t *ctx)
-{
-	if (ctx) {
-		if (ctx->oc_domain)
-			kmem_free(ctx->oc_domain, ctx->oc_domain_len);
-		if (ctx->oc_account)
-			kmem_free(ctx->oc_account, ctx->oc_account_len);
-		if (ctx->oc_workstation)
-			kmem_free(ctx->oc_workstation, ctx->oc_workstation_len);
-		bzero(ctx, sizeof (smb_opipe_context_t));
-	}
-}
--- a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c	Mon Jul 20 13:07:46 2009 -0400
@@ -367,7 +367,7 @@
  * ENOENT will be returned.
  *
  * Path components are processed one at a time so that smb_nodes can be
- * created for each component.  This allows the dir_snode field in the
+ * created for each component.  This allows the n_dnode field in the
  * smb_node to be properly populated.
  *
  * Because of the above, links are also processed in this routine
--- a/usr/src/uts/common/fs/smbsrv/smb_query_information.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_information.c	Mon Jul 20 13:07:46 2009 -0400
@@ -102,9 +102,9 @@
 	timestruc_t	*mtime;
 
 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
-		rc = smbsr_encode_result(sr, 10, 0, "bwll10.w",
-		    10, FILE_ATTRIBUTE_NORMAL, 0, 0, 0);
-		return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
+		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
+		    ERROR_ACCESS_DENIED);
+		return (SDRC_ERROR);
 	}
 
 	if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
--- a/usr/src/uts/common/fs/smbsrv/smb_query_information2.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_information2.c	Mon Jul 20 13:07:46 2009 -0400
@@ -93,8 +93,9 @@
 	}
 
 	if (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK) {
-		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
-		return (SDRC_ERROR);
+		rc = smbsr_encode_result(sr, 11, 0, "blllllww",
+		    11, 0, 0, 0, 0, 0, 0, 0);
+		return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 	}
 
 	node = sr->fid_ofile->f_node;
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_server.c	Mon Jul 20 13:07:46 2009 -0400
@@ -236,8 +236,6 @@
     in_port_t, int, int);
 static int smb_server_lookup(smb_server_t **);
 static void smb_server_release(smb_server_t *);
-static int smb_server_ulist_geti(smb_session_list_t *, uint32_t,
-    uint8_t *, uint32_t, uint_t *);
 static void smb_server_store_cfg(smb_server_t *, smb_ioc_cfg_t *);
 static void smb_server_stop(smb_server_t *);
 static int smb_server_fsop_start(smb_server_t *);
@@ -246,6 +244,11 @@
 static void smb_server_disconnect_share(char *, smb_server_t *);
 static void smb_server_thread_unexport(smb_thread_t *, void *);
 
+static void smb_server_enum_private(smb_session_list_t *, smb_svcenum_t *);
+static int smb_server_sesion_disconnect(smb_session_list_t *, const char *,
+    const char *);
+static int smb_server_fclose(smb_session_list_t *, uint32_t);
+
 static smb_llist_t	smb_servers;
 
 /*
@@ -253,7 +256,8 @@
  * **************** Functions called from the device interface *****************
  * *****************************************************************************
  *
- * These functions determine the relevant smb server to which the call apply.
+ * These functions typically have to determine the relevant smb server
+ * to which the call applies.
  */
 
 /*
@@ -759,75 +763,117 @@
 }
 
 int
-smb_server_user_number(smb_ioc_usernum_t *ioc)
+smb_server_numopen(smb_ioc_opennum_t *ioc)
 {
 	smb_server_t	*sv;
 	int		rc;
 
 	if ((rc = smb_server_lookup(&sv)) == 0) {
-		ioc->num = sv->sv_open_users;
-		smb_server_release(sv);
-	}
-	return (rc);
-}
-
-int
-smb_server_user_list(smb_ioc_ulist_t *ioc)
-{
-	smb_server_t *sv;
-	uint8_t *data;
-	uint32_t data_len;
-	uint_t bytes_encoded;
-	int rc;
-
-	if ((rc = smb_server_lookup(&sv)) == 0) {
-
-		bytes_encoded = 0;
-		data = ioc->data;
-		data_len = ioc->data_len;
-		ioc->num =
-		    smb_server_ulist_geti(&sv->sv_nbt_daemon.ld_session_list,
-		    ioc->cookie, data, data_len, &bytes_encoded);
-
-		data += bytes_encoded;
-		data_len -= bytes_encoded;
-		ioc->data_len = bytes_encoded;
-		ioc->cookie += ioc->num;
-
-		ioc->num +=
-		    smb_server_ulist_geti(&sv->sv_tcp_daemon.ld_session_list,
-		    ioc->cookie, data, data_len, &bytes_encoded);
-
-		ioc->data_len += bytes_encoded;
-
+		ioc->open_users = sv->sv_open_users;
+		ioc->open_trees = sv->sv_open_trees;
+		ioc->open_files = sv->sv_open_files;
 		smb_server_release(sv);
 	}
 	return (rc);
 }
 
 /*
- * *****************************************************************************
- * ****************** Functions called from the door interface *****************
- * *****************************************************************************
- *
+ * Enumerate objects within the server.  The svcenum provides the
+ * enumeration context, i.e. what the caller want to get back.
+ */
+int
+smb_server_enum(smb_ioc_svcenum_t *ioc)
+{
+	smb_svcenum_t		*svcenum = &ioc->svcenum;
+	smb_server_t		*sv;
+	smb_session_list_t	*se;
+	int			rc;
+
+	switch (svcenum->se_type) {
+	case SMB_SVCENUM_TYPE_USER:
+	case SMB_SVCENUM_TYPE_TREE:
+	case SMB_SVCENUM_TYPE_FILE:
+		break;
+	default:
+		return (EINVAL);
+	}
+
+	if ((rc = smb_server_lookup(&sv)) != 0)
+		return (rc);
+
+	svcenum->se_bavail = svcenum->se_buflen;
+	svcenum->se_bused = 0;
+	svcenum->se_nitems = 0;
+
+	se = &sv->sv_nbt_daemon.ld_session_list;
+	smb_server_enum_private(se, svcenum);
+
+	se = &sv->sv_tcp_daemon.ld_session_list;
+	smb_server_enum_private(se, svcenum);
+
+	smb_server_release(sv);
+	return (0);
+}
+
+/*
+ * Look for sessions to disconnect by client and user name.
+ */
+int
+smb_server_session_close(smb_ioc_session_t *ioc)
+{
+	smb_session_list_t	*se;
+	smb_server_t		*sv;
+	int			nbt_cnt;
+	int			tcp_cnt;
+	int			rc;
+
+	if ((rc = smb_server_lookup(&sv)) != 0)
+		return (rc);
+
+	se = &sv->sv_nbt_daemon.ld_session_list;
+	nbt_cnt = smb_server_sesion_disconnect(se, ioc->client, ioc->username);
+
+	se = &sv->sv_tcp_daemon.ld_session_list;
+	tcp_cnt = smb_server_sesion_disconnect(se, ioc->client, ioc->username);
+
+	smb_server_release(sv);
+
+	if ((nbt_cnt == 0) && (tcp_cnt == 0))
+		return (ENOENT);
+	return (0);
+}
+
+/*
+ * Close a file by uniqid.
+ */
+int
+smb_server_file_close(smb_ioc_fileid_t *ioc)
+{
+	uint32_t		uniqid = ioc->uniqid;
+	smb_session_list_t	*se;
+	smb_server_t		*sv;
+	int			rc;
+
+	if ((rc = smb_server_lookup(&sv)) != 0)
+		return (rc);
+
+	se = &sv->sv_nbt_daemon.ld_session_list;
+	rc = smb_server_fclose(se, uniqid);
+
+	if (rc == ENOENT) {
+		se = &sv->sv_tcp_daemon.ld_session_list;
+		rc = smb_server_fclose(se, uniqid);
+	}
+
+	smb_server_release(sv);
+	return (rc);
+}
+
+/*
  * These functions determine the relevant smb server to which the call apply.
  */
 
 uint32_t
-smb_server_get_user_count(void)
-{
-	smb_server_t	*sv;
-	uint32_t	counter = 0;
-
-	if (smb_server_lookup(&sv) == 0) {
-		counter = (uint32_t)sv->sv_open_users;
-		smb_server_release(sv);
-	}
-
-	return (counter);
-}
-
-uint32_t
 smb_server_get_session_count(void)
 {
 	smb_server_t	*sv;
@@ -1422,51 +1468,140 @@
 	mutex_exit(&sv->sv_mutex);
 }
 
-static int
-smb_server_ulist_geti(smb_session_list_t *se, uint32_t cookie,
-    uint8_t *buf, uint32_t buf_len, uint_t *pbe)
+/*
+ * Enumerate the users associated with a session list.
+ */
+static void
+smb_server_enum_private(smb_session_list_t *se, smb_svcenum_t *svcenum)
 {
-	smb_session_t *sn = NULL;
-	smb_user_t *user;
-	smb_llist_t *ulist;
-	smb_opipe_context_t ctx;
-	uint_t bytes_encoded;
-	int rc = 0;
-	int cnt = 0;
+	smb_session_t	*sn;
+	smb_llist_t	*ulist;
+	smb_user_t	*user;
+	int		rc = 0;
 
 	rw_enter(&se->se_lock, RW_READER);
 	sn = list_head(&se->se_act.lst);
-	while ((sn != NULL) && (rc == 0)) {
+
+	while (sn != NULL) {
 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
 		ulist = &sn->s_user_list;
 		smb_llist_enter(ulist, RW_READER);
 		user = smb_llist_head(ulist);
-		while ((user != NULL) && (rc == 0)) {
-			ASSERT(user->u_magic == SMB_USER_MAGIC);
-			mutex_enter(&user->u_mutex);
-			if ((user->u_state == SMB_USER_STATE_LOGGED_IN) &&
-			    (cookie == 0)) {
-				smb_user_context_init(user, &ctx);
-				rc = smb_opipe_context_encode(&ctx, buf,
-				    buf_len, &bytes_encoded);
-				smb_user_context_fini(&ctx);
-				if (rc == 0) {
-					*pbe += bytes_encoded;
-					buf += bytes_encoded;
-					buf_len -= bytes_encoded;
-					cnt++;
+
+		while (user != NULL) {
+			if (smb_user_hold(user)) {
+				rc = smb_user_enum(user, svcenum);
+				smb_user_release(user);
+			}
+
+			user = smb_llist_next(ulist, user);
+		}
+
+		smb_llist_exit(ulist);
+
+		if (rc != 0)
+			break;
+
+		sn = list_next(&se->se_act.lst, sn);
+	}
+
+	rw_exit(&se->se_lock);
+}
+
+/*
+ * Disconnect sessions associated with the specified client and username.
+ * Empty strings are treated as wildcards.
+ */
+static int
+smb_server_sesion_disconnect(smb_session_list_t *se,
+    const char *client, const char *name)
+{
+	smb_session_t	*sn;
+	smb_llist_t	*ulist;
+	smb_user_t	*user;
+	boolean_t	match;
+	int		count = 0;
+
+	rw_enter(&se->se_lock, RW_READER);
+	sn = list_head(&se->se_act.lst);
+
+	while (sn != NULL) {
+		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
+
+		if ((*client != '\0') && (!smb_session_isclient(sn, client))) {
+			sn = list_next(&se->se_act.lst, sn);
+			continue;
+		}
+
+		ulist = &sn->s_user_list;
+		smb_llist_enter(ulist, RW_READER);
+		user = smb_llist_head(ulist);
+
+		while (user != NULL) {
+			if (smb_user_hold(user)) {
+				match = (*name == '\0');
+				if (!match)
+					match = smb_user_namecmp(user, name);
+
+				if (match) {
+					smb_llist_exit(ulist);
+					smb_user_logoff(user);
+					++count;
+					smb_user_release(user);
+					smb_llist_enter(ulist, RW_READER);
+					user = smb_llist_head(ulist);
+					continue;
 				}
+
+				smb_user_release(user);
 			}
-			mutex_exit(&user->u_mutex);
+
 			user = smb_llist_next(ulist, user);
-			if (cookie > 0)
-				cookie--;
 		}
+
 		smb_llist_exit(ulist);
 		sn = list_next(&se->se_act.lst, sn);
 	}
+
 	rw_exit(&se->se_lock);
-	return (cnt);
+	return (count);
+}
+
+/*
+ * Close a file by its unique id.
+ */
+static int
+smb_server_fclose(smb_session_list_t *se, uint32_t uniqid)
+{
+	smb_session_t	*sn;
+	smb_llist_t	*ulist;
+	smb_user_t	*user;
+	int		rc = ENOENT;
+
+	rw_enter(&se->se_lock, RW_READER);
+	sn = list_head(&se->se_act.lst);
+
+	while ((sn != NULL) && (rc == ENOENT)) {
+		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
+		ulist = &sn->s_user_list;
+		smb_llist_enter(ulist, RW_READER);
+		user = smb_llist_head(ulist);
+
+		while ((user != NULL) && (rc == ENOENT)) {
+			if (smb_user_hold(user)) {
+				rc = smb_user_fclose(user, uniqid);
+				smb_user_release(user);
+			}
+
+			user = smb_llist_next(ulist, user);
+		}
+
+		smb_llist_exit(ulist);
+		sn = list_next(&se->se_act.lst, sn);
+	}
+
+	rw_exit(&se->se_lock);
+	return (rc);
 }
 
 static void
--- a/usr/src/uts/common/fs/smbsrv/smb_session.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_session.c	Mon Jul 20 13:07:46 2009 -0400
@@ -1041,13 +1041,8 @@
 		ASSERT(user->u_magic == SMB_USER_MAGIC);
 		if (!utf8_strcasecmp(user->u_name, name) &&
 		    !utf8_strcasecmp(user->u_domain, domain)) {
-			mutex_enter(&user->u_mutex);
-			if (user->u_state == SMB_USER_STATE_LOGGED_IN) {
-				user->u_refcnt++;
-				mutex_exit(&user->u_mutex);
+			if (smb_user_hold(user))
 				break;
-			}
-			mutex_exit(&user->u_mutex);
 		}
 		user = smb_llist_next(ulist, user);
 	}
@@ -1084,6 +1079,64 @@
 }
 
 /*
+ * Copy the session workstation/client name to buf.  If the workstation
+ * is an empty string (which it will be on TCP connections), use the
+ * client IP address.
+ */
+void
+smb_session_getclient(smb_session_t *sn, char *buf, size_t buflen)
+{
+	char		ipbuf[INET6_ADDRSTRLEN];
+	smb_inaddr_t	*ipaddr;
+
+	ASSERT(sn);
+	ASSERT(buf);
+	ASSERT(buflen);
+
+	*buf = '\0';
+
+	if (sn->workstation[0] != '\0') {
+		(void) strlcpy(buf, sn->workstation, buflen);
+		return;
+	}
+
+	ipaddr = &sn->ipaddr;
+	if (smb_inet_ntop(ipaddr, ipbuf, SMB_IPSTRLEN(ipaddr->a_family)))
+		(void) strlcpy(buf, ipbuf, buflen);
+}
+
+/*
+ * Check whether or not the specified client name is the client of this
+ * session.  The name may be in UNC format (\\CLIENT).
+ *
+ * A workstation/client name is setup on NBT connections as part of the
+ * NetBIOS session request but that isn't available on TCP connections.
+ * If the session doesn't have a client name we typically return the
+ * client IP address as the workstation name on MSRPC requests.  So we
+ * check for the IP address here in addition to the workstation name.
+ */
+boolean_t
+smb_session_isclient(smb_session_t *sn, const char *client)
+{
+	char		buf[INET6_ADDRSTRLEN];
+	smb_inaddr_t	*ipaddr;
+
+	client += strspn(client, "\\");
+
+	if (utf8_strcasecmp(client, sn->workstation) == 0)
+		return (B_TRUE);
+
+	ipaddr = &sn->ipaddr;
+	if (smb_inet_ntop(ipaddr, buf, SMB_IPSTRLEN(ipaddr->a_family)) == NULL)
+		return (B_FALSE);
+
+	if (utf8_strcasecmp(client, buf) == 0)
+		return (B_TRUE);
+
+	return (B_FALSE);
+}
+
+/*
  * smb_request_alloc
  *
  * Allocate an smb_request_t structure from the kmem_cache.  Partially
@@ -1171,7 +1224,7 @@
 void
 dump_smb_inaddr(smb_inaddr_t *ipaddr)
 {
-char ipstr[INET6_ADDRSTRLEN];
+	char ipstr[INET6_ADDRSTRLEN];
 
 	if (smb_inet_ntop(ipaddr, ipstr, SMB_IPSTRLEN(ipaddr->a_family)))
 		cmn_err(CE_WARN, "error ipstr=%s", ipstr);
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c	Mon Jul 20 13:07:46 2009 -0400
@@ -519,8 +519,12 @@
 	if (count != 0)
 		smb_odir_save_cookie(od, 0, cookie);
 
-	/* if eos not already detected, check if more entries */
-	if (!*eos)
+	/*
+	 * If all retrieved entries have been successfully encoded
+	 * and eos has not already been detected, check if there are
+	 * any more entries. eos will be set if there are no more.
+	 */
+	if ((rc == 0) && (!*eos))
 		(void) smb_odir_read_fileinfo(sr, od, &fileinfo, eos);
 
 	return (count);
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c	Mon Jul 20 13:07:46 2009 -0400
@@ -52,6 +52,8 @@
 #include <smbsrv/smb_fsops.h>
 
 uint32_t smb_pad_align(uint32_t offset, uint32_t align);
+void smb_encode_smb_datetimes(smb_request_t *, smb_xa_t *, smb_attr_t *);
+void smb_encode_nt_times(smb_request_t *, smb_xa_t *, smb_attr_t *);
 extern int smb_query_all_info_filename(smb_tree_t *, smb_node_t *,
     char *, size_t);
 
@@ -80,11 +82,10 @@
 	u_offset_t	datasz = 0, allocsz = 0;
 	smb_attr_t	*ap = NULL;
 	char		*namep = NULL;
-	char		*filename = NULL, *alt_nm_ptr = NULL;
+	char		*filename = NULL;
 	int		filename_len = 0;
 	smb_node_t	*node = NULL; /* only set for SMB_FTYPE_DISK files */
-	smb_node_t	*dir_snode = NULL;
-	timestruc_t	*creation_time = NULL;
+	smb_node_t	*dnode = NULL;
 	unsigned char	delete_on_close = 0;
 	unsigned char	is_dir = 0;
 	char		*filebuf = NULL;
@@ -133,7 +134,6 @@
 		}
 
 		dattr = ap->sa_dosattr;
-		creation_time = &ap->sa_crtime;
 
 		if (smb_node_is_dir(node)) {
 			is_dir = 1;
@@ -144,31 +144,55 @@
 			allocsz = ap->sa_vattr.va_nblocks * DEV_BSIZE;
 		}
 
-		dir_snode = node->dir_snode;
+		dnode = node->n_dnode;
 		delete_on_close =
 		    (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
+
+		/*
+		 * The number of links reported should be the number of
+		 * non-deleted links. Thus if delete_on_close is set,
+		 * decrement the link count.
+		 */
+		if (delete_on_close && ap->sa_vattr.va_nlink > 0)
+			--(ap->sa_vattr.va_nlink);
+
 		}
 		break;
 
 	case SMB_FTYPE_MESG_PIPE:
 		{
-		/*
-		 * The pipe is only valid for SMB_FTYPE_MESG_PIPE files.
-		 */
+		/* The pipe is only valid for SMB_FTYPE_MESG_PIPE files */
 		namep = sr->fid_ofile->f_pipe->p_name;
 		filename = namep;
 		filename_len = smb_ascii_or_unicode_strlen(sr, filename);
 
 		ap = &pipe_attr;
-		creation_time = (timestruc_t *)&ap->sa_vattr.va_ctime;
+		ap->sa_vattr.va_nlink = 1;
 		dattr = FILE_ATTRIBUTE_NORMAL;
 		datasz = allocsz = 0;
 
-		delete_on_close = 0;
+		delete_on_close = 1;
 		is_dir = 0;
+
+		/* some levels are not valid for pipes */
+		switch (infolev) {
+		case SMB_QUERY_FILE_ALT_NAME_INFO:
+		case SMB_FILE_ALT_NAME_INFORMATION:
+		case SMB_QUERY_FILE_STREAM_INFO:
+		case SMB_FILE_STREAM_INFORMATION:
+		case SMB_QUERY_FILE_COMPRESSION_INFO:
+		case SMB_FILE_COMPRESSION_INFORMATION:
+		case SMB_FILE_ATTR_TAG_INFORMATION:
+			smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+			    ERRDOS, ERROR_INVALID_PARAMETER);
+			return (SDRC_ERROR);
+		case SMB_INFO_QUERY_ALL_EAS:
+			smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+			    ERRDOS, ERROR_ACCESS_DENIED);
+			return (SDRC_ERROR);
+		}
 		}
 		break;
-
 	default:
 		smbsr_error(sr, 0, ERRDOS, ERRbadfile);
 		return (SDRC_ERROR);
@@ -188,16 +212,14 @@
 		if (allocsz > UINT_MAX)
 			allocsz = UINT_MAX;
 
+		/* unlike other levels attributes should be 0 here for pipes */
+		if (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)
+			dattr = 0;
+
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
-		(void) smb_mbc_encodef(&xa->rep_data_mb,
-		    ((sr->session->native_os == NATIVE_OS_WIN95)
-		    ? "YYYllw" : "yyyllw"),
-		    smb_gmt2local(sr, creation_time->tv_sec),
-		    smb_gmt2local(sr, ap->sa_vattr.va_atime.tv_sec),
-		    smb_gmt2local(sr, ap->sa_vattr.va_mtime.tv_sec),
-		    (uint32_t)datasz,
-		    (uint32_t)allocsz,
-		    dattr);
+		smb_encode_smb_datetimes(sr, xa, ap);
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "llw",
+		    (uint32_t)datasz, (uint32_t)allocsz, dattr);
 		break;
 
 	case SMB_INFO_QUERY_EA_SIZE:
@@ -206,20 +228,18 @@
 		if (allocsz > UINT_MAX)
 			allocsz = UINT_MAX;
 
+		/* unlike other levels attributes should be 0 here for pipes */
+		if (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)
+			dattr = 0;
+
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
-		(void) smb_mbc_encodef(&xa->rep_data_mb,
-		    ((sr->session->native_os == NATIVE_OS_WIN95)
-		    ? "YYYllwl" : "yyyllwl"),
-		    smb_gmt2local(sr, creation_time->tv_sec),
-		    smb_gmt2local(sr, ap->sa_vattr.va_atime.tv_sec),
-		    smb_gmt2local(sr, ap->sa_vattr.va_mtime.tv_sec),
-		    (uint32_t)datasz,
-		    (uint32_t)allocsz,
-		    dattr, 0);
+		smb_encode_smb_datetimes(sr, xa, ap);
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "llwl",
+		    (uint32_t)datasz, (uint32_t)allocsz, dattr, 0);
 		break;
 
+	case SMB_INFO_QUERY_ALL_EAS:
 	case SMB_INFO_QUERY_EAS_FROM_LIST:
-	case SMB_INFO_QUERY_ALL_EAS:
 	case SMB_FILE_EA_INFORMATION:
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
@@ -236,12 +256,8 @@
 		 * Similar change in smb_trans2_query_path_information.c.
 		 */
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
-		(void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.",
-		    creation_time,
-		    &ap->sa_vattr.va_atime,
-		    &ap->sa_vattr.va_mtime,
-		    &ap->sa_vattr.va_ctime,
-		    dattr);
+		smb_encode_nt_times(sr, xa, ap);
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "w6.", dattr);
 		break;
 
 	case SMB_QUERY_FILE_STANDARD_INFO:
@@ -294,19 +310,28 @@
 
 	case SMB_QUERY_FILE_ALL_INFO:
 	case SMB_FILE_ALL_INFORMATION:
+		if (sr->fid_ofile->f_ftype == SMB_FTYPE_DISK) {
+			rc = smb_query_all_info_filename(sr->tid_tree, node,
+			    filebuf, MAXPATHLEN);
+			if (rc != 0) {
+				smbsr_errno(sr, rc);
+				kmem_free(filebuf, MAXPATHLEN+1);
+				return (SDRC_ERROR);
+			}
+			filename = filebuf;
+		} else {
+			/* If the leading \ is missing, add it. */
+			if (*namep != '\\') {
+				(void) snprintf(filebuf, MAXNAMELEN,
+				    "\\%s", namep);
+				filename = filebuf;
+			}
+		}
+		filename_len = smb_ascii_or_unicode_strlen(sr, filename);
+
 		/*
-		 * The reply of this information level on the
-		 * wire doesn't match with protocol specification.
-		 * This is what spec. needs: "TTTTwqqlbbqllqqll"
-		 * But this is actually is sent on the wire:
-		 * "TTTTw6.qqlbb2.l"
-		 * So, there is a 6-byte pad between Attributes and
-		 * AllocationSize. Also there is a 2-byte pad After
-		 * Directory field. Between Directory and FileNameLength
-		 * there is just 4 bytes that it seems is AlignmentRequirement.
-		 * There are 6 other fields between Directory and
-		 * AlignmentRequirement in spec. that aren't sent
-		 * on the wire.
+		 * There is a 6-byte pad between Attributes and AllocationSize,
+		 * and a 2-byte pad after the Directory field.
 		 */
 		if (node) {
 			rc = smb_query_all_info_filename(sr->tid_tree, node,
@@ -322,11 +347,8 @@
 		}
 
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
-		(void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
-		    creation_time,
-		    &ap->sa_vattr.va_atime,
-		    &ap->sa_vattr.va_mtime,
-		    &ap->sa_vattr.va_ctime,
+		smb_encode_nt_times(sr, xa, ap);
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "w6.qqlbb2.l",
 		    dattr,
 		    (uint64_t)allocsz,
 		    (uint64_t)datasz,
@@ -342,43 +364,41 @@
 	case SMB_QUERY_FILE_ALT_NAME_INFO:
 	case SMB_FILE_ALT_NAME_INFORMATION:
 		/*
-		 * Conform to the rule used by Windows NT/2003 servers.
-		 * Shortname is created only if either the filename or
-		 * extension portion of a file is made up of mixed case.
-		 *
-		 * If the shortname is generated, it will be returned as
-		 * the alternative name.  Otherwise, convert the original
-		 * name to all upper-case and return it as the alternative
-		 * name.
+		 * If the shortname is generated by smb_mangle_name()
+		 * it will be returned as the alternative name.
+		 * Otherwise, convert the original name to  upper-case
+		 * and return it as the alternative name.
 		 */
 		(void) smb_mangle_name(ap->sa_vattr.va_nodeid,
 		    filename, short_name, name83, 0);
-		alt_nm_ptr = (*short_name == 0) ?
-		    utf8_strupr(filename) : short_name;
+		if (*short_name == 0) {
+			(void) strlcpy(short_name, filename, SMB_SHORTNAMELEN);
+			(void) utf8_strupr(short_name);
+		}
+
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
-		    mts_wcequiv_strlen(alt_nm_ptr), alt_nm_ptr);
+		    mts_wcequiv_strlen(short_name), short_name);
 		break;
 
 	case SMB_QUERY_FILE_STREAM_INFO:
 	case SMB_FILE_STREAM_INFORMATION:
 		{
 		struct smb_node *node = sr->fid_ofile->f_node;
-		if (dir_snode == NULL) {
+		if (dnode == NULL) {
 			kmem_free(filebuf, MAXPATHLEN+1);
 			smbsr_error(sr, 0, ERRDOS, ERRbadfile);
 			return (SDRC_ERROR);
 		}
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 		if (SMB_IS_STREAM(node)) {
-			ASSERT(node->unnamed_stream_node);
-			ASSERT(node->unnamed_stream_node->n_magic ==
-			    SMB_NODE_MAGIC);
-			ASSERT(node->unnamed_stream_node->n_state !=
+			ASSERT(node->n_unode);
+			ASSERT(node->n_unode->n_magic == SMB_NODE_MAGIC);
+			ASSERT(node->n_unode->n_state !=
 			    SMB_NODE_STATE_DESTROYING);
 
 			(void) smb_encode_stream_info(sr, xa,
-			    node->unnamed_stream_node, ap);
+			    node->n_unode, ap);
 		} else {
 			(void) smb_encode_stream_info(sr, xa, node, ap);
 		}
@@ -572,3 +592,45 @@
 
 	return (pad);
 }
+
+/*
+ * smb_encode_smb_datetimes
+ *
+ * Encode timestamps in the SMB_DATE / SMB_TIME format.
+ */
+void
+smb_encode_smb_datetimes(smb_request_t *sr, smb_xa_t *xa, smb_attr_t *attr)
+{
+	if ((sr->fid_ofile) &&
+	    (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)) {
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "lll", 0, 0, 0);
+		return;
+	}
+
+	(void) smb_mbc_encodef(&xa->rep_data_mb,
+	    ((sr->session->native_os == NATIVE_OS_WIN95) ? "YYY" : "yyy"),
+	    smb_gmt2local(sr, attr->sa_crtime.tv_sec),
+	    smb_gmt2local(sr, attr->sa_vattr.va_atime.tv_sec),
+	    smb_gmt2local(sr, attr->sa_vattr.va_mtime.tv_sec));
+}
+
+/*
+ * smb_encode_nt_times
+ *
+ * Encode timestamps in LARGE INTEGER format NT Times.
+ */
+void
+smb_encode_nt_times(smb_request_t *sr, smb_xa_t *xa, smb_attr_t *attr)
+{
+	if ((sr->fid_ofile) &&
+	    (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)) {
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "qqqq", 0, 0, 0, 0);
+		return;
+	}
+
+	(void) smb_mbc_encodef(&xa->rep_data_mb, "TTTT",
+	    &attr->sa_crtime,
+	    &attr->sa_vattr.va_atime,
+	    &attr->sa_vattr.va_mtime,
+	    &attr->sa_vattr.va_ctime);
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c	Mon Jul 20 13:07:46 2009 -0400
@@ -322,6 +322,8 @@
 #include <smbsrv/smb_fsops.h>
 
 int smb_query_all_info_filename(smb_tree_t *, smb_node_t *, char *, size_t);
+extern void smb_encode_smb_datetimes(smb_request_t *, smb_xa_t *, smb_attr_t *);
+extern void smb_encode_nt_times(smb_request_t *, smb_xa_t *, smb_attr_t *);
 
 /*
  * Function: int smb_com_trans2_query_path_information(struct smb_request *)
@@ -340,11 +342,12 @@
 	char			short_name[SMB_SHORTNAMELEN];
 	char			name83[SMB_SHORTNAMELEN];
 	unsigned char		is_dir;
+	unsigned char		delete_on_close;
 	int			len;
 
 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
-		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
-		    ERROR_ACCESS_DENIED);
+		smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST, ERRDOS,
+		    ERROR_INVALID_FUNCTION);
 		return (SDRC_ERROR);
 	}
 
@@ -422,6 +425,18 @@
 		allocsz = ap->sa_vattr.va_nblocks * DEV_BSIZE;
 	}
 
+	delete_on_close =
+	    (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
+
+	/*
+	 * The number of links reported should be the number of
+	 * non-deleted links. Thus if delete_on_close is set,
+	 * decrement the link count.
+	 */
+	if (delete_on_close && ap->sa_vattr.va_nlink > 0)
+		--(ap->sa_vattr.va_nlink);
+
+
 
 	switch (infolev) {
 	case SMB_INFO_STANDARD:
@@ -431,15 +446,9 @@
 			allocsz = UINT_MAX;
 
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
-		(void) smb_mbc_encodef(&xa->rep_data_mb,
-		    ((sr->session->native_os == NATIVE_OS_WIN95)
-		    ? "YYYllw" : "yyyllw"),
-		    smb_gmt2local(sr, ap->sa_crtime.tv_sec),
-		    smb_gmt2local(sr, ap->sa_vattr.va_atime.tv_sec),
-		    smb_gmt2local(sr, ap->sa_vattr.va_mtime.tv_sec),
-		    (uint32_t)datasz,
-		    (uint32_t)allocsz,
-		    dattr);
+		smb_encode_smb_datetimes(sr, xa, ap);
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "llw",
+		    (uint32_t)datasz, (uint32_t)allocsz, dattr);
 		break;
 
 	case SMB_INFO_QUERY_EA_SIZE:
@@ -449,15 +458,9 @@
 			allocsz = UINT_MAX;
 
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
-		(void) smb_mbc_encodef(&xa->rep_data_mb,
-		    ((sr->session->native_os == NATIVE_OS_WIN95)
-		    ? "YYYllwl" : "yyyllwl"),
-		    smb_gmt2local(sr, ap->sa_crtime.tv_sec),
-		    smb_gmt2local(sr, ap->sa_vattr.va_atime.tv_sec),
-		    smb_gmt2local(sr, ap->sa_vattr.va_mtime.tv_sec),
-		    (uint32_t)datasz,
-		    (uint32_t)allocsz,
-		    dattr, 0);
+		smb_encode_smb_datetimes(sr, xa, ap);
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "llwl",
+		    (uint32_t)datasz, (uint32_t)allocsz, dattr, 0);
 		break;
 
 	case SMB_INFO_QUERY_EAS_FROM_LIST:
@@ -477,12 +480,8 @@
 		 * Similar change in smb_trans2_query_file_information.c.
 		 */
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
-		(void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.",
-		    &ap->sa_crtime,
-		    &ap->sa_vattr.va_atime,
-		    &ap->sa_vattr.va_mtime,
-		    &ap->sa_vattr.va_ctime,
-		    dattr);
+		smb_encode_nt_times(sr, xa, ap);
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "w6.", dattr);
 		break;
 
 	case SMB_QUERY_FILE_STANDARD_INFO:
@@ -496,7 +495,7 @@
 		    (uint64_t)allocsz,
 		    (uint64_t)datasz,
 		    ap->sa_vattr.va_nlink,
-		    (node && (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0),
+		    delete_on_close,
 		    (char)(ap->sa_vattr.va_type == VDIR));
 		break;
 
@@ -520,19 +519,18 @@
 
 	case SMB_QUERY_FILE_ALL_INFO:
 	case SMB_FILE_ALL_INFORMATION:
+		rc = smb_query_all_info_filename(sr->tid_tree, node,
+		    name, MAXPATHLEN);
+		if (rc != 0) {
+			smbsr_errno(sr, rc);
+			smb_node_release(node);
+			kmem_free(name, MAXPATHLEN);
+			return (SDRC_ERROR);
+		}
+
 		/*
-		 * The reply of this information level on the
-		 * wire doesn't match with protocol specification.
-		 * This is what spec. needs: "TTTTwqqlbbqllqqll"
-		 * But this is actually is sent on the wire:
-		 * "TTTTw6.qqlbb2.l"
-		 * So, there is a 6-byte pad between Attributes and
-		 * AllocationSize. Also there is a 2-byte pad After
-		 * Directory field. Between Directory and FileNameLength
-		 * there is just 4 bytes that it seems is AlignmentRequirement.
-		 * There are 6 other fields between Directory and
-		 * AlignmentRequirement in spec. that aren't sent
-		 * on the wire.
+		 * There is a 6-byte pad between Attributes and AllocationSize,
+		 * and a 2-byte pad after the Directory field.
 		 */
 		rc = smb_query_all_info_filename(sr->tid_tree, node,
 		    name, MAXPATHLEN);
@@ -544,11 +542,8 @@
 		}
 
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
-		(void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
-		    &ap->sa_crtime,
-		    &ap->sa_vattr.va_atime,
-		    &ap->sa_vattr.va_mtime,
-		    &ap->sa_vattr.va_ctime,
+		smb_encode_nt_times(sr, xa, ap);
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "w6.qqlbb2.l",
 		    dattr,
 		    (uint64_t)allocsz,
 		    (uint64_t)datasz,
@@ -564,14 +559,10 @@
 	case SMB_QUERY_FILE_ALT_NAME_INFO:
 	case SMB_FILE_ALT_NAME_INFORMATION:
 		/*
-		 * Conform to the rule used by Windows NT/2003 servers.
-		 * Shortname is created only if either the filename or
-		 * extension portion of a file is made up of mixed case.
-		 *
-		 * If the shortname is generated, it will be returned as
-		 * the alternative name.  Otherwise, convert the original
-		 * name to all upper-case and return it as the alternative
-		 * name.
+		 * If the shortname is generated by smb_mangle_name()
+		 * it will be returned as the alternative name.
+		 * Otherwise, convert the original name to  upper-case
+		 * and return it as the alternative name.
 		 */
 		(void) smb_mangle_name(ap->sa_vattr.va_nodeid,
 		    name, short_name, name83, 0);
@@ -656,7 +647,7 @@
 	buflen -= len;
 
 	if (SMB_IS_STREAM(node))
-		vp = node->unnamed_stream_node->vp;
+		vp = node->n_unode->vp;
 	else
 		vp = node->vp;
 
--- a/usr/src/uts/common/fs/smbsrv/smb_tree.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c	Mon Jul 20 13:07:46 2009 -0400
@@ -193,8 +193,13 @@
 static void smb_tree_get_flags(const smb_share_t *, vfs_t *, smb_tree_t *);
 static void smb_tree_log(smb_request_t *, const char *, const char *, ...);
 static void smb_tree_close_odirs(smb_tree_t *, uint16_t);
+static smb_ofile_t *smb_tree_get_ofile(smb_tree_t *, smb_ofile_t *);
 static smb_odir_t *smb_tree_get_odir(smb_tree_t *, smb_odir_t *);
 static void smb_tree_set_execsub_info(smb_tree_t *, smb_execsub_info_t *);
+static int smb_tree_enum_private(smb_tree_t *, smb_svcenum_t *);
+static int smb_tree_netinfo_encode(smb_tree_t *, uint8_t *, size_t, uint32_t *);
+static void smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *);
+static void smb_tree_netinfo_fini(smb_netconnectinfo_t *);
 
 /*
  * Extract the share name and share type and connect as appropriate.
@@ -362,8 +367,69 @@
 	return ((tree->t_flags & flags) == flags);
 }
 
+/*
+ * If the enumeration request is for tree data, handle the request
+ * here.  Otherwise, pass it on to the ofiles.
+ *
+ * This function should be called with a hold on the tree.
+ */
+int
+smb_tree_enum(smb_tree_t *tree, smb_svcenum_t *svcenum)
+{
+	smb_ofile_t	*of;
+	smb_ofile_t	*next;
+	int		rc;
+
+	ASSERT(tree);
+	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+	if (svcenum->se_type == SMB_SVCENUM_TYPE_TREE)
+		return (smb_tree_enum_private(tree, svcenum));
+
+	of = smb_tree_get_ofile(tree, NULL);
+	while (of) {
+		ASSERT(of->f_tree == tree);
+
+		rc = smb_ofile_enum(of, svcenum);
+		if (rc != 0) {
+			smb_ofile_release(of);
+			break;
+		}
+
+		next = smb_tree_get_ofile(tree, of);
+		smb_ofile_release(of);
+		of = next;
+	}
+
+	return (rc);
+}
+
+/*
+ * Close a file by its unique id.
+ */
+int
+smb_tree_fclose(smb_tree_t *tree, uint32_t uniqid)
+{
+	smb_ofile_t	*of;
+
+	ASSERT(tree);
+	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+	if ((of = smb_ofile_lookup_by_uniqid(tree, uniqid)) == NULL)
+		return (ENOENT);
+
+	if (smb_ofile_disallow_fclose(of)) {
+		smb_ofile_release(of);
+		return (EACCES);
+	}
+
+	smb_ofile_close(of, 0);
+	smb_ofile_release(of);
+	return (0);
+}
 
 /* *************************** Static Functions ***************************** */
+
 #define	SHARES_DIR	".zfs/shares/"
 static void
 smb_tree_acl_access(cred_t *cred, const char *sharename, vnode_t *pathvp,
@@ -434,7 +500,7 @@
 smb_tree_connect_disk(smb_request_t *sr, const char *sharename)
 {
 	smb_user_t		*user = sr->uid_user;
-	smb_node_t		*dir_snode = NULL;
+	smb_node_t		*dnode = NULL;
 	smb_node_t		*snode = NULL;
 	char			last_component[MAXNAMELEN];
 	smb_tree_t		*tree;
@@ -529,15 +595,15 @@
 	/*
 	 * Check that the shared directory exists.
 	 */
-	rc = smb_pathname_reduce(sr, u_cred, si->shr_path, 0, 0, &dir_snode,
+	rc = smb_pathname_reduce(sr, u_cred, si->shr_path, 0, 0, &dnode,
 	    last_component);
 
 	if (rc == 0) {
 		rc = smb_fsop_lookup(sr, u_cred, SMB_FOLLOW_LINKS,
-		    sr->sr_server->si_root_smb_node, dir_snode, last_component,
+		    sr->sr_server->si_root_smb_node, dnode, last_component,
 		    &snode);
 
-		smb_node_release(dir_snode);
+		smb_node_release(dnode);
 	}
 
 	if (rc) {
@@ -704,6 +770,7 @@
 	tree->t_state = SMB_TREE_STATE_CONNECTED;
 	tree->t_magic = SMB_TREE_MAGIC;
 	tree->t_access = access;
+	tree->t_connect_time = gethrestime_sec();
 
 	/* if FS is readonly, enforce that here */
 	if (tree->t_flags & SMB_TREE_READONLY)
@@ -1080,6 +1147,44 @@
 }
 
 /*
+ * Get the next open ofile in the list.  A reference is taken on
+ * the ofile, which can be released later with smb_ofile_release().
+ *
+ * If the specified ofile is NULL, search from the beginning of the
+ * list.  Otherwise, the search starts just after that ofile.
+ *
+ * Returns NULL if there are no open files in the list.
+ */
+static smb_ofile_t *
+smb_tree_get_ofile(smb_tree_t *tree, smb_ofile_t *of)
+{
+	smb_llist_t *ofile_list;
+
+	ASSERT(tree);
+	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+	ofile_list = &tree->t_ofile_list;
+	smb_llist_enter(ofile_list, RW_READER);
+
+	if (of) {
+		ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+		of = smb_llist_next(ofile_list, of);
+	} else {
+		of = smb_llist_head(ofile_list);
+	}
+
+	while (of) {
+		if (smb_ofile_hold(of))
+			break;
+
+		of = smb_llist_next(ofile_list, of);
+	}
+
+	smb_llist_exit(ofile_list);
+	return (of);
+}
+
+/*
  * smb_tree_get_odir
  *
  * Find the next odir in the tree's list of odirs, and obtain a
@@ -1157,3 +1262,96 @@
 		subs->e_cli_netbiosname = tree->t_session->workstation;
 		subs->e_uid = tree->t_user->u_cred->cr_uid;
 }
+
+/*
+ * Private function to support smb_tree_enum.
+ */
+static int
+smb_tree_enum_private(smb_tree_t *tree, smb_svcenum_t *svcenum)
+{
+	uint8_t *pb;
+	uint_t nbytes;
+	int rc;
+
+	if (svcenum->se_nskip > 0) {
+		svcenum->se_nskip--;
+		return (0);
+	}
+
+	if (svcenum->se_nitems >= svcenum->se_nlimit) {
+		svcenum->se_nitems = svcenum->se_nlimit;
+		return (0);
+	}
+
+	pb = &svcenum->se_buf[svcenum->se_bused];
+	rc = smb_tree_netinfo_encode(tree, pb, svcenum->se_bavail, &nbytes);
+	if (rc == 0) {
+		svcenum->se_bavail -= nbytes;
+		svcenum->se_bused += nbytes;
+		svcenum->se_nitems++;
+	}
+
+	return (rc);
+}
+
+/*
+ * Encode connection information into a buffer: connection information
+ * needed in user space to support RPC requests.
+ */
+static int
+smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen,
+    uint32_t *nbytes)
+{
+	smb_netconnectinfo_t	info;
+	int			rc;
+
+	smb_tree_netinfo_init(tree, &info);
+	rc = smb_netconnectinfo_encode(&info, buf, buflen, nbytes);
+	smb_tree_netinfo_fini(&info);
+
+	return (rc);
+}
+
+/*
+ * Note: ci_numusers should be the number of users connected to
+ * the share rather than the number of references on the tree but
+ * we don't have a mechanism to track users/share in smbsrv yet.
+ */
+static void
+smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info)
+{
+	smb_user_t	*user;
+
+	ASSERT(tree);
+
+	info->ci_id = tree->t_tid;
+	info->ci_type = tree->t_res_type;
+	info->ci_numopens = tree->t_open_files;
+	info->ci_numusers = tree->t_refcnt;
+	info->ci_time = gethrestime_sec() - tree->t_connect_time;
+
+	info->ci_sharelen = strlen(tree->t_sharename) + 1;
+	info->ci_share = smb_kstrdup(tree->t_sharename, info->ci_sharelen);
+
+	user = tree->t_user;
+	ASSERT(user);
+
+	info->ci_namelen = user->u_domain_len + user->u_name_len + 2;
+	info->ci_username = kmem_alloc(info->ci_namelen, KM_SLEEP);
+	(void) snprintf(info->ci_username, info->ci_namelen, "%s\\%s",
+	    user->u_domain, user->u_name);
+}
+
+static void
+smb_tree_netinfo_fini(smb_netconnectinfo_t *info)
+{
+	if (info == NULL)
+		return;
+
+	if (info->ci_username)
+		kmem_free(info->ci_username, info->ci_namelen);
+	if (info->ci_share)
+		kmem_free(info->ci_share, info->ci_sharelen);
+
+	bzero(info, sizeof (smb_netconnectinfo_t));
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_user.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_user.c	Mon Jul 20 13:07:46 2009 -0400
@@ -171,6 +171,8 @@
 
 static smb_sid_t *smb_admins_sid = NULL;
 
+static boolean_t smb_user_is_logged_in(smb_user_t *);
+static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *);
 static void smb_user_delete(smb_user_t *user);
 static smb_tree_t *smb_user_get_tree(smb_llist_t *, smb_tree_t *);
 
@@ -287,7 +289,8 @@
 /*
  * smb_user_logoff
  *
- *
+ * Change the user state and disconnect trees.
+ * The user list must not be entered or modified here.
  */
 void
 smb_user_logoff(
@@ -376,6 +379,27 @@
 }
 
 /*
+ * Take a reference on a user.
+ */
+boolean_t
+smb_user_hold(smb_user_t *user)
+{
+	ASSERT(user);
+	ASSERT(user->u_magic == SMB_USER_MAGIC);
+
+	mutex_enter(&user->u_mutex);
+
+	if (smb_user_is_logged_in(user)) {
+		user->u_refcnt++;
+		mutex_exit(&user->u_mutex);
+		return (B_TRUE);
+	}
+
+	mutex_exit(&user->u_mutex);
+	return (B_FALSE);
+}
+
+/*
  * smb_user_release
  *
  *
@@ -434,29 +458,10 @@
 		ASSERT(user->u_magic == SMB_USER_MAGIC);
 		ASSERT(user->u_session == session);
 		if (user->u_uid == uid) {
-			mutex_enter(&user->u_mutex);
-			switch (user->u_state) {
-
-			case SMB_USER_STATE_LOGGED_IN:
-				/* The user exists and is still logged in. */
-				user->u_refcnt++;
-				mutex_exit(&user->u_mutex);
+			if (smb_user_hold(user)) {
 				smb_llist_exit(&session->s_user_list);
 				return (user);
-
-			case SMB_USER_STATE_LOGGING_OFF:
-			case SMB_USER_STATE_LOGGED_OFF:
-				/*
-				 * The user exists but has logged off or is in
-				 * the process of logging off.
-				 */
-				mutex_exit(&user->u_mutex);
-				smb_llist_exit(&session->s_user_list);
-				return (NULL);
-
-			default:
-				ASSERT(0);
-				mutex_exit(&user->u_mutex);
+			} else {
 				smb_llist_exit(&session->s_user_list);
 				return (NULL);
 			}
@@ -499,17 +504,11 @@
 	while (next) {
 		ASSERT(next->u_magic == SMB_USER_MAGIC);
 		ASSERT(next->u_session == session);
-		mutex_enter(&next->u_mutex);
-		if (next->u_state == SMB_USER_STATE_LOGGED_IN) {
-			next->u_refcnt++;
-			mutex_exit(&next->u_mutex);
+
+		if (smb_user_hold(next))
 			break;
-		} else {
-			ASSERT((next->u_state == SMB_USER_STATE_LOGGING_OFF) ||
-			    (next->u_state == SMB_USER_STATE_LOGGED_OFF));
-			mutex_exit(&next->u_mutex);
-			next = smb_llist_next(lst, next);
-		}
+
+		next = smb_llist_next(lst, next);
 	}
 	smb_llist_exit(lst);
 
@@ -712,6 +711,40 @@
 }
 
 /*
+ * Close a file by its unique id.
+ */
+int
+smb_user_fclose(smb_user_t *user, uint32_t uniqid)
+{
+	smb_llist_t	*tree_list;
+	smb_tree_t	*tree;
+	int		rc = ENOENT;
+
+	ASSERT(user);
+	ASSERT(user->u_magic == SMB_USER_MAGIC);
+
+	tree_list = &user->u_tree_list;
+	ASSERT(tree_list);
+
+	smb_llist_enter(tree_list, RW_READER);
+	tree = smb_llist_head(tree_list);
+
+	while ((tree != NULL) && (rc == ENOENT)) {
+		ASSERT(tree->t_user == user);
+
+		if (smb_tree_hold(tree)) {
+			rc = smb_tree_fclose(tree, uniqid);
+			smb_tree_release(tree);
+		}
+
+		tree = smb_llist_next(tree_list, tree);
+	}
+
+	smb_llist_exit(tree_list);
+	return (rc);
+}
+
+/*
  * Determine whether or not the user is an administrator.
  * Members of the administrators group have administrative rights.
  */
@@ -734,9 +767,99 @@
 	return (B_FALSE);
 }
 
+/*
+ * This function should be called with a hold on the user.
+ */
+boolean_t
+smb_user_namecmp(smb_user_t *user, const char *name)
+{
+	char		*fq_name;
+	boolean_t	match;
+
+	if (utf8_strcasecmp(name, user->u_name) == 0)
+		return (B_TRUE);
+
+	fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+	(void) snprintf(fq_name, MAXNAMELEN, "%s\\%s",
+	    user->u_domain, user->u_name);
+
+	match = (utf8_strcasecmp(name, fq_name) == 0);
+	if (!match) {
+		(void) snprintf(fq_name, MAXNAMELEN, "%s@%s",
+		    user->u_name, user->u_domain);
+
+		match = (utf8_strcasecmp(name, fq_name) == 0);
+	}
+
+	kmem_free(fq_name, MAXNAMELEN);
+	return (match);
+}
+
+/*
+ * If the enumeration request is for user data, handle the request
+ * here.  Otherwise, pass it on to the trees.
+ *
+ * This function should be called with a hold on the user.
+ */
+int
+smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum)
+{
+	smb_tree_t	*tree;
+	smb_tree_t	*next;
+	int		rc;
+
+	ASSERT(user);
+	ASSERT(user->u_magic == SMB_USER_MAGIC);
+
+	if (svcenum->se_type == SMB_SVCENUM_TYPE_USER)
+		return (smb_user_enum_private(user, svcenum));
+
+	tree = smb_user_get_tree(&user->u_tree_list, NULL);
+	while (tree) {
+		ASSERT(tree->t_user == user);
+
+		rc = smb_tree_enum(tree, svcenum);
+		if (rc != 0) {
+			smb_tree_release(tree);
+			break;
+		}
+
+		next = smb_user_get_tree(&user->u_tree_list, tree);
+		smb_tree_release(tree);
+		tree = next;
+	}
+
+	return (rc);
+}
+
 /* *************************** Static Functions ***************************** */
 
 /*
+ * Determine whether or not a user is logged in.
+ * Typically, a reference can only be taken on a logged-in user.
+ *
+ * This is a private function and must be called with the user
+ * mutex held.
+ */
+static boolean_t
+smb_user_is_logged_in(smb_user_t *user)
+{
+	switch (user->u_state) {
+	case SMB_USER_STATE_LOGGED_IN:
+		return (B_TRUE);
+
+	case SMB_USER_STATE_LOGGING_OFF:
+	case SMB_USER_STATE_LOGGED_OFF:
+		return (B_FALSE);
+
+	default:
+		ASSERT(0);
+		return (B_FALSE);
+	}
+}
+
+/*
  * smb_user_delete
  */
 static void
@@ -821,3 +944,104 @@
 {
 	return ((user->u_privcred)? user->u_privcred : user->u_cred);
 }
+
+/*
+ * Private function to support smb_user_enum.
+ */
+static int
+smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum)
+{
+	uint8_t *pb;
+	uint_t nbytes;
+	int rc;
+
+	if (svcenum->se_nskip > 0) {
+		svcenum->se_nskip--;
+		return (0);
+	}
+
+	if (svcenum->se_nitems >= svcenum->se_nlimit) {
+		svcenum->se_nitems = svcenum->se_nlimit;
+		return (0);
+	}
+
+	pb = &svcenum->se_buf[svcenum->se_bused];
+	rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes);
+	if (rc == 0) {
+		svcenum->se_bavail -= nbytes;
+		svcenum->se_bused += nbytes;
+		svcenum->se_nitems++;
+	}
+
+	return (rc);
+}
+
+/*
+ * Encode the NetInfo for a user into a buffer.  NetInfo contains
+ * information that is often needed in user space to support RPC
+ * requests.
+ */
+int
+smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen,
+    uint32_t *nbytes)
+{
+	smb_netuserinfo_t	info;
+	int			rc;
+
+	smb_user_netinfo_init(user, &info);
+	rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes);
+	smb_user_netinfo_fini(&info);
+
+	return (rc);
+}
+
+void
+smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info)
+{
+	smb_session_t	*session;
+	char		*buf;
+
+	ASSERT(user);
+	ASSERT(user->u_domain);
+	ASSERT(user->u_name);
+
+	session = user->u_session;
+	ASSERT(session);
+	ASSERT(session->workstation);
+
+	info->ui_session_id = session->s_kid;
+	info->ui_native_os = session->native_os;
+	info->ui_ipaddr = session->ipaddr;
+	info->ui_numopens = session->s_file_cnt;
+	info->ui_uid = user->u_uid;
+	info->ui_logon_time = user->u_logon_time;
+	info->ui_flags = user->u_flags;
+
+	info->ui_domain_len = user->u_domain_len;
+	info->ui_domain = smb_kstrdup(user->u_domain, info->ui_domain_len);
+
+	info->ui_account_len = user->u_name_len;
+	info->ui_account = smb_kstrdup(user->u_name, info->ui_account_len);
+
+	buf = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+	smb_session_getclient(session, buf, MAXNAMELEN);
+	info->ui_workstation_len = strlen(buf) + 1;
+	info->ui_workstation = smb_kstrdup(buf, info->ui_workstation_len);
+	kmem_free(buf, MAXNAMELEN);
+}
+
+void
+smb_user_netinfo_fini(smb_netuserinfo_t *info)
+{
+	if (info == NULL)
+		return;
+
+	if (info->ui_domain)
+		kmem_free(info->ui_domain, info->ui_domain_len);
+	if (info->ui_account)
+		kmem_free(info->ui_account, info->ui_account_len);
+	if (info->ui_workstation)
+		kmem_free(info->ui_workstation, info->ui_workstation_len);
+
+	bzero(info, sizeof (smb_netuserinfo_t));
+}
--- a/usr/src/uts/common/fs/sockfs/sockcommon_sops.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/sockfs/sockcommon_sops.c	Mon Jul 20 13:07:46 2009 -0400
@@ -1129,6 +1129,8 @@
 		so->so_proto_props.sopp_rcvthresh = soppp->sopp_rcvthresh;
 	if (soppp->sopp_flags & SOCKOPT_MAXADDRLEN)
 		so->so_proto_props.sopp_maxaddrlen = soppp->sopp_maxaddrlen;
+	if (soppp->sopp_flags & SOCKOPT_LOOPBACK)
+		so->so_proto_props.sopp_loopback = soppp->sopp_loopback;
 
 	mutex_exit(&so->so_lock);
 
@@ -1136,7 +1138,8 @@
 	soppp->sopp_flags &= ~(SOCKOPT_MAXBLK | SOCKOPT_WROFF | SOCKOPT_TAIL |
 	    SOCKOPT_RCVHIWAT | SOCKOPT_RCVLOWAT | SOCKOPT_MAXPSZ |
 	    SOCKOPT_ZCOPY | SOCKOPT_OOBINLINE | SOCKOPT_RCVTIMER |
-	    SOCKOPT_RCVTHRESH | SOCKOPT_MAXADDRLEN | SOCKOPT_MINPSZ);
+	    SOCKOPT_RCVTHRESH | SOCKOPT_MAXADDRLEN | SOCKOPT_MINPSZ |
+	    SOCKOPT_LOOPBACK);
 	ASSERT(soppp->sopp_flags == 0);
 #endif
 }
--- a/usr/src/uts/common/fs/sockfs/sodirect.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/sockfs/sodirect.c	Mon Jul 20 13:07:46 2009 -0400
@@ -78,6 +78,7 @@
 	if (uiop->uio_resid >= uioasync.mincnt &&
 	    sodp != NULL && sodp->sod_enabled &&
 	    uioasync.enabled && !(flags & MSG_PEEK) &&
+	    !so->so_proto_props.sopp_loopback &&
 	    !(so->so_state & SS_CANTRCVMORE)) {
 		/*
 		 * Big enough I/O for uioa min setup and an sodirect socket
--- a/usr/src/uts/common/fs/zfs/spa.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/zfs/spa.c	Mon Jul 20 13:07:46 2009 -0400
@@ -1574,9 +1574,12 @@
 		/*
 		 * If the config cache is stale, or we have uninitialized
 		 * metaslabs (see spa_vdev_add()), then update the config.
+		 *
+		 * If spa_load_verbatim is true, trust the current
+		 * in-core spa_config and update the disk labels.
 		 */
 		if (config_cache_txg != spa->spa_config_txg ||
-		    state == SPA_LOAD_IMPORT)
+		    state == SPA_LOAD_IMPORT || spa->spa_load_verbatim)
 			need_update = B_TRUE;
 
 		for (int c = 0; c < rvd->vdev_children; c++)
@@ -2405,6 +2408,7 @@
 
 	spa = spa_add(pname, NULL);
 	spa->spa_is_root = B_TRUE;
+	spa->spa_load_verbatim = B_TRUE;
 
 	/*
 	 * Build up a vdev tree based on the boot device's label config.
@@ -2493,7 +2497,7 @@
 	    zpool_prop_to_name(ZPOOL_PROP_ALTROOT), &altroot);
 	spa = spa_add(pool, altroot);
 
-	spa->spa_inactive_states_ok = B_TRUE;
+	spa->spa_load_verbatim = B_TRUE;
 
 	VERIFY(nvlist_dup(config, &spa->spa_config, 0) == 0);
 
@@ -2629,7 +2633,7 @@
 		/*
 		 * Update the config cache to include the newly-imported pool.
 		 */
-		spa_config_update_common(spa, SPA_CONFIG_UPDATE_POOL, B_FALSE);
+		spa_config_update(spa, SPA_CONFIG_UPDATE_POOL);
 	}
 
 	/*
--- a/usr/src/uts/common/fs/zfs/spa_config.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/zfs/spa_config.c	Mon Jul 20 13:07:46 2009 -0400
@@ -394,23 +394,12 @@
 }
 
 /*
- * For a pool that's not currently a booting rootpool, update all disk labels,
- * generate a fresh config based on the current in-core state, and sync the
- * global config cache.
- */
-void
-spa_config_update(spa_t *spa, int what)
-{
-	spa_config_update_common(spa, what, FALSE);
-}
-
-/*
  * Update all disk labels, generate a fresh config based on the current
  * in-core state, and sync the global config cache (do not sync the config
  * cache if this is a booting rootpool).
  */
 void
-spa_config_update_common(spa_t *spa, int what, boolean_t isroot)
+spa_config_update(spa_t *spa, int what)
 {
 	vdev_t *rvd = spa->spa_root_vdev;
 	uint64_t txg;
@@ -447,9 +436,9 @@
 	/*
 	 * Update the global config cache to reflect the new mosconfig.
 	 */
-	if (!isroot)
+	if (!spa->spa_is_root)
 		spa_config_sync(spa, B_FALSE, what != SPA_CONFIG_UPDATE_POOL);
 
 	if (what == SPA_CONFIG_UPDATE_POOL)
-		spa_config_update_common(spa, SPA_CONFIG_UPDATE_VDEVS, isroot);
+		spa_config_update(spa, SPA_CONFIG_UPDATE_VDEVS);
 }
--- a/usr/src/uts/common/fs/zfs/sys/spa_impl.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/zfs/sys/spa_impl.h	Mon Jul 20 13:07:46 2009 -0400
@@ -105,7 +105,7 @@
 	int		spa_inject_ref;		/* injection references */
 	uint8_t		spa_sync_on;		/* sync threads are running */
 	spa_load_state_t spa_load_state;	/* current load operation */
-	boolean_t	spa_inactive_states_ok;	/* ok to open inactive state? */
+	boolean_t	spa_load_verbatim;	/* load the given config? */
 	taskq_t		*spa_zio_taskq[ZIO_TYPES][ZIO_TASKQ_TYPES];
 	dsl_pool_t	*spa_dsl_pool;
 	metaslab_class_t *spa_normal_class;	/* normal data class */
--- a/usr/src/uts/common/fs/zfs/sys/zio.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/zfs/sys/zio.h	Mon Jul 20 13:07:46 2009 -0400
@@ -143,6 +143,8 @@
 #define	ZIO_FLAG_GODFATHER		0x080000
 
 #define	ZIO_FLAG_TRYHARD		0x100000
+#define	ZIO_FLAG_NODATA			0x200000
+#define	ZIO_FLAG_OPTIONAL		0x400000
 
 #define	ZIO_FLAG_GANG_INHERIT		\
 	(ZIO_FLAG_CANFAIL |		\
@@ -161,7 +163,9 @@
 	ZIO_FLAG_IO_REPAIR |		\
 	ZIO_FLAG_IO_RETRY |		\
 	ZIO_FLAG_PROBE |		\
-	ZIO_FLAG_TRYHARD)
+	ZIO_FLAG_TRYHARD |		\
+	ZIO_FLAG_NODATA |		\
+	ZIO_FLAG_OPTIONAL)
 
 #define	ZIO_FLAG_AGG_INHERIT		\
 	(ZIO_FLAG_DONT_AGGREGATE |	\
--- a/usr/src/uts/common/fs/zfs/vdev.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/zfs/vdev.c	Mon Jul 20 13:07:46 2009 -0400
@@ -405,22 +405,26 @@
 		if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY,
 		    &nparity) == 0) {
 			/*
-			 * Currently, we can only support 2 parity devices.
+			 * Currently, we can only support 3 parity devices.
 			 */
-			if (nparity == 0 || nparity > 2)
+			if (nparity == 0 || nparity > 3)
 				return (EINVAL);
 			/*
-			 * Older versions can only support 1 parity device.
+			 * Previous versions could only support 1 or 2 parity
+			 * device.
 			 */
-			if (nparity == 2 &&
-			    spa_version(spa) < SPA_VERSION_RAID6)
+			if (nparity > 1 &&
+			    spa_version(spa) < SPA_VERSION_RAIDZ2)
+				return (ENOTSUP);
+			if (nparity > 2 &&
+			    spa_version(spa) < SPA_VERSION_RAIDZ3)
 				return (ENOTSUP);
 		} else {
 			/*
 			 * We require the parity to be specified for SPAs that
 			 * support multiple parity levels.
 			 */
-			if (spa_version(spa) >= SPA_VERSION_RAID6)
+			if (spa_version(spa) >= SPA_VERSION_RAIDZ2)
 				return (EINVAL);
 			/*
 			 * Otherwise, we default to 1 parity device for RAID-Z.
@@ -1187,7 +1191,6 @@
 	nvlist_t *label;
 	uint64_t guid, top_guid;
 	uint64_t state;
-	boolean_t inactive_state;
 
 	for (int c = 0; c < vd->vdev_children; c++)
 		if (vdev_validate(vd->vdev_child[c]) != 0)
@@ -1244,12 +1247,13 @@
 
 		nvlist_free(label);
 
-		inactive_state = (state == POOL_STATE_EXPORTED ||
-		    state == POOL_STATE_DESTROYED);
-
-		if (spa->spa_load_state == SPA_LOAD_OPEN &&
-		    !(state == POOL_STATE_ACTIVE) &&
-		    !(spa->spa_inactive_states_ok && inactive_state))
+		/*
+		 * If spa->spa_load_verbatim is true, no need to check the
+		 * state of the pool.
+		 */
+		if (!spa->spa_load_verbatim &&
+		    spa->spa_load_state == SPA_LOAD_OPEN &&
+		    state != POOL_STATE_ACTIVE)
 			return (EBADF);
 
 		/*
--- a/usr/src/uts/common/fs/zfs/vdev_label.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/zfs/vdev_label.c	Mon Jul 20 13:07:46 2009 -0400
@@ -246,8 +246,10 @@
 		 * into a crufty old storage pool.
 		 */
 		ASSERT(vd->vdev_nparity == 1 ||
-		    (vd->vdev_nparity == 2 &&
-		    spa_version(spa) >= SPA_VERSION_RAID6));
+		    (vd->vdev_nparity <= 2 &&
+		    spa_version(spa) >= SPA_VERSION_RAIDZ2) ||
+		    (vd->vdev_nparity <= 3 &&
+		    spa_version(spa) >= SPA_VERSION_RAIDZ3));
 
 		/*
 		 * Note that we'll add the nparity tag even on storage pools
--- a/usr/src/uts/common/fs/zfs/vdev_queue.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/zfs/vdev_queue.c	Mon Jul 20 13:07:46 2009 -0400
@@ -24,7 +24,7 @@
  */
 
 #include <sys/zfs_context.h>
-#include <sys/spa.h>
+#include <sys/spa_impl.h>
 #include <sys/vdev_impl.h>
 #include <sys/zio.h>
 #include <sys/avl.h>
@@ -48,11 +48,14 @@
 int zfs_vdev_ramp_rate = 2;
 
 /*
- * To reduce IOPs, we aggregate small adjacent i/os into one large i/o.
- * For read i/os, we also aggregate across small adjacency gaps.
+ * To reduce IOPs, we aggregate small adjacent I/Os into one large I/O.
+ * For read I/Os, we also aggregate across small adjacency gaps; for writes
+ * we include spans of optional I/Os to aid aggregation at the disk even when
+ * they aren't able to help us aggregate at this level.
  */
 int zfs_vdev_aggregation_limit = SPA_MAXBLOCKSIZE;
 int zfs_vdev_read_gap_limit = 32 << 10;
+int zfs_vdev_write_gap_limit = 4 << 10;
 
 /*
  * Virtual device vector for disk I/O scheduling.
@@ -172,12 +175,14 @@
 static zio_t *
 vdev_queue_io_to_issue(vdev_queue_t *vq, uint64_t pending_limit)
 {
-	zio_t *fio, *lio, *aio, *dio, *nio;
+	zio_t *fio, *lio, *aio, *dio, *nio, *mio;
 	avl_tree_t *t;
 	int flags;
 	uint64_t maxspan = zfs_vdev_aggregation_limit;
 	uint64_t maxgap;
+	int stretch;
 
+again:
 	ASSERT(MUTEX_HELD(&vq->vq_lock));
 
 	if (avl_numnodes(&vq->vq_pending_tree) >= pending_limit ||
@@ -192,21 +197,88 @@
 
 	if (!(flags & ZIO_FLAG_DONT_AGGREGATE)) {
 		/*
-		 * We can aggregate I/Os that are adjacent and of the
-		 * same flavor, as expressed by the AGG_INHERIT flags.
-		 * The latter is necessary so that certain attributes
-		 * of the I/O, such as whether it's a normal I/O or a
-		 * scrub/resilver, can be preserved in the aggregate.
+		 * We can aggregate I/Os that are sufficiently adjacent and of
+		 * the same flavor, as expressed by the AGG_INHERIT flags.
+		 * The latter requirement is necessary so that certain
+		 * attributes of the I/O, such as whether it's a normal I/O
+		 * or a scrub/resilver, can be preserved in the aggregate.
+		 * We can include optional I/Os, but don't allow them
+		 * to begin a range as they add no benefit in that situation.
+		 */
+
+		/*
+		 * We keep track of the last non-optional I/O.
+		 */
+		mio = (fio->io_flags & ZIO_FLAG_OPTIONAL) ? NULL : fio;
+
+		/*
+		 * Walk backwards through sufficiently contiguous I/Os
+		 * recording the last non-option I/O.
 		 */
 		while ((dio = AVL_PREV(t, fio)) != NULL &&
 		    (dio->io_flags & ZIO_FLAG_AGG_INHERIT) == flags &&
-		    IO_SPAN(dio, lio) <= maxspan && IO_GAP(dio, fio) <= maxgap)
+		    IO_SPAN(dio, lio) <= maxspan &&
+		    IO_GAP(dio, fio) <= maxgap) {
 			fio = dio;
+			if (mio == NULL && !(fio->io_flags & ZIO_FLAG_OPTIONAL))
+				mio = fio;
+		}
 
+		/*
+		 * Skip any initial optional I/Os.
+		 */
+		while ((fio->io_flags & ZIO_FLAG_OPTIONAL) && fio != lio) {
+			fio = AVL_NEXT(t, fio);
+			ASSERT(fio != NULL);
+		}
+
+		/*
+		 * Walk forward through sufficiently contiguous I/Os.
+		 */
 		while ((dio = AVL_NEXT(t, lio)) != NULL &&
 		    (dio->io_flags & ZIO_FLAG_AGG_INHERIT) == flags &&
-		    IO_SPAN(fio, dio) <= maxspan && IO_GAP(lio, dio) <= maxgap)
+		    IO_SPAN(fio, dio) <= maxspan &&
+		    IO_GAP(lio, dio) <= maxgap) {
 			lio = dio;
+			if (!(lio->io_flags & ZIO_FLAG_OPTIONAL))
+				mio = lio;
+		}
+
+		/*
+		 * Now that we've established the range of the I/O aggregation
+		 * we must decide what to do with trailing optional I/Os.
+		 * For reads, there's nothing to do. While we are unable to
+		 * aggregate further, it's possible that a trailing optional
+		 * I/O would allow the underlying device to aggregate with
+		 * subsequent I/Os. We must therefore determine if the next
+		 * non-optional I/O is close enough to make aggregation
+		 * worthwhile.
+		 */
+		stretch = B_FALSE;
+		if (t != &vq->vq_read_tree && mio != NULL) {
+			nio = lio;
+			while ((dio = AVL_NEXT(t, nio)) != NULL &&
+			    IO_GAP(nio, dio) == 0 &&
+			    IO_GAP(mio, dio) <= zfs_vdev_write_gap_limit) {
+				nio = dio;
+				if (!(nio->io_flags & ZIO_FLAG_OPTIONAL)) {
+					stretch = B_TRUE;
+					break;
+				}
+			}
+		}
+
+		if (stretch) {
+			/* This may be a no-op. */
+			VERIFY((dio = AVL_NEXT(t, lio)) != NULL);
+			dio->io_flags &= ~ZIO_FLAG_OPTIONAL;
+		} else {
+			while (lio != mio && lio != fio) {
+				ASSERT(lio->io_flags & ZIO_FLAG_OPTIONAL);
+				lio = AVL_PREV(t, lio);
+				ASSERT(lio != NULL);
+			}
+		}
 	}
 
 	if (fio != lio) {
@@ -225,10 +297,15 @@
 			ASSERT(dio->io_type == aio->io_type);
 			ASSERT(dio->io_vdev_tree == t);
 
-			if (dio->io_type == ZIO_TYPE_WRITE)
+			if (dio->io_flags & ZIO_FLAG_NODATA) {
+				ASSERT(dio->io_type == ZIO_TYPE_WRITE);
+				bzero((char *)aio->io_data + (dio->io_offset -
+				    aio->io_offset), dio->io_size);
+			} else if (dio->io_type == ZIO_TYPE_WRITE) {
 				bcopy(dio->io_data, (char *)aio->io_data +
 				    (dio->io_offset - aio->io_offset),
 				    dio->io_size);
+			}
 
 			zio_add_child(dio, aio);
 			vdev_queue_io_remove(vq, dio);
@@ -244,6 +321,20 @@
 	ASSERT(fio->io_vdev_tree == t);
 	vdev_queue_io_remove(vq, fio);
 
+	/*
+	 * If the I/O is or was optional and therefore has no data, we need to
+	 * simply discard it. We need to drop the vdev queue's lock to avoid a
+	 * deadlock that we could encounter since this I/O will complete
+	 * immediately.
+	 */
+	if (fio->io_flags & ZIO_FLAG_NODATA) {
+		mutex_exit(&vq->vq_lock);
+		zio_vdev_io_bypass(fio);
+		zio_execute(fio);
+		mutex_enter(&vq->vq_lock);
+		goto again;
+	}
+
 	avl_add(&vq->vq_pending_tree, fio);
 
 	return (fio);
--- a/usr/src/uts/common/fs/zfs/vdev_raidz.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/fs/zfs/vdev_raidz.c	Mon Jul 20 13:07:46 2009 -0400
@@ -35,12 +35,27 @@
 /*
  * Virtual device vector for RAID-Z.
  *
- * This vdev supports both single and double parity. For single parity, we
- * use a simple XOR of all the data columns. For double parity, we use both
- * the simple XOR as well as a technique described in "The mathematics of
- * RAID-6" by H. Peter Anvin. This technique defines a Galois field, GF(2^8),
- * over the integers expressable in a single byte. Briefly, the operations on
- * the field are defined as follows:
+ * This vdev supports single, double, and triple parity. For single parity,
+ * we use a simple XOR of all the data columns. For double or triple parity,
+ * we use a special case of Reed-Solomon coding. This extends the
+ * technique described in "The mathematics of RAID-6" by H. Peter Anvin by
+ * drawing on the system described in "A Tutorial on Reed-Solomon Coding for
+ * Fault-Tolerance in RAID-like Systems" by James S. Plank on which the
+ * former is also based. The latter is designed to provide higher performance
+ * for writes.
+ *
+ * Note that the Plank paper claimed to support arbitrary N+M, but was then
+ * amended six years later identifying a critical flaw that invalidates its
+ * claims. Nevertheless, the technique can be adapted to work for up to
+ * triple parity. For additional parity, the amendment "Note: Correction to
+ * the 1997 Tutorial on Reed-Solomon Coding" by James S. Plank and Ying Ding
+ * is viable, but the additional complexity means that write performance will
+ * suffer.
+ *
+ * All of the methods above operate on a Galois field, defined over the
+ * integers mod 2^N. In our case we choose N=8 for GF(8) so that all elements
+ * can be expressed with a single byte. Briefly, the operations on the
+ * field are defined as follows:
  *
  *   o addition (+) is represented by a bitwise XOR
  *   o subtraction (-) is therefore identical to addition: A + B = A - B
@@ -55,22 +70,32 @@
  *	(A * 2)_0 = A_7
  *
  * In C, multiplying by 2 is therefore ((a << 1) ^ ((a & 0x80) ? 0x1d : 0)).
+ * As an aside, this multiplication is derived from the error correcting
+ * primitive polynomial x^8 + x^4 + x^3 + x^2 + 1.
  *
  * Observe that any number in the field (except for 0) can be expressed as a
  * power of 2 -- a generator for the field. We store a table of the powers of
  * 2 and logs base 2 for quick look ups, and exploit the fact that A * B can
  * be rewritten as 2^(log_2(A) + log_2(B)) (where '+' is normal addition rather
- * than field addition). The inverse of a field element A (A^-1) is A^254.
+ * than field addition). The inverse of a field element A (A^-1) is therefore
+ * A ^ (255 - 1) = A^254.
  *
- * The two parity columns, P and Q, over several data columns, D_0, ... D_n-1,
- * can be expressed by field operations:
+ * The up-to-three parity columns, P, Q, R over several data columns,
+ * D_0, ... D_n-1, can be expressed by field operations:
  *
  *	P = D_0 + D_1 + ... + D_n-2 + D_n-1
  *	Q = 2^n-1 * D_0 + 2^n-2 * D_1 + ... + 2^1 * D_n-2 + 2^0 * D_n-1
  *	  = ((...((D_0) * 2 + D_1) * 2 + ...) * 2 + D_n-2) * 2 + D_n-1
+ *	R = 4^n-1 * D_0 + 4^n-2 * D_1 + ... + 4^1 * D_n-2 + 4^0 * D_n-1
+ *	  = ((...((D_0) * 4 + D_1) * 4 + ...) * 4 + D_n-2) * 4 + D_n-1
  *
- * See the reconstruction code below for how P and Q can used individually or
- * in concert to recover missing data columns.
+ * We chose 1, 2, and 4 as our generators because 1 corresponds to the trival
+ * XOR operation, and 2 and 4 can be computed quickly and generate linearly-
+ * independent coefficients. (There are no additional coefficients that have
+ * this property which is why the uncorrected Plank method breaks down.)
+ *
+ * See the reconstruction code below for how P, Q and R can used individually
+ * or in concert to recover missing data columns.
  */
 
 typedef struct raidz_col {
@@ -84,21 +109,49 @@
 } raidz_col_t;
 
 typedef struct raidz_map {
-	uint64_t rm_cols;		/* Column count */
+	uint64_t rm_cols;		/* Regular column count */
+	uint64_t rm_scols;		/* Count including skipped columns */
 	uint64_t rm_bigcols;		/* Number of oversized columns */
 	uint64_t rm_asize;		/* Actual total I/O size */
 	uint64_t rm_missingdata;	/* Count of missing data devices */
 	uint64_t rm_missingparity;	/* Count of missing parity devices */
 	uint64_t rm_firstdatacol;	/* First data column/parity count */
+	uint64_t rm_skipped;		/* Skipped sectors for padding */
 	raidz_col_t rm_col[1];		/* Flexible array of I/O columns */
 } raidz_map_t;
 
 #define	VDEV_RAIDZ_P		0
 #define	VDEV_RAIDZ_Q		1
+#define	VDEV_RAIDZ_R		2
+#define	VDEV_RAIDZ_MAXPARITY	3
 
-#define	VDEV_RAIDZ_MAXPARITY	2
+#define	VDEV_RAIDZ_MUL_2(x)	(((x) << 1) ^ (((x) & 0x80) ? 0x1d : 0))
+#define	VDEV_RAIDZ_MUL_4(x)	(VDEV_RAIDZ_MUL_2(VDEV_RAIDZ_MUL_2(x)))
 
-#define	VDEV_RAIDZ_MUL_2(a)	(((a) << 1) ^ (((a) & 0x80) ? 0x1d : 0))
+/*
+ * We provide a mechanism to perform the field multiplication operation on a
+ * 64-bit value all at once rather than a byte at a time. This works by
+ * creating a mask from the top bit in each byte and using that to
+ * conditionally apply the XOR of 0x1d.
+ */
+#define	VDEV_RAIDZ_64MUL_2(x, mask) \
+{ \
+	(mask) = (x) & 0x8080808080808080ULL; \
+	(mask) = ((mask) << 1) - ((mask) >> 7); \
+	(x) = (((x) << 1) & 0xfefefefefefefefeULL) ^ \
+	    ((mask) & 0x1d1d1d1d1d1d1d1d); \
+}
+
+#define	VDEV_RAIDZ_64MUL_4(x, mask) \
+{ \
+	VDEV_RAIDZ_64MUL_2((x), mask); \
+	VDEV_RAIDZ_64MUL_2((x), mask); \
+}
+
+/*
+ * Force reconstruction to use the general purpose method.
+ */
+int vdev_raidz_default_to_general;
 
 /*
  * These two tables represent powers and logs of 2 in the Galois field defined
@@ -201,7 +254,7 @@
 	for (c = 0; c < rm->rm_firstdatacol; c++)
 		zio_buf_free(rm->rm_col[c].rc_data, rm->rm_col[c].rc_size);
 
-	kmem_free(rm, offsetof(raidz_map_t, rm_col[rm->rm_cols]));
+	kmem_free(rm, offsetof(raidz_map_t, rm_col[rm->rm_scols]));
 }
 
 static raidz_map_t *
@@ -213,24 +266,35 @@
 	uint64_t s = zio->io_size >> unit_shift;
 	uint64_t f = b % dcols;
 	uint64_t o = (b / dcols) << unit_shift;
-	uint64_t q, r, c, bc, col, acols, coff, devidx;
+	uint64_t q, r, c, bc, col, acols, scols, coff, devidx, asize, tot;
 
 	q = s / (dcols - nparity);
 	r = s - q * (dcols - nparity);
 	bc = (r == 0 ? 0 : r + nparity);
+	tot = s + nparity * (q + (r == 0 ? 0 : 1));
 
-	acols = (q == 0 ? bc : dcols);
+	if (q == 0) {
+		acols = bc;
+		scols = MIN(dcols, roundup(bc, nparity + 1));
+	} else {
+		acols = dcols;
+		scols = dcols;
+	}
 
-	rm = kmem_alloc(offsetof(raidz_map_t, rm_col[acols]), KM_SLEEP);
+	ASSERT3U(acols, <=, scols);
+
+	rm = kmem_alloc(offsetof(raidz_map_t, rm_col[scols]), KM_SLEEP);
 
 	rm->rm_cols = acols;
+	rm->rm_scols = scols;
 	rm->rm_bigcols = bc;
-	rm->rm_asize = 0;
 	rm->rm_missingdata = 0;
 	rm->rm_missingparity = 0;
 	rm->rm_firstdatacol = nparity;
 
-	for (c = 0; c < acols; c++) {
+	asize = 0;
+
+	for (c = 0; c < scols; c++) {
 		col = f + c;
 		coff = o;
 		if (col >= dcols) {
@@ -239,15 +303,26 @@
 		}
 		rm->rm_col[c].rc_devidx = col;
 		rm->rm_col[c].rc_offset = coff;
-		rm->rm_col[c].rc_size = (q + (c < bc)) << unit_shift;
 		rm->rm_col[c].rc_data = NULL;
 		rm->rm_col[c].rc_error = 0;
 		rm->rm_col[c].rc_tried = 0;
 		rm->rm_col[c].rc_skipped = 0;
-		rm->rm_asize += rm->rm_col[c].rc_size;
+
+		if (c >= acols)
+			rm->rm_col[c].rc_size = 0;
+		else if (c < bc)
+			rm->rm_col[c].rc_size = (q + 1) << unit_shift;
+		else
+			rm->rm_col[c].rc_size = q << unit_shift;
+
+		asize += rm->rm_col[c].rc_size;
 	}
 
-	rm->rm_asize = roundup(rm->rm_asize, (nparity + 1) << unit_shift);
+	ASSERT3U(asize, ==, tot << unit_shift);
+	rm->rm_asize = roundup(asize, (nparity + 1) << unit_shift);
+	rm->rm_skipped = roundup(tot, nparity + 1) - tot;
+	ASSERT3U(rm->rm_asize - asize, ==, rm->rm_skipped << unit_shift);
+	ASSERT3U(rm->rm_skipped, <=, nparity);
 
 	for (c = 0; c < rm->rm_firstdatacol; c++)
 		rm->rm_col[c].rc_data = zio_buf_alloc(rm->rm_col[c].rc_size);
@@ -305,12 +380,12 @@
 
 		if (c == rm->rm_firstdatacol) {
 			ASSERT(ccount == pcount);
-			for (i = 0; i < ccount; i++, p++, src++) {
+			for (i = 0; i < ccount; i++, src++, p++) {
 				*p = *src;
 			}
 		} else {
 			ASSERT(ccount <= pcount);
-			for (i = 0; i < ccount; i++, p++, src++) {
+			for (i = 0; i < ccount; i++, src++, p++) {
 				*p ^= *src;
 			}
 		}
@@ -320,10 +395,10 @@
 static void
 vdev_raidz_generate_parity_pq(raidz_map_t *rm)
 {
-	uint64_t *q, *p, *src, pcount, ccount, mask, i;
+	uint64_t *p, *q, *src, pcnt, ccnt, mask, i;
 	int c;
 
-	pcount = rm->rm_col[VDEV_RAIDZ_P].rc_size / sizeof (src[0]);
+	pcnt = rm->rm_col[VDEV_RAIDZ_P].rc_size / sizeof (src[0]);
 	ASSERT(rm->rm_col[VDEV_RAIDZ_P].rc_size ==
 	    rm->rm_col[VDEV_RAIDZ_Q].rc_size);
 
@@ -331,55 +406,138 @@
 		src = rm->rm_col[c].rc_data;
 		p = rm->rm_col[VDEV_RAIDZ_P].rc_data;
 		q = rm->rm_col[VDEV_RAIDZ_Q].rc_data;
-		ccount = rm->rm_col[c].rc_size / sizeof (src[0]);
+
+		ccnt = rm->rm_col[c].rc_size / sizeof (src[0]);
 
 		if (c == rm->rm_firstdatacol) {
-			ASSERT(ccount == pcount || ccount == 0);
-			for (i = 0; i < ccount; i++, p++, q++, src++) {
-				*q = *src;
+			ASSERT(ccnt == pcnt || ccnt == 0);
+			for (i = 0; i < ccnt; i++, src++, p++, q++) {
 				*p = *src;
+				*q = *src;
 			}
-			for (; i < pcount; i++, p++, q++, src++) {
+			for (; i < pcnt; i++, src++, p++, q++) {
+				*p = 0;
 				*q = 0;
-				*p = 0;
 			}
 		} else {
-			ASSERT(ccount <= pcount);
+			ASSERT(ccnt <= pcnt);
 
 			/*
-			 * Rather than multiplying each byte individually (as
-			 * described above), we are able to handle 8 at once
-			 * by generating a mask based on the high bit in each
-			 * byte and using that to conditionally XOR in 0x1d.
+			 * Apply the algorithm described above by multiplying
+			 * the previous result and adding in the new value.
 			 */
-			for (i = 0; i < ccount; i++, p++, q++, src++) {
-				mask = *q & 0x8080808080808080ULL;
-				mask = (mask << 1) - (mask >> 7);
-				*q = ((*q << 1) & 0xfefefefefefefefeULL) ^
-				    (mask & 0x1d1d1d1d1d1d1d1dULL);
+			for (i = 0; i < ccnt; i++, src++, p++, q++) {
+				*p ^= *src;
+
+				VDEV_RAIDZ_64MUL_2(*q, mask);
 				*q ^= *src;
-				*p ^= *src;
 			}
 
 			/*
 			 * Treat short columns as though they are full of 0s.
+			 * Note that there's therefore nothing needed for P.
 			 */
-			for (; i < pcount; i++, q++) {
-				mask = *q & 0x8080808080808080ULL;
-				mask = (mask << 1) - (mask >> 7);
-				*q = ((*q << 1) & 0xfefefefefefefefeULL) ^
-				    (mask & 0x1d1d1d1d1d1d1d1dULL);
+			for (; i < pcnt; i++, q++) {
+				VDEV_RAIDZ_64MUL_2(*q, mask);
 			}
 		}
 	}
 }
 
 static void
-vdev_raidz_reconstruct_p(raidz_map_t *rm, int x)
+vdev_raidz_generate_parity_pqr(raidz_map_t *rm)
+{
+	uint64_t *p, *q, *r, *src, pcnt, ccnt, mask, i;
+	int c;
+
+	pcnt = rm->rm_col[VDEV_RAIDZ_P].rc_size / sizeof (src[0]);
+	ASSERT(rm->rm_col[VDEV_RAIDZ_P].rc_size ==
+	    rm->rm_col[VDEV_RAIDZ_Q].rc_size);
+	ASSERT(rm->rm_col[VDEV_RAIDZ_P].rc_size ==
+	    rm->rm_col[VDEV_RAIDZ_R].rc_size);
+
+	for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) {
+		src = rm->rm_col[c].rc_data;
+		p = rm->rm_col[VDEV_RAIDZ_P].rc_data;
+		q = rm->rm_col[VDEV_RAIDZ_Q].rc_data;
+		r = rm->rm_col[VDEV_RAIDZ_R].rc_data;
+
+		ccnt = rm->rm_col[c].rc_size / sizeof (src[0]);
+
+		if (c == rm->rm_firstdatacol) {
+			ASSERT(ccnt == pcnt || ccnt == 0);
+			for (i = 0; i < ccnt; i++, src++, p++, q++, r++) {
+				*p = *src;
+				*q = *src;
+				*r = *src;
+			}
+			for (; i < pcnt; i++, src++, p++, q++, r++) {
+				*p = 0;
+				*q = 0;
+				*r = 0;
+			}
+		} else {
+			ASSERT(ccnt <= pcnt);
+
+			/*
+			 * Apply the algorithm described above by multiplying
+			 * the previous result and adding in the new value.
+			 */
+			for (i = 0; i < ccnt; i++, src++, p++, q++, r++) {
+				*p ^= *src;
+
+				VDEV_RAIDZ_64MUL_2(*q, mask);
+				*q ^= *src;
+
+				VDEV_RAIDZ_64MUL_4(*r, mask);
+				*r ^= *src;
+			}
+
+			/*
+			 * Treat short columns as though they are full of 0s.
+			 * Note that there's therefore nothing needed for P.
+			 */
+			for (; i < pcnt; i++, q++, r++) {
+				VDEV_RAIDZ_64MUL_2(*q, mask);
+				VDEV_RAIDZ_64MUL_4(*r, mask);
+			}
+		}
+	}
+}
+
+/*
+ * Generate RAID parity in the first virtual columns according to the number of
+ * parity columns available.
+ */
+static void
+vdev_raidz_generate_parity(raidz_map_t *rm)
+{
+	switch (rm->rm_firstdatacol) {
+	case 1:
+		vdev_raidz_generate_parity_p(rm);
+		break;
+	case 2:
+		vdev_raidz_generate_parity_pq(rm);
+		break;
+	case 3:
+		vdev_raidz_generate_parity_pqr(rm);
+		break;
+	default:
+		cmn_err(CE_PANIC, "invalid RAID-Z configuration");
+	}
+}
+
+static int
+vdev_raidz_reconstruct_p(raidz_map_t *rm, int *tgts, int ntgts)
 {
 	uint64_t *dst, *src, xcount, ccount, count, i;
+	int x = tgts[0];
 	int c;
 
+	ASSERT(ntgts == 1);
+	ASSERT(x >= rm->rm_firstdatacol);
+	ASSERT(x < rm->rm_cols);
+
 	xcount = rm->rm_col[x].rc_size / sizeof (src[0]);
 	ASSERT(xcount <= rm->rm_col[VDEV_RAIDZ_P].rc_size / sizeof (src[0]));
 	ASSERT(xcount > 0);
@@ -404,15 +562,20 @@
 			*dst ^= *src;
 		}
 	}
+
+	return (1 << VDEV_RAIDZ_P);
 }
 
-static void
-vdev_raidz_reconstruct_q(raidz_map_t *rm, int x)
+static int
+vdev_raidz_reconstruct_q(raidz_map_t *rm, int *tgts, int ntgts)
 {
 	uint64_t *dst, *src, xcount, ccount, count, mask, i;
 	uint8_t *b;
+	int x = tgts[0];
 	int c, j, exp;
 
+	ASSERT(ntgts == 1);
+
 	xcount = rm->rm_col[x].rc_size / sizeof (src[0]);
 	ASSERT(xcount <= rm->rm_col[VDEV_RAIDZ_Q].rc_size / sizeof (src[0]));
 
@@ -436,23 +599,13 @@
 			}
 
 		} else {
-			/*
-			 * For an explanation of this, see the comment in
-			 * vdev_raidz_generate_parity_pq() above.
-			 */
 			for (i = 0; i < count; i++, dst++, src++) {
-				mask = *dst & 0x8080808080808080ULL;
-				mask = (mask << 1) - (mask >> 7);
-				*dst = ((*dst << 1) & 0xfefefefefefefefeULL) ^
-				    (mask & 0x1d1d1d1d1d1d1d1dULL);
+				VDEV_RAIDZ_64MUL_2(*dst, mask);
 				*dst ^= *src;
 			}
 
 			for (; i < xcount; i++, dst++) {
-				mask = *dst & 0x8080808080808080ULL;
-				mask = (mask << 1) - (mask >> 7);
-				*dst = ((*dst << 1) & 0xfefefefefefefefeULL) ^
-				    (mask & 0x1d1d1d1d1d1d1d1dULL);
+				VDEV_RAIDZ_64MUL_2(*dst, mask);
 			}
 		}
 	}
@@ -467,15 +620,20 @@
 			*b = vdev_raidz_exp2(*b, exp);
 		}
 	}
+
+	return (1 << VDEV_RAIDZ_Q);
 }
 
-static void
-vdev_raidz_reconstruct_pq(raidz_map_t *rm, int x, int y)
+static int
+vdev_raidz_reconstruct_pq(raidz_map_t *rm, int *tgts, int ntgts)
 {
 	uint8_t *p, *q, *pxy, *qxy, *xd, *yd, tmp, a, b, aexp, bexp;
 	void *pdata, *qdata;
 	uint64_t xsize, ysize, i;
+	int x = tgts[0];
+	int y = tgts[1];
 
+	ASSERT(ntgts == 2);
 	ASSERT(x < y);
 	ASSERT(x >= rm->rm_firstdatacol);
 	ASSERT(y < rm->rm_cols);
@@ -553,13 +711,554 @@
 	 */
 	rm->rm_col[VDEV_RAIDZ_P].rc_data = pdata;
 	rm->rm_col[VDEV_RAIDZ_Q].rc_data = qdata;
+
+	return ((1 << VDEV_RAIDZ_P) | (1 << VDEV_RAIDZ_Q));
+}
+
+/* BEGIN CSTYLED */
+/*
+ * In the general case of reconstruction, we must solve the system of linear
+ * equations defined by the coeffecients used to generate parity as well as
+ * the contents of the data and parity disks. This can be expressed with
+ * vectors for the original data (D) and the actual data (d) and parity (p)
+ * and a matrix composed of the identity matrix (I) and a dispersal matrix (V):
+ *
+ *            __   __                     __     __
+ *            |     |         __     __   |  p_0  |
+ *            |  V  |         |  D_0  |   | p_m-1 |
+ *            |     |    x    |   :   | = |  d_0  |
+ *            |  I  |         | D_n-1 |   |   :   |
+ *            |     |         ~~     ~~   | d_n-1 |
+ *            ~~   ~~                     ~~     ~~
+ *
+ * I is simply a square identity matrix of size n, and V is a vandermonde
+ * matrix defined by the coeffecients we chose for the various parity columns
+ * (1, 2, 4). Note that these values were chosen both for simplicity, speedy
+ * computation as well as linear separability.
+ *
+ *      __               __               __     __
+ *      |   1   ..  1 1 1 |               |  p_0  |
+ *      | 2^n-1 ..  4 2 1 |   __     __   |   :   |
+ *      | 4^n-1 .. 16 4 1 |   |  D_0  |   | p_m-1 |
+ *      |   1   ..  0 0 0 |   |  D_1  |   |  d_0  |
+ *      |   0   ..  0 0 0 | x |  D_2  | = |  d_1  |
+ *      |   :       : : : |   |   :   |   |  d_2  |
+ *      |   0   ..  1 0 0 |   | D_n-1 |   |   :   |
+ *      |   0   ..  0 1 0 |   ~~     ~~   |   :   |
+ *      |   0   ..  0 0 1 |               | d_n-1 |
+ *      ~~               ~~               ~~     ~~
+ *
+ * Note that I, V, d, and p are known. To compute D, we must invert the
+ * matrix and use the known data and parity values to reconstruct the unknown
+ * data values. We begin by removing the rows in V|I and d|p that correspond
+ * to failed or missing columns; we then make V|I square (n x n) and d|p
+ * sized n by removing rows corresponding to unused parity from the bottom up
+ * to generate (V|I)' and (d|p)'. We can then generate the inverse of (V|I)'
+ * using Gauss-Jordan elimination. In the example below we use m=3 parity
+ * columns, n=8 data columns, with errors in d_1, d_2, and p_1:
+ *           __                               __
+ *           |  1   1   1   1   1   1   1   1  |
+ *           | 128  64  32  16  8   4   2   1  | <-----+-+-- missing disks
+ *           |  19 205 116  29  64  16  4   1  |      / /
+ *           |  1   0   0   0   0   0   0   0  |     / /
+ *           |  0   1   0   0   0   0   0   0  | <--' /
+ *  (V|I)  = |  0   0   1   0   0   0   0   0  | <---'
+ *           |  0   0   0   1   0   0   0   0  |
+ *           |  0   0   0   0   1   0   0   0  |
+ *           |  0   0   0   0   0   1   0   0  |
+ *           |  0   0   0   0   0   0   1   0  |
+ *           |  0   0   0   0   0   0   0   1  |
+ *           ~~                               ~~
+ *           __                               __
+ *           |  1   1   1   1   1   1   1   1  |
+ *           | 128  64  32  16  8   4   2   1  |
+ *           |  19 205 116  29  64  16  4   1  |
+ *           |  1   0   0   0   0   0   0   0  |
+ *           |  0   1   0   0   0   0   0   0  |
+ *  (V|I)' = |  0   0   1   0   0   0   0   0  |
+ *           |  0   0   0   1   0   0   0   0  |
+ *           |  0   0   0   0   1   0   0   0  |
+ *           |  0   0   0   0   0   1   0   0  |
+ *           |  0   0   0   0   0   0   1   0  |
+ *           |  0   0   0   0   0   0   0   1  |
+ *           ~~                               ~~
+ *
+ * Here we employ Gauss-Jordan elimination to find the inverse of (V|I)'. We
+ * have carefully chosen the seed values 1, 2, and 4 to ensure that this
+ * matrix is not singular.
+ * __                                                                 __
+ * |  1   1   1   1   1   1   1   1     1   0   0   0   0   0   0   0  |
+ * |  19 205 116  29  64  16  4   1     0   1   0   0   0   0   0   0  |
+ * |  1   0   0   0   0   0   0   0     0   0   1   0   0   0   0   0  |
+ * |  0   0   0   1   0   0   0   0     0   0   0   1   0   0   0   0  |
+ * |  0   0   0   0   1   0   0   0     0   0   0   0   1   0   0   0  |
+ * |  0   0   0   0   0   1   0   0     0   0   0   0   0   1   0   0  |
+ * |  0   0   0   0   0   0   1   0     0   0   0   0   0   0   1   0  |
+ * |  0   0   0   0   0   0   0   1     0   0   0   0   0   0   0   1  |
+ * ~~                                                                 ~~
+ * __                                                                 __
+ * |  1   0   0   0   0   0   0   0     0   0   1   0   0   0   0   0  |
+ * |  1   1   1   1   1   1   1   1     1   0   0   0   0   0   0   0  |
+ * |  19 205 116  29  64  16  4   1     0   1   0   0   0   0   0   0  |
+ * |  0   0   0   1   0   0   0   0     0   0   0   1   0   0   0   0  |
+ * |  0   0   0   0   1   0   0   0     0   0   0   0   1   0   0   0  |
+ * |  0   0   0   0   0   1   0   0     0   0   0   0   0   1   0   0  |
+ * |  0   0   0   0   0   0   1   0     0   0   0   0   0   0   1   0  |
+ * |  0   0   0   0   0   0   0   1     0   0   0   0   0   0   0   1  |
+ * ~~                                                                 ~~
+ * __                                                                 __
+ * |  1   0   0   0   0   0   0   0     0   0   1   0   0   0   0   0  |
+ * |  0   1   1   0   0   0   0   0     1   0   1   1   1   1   1   1  |
+ * |  0  205 116  0   0   0   0   0     0   1   19  29  64  16  4   1  |
+ * |  0   0   0   1   0   0   0   0     0   0   0   1   0   0   0   0  |
+ * |  0   0   0   0   1   0   0   0     0   0   0   0   1   0   0   0  |
+ * |  0   0   0   0   0   1   0   0     0   0   0   0   0   1   0   0  |
+ * |  0   0   0   0   0   0   1   0     0   0   0   0   0   0   1   0  |
+ * |  0   0   0   0   0   0   0   1     0   0   0   0   0   0   0   1  |
+ * ~~                                                                 ~~
+ * __                                                                 __
+ * |  1   0   0   0   0   0   0   0     0   0   1   0   0   0   0   0  |
+ * |  0   1   1   0   0   0   0   0     1   0   1   1   1   1   1   1  |
+ * |  0   0  185  0   0   0   0   0    205  1  222 208 141 221 201 204 |
+ * |  0   0   0   1   0   0   0   0     0   0   0   1   0   0   0   0  |
+ * |  0   0   0   0   1   0   0   0     0   0   0   0   1   0   0   0  |
+ * |  0   0   0   0   0   1   0   0     0   0   0   0   0   1   0   0  |
+ * |  0   0   0   0   0   0   1   0     0   0   0   0   0   0   1   0  |
+ * |  0   0   0   0   0   0   0   1     0   0   0   0   0   0   0   1  |
+ * ~~                                                                 ~~
+ * __                                                                 __
+ * |  1   0   0   0   0   0   0   0     0   0   1   0   0   0   0   0  |
+ * |  0   1   1   0   0   0   0   0     1   0   1   1   1   1   1   1  |
+ * |  0   0   1   0   0   0   0   0    166 100  4   40 158 168 216 209 |
+ * |  0   0   0   1   0   0   0   0     0   0   0   1   0   0   0   0  |
+ * |  0   0   0   0   1   0   0   0     0   0   0   0   1   0   0   0  |
+ * |  0   0   0   0   0   1   0   0     0   0   0   0   0   1   0   0  |
+ * |  0   0   0   0   0   0   1   0     0   0   0   0   0   0   1   0  |
+ * |  0   0   0   0   0   0   0   1     0   0   0   0   0   0   0   1  |
+ * ~~                                                                 ~~
+ * __                                                                 __
+ * |  1   0   0   0   0   0   0   0     0   0   1   0   0   0   0   0  |
+ * |  0   1   0   0   0   0   0   0    167 100  5   41 159 169 217 208 |
+ * |  0   0   1   0   0   0   0   0    166 100  4   40 158 168 216 209 |
+ * |  0   0   0   1   0   0   0   0     0   0   0   1   0   0   0   0  |
+ * |  0   0   0   0   1   0   0   0     0   0   0   0   1   0   0   0  |
+ * |  0   0   0   0   0   1   0   0     0   0   0   0   0   1   0   0  |
+ * |  0   0   0   0   0   0   1   0     0   0   0   0   0   0   1   0  |
+ * |  0   0   0   0   0   0   0   1     0   0   0   0   0   0   0   1  |
+ * ~~                                                                 ~~
+ *                   __                               __
+ *                   |  0   0   1   0   0   0   0   0  |
+ *                   | 167 100  5   41 159 169 217 208 |
+ *                   | 166 100  4   40 158 168 216 209 |
+ *       (V|I)'^-1 = |  0   0   0   1   0   0   0   0  |
+ *                   |  0   0   0   0   1   0   0   0  |
+ *                   |  0   0   0   0   0   1   0   0  |
+ *                   |  0   0   0   0   0   0   1   0  |
+ *                   |  0   0   0   0   0   0   0   1  |
+ *                   ~~                               ~~
+ *
+ * We can then simply compute D = (V|I)'^-1 x (d|p)' to discover the values
+ * of the missing data.
+ *
+ * As is apparent from the example above, the only non-trivial rows in the
+ * inverse matrix correspond to the data disks that we're trying to
+ * reconstruct. Indeed, those are the only rows we need as the others would
+ * only be useful for reconstructing data known or assumed to be valid. For
+ * that reason, we only build the coefficients in the rows that correspond to
+ * targeted columns.
+ */
+/* END CSTYLED */
+
+static void
+vdev_raidz_matrix_init(raidz_map_t *rm, int n, int nmap, int *map,
+    uint8_t **rows)
+{
+	int i, j;
+	int pow;
+
+	ASSERT(n == rm->rm_cols - rm->rm_firstdatacol);
+
+	/*
+	 * Fill in the missing rows of interest.
+	 */
+	for (i = 0; i < nmap; i++) {
+		ASSERT3S(0, <=, map[i]);
+		ASSERT3S(map[i], <=, 2);
+
+		pow = map[i] * n;
+		if (pow > 255)
+			pow -= 255;
+		ASSERT(pow <= 255);
+
+		for (j = 0; j < n; j++) {
+			pow -= map[i];
+			if (pow < 0)
+				pow += 255;
+			rows[i][j] = vdev_raidz_pow2[pow];
+		}
+	}
 }
 
+static void
+vdev_raidz_matrix_invert(raidz_map_t *rm, int n, int nmissing, int *missing,
+    uint8_t **rows, uint8_t **invrows, const uint8_t *used)
+{
+	int i, j, ii, jj;
+	uint8_t log;
+
+	/*
+	 * Assert that the first nmissing entries from the array of used
+	 * columns correspond to parity columns and that subsequent entries
+	 * correspond to data columns.
+	 */
+	for (i = 0; i < nmissing; i++) {
+		ASSERT3S(used[i], <, rm->rm_firstdatacol);
+	}
+	for (; i < n; i++) {
+		ASSERT3S(used[i], >=, rm->rm_firstdatacol);
+	}
+
+	/*
+	 * First initialize the storage where we'll compute the inverse rows.
+	 */
+	for (i = 0; i < nmissing; i++) {
+		for (j = 0; j < n; j++) {
+			invrows[i][j] = (i == j) ? 1 : 0;
+		}
+	}
+
+	/*
+	 * Subtract all trivial rows from the rows of consequence.
+	 */
+	for (i = 0; i < nmissing; i++) {
+		for (j = nmissing; j < n; j++) {
+			ASSERT3U(used[j], >=, rm->rm_firstdatacol);
+			jj = used[j] - rm->rm_firstdatacol;
+			ASSERT3S(jj, <, n);
+			invrows[i][j] = rows[i][jj];
+			rows[i][jj] = 0;
+		}
+	}
+
+	/*
+	 * For each of the rows of interest, we must normalize it and subtract
+	 * a multiple of it from the other rows.
+	 */
+	for (i = 0; i < nmissing; i++) {
+		for (j = 0; j < missing[i]; j++) {
+			ASSERT3U(rows[i][j], ==, 0);
+		}
+		ASSERT3U(rows[i][missing[i]], !=, 0);
+
+		/*
+		 * Compute the inverse of the first element and multiply each
+		 * element in the row by that value.
+		 */
+		log = 255 - vdev_raidz_log2[rows[i][missing[i]]];
+
+		for (j = 0; j < n; j++) {
+			rows[i][j] = vdev_raidz_exp2(rows[i][j], log);
+			invrows[i][j] = vdev_raidz_exp2(invrows[i][j], log);
+		}
+
+		for (ii = 0; ii < nmissing; ii++) {
+			if (i == ii)
+				continue;
+
+			ASSERT3U(rows[ii][missing[i]], !=, 0);
+
+			log = vdev_raidz_log2[rows[ii][missing[i]]];
+
+			for (j = 0; j < n; j++) {
+				rows[ii][j] ^=
+				    vdev_raidz_exp2(rows[i][j], log);
+				invrows[ii][j] ^=
+				    vdev_raidz_exp2(invrows[i][j], log);
+			}
+		}
+	}
+
+	/*
+	 * Verify that the data that is left in the rows are properly part of
+	 * an identity matrix.
+	 */
+	for (i = 0; i < nmissing; i++) {
+		for (j = 0; j < n; j++) {
+			if (j == missing[i]) {
+				ASSERT3U(rows[i][j], ==, 1);
+			} else {
+				ASSERT3U(rows[i][j], ==, 0);
+			}
+		}
+	}
+}
+
+static void
+vdev_raidz_matrix_reconstruct(raidz_map_t *rm, int n, int nmissing,
+    int *missing, uint8_t **invrows, const uint8_t *used)
+{
+	int i, j, x, cc, c;
+	uint8_t *src;
+	uint64_t ccount;
+	uint8_t *dst[VDEV_RAIDZ_MAXPARITY];
+	uint64_t dcount[VDEV_RAIDZ_MAXPARITY];
+	uint8_t log, val;
+	int ll;
+	uint8_t *invlog[VDEV_RAIDZ_MAXPARITY];
+	uint8_t *p, *pp;
+	size_t psize;
+
+	psize = sizeof (invlog[0][0]) * n * nmissing;
+	p = kmem_alloc(psize, KM_SLEEP);
+
+	for (pp = p, i = 0; i < nmissing; i++) {
+		invlog[i] = pp;
+		pp += n;
+	}
+
+	for (i = 0; i < nmissing; i++) {
+		for (j = 0; j < n; j++) {
+			ASSERT3U(invrows[i][j], !=, 0);
+			invlog[i][j] = vdev_raidz_log2[invrows[i][j]];
+		}
+	}
+
+	for (i = 0; i < n; i++) {
+		c = used[i];
+		ASSERT3U(c, <, rm->rm_cols);
+
+		src = rm->rm_col[c].rc_data;
+		ccount = rm->rm_col[c].rc_size;
+		for (j = 0; j < nmissing; j++) {
+			cc = missing[j] + rm->rm_firstdatacol;
+			ASSERT3U(cc, >=, rm->rm_firstdatacol);
+			ASSERT3U(cc, <, rm->rm_cols);
+			ASSERT3U(cc, !=, c);
+
+			dst[j] = rm->rm_col[cc].rc_data;
+			dcount[j] = rm->rm_col[cc].rc_size;
+		}
+
+		ASSERT(ccount >= rm->rm_col[missing[0]].rc_size || i > 0);
+
+		for (x = 0; x < ccount; x++, src++) {
+			if (*src != 0)
+				log = vdev_raidz_log2[*src];
+
+			for (cc = 0; cc < nmissing; cc++) {
+				if (x >= dcount[cc])
+					continue;
+
+				if (*src == 0) {
+					val = 0;
+				} else {
+					if ((ll = log + invlog[cc][i]) >= 255)
+						ll -= 255;
+					val = vdev_raidz_pow2[ll];
+				}
+
+				if (i == 0)
+					dst[cc][x] = val;
+				else
+					dst[cc][x] ^= val;
+			}
+		}
+	}
+
+	kmem_free(p, psize);
+}
+
+static int
+vdev_raidz_reconstruct_general(raidz_map_t *rm, int *tgts, int ntgts)
+{
+	int n, i, c, t, tt;
+	int nmissing_rows;
+	int missing_rows[VDEV_RAIDZ_MAXPARITY];
+	int parity_map[VDEV_RAIDZ_MAXPARITY];
+
+	uint8_t *p, *pp;
+	size_t psize;
+
+	uint8_t *rows[VDEV_RAIDZ_MAXPARITY];
+	uint8_t *invrows[VDEV_RAIDZ_MAXPARITY];
+	uint8_t *used;
+
+	int code = 0;
+
+
+	n = rm->rm_cols - rm->rm_firstdatacol;
+
+	/*
+	 * Figure out which data columns are missing.
+	 */
+	nmissing_rows = 0;
+	for (t = 0; t < ntgts; t++) {
+		if (tgts[t] >= rm->rm_firstdatacol) {
+			missing_rows[nmissing_rows++] =
+			    tgts[t] - rm->rm_firstdatacol;
+		}
+	}
+
+	/*
+	 * Figure out which parity columns to use to help generate the missing
+	 * data columns.
+	 */
+	for (tt = 0, c = 0, i = 0; i < nmissing_rows; c++) {
+		ASSERT(tt < ntgts);
+		ASSERT(c < rm->rm_firstdatacol);
+
+		/*
+		 * Skip any targeted parity columns.
+		 */
+		if (c == tgts[tt]) {
+			tt++;
+			continue;
+		}
+
+		code |= 1 << c;
+
+		parity_map[i] = c;
+		i++;
+	}
+
+	ASSERT(code != 0);
+	ASSERT3U(code, <, 1 << VDEV_RAIDZ_MAXPARITY);
+
+	psize = (sizeof (rows[0][0]) + sizeof (invrows[0][0])) *
+	    nmissing_rows * n + sizeof (used[0]) * n;
+	p = kmem_alloc(psize, KM_SLEEP);
+
+	for (pp = p, i = 0; i < nmissing_rows; i++) {
+		rows[i] = pp;
+		pp += n;
+		invrows[i] = pp;
+		pp += n;
+	}
+	used = pp;
+
+	for (i = 0; i < nmissing_rows; i++) {
+		used[i] = parity_map[i];
+	}
+
+	for (tt = 0, c = rm->rm_firstdatacol; c < rm->rm_cols; c++) {
+		if (tt < nmissing_rows &&
+		    c == missing_rows[tt] + rm->rm_firstdatacol) {
+			tt++;
+			continue;
+		}
+
+		ASSERT3S(i, <, n);
+		used[i] = c;
+		i++;
+	}
+
+	/*
+	 * Initialize the interesting rows of the matrix.
+	 */
+	vdev_raidz_matrix_init(rm, n, nmissing_rows, parity_map, rows);
+
+	/*
+	 * Invert the matrix.
+	 */
+	vdev_raidz_matrix_invert(rm, n, nmissing_rows, missing_rows, rows,
+	    invrows, used);
+
+	/*
+	 * Reconstruct the missing data using the generated matrix.
+	 */
+	vdev_raidz_matrix_reconstruct(rm, n, nmissing_rows, missing_rows,
+	    invrows, used);
+
+	kmem_free(p, psize);
+
+	return (code);
+}
+
+static int
+vdev_raidz_reconstruct(raidz_map_t *rm, int *t, int nt)
+{
+	int tgts[VDEV_RAIDZ_MAXPARITY], *dt;
+	int ntgts;
+	int i, c;
+	int code;
+	int nbadparity, nbaddata;
+	int parity_valid[VDEV_RAIDZ_MAXPARITY];
+
+	/*
+	 * The tgts list must already be sorted.
+	 */
+	for (i = 1; i < nt; i++) {
+		ASSERT(t[i] > t[i - 1]);
+	}
+
+	nbadparity = rm->rm_firstdatacol;
+	nbaddata = rm->rm_cols - nbadparity;
+	ntgts = 0;
+	for (i = 0, c = 0; c < rm->rm_cols; c++) {
+		if (c < rm->rm_firstdatacol)
+			parity_valid[c] = B_FALSE;
+
+		if (i < nt && c == t[i]) {
+			tgts[ntgts++] = c;
+			i++;
+		} else if (rm->rm_col[c].rc_error != 0) {
+			tgts[ntgts++] = c;
+		} else if (c >= rm->rm_firstdatacol) {
+			nbaddata--;
+		} else {
+			parity_valid[c] = B_TRUE;
+			nbadparity--;
+		}
+	}
+
+	ASSERT(ntgts >= nt);
+	ASSERT(nbaddata >= 0);
+	ASSERT(nbaddata + nbadparity == ntgts);
+
+	dt = &tgts[nbadparity];
+
+	/*
+	 * See if we can use any of our optimized reconstruction routines.
+	 */
+	if (!vdev_raidz_default_to_general) {
+		switch (nbaddata) {
+		case 1:
+			if (parity_valid[VDEV_RAIDZ_P])
+				return (vdev_raidz_reconstruct_p(rm, dt, 1));
+
+			ASSERT(rm->rm_firstdatacol > 1);
+
+			if (parity_valid[VDEV_RAIDZ_Q])
+				return (vdev_raidz_reconstruct_q(rm, dt, 1));
+
+			ASSERT(rm->rm_firstdatacol > 2);
+			break;
+
+		case 2:
+			ASSERT(rm->rm_firstdatacol > 1);
+
+			if (parity_valid[VDEV_RAIDZ_P] &&
+			    parity_valid[VDEV_RAIDZ_Q])
+				return (vdev_raidz_reconstruct_pq(rm, dt, 2));
+
+			ASSERT(rm->rm_firstdatacol > 2);
+
+			break;
+		}
+	}
+
+	code = vdev_raidz_reconstruct_general(rm, tgts, ntgts);
+	ASSERT(code < (1 << VDEV_RAIDZ_MAXPARITY));
+	ASSERT(code > 0);
+	return (code);
+}
 
 static int
 vdev_raidz_open(vdev_t *vd, uint64_t *asize, uint64_t *ashift)
 {
+	vdev_t *cvd;
 	uint64_t nparity = vd->vdev_nparity;
+	int c;
 	int lasterror = 0;
 	int numerrors = 0;
 
@@ -573,10 +1272,10 @@
 
 	vdev_open_children(vd);
 
-	for (int c = 0; c < vd->vdev_children; c++) {
-		vdev_t *cvd = vd->vdev_child[c];
+	for (c = 0; c < vd->vdev_children; c++) {
+		cvd = vd->vdev_child[c];
 
-		if (cvd->vdev_open_error) {
+		if (cvd->vdev_open_error != 0) {
 			lasterror = cvd->vdev_open_error;
 			numerrors++;
 			continue;
@@ -599,7 +1298,9 @@
 static void
 vdev_raidz_close(vdev_t *vd)
 {
-	for (int c = 0; c < vd->vdev_children; c++)
+	int c;
+
+	for (c = 0; c < vd->vdev_children; c++)
 		vdev_close(vd->vdev_child[c]);
 }
 
@@ -637,7 +1338,7 @@
 	blkptr_t *bp = zio->io_bp;
 	raidz_map_t *rm;
 	raidz_col_t *rc;
-	int c;
+	int c, i;
 
 	rm = vdev_raidz_map_alloc(zio, tvd->vdev_ashift, vd->vdev_children,
 	    vd->vdev_nparity);
@@ -645,13 +1346,7 @@
 	ASSERT3U(rm->rm_asize, ==, vdev_psize_to_asize(vd, zio->io_size));
 
 	if (zio->io_type == ZIO_TYPE_WRITE) {
-		/*
-		 * Generate RAID parity in the first virtual columns.
-		 */
-		if (rm->rm_firstdatacol == 1)
-			vdev_raidz_generate_parity_p(rm);
-		else
-			vdev_raidz_generate_parity_pq(rm);
+		vdev_raidz_generate_parity(rm);
 
 		for (c = 0; c < rm->rm_cols; c++) {
 			rc = &rm->rm_col[c];
@@ -662,6 +1357,23 @@
 			    vdev_raidz_child_done, rc));
 		}
 
+		/*
+		 * Generate optional I/Os for any skipped sectors to improve
+		 * aggregation contiguity.
+		 */
+		for (c = rm->rm_bigcols, i = 0; i < rm->rm_skipped; c++, i++) {
+			ASSERT(c <= rm->rm_scols);
+			if (c == rm->rm_scols)
+				c = 0;
+			rc = &rm->rm_col[c];
+			cvd = vd->vdev_child[rc->rc_devidx];
+			zio_nowait(zio_vdev_child_io(zio, NULL, cvd,
+			    rc->rc_offset + rc->rc_size, NULL,
+			    1 << tvd->vdev_ashift,
+			    zio->io_type, zio->io_priority,
+			    ZIO_FLAG_NODATA | ZIO_FLAG_OPTIONAL, NULL, NULL));
+		}
+
 		return (ZIO_PIPELINE_CONTINUE);
 	}
 
@@ -669,8 +1381,7 @@
 
 	/*
 	 * Iterate over the columns in reverse order so that we hit the parity
-	 * last -- any errors along the way will force us to read the parity
-	 * data.
+	 * last -- any errors along the way will force us to read the parity.
 	 */
 	for (c = rm->rm_cols - 1; c >= 0; c--) {
 		rc = &rm->rm_col[c];
@@ -746,10 +1457,7 @@
 		bcopy(rc->rc_data, orig[c], rc->rc_size);
 	}
 
-	if (rm->rm_firstdatacol == 1)
-		vdev_raidz_generate_parity_p(rm);
-	else
-		vdev_raidz_generate_parity_pq(rm);
+	vdev_raidz_generate_parity(rm);
 
 	for (c = 0; c < rm->rm_firstdatacol; c++) {
 		rc = &rm->rm_col[c];
@@ -766,9 +1474,10 @@
 	return (ret);
 }
 
-static uint64_t raidz_corrected_p;
-static uint64_t raidz_corrected_q;
-static uint64_t raidz_corrected_pq;
+/*
+ * Keep statistics on all the ways that we used parity to correct data.
+ */
+static uint64_t raidz_corrected[1 << VDEV_RAIDZ_MAXPARITY];
 
 static int
 vdev_raidz_worst_error(raidz_map_t *rm)
@@ -781,19 +1490,176 @@
 	return (error);
 }
 
+/*
+ * Iterate over all combinations of bad data and attempt a reconstruction.
+ * Note that the algorithm below is non-optimal because it doesn't take into
+ * account how reconstruction is actually performed. For example, with
+ * triple-parity RAID-Z the reconstruction procedure is the same if column 4
+ * is targeted as invalid as if columns 1 and 4 are targeted since in both
+ * cases we'd only use parity information in column 0.
+ */
+static int
+vdev_raidz_combrec(zio_t *zio, int total_errors, int data_errors)
+{
+	raidz_map_t *rm = zio->io_vsd;
+	raidz_col_t *rc;
+	void *orig[VDEV_RAIDZ_MAXPARITY];
+	int tstore[VDEV_RAIDZ_MAXPARITY + 2];
+	int *tgts = &tstore[1];
+	int current, next, i, c, n;
+	int code, ret = 0;
+
+	ASSERT(total_errors < rm->rm_firstdatacol);
+
+	/*
+	 * This simplifies one edge condition.
+	 */
+	tgts[-1] = -1;
+
+	for (n = 1; n <= rm->rm_firstdatacol - total_errors; n++) {
+		/*
+		 * Initialize the targets array by finding the first n columns
+		 * that contain no error.
+		 *
+		 * If there were no data errors, we need to ensure that we're
+		 * always explicitly attempting to reconstruct at least one
+		 * data column. To do this, we simply push the highest target
+		 * up into the data columns.
+		 */
+		for (c = 0, i = 0; i < n; i++) {
+			if (i == n - 1 && data_errors == 0 &&
+			    c < rm->rm_firstdatacol) {
+				c = rm->rm_firstdatacol;
+			}
+
+			while (rm->rm_col[c].rc_error != 0) {
+				c++;
+				ASSERT3S(c, <, rm->rm_cols);
+			}
+
+			tgts[i] = c++;
+		}
+
+		/*
+		 * Setting tgts[n] simplifies the other edge condition.
+		 */
+		tgts[n] = rm->rm_cols;
+
+		/*
+		 * These buffers were allocated in previous iterations.
+		 */
+		for (i = 0; i < n - 1; i++) {
+			ASSERT(orig[i] != NULL);
+		}
+
+		orig[n - 1] = zio_buf_alloc(rm->rm_col[0].rc_size);
+
+		current = 0;
+		next = tgts[current];
+
+		while (current != n) {
+			tgts[current] = next;
+			current = 0;
+
+			/*
+			 * Save off the original data that we're going to
+			 * attempt to reconstruct.
+			 */
+			for (i = 0; i < n; i++) {
+				ASSERT(orig[i] != NULL);
+				c = tgts[i];
+				ASSERT3S(c, >=, 0);
+				ASSERT3S(c, <, rm->rm_cols);
+				rc = &rm->rm_col[c];
+				bcopy(rc->rc_data, orig[i], rc->rc_size);
+			}
+
+			/*
+			 * Attempt a reconstruction and exit the outer loop on
+			 * success.
+			 */
+			code = vdev_raidz_reconstruct(rm, tgts, n);
+			if (zio_checksum_error(zio) == 0) {
+				atomic_inc_64(&raidz_corrected[code]);
+
+				for (i = 0; i < n; i++) {
+					c = tgts[i];
+					rc = &rm->rm_col[c];
+					ASSERT(rc->rc_error == 0);
+					if (rc->rc_tried)
+						raidz_checksum_error(zio, rc);
+					rc->rc_error = ECKSUM;
+				}
+
+				ret = code;
+				goto done;
+			}
+
+			/*
+			 * Restore the original data.
+			 */
+			for (i = 0; i < n; i++) {
+				c = tgts[i];
+				rc = &rm->rm_col[c];
+				bcopy(orig[i], rc->rc_data, rc->rc_size);
+			}
+
+			do {
+				/*
+				 * Find the next valid column after the current
+				 * position..
+				 */
+				for (next = tgts[current] + 1;
+				    next < rm->rm_cols &&
+				    rm->rm_col[next].rc_error != 0; next++)
+					continue;
+
+				ASSERT(next <= tgts[current + 1]);
+
+				/*
+				 * If that spot is available, we're done here.
+				 */
+				if (next != tgts[current + 1])
+					break;
+
+				/*
+				 * Otherwise, find the next valid column after
+				 * the previous position.
+				 */
+				for (c = tgts[current - 1] + 1;
+				    rm->rm_col[c].rc_error != 0; c++)
+					continue;
+
+				tgts[current] = c;
+				current++;
+
+			} while (current != n);
+		}
+	}
+	n--;
+done:
+	for (i = 0; i < n; i++) {
+		zio_buf_free(orig[i], rm->rm_col[0].rc_size);
+	}
+
+	return (ret);
+}
+
 static void
 vdev_raidz_io_done(zio_t *zio)
 {
 	vdev_t *vd = zio->io_vd;
 	vdev_t *cvd;
 	raidz_map_t *rm = zio->io_vsd;
-	raidz_col_t *rc, *rc1;
+	raidz_col_t *rc;
 	int unexpected_errors = 0;
 	int parity_errors = 0;
 	int parity_untried = 0;
 	int data_errors = 0;
 	int total_errors = 0;
-	int n, c, c1;
+	int n, c;
+	int tgts[VDEV_RAIDZ_MAXPARITY];
+	int code;
 
 	ASSERT(zio->io_bp != NULL);  /* XXX need to add code to enforce this */
 
@@ -857,8 +1723,7 @@
 	 * any errors.
 	 */
 	if (total_errors <= rm->rm_firstdatacol - parity_untried) {
-		switch (data_errors) {
-		case 0:
+		if (data_errors == 0) {
 			if (zio_checksum_error(zio) == 0) {
 				/*
 				 * If we read parity information (unnecessarily
@@ -878,9 +1743,7 @@
 				}
 				goto done;
 			}
-			break;
-
-		case 1:
+		} else {
 			/*
 			 * We either attempt to read all the parity columns or
 			 * none of them. If we didn't try to read parity, we
@@ -892,45 +1755,38 @@
 			ASSERT(parity_errors < rm->rm_firstdatacol);
 
 			/*
-			 * Find the column that reported the error.
+			 * Identify the data columns that reported an error.
 			 */
+			n = 0;
 			for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) {
 				rc = &rm->rm_col[c];
-				if (rc->rc_error != 0)
-					break;
+				if (rc->rc_error != 0) {
+					ASSERT(n < VDEV_RAIDZ_MAXPARITY);
+					tgts[n++] = c;
+				}
 			}
-			ASSERT(c != rm->rm_cols);
-			ASSERT(!rc->rc_skipped || rc->rc_error == ENXIO ||
-			    rc->rc_error == ESTALE);
 
-			if (rm->rm_col[VDEV_RAIDZ_P].rc_error == 0) {
-				vdev_raidz_reconstruct_p(rm, c);
-			} else {
-				ASSERT(rm->rm_firstdatacol > 1);
-				vdev_raidz_reconstruct_q(rm, c);
-			}
+			ASSERT(rm->rm_firstdatacol >= n);
+
+			code = vdev_raidz_reconstruct(rm, tgts, n);
 
 			if (zio_checksum_error(zio) == 0) {
-				if (rm->rm_col[VDEV_RAIDZ_P].rc_error == 0)
-					atomic_inc_64(&raidz_corrected_p);
-				else
-					atomic_inc_64(&raidz_corrected_q);
+				atomic_inc_64(&raidz_corrected[code]);
 
 				/*
-				 * If there's more than one parity disk that
-				 * was successfully read, confirm that the
-				 * other parity disk produced the correct data.
-				 * This routine is suboptimal in that it
-				 * regenerates both the parity we wish to test
-				 * as well as the parity we just used to
-				 * perform the reconstruction, but this should
-				 * be a relatively uncommon case, and can be
-				 * optimized if it becomes a problem.
-				 * We also regenerate parity when resilvering
-				 * so we can write it out to the failed device
-				 * later.
+				 * If we read more parity disks than were used
+				 * for reconstruction, confirm that the other
+				 * parity disks produced correct data. This
+				 * routine is suboptimal in that it regenerates
+				 * the parity that we already used in addition
+				 * to the parity that we're attempting to
+				 * verify, but this should be a relatively
+				 * uncommon case, and can be optimized if it
+				 * becomes a problem. Note that we regenerate
+				 * parity when resilvering so we can write it
+				 * out to failed devices later.
 				 */
-				if (parity_errors < rm->rm_firstdatacol - 1 ||
+				if (parity_errors < rm->rm_firstdatacol - n ||
 				    (zio->io_flags & ZIO_FLAG_RESILVER)) {
 					n = raidz_parity_verify(zio, rm);
 					unexpected_errors += n;
@@ -940,46 +1796,6 @@
 
 				goto done;
 			}
-			break;
-
-		case 2:
-			/*
-			 * Two data column errors require double parity.
-			 */
-			ASSERT(rm->rm_firstdatacol == 2);
-
-			/*
-			 * Find the two columns that reported errors.
-			 */
-			for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) {
-				rc = &rm->rm_col[c];
-				if (rc->rc_error != 0)
-					break;
-			}
-			ASSERT(c != rm->rm_cols);
-			ASSERT(!rc->rc_skipped || rc->rc_error == ENXIO ||
-			    rc->rc_error == ESTALE);
-
-			for (c1 = c++; c < rm->rm_cols; c++) {
-				rc = &rm->rm_col[c];
-				if (rc->rc_error != 0)
-					break;
-			}
-			ASSERT(c != rm->rm_cols);
-			ASSERT(!rc->rc_skipped || rc->rc_error == ENXIO ||
-			    rc->rc_error == ESTALE);
-
-			vdev_raidz_reconstruct_pq(rm, c1, c);
-
-			if (zio_checksum_error(zio) == 0) {
-				atomic_inc_64(&raidz_corrected_pq);
-				goto done;
-			}
-			break;
-
-		default:
-			ASSERT(rm->rm_firstdatacol <= 2);
-			ASSERT(0);
 		}
 	}
 
@@ -1018,8 +1834,10 @@
 	 * errors we detected, and we've attempted to read all columns. There
 	 * must, therefore, be one or more additional problems -- silent errors
 	 * resulting in invalid data rather than explicit I/O errors resulting
-	 * in absent data. Before we attempt combinatorial reconstruction make
-	 * sure we have a chance of coming up with the right answer.
+	 * in absent data. We check if there is enough additional data to
+	 * possibly reconstruct the data and then perform combinatorial
+	 * reconstruction over all possible combinations. If that fails,
+	 * we're cooked.
 	 */
 	if (total_errors >= rm->rm_firstdatacol) {
 		zio->io_error = vdev_raidz_worst_error(rm);
@@ -1030,133 +1848,30 @@
 		 */
 		if (total_errors == rm->rm_firstdatacol)
 			zio->io_error = zio_worst_error(zio->io_error, ECKSUM);
-		goto done;
-	}
-
-	if (rm->rm_col[VDEV_RAIDZ_P].rc_error == 0) {
-		/*
-		 * Attempt to reconstruct the data from parity P.
-		 */
-		for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) {
-			void *orig;
-			rc = &rm->rm_col[c];
-
-			orig = zio_buf_alloc(rc->rc_size);
-			bcopy(rc->rc_data, orig, rc->rc_size);
-			vdev_raidz_reconstruct_p(rm, c);
-
-			if (zio_checksum_error(zio) == 0) {
-				zio_buf_free(orig, rc->rc_size);
-				atomic_inc_64(&raidz_corrected_p);
-
-				/*
-				 * If this child didn't know that it returned
-				 * bad data, inform it.
-				 */
-				if (rc->rc_tried && rc->rc_error == 0)
-					raidz_checksum_error(zio, rc);
-				rc->rc_error = ECKSUM;
-				goto done;
-			}
-
-			bcopy(orig, rc->rc_data, rc->rc_size);
-			zio_buf_free(orig, rc->rc_size);
-		}
-	}
-
-	if (rm->rm_firstdatacol > 1 && rm->rm_col[VDEV_RAIDZ_Q].rc_error == 0) {
-		/*
-		 * Attempt to reconstruct the data from parity Q.
-		 */
-		for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) {
-			void *orig;
-			rc = &rm->rm_col[c];
-
-			orig = zio_buf_alloc(rc->rc_size);
-			bcopy(rc->rc_data, orig, rc->rc_size);
-			vdev_raidz_reconstruct_q(rm, c);
-
-			if (zio_checksum_error(zio) == 0) {
-				zio_buf_free(orig, rc->rc_size);
-				atomic_inc_64(&raidz_corrected_q);
-
-				/*
-				 * If this child didn't know that it returned
-				 * bad data, inform it.
-				 */
-				if (rc->rc_tried && rc->rc_error == 0)
-					raidz_checksum_error(zio, rc);
-				rc->rc_error = ECKSUM;
-				goto done;
-			}
 
-			bcopy(orig, rc->rc_data, rc->rc_size);
-			zio_buf_free(orig, rc->rc_size);
-		}
-	}
-
-	if (rm->rm_firstdatacol > 1 &&
-	    rm->rm_col[VDEV_RAIDZ_P].rc_error == 0 &&
-	    rm->rm_col[VDEV_RAIDZ_Q].rc_error == 0) {
+	} else if ((code = vdev_raidz_combrec(zio, total_errors,
+	    data_errors)) != 0) {
 		/*
-		 * Attempt to reconstruct the data from both P and Q.
+		 * If we didn't use all the available parity for the
+		 * combinatorial reconstruction, verify that the remaining
+		 * parity is correct.
 		 */
-		for (c = rm->rm_firstdatacol; c < rm->rm_cols - 1; c++) {
-			void *orig, *orig1;
-			rc = &rm->rm_col[c];
-
-			orig = zio_buf_alloc(rc->rc_size);
-			bcopy(rc->rc_data, orig, rc->rc_size);
-
-			for (c1 = c + 1; c1 < rm->rm_cols; c1++) {
-				rc1 = &rm->rm_col[c1];
-
-				orig1 = zio_buf_alloc(rc1->rc_size);
-				bcopy(rc1->rc_data, orig1, rc1->rc_size);
-
-				vdev_raidz_reconstruct_pq(rm, c, c1);
-
-				if (zio_checksum_error(zio) == 0) {
-					zio_buf_free(orig, rc->rc_size);
-					zio_buf_free(orig1, rc1->rc_size);
-					atomic_inc_64(&raidz_corrected_pq);
+		if (code != (1 << rm->rm_firstdatacol) - 1)
+			(void) raidz_parity_verify(zio, rm);
+	} else {
+		/*
+		 * All combinations failed to checksum. Generate checksum
+		 * ereports for all children.
+		 */
+		zio->io_error = ECKSUM;
 
-					/*
-					 * If these children didn't know they
-					 * returned bad data, inform them.
-					 */
-					if (rc->rc_tried && rc->rc_error == 0)
-						raidz_checksum_error(zio, rc);
-					if (rc1->rc_tried && rc1->rc_error == 0)
-						raidz_checksum_error(zio, rc1);
-
-					rc->rc_error = ECKSUM;
-					rc1->rc_error = ECKSUM;
-
-					goto done;
-				}
-
-				bcopy(orig1, rc1->rc_data, rc1->rc_size);
-				zio_buf_free(orig1, rc1->rc_size);
+		if (!(zio->io_flags & ZIO_FLAG_SPECULATIVE)) {
+			for (c = 0; c < rm->rm_cols; c++) {
+				rc = &rm->rm_col[c];
+				zfs_ereport_post(FM_EREPORT_ZFS_CHECKSUM,
+				    zio->io_spa, vd->vdev_child[rc->rc_devidx],
+				    zio, rc->rc_offset, rc->rc_size);
 			}
-
-			bcopy(orig, rc->rc_data, rc->rc_size);
-			zio_buf_free(orig, rc->rc_size);
-		}
-	}
-
-	/*
-	 * All combinations failed to checksum. Generate checksum ereports for
-	 * all children.
-	 */
-	zio->io_error = ECKSUM;
-
-	if (!(zio->io_flags & ZIO_FLAG_SPECULATIVE)) {
-		for (c = 0; c < rm->rm_cols; c++) {
-			rc = &rm->rm_col[c];
-			zfs_ereport_post(FM_EREPORT_ZFS_CHECKSUM,
-			    zio->io_spa, vd->vdev_child[rc->rc_devidx], zio,
-			    rc->rc_offset, rc->rc_size);
 		}
 	}
 
--- a/usr/src/uts/common/inet/kssl/ksslrec.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/inet/kssl/ksslrec.c	Mon Jul 20 13:07:46 2009 -0400
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/stream.h>
 #include <sys/strsubr.h>
@@ -444,6 +442,15 @@
 }
 
 
+/*
+ * Minimum message length for a client hello =
+ * 2-byte client_version +
+ * 32-byte random +
+ * 1-byte session_id length +
+ * 2-byte cipher_suites length +
+ * 1-byte compression_methods length +
+ * 1-byte CompressionMethod.null
+ */
 #define	KSSL_SSL3_CH_MIN_MSGLEN	(39)
 
 static int
@@ -452,8 +459,7 @@
 	uchar_t *msgend;
 	int err;
 	SSL3AlertDescription desc = illegal_parameter;
-	uint_t sidlen;
-	uint_t nsuites;
+	uint_t sidlen, cslen, cmlen;
 	uchar_t *suitesp;
 	uint_t i, j;
 	uint16_t suite;
@@ -498,25 +504,35 @@
 		mp->b_rptr += SSL3_SESSIONID_BYTES;
 	}
 
-	nsuites = ((uint_t)mp->b_rptr[0] << 8) + (uint_t)mp->b_rptr[1];
+	cslen = ((uint_t)mp->b_rptr[0] << 8) + (uint_t)mp->b_rptr[1];
 	mp->b_rptr += 2;
-	ch_msglen += nsuites;
-	if (msglen != ch_msglen) {
+	ch_msglen += cslen;
+
+	/*
+	 * This check can't be a "!=" since there can be
+	 * compression methods other than CompressionMethod.null.
+	 * Also, there can be extra data (TLS extensions) after the
+	 * compression methods field. We do not support any TLS
+	 * extensions and hence ignore them.
+	 */
+	if (msglen < ch_msglen) {
 		goto falert;
 	}
-	if (nsuites & 0x1) {
+
+	/* The length has to be even since a cipher suite is 2-byte long */
+	if (cslen & 0x1) {
 		goto falert;
 	}
 	suitesp = mp->b_rptr;
 	if (ssl->sid.cached == B_TRUE) {
 		suite = ssl->sid.cipher_suite;
-		for (j = 0; j < nsuites; j += 2) {
+		for (j = 0; j < cslen; j += 2) {
 			if (suitesp[j] == ((suite >> 8) & 0xff) &&
 			    suitesp[j + 1] == (suite & 0xff)) {
 				break;
 			}
 		}
-		if (j < nsuites) {
+		if (j < cslen) {
 			goto suite_found;
 		}
 		kssl_uncache_sid(&ssl->sid, ssl->kssl_entry);
@@ -526,13 +542,13 @@
 	/* Check if this server is capable of the cipher suite */
 	for (i = 0; i < ssl->kssl_entry->kssl_cipherSuites_nentries; i++) {
 		suite = ssl->kssl_entry->kssl_cipherSuites[i];
-		for (j = 0; j < nsuites; j += 2) {
+		for (j = 0; j < cslen; j += 2) {
 			if (suitesp[j] == ((suite >> 8) & 0xff) &&
 			    suitesp[j + 1] == (suite & 0xff)) {
 				break;
 			}
 		}
-		if (j < nsuites) {
+		if (j < cslen) {
 			break;
 		}
 	}
@@ -547,11 +563,27 @@
 	}
 
 suite_found:
+	mp->b_rptr += cslen;
 
-	mp->b_rptr += nsuites;
-	if (*mp->b_rptr++ != 1 || *mp->b_rptr++ != 0) {
+	/*
+	 * Check for the mandatory CompressionMethod.null. We do not
+	 * support any other compression methods.
+	 */
+	cmlen = *mp->b_rptr++;
+	ch_msglen += cmlen - 1;	/* -1 accounts for the null method */
+	if (msglen < ch_msglen) {
+		goto falert;
+	}
+
+	while (cmlen >= 1) {
+		if (*mp->b_rptr++ == 0)
+			break;
+		cmlen--;
+	}
+
+	if (cmlen == 0) {
 		desc = handshake_failure;
-		DTRACE_PROBE(kssl_err__handshake_failure);
+		DTRACE_PROBE(kssl_err__no_null_method_failure);
 		goto falert;
 	}
 
@@ -1352,8 +1384,10 @@
 		}
 	} else {
 		if (cipher_defs[ssl->pending_calg].bsize > 0) {
+			/* server_write_IV */
 			spec->cipher_mech.cm_param += spec->cipher_bsize;
 		}
+
 		/* server_write_key */
 		spec->cipher_key.ck_data =
 		    &(ssl->pending_keyblock[2 * spec->mac_hashsz +
@@ -1802,7 +1836,7 @@
 	SSL3AlertDescription desc = illegal_parameter;
 	uint_t randlen;
 	uint_t sidlen;
-	uint_t nsuites;
+	uint_t cslen;
 	uchar_t *suitesp;
 	uchar_t *rand;
 	uint_t i, j;
@@ -1829,11 +1863,11 @@
 	}
 	mp->b_rptr += 3;
 
-	nsuites = ((uint_t)mp->b_rptr[0] << 8) + (uint_t)mp->b_rptr[1];
+	cslen = ((uint_t)mp->b_rptr[0] << 8) + (uint_t)mp->b_rptr[1];
 	sidlen = ((uint_t)mp->b_rptr[2] << 8) + (uint_t)mp->b_rptr[3];
 	randlen = ((uint_t)mp->b_rptr[4] << 8) + (uint_t)mp->b_rptr[5];
-	if (nsuites % 3 != 0) {
-		DTRACE_PROBE1(kssl_err__nsuites_error, uint_t, nsuites);
+	if (cslen % 3 != 0) {
+		DTRACE_PROBE1(kssl_err__cipher_suites_len_error, uint_t, cslen);
 		goto falert;
 	}
 	if (randlen < SSL_MIN_CHALLENGE_BYTES ||
@@ -1843,12 +1877,12 @@
 		goto falert;
 	}
 	mp->b_rptr += 6;
-	ch_recsz += nsuites + sidlen + randlen;
+	ch_recsz += cslen + sidlen + randlen;
 	if (recsz != ch_recsz) {
 		goto falert;
 	}
 	suitesp = mp->b_rptr;
-	rand = suitesp + nsuites + sidlen;
+	rand = suitesp + cslen + sidlen;
 	if (randlen < SSL3_RANDOM_LENGTH) {
 		bzero(ssl->client_random, SSL3_RANDOM_LENGTH);
 	}
@@ -1857,7 +1891,7 @@
 
 	for (i = 0; i < ssl->kssl_entry->kssl_cipherSuites_nentries; i++) {
 		suite = ssl->kssl_entry->kssl_cipherSuites[i];
-		for (j = 0; j < nsuites; j += 3) {
+		for (j = 0; j < cslen; j += 3) {
 			if (suitesp[j] != 0) {
 				continue;
 			}
@@ -1867,7 +1901,7 @@
 				break;
 			}
 		}
-		if (j < nsuites) {
+		if (j < cslen) {
 			break;
 		}
 	}
@@ -1920,7 +1954,7 @@
 
 /*
  * Call back routine for asynchronously submitted RSA decryption jobs.
- * The routine retreived the pre-master secret, and proceeds to generate
+ * This routine retrieves the pre-master secret, and proceeds to generate
  * the remaining key materials.
  */
 static void
--- a/usr/src/uts/common/inet/tcp/tcp.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/inet/tcp/tcp.c	Mon Jul 20 13:07:46 2009 -0400
@@ -13633,6 +13633,20 @@
 	if (flags & TH_URG && urp >= 0) {
 		if (!tcp->tcp_urp_last_valid ||
 		    SEQ_GT(urp + seg_seq, tcp->tcp_urp_last)) {
+			/*
+			 * Non-STREAMS sockets handle the urgent data a litte
+			 * differently from STREAMS based sockets. There is no
+			 * need to mark any mblks with the MSG{NOT,}MARKNEXT
+			 * flags to keep SIOCATMARK happy. Instead a
+			 * su_signal_oob upcall is made to update the mark.
+			 * Neither is a T_EXDATA_IND mblk needed to be
+			 * prepended to the urgent data. The urgent data is
+			 * delivered using the su_recv upcall, where we set
+			 * the MSG_OOB flag to indicate that it is urg data.
+			 *
+			 * Neither TH_SEND_URP_MARK nor TH_MARKNEXT_NEEDED
+			 * are used by non-STREAMS sockets.
+			 */
 			if (IPCL_IS_NONSTR(connp)) {
 				if (!TCP_IS_DETACHED(tcp)) {
 					(*connp->conn_upcalls->su_signal_oob)
@@ -13858,26 +13872,34 @@
 		} else if (urp == seg_len) {
 			/*
 			 * The urgent byte is the next byte after this sequence
-			 * number. If there is data it is marked with
-			 * MSGMARKNEXT and any tcp_urp_mark_mp is discarded
-			 * since it is not needed. Otherwise, if the code
-			 * above just allocated a zero-length tcp_urp_mark_mp
-			 * message, that message is tagged with MSGMARKNEXT.
-			 * Sending up these MSGMARKNEXT messages makes
-			 * SIOCATMARK work correctly even though
-			 * the T_EXDATA_IND will not be sent up until the
-			 * urgent byte arrives.
-			 */
-			if (seg_len != 0) {
-				flags |= TH_MARKNEXT_NEEDED;
-				freemsg(tcp->tcp_urp_mark_mp);
-				tcp->tcp_urp_mark_mp = NULL;
-				flags &= ~TH_SEND_URP_MARK;
-			} else if (tcp->tcp_urp_mark_mp != NULL) {
-				flags |= TH_SEND_URP_MARK;
-				tcp->tcp_urp_mark_mp->b_flag &=
-				    ~MSGNOTMARKNEXT;
-				tcp->tcp_urp_mark_mp->b_flag |= MSGMARKNEXT;
+			 * number. If this endpoint is non-STREAMS, then there
+			 * is nothing to do here since the socket has already
+			 * been notified about the urg pointer by the
+			 * su_signal_oob call above.
+			 *
+			 * In case of STREAMS, some more work might be needed.
+			 * If there is data it is marked with MSGMARKNEXT and
+			 * and any tcp_urp_mark_mp is discarded since it is not
+			 * needed. Otherwise, if the code above just allocated
+			 * a zero-length tcp_urp_mark_mp message, that message
+			 * is tagged with MSGMARKNEXT. Sending up these
+			 * MSGMARKNEXT messages makes SIOCATMARK work correctly
+			 * even though the T_EXDATA_IND will not be sent up
+			 * until the urgent byte arrives.
+			 */
+			if (!IPCL_IS_NONSTR(tcp->tcp_connp)) {
+				if (seg_len != 0) {
+					flags |= TH_MARKNEXT_NEEDED;
+					freemsg(tcp->tcp_urp_mark_mp);
+					tcp->tcp_urp_mark_mp = NULL;
+					flags &= ~TH_SEND_URP_MARK;
+				} else if (tcp->tcp_urp_mark_mp != NULL) {
+					flags |= TH_SEND_URP_MARK;
+					tcp->tcp_urp_mark_mp->b_flag &=
+					    ~MSGNOTMARKNEXT;
+					tcp->tcp_urp_mark_mp->b_flag |=
+					    MSGMARKNEXT;
+				}
 			}
 #ifdef DEBUG
 			(void) strlog(TCP_MOD_ID, 0, 1, SL_TRACE,
@@ -14910,24 +14932,35 @@
 		} else {
 			tcp_rcv_enqueue(tcp, mp, seg_len);
 		}
-	} else {
+	} else if (IPCL_IS_NONSTR(connp)) {
+		/*
+		 * Non-STREAMS socket
+		 *
+		 * Note that no KSSL processing is done here, because
+		 * KSSL is not supported for non-STREAMS sockets.
+		 */
+		boolean_t push = flags & (TH_PUSH|TH_FIN);
+		int error;
+
+		if ((*connp->conn_upcalls->su_recv)(
+		    connp->conn_upper_handle,
+		    mp, seg_len, 0, &error, &push) <= 0) {
+			/*
+			 * We should never be in middle of a
+			 * fallback, the squeue guarantees that.
+			 */
+			ASSERT(error != EOPNOTSUPP);
+			if (error == ENOSPC)
+				tcp->tcp_rwnd -= seg_len;
+		} else if (push) {
+			/* PUSH bit set and sockfs is not flow controlled */
+			flags |= tcp_rwnd_reopen(tcp);
+		}
+	} else {
+		/* STREAMS socket */
 		if (mp->b_datap->db_type != M_DATA ||
 		    (flags & TH_MARKNEXT_NEEDED)) {
-			if (IPCL_IS_NONSTR(connp)) {
-				int error;
-
-				if ((*connp->conn_upcalls->su_recv)
-				    (connp->conn_upper_handle, mp,
-				    seg_len, 0, &error, NULL) <= 0) {
-					/*
-					 * We should never be in middle of a
-					 * fallback, the squeue guarantees that.
-					 */
-					ASSERT(error != EOPNOTSUPP);
-					if (error == ENOSPC)
-						tcp->tcp_rwnd -= seg_len;
-				}
-			} else if (tcp->tcp_rcv_list != NULL) {
+			if (tcp->tcp_rcv_list != NULL) {
 				flags |= tcp_rcv_drain(tcp);
 			}
 			ASSERT(tcp->tcp_rcv_list == NULL ||
@@ -14950,8 +14983,7 @@
 				DTRACE_PROBE1(kssl_mblk__ksslinput_data1,
 				    mblk_t *, mp);
 				tcp_kssl_input(tcp, mp);
-			} else if (!IPCL_IS_NONSTR(connp)) {
-				/* Already handled non-STREAMS case. */
+			} else {
 				putnext(tcp->tcp_rq, mp);
 				if (!canputnext(tcp->tcp_rq))
 					tcp->tcp_rwnd -= seg_len;
@@ -14961,28 +14993,6 @@
 			/* Does this need SSL processing first? */
 			DTRACE_PROBE1(kssl_mblk__ksslinput_data2, mblk_t *, mp);
 			tcp_kssl_input(tcp, mp);
-		} else if (IPCL_IS_NONSTR(connp)) {
-			/* Non-STREAMS socket */
-			boolean_t push = flags & (TH_PUSH|TH_FIN);
-			int	error;
-
-			if ((*connp->conn_upcalls->su_recv)(
-			    connp->conn_upper_handle,
-			    mp, seg_len, 0, &error, &push) <= 0) {
-				/*
-				 * We should never be in middle of a
-				 * fallback, the squeue guarantees that.
-				 */
-				ASSERT(error != EOPNOTSUPP);
-				if (error == ENOSPC)
-					tcp->tcp_rwnd -= seg_len;
-			} else if (push) {
-				/*
-				 * PUSH bit set and sockfs is not
-				 * flow controlled
-				 */
-				flags |= tcp_rwnd_reopen(tcp);
-			}
 		} else if ((flags & (TH_PUSH|TH_FIN)) ||
 		    tcp->tcp_rcv_cnt + seg_len >= tcp->tcp_recv_hiwater >> 3) {
 			if (tcp->tcp_rcv_list != NULL) {
@@ -15018,8 +15028,7 @@
 		 * for a push bit. This provides resiliency against
 		 * implementations that do not correctly generate push bits.
 		 */
-		if (!IPCL_IS_NONSTR(connp) && tcp->tcp_rcv_list != NULL &&
-		    tcp->tcp_push_tid == 0) {
+		if (tcp->tcp_rcv_list != NULL && tcp->tcp_push_tid == 0) {
 			/*
 			 * The connection may be closed at this point, so don't
 			 * do anything for a detached tcp.
@@ -17362,6 +17371,10 @@
 			sopp.sopp_tail = sopp_tail;
 			sopp.sopp_zcopyflag = sopp_copyopt;
 		}
+		if (tcp->tcp_loopback) {
+			sopp.sopp_flags |= SOCKOPT_LOOPBACK;
+			sopp.sopp_loopback = B_TRUE;
+		}
 		(*connp->conn_upcalls->su_set_proto_props)
 		    (connp->conn_upper_handle, &sopp);
 	} else {
@@ -26454,6 +26467,16 @@
 			error = proto_tlitosyserr(-error);
 		}
 	}
+
+	if (tcp->tcp_loopback) {
+		struct sock_proto_props sopp;
+
+		sopp.sopp_flags = SOCKOPT_LOOPBACK;
+		sopp.sopp_loopback = B_TRUE;
+
+		(*connp->conn_upcalls->su_set_proto_props)(
+		    connp->conn_upper_handle, &sopp);
+	}
 done:
 	squeue_synch_exit(sqp, connp);
 
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c	Mon Jul 20 13:07:46 2009 -0400
@@ -762,7 +762,7 @@
 	sli->sli_data_order		= SMS_DATA_ORDER;
 	sli->sli_flags			= BSWAP_32(sli->sli_flags);
 	sli->sli_lu_size		= BSWAP_64(sli->sli_lu_size);
-	sli->sli_meta_fname_offset	= BSWAP_16(sli->sli_meta_fname_offset);
+	sli->sli_meta_fname_offset	= BSWAP_64(sli->sli_meta_fname_offset);
 	sli->sli_data_fname_offset	= BSWAP_16(sli->sli_data_fname_offset);
 	sli->sli_serial_offset		= BSWAP_16(sli->sli_serial_offset);
 	sli->sli_alias_offset		= BSWAP_16(sli->sli_alias_offset);
@@ -1066,6 +1066,9 @@
 	if (sl->sl_alias) {
 		s += strlen(sl->sl_alias) + 1;
 	}
+	if (sl->sl_mgmt_url) {
+		s += strlen(sl->sl_mgmt_url) + 1;
+	}
 	sli = (sbd_lu_info_1_1_t *)kmem_zalloc(sizeof (*sli) + s, KM_SLEEP);
 	p = sli->sli_buf;
 	if ((sl->sl_flags & (SL_SHARED_META | SL_ZFS_META)) == 0) {
@@ -1092,6 +1095,13 @@
 		sli->sli_flags |= SLI_ALIAS_VALID;
 		p += strlen(sl->sl_alias) + 1;
 	}
+	if (sl->sl_mgmt_url) {
+		(void) strcpy((char *)p, sl->sl_mgmt_url);
+		sli->sli_mgmt_url_offset =
+		    (uintptr_t)p - (uintptr_t)sli->sli_buf;
+		sli->sli_flags |= SLI_MGMT_URL_VALID;
+		p += strlen(sl->sl_mgmt_url) + 1;
+	}
 	if (sl->sl_flags & SL_WRITE_PROTECTED) {
 		sli->sli_flags |= SLI_WRITE_PROTECTED;
 	}
@@ -1338,6 +1348,9 @@
 	if (sl->sl_alias_alloc_size) {
 		kmem_free(sl->sl_alias, sl->sl_alias_alloc_size);
 	}
+	if (sl->sl_mgmt_url_alloc_size) {
+		kmem_free(sl->sl_mgmt_url, sl->sl_mgmt_url_alloc_size);
+	}
 	stmf_free(sl->sl_lu);
 	return (ret);
 }
@@ -1368,6 +1381,8 @@
 	    (slu->slu_data_fname_off >= sz) ||
 	    ((slu->slu_alias_valid) &&
 	    (slu->slu_alias_off >= sz)) ||
+	    ((slu->slu_mgmt_url_valid) &&
+	    (slu->slu_mgmt_url_off >= sz)) ||
 	    ((slu->slu_serial_valid) &&
 	    ((slu->slu_serial_off + slu->slu_serial_size) >= sz))) {
 		return (EINVAL);
@@ -1385,6 +1400,9 @@
 	if (slu->slu_alias_valid) {
 		alloc_sz += strlen(namebuf + slu->slu_alias_off) + 1;
 	}
+	if (slu->slu_mgmt_url_valid) {
+		alloc_sz += strlen(namebuf + slu->slu_mgmt_url_off) + 1;
+	}
 	if (slu->slu_serial_valid) {
 		alloc_sz += slu->slu_serial_size;
 	}
@@ -1428,6 +1446,11 @@
 		(void) strcpy(p, namebuf + slu->slu_alias_off);
 		p += strlen(sl->sl_alias) + 1;
 	}
+	if (slu->slu_mgmt_url_valid) {
+		sl->sl_mgmt_url = p;
+		(void) strcpy(p, namebuf + slu->slu_mgmt_url_off);
+		p += strlen(sl->sl_mgmt_url) + 1;
+	}
 	if (slu->slu_serial_valid) {
 		sl->sl_serial_no = (uint8_t *)p;
 		bcopy(namebuf + slu->slu_serial_off, sl->sl_serial_no,
@@ -1784,6 +1807,8 @@
 	    (sli->sli_meta_fname_offset > sli_buf_sz)) ||
 	    ((sli->sli_flags & SLI_DATA_FNAME_VALID) &&
 	    (sli->sli_data_fname_offset > sli_buf_sz)) ||
+	    ((sli->sli_flags & SLI_MGMT_URL_VALID) &&
+	    (sli->sli_mgmt_url_offset > sli_buf_sz)) ||
 	    ((sli->sli_flags & SLI_SERIAL_VALID) &&
 	    ((sli->sli_serial_offset + sli->sli_serial_size) > sli_buf_sz)) ||
 	    ((sli->sli_flags & SLI_ALIAS_VALID) &&
@@ -1855,6 +1880,14 @@
 		(void) strcpy(sl->sl_alias, (char *)sli_buf_copy +
 		    sli->sli_alias_offset);
 	}
+	if (sli->sli_flags & SLI_MGMT_URL_VALID) {
+		sl->sl_mgmt_url_alloc_size = strlen((char *)sli_buf_copy +
+		    sli->sli_mgmt_url_offset) + 1;
+		sl->sl_mgmt_url = kmem_alloc(sl->sl_mgmt_url_alloc_size,
+		    KM_SLEEP);
+		(void) strcpy(sl->sl_mgmt_url, (char *)sli_buf_copy +
+		    sli->sli_mgmt_url_offset);
+	}
 	if (sli->sli_flags & SLI_WRITE_PROTECTED) {
 		sl->sl_flags |= SL_WRITE_PROTECTED;
 	}
@@ -1958,7 +1991,7 @@
 sbd_modify_lu(sbd_modify_lu_t *mlu, int struct_sz, uint32_t *err_ret)
 {
 	sbd_lu_t *sl = NULL;
-	int alias_sz;
+	uint16_t alias_sz;
 	int ret = 0;
 	sbd_it_data_t *it;
 	sbd_status_t sret;
@@ -1982,6 +2015,8 @@
 	/* Lets validate offsets */
 	if (((mlu->mlu_alias_valid) &&
 	    (mlu->mlu_alias_off >= sz)) ||
+	    ((mlu->mlu_mgmt_url_valid) &&
+	    (mlu->mlu_mgmt_url_off >= sz)) ||
 	    (mlu->mlu_by_fname) &&
 	    (mlu->mlu_fname_off >= sz)) {
 		return (EINVAL);
@@ -2088,6 +2123,35 @@
 		mutex_exit(&sl->sl_lock);
 	}
 
+	if (mlu->mlu_mgmt_url_valid) {
+		uint16_t url_sz;
+
+		url_sz = strlen((char *)mlu->mlu_buf + mlu->mlu_mgmt_url_off);
+		if (url_sz > 0)
+			url_sz++;
+
+		mutex_enter(&sl->sl_lock);
+		if (sl->sl_mgmt_url_alloc_size > 0 &&
+		    (url_sz == 0 || sl->sl_mgmt_url_alloc_size < url_sz)) {
+			kmem_free(sl->sl_mgmt_url, sl->sl_mgmt_url_alloc_size);
+			sl->sl_mgmt_url = NULL;
+			sl->sl_mgmt_url_alloc_size = 0;
+		}
+		if (url_sz > 0) {
+			if (sl->sl_mgmt_url_alloc_size == 0) {
+				sl->sl_mgmt_url = kmem_alloc(url_sz, KM_SLEEP);
+				sl->sl_mgmt_url_alloc_size = url_sz;
+			}
+			(void) strcpy(sl->sl_mgmt_url, (char *)mlu->mlu_buf +
+			    mlu->mlu_mgmt_url_off);
+		}
+		for (it = sl->sl_it_list; it != NULL;
+		    it = it->sbd_it_next) {
+			it->sbd_it_ua_conditions |=
+			    SBD_UA_MODE_PARAMETERS_CHANGED;
+		}
+		mutex_exit(&sl->sl_lock);
+	}
 
 	if (mlu->mlu_write_protected_valid) {
 		mutex_enter(&sl->sl_lock);
@@ -2368,6 +2432,9 @@
 		sz += strlen(sl->sl_alias) + 1;
 	}
 
+	if (sl->sl_mgmt_url) {
+		sz += strlen(sl->sl_mgmt_url) + 1;
+	}
 	bzero(oslp, sizeof (*oslp) - 8);
 	oslp->slp_buf_size_needed = sz;
 
@@ -2404,6 +2471,12 @@
 		(void) strcpy((char *)&oslp->slp_buf[off], sl->sl_alias);
 		off += strlen(sl->sl_alias) + 1;
 	}
+	if (sl->sl_mgmt_url) {
+		oslp->slp_mgmt_url_valid = 1;
+		oslp->slp_mgmt_url_off = off;
+		(void) strcpy((char *)&oslp->slp_buf[off], sl->sl_mgmt_url);
+		off += strlen(sl->sl_mgmt_url) + 1;
+	}
 	if (sl->sl_serial_no_size) {
 		oslp->slp_serial_off = off;
 		bcopy(sl->sl_serial_no, &oslp->slp_buf[off],
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c	Mon Jul 20 13:07:46 2009 -0400
@@ -138,7 +138,7 @@
 		if (iolen == 0)
 			break;
 		if (sbd_data_read(sl, laddr, (uint64_t)iolen,
-		    dbuf->db_sglist[0].seg_addr) != STMF_SUCCESS) {
+		    dbuf->db_sglist[ndx].seg_addr) != STMF_SUCCESS) {
 			scmd->flags |= SBD_SCSI_CMD_XFER_FAIL;
 			/* Do not need to do xfer anymore, just complete it */
 			dbuf->db_data_size = 0;
@@ -401,7 +401,7 @@
 		if (iolen == 0)
 			break;
 		if (sbd_data_write(sl, laddr, (uint64_t)iolen,
-		    dbuf->db_sglist[0].seg_addr) != STMF_SUCCESS) {
+		    dbuf->db_sglist[ndx].seg_addr) != STMF_SUCCESS) {
 			scmd->flags |= SBD_SCSI_CMD_XFER_FAIL;
 			break;
 		}
@@ -1070,15 +1070,56 @@
 	    STMF_SAA_INVALID_FIELD_IN_PARAM_LIST);
 }
 
+/*
+ * This function parse through a string, passed to it as a pointer to a string,
+ * by adjusting the pointer to the first non-space character and returns
+ * the count/length of the first bunch of non-space characters. Multiple
+ * Management URLs are stored as a space delimited string in sl_mgmt_url
+ * field of sbd_lu_t. This function is used to retrieve one url at a time.
+ *
+ * i/p : pointer to pointer to a url string
+ * o/p : Adjust the pointer to the url to the first non white character
+ *       and returns the length of the URL
+ */
+uint16_t
+sbd_parse_mgmt_url(char **url_addr) {
+	uint16_t url_length = 0;
+	char *url;
+	url = *url_addr;
+
+	while (*url != '\0') {
+		if (*url == ' ' || *url == '\t' || *url == '\n') {
+			(*url_addr)++;
+			url = *url_addr;
+		} else {
+			break;
+		}
+	}
+
+	while (*url != '\0') {
+		if (*url == ' ' || *url == '\t' ||
+		    *url == '\n' || *url == '\0') {
+			break;
+		}
+		url++;
+		url_length++;
+	}
+	return (url_length);
+}
+
 void
-sbd_handle_inquiry(struct scsi_task *task, struct stmf_data_buf *initial_dbuf,
-			uint8_t *p, int bsize)
+sbd_handle_inquiry(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
 {
 	sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private;
 	uint8_t *cdbp = (uint8_t *)&task->task_cdb[0];
-	uint32_t cmd_size;
+	uint8_t *p;
+	uint8_t byte0;
 	uint8_t page_length;
-	uint8_t byte0;
+	uint16_t bsize = 512;
+	uint16_t cmd_size;
+	uint32_t xfer_size = 4;
+	uint32_t mgmt_url_size = 0;
+
 
 	byte0 = DTYPE_DIRECT;
 	/*
@@ -1096,7 +1137,7 @@
 	 * return success.
 	 */
 
-	cmd_size = (((uint32_t)cdbp[3]) << 8) | cdbp[4];
+	cmd_size = (((uint16_t)cdbp[3]) << 8) | cdbp[4];
 
 	if (cmd_size == 0) {
 		task->task_cmd_xfer_length = 0;
@@ -1108,15 +1149,23 @@
 		return;
 	}
 
+	if (sl->sl_mgmt_url) {
+		mgmt_url_size = strlen(sl->sl_mgmt_url);
+	}
+
 	/*
 	 * Standard inquiry
 	 */
 
 	if ((cdbp[1] & 1) == 0) {
-		struct scsi_inquiry *inq = (struct scsi_inquiry *)p;
+		int	i;
+		struct scsi_inquiry *inq;
 
-		page_length = 31;
-		bzero(inq, page_length + 5);
+		p = (uint8_t *)kmem_zalloc(bsize, KM_SLEEP);
+		inq = (struct scsi_inquiry *)p;
+
+		page_length = 69;
+		xfer_size = page_length + 5;
 
 		inq->inq_dtype = DTYPE_DIRECT;
 		inq->inq_ansi = 5;	/* SPC-3 */
@@ -1124,7 +1173,7 @@
 		inq->inq_rdf = 2;	/* Response data format for SPC-3 */
 		inq->inq_len = page_length;
 
-		inq->inq_tpgs = 1;
+		inq->inq_tpgs = TPGS_FAILOVER_IMPLICIT;
 		inq->inq_cmdque = 1;
 
 		if (sl->sl_flags & SL_VID_VALID) {
@@ -1145,8 +1194,59 @@
 			bcopy(sbd_revision, inq->inq_revision, 4);
 		}
 
+		/* Adding Version Descriptors */
+		i = 0;
+		/* SAM-3 no version */
+		inq->inq_vd[i].inq_vd_msb = 0x00;
+		inq->inq_vd[i].inq_vd_lsb = 0x60;
+		i++;
+
+		/* transport */
+		switch (task->task_lport->lport_id->protocol_id) {
+		case PROTOCOL_FIBRE_CHANNEL:
+			inq->inq_vd[i].inq_vd_msb = 0x09;
+			inq->inq_vd[i].inq_vd_lsb = 0x00;
+			i++;
+			break;
+
+		case PROTOCOL_PARALLEL_SCSI:
+		case PROTOCOL_SSA:
+		case PROTOCOL_IEEE_1394:
+			/* Currently no claims of conformance */
+			break;
+
+		case PROTOCOL_SRP:
+			inq->inq_vd[i].inq_vd_msb = 0x09;
+			inq->inq_vd[i].inq_vd_lsb = 0x40;
+			i++;
+			break;
+
+		case PROTOCOL_iSCSI:
+			inq->inq_vd[i].inq_vd_msb = 0x09;
+			inq->inq_vd[i].inq_vd_lsb = 0x60;
+			i++;
+			break;
+
+		case PROTOCOL_SAS:
+		case PROTOCOL_ADT:
+		case PROTOCOL_ATAPI:
+		default:
+			/* Currently no claims of conformance */
+			break;
+		}
+
+		/* SPC-3 no version */
+		inq->inq_vd[i].inq_vd_msb = 0x03;
+		inq->inq_vd[i].inq_vd_lsb = 0x00;
+		i++;
+
+		/* SBC-2 no version */
+		inq->inq_vd[i].inq_vd_msb = 0x03;
+		inq->inq_vd[i].inq_vd_lsb = 0x20;
+
 		sbd_handle_short_read_transfers(task, initial_dbuf, p, cmd_size,
-		    min(cmd_size, page_length + 5));
+		    min(cmd_size, xfer_size));
+		kmem_free(p, bsize);
 
 		return;
 	}
@@ -1155,18 +1255,30 @@
 	 * EVPD handling
 	 */
 
+	/* Default 512 bytes may not be enough, increase bsize if necessary */
+	if (cdbp[2] == 0x83 || cdbp[2] == 0x85) {
+		if (bsize <  cmd_size)
+			bsize = cmd_size;
+	}
+	p = (uint8_t *)kmem_zalloc(bsize, KM_SLEEP);
+
 	switch (cdbp[2]) {
 	case 0x00:
-		page_length = 4;
-
-		bzero(p, page_length + 4);
+		page_length = 4 + (mgmt_url_size ? 1 : 0);
 
 		p[0] = byte0;
 		p[3] = page_length;
-		p[5] = 0x80;
-		p[6] = 0x83;
-		p[7] = 0x86;
+		/* Supported VPD pages in ascending order */
+		{
+			uint8_t i = 5;
 
+			p[i++] = 0x80;
+			p[i++] = 0x83;
+			if (mgmt_url_size != 0)
+				p[i++] = 0x85;
+			p[i++] = 0x86;
+		}
+		xfer_size = page_length + 4;
 		break;
 
 	case 0x80:
@@ -1174,25 +1286,74 @@
 			page_length = sl->sl_serial_no_size;
 			bcopy(sl->sl_serial_no, p + 4, sl->sl_serial_no_size);
 		} else {
+			/* if no serial num is specified set 4 spaces */
+			page_length = 4;
 			bcopy("    ", p + 4, 4);
 		}
 		p[0] = byte0;
 		p[1] = 0x80;
 		p[3] = page_length;
+		xfer_size = page_length + 4;
 		break;
 
 	case 0x83:
-
-		page_length = stmf_scsilib_prepare_vpd_page83(task, p,
+		xfer_size = stmf_scsilib_prepare_vpd_page83(task, p,
 		    bsize, byte0, STMF_VPD_LU_ID|STMF_VPD_TARGET_ID|
-		    STMF_VPD_TP_GROUP|STMF_VPD_RELATIVE_TP_ID) - 4;
+		    STMF_VPD_TP_GROUP|STMF_VPD_RELATIVE_TP_ID);
 		break;
 
+	case 0x85:
+		if (mgmt_url_size == 0) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INVALID_FIELD_IN_CDB);
+			kmem_free(p, bsize);
+			return;
+		}
+		{
+			uint16_t idx, newidx, sz, url_size;
+			char *url;
+
+			p[0] = byte0;
+			p[1] = 0x85;
+
+			idx = 4;
+			url = sl->sl_mgmt_url;
+			url_size = sbd_parse_mgmt_url(&url);
+			/* Creating Network Service Descriptors */
+			while (url_size != 0) {
+				/* Null terminated and 4 Byte aligned */
+				sz = url_size + 1;
+				sz += (sz % 4) ? 4 - (sz % 4) : 0;
+				newidx = idx + sz + 4;
+
+				if (newidx < bsize) {
+					/*
+					 * SPC-3r23 : Table 320  (Sec 7.6.5)
+					 * (Network service descriptor format
+					 *
+					 * Note: Hard coding service type as
+					 * "Storage Configuration Service".
+					 */
+					p[idx] = 1;
+					SCSI_WRITE16(p + idx + 2, sz);
+					bcopy(url, p + idx + 4, url_size);
+					xfer_size = newidx + 4;
+				}
+				idx = newidx;
+
+				/* skip to next mgmt url if any */
+				url += url_size;
+				url_size = sbd_parse_mgmt_url(&url);
+			}
+
+			/* Total descriptor length */
+			SCSI_WRITE16(p + 2, idx - 4);
+			break;
+		}
+
 	case 0x86:
 		page_length = 0x3c;
 
-		bzero(p, page_length + 4);
-
 		p[0] = byte0;
 		p[1] = 0x86;		/* Page 86 response */
 		p[3] = page_length;
@@ -1204,17 +1365,19 @@
 		 * to claim support only for Simple TA.
 		 */
 		p[5] = 1;
-
+		xfer_size = page_length + 4;
 		break;
 
 	default:
 		stmf_scsilib_send_status(task, STATUS_CHECK,
 		    STMF_SAA_INVALID_FIELD_IN_CDB);
+		kmem_free(p, bsize);
 		return;
 	}
 
 	sbd_handle_short_read_transfers(task, initial_dbuf, p, cmd_size,
-	    min(cmd_size, page_length + 4));
+	    min(cmd_size, xfer_size));
+	kmem_free(p, bsize);
 }
 
 stmf_status_t
@@ -1424,11 +1587,7 @@
 	cdb1 = task->task_cdb[1];
 
 	if (cdb0 == SCMD_INQUIRY) {		/* Inquiry */
-		uint8_t *p;
-
-		p = (uint8_t *)kmem_zalloc(512, KM_SLEEP);
-		sbd_handle_inquiry(task, initial_dbuf, p, 512);
-		kmem_free(p, 512);
+		sbd_handle_inquiry(task, initial_dbuf);
 		return;
 	}
 
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h	Mon Jul 20 13:07:46 2009 -0400
@@ -130,7 +130,7 @@
 	 * metadata is coming in from the correct zvol and not from a
 	 * clone. Has no meaning in any other case.
 	 */
-	uint16_t		sli_meta_fname_offset;
+	uint64_t		sli_meta_fname_offset;
 
 	/*
 	 * Data filename or the media filename when the metadata is in
@@ -145,7 +145,8 @@
 	uint8_t			sli_serial_size;
 	uint8_t			sli_rsvd1;
 	uint8_t			sli_device_id[20];
-	uint8_t			sli_rsvd2[256];
+	uint64_t		sli_mgmt_url_offset;
+	uint8_t			sli_rsvd2[248];
 
 	/*
 	 * In case there is no separate meta, sli_meta_fname_offset wont
@@ -169,6 +170,7 @@
 #define	SLI_ALIAS_VALID				0x0100
 #define	SLI_WRITEBACK_CACHE_DISABLE		0x0200
 #define	SLI_ZFS_META				0x0400
+#define	SLI_MGMT_URL_VALID			0x0800
 
 struct sbd_it_data;
 
@@ -189,6 +191,7 @@
 	/* Metadata */
 	char		*sl_alias;
 	char		*sl_meta_filename;	/* If applicable */
+	char		*sl_mgmt_url;
 	vnode_t		*sl_meta_vp;
 	vtype_t		sl_meta_vtype;
 	uint8_t		sl_device_id[20];	/* 4(hdr) + 16(GUID) */
@@ -203,7 +206,8 @@
 	char		sl_product_id[16];
 	char		sl_revision[4];
 	uint32_t	sl_data_fname_alloc_size; /* for an explicit alloc */
-	uint32_t	sl_alias_alloc_size;
+	uint16_t	sl_alias_alloc_size;
+	uint16_t	sl_mgmt_url_alloc_size;
 	uint8_t		sl_serial_no_alloc_size;
 	uint64_t	sl_meta_offset;
 
--- a/usr/src/uts/common/io/comstar/port/fct/discovery.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/comstar/port/fct/discovery.c	Mon Jul 20 13:07:46 2009 -0400
@@ -2671,6 +2671,52 @@
 	rw_exit(&iport->iport_lock);
 }
 
+void
+fct_rls_cb(fct_i_cmd_t *icmd)
+{
+	fct_els_t		*els = ICMD_TO_ELS(icmd);
+	uint8_t			*resp;
+	fct_rls_cb_data_t	*rls_cb_data = NULL;
+	fct_port_link_status_t	*rls_resp;
+	fct_i_local_port_t	*iport = ICMD_TO_IPORT(icmd);
+
+	rls_cb_data = icmd->icmd_cb_private;
+
+	if (!FCT_IS_ELS_ACC(icmd)) {
+		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_rls_cb: "
+		    "solicited RLS is not accepted - icmd/%p", icmd);
+		if (rls_cb_data) {
+			rls_cb_data->fct_els_res = FCT_FAILURE;
+			sema_v(&iport->iport_rls_sema);
+		}
+		return;
+	}
+
+	if (!rls_cb_data) {
+		sema_v(&iport->iport_rls_sema);
+		return;
+	}
+
+	resp = els->els_resp_payload;
+
+	rls_cb_data = icmd->icmd_cb_private;
+
+	/* Get the response and store it somewhere */
+	rls_resp = (fct_port_link_status_t *)rls_cb_data->fct_link_status;
+	rls_resp->LinkFailureCount = BE_32(*((uint32_t *)(resp + 4)));
+	rls_resp->LossOfSyncCount = BE_32(*((uint32_t *)(resp + 8)));
+	rls_resp->LossOfSignalsCount = BE_32(*((uint32_t *)(resp + 12)));
+	rls_resp->PrimitiveSeqProtocolErrorCount =
+	    BE_32(*((uint32_t *)(resp + 16)));
+	rls_resp->InvalidTransmissionWordCount =
+	    BE_32(*((uint32_t *)(resp + 20)));
+	rls_resp->InvalidCRCCount = BE_32(*((uint32_t *)(resp + 24)));
+
+	rls_cb_data->fct_els_res = FCT_SUCCESS;
+	sema_v(&iport->iport_rls_sema);
+	icmd->icmd_cb_private = NULL;
+}
+
 /*
  * For lookup functions, we move locking up one level
  */
@@ -2758,6 +2804,10 @@
 		page_format = 0x03 & page_buf[0];
 		page_portid = fct_netbuf_to_value(page_buf + 1, 3);
 
+		DTRACE_FC_2(rscn__receive,
+		    fct_i_local_port_t, iport,
+		    int, page_portid);
+
 		rw_enter(&iport->iport_lock, RW_READER);
 		if (!page_format) {
 			irp = fct_portid_to_portptr(iport, page_portid);
--- a/usr/src/uts/common/io/comstar/port/fct/fct.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/comstar/port/fct/fct.c	Mon Jul 20 13:07:46 2009 -0400
@@ -53,6 +53,7 @@
 static int fct_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
     cred_t *credp, int *rval);
 static int fct_fctiocmd(intptr_t data, int mode);
+void fct_init_kstats(fct_i_local_port_t *iport);
 
 static dev_info_t *fct_dip;
 static struct cb_ops fct_cb_ops = {
@@ -91,6 +92,7 @@
 };
 
 #define	FCT_NAME	"COMSTAR FCT"
+#define	FCT_MODULE_NAME	"fct"
 
 extern struct mod_ops mod_driverops;
 static struct modldrv modldrv = {
@@ -633,29 +635,111 @@
 fct_get_port_stats(uint8_t *port_wwn,
     fc_tgt_hba_adapter_port_stats_t *port_stats, uint32_t *error_detail)
 {
+	int ret;
 	fct_i_local_port_t *iport = fct_get_iport_per_wwn(port_wwn);
+	fct_port_link_status_t	stat;
+	uint32_t buf_size = sizeof (fc_tgt_hba_adapter_port_stats_t);
 
 	if (!iport)
 		return (ENXIO);
 	port_stats->version = FCT_HBA_ADAPTER_PORT_STATS_VERSION;
+
+	if (iport->iport_port->port_info == NULL) {
+		*error_detail = FCTIO_FAILURE;
+		return (EIO);
+	}
+	ret = iport->iport_port->port_info(FC_TGT_PORT_RLS,
+	    iport->iport_port, NULL, (uint8_t *)&stat, &buf_size);
+	if (ret != STMF_SUCCESS) {
+		*error_detail = FCTIO_FAILURE;
+		return (EIO);
+	}
+
+	port_stats->SecondsSinceLastReset = 0;
+	port_stats->TxFrames = 0;
+	port_stats->TxWords = 0;
+	port_stats->RxFrames = 0;
+	port_stats->RxWords = 0;
+	port_stats->LIPCount = 0;
+	port_stats->NOSCount = 0;
+	port_stats->ErrorFrames = 0;
+	port_stats->DumpedFrames = 0;
+	port_stats->LinkFailureCount = stat.LinkFailureCount;
+	port_stats->LossOfSyncCount = stat.LossOfSyncCount;
+	port_stats->LossOfSignalCount = stat.LossOfSignalsCount;
+	port_stats->PrimitiveSeqProtocolErrCount =
+	    stat.PrimitiveSeqProtocolErrorCount;
+	port_stats->InvalidTxWordCount =
+	    stat.InvalidTransmissionWordCount;
+	port_stats->InvalidCRCCount = stat.InvalidCRCCount;
+
+	return (ret);
+}
+
+int
+fct_get_link_status(uint8_t *port_wwn, uint64_t *dest_id,
+    fct_port_link_status_t *link_status, uint32_t *error_detail)
+{
+	fct_i_local_port_t *iport = fct_get_iport_per_wwn(port_wwn);
+	fct_i_remote_port_t *irp = NULL;
+	uint32_t buf_size = sizeof (fct_port_link_status_t);
+	stmf_status_t ret = 0;
+	int i;
+	fct_cmd_t *cmd = NULL;
+
+	if (!iport) {
+		*error_detail = FCTIO_BADWWN;
+		return (ENXIO);
+	}
+
 	/*
-	 * port_stats->SecondsSinceLastReset = ;
-	 * port_stats->TxFrames = ;
-	 * port_stats->TxWords = ;
-	 * port_stats->RxFrames = ;
-	 * port_stats->RxWords = ;
-	 * port_stats->LIPCount = ;
-	 * port_stats->NOSCount = ;
-	 * port_stats->ErrorFrames = ;
-	 * port_stats->DumpedFrames = ;
-	 * port_stats->LinkFailureCount = ;
-	 * port_stats->LossOfSyncCount = ;
-	 * port_stats->LossOfSignalCount = ;
-	 * port_stats->PrimitiveSeqProtocol = ;
-	 * port_stats->InvalidTxWordCount = ;
-	 * port_stats->InvalidCRCCount = ;
+	 * If what we are requesting is zero or same as local port,
+	 * then we use port_info()
+	 */
+	if (dest_id == NULL || *dest_id == iport->iport_link_info.portid) {
+		if (iport->iport_port->port_info == NULL) {
+			*error_detail = FCTIO_FAILURE;
+			return (EIO);
+		}
+		ret = iport->iport_port->port_info(FC_TGT_PORT_RLS,
+		    iport->iport_port, NULL,
+		    (uint8_t *)link_status, &buf_size);
+		if (ret == STMF_SUCCESS) {
+			return (0);
+		} else {
+			*error_detail = FCTIO_FAILURE;
+			return (EIO);
+		}
+	}
+
+	/*
+	 * For remote port, we will send RLS
 	 */
-	return (0);
+	for (i = 0; i < rportid_table_size; i++) {
+		irp = iport->iport_rp_tb[i];
+		while (irp) {
+			if (irp->irp_rp->rp_id == *dest_id &&
+			    irp->irp_flags & IRP_PLOGI_DONE) {
+				goto SEND_RLS_ELS;
+			}
+			irp = irp->irp_next;
+		}
+	}
+	return (ENXIO);
+
+SEND_RLS_ELS:
+	cmd = fct_create_solels(iport->iport_port,
+	    irp->irp_rp, 0, ELS_OP_RLS,
+	    0, fct_rls_cb);
+	if (!cmd)
+		return (ENOMEM);
+	iport->iport_rls_cb_data.fct_link_status = link_status;
+	CMD_TO_ICMD(cmd)->icmd_cb_private = &iport->iport_rls_cb_data;
+	fct_post_to_solcmd_queue(iport->iport_port, cmd);
+	sema_p(&iport->iport_rls_sema);
+	if (iport->iport_rls_cb_data.fct_els_res != FCT_SUCCESS)
+		ret = EIO;
+	return (ret);
 }
 
 static int
@@ -788,6 +872,19 @@
 		mutex_exit(&fct_global_mutex);
 		break;
 		}
+	case FCTIO_GET_LINK_STATUS: {
+		uint8_t *port_wwn = (uint8_t *)ibuf;
+		fct_port_link_status_t *link_status =
+		    (fct_port_link_status_t *)obuf;
+		uint64_t *dest_id = abuf;
+
+		mutex_enter(&fct_global_mutex);
+		ret = fct_get_link_status(port_wwn, dest_id, link_status,
+		    &fctio->fctio_errno);
+		mutex_exit(&fct_global_mutex);
+		break;
+		}
+
 	default:
 		break;
 	}
@@ -1018,6 +1115,7 @@
 	mutex_init(&iport->iport_worker_lock, NULL, MUTEX_DRIVER, NULL);
 	cv_init(&iport->iport_worker_cv, NULL, CV_DRIVER, NULL);
 	rw_init(&iport->iport_lock, NULL, RW_DRIVER, NULL);
+	sema_init(&iport->iport_rls_sema, 0, NULL, SEMA_DRIVER, NULL);
 
 	/* Remote port mgmt */
 	iport->iport_rp_slots = (fct_i_remote_port_t **)kmem_zalloc(
@@ -1088,6 +1186,8 @@
 	fct_iport_list = iport;
 	mutex_exit(&fct_global_mutex);
 
+	fct_init_kstats(iport);
+
 	fct_log_local_port_event(port, ESC_SUNFC_PORT_ATTACH);
 
 	return (FCT_SUCCESS);
@@ -1169,6 +1269,7 @@
 	    sizeof (fct_i_remote_port_t *));
 	rw_destroy(&iport->iport_lock);
 	cv_destroy(&iport->iport_worker_cv);
+	sema_destroy(&iport->iport_rls_sema);
 	mutex_destroy(&iport->iport_worker_lock);
 	ddi_taskq_destroy(iport->iport_worker_taskq);
 	if (iport->iport_rp_tb) {
@@ -1176,6 +1277,10 @@
 		    sizeof (fct_i_remote_port_t *));
 	}
 
+	if (iport->iport_kstat_portstat) {
+		kstat_delete(iport->iport_kstat_portstat);
+	}
+
 	fct_log_local_port_event(port, ESC_SUNFC_PORT_DETACH);
 	return (FCT_SUCCESS);
 
@@ -2275,6 +2380,16 @@
 			    kmem_zalloc(els->els_req_size, KM_SLEEP);
 			p[7] = FC_SCR_FULL_REGISTRATION;
 			break;
+		case ELS_OP_RLS:
+			els->els_resp_alloc_size = els->els_resp_size = 28;
+			els->els_resp_payload = (uint8_t *)
+			    kmem_zalloc(els->els_resp_size, KM_SLEEP);
+			els->els_req_alloc_size = els->els_req_size = 8;
+			p = els->els_req_payload = (uint8_t *)
+			    kmem_zalloc(els->els_req_size, KM_SLEEP);
+			ptid = PORT_TO_IPORT(port)->iport_link_info.portid;
+			fct_value_to_netbuf(ptid, els->els_req_payload + 5, 3);
+			break;
 
 		default:
 			ASSERT(0);
@@ -2737,6 +2852,12 @@
 		fct_queue_cmd_for_termination(cmd, FCT_NOT_LOGGED_IN);
 		return;
 	}
+
+	DTRACE_FC_3(abts__receive,
+	    fct_cmd_t, cmd,
+	    fct_local_port_t, port,
+	    fct_i_remote_port_t, irp);
+
 	cmd->cmd_rp = irp->irp_rp;
 
 	/*
@@ -3339,3 +3460,82 @@
 	    from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3],
 	    from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]);
 }
+
+static int
+fct_update_stats(kstat_t *ks, int rw)
+{
+	fct_i_local_port_t *iport;
+	fct_port_stat_t *port_kstat;
+	fct_port_link_status_t stat;
+	uint32_t	buf_size = sizeof (stat);
+	int		ret;
+
+	if (rw == KSTAT_WRITE)
+		return (EACCES);
+
+	iport = (fct_i_local_port_t *)ks->ks_private;
+	port_kstat = (fct_port_stat_t *)ks->ks_data;
+
+	if (iport->iport_port->port_info == NULL) {
+		return (EIO);
+	}
+	ret = iport->iport_port->port_info(FC_TGT_PORT_RLS,
+	    iport->iport_port, NULL, (uint8_t *)&stat, &buf_size);
+	if (ret != STMF_SUCCESS) {
+		return (EIO);
+	}
+
+	port_kstat->link_failure_cnt.value.ui32 =
+	    stat.LinkFailureCount;
+	port_kstat->loss_of_sync_cnt.value.ui32 =
+	    stat.LossOfSyncCount;
+	port_kstat->loss_of_signals_cnt.value.ui32 =
+	    stat.LossOfSignalsCount;
+	port_kstat->prim_seq_protocol_err_cnt.value.ui32 =
+	    stat.PrimitiveSeqProtocolErrorCount;
+	port_kstat->invalid_tx_word_cnt.value.ui32 =
+	    stat.InvalidTransmissionWordCount;
+	port_kstat->invalid_crc_cnt.value.ui32 =
+	    stat.InvalidCRCCount;
+
+	return (0);
+}
+
+void
+fct_init_kstats(fct_i_local_port_t *iport)
+{
+	kstat_t *ks;
+	fct_port_stat_t *port_kstat;
+	char	name[256];
+
+	if (iport->iport_alias)
+		(void) sprintf(name, "iport_%s", iport->iport_alias);
+	else
+		(void) sprintf(name, "iport_%"PRIxPTR"", (uintptr_t)iport);
+	ks = kstat_create(FCT_MODULE_NAME, 0, name, "rawdata",
+	    KSTAT_TYPE_NAMED, sizeof (fct_port_stat_t) / sizeof (kstat_named_t),
+	    0);
+
+	if (ks == NULL) {
+		return;
+	}
+	port_kstat = (fct_port_stat_t *)ks->ks_data;
+
+	iport->iport_kstat_portstat = ks;
+	kstat_named_init(&port_kstat->link_failure_cnt,
+	    "Link_failure_cnt", KSTAT_DATA_UINT32);
+	kstat_named_init(&port_kstat->loss_of_sync_cnt,
+	    "Loss_of_sync_cnt", KSTAT_DATA_UINT32);
+	kstat_named_init(&port_kstat->loss_of_signals_cnt,
+	    "Loss_of_signals_cnt", KSTAT_DATA_UINT32);
+	kstat_named_init(&port_kstat->prim_seq_protocol_err_cnt,
+	    "Prim_seq_protocol_err_cnt", KSTAT_DATA_UINT32);
+	kstat_named_init(&port_kstat->invalid_tx_word_cnt,
+	    "Invalid_tx_word_cnt", KSTAT_DATA_UINT32);
+	kstat_named_init(&port_kstat->invalid_crc_cnt,
+	    "Invalid_crc_cnt", KSTAT_DATA_UINT32);
+	ks->ks_update = fct_update_stats;
+	ks->ks_private = (void *)iport;
+	kstat_install(ks);
+
+}
--- a/usr/src/uts/common/io/comstar/port/fct/fct_impl.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/comstar/port/fct/fct_impl.h	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #ifndef	_FCT_IMPL_H
@@ -154,6 +154,14 @@
 } fct_i_remote_port_t;
 
 /*
+ * structure used for fct_rls_cb() callback private data
+ */
+typedef struct fct_rls_cb_data {
+	struct fct_port_link_status	*fct_link_status;
+	fct_status_t			fct_els_res;
+} fct_rls_cb_data_t;
+
+/*
  * irp flags
  */
 #define	IRP_PLOGI_DONE			0x0001
@@ -266,7 +274,9 @@
 	/* rpwe = remote port with pending els(es) */
 	fct_i_remote_port_t	*iport_rpwe_head;
 	fct_i_remote_port_t	*iport_rpwe_tail;
-
+	kstat_t			*iport_kstat_portstat;
+	ksema_t			iport_rls_sema;
+	fct_rls_cb_data_t	iport_rls_cb_data;
 } fct_i_local_port_t;
 
 #define	IPORT_FLOGI_DONE(iport)	PORT_FLOGI_DONE(&(iport)->iport_link_info)
@@ -423,6 +433,7 @@
 void fct_gcs_cb(fct_i_cmd_t *icmd);
 void fct_gft_cb(fct_i_cmd_t *icmd);
 void fct_gspn_cb(fct_i_cmd_t *icmd);
+void fct_rls_cb(fct_i_cmd_t *icmd);
 disc_action_t fct_process_link_init(fct_i_local_port_t *iport);
 
 #ifdef	__cplusplus
--- a/usr/src/uts/common/io/comstar/port/qlt/qlt.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/comstar/port/qlt/qlt.c	Mon Jul 20 13:07:46 2009 -0400
@@ -888,6 +888,64 @@
 	    FCHBA_MODEL_DESCRIPTION_LEN, "%s", qlt->nvram->model_name);
 }
 
+/* ARGSUSED */
+fct_status_t
+qlt_info(uint32_t cmd, fct_local_port_t *port,
+    void *arg, uint8_t *buf, uint32_t *bufsizep)
+{
+	qlt_state_t	*qlt = (qlt_state_t *)port->port_fca_private;
+	mbox_cmd_t	*mcp;
+	fct_status_t	ret = FCT_SUCCESS;
+	uint8_t		*p;
+	fct_port_link_status_t	*link_status;
+
+	switch (cmd) {
+	case FC_TGT_PORT_RLS:
+		if ((*bufsizep) < sizeof (fct_port_link_status_t)) {
+			ret = FCT_FAILURE;
+			break;
+		}
+		/* send mailbox command to get link status */
+		mcp = qlt_alloc_mailbox_command(qlt, 156);
+		if (mcp == NULL) {
+			ret = FCT_ALLOC_FAILURE;
+			break;
+		}
+
+		/* GET LINK STATUS count */
+		mcp->to_fw[0] = 0x6d;
+		mcp->to_fw[8] = 156/4;
+		mcp->to_fw_mask |= BIT_1 | BIT_8;
+		mcp->from_fw_mask |= BIT_1 | BIT_2;
+
+		ret = qlt_mailbox_command(qlt, mcp);
+		if (ret != QLT_SUCCESS) {
+			qlt_free_mailbox_command(qlt, mcp);
+			break;
+		}
+		qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORCPU);
+
+		p = mcp->dbuf->db_sglist[0].seg_addr;
+		link_status = (fct_port_link_status_t *)buf;
+		link_status->LinkFailureCount = LE_32(*((uint32_t *)p));
+		link_status->LossOfSyncCount = LE_32(*((uint32_t *)(p + 4)));
+		link_status->LossOfSignalsCount = LE_32(*((uint32_t *)(p + 8)));
+		link_status->PrimitiveSeqProtocolErrorCount =
+		    LE_32(*((uint32_t *)(p + 12)));
+		link_status->InvalidTransmissionWordCount =
+		    LE_32(*((uint32_t *)(p + 16)));
+		link_status->InvalidCRCCount =
+		    LE_32(*((uint32_t *)(p + 20)));
+
+		qlt_free_mailbox_command(qlt, mcp);
+		break;
+	default:
+		ret = FCT_FAILURE;
+		break;
+	}
+	return (ret);
+}
+
 fct_status_t
 qlt_port_start(caddr_t arg)
 {
@@ -940,6 +998,7 @@
 	port->port_ctl = qlt_ctl;
 	port->port_flogi_xchg = qlt_do_flogi;
 	port->port_populate_hba_details = qlt_populate_hba_fru_details;
+	port->port_info = qlt_info;
 
 	if (fct_register_local_port(port) != FCT_SUCCESS) {
 		goto qlt_pstart_fail_2_5;
--- a/usr/src/uts/common/io/fibre-channel/impl/fp.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/fibre-channel/impl/fp.c	Mon Jul 20 13:07:46 2009 -0400
@@ -2940,7 +2940,8 @@
 			    p2p_info.d_id,
 			    pd_recepient, KM_NOSLEEP);
 			FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup;"
-			    " P2P port=%p pd=%p", port, pd);
+			    " P2P port=%p pd=%p fp %x pd %x", port, pd,
+			    port->fp_port_id.port_id, p2p_info.d_id);
 			mutex_enter(&port->fp_mutex);
 			return (FC_SUCCESS);
 		}
@@ -3292,7 +3293,9 @@
 		break;
 
 	case FC_PKT_FS_RJT:
-		if (pkt->pkt_reason == FC_REASON_FS_LOGICAL_BUSY) {
+		if ((pkt->pkt_reason == FC_REASON_FS_LOGICAL_BUSY) ||
+		    ((pkt->pkt_reason == FC_REASON_FS_CMD_UNABLE) &&
+		    (pkt->pkt_expln == 0x00))) {
 			cmd->cmd_retry_interval = fp_retry_delay;
 			rval = fp_retry_cmd(pkt);
 		}
@@ -5888,6 +5891,8 @@
 				port->fp_port_id.port_id = s_id;
 				mutex_exit(&port->fp_mutex);
 
+				FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr: fp %x"
+				    "pd %x", port->fp_port_id.port_id, d_id);
 				pd = fctl_create_remote_port(port,
 				    &nwwn, &dwwn, d_id, PD_PLOGI_INITIATOR,
 				    KM_NOSLEEP);
@@ -6116,6 +6121,8 @@
 	if ((pd = pkt->pkt_pd) == NULL) {
 		pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
 		if (pd == NULL) {
+			FP_TRACE(FP_NHEAD2(9, 0), "fp_plogi_intr: fp %x pd %x",
+			    port->fp_port_id.port_id, d_id);
 			pd = fctl_create_remote_port(port, &nwwn, &pwwn, d_id,
 			    PD_PLOGI_INITIATOR, KM_NOSLEEP);
 			if (pd == NULL) {
@@ -12091,6 +12098,8 @@
 		do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
 		mutex_exit(&port->fp_mutex);
 
+		FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_acc_init fp %x, pd %x",
+		    port->fp_port_id.port_id, buf->ub_frame.s_id);
 		pd = fctl_create_remote_port(port, &req->node_ww_name,
 		    &req->nport_ww_name, buf->ub_frame.s_id,
 		    PD_PLOGI_RECEPIENT, sleep);
@@ -12774,6 +12783,11 @@
 
 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
 
+	if (ns_cmd->ns_cmd_code == NS_GA_NXT) {
+		FP_TRACE(FP_NHEAD1(1, 0), "fp_ns_query GA_NXT fp %x pd %x",
+		    port->fp_port_id.port_id, ns_cmd->ns_gan_sid);
+	}
+
 	if (ns_cmd->ns_cmd_size == 0) {
 		return (FC_FAILURE);
 	}
@@ -12958,8 +12972,11 @@
 
 		}
 
-		FP_TRACE(FP_NHEAD1(4, 0), "NS failure; pkt state=%x reason=%x",
-		    pkt->pkt_state, pkt->pkt_reason);
+		FP_TRACE(FP_NHEAD2(9, 0), "%x NS failure pkt state=%x"
+		    "reason=%x, expln=%x, NSCMD=%04X, NSRSP=%04X",
+		    port->fp_port_id.port_id, pkt->pkt_state,
+		    pkt->pkt_reason, pkt->pkt_expln,
+		    cmd_hdr.ct_cmdrsp,  resp_hdr.ct_cmdrsp);
 
 		(void) fp_common_intr(pkt, 1);
 
@@ -13046,9 +13063,8 @@
 	my_did = (d_id.port_id == port->fp_port_id.port_id) ? 1 : 0;
 	mutex_exit(&port->fp_mutex);
 
-	FP_TRACE(FP_NHEAD1(1, 0), "GAN response; port=%p, d_id=%x", port,
-	    d_id.port_id);
-
+	FP_TRACE(FP_NHEAD1(1, 0), "GAN response; port=%p, fp %x pd %x", port,
+	    port->fp_port_id.port_id, d_id.port_id);
 	if (my_did == 0) {
 		la_wwn_t pwwn;
 		la_wwn_t nwwn;
@@ -13086,6 +13102,8 @@
 		    DDI_DEV_AUTOINCR);
 
 		if (ns_cmd->ns_flags & FCTL_NS_CREATE_DEVICE && pd == NULL) {
+			FP_TRACE(FP_NHEAD1(1, 0), "fp %x gan_hander create"
+			    "pd %x", port->fp_port_id.port_id, d_id.port_id);
 			pd = fctl_create_remote_port(port, &nwwn, &pwwn,
 			    d_id.port_id, PD_PLOGI_INITIATOR, KM_NOSLEEP);
 		}
--- a/usr/src/uts/common/io/fibre-channel/ulp/fcsm.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/fibre-channel/ulp/fcsm.c	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -39,7 +39,7 @@
 #include <sys/fibre-channel/ulp/fcsm.h>
 
 /* Definitions */
-#define	FCSM_VERSION		"1.26"
+#define	FCSM_VERSION		"1.27"
 #define	FCSM_NAME_VERSION	"SunFC FCSM v" FCSM_VERSION
 
 
@@ -1624,45 +1624,45 @@
 	}
 
 	case  FCSMIO_ADAPTER_LIST: {
-	    fc_hba_list_t	*list;
-	    int			count;
-
-	    if ((fcio->fcio_xfer != FCIO_XFER_RW) ||
+		fc_hba_list_t	*list;
+		int		count;
+
+		if ((fcio->fcio_xfer != FCIO_XFER_RW) ||
 		    (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) {
-		retval = EINVAL;
-		break;
-	    }
-
-	    list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
-
-	    if (ddi_copyin(fcio->fcio_obuf, list, fcio->fcio_olen, mode)) {
-		retval = EFAULT;
-		break;
-	    }
-	    list->version = FC_HBA_LIST_VERSION;
-
-	    if (fcio->fcio_olen < MAXPATHLEN * list->numAdapters) {
-		retval = EFAULT;
-		break;
-	    }
-
-	    count = fc_ulp_get_adapter_paths((char *)list->hbaPaths,
-		list->numAdapters);
-	    if (count < 0) { /* Did something go wrong? */
-		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
-		    "Error fetching adapter list."));
-		retval = ENXIO;
+			retval = EINVAL;
+			break;
+		}
+
+		list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
+
+		if (ddi_copyin(fcio->fcio_obuf, list, fcio->fcio_olen, mode)) {
+			retval = EFAULT;
+			break;
+		}
+		list->version = FC_HBA_LIST_VERSION;
+
+		if (fcio->fcio_olen < MAXPATHLEN * list->numAdapters) {
+			retval = EFAULT;
+			break;
+		}
+
+		count = fc_ulp_get_adapter_paths((char *)list->hbaPaths,
+		    list->numAdapters);
+		if (count < 0) { /* Did something go wrong? */
+			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
+			    "Error fetching adapter list."));
+			retval = ENXIO;
+			kmem_free(list, fcio->fcio_olen);
+			break;
+		}
+		/* Sucess (or short buffer) */
+		list->numAdapters = count;
+		if (ddi_copyout(list, fcio->fcio_obuf,
+		    fcio->fcio_olen, mode)) {
+			retval = EFAULT;
+		}
 		kmem_free(list, fcio->fcio_olen);
 		break;
-	    }
-	    /* Sucess (or short buffer) */
-	    list->numAdapters = count;
-	    if (ddi_copyout(list, fcio->fcio_obuf,
-		    fcio->fcio_olen, mode)) {
-		retval = EFAULT;
-	    }
-	    kmem_free(list, fcio->fcio_olen);
-	    break;
 	}
 
 	default:
@@ -2752,10 +2752,10 @@
 	ASSERT(fcio != NULL);
 
 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
-		fcsm_display(CE_WARN, SM_LOG, cmd->cmd_fcsm, pkt,
+		FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, cmd->cmd_fcsm, pkt,
 		    "ct_intr: CT command <0x%x> to did 0x%x failed",
 		    ((fc_ct_aiu_t *)fcio->fcio_ibuf)->aiu_header.ct_cmdrsp,
-		    pkt->pkt_cmd_fhdr.d_id);
+		    pkt->pkt_cmd_fhdr.d_id));
 	} else {
 		/* Get the CT response payload */
 		FCSM_REP_RD(pkt->pkt_resp_acc, fcio->fcio_obuf,
@@ -3249,9 +3249,9 @@
 	fcsm = cmd->cmd_fcsm;
 	ASSERT(fcsm != NULL);
 
-	fcsm_display(CE_WARN, SM_LOG, cmd->cmd_fcsm, pkt,
+	FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, cmd->cmd_fcsm, pkt,
 	    "fc packet to DID 0x%x failed for pkt 0x%p",
-	    pkt->pkt_cmd_fhdr.d_id, pkt);
+	    pkt->pkt_cmd_fhdr.d_id, pkt));
 
 	mutex_enter(&fcsm->sm_mutex);
 	if (fcsm->sm_flags & FCSM_LINK_DOWN) {
--- a/usr/src/uts/common/io/hxge/hxge.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/hxge/hxge.h	Mon Jul 20 13:07:46 2009 -0400
@@ -18,6 +18,7 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
@@ -397,6 +398,7 @@
 	uint32_t 		hxge_port_rcr_size;
 	uint32_t 		hxge_port_tx_ring_size;
 
+	kmutex_t		vmac_lock;
 	kmutex_t		pio_lock;
 	hxge_timeout		timeout;
 
--- a/usr/src/uts/common/io/hxge/hxge_hw.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/hxge/hxge_hw.c	Mon Jul 20 13:07:46 2009 -0400
@@ -111,14 +111,13 @@
 {
 	p_hxge_ldv_t		ldvp = (p_hxge_ldv_t)arg1;
 	p_hxge_t		hxgep = (p_hxge_t)arg2;
-	uint_t			serviced = DDI_INTR_UNCLAIMED;
 	uint8_t			ldv;
 	hpi_handle_t		handle;
 	p_hxge_ldgv_t		ldgvp;
 	p_hxge_ldg_t		ldgp, t_ldgp;
 	p_hxge_ldv_t		t_ldvp;
 	uint32_t		vector0 = 0, vector1 = 0;
-	int			i, j, nldvs, nintrs = 1;
+	int			j, nldvs;
 	hpi_status_t		rs = HPI_SUCCESS;
 
 	/*
@@ -130,23 +129,20 @@
 
 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr"));
 
-	if (!(hxgep->drv_state & STATE_HW_INITIALIZED)) {
+	if (hxgep->hxge_mac_state != HXGE_MAC_STARTED) {
 		HXGE_ERROR_MSG((hxgep, INT_CTL,
-		    "<== hxge_intr: not initialized 0x%x", serviced));
-		return (serviced);
+		    "<== hxge_intr: not initialized"));
+		return (DDI_INTR_UNCLAIMED);
 	}
 
 	ldgvp = hxgep->ldgvp;
 
 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr: ldgvp $%p", ldgvp));
 
-	if (ldvp == NULL && ldgvp) {
+	if (ldvp == NULL && ldgvp)
 		t_ldvp = ldvp = ldgvp->ldvp;
-	}
-
-	if (ldvp) {
+	if (ldvp)
 		ldgp = t_ldgp = ldvp->ldgp;
-	}
 
 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr: "
 	    "ldgvp $%p ldvp $%p ldgp $%p", ldgvp, ldvp, ldgp));
@@ -167,65 +163,62 @@
 	handle = HXGE_DEV_HPI_HANDLE(hxgep);
 	t_ldgp = ldgp;
 	t_ldvp = ldgp->ldvp;
-
 	nldvs = ldgp->nldvs;
 
 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr: #ldvs %d #intrs %d",
 	    nldvs, ldgvp->ldg_intrs));
-
-	serviced = DDI_INTR_CLAIMED;
-	for (i = 0; i < nintrs; i++, t_ldgp++) {
-		HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr(%d): #ldvs %d "
-		    " #intrs %d", i, nldvs, nintrs));
+	HXGE_DEBUG_MSG((hxgep, INT_CTL,
+	    "==> hxge_intr(%d): #ldvs %d", i, nldvs));
 
-		/* Get this group's flag bits. */
-		t_ldgp->interrupted = B_FALSE;
-		rs = hpi_ldsv_ldfs_get(handle, t_ldgp->ldg, &vector0, &vector1);
-		if (rs) {
-			continue;
-		}
+	/*
+	 * Get this group's flag bits.
+	 */
+	t_ldgp->interrupted = B_FALSE;
+	rs = hpi_ldsv_ldfs_get(handle, t_ldgp->ldg, &vector0, &vector1);
+	if (rs != HPI_SUCCESS)
+		return (DDI_INTR_UNCLAIMED);
 
-		if (!vector0 && !vector1) {
-			HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr: "
-			    "no interrupts on group %d", t_ldgp->ldg));
-			continue;
-		}
+	if (!vector0 && !vector1) {
+		HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr: "
+		    "no interrupts on group %d", t_ldgp->ldg));
+		return (DDI_INTR_UNCLAIMED);
+	}
 
-		HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr: "
-		    "vector0 0x%llx vector1 0x%llx", vector0, vector1));
+	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr: "
+	    "vector0 0x%llx vector1 0x%llx", vector0, vector1));
 
-		t_ldgp->interrupted = B_TRUE;
-		nldvs = t_ldgp->nldvs;
+	t_ldgp->interrupted = B_TRUE;
+	nldvs = t_ldgp->nldvs;
 
-		for (j = 0; j < nldvs; j++, t_ldvp++) {
-			/*
-			 * Call device's handler if flag bits are on.
-			 */
-			ldv = t_ldvp->ldv;
-			if ((LDV_ON(ldv, vector0) | (LDV_ON(ldv, vector1)))) {
-				HXGE_DEBUG_MSG((hxgep, INT_CTL,
-				    "==> hxge_intr: calling device %d"
-				    " #ldvs %d #intrs %d", j, nldvs, nintrs));
-				(void) (t_ldvp->ldv_intr_handler)(
-				    (caddr_t)t_ldvp, arg2);
-			}
+	/*
+	 * Process all devices that share this group.
+	 */
+	for (j = 0; j < nldvs; j++, t_ldvp++) {
+		/*
+		 * Call device's handler if flag bits are on.
+		 */
+		ldv = t_ldvp->ldv;
+		if ((LDV_ON(ldv, vector0) | (LDV_ON(ldv, vector1)))) {
+			HXGE_DEBUG_MSG((hxgep, INT_CTL,
+			    "==> hxge_intr: calling device %d"
+			    " #ldvs %d #intrs %d", j, nldvs, nintrs));
+			(void) (t_ldvp->ldv_intr_handler)(
+			    (caddr_t)t_ldvp, arg2);
 		}
 	}
 
-	t_ldgp = ldgp;
-	for (i = 0; i < nintrs; i++, t_ldgp++) {
-		/* rearm group interrupts */
-		if (t_ldgp->interrupted) {
-			HXGE_DEBUG_MSG((hxgep, INT_CTL,
-			    "==> hxge_intr: arm group %d", t_ldgp->ldg));
-			(void) hpi_intr_ldg_mgmt_set(handle, t_ldgp->ldg,
-			    t_ldgp->arm, t_ldgp->ldg_timer);
-		}
+	/*
+	 * Re-arm group interrupts
+	 */
+	if (t_ldgp->interrupted) {
+		HXGE_DEBUG_MSG((hxgep, INT_CTL,
+		    "==> hxge_intr: arm group %d", t_ldgp->ldg));
+		(void) hpi_intr_ldg_mgmt_set(handle, t_ldgp->ldg,
+		    t_ldgp->arm, t_ldgp->ldg_timer);
 	}
 
-	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_intr: serviced 0x%x",
-	    serviced));
-	return (serviced);
+	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_intr"));
+	return (DDI_INTR_CLAIMED);
 }
 
 hxge_status_t
@@ -338,7 +331,6 @@
 	}
 
 	HXGE_FM_REPORT_ERROR(hxgep, NULL, HXGE_FM_EREPORT_PEU_ERR);
-
 	return (HXGE_OK);
 }
 
@@ -351,10 +343,9 @@
 	p_hxge_ldg_t	ldgp = NULL;
 	hpi_handle_t	handle;
 	dev_err_stat_t	estat;
-	uint_t		serviced = DDI_INTR_UNCLAIMED;
 
 	if ((arg1 == NULL) && (arg2 == NULL)) {
-		return (serviced);
+		return (DDI_INTR_UNCLAIMED);
 	}
 
 	if ((arg2 == NULL) ||
@@ -375,12 +366,11 @@
 			    "arg2 $%p arg1 $%p", hxgep, ldvp));
 			return (DDI_INTR_UNCLAIMED);
 		}
-		/*
-		 * Get the logical device state if the function uses interrupt.
-		 */
 	}
 
-	/* This interrupt handler is for system error interrupts.  */
+	/*
+	 * This interrupt handler is for system error interrupts.
+	 */
 	handle = HXGE_DEV_HPI_HANDLE(hxgep);
 	estat.value = 0;
 	(void) hpi_fzc_sys_err_stat_get(handle, &estat);
@@ -417,8 +407,6 @@
 		    "==> hxge_syserr_intr: device error - unknown"));
 	}
 
-	serviced = DDI_INTR_CLAIMED;
-
 	if ((ldgp != NULL) && (ldvp != NULL) &&
 	    (ldgp->nldvs == 1) && !ldvp->use_timer) {
 		(void) hpi_intr_ldg_mgmt_set(handle, ldgp->ldg,
@@ -426,7 +414,7 @@
 	}
 
 	HXGE_DEBUG_MSG((hxgep, SYSERR_CTL, "<== hxge_syserr_intr"));
-	return (serviced);
+	return (DDI_INTR_CLAIMED);
 }
 
 void
--- a/usr/src/uts/common/io/hxge/hxge_kstats.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/hxge/hxge_kstats.c	Mon Jul 20 13:07:46 2009 -0400
@@ -1234,13 +1234,18 @@
 		val = 0;
 		break;
 
+	case ETHER_STAT_ADV_CAP_10GFDX:
+	case ETHER_STAT_CAP_10GFDX:
+	case ETHER_STAT_LP_CAP_10GFDX:
+		val = 0;
+		break;
+
 	default:
 		/*
 		 * Shouldn't reach here...
 		 */
 		cmn_err(CE_WARN,
 		    "hxge_m_stat: unrecognized parameter value = 0x%x", stat);
-
 		return (ENOTSUP);
 	}
 	*value = val;
--- a/usr/src/uts/common/io/hxge/hxge_main.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/hxge/hxge_main.c	Mon Jul 20 13:07:46 2009 -0400
@@ -34,11 +34,7 @@
  * (This PSARC case is limited to MSI-X vectors
  *  and SPARC platforms only).
  */
-#if defined(_BIG_ENDIAN)
 uint32_t hxge_msi_enable = 2;
-#else
-uint32_t hxge_msi_enable = 2;
-#endif
 
 /*
  * Globals: tunable parameters (/etc/system or adb)
@@ -911,6 +907,8 @@
 	 */
 	MUTEX_INIT(hxgep->genlock, NULL,
 	    MUTEX_DRIVER, (void *) hxgep->interrupt_cookie);
+	MUTEX_INIT(&hxgep->vmac_lock, NULL,
+	    MUTEX_DRIVER, (void *) hxgep->interrupt_cookie);
 	MUTEX_INIT(&hxgep->ouraddr_lock, NULL,
 	    MUTEX_DRIVER, (void *) hxgep->interrupt_cookie);
 	RW_INIT(&hxgep->filter_lock, NULL,
@@ -935,6 +933,7 @@
 {
 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_destroy_mutexes"));
 	RW_DESTROY(&hxgep->filter_lock);
+	MUTEX_DESTROY(&hxgep->vmac_lock);
 	MUTEX_DESTROY(&hxgep->ouraddr_lock);
 	MUTEX_DESTROY(hxgep->genlock);
 	MUTEX_DESTROY(&hxgep->pio_lock);
@@ -2646,6 +2645,7 @@
 	 * Fill in the handle for the transmit.
 	 */
 	MUTEX_ENTER(&ring->lock);
+	rhp->started = B_TRUE;
 	ring->ring_handle = rhp->ring_handle;
 	MUTEX_EXIT(&ring->lock);
 
@@ -2667,6 +2667,7 @@
 
 	MUTEX_ENTER(&ring->lock);
 	ring->ring_handle = (mac_ring_handle_t)NULL;
+	rhp->started = B_FALSE;
 	MUTEX_EXIT(&ring->lock);
 }
 
--- a/usr/src/uts/common/io/hxge/hxge_rxdma.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/hxge/hxge_rxdma.c	Mon Jul 20 13:07:46 2009 -0400
@@ -25,6 +25,8 @@
 
 #include <hxge_impl.h>
 #include <hxge_rxdma.h>
+#include <hpi.h>
+#include <hpi_vir.h>
 
 /*
  * Number of blocks to accumulate before re-enabling DMA
@@ -258,18 +260,20 @@
 		return (HXGE_ERROR | rs);
 	}
 
-	/* Enable the DMA */
-	rs = hpi_rxdma_cfg_rdc_enable(handle, channel);
-	if (rs != HPI_SUCCESS) {
-		return (HXGE_ERROR | rs);
-	}
-
 	/* Kick the DMA engine */
 	hpi_rxdma_rdc_rbr_kick(handle, channel, n_init_kick);
 
 	/* Clear the rbr empty bit */
 	(void) hpi_rxdma_channel_rbr_empty_clear(handle, channel);
 
+	/*
+	 * Enable the DMA
+	 */
+	rs = hpi_rxdma_cfg_rdc_enable(handle, channel);
+	if (rs != HPI_SUCCESS) {
+		return (HXGE_ERROR | rs);
+	}
+
 	HXGE_DEBUG_MSG((hxgep, DMA_CTL, "<== hxge_enable_rxdma_channel"));
 
 	return (HXGE_OK);
@@ -737,8 +741,10 @@
 {
 	HXGE_DEBUG_MSG((hxgep, RX_CTL, "==> hxge_rxdma_stop"));
 
+	MUTEX_ENTER(&hxgep->vmac_lock);
 	(void) hxge_rx_vmac_disable(hxgep);
 	(void) hxge_rxdma_hw_mode(hxgep, HXGE_DMA_STOP);
+	MUTEX_EXIT(&hxgep->vmac_lock);
 
 	HXGE_DEBUG_MSG((hxgep, RX_CTL, "<== hxge_rxdma_stop"));
 }
@@ -752,7 +758,9 @@
 	(void) hxge_uninit_rxdma_channels(hxgep);
 	(void) hxge_init_rxdma_channels(hxgep);
 
+	MUTEX_ENTER(&hxgep->vmac_lock);
 	(void) hxge_rx_vmac_enable(hxgep);
+	MUTEX_EXIT(&hxgep->vmac_lock);
 
 	HXGE_DEBUG_MSG((hxgep, RX_CTL, "<== hxge_rxdma_stop_reinit"));
 }
@@ -1132,7 +1140,6 @@
 	uint8_t			channel;
 	hpi_handle_t		handle;
 	rdc_stat_t		cs;
-	uint_t			serviced = DDI_INTR_UNCLAIMED;
 	p_rx_rcr_ring_t		ring;
 	mblk_t			*mp = NULL;
 
@@ -1146,13 +1153,6 @@
 		hxgep = ldvp->hxgep;
 	}
 
-	/*
-	 * If the interface is not started, just swallow the interrupt
-	 * for the logical device and don't rearm it.
-	 */
-	if (hxgep->hxge_mac_state != HXGE_MAC_STARTED)
-		return (DDI_INTR_CLAIMED);
-
 	HXGE_DEBUG_MSG((hxgep, RX_INT_CTL,
 	    "==> hxge_rx_intr: arg2 $%p arg1 $%p", hxgep, ldvp));
 
@@ -1175,71 +1175,61 @@
 
 	MUTEX_ENTER(&ring->lock);
 
-	/*
-	 * If the channel is not started, then we are not
-	 * ready to process packets.
-	 */
-	if (!rhp->started) {
-		MUTEX_EXIT(&ring->lock);
-		return (DDI_INTR_CLAIMED);
-	}
-
-	RXDMA_REG_READ64(handle, RDC_STAT, channel, &cs.value);
-	cs.bits.ptrread = 0;
-	cs.bits.pktread = 0;
-	RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value);
-
-	HXGE_DEBUG_MSG((hxgep, RX_INT_CTL, "==> hxge_rx_intr:channel %d "
-	    "cs 0x%016llx rcrto 0x%x rcrthres %x",
-	    channel, cs.value, cs.bits.rcr_to, cs.bits.rcr_thres));
-
-	/*
-	 * Process packets, if we are not in polling mode. The MAC layer
-	 * under load will be operating in polling mode for RX traffic.
-	 */
-	if (ring->poll_flag == 0) {
-		mp = hxge_rx_pkts(hxgep, ldvp->vdma_index, ldvp, ring, cs, -1);
-	}
-	serviced = DDI_INTR_CLAIMED;
-
-	/* error events. */
-	if (cs.value & RDC_STAT_ERROR) {
-		(void) hxge_rx_err_evnts(hxgep, ldvp->vdma_index, ldvp, cs);
+	if (!ring->poll_flag) {
+		RXDMA_REG_READ64(handle, RDC_STAT, channel, &cs.value);
+		cs.bits.ptrread = 0;
+		cs.bits.pktread = 0;
+		RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value);
+
+		/*
+		 * Process packets, if we are not in polling mode, the ring is
+		 * started and the interface is started. The MAC layer under
+		 * load will be operating in polling mode for RX traffic.
+		 */
+		if ((rhp->started) &&
+		    (hxgep->hxge_mac_state == HXGE_MAC_STARTED)) {
+			mp = hxge_rx_pkts(hxgep, ldvp->vdma_index,
+			    ldvp, ring, cs, -1);
+		}
+
+		/* Process error events. */
+		if (cs.value & RDC_STAT_ERROR) {
+			MUTEX_EXIT(&ring->lock);
+			(void) hxge_rx_err_evnts(hxgep, channel, ldvp, cs);
+			MUTEX_ENTER(&ring->lock);
+		}
+
+		/*
+		 * Enable the mailbox update interrupt if we want to use
+		 * mailbox. We probably don't need to use mailbox as it only
+		 * saves us one pio read.  Also write 1 to rcrthres and
+		 * rcrto to clear these two edge triggered bits.
+		 */
+		cs.value &= RDC_STAT_WR1C;
+		cs.bits.mex = 1;
+		cs.bits.ptrread = 0;
+		cs.bits.pktread = 0;
+		RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value);
+
+		if (ldgp->nldvs == 1) {
+			/*
+			 * Re-arm the group.
+			 */
+			(void) hpi_intr_ldg_mgmt_set(handle, ldgp->ldg, B_TRUE,
+			    ldgp->ldg_timer);
+		}
+	} else if ((ldgp->nldvs == 1) && (ring->poll_flag)) {
+		/*
+		 * Disarm the group, if we are not a shared interrupt.
+		 */
+		(void) hpi_intr_ldg_mgmt_set(handle, ldgp->ldg, B_FALSE, 0);
+	} else if (ring->poll_flag) {
+		/*
+		 * Mask-off this device from the group.
+		 */
+		(void) hpi_intr_mask_set(handle, ldvp->ldv, 1);
 	}
 
-	/*
-	 * Enable the mailbox update interrupt if we want to use mailbox. We
-	 * probably don't need to use mailbox as it only saves us one pio read.
-	 * Also write 1 to rcrthres and rcrto to clear these two edge triggered
-	 * bits.
-	 */
-	cs.value &= RDC_STAT_WR1C;
-	cs.bits.mex = 1;
-	cs.bits.ptrread = 0;
-	cs.bits.pktread = 0;
-	RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value);
-
-	/*
-	 * Rearm this logical group if this is a single device group.
-	 */
-	if (ring->poll_flag) {
-		if (ldgp->nldvs == 1) {
-			ld_intr_mgmt_t mgm;
-
-			mgm.value = 0;
-			mgm.bits.arm = 0;
-			HXGE_REG_WR32(handle,
-			    LD_INTR_MGMT + LDSV_OFFSET(ldgp->ldg), mgm.value);
-		}
-	} else if (ldgp->nldvs == 1) {
-		ld_intr_mgmt_t mgm;
-
-		mgm.value = 0;
-		mgm.bits.arm = 1;
-		mgm.bits.timer = ldgp->ldg_timer;
-		HXGE_REG_WR32(handle,
-		    LD_INTR_MGMT + LDSV_OFFSET(ldgp->ldg), mgm.value);
-	}
 	MUTEX_EXIT(&ring->lock);
 
 	/*
@@ -1250,9 +1240,8 @@
 		    ring->rcr_gen_num);
 	}
 
-	HXGE_DEBUG_MSG((hxgep, RX_INT_CTL,
-	    "<== hxge_rx_intr: serviced %d", serviced));
-	return (serviced);
+	HXGE_DEBUG_MSG((NULL, RX_INT_CTL, "<== hxge_rx_intr"));
+	return (DDI_INTR_CLAIMED);
 }
 
 /*
@@ -1268,26 +1257,34 @@
 	p_hxge_ldg_t		ldgp;
 
 	if (ring_handle == NULL) {
-		return (0);
+		ASSERT(ring_handle != NULL);
+		return (1);
 	}
 
+
 	hxgep = ring_handle->hxgep;
 	ringp = hxgep->rx_rcr_rings->rcr_rings[ring_handle->index];
 
 	MUTEX_ENTER(&ringp->lock);
 
+	/*
+	 * Are we already polling ?
+	 */
+	if (ringp->poll_flag) {
+		MUTEX_EXIT(&ringp->lock);
+		return (1);
+	}
+
 	ldgp = ringp->ldgp;
 	if (ldgp == NULL) {
 		MUTEX_EXIT(&ringp->lock);
-		return (0);
+		return (1);
 	}
 
 	/*
 	 * Enable polling
 	 */
-	if (ringp->poll_flag == 0) {
-		ringp->poll_flag = 1;
-	}
+	ringp->poll_flag = B_TRUE;
 
 	MUTEX_EXIT(&ringp->lock);
 	return (0);
@@ -1304,6 +1301,7 @@
 	p_hxge_t		hxgep;
 
 	if (ring_handle == NULL) {
+		ASSERT(ring_handle != NULL);
 		return (0);
 	}
 
@@ -1318,26 +1316,12 @@
 	if (ringp->poll_flag) {
 		hpi_handle_t		handle;
 		rdc_stat_t		cs;
-		uint8_t			channel;
 		p_hxge_ldg_t		ldgp;
 
 		/*
 		 * Get the control and status for this channel.
 		 */
 		handle = HXGE_DEV_HPI_HANDLE(hxgep);
-		channel = ringp->rdc;
-		RXDMA_REG_READ64(handle, RDC_STAT, channel, &cs.value);
-
-		/*
-		 * Enable mailbox update
-		 * Since packets were not read and the hardware uses
-		 * bits pktread and ptrread to update the queue
-		 * length, we need to set both bits to 0.
-		 */
-		cs.bits.pktread = 0;
-		cs.bits.ptrread = 0;
-		cs.bits.mex = 1;
-		RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value);
 
 		/*
 		 * Rearm this logical group if this is a single device
@@ -1345,21 +1329,37 @@
 		 */
 		ldgp = ringp->ldgp;
 		if (ldgp == NULL) {
-			ringp->poll_flag = 0;
 			MUTEX_EXIT(&ringp->lock);
-			return (0);
+			return (1);
 		}
 
+		ringp->poll_flag = B_FALSE;
+
+		/*
+		 * Enable mailbox update, to start interrupts again.
+		 */
+		cs.value = 0ULL;
+		cs.bits.mex = 1;
+		cs.bits.pktread = 0;
+		cs.bits.ptrread = 0;
+		RXDMA_REG_WRITE64(handle, RDC_STAT, ringp->rdc, cs.value);
+
 		if (ldgp->nldvs == 1) {
-			ld_intr_mgmt_t mgm;
-
-			mgm.value = 0;
-			mgm.bits.arm = 1;
-			mgm.bits.timer = ldgp->ldg_timer;
-			HXGE_REG_WR32(handle,
-			    LD_INTR_MGMT + LDSV_OFFSET(ldgp->ldg), mgm.value);
+			/*
+			 * Re-arm the group, since it is the only member
+			 * of the group.
+			 */
+			(void) hpi_intr_ldg_mgmt_set(handle, ldgp->ldg, B_TRUE,
+			    ldgp->ldg_timer);
+		} else {
+			/*
+			 * Mask-on interrupts for the device and re-arm
+			 * the group.
+			 */
+			(void) hpi_intr_mask_set(handle, ringp->ldvp->ldv, 0);
+			(void) hpi_intr_ldg_mgmt_set(handle, ldgp->ldg, B_TRUE,
+			    ldgp->ldg_timer);
 		}
-		ringp->poll_flag = 0;
 	}
 	MUTEX_EXIT(&ringp->lock);
 	return (0);
@@ -1388,23 +1388,25 @@
 	ring = hxgep->rx_rcr_rings->rcr_rings[rhp->index];
 
 	MUTEX_ENTER(&ring->lock);
-	ASSERT(ring->poll_flag == 1);
+	ASSERT(ring->poll_flag == B_TRUE);
 	ASSERT(rhp->started);
 
-	/*
-	 * Make sure the ring is started and polling is
-	 * started before processing packets.
-	 */
-	if ((!rhp->started) || (ring->poll_flag == 0)) {
+	if (!ring->poll_flag) {
 		MUTEX_EXIT(&ring->lock);
 		return ((mblk_t *)NULL);
 	}
 
+	/*
+	 * Get the control and status bits for the ring.
+	 */
 	RXDMA_REG_READ64(handle, RDC_STAT, rhp->index, &cs.value);
 	cs.bits.ptrread = 0;
 	cs.bits.pktread = 0;
 	RXDMA_REG_WRITE64(handle, RDC_STAT, rhp->index, cs.value);
 
+	/*
+	 * Process packets.
+	 */
 	mblk = hxge_rx_pkts(hxgep, ring->ldvp->vdma_index,
 	    ring->ldvp, ring, cs, bytes_to_pickup);
 	ldvp = ring->ldvp;
@@ -1413,9 +1415,23 @@
 	 * Process Error Events.
 	 */
 	if (ldvp && (cs.value & RDC_STAT_ERROR)) {
+		/*
+		 * Recovery routines will grab the RCR ring lock.
+		 */
+		MUTEX_EXIT(&ring->lock);
 		(void) hxge_rx_err_evnts(hxgep, ldvp->vdma_index, ldvp, cs);
+		MUTEX_ENTER(&ring->lock);
 	}
 
+	/*
+	 * Clear any control and status bits and update
+	 * the hardware.
+	 */
+	cs.value &= RDC_STAT_WR1C;
+	cs.bits.ptrread = 0;
+	cs.bits.pktread = 0;
+	RXDMA_REG_WRITE64(handle, RDC_STAT, rhp->index, cs.value);
+
 	MUTEX_EXIT(&ring->lock);
 	return (mblk);
 }
@@ -1445,10 +1461,6 @@
 	HXGE_DEBUG_MSG((hxgep, RX_INT_CTL, "==> hxge_rx_pkts:vindex %d "
 	    "channel %d", vindex, ldvp->channel));
 
-	if (!(hxgep->drv_state & STATE_HW_INITIALIZED)) {
-		return (NULL);
-	}
-
 	handle = HXGE_DEV_HPI_HANDLE(hxgep);
 	channel = rcrp->rdc;
 	if (channel != ldvp->channel) {
@@ -2276,6 +2288,7 @@
 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
 		    " hxge_rx_err_evnts: fatal error on Channel #%d\n",
 		    channel));
+
 		MUTEX_ENTER(&rbrp->post_lock);
 		/* This function needs to be inside the post_lock */
 		status = hxge_rxdma_fatal_err_recover(hxgep, channel);
@@ -2284,8 +2297,8 @@
 			FM_SERVICE_RESTORED(hxgep);
 		}
 	}
+
 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_rx_err_evnts"));
-
 	return (status);
 }
 
@@ -2762,6 +2775,8 @@
 
 	/* Map in the receive completion ring */
 	rcrp = (p_rx_rcr_ring_t)KMEM_ZALLOC(sizeof (rx_rcr_ring_t), KM_SLEEP);
+	MUTEX_INIT(&rcrp->lock, NULL, MUTEX_DRIVER,
+	    (void *) hxgep->interrupt_cookie);
 	rcrp->rdc = dma_channel;
 	rcrp->hxgep = hxgep;
 
@@ -2882,6 +2897,7 @@
 	HXGE_DEBUG_MSG((hxgep, MEM2_CTL,
 	    "==> hxge_unmap_rxdma_channel_cfg_ring: channel %d", rcr_p->rdc));
 
+	MUTEX_DESTROY(&rcr_p->lock);
 	KMEM_FREE(rcr_p, sizeof (rx_rcr_ring_t));
 	KMEM_FREE(rx_mbox_p, sizeof (rx_mbox_t));
 
@@ -3174,7 +3190,7 @@
 		 * unmapped, so it may free <rbr_p> for us.
 		 */
 		rbr_p->rbr_state = RBR_UNMAPPED;
-		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
+		HXGE_DEBUG_MSG((hxgep, MEM2_CTL,
 		    "unmap_rxdma_buf_ring: %d %s outstanding.",
 		    rbr_p->rbr_ref_cnt,
 		    rbr_p->rbr_ref_cnt == 1 ? "msg" : "msgs"));
@@ -3468,7 +3484,6 @@
 	HXGE_DEBUG_MSG((hxgep, MEM2_CTL,
 	    "==> hxge_rxdma_start_channel: enable done"));
 	HXGE_DEBUG_MSG((hxgep, MEM2_CTL, "<== hxge_rxdma_start_channel"));
-
 	return (HXGE_OK);
 }
 
@@ -3621,7 +3636,6 @@
 {
 	hpi_handle_t		handle;
 	hpi_status_t 		rs = HPI_SUCCESS;
-	hxge_status_t 		status = HXGE_OK;
 	p_rx_rbr_ring_t		rbrp;
 	p_rx_rcr_ring_t		rcrp;
 	p_rx_mbox_t		mboxp;
@@ -3635,8 +3649,6 @@
 	int			n_init_kick = 0;
 
 	HXGE_DEBUG_MSG((hxgep, RX_CTL, "==> hxge_rxdma_fatal_err_recover"));
-	HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
-	    "Recovering from RxDMAChannel#%d error...", channel));
 
 	/*
 	 * Stop the dma channel waits for the stop done. If the stop done bit
@@ -3648,6 +3660,10 @@
 	HXGE_DEBUG_MSG((hxgep, RX_CTL, "Rx DMA stop..."));
 
 	ring_idx = hxge_rxdma_get_ring_index(hxgep, channel);
+	if (ring_idx < 0) {
+		return (HXGE_ERROR);
+	}
+
 	rbrp = (p_rx_rbr_ring_t)hxgep->rx_rbr_rings->rbr_rings[ring_idx];
 	rcrp = (p_rx_rcr_ring_t)hxgep->rx_rcr_rings->rcr_rings[ring_idx];
 
@@ -3728,11 +3744,8 @@
 	 * owned by the hardware initially. The apps will post theirs
 	 * eventually.
 	 */
-	status = hxge_rxdma_start_channel(hxgep, channel, rbrp, rcrp, mboxp,
+	(void) hxge_rxdma_start_channel(hxgep, channel, rbrp, rcrp, mboxp,
 	    n_init_kick);
-	if (status != HXGE_OK) {
-		goto fail;
-	}
 
 	/*
 	 * The DMA channel may disable itself automatically.
@@ -3745,20 +3758,26 @@
 		    "hpi_rxdma_cfg_rdc_enable (channel %d)", channel));
 	}
 
+	/*
+	 * Delay a bit of time by doing reads.
+	 */
+	for (i = 0; i < 1024; i++) {
+		uint64_t value;
+		RXDMA_REG_READ64(HXGE_DEV_HPI_HANDLE(hxgep),
+		    RDC_INT_MASK, i & 3, &value);
+	}
+
 	MUTEX_EXIT(&rbrp->lock);
 	MUTEX_EXIT(&rcrp->lock);
 
-	HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
-	    "Recovery Successful, RxDMAChannel#%d Restored", channel));
 	HXGE_DEBUG_MSG((hxgep, RX_CTL, "<== hxge_rxdma_fatal_err_recover"));
-
 	return (HXGE_OK);
 
 fail:
 	MUTEX_EXIT(&rbrp->lock);
 	MUTEX_EXIT(&rcrp->lock);
-	HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "Recovery failed"));
-
+	HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
+	    "Error Recovery failed for channel(%d)", channel));
 	return (HXGE_ERROR | rs);
 }
 
@@ -3784,6 +3803,7 @@
 
 	/* Disable RxMAC */
 	HXGE_DEBUG_MSG((hxgep, RX_CTL, "Disable RxMAC...\n"));
+	MUTEX_ENTER(&hxgep->vmac_lock);
 	if (hxge_rx_vmac_disable(hxgep) != HXGE_OK)
 		goto fail;
 
@@ -3837,6 +3857,7 @@
 		    "hxge_rx_port_fatal_err_recover: Failed to enable RxMAC"));
 		goto fail;
 	}
+	MUTEX_EXIT(&hxgep->vmac_lock);
 
 	/* Reset the error mask since PEU reset cleared it */
 	HXGE_REG_WR64(hxgep->hpi_handle, RDC_FIFO_ERR_INT_MASK, 0x0);
@@ -3844,10 +3865,12 @@
 	HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
 	    "Recovery Successful, RxPort Restored"));
 	HXGE_DEBUG_MSG((hxgep, RX_CTL, "<== hxge_rx_port_fatal_err_recover"));
-
 	return (HXGE_OK);
+
 fail:
-	HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "Recovery failed"));
+	MUTEX_EXIT(&hxgep->vmac_lock);
+	HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
+	    "Error Recovery failed for hxge(%d)", hxgep->instance));
 	return (status);
 }
 
@@ -3856,7 +3879,6 @@
 {
 	hpi_status_t		hpi_status;
 	hxge_status_t		status;
-	int			i;
 	p_hxge_rx_ring_stats_t	rdc_stats;
 
 	rdc_stats = &hxgep->statsp->rdc_stats[rx_rbr_p->rdc];
@@ -3877,9 +3899,8 @@
 	 * to 0, since there is a hardware bug when disabling
 	 * the vmac.
 	 */
-	MUTEX_ENTER(hxgep->genlock);
-	(void) hpi_vmac_rx_set_framesize(
-	    HXGE_DEV_HPI_HANDLE(hxgep), (uint16_t)0);
+	MUTEX_ENTER(&hxgep->vmac_lock);
+	(void) hxge_rx_vmac_disable(hxgep);
 
 	hpi_status = hpi_rxdma_cfg_rdc_enable(
 	    HXGE_DEV_HPI_HANDLE(hxgep), rx_rbr_p->rdc);
@@ -3895,16 +3916,9 @@
 		}
 	}
 
-	for (i = 0; i < 1024; i++) {
-		uint64_t value;
-		RXDMA_REG_READ64(HXGE_DEV_HPI_HANDLE(hxgep),
-		    RDC_STAT, i & 3, &value);
-	}
-
 	/*
 	 * Re-enable the RX VMAC.
 	 */
-	(void) hpi_vmac_rx_set_framesize(HXGE_DEV_HPI_HANDLE(hxgep),
-	    (uint16_t)hxgep->vmac.maxframesize);
-	MUTEX_EXIT(hxgep->genlock);
+	(void) hxge_rx_vmac_enable(hxgep);
+	MUTEX_EXIT(&hxgep->vmac_lock);
 }
--- a/usr/src/uts/common/io/i8042.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/i8042.c	Mon Jul 20 13:07:46 2009 -0400
@@ -147,17 +147,10 @@
 	int			rptr;
 	int			overruns;
 	unsigned char		buf[BUFSIZ];
-
 	/*
-	 * Used during i8042_rep_put8 to intercept the 8042 response in
-	 * i8042_intr()
+	 * has_glock is 1 if this child has the [put8] exclusive-access lock.
 	 */
-	boolean_t		intercept_complete;
-	boolean_t		intr_intercept_enabled;
-	uint8_t			intercept[2];
-	uint8_t			intercepted_byte;
-	kcondvar_t		intercept_cv;
-	kmutex_t		intercept_mutex;
+	volatile boolean_t	has_glock;
 };
 
 /*
@@ -183,14 +176,16 @@
 #ifdef __sparc
 	timeout_id_t		timeout_id;
 #endif
-#ifdef DEBUG
 	/*
-	 * intr_thread is set to curthread in i8042_intr and is
-	 * tested against curthread in i8402_rep_put8().
+	 * glock is 1 if any child has the [put8] exclusive-access lock
+	 * glock_cv is associated with the condition `glock == 0'
 	 */
-	kthread_t		*intr_thread;
-#endif
-	ddi_softint_handle_t	intercept_sih;
+	volatile int		glock;
+	/*
+	 * Callers awaiting exclusive access in i8042_put8 sleep on glock_cv
+	 * and are signaled when another child relinquishes exclusive access.
+	 */
+	kcondvar_t		glock_cv;
 };
 
 /*
@@ -401,12 +396,8 @@
 static uint8_t i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr);
 static void i8042_put8(ddi_acc_impl_t *handlep, uint8_t *addr,
     uint8_t value);
-static void i8042_put8_nolock(ddi_acc_impl_t *handlep, uint8_t *addr,
-    uint8_t value);
-static void i8042_rep_put8(ddi_acc_impl_t *handlep, uint8_t *haddr,
-    uint8_t *daddr, size_t repcount, uint_t flags);
 static void i8042_send(struct i8042 *global, int reg, unsigned char cmd);
-static uint_t i8042_intercept_softint(caddr_t arg1, caddr_t arg2);
+static uint8_t i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr);
 
 unsigned int i8042_unclaimed_interrupts = 0;
 
@@ -492,8 +483,6 @@
 		}
 	}
 
-	(void) ddi_intr_remove_softint(global->intercept_sih);
-
 
 	if (global->init_state & I8042_INIT_MUTEXES) {
 		for (which_port = 0; which_port < NUM_PORTS; which_port++) {
@@ -501,9 +490,8 @@
 			port = &global->i8042_ports[which_port];
 			mutex_destroy(&port->intr_mutex);
 #endif
-			mutex_destroy(&port->intercept_mutex);
-			cv_destroy(&port->intercept_cv);
 		}
+		cv_destroy(&global->glock_cv);
 		mutex_destroy(&global->i8042_out_mutex);
 		mutex_destroy(&global->i8042_mutex);
 	}
@@ -685,20 +673,17 @@
 
 	mutex_init(&global->i8042_out_mutex, NULL, MUTEX_DRIVER, NULL);
 
+	cv_init(&global->glock_cv, NULL, CV_DRIVER, NULL);
+
 	for (which_port = 0; which_port < NUM_PORTS; ++which_port) {
 		port = &global->i8042_ports[which_port];
 		port->initialized = B_FALSE;
 		port->i8042_global = global;
 		port->which = which_port;
-		port->intr_intercept_enabled = B_FALSE;
-		cv_init(&port->intercept_cv, NULL, CV_DRIVER, NULL);
 #if defined(USE_SOFT_INTRS)
 		port->soft_hdl = 0;
 #else
 
-		mutex_init(&port->intercept_mutex, NULL, MUTEX_DRIVER,
-		    (void *)DDI_INTR_SOFTPRI_DEFAULT);
-
 		/*
 		 * Assume that the interrupt block cookie for port <n>
 		 * is iblock_cookies[<n>] (a 1:1 mapping).  If there are not
@@ -714,8 +699,6 @@
 
 		} else {
 			mutex_init(&port->intr_mutex, NULL, MUTEX_DRIVER, NULL);
-			mutex_init(&port->intercept_mutex, NULL, MUTEX_DRIVER,
-			    NULL);
 		}
 
 #endif
@@ -746,11 +729,6 @@
 		goto fail;
 
 
-	if (ddi_intr_add_softint(dip, &global->intercept_sih,
-	    DDI_INTR_SOFTPRI_DEFAULT, i8042_intercept_softint, global)
-	    != DDI_SUCCESS)
-		goto fail;
-
 	/*
 	 * Assume the number of interrupts is less that the number of
 	 * bits in the variable used to keep track of which interrupt
@@ -938,6 +916,7 @@
 		port->rptr = 0;
 		port->dip = dip;
 		port->inumber = 0;
+		port->has_glock = B_FALSE;
 		port->initialized = B_TRUE;
 
 		handle = mp->map_handlep;
@@ -955,7 +934,7 @@
 		ap->ahi_get32 = NULL;
 		ap->ahi_put64 = NULL;
 		ap->ahi_get64 = NULL;
-		ap->ahi_rep_put8 = i8042_rep_put8;
+		ap->ahi_rep_put8 = NULL;
 		ap->ahi_rep_get8 = NULL;
 		ap->ahi_rep_put16 = NULL;
 		ap->ahi_rep_get16 = NULL;
@@ -1030,9 +1009,6 @@
 	int			new_wptr;
 	struct i8042_port	*port;
 
-#ifdef DEBUG
-	global->intr_thread = curthread;
-#endif
 	mutex_enter(&global->i8042_mutex);
 
 	stat = ddi_get8(global->io_handle, global->io_addr + I8042_STAT);
@@ -1040,9 +1016,6 @@
 	if (! (stat & I8042_STAT_OUTBF)) {
 		++i8042_unclaimed_interrupts;
 		mutex_exit(&global->i8042_mutex);
-#ifdef DEBUG
-		global->intr_thread = NULL;
-#endif
 		return (DDI_INTR_UNCLAIMED);
 	}
 
@@ -1054,27 +1027,6 @@
 
 	if (! port->initialized) {
 		mutex_exit(&global->i8042_mutex);
-#ifdef DEBUG
-		global->intr_thread = NULL;
-#endif
-		return (DDI_INTR_CLAIMED);
-	}
-
-	/*
-	 * If interception is enabled, and the byte matches what is being
-	 * waited for, clear the interception flag and trigger a softintr
-	 * that will signal the waiter, then exit the interrupt handler
-	 * without passing the byte to the child's interrupt handler.
-	 */
-	if (port->intr_intercept_enabled && (port->intercept[0] == byte ||
-	    port->intercept[1] == byte)) {
-		port->intercepted_byte = byte;
-		port->intr_intercept_enabled = B_FALSE;
-		(void) ddi_intr_trigger_softint(global->intercept_sih, port);
-		mutex_exit(&global->i8042_mutex);
-#ifdef DEBUG
-		global->intr_thread = NULL;
-#endif
 		return (DDI_INTR_CLAIMED);
 	}
 
@@ -1089,10 +1041,6 @@
 #endif
 
 		mutex_exit(&global->i8042_mutex);
-
-#ifdef DEBUG
-		global->intr_thread = NULL;
-#endif
 		return (DDI_INTR_CLAIMED);
 	}
 
@@ -1114,9 +1062,6 @@
 	mutex_exit(&port->intr_mutex);
 #endif
 
-#ifdef DEBUG
-	global->intr_thread = NULL;
-#endif
 	return (DDI_INTR_CLAIMED);
 }
 
@@ -1204,6 +1149,37 @@
 	global = port->i8042_global;
 
 	switch ((uintptr_t)addr) {
+	case I8042_LOCK:
+		ASSERT(port->has_glock != B_TRUE);	/* No reentrancy */
+		mutex_enter(&global->i8042_out_mutex);
+		/*
+		 * Block other children requesting exclusive access here until
+		 * the child possessing it relinquishes the lock.
+		 */
+		while (global->glock) {
+			cv_wait(&global->glock_cv, &global->i8042_out_mutex);
+		}
+		port->has_glock = B_TRUE;
+		global->glock = 1;
+		mutex_exit(&global->i8042_out_mutex);
+		ret = 0;
+		break;
+
+	case I8042_UNLOCK:
+		mutex_enter(&global->i8042_out_mutex);
+		ASSERT(global->glock != 0);
+		ASSERT(port->has_glock == B_TRUE);
+		port->has_glock = B_FALSE;
+		global->glock = 0;
+		/*
+		 * Signal anyone waiting for exclusive access that it is now
+		 * available.
+		 */
+		cv_signal(&global->glock_cv);
+		mutex_exit(&global->i8042_out_mutex);
+		ret = 0;
+		break;
+
 	case I8042_INT_INPUT_AVAIL:
 		mutex_enter(&global->i8042_mutex);
 		ret = port->rptr != port->wptr;
@@ -1311,211 +1287,14 @@
 	return (ret);
 }
 
-/*
- * Send the byte specified and wait for a reply -- either the retry response,
- * or another response (assumed to be an acknowledgement).  If the retry
- * response is received within the timeout period, the initial byte is resent
- * to the 8042.
- */
-static int
-i8042_do_intercept(ddi_acc_impl_t *handlep, struct i8042_port *port,
-    uint8_t *oaddr, uint8_t byte, uint8_t retry_response)
+static void
+i8042_put8(ddi_acc_impl_t *handlep, uint8_t *addr, uint8_t value)
 {
-	int 	timedout = 0;
-	struct i8042	*global;
-	clock_t	tval;
-
-	global = port->i8042_global;
-
-	/*
-	 * Intercept the command response so that the 8042 interrupt handler
-	 * does not call the port's interrupt handler.
-	 */
-	port->intercept_complete = B_FALSE;
-	port->intr_intercept_enabled = B_TRUE;
-
-	/* Maximum time to wait: */
-	tval = ddi_get_lbolt() + drv_usectohz(MAX_WAIT_ITERATIONS *
-	    USECS_PER_WAIT);
-
-	do {
-		i8042_put8_nolock(handlep, oaddr, byte);
-
-		/*
-		 * Wait for the command response
-		 */
-		while (!port->intercept_complete) {
-			if (cv_timedwait(&port->intercept_cv,
-			    &port->intercept_mutex, tval) < 0 &&
-			    !port->intercept_complete) {
-				timedout = 1;
-				break;
-			}
-		}
-
-		/*
-		 * If the intercepted byte is the retry response, keep retrying
-		 * until we time out, or until the success response is received.
-		 */
-		if (port->intercept_complete &&
-		    port->intercepted_byte == retry_response)
-			port->intercept_complete = B_FALSE;
-
-	} while (!timedout && !port->intercept_complete);
-
-	port->intr_intercept_enabled = B_FALSE;
-
-	if (timedout && !port->intercept_complete) {
-		/*
-		 * Some keyboard controllers don't trigger an interrupt,
-		 * so check the status bits to see if there's input available
-		 */
-		if (ddi_get8(global->io_handle, global->io_addr + I8042_STAT) &
-		    I8042_STAT_OUTBF) {
-			byte = ddi_get8(global->io_handle,
-			    global->io_addr + I8042_DATA);
-
-			port->intercepted_byte = byte;
-
-			if (byte == retry_response)
-				return (B_TRUE);	/* Timed out */
-			else if (port->intercept[0] == byte) {
-				port->intercept_complete = B_TRUE;
-				return (B_FALSE);	/* Response OK */
-			}
-		}
-	}
-
-	return (timedout);
-}
-
-/*
- * The _rep_put8() operation is designed to allow child drivers to
- * execute commands that have responses or that have responses plus an
- * option byte.  These commands need to be executed atomically with respect
- * to commands from other children (some 8042 implementations get confused
- * when other child devices intersperse their commands while a command
- * to a different 8042-connected device is in flight).
- *
- * haddr points to a buffer with either 3 or 4 bytes.  Three bytes if a
- * command (byte 0) is being sent for which we expect a response code (byte 1)
- * (this function blocks until we either read a response code (or the retry
- * code (byte 2)) or until a timer expires).
- * Four if the command (byte 0) requires a response (byte 1) and then an
- * option byte (byte 3).  The option byte is only sent iff the response code
- * expected is received before the timeout.  As with the 3-byte request, byte
- * 2 is the retry response.
- *
- * While this function may technically called in interrupt context, it may
- * block (depending on the IPL of the i8042 interrupt handler vs. the handler
- * executing) for as long as the timeout (and fail if i8042_intr cannot run).
- *
- * flags are ignored.
- *
- */
-/*ARGSUSED*/
-static void
-i8042_rep_put8(ddi_acc_impl_t *handlep, uint8_t *haddr, uint8_t *daddr,
-    size_t repcount, uint_t flags)
-{
+	struct i8042		*global;
 	struct i8042_port	*port;
-	struct i8042		*global;
-	uint8_t			*oaddr;
-	uintptr_t		devaddr = (uintptr_t)daddr;
-	int			timedout = 0;
-	boolean_t		polled;
 	ddi_acc_hdl_t		*h;
 
 	h = (ddi_acc_hdl_t *)handlep;
-
-	port = (struct i8042_port *)h->ah_bus_private;
-	global = port->i8042_global;
-
-	/*
-	 * If this function is called, somehow, while we're in i8042_intr,
-	 * the logic below will not work.  That situation should never be
-	 * possible.
-	 */
-	ASSERT(global->intr_thread != curthread);
-
-	/*
-	 * Only support the main port for now
-	 */
-	if (port->which != MAIN_PORT || (devaddr != I8042_INT_CMD_PLUS_PARAM &&
-	    devaddr != I8042_POLL_CMD_PLUS_PARAM)) {
-#ifdef DEBUG
-		prom_printf("WARNING: i8042_rep_put8(): port or address "
-		    "invalid\n");
-#endif
-		return;
-	}
-
-	/*
-	 * Only support commands with MAX one parameter.  The format of the
-	 * buffer supplied must be { <CMD>, <CMD_OK_RESPONSE>[, <PARAMETER>] }
-	 */
-	if (repcount != 3 && repcount != 4) {
-#ifdef DEBUG
-		prom_printf("WARNING: i8042_rep_put8(): Invalid repetition "
-		    "count (%d)\n", (int)repcount);
-#endif
-		return;
-	}
-
-	polled = (devaddr == I8042_POLL_CMD_PLUS_PARAM);
-
-	if (polled) {
-		oaddr = (uint8_t *)I8042_POLL_OUTPUT_DATA;
-	} else {
-		oaddr = (uint8_t *)I8042_INT_OUTPUT_DATA;
-		/*
-		 * Mutexes are only required for the non-polled (polled
-		 * via the virtual registers, NOT via the polling mechanism
-		 * used for systems without 8042 interrupts) case, because
-		 * when polling is used, the system is single-threaded
-		 * with interrupts disabled.
-		 */
-		mutex_enter(&global->i8042_out_mutex);
-	}
-
-	/* Initialize the response and retry bytes from the caller */
-	port->intercept[0] = haddr[1];
-	port->intercept[1] = haddr[2];
-
-	mutex_enter(&port->intercept_mutex);
-
-	timedout = i8042_do_intercept(handlep, port, oaddr, haddr[0], haddr[2]);
-
-	/*
-	 * If the first byte was processed before the timeout period, and
-	 * there's an option byte, send it now.
-	 */
-	if (!timedout && repcount == 4) {
-		timedout = i8042_do_intercept(handlep, port, oaddr, haddr[3],
-		    haddr[2]);
-	}
-
-	mutex_exit(&port->intercept_mutex);
-
-#ifdef DEBUG
-	if (timedout && i8042_debug)
-		prom_printf("WARNING: i8042_rep_put8(): timed out waiting for "
-		    "command response\n");
-#endif
-
-	if (!polled)
-		mutex_exit(&global->i8042_out_mutex);
-}
-
-static void
-i8042_put8_nolock(ddi_acc_impl_t *handlep, uint8_t *addr, uint8_t value)
-{
-	struct i8042_port *port;
-	struct i8042 *global;
-	ddi_acc_hdl_t	*h;
-
-	h = (ddi_acc_hdl_t *)handlep;
-
 	port = (struct i8042_port *)h->ah_bus_private;
 	global = port->i8042_global;
 
@@ -1523,43 +1302,33 @@
 	case I8042_INT_OUTPUT_DATA:
 	case I8042_POLL_OUTPUT_DATA:
 
+		if ((uintptr_t)addr == I8042_INT_OUTPUT_DATA) {
+			mutex_enter(&global->i8042_out_mutex);
+
+			/*
+			 * If no child has exclusive access, then proceed with
+			 * the put8 below.  If a child (not the one making the
+			 * call) has exclusive access, wait for it to be
+			 * relinquished.  The use of i8042_out_mutex prevents
+			 * children seeking exclusive access from getting it
+			 * while a child is writing to the 8042.
+			 */
+			while (global->glock && !port->has_glock) {
+				cv_wait(&global->glock_cv,
+				    &global->i8042_out_mutex);
+			}
+		}
+
 		if (port->which == AUX_PORT)
 			i8042_send(global, I8042_CMD, I8042_CMD_WRITE_AUX);
 
 		i8042_send(global, I8042_DATA, value);
 
-		break;
-	}
-}
-
-static void
-i8042_put8(ddi_acc_impl_t *handlep, uint8_t *addr, uint8_t value)
-{
-	struct i8042 *global;
-	ddi_acc_hdl_t	*h;
-
-	h = (ddi_acc_hdl_t *)handlep;
-	global = ((struct i8042_port *)h->ah_bus_private)->i8042_global;
-
-	switch ((uintptr_t)addr) {
-	case I8042_INT_OUTPUT_DATA:
-	case I8042_POLL_OUTPUT_DATA:
-
-		if ((uintptr_t)addr == I8042_INT_OUTPUT_DATA)
-			mutex_enter(&global->i8042_out_mutex);
-
-		i8042_put8_nolock(handlep, addr, value);
-
 		if ((uintptr_t)addr == I8042_INT_OUTPUT_DATA)
 			mutex_exit(&global->i8042_out_mutex);
 
 		break;
 
-	case I8042_INT_CMD_PLUS_PARAM:
-	case I8042_POLL_CMD_PLUS_PARAM:
-
-		break;
-
 #if defined(DEBUG)
 	case I8042_INT_INPUT_AVAIL:
 	case I8042_INT_INPUT_DATA:
@@ -1915,25 +1684,3 @@
 		return (B_FALSE);
 }
 #endif
-
-/*
- * arg1 is the global i8042 state pointer (not used)
- * arg2 is the port pointer for the intercepted port
- */
-/*ARGSUSED*/
-static uint_t
-i8042_intercept_softint(caddr_t arg1, caddr_t arg2)
-{
-	struct i8042_port *port = (struct i8042_port *)arg2;
-	ASSERT(port != NULL);
-
-	mutex_enter(&port->intercept_mutex);
-	if (!port->intercept_complete) {
-		port->intercept_complete = B_TRUE;
-		cv_signal(&port->intercept_cv);
-		mutex_exit(&port->intercept_mutex);
-		return (DDI_INTR_CLAIMED);
-	}
-	mutex_exit(&port->intercept_mutex);
-	return (DDI_INTR_UNCLAIMED);
-}
--- a/usr/src/uts/common/io/ib/adapters/hermon/hermon.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/ib/adapters/hermon/hermon.c	Mon Jul 20 13:07:46 2009 -0400
@@ -1171,6 +1171,7 @@
 	} else if (HERMON_IS_MAINTENANCE_MODE(state->hs_dip)) {
 		HERMON_FMANOTE(state, HERMON_FMA_MAINT);
 		state->hs_operational_mode = HERMON_MAINTENANCE_MODE;
+		state->hs_fm_degraded_reason = HCA_FW_MISC; /* not fw reason */
 		return (DDI_FAILURE);
 
 	} else {
@@ -1626,6 +1627,7 @@
 			    state->hs_fw.fw_rev_subminor);
 		}
 		state->hs_operational_mode = HERMON_MAINTENANCE_MODE;
+		state->hs_fm_degraded_reason = HCA_FW_MISMATCH;
 		hermon_hw_fini(state, cleanup);
 		HERMON_ATTACH_MSG(state->hs_attach_buf,
 		    "hw_init_checkfwver_fail");
@@ -1696,6 +1698,7 @@
 		cmn_err(CE_NOTE, "RUN_FW command failed: 0x%08x\n", status);
 		if (status == HERMON_CMD_BAD_NVMEM) {
 			state->hs_operational_mode = HERMON_MAINTENANCE_MODE;
+			state->hs_fm_degraded_reason = HCA_FW_CORRUPT;
 		}
 		hermon_hw_fini(state, cleanup);
 		HERMON_ATTACH_MSG(state->hs_attach_buf, "hw_init_run_fw_fail");
--- a/usr/src/uts/common/io/ib/adapters/hermon/hermon_cmd.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/ib/adapters/hermon/hermon_cmd.c	Mon Jul 20 13:07:46 2009 -0400
@@ -265,9 +265,11 @@
 			break;
 
 		case HERMON_CMD_BAD_NVMEM:
+			/*
+			 * No need of an ereport here since this case
+			 * is treated as a degradation later.
+			 */
 			HERMON_FMANOTE(state, HERMON_FMA_NVMEM);
-			hermon_fm_ereport(state, HCA_IBA_ERR,
-			    HCA_ERR_NON_FATAL);
 			break;
 
 		default:
@@ -1820,9 +1822,11 @@
 #ifdef FMA_TEST
 	if (hermon_test_num == -2) {
 		status = HERMON_CMD_BAD_NVMEM;
+		/*
+		 * No need of an ereport here since this case
+		 * is treated as a degradation later.
+		 */
 		HERMON_FMANOTE(state, HERMON_FMA_BADNVMEM);
-		hermon_fm_ereport(state, HCA_IBA_ERR,
-		    HCA_ERR_NON_FATAL);
 	}
 #endif
 	return (status);
--- a/usr/src/uts/common/io/ib/adapters/hermon/hermon_fm.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/ib/adapters/hermon/hermon_fm.c	Mon Jul 20 13:07:46 2009 -0400
@@ -1008,6 +1008,21 @@
 			    DDI_SERVICE_LOST);
 			break;
 		case HCA_ERR_DEGRADED:
+			switch (state->hs_fm_degraded_reason) {
+			case HCA_FW_CORRUPT:
+				i_hca_fm_ereport(state->hs_dip, type,
+				    DDI_FM_DEVICE_FW_CORRUPT);
+				break;
+			case HCA_FW_MISMATCH:
+				i_hca_fm_ereport(state->hs_dip, type,
+				    DDI_FM_DEVICE_FW_MISMATCH);
+				break;
+			case HCA_FW_MISC:
+			default:
+				i_hca_fm_ereport(state->hs_dip, type,
+				    DDI_FM_DEVICE_INTERN_UNCORR);
+				break;
+			}
 			ddi_fm_service_impact(state->hs_dip,
 			    DDI_SERVICE_DEGRADED);
 			break;
@@ -1035,8 +1050,21 @@
 			    "error. type = %d, detail = %d\n.", type, detail);
 			break;
 		case HCA_ERR_DEGRADED:
-			i_hca_fm_ereport(state->hs_dip, type,
-			    DDI_FM_DEVICE_INTERN_UNCORR);
+			switch (state->hs_fm_degraded_reason) {
+			case HCA_FW_CORRUPT:
+				i_hca_fm_ereport(state->hs_dip, type,
+				    DDI_FM_DEVICE_FW_CORRUPT);
+				break;
+			case HCA_FW_MISMATCH:
+				i_hca_fm_ereport(state->hs_dip, type,
+				    DDI_FM_DEVICE_FW_MISMATCH);
+				break;
+			case HCA_FW_MISC:
+			default:
+				i_hca_fm_ereport(state->hs_dip, type,
+				    DDI_FM_DEVICE_INTERN_UNCORR);
+				break;
+			}
 			ddi_fm_service_impact(state->hs_dip,
 			    DDI_SERVICE_DEGRADED);
 			break;
--- a/usr/src/uts/common/io/ib/clients/iser/iser_cq.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/ib/clients/iser/iser_cq.c	Mon Jul 20 13:07:46 2009 -0400
@@ -54,24 +54,30 @@
 
 	iser_chan = (iser_chan_t *)arg;
 
-	/* Poll completions until the CQ is empty */
+	/*
+	 * Poll for work request completion while successful. If the
+	 * queue empties or otherwise becomes invalid, stop polling.
+	 */
 	do {
 		status = iser_ib_poll_send_completions(cq_hdl, iser_chan);
-	} while (status != IBT_CQ_EMPTY);
+	} while (status == IBT_SUCCESS);
 
-	/* We've emptied the CQ, rearm it before we're done here */
-	status = ibt_enable_cq_notify(cq_hdl, IBT_NEXT_COMPLETION);
-	if (status != IBT_SUCCESS) {
-		/* Unexpected error */
-		ISER_LOG(CE_NOTE, "iser_ib_sendcq_handler: "
-		    "ibt_enable_cq_notify error (%d)", status);
-		return;
+	if (status == IBT_CQ_EMPTY) {
+		/* We've emptied the CQ, rearm it before we're done here */
+		status = ibt_enable_cq_notify(cq_hdl, IBT_NEXT_COMPLETION);
+		if (status != IBT_SUCCESS) {
+			/* Unexpected error */
+			ISER_LOG(CE_NOTE, "iser_ib_sendcq_handler: "
+			    "ibt_enable_cq_notify error (%d)", status);
+			return;
+		}
+
+		/* Now, check for more completions after the rearm */
+		do {
+			status = iser_ib_poll_send_completions(
+			    cq_hdl, iser_chan);
+		} while (status == IBT_SUCCESS);
 	}
-
-	/* Now, check for more completions after the rearm */
-	do {
-		status = iser_ib_poll_send_completions(cq_hdl, iser_chan);
-	} while (status != IBT_CQ_EMPTY);
 }
 
 static int
@@ -91,16 +97,14 @@
 
 	iser_conn = iser_chan->ic_conn;
 
-	/*
-	 * Poll ISER_IB_SCQ_POLL_MAX completions from the CQ.
-	 */
+	/* Poll ISER_IB_SCQ_POLL_MAX completions from the CQ */
 	status = ibt_poll_cq(cq_hdl, wc, ISER_IB_SCQ_POLL_MAX, &npoll);
 
 	if (status != IBT_SUCCESS) {
 		if (status != IBT_CQ_EMPTY) {
 			/* Unexpected error */
 			ISER_LOG(CE_NOTE, "iser_ib_sendcq_handler: ibt_poll_cq "
-			    "error (%d)", status);
+			    "unexpected error (%d)", status);
 		}
 		/* CQ is empty. Either way, move along... */
 		return (status);
@@ -313,24 +317,30 @@
 
 	iser_chan = (iser_chan_t *)arg;
 
-	/* Poll completions until the CQ is empty */
+	/*
+	 * Poll for work request completion while successful. If the
+	 * queue empties or otherwise becomes invalid, stop polling.
+	 */
 	do {
 		status = iser_ib_poll_recv_completions(cq_hdl, iser_chan);
-	} while (status != IBT_CQ_EMPTY);
+	} while (status == IBT_SUCCESS);
 
-	/* We've emptied the CQ, rearm it before we're done here */
-	status = ibt_enable_cq_notify(cq_hdl, IBT_NEXT_COMPLETION);
-	if (status != IBT_SUCCESS) {
-		/* Unexpected error */
-		ISER_LOG(CE_NOTE, "iser_ib_recvcq_handler: "
-		    "ibt_enable_cq_notify error (%d)", status);
-		return;
+	if (status == IBT_CQ_EMPTY) {
+		/* We've emptied the CQ, rearm it before we're done here */
+		status = ibt_enable_cq_notify(cq_hdl, IBT_NEXT_COMPLETION);
+		if (status != IBT_SUCCESS) {
+			/* Unexpected error */
+			ISER_LOG(CE_NOTE, "iser_ib_recvcq_handler: "
+			    "ibt_enable_cq_notify error (%d)", status);
+			return;
+		}
+
+		/* Now, check for more completions after the rearm */
+		do {
+			status = iser_ib_poll_recv_completions(
+			    cq_hdl, iser_chan);
+		} while (status == IBT_SUCCESS);
 	}
-
-	/* Now, check for more completions after the rearm */
-	do {
-		status = iser_ib_poll_recv_completions(cq_hdl, iser_chan);
-	} while (status != IBT_CQ_EMPTY);
 }
 
 static int
--- a/usr/src/uts/common/io/ib/clients/iser/iser_ib.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/ib/clients/iser/iser_ib.c	Mon Jul 20 13:07:46 2009 -0400
@@ -187,7 +187,14 @@
 /*
  * iser_ib_bind_service
  *
- * This function binds a given iSER service on all available HCA ports
+ * This function binds a given iSER service on all available HCA ports. The
+ * current specification does not allow user to specify transport bindings
+ * for each iscsi target. The ULP invokes this function to bind the target
+ * to all available iser ports after checking for the presence of an IB HCA.
+ * iSER is "configured" whenever an IB-capable IP address exists. The lack
+ * of active IB ports is a less-fatal condition, and sockets would be used
+ * as the transport even though an Infiniband HCA is configured but unusable.
+ *
  */
 int
 iser_ib_bind_service(idm_svc_t *idm_svc)
@@ -196,6 +203,7 @@
 	ib_gid_t	gid;
 	int		num_ports = 0;
 	int		num_binds = 0;
+	int		num_inactive_binds = 0; /* if HCA ports inactive */
 	int		status;
 	int		i;
 
@@ -218,6 +226,7 @@
 				 * in our async handler if the port comes up
 				 * at a later time.
 				 */
+				num_inactive_binds++;
 				continue;
 			}
 
@@ -246,6 +255,14 @@
 		ISER_LOG(CE_NOTE, "iser_ib_bind_service: Service available on "
 		    "(%d) of (%d) ports", num_binds, num_ports);
 		return (ISER_STATUS_SUCCESS);
+	} else if (num_inactive_binds) {
+		ISER_LOG(CE_NOTE, "iser_ib_bind_service: Could not bind "
+		    "service, HCA ports are not active.");
+		/*
+		 * still considered success, the async handler will bind
+		 * the service when the port comes up at a later time
+		 */
+		return (ISER_STATUS_SUCCESS);
 	} else {
 		ISER_LOG(CE_NOTE, "iser_ib_bind_service: Did not bind service");
 		return (ISER_STATUS_FAIL);
--- a/usr/src/uts/common/io/ib/clients/iser/iser_xfer.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/ib/clients/iser/iser_xfer.c	Mon Jul 20 13:07:46 2009 -0400
@@ -95,21 +95,28 @@
 	wr.wr_nds	= 1;
 	wr.wr_sgl	= &msg->msg_ds;
 
-	status = ibt_post_send(chan->ic_chanhdl, &wr, 1, NULL);
-	if (status != IBT_SUCCESS) {
-		ISER_LOG(CE_NOTE, "iser_xfer_hello_msg: ibt_post_send "
-		    "failure (%d)", status);
-		iser_msg_free(msg);
-		iser_wr_free(iser_wr);
-		return (ISER_STATUS_FAIL);
-	}
-	/* Increment this channel's SQ posted count */
+	/*
+	 * Avoid race condition by incrementing this channel's
+	 * SQ posted count prior to calling ibt_post_send
+	 */
 	mutex_enter(&chan->ic_sq_post_lock);
 	chan->ic_sq_post_count++;
 	if (chan->ic_sq_post_count > chan->ic_sq_max_post_count)
 		chan->ic_sq_max_post_count = chan->ic_sq_post_count;
 	mutex_exit(&chan->ic_sq_post_lock);
 
+	status = ibt_post_send(chan->ic_chanhdl, &wr, 1, NULL);
+	if (status != IBT_SUCCESS) {
+		ISER_LOG(CE_NOTE, "iser_xfer_hello_msg: ibt_post_send "
+		    "failure (%d)", status);
+		mutex_enter(&chan->ic_sq_post_lock);
+		chan->ic_sq_post_count--;
+		mutex_exit(&chan->ic_sq_post_lock);
+		iser_msg_free(msg);
+		iser_wr_free(iser_wr);
+		return (ISER_STATUS_FAIL);
+	}
+
 	ISER_LOG(CE_NOTE, "Posting iSER Hello message: chan (0x%p): "
 	    "IP [%x to %x]", (void *)chan, chan->ic_localip.un.ip4addr,
 	    chan->ic_remoteip.un.ip4addr);
@@ -176,21 +183,24 @@
 	wr.wr_nds	= 1;
 	wr.wr_sgl	= &msg->msg_ds;
 
+	mutex_enter(&chan->ic_sq_post_lock);
+	chan->ic_sq_post_count++;
+	if (chan->ic_sq_post_count > chan->ic_sq_max_post_count)
+		chan->ic_sq_max_post_count = chan->ic_sq_post_count;
+
+	mutex_exit(&chan->ic_sq_post_lock);
+
 	status = ibt_post_send(chan->ic_chanhdl, &wr, 1, NULL);
 	if (status != IBT_SUCCESS) {
 		ISER_LOG(CE_NOTE, "iser_xfer_helloreply_msg: ibt_post_send "
 		    "failure (%d)", status);
+		mutex_enter(&chan->ic_sq_post_lock);
+		chan->ic_sq_post_count--;
+		mutex_exit(&chan->ic_sq_post_lock);
 		iser_msg_free(msg);
 		iser_wr_free(iser_wr);
 		return (ISER_STATUS_FAIL);
 	}
-	/* Increment this channel's SQ posted count */
-	mutex_enter(&chan->ic_sq_post_lock);
-	chan->ic_sq_post_count++;
-	if (chan->ic_sq_post_count > chan->ic_sq_max_post_count)
-		chan->ic_sq_max_post_count = chan->ic_sq_post_count;
-	mutex_exit(&chan->ic_sq_post_lock);
-
 	ISER_LOG(CE_NOTE, "Posting iSER HelloReply message: chan (0x%p): "
 	    "IP [%x to %x]", (void *)chan, chan->ic_localip.un.ip4addr,
 	    chan->ic_remoteip.un.ip4addr);
@@ -228,6 +238,14 @@
 
 	ASSERT(chan != NULL);
 
+	mutex_enter(&chan->ic_conn->ic_lock);
+	/* Bail out if the connection is closed */
+	if ((chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSING) ||
+	    (chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSED)) {
+		mutex_exit(&chan->ic_conn->ic_lock);
+		return (ISER_STATUS_FAIL);
+	}
+
 	/*
 	 * All SCSI command PDU (except SCSI Read and SCSI Write) and the SCSI
 	 * Response PDU are sent to the remote end using the SendSE Message.
@@ -238,6 +256,7 @@
 	hca = (iser_hca_t *)chan->ic_hca;
 	if (hca == NULL) {
 		ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: no hca handle found");
+		mutex_exit(&chan->ic_conn->ic_lock);
 		return (ISER_STATUS_FAIL);
 	}
 
@@ -245,15 +264,14 @@
 	if (msg == NULL) {
 		ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: iser message cache "
 		    "alloc failed");
+		mutex_exit(&chan->ic_conn->ic_lock);
 		return (ISER_STATUS_FAIL);
 	}
 
 	/* Pull the BHS out of the PDU handle */
 	bhs = (iscsi_data_hdr_t *)pdu->isp_hdr;
 
-	ASSERT(chan->ic_conn != NULL && chan->ic_conn->ic_idmc != NULL);
 	ic = chan->ic_conn->ic_idmc;
-	ASSERT(ic != NULL);
 
 	hdr = (iser_ctrl_hdr_t *)(uintptr_t)msg->msg_ds.ds_va;
 
@@ -330,6 +348,7 @@
 		ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: unable to allocate "
 		    "iser wr handle");
 		iser_msg_free(msg);
+		mutex_exit(&chan->ic_conn->ic_lock);
 		return (ISER_STATUS_FAIL);
 	}
 	iser_wr->iw_pdu = pdu;
@@ -346,6 +365,13 @@
 	wr.wr_nds	= 1;
 	wr.wr_sgl	= &msg->msg_ds;
 
+	/* Increment this channel's SQ posted count */
+	mutex_enter(&chan->ic_sq_post_lock);
+	chan->ic_sq_post_count++;
+	if (chan->ic_sq_post_count > chan->ic_sq_max_post_count)
+		chan->ic_sq_max_post_count = chan->ic_sq_post_count;
+	mutex_exit(&chan->ic_sq_post_lock);
+
 	/* Post Send Work Request on the specified channel */
 	status = ibt_post_send(chan->ic_chanhdl, &wr, 1, NULL);
 	if (status != IBT_SUCCESS) {
@@ -353,15 +379,14 @@
 		    "failure (%d)", status);
 		iser_msg_free(msg);
 		iser_wr_free(iser_wr);
+		mutex_enter(&chan->ic_sq_post_lock);
+		chan->ic_sq_post_count--;
+		mutex_exit(&chan->ic_sq_post_lock);
+		mutex_exit(&chan->ic_conn->ic_lock);
 		return (ISER_STATUS_FAIL);
 	}
-	/* Increment this channel's SQ posted count */
-	mutex_enter(&chan->ic_sq_post_lock);
-	chan->ic_sq_post_count++;
-	if (chan->ic_sq_post_count > chan->ic_sq_max_post_count)
-		chan->ic_sq_max_post_count = chan->ic_sq_post_count;
-	mutex_exit(&chan->ic_sq_post_lock);
 
+	mutex_exit(&chan->ic_conn->ic_lock);
 	return (ISER_STATUS_SUCCESS);
 }
 
@@ -388,6 +413,15 @@
 	/* Grab the iSER resources from the task and buf handles */
 	iser_conn = (iser_conn_t *)idt->idt_ic->ic_transport_private;
 	iser_chan = iser_conn->ic_chan;
+
+	mutex_enter(&iser_chan->ic_conn->ic_lock);
+	/* Bail out if the connection is closed */
+	if ((iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSING) ||
+	    (iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSED)) {
+		mutex_exit(&iser_chan->ic_conn->ic_lock);
+		return (ISER_STATUS_FAIL);
+	}
+
 	iser_buf  = (iser_buf_t *)buf->idb_buf_private;
 	iser_hdr  = (iser_ctrl_hdr_t *)idt->idt_transport_hdr;
 
@@ -408,6 +442,7 @@
 	if (iser_wr == NULL) {
 		ISER_LOG(CE_NOTE, "iser_xfer_buf_to_ini: unable to allocate "
 		    "iser wr handle");
+		mutex_exit(&iser_chan->ic_conn->ic_lock);
 		return (ISER_STATUS_FAIL);
 	}
 	iser_wr->iw_buf = buf;
@@ -433,13 +468,6 @@
 	    uint32_t,  reg_rkey,
 	    uint32_t, buf->idb_xfer_len, int, XFER_BUF_TX_TO_INI);
 
-	status = ibt_post_send(iser_chan->ic_chanhdl, &wr, 1, NULL);
-	if (status != IBT_SUCCESS) {
-		ISER_LOG(CE_NOTE, "iser_xfer_buf_to_ini: ibt_post_send "
-		    "failure (%d)", status);
-		iser_wr_free(iser_wr);
-		return (ISER_STATUS_FAIL);
-	}
 	/* Increment this channel's SQ posted count */
 	mutex_enter(&iser_chan->ic_sq_post_lock);
 	iser_chan->ic_sq_post_count++;
@@ -447,6 +475,19 @@
 		iser_chan->ic_sq_max_post_count = iser_chan->ic_sq_post_count;
 	mutex_exit(&iser_chan->ic_sq_post_lock);
 
+	status = ibt_post_send(iser_chan->ic_chanhdl, &wr, 1, NULL);
+	if (status != IBT_SUCCESS) {
+		ISER_LOG(CE_NOTE, "iser_xfer_buf_to_ini: ibt_post_send "
+		    "failure (%d)", status);
+		iser_wr_free(iser_wr);
+		mutex_enter(&iser_chan->ic_sq_post_lock);
+		iser_chan->ic_sq_post_count--;
+		mutex_exit(&iser_chan->ic_sq_post_lock);
+		mutex_exit(&iser_chan->ic_conn->ic_lock);
+		return (ISER_STATUS_FAIL);
+	}
+
+	mutex_exit(&iser_chan->ic_conn->ic_lock);
 	return (ISER_STATUS_SUCCESS);
 }
 
@@ -474,6 +515,15 @@
 	/* Grab the iSER resources from the task and buf handles */
 	iser_conn = (iser_conn_t *)idt->idt_ic->ic_transport_private;
 	iser_chan = iser_conn->ic_chan;
+
+	mutex_enter(&iser_chan->ic_conn->ic_lock);
+	/* Bail out if the connection is closed */
+	if ((iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSING) ||
+	    (iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSED)) {
+		mutex_exit(&iser_chan->ic_conn->ic_lock);
+		return (ISER_STATUS_FAIL);
+	}
+
 	iser_buf = (iser_buf_t *)buf->idb_buf_private;
 	iser_hdr  = (iser_ctrl_hdr_t *)idt->idt_transport_hdr;
 
@@ -494,6 +544,7 @@
 	if (iser_wr == NULL) {
 		ISER_LOG(CE_NOTE, "iser_xfer_buf_from_ini: unable to allocate "
 		    "iser wr handle");
+		mutex_exit(&iser_chan->ic_conn->ic_lock);
 		return (ISER_STATUS_FAIL);
 	}
 	iser_wr->iw_buf = buf;
@@ -519,13 +570,6 @@
 	    uint32_t,  reg_rkey,
 	    uint32_t, buf->idb_xfer_len, int, XFER_BUF_RX_FROM_INI);
 
-	status = ibt_post_send(iser_chan->ic_chanhdl, &wr, 1, NULL);
-	if (status != IBT_SUCCESS) {
-		ISER_LOG(CE_NOTE, "iser_xfer_buf_from_ini: ibt_post_send "
-		    "failure (%d)", status);
-		iser_wr_free(iser_wr);
-		return (ISER_STATUS_FAIL);
-	}
 	/* Increment this channel's SQ posted count */
 	mutex_enter(&iser_chan->ic_sq_post_lock);
 	iser_chan->ic_sq_post_count++;
@@ -533,5 +577,18 @@
 		iser_chan->ic_sq_max_post_count = iser_chan->ic_sq_post_count;
 	mutex_exit(&iser_chan->ic_sq_post_lock);
 
+	status = ibt_post_send(iser_chan->ic_chanhdl, &wr, 1, NULL);
+	if (status != IBT_SUCCESS) {
+		ISER_LOG(CE_NOTE, "iser_xfer_buf_from_ini: ibt_post_send "
+		    "failure (%d)", status);
+		iser_wr_free(iser_wr);
+		mutex_enter(&iser_chan->ic_sq_post_lock);
+		iser_chan->ic_sq_post_count--;
+		mutex_exit(&iser_chan->ic_sq_post_lock);
+		mutex_exit(&iser_chan->ic_conn->ic_lock);
+		return (ISER_STATUS_FAIL);
+	}
+
+	mutex_exit(&iser_chan->ic_conn->ic_lock);
 	return (ISER_STATUS_SUCCESS);
 }
--- a/usr/src/uts/common/io/ib/ibnex/ibnex.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/ib/ibnex/ibnex.c	Mon Jul 20 13:07:46 2009 -0400
@@ -54,6 +54,7 @@
 #include <sys/ib/ibtl/impl/ibtl_ibnex.h>
 #include <sys/file.h>
 #include <sys/hwconf.h>
+#include <sys/fs/dv_node.h>
 
 /* Function prototypes */
 static int		ibnex_attach(dev_info_t *, ddi_attach_cmd_t);
@@ -1633,8 +1634,6 @@
 				(void) ibnex_commsvc_initnode(parent, port_attr,
 				    idx, IBNEX_VPPA_COMMSVC_NODE,
 				    pkey, &rval, IBNEX_CFGADM_ENUMERATE);
-				IBTF_DPRINTF_L5("ibnex", "\tcreate_vppa_nodes: "
-				    "commsvc_initnode failed rval %x", rval);
 			}
 		}
 	}
@@ -2948,6 +2947,7 @@
 	char	hca_guid[IBNEX_HCAGUID_STRSZ];
 	ibdm_ioc_info_t	*ioc_list, *ioc;
 	ibnex_node_data_t	*node_data;
+	dev_info_t		*phci;
 
 	IBTF_DPRINTF_L4("ibnex", "\tdm_callback: attr %p event %x", arg, flag);
 
@@ -2987,6 +2987,16 @@
 		}
 		mutex_exit(&ibnex.ibnex_mutex);
 		ibdm_ibnex_free_ioc_list(ioc);
+		break;
+
+	case IBDM_EVENT_PORT_UP:
+	case IBDM_EVENT_PORT_PKEY_CHANGE:
+		phci = ibtl_ibnex_hcaguid2dip(*(longlong_t *)arg);
+		devfs_clean(phci, NULL, 0);
+		break;
+	default:
+		break;
+
 	}
 }
 
--- a/usr/src/uts/common/io/ib/ibnex/ibnex_ioctl.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/ib/ibnex/ibnex_ioctl.c	Mon Jul 20 13:07:46 2009 -0400
@@ -2880,6 +2880,72 @@
 	return (rv);
 }
 
+#define	IBNEX_CTL_CP_HCA_INFO(x, y, driver_name, instance, device_path, \
+    device_path_alloc_sz, device_path_len)				\
+{									\
+	(x)->hca_node_guid		= (y)->hca_node_guid;		\
+	(x)->hca_si_guid		= (y)->hca_si_guid;		\
+	(x)->hca_nports			= (y)->hca_nports;		\
+	(x)->hca_flags			= (y)->hca_flags;		\
+	(x)->hca_flags2			= (y)->hca_flags2;		\
+	(x)->hca_vendor_id		= (y)->hca_vendor_id;		\
+	(x)->hca_device_id		= (y)->hca_device_id;		\
+	(x)->hca_version_id		= (y)->hca_version_id;		\
+	(x)->hca_max_chans		= (y)->hca_max_chans;		\
+	(x)->hca_max_chan_sz		= (y)->hca_max_chan_sz;		\
+	(x)->hca_max_sgl		= (y)->hca_max_sgl;		\
+	(x)->hca_max_cq			= (y)->hca_max_cq;		\
+	(x)->hca_max_cq_sz		= (y)->hca_max_cq_sz;		\
+	(x)->hca_page_sz		= (y)->hca_page_sz;		\
+	(x)->hca_max_memr		= (y)->hca_max_memr;		\
+	(x)->hca_max_memr_len		= (y)->hca_max_memr_len;	\
+	(x)->hca_max_mem_win		= (y)->hca_max_mem_win;		\
+	(x)->hca_max_rsc		= (y)->hca_max_rsc;		\
+	(x)->hca_max_rdma_in_chan	= (y)->hca_max_rdma_in_chan;	\
+	(x)->hca_max_rdma_out_chan	= (y)->hca_max_rdma_out_chan;	\
+	(x)->hca_max_ipv6_chan		= (y)->hca_max_ipv6_chan;	\
+	(x)->hca_max_ether_chan 	= (y)->hca_max_ether_chan;	\
+	(x)->hca_max_mcg_chans		= (y)->hca_max_mcg_chans;	\
+	(x)->hca_max_mcg		= (y)->hca_max_mcg;		\
+	(x)->hca_max_chan_per_mcg	= (y)->hca_max_chan_per_mcg;	\
+	(x)->hca_max_partitions		= (y)->hca_max_partitions;	\
+	(x)->hca_local_ack_delay	= (y)->hca_local_ack_delay;	\
+	(x)->hca_max_port_sgid_tbl_sz	= (y)->hca_max_port_sgid_tbl_sz; \
+	(x)->hca_max_port_pkey_tbl_sz	= (y)->hca_max_port_pkey_tbl_sz; \
+	(x)->hca_max_pd			= (y)->hca_max_pd;		\
+	(x)->hca_max_ud_dest		= (y)->hca_max_ud_dest;		\
+	(x)->hca_max_srqs		= (y)->hca_max_srqs;		\
+	(x)->hca_max_srqs_sz		= (y)->hca_max_srqs_sz;		\
+	(x)->hca_max_srq_sgl		= (y)->hca_max_srq_sgl;		\
+	(x)->hca_max_cq_handlers	= (y)->hca_max_cq_handlers;	\
+	(x)->hca_reserved_lkey		= (y)->hca_reserved_lkey;	\
+	(x)->hca_max_fmrs		= (y)->hca_max_fmrs;		\
+	(x)->hca_max_lso_size		= (y)->hca_max_lso_size;	\
+	(x)->hca_max_lso_hdr_size	= (y)->hca_max_lso_hdr_size;	\
+	(x)->hca_max_inline_size	= (y)->hca_max_inline_size;	\
+	(x)->hca_max_cq_mod_count	= (y)->hca_max_cq_mod_count;	\
+	(x)->hca_max_cq_mod_usec	= (y)->hca_max_cq_mod_usec;	\
+	(x)->hca_fw_major_version	= (y)->hca_fw_major_version;	\
+	(x)->hca_fw_minor_version	= (y)->hca_fw_minor_version;	\
+	(x)->hca_fw_micro_version	= (y)->hca_fw_micro_version;	\
+	(x)->hca_ud_send_inline_sz	= (y)->hca_ud_send_inline_sz;	\
+	(x)->hca_conn_send_inline_sz	= (y)->hca_conn_send_inline_sz;	\
+	(x)->hca_conn_rdmaw_inline_overhead =				\
+	    (y)->hca_conn_rdmaw_inline_overhead;			\
+	(x)->hca_recv_sgl_sz		= (y)->hca_recv_sgl_sz;		\
+	(x)->hca_ud_send_sgl_sz		= (y)->hca_ud_send_sgl_sz;	\
+	(x)->hca_conn_send_sgl_sz	= (y)->hca_conn_send_sgl_sz;	\
+	(x)->hca_conn_rdma_sgl_overhead = (y)->hca_conn_rdma_sgl_overhead; \
+									\
+	(void) strlcpy((x)->hca_driver_name, (driver_name),		\
+	    MAX_HCA_DRVNAME_LEN);					\
+	(x)->hca_driver_instance	= (instance);			\
+									\
+	(x)->hca_device_path = ((device_path_alloc_sz) >= (device_path_len)) \
+	    ? (device_path) : NULL;					\
+	(x)->hca_device_path_len	= (device_path_len);		\
+}
+
 /*
  * IOCTL implementation to query HCA attributes
  */
@@ -2888,110 +2954,121 @@
     cred_t *credp, int *rvalp)
 {
 	int			rv = 0;
-	ibnex_ctl_hca_info_t	*hca_info;
-	ibnex_ctl_query_hca_t	*query_hca;
-	ibt_hca_attr_t		*hca_attr;
+	ibnex_ctl_query_hca_t	*query_hca = NULL;
+	ibnex_ctl_query_hca_32_t *query_hca_32 = NULL;
+	ibt_hca_attr_t		*hca_attr = NULL;
 	char			driver_name[MAX_HCA_DRVNAME_LEN];
 	int			instance;
+	ib_guid_t		hca_guid;
+	char			*device_path;
+	uint_t			device_path_alloc_sz, hca_device_path_len;
+	char			*hca_device_path = NULL;
 
 	IBTF_DPRINTF_L4("ibnex", "\tctl_query_hca: cmd=%x, arg=%p, "
 	    "mode=%x, cred=%p, rval=%p, dev=0x%x", cmd, arg, mode, credp,
 	    rvalp, dev);
 
-	/*
-	 * NOTE: 32-bit versions of the structures for ibnex_ctl_query_hca_t
-	 * and ibnex_ctl_hca_info_t are not defined because the alignment
-	 * of fields for these structures happen to be the same for both
-	 * 64-bit and 32-bit cases.
-	 */
-
-	query_hca = kmem_zalloc(sizeof (ibnex_ctl_query_hca_t), KM_SLEEP);
+#ifdef	_MULTI_DATAMODEL
+	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
+		query_hca_32 = kmem_zalloc(
+		    sizeof (ibnex_ctl_query_hca_32_t), KM_SLEEP);
+
+		if (ddi_copyin((void *)arg, query_hca_32,
+		    sizeof (ibnex_ctl_query_hca_32_t), mode) != 0) {
+			IBTF_DPRINTF_L2("ibnex",
+			    "\tctl_query_hca: ddi_copyin err 1");
+			rv = EFAULT;
+			goto out;
+		}
+
+		hca_guid = query_hca_32->hca_guid;
+		device_path = (char *)(uintptr_t)query_hca_32->hca_device_path;
+		device_path_alloc_sz = query_hca_32->hca_device_path_alloc_sz;
+	} else
+#endif
+	{
+		query_hca = kmem_zalloc(sizeof (ibnex_ctl_query_hca_t),
+		    KM_SLEEP);
+
+		if (ddi_copyin((void *)arg, query_hca,
+		    sizeof (ibnex_ctl_query_hca_t), mode) != 0) {
+			IBTF_DPRINTF_L2("ibnex",
+			    "\tctl_query_hca: ddi_copyin err 2");
+			rv = EFAULT;
+			goto out;
+		}
+
+		hca_guid = query_hca->hca_guid;
+		device_path = query_hca->hca_device_path;
+		device_path_alloc_sz = query_hca->hca_device_path_alloc_sz;
+	}
+
 	hca_attr = kmem_zalloc(sizeof (ibt_hca_attr_t), KM_SLEEP);
-
-	if (ddi_copyin((void *)arg, query_hca,
-	    sizeof (ibnex_ctl_query_hca_t), mode) != 0) {
-		IBTF_DPRINTF_L2("ibnex", "\tctl_query_hca: ddi_copyin err");
-		rv = EFAULT;
-		goto out;
-	}
-
-	if (ibtl_ibnex_query_hca_byguid(query_hca->hca_guid, hca_attr,
-	    driver_name, sizeof (driver_name), &instance) != IBT_SUCCESS) {
+	hca_device_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+
+	if (ibtl_ibnex_query_hca_byguid(hca_guid, hca_attr,
+	    driver_name, sizeof (driver_name), &instance, hca_device_path)
+	    != IBT_SUCCESS) {
 		rv = ENXIO;
 		goto out;
 	}
 
-	hca_info = &query_hca->hca_info;
-
-	hca_info->hca_node_guid = hca_attr->hca_node_guid;
-	hca_info->hca_si_guid = hca_attr->hca_si_guid;
-	hca_info->hca_nports = hca_attr->hca_nports;
-	hca_info->hca_flags = hca_attr->hca_flags;
-	hca_info->hca_flags2 = hca_attr->hca_flags2;
-	hca_info->hca_vendor_id = hca_attr->hca_vendor_id;
-	hca_info->hca_device_id = hca_attr->hca_device_id;
-	hca_info->hca_version_id = hca_attr->hca_version_id;
-	hca_info->hca_max_chans = hca_attr->hca_max_chans;
-	hca_info->hca_max_chan_sz = hca_attr->hca_max_chan_sz;
-	hca_info->hca_max_sgl = hca_attr->hca_max_sgl;
-	hca_info->hca_max_cq = hca_attr->hca_max_cq;
-	hca_info->hca_max_cq_sz = hca_attr->hca_max_cq_sz;
-	hca_info->hca_page_sz = hca_attr->hca_page_sz;
-	hca_info->hca_max_memr = hca_attr->hca_max_memr;
-	hca_info->hca_max_memr_len = hca_attr->hca_max_memr_len;
-	hca_info->hca_max_mem_win = hca_attr->hca_max_mem_win;
-	hca_info->hca_max_rsc = hca_attr->hca_max_rsc;
-	hca_info->hca_max_rdma_in_chan = hca_attr->hca_max_rdma_in_chan;
-	hca_info->hca_max_rdma_out_chan = hca_attr->hca_max_rdma_out_chan;
-	hca_info->hca_max_ipv6_chan = hca_attr->hca_max_ipv6_chan;
-	hca_info->hca_max_ether_chan = hca_attr->hca_max_ether_chan;
-	hca_info->hca_max_mcg_chans = hca_attr->hca_max_mcg_chans;
-	hca_info->hca_max_mcg = hca_attr->hca_max_mcg;
-	hca_info->hca_max_chan_per_mcg = hca_attr->hca_max_chan_per_mcg;
-	hca_info->hca_max_partitions = hca_attr->hca_max_partitions;
-	hca_info->hca_local_ack_delay = hca_attr->hca_local_ack_delay;
-	hca_info->hca_max_port_sgid_tbl_sz = hca_attr->hca_max_port_sgid_tbl_sz;
-	hca_info->hca_max_port_pkey_tbl_sz = hca_attr->hca_max_port_pkey_tbl_sz;
-	hca_info->hca_max_pd = hca_attr->hca_max_pd;
-	hca_info->hca_max_ud_dest = hca_attr->hca_max_ud_dest;
-	hca_info->hca_max_srqs = hca_attr->hca_max_srqs;
-	hca_info->hca_max_srqs_sz = hca_attr->hca_max_srqs_sz;
-	hca_info->hca_max_srq_sgl = hca_attr->hca_max_srq_sgl;
-	hca_info->hca_max_cq_handlers = hca_attr->hca_max_cq_handlers;
-	hca_info->hca_reserved_lkey = hca_attr->hca_reserved_lkey;
-	hca_info->hca_max_fmrs = hca_attr->hca_max_fmrs;
-	hca_info->hca_max_lso_size = hca_attr->hca_max_lso_size;
-	hca_info->hca_max_lso_hdr_size = hca_attr->hca_max_lso_hdr_size;
-	hca_info->hca_max_inline_size = hca_attr->hca_max_inline_size;
-	hca_info->hca_max_cq_mod_count = hca_attr->hca_max_cq_mod_count;
-	hca_info->hca_max_cq_mod_usec = hca_attr->hca_max_cq_mod_usec;
-	hca_info->hca_fw_major_version = hca_attr->hca_fw_major_version;
-	hca_info->hca_fw_minor_version = hca_attr->hca_fw_minor_version;
-	hca_info->hca_fw_micro_version = hca_attr->hca_fw_micro_version;
-	hca_info->hca_ud_send_inline_sz = hca_attr->hca_ud_send_inline_sz;
-	hca_info->hca_conn_send_inline_sz = hca_attr->hca_conn_send_inline_sz;
-	hca_info->hca_conn_rdmaw_inline_overhead =
-	    hca_attr->hca_conn_rdmaw_inline_overhead;
-	hca_info->hca_recv_sgl_sz = hca_attr->hca_recv_sgl_sz;
-	hca_info->hca_ud_send_sgl_sz = hca_attr->hca_ud_send_sgl_sz;
-	hca_info->hca_conn_send_sgl_sz = hca_attr->hca_conn_send_sgl_sz;
-	hca_info->hca_conn_rdma_sgl_overhead =
-	    hca_attr->hca_conn_rdma_sgl_overhead;
-
-	(void) strlcpy(hca_info->hca_driver_name, driver_name,
-	    MAX_HCA_DRVNAME_LEN);
-	hca_info->hca_driver_instance = instance;
-
-	/* copy hca information to the user space */
-	if (ddi_copyout(hca_info, &((ibnex_ctl_query_hca_t *)arg)->hca_info,
-	    sizeof (ibnex_ctl_hca_info_t), mode) != 0) {
-		IBTF_DPRINTF_L2("ibnex", "\tctl_query_hca: ddi_copyout err");
-		rv = EFAULT;
+	hca_device_path_len = strlen(hca_device_path) + 1;
+
+#ifdef	_MULTI_DATAMODEL
+	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
+
+		IBNEX_CTL_CP_HCA_INFO(&query_hca_32->hca_info, hca_attr,
+		    driver_name, instance, query_hca_32->hca_device_path,
+		    device_path_alloc_sz, hca_device_path_len);
+
+		/* copy hca information to the user space */
+		if (ddi_copyout(&query_hca_32->hca_info,
+		    &((ibnex_ctl_query_hca_32_t *)arg)->hca_info,
+		    sizeof (ibnex_ctl_hca_info_32_t), mode) != 0) {
+			IBTF_DPRINTF_L2("ibnex",
+			    "\tctl_query_hca: ddi_copyout err 1");
+			rv = EFAULT;
+			goto out;
+		}
+	} else
+#endif
+	{
+		IBNEX_CTL_CP_HCA_INFO(&query_hca->hca_info, hca_attr,
+		    driver_name, instance, device_path,
+		    device_path_alloc_sz, hca_device_path_len);
+
+		/* copy hca information to the user space */
+		if (ddi_copyout(&query_hca->hca_info,
+		    &((ibnex_ctl_query_hca_t *)arg)->hca_info,
+		    sizeof (ibnex_ctl_hca_info_t), mode) != 0) {
+			IBTF_DPRINTF_L2("ibnex",
+			    "\tctl_query_hca: ddi_copyout err 2");
+			rv = EFAULT;
+			goto out;
+		}
+	}
+
+	if (device_path_alloc_sz >= hca_device_path_len) {
+		if (ddi_copyout(hca_device_path,
+		    device_path,
+		    hca_device_path_len, mode) != 0) {
+			IBTF_DPRINTF_L2("ibnex", "\tctl_query_hca: "
+			    "ddi_copyout err copying device path");
+			rv = EFAULT;
+		}
 	}
 
 out:
-	kmem_free(query_hca, sizeof (ibnex_ctl_query_hca_t));
-	kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
+	if (query_hca)
+		kmem_free(query_hca, sizeof (ibnex_ctl_query_hca_t));
+	if (query_hca_32)
+		kmem_free(query_hca_32, sizeof (ibnex_ctl_query_hca_32_t));
+	if (hca_attr)
+		kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
+	if (hca_device_path)
+		kmem_free(hca_device_path, MAXPATHLEN);
+
 	return (rv);
 }
 
@@ -3056,7 +3133,7 @@
 		if (ddi_copyin((void *)arg, query_hca_port_32,
 		    sizeof (ibnex_ctl_query_hca_port_32_t), mode) != 0) {
 			IBTF_DPRINTF_L2("ibnex",
-			    "\tctl_query_hca_port: ddi_copyin err 2");
+			    "\tctl_query_hca_port: ddi_copyin err 1");
 			rv = EFAULT;
 			goto out;
 		}
--- a/usr/src/uts/common/io/ib/ibtl/ibtl_ibnex.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/ib/ibtl/ibtl_ibnex.c	Mon Jul 20 13:07:46 2009 -0400
@@ -635,6 +635,8 @@
  *	driver_name	- caller allocated buffer which will contain
  *			  HCA driver name upon success
  *	driver_instance - HCA driver instance
+ *	hca_device_path	- caller allocated buffer of size MAXPATHLEN which
+ *			  will contain hca device path upon success.
  * Returns:
  *	IBT_SUCCESS/IBT_FAILURE
  * Description:
@@ -643,7 +645,8 @@
  */
 ibt_status_t
 ibtl_ibnex_query_hca_byguid(ib_guid_t hca_guid, ibt_hca_attr_t *hca_attrs,
-    char *driver_name, size_t driver_name_size, int *driver_instance)
+    char *driver_name, size_t driver_name_size, int *driver_instance,
+    char *hca_device_path)
 {
 	ibtl_hca_devinfo_t	*hca_devp;
 
@@ -667,6 +670,7 @@
 		return (IBT_INSUFF_KERNEL_RESOURCE);
 	}
 
+	(void) ddi_pathname(hca_devp->hd_hca_dip, hca_device_path);
 	*driver_instance = ddi_get_instance(hca_devp->hd_hca_dip);
 	bcopy(hca_devp->hd_hca_attr, hca_attrs, sizeof (ibt_hca_attr_t));
 
--- a/usr/src/uts/common/io/ib/mgt/ibdm/ibdm.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/ib/mgt/ibdm/ibdm.c	Mon Jul 20 13:07:46 2009 -0400
@@ -41,6 +41,7 @@
 #include <sys/taskq.h>
 #include <sys/ib/mgt/ibdm/ibdm_impl.h>
 #include <sys/ib/mgt/ibmf/ibmf_impl.h>
+#include <sys/ib/ibtl/impl/ibtl_ibnex.h>
 #include <sys/modctl.h>
 
 /* Function Prototype declarations */
@@ -87,6 +88,7 @@
 static void	ibdm_alloc_send_buffers(ibmf_msg_t *);
 static void	ibdm_free_send_buffers(ibmf_msg_t *);
 static void	ibdm_handle_hca_detach(ib_guid_t);
+static void	ibdm_handle_port_change_event(ibt_async_event_t *);
 static int	ibdm_fini_port(ibdm_port_attr_t *);
 static int	ibdm_uninit_hca(ibdm_hca_list_t *);
 static void	ibdm_handle_setclassportinfo(ibmf_handle_t, ibmf_msg_t *,
@@ -553,6 +555,14 @@
 		hca_list->hl_nports_active++;
 		cv_broadcast(&ibdm.ibdm_port_settle_cv);
 		mutex_exit(&ibdm.ibdm_hl_mutex);
+
+		/* Inform IB nexus driver */
+		mutex_enter(&ibdm.ibdm_ibnex_mutex);
+		if (ibdm.ibdm_ibnex_callback != NULL) {
+			(*ibdm.ibdm_ibnex_callback)((void *)
+			    &event->ev_hca_guid, IBDM_EVENT_PORT_UP);
+		}
+		mutex_exit(&ibdm.ibdm_ibnex_mutex);
 		break;
 
 	case IBT_ERROR_PORT_DOWN:
@@ -576,19 +586,8 @@
 
 	case IBT_PORT_CHANGE_EVENT:
 		IBTF_DPRINTF_L4("ibdm", "\tevent_hdlr: PORT_CHANGE");
-		if (event->ev_port_flags & IBT_PORT_CHANGE_PKEY) {
-			mutex_enter(&ibdm.ibdm_hl_mutex);
-			port = ibdm_get_port_attr(event, &hca_list);
-			if (port == NULL) {
-				IBTF_DPRINTF_L2("ibdm",
-				    "\tevent_hdlr: HCA not present");
-				mutex_exit(&ibdm.ibdm_hl_mutex);
-				break;
-			}
-			ibdm_update_port_pkeys(port);
-			cv_broadcast(&ibdm.ibdm_port_settle_cv);
-			mutex_exit(&ibdm.ibdm_hl_mutex);
-		}
+		if (event->ev_port_flags & IBT_PORT_CHANGE_PKEY)
+			ibdm_handle_port_change_event(event);
 		break;
 
 	default:		/* Ignore all other events/errors */
@@ -596,6 +595,33 @@
 	}
 }
 
+static void
+ibdm_handle_port_change_event(ibt_async_event_t *event)
+{
+	ibdm_port_attr_t	*port;
+	ibdm_hca_list_t		*hca_list;
+
+	IBTF_DPRINTF_L2("ibdm", "\tibdm_handle_port_change_event:"
+	    " HCA guid  %llx", event->ev_hca_guid);
+	mutex_enter(&ibdm.ibdm_hl_mutex);
+	port = ibdm_get_port_attr(event, &hca_list);
+	if (port == NULL) {
+		IBTF_DPRINTF_L2("ibdm", "\tevent_hdlr: HCA not present");
+		mutex_exit(&ibdm.ibdm_hl_mutex);
+		return;
+	}
+	ibdm_update_port_pkeys(port);
+	cv_broadcast(&ibdm.ibdm_port_settle_cv);
+	mutex_exit(&ibdm.ibdm_hl_mutex);
+
+	/* Inform IB nexus driver */
+	mutex_enter(&ibdm.ibdm_ibnex_mutex);
+	if (ibdm.ibdm_ibnex_callback != NULL) {
+		(*ibdm.ibdm_ibnex_callback)((void *)
+		    &event->ev_hca_guid, IBDM_EVENT_PORT_PKEY_CHANGE);
+	}
+	mutex_exit(&ibdm.ibdm_ibnex_mutex);
+}
 
 /*
  * ibdm_update_port_pkeys()
@@ -1106,8 +1132,11 @@
 		}
 	}
 	if (head->hl_hca_hdl)
-		if (ibt_close_hca(head->hl_hca_hdl) != IBT_SUCCESS)
+		if (ibt_close_hca(head->hl_hca_hdl) != IBT_SUCCESS) {
+			IBTF_DPRINTF_L2("ibdm", "uninit_hca: "
+			    "ibt_close_hca() failed");
 			return (IBDM_FAILURE);
+		}
 	kmem_free(head->hl_port_attr,
 	    head->hl_nports * sizeof (ibdm_port_attr_t));
 	kmem_free(head->hl_hca_port_attr, sizeof (ibdm_port_attr_t));
@@ -1151,7 +1180,7 @@
 
 		ibmf_status = ibmf_unregister(&port_attr->pa_ibmf_hdl, 0);
 		if (ibmf_status != IBMF_SUCCESS) {
-			IBTF_DPRINTF_L4("ibdm", "\tfini_port: "
+			IBTF_DPRINTF_L2("ibdm", "\tfini_port: "
 			    "ibmf_unregister failed %d", ibmf_status);
 			return (IBDM_FAILURE);
 		}
@@ -1162,7 +1191,7 @@
 	if (port_attr->pa_sa_hdl) {
 		ibmf_status = ibmf_sa_session_close(&port_attr->pa_sa_hdl, 0);
 		if (ibmf_status != IBMF_SUCCESS) {
-			IBTF_DPRINTF_L4("ibdm", "\tfini_port: "
+			IBTF_DPRINTF_L2("ibdm", "\tfini_port: "
 			    "ibmf_sa_session_close failed %d", ibmf_status);
 			return (IBDM_FAILURE);
 		}
@@ -5404,7 +5433,7 @@
 	 */
 	if (ibmf_alloc_msg(gid_info->gl_ibmf_hdl, IBMF_ALLOC_SLEEP,
 	    &msg) != IBMF_SUCCESS) {
-		IBTF_DPRINTF_L4("ibdm", "\tsend_ioc_profile: pkt alloc fail");
+		IBTF_DPRINTF_L2("ibdm", "\tsend_ioc_profile: pkt alloc fail");
 		return (IBDM_FAILURE);
 	}
 
--- a/usr/src/uts/common/io/kb8042/at_keyprocess.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/kb8042/at_keyprocess.c	Mon Jul 20 13:07:46 2009 -0400
@@ -33,29 +33,12 @@
 #include "kb8042.h"
 
 /*
- * Debugging for this module is enabled by the kb8042_debug flag
- * defined in kb8042.c.  See that module for details.  This flag is
- * hotkey enabled by F10 if the kb8042_enable_debug_hotkey flag is set.
- */
-
-#if	defined(DEBUG) || defined(lint)
-#define	KD_DEBUG
-#endif
-
-/*
  * A note on the use of prom_printf here:  Most of these routines can be
  * called from "polled mode", where we're servicing I/O requests from kmdb.
  * Normal system services are not available from polled mode; cmn_err will
  * not work.  prom_printf is the only safe output mechanism.
  */
 
-#if	defined(KD_DEBUG)
-extern boolean_t kb8042_debug;
-#define	DEBUG_KD(f)	{ if (kb8042_debug) prom_printf f; }
-#else
-#define	DEBUG_KD(f)	/* nothing */
-#endif
-
 #define	KEYBAD		0xff		/* should generate an error */
 #define	KEYIGN		0xfe		/* ignore this sequence */
 
@@ -748,8 +731,6 @@
     enum keystate	*state,
     boolean_t		*synthetic_release_needed)
 {
-	DEBUG_KD(("KeyboardConvertScan_set1: 0x%02x ", scan));
-
 	*synthetic_release_needed = B_FALSE;
 	*state = KEY_PRESSED;
 
@@ -763,7 +744,6 @@
 		 * Perhaps we should reset state here,
 		 * since we no longer know what's going on.
 		 */
-		DEBUG_KD(("-> overrun\n"));
 		return (B_FALSE);
 	case KB_POST_FAIL:
 		/*
@@ -776,7 +756,6 @@
 		 * Reset to idle
 		 */
 		kb8042->parse_scan_state = STATE_IDLE;
-		DEBUG_KD(("-> POST %s\n", scan == KB_POST_OK ? "OK" : "FAIL"));
 		return (B_FALSE);
 
 	case KXT_EXTEND:
@@ -809,12 +788,10 @@
 		switch (scan) {
 		case KXT_EXTEND:
 			kb8042->parse_scan_state = STATE_E0;
-			DEBUG_KD(("-> state E0\n"));
 			return (B_FALSE);
 
 		case KXT_EXTEND2:
 			kb8042->parse_scan_state = STATE_E1;
-			DEBUG_KD(("-> state E1\n"));
 			return (B_FALSE);
 
 		/*
@@ -857,7 +834,6 @@
 		switch (scan) {
 		case 0x1d:
 			kb8042->parse_scan_state = STATE_E1_1D;
-			DEBUG_KD(("-> state E1 1D\n"));
 			return (B_FALSE);
 		default:
 			*keynum = INVALID;
@@ -888,11 +864,9 @@
 
 	switch (*keynum) {
 	case KEYIGN:				/* not a key, nor an error */
-		DEBUG_KD(("-> hole -> ignored\n"));
 		return (B_FALSE);		/* also not a final keycode */
 
 	case KEYBAD:		/* not part of a legit sequence? */
-		DEBUG_KD(("-> bad -> ignored\n"));
 		return (B_FALSE);	/* and return not a final keycode */
 
 	default:
@@ -900,11 +874,6 @@
 		 * If we're here, it's a valid keycode.  We've already
 		 * filled in the return values; return success.
 		 */
-
-		DEBUG_KD(("-> %s keypos %d\n",
-		    *state == KEY_RELEASED ? "released" : "pressed",
-		    *keynum));
-
 		return (B_TRUE);		/* resolved to a key */
 	}
 }
@@ -930,8 +899,6 @@
     enum keystate	*state,
     boolean_t		*synthetic_release_needed)
 {
-	DEBUG_KD(("KeyboardConvertScan_set2: 0x%02x ", scan));
-
 	*synthetic_release_needed = B_FALSE;
 	*state = KEY_PRESSED;
 
@@ -949,7 +916,6 @@
 	case KAT_BREAK:
 		/* Switch states so we can recognize the code that follows */
 		kb8042->break_received = 1;
-		DEBUG_KD(("-> break prefix\n"));
 		return (B_FALSE);	/* not a final keycode */
 
 	case KB_ERROR:
@@ -957,7 +923,6 @@
 		 * Perhaps we should reset state here,
 		 * since we no longer know what's going on.
 		 */
-		DEBUG_KD(("-> overrun\n"));
 		return (B_FALSE);
 
 	case KB_POST_OK:
@@ -972,7 +937,6 @@
 		 * Reset to idle
 		 */
 		kb8042->parse_scan_state = STATE_IDLE;
-		DEBUG_KD(("-> POST %s\n", scan == KB_POST_OK ? "OK" : "FAIL"));
 		return (B_FALSE);
 	}
 
@@ -986,12 +950,10 @@
 		switch (scan) {
 		case KXT_EXTEND:
 			kb8042->parse_scan_state = STATE_E0;
-			DEBUG_KD(("-> state E0\n"));
 			return (B_FALSE);
 
 		case KXT_EXTEND2:
 			kb8042->parse_scan_state = STATE_E1;
-			DEBUG_KD(("-> state E1\n"));
 			return (B_FALSE);
 
 		/*
@@ -1034,7 +996,6 @@
 		switch (scan) {
 		case 0x14:
 			kb8042->parse_scan_state = STATE_E1_14;
-			DEBUG_KD(("-> state E1 14\n"));
 			return (B_FALSE);
 		default:
 			*keynum = INVALID;
@@ -1112,11 +1073,9 @@
 
 	switch (*keynum) {
 	case KEYIGN:				/* not a key, nor an error */
-		DEBUG_KD(("-> hole -> ignored\n"));
 		return (B_FALSE);		/* also not a final keycode */
 
 	case KEYBAD:		/* not part of a legit sequence? */
-		DEBUG_KD(("-> bad -> ignored\n"));
 		return (B_FALSE);	/* and return not a final keycode */
 
 	default:
@@ -1124,11 +1083,6 @@
 		 * If we're here, it's a valid keycode.  We've already
 		 * filled in the return values; return success.
 		 */
-
-		DEBUG_KD(("-> %s keypos %d\n",
-		    *state == KEY_RELEASED ? "released" : "pressed",
-		    *keynum));
-
 		return (B_TRUE);		/* resolved to a key */
 	}
 }
--- a/usr/src/uts/common/io/kb8042/kb8042.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/kb8042/kb8042.c	Mon Jul 20 13:07:46 2009 -0400
@@ -103,32 +103,6 @@
 /* 248 */	0,	0,	0,	0
 };
 
-/*
- * DEBUG (or KD_DEBUG for just this module) turns on a flag called
- * kb8042_enable_debug_hotkey.  If kb8042_enable_debug_hotkey is true,
- * then the following hotkeys are enabled:
- *    F10 - turn on debugging "normal" translations
- *    F9  - turn on debugging "getchar" translations
- *    F8  - turn on "low level" debugging
- *    F7  - turn on terse press/release debugging
- *    F1  - turn off all debugging
- * The default value for kb8042_enable_debug_hotkey is false, disabling
- * these hotkeys.
- */
-
-#if	defined(DEBUG) || defined(lint)
-#define	KD_DEBUG
-#endif
-
-#ifdef	KD_DEBUG
-boolean_t	kb8042_enable_debug_hotkey = B_FALSE;
-boolean_t	kb8042_debug = B_FALSE;
-boolean_t	kb8042_getchar_debug = B_FALSE;
-boolean_t	kb8042_low_level_debug = B_FALSE;
-boolean_t	kb8042_pressrelease_debug = B_FALSE;
-static void kb8042_debug_hotkey(int scancode);
-#endif
-
 #ifdef __sparc
 #define	USECS_PER_WAIT 100
 #define	MAX_WAIT_USECS 100000 /* in usecs = 100 ms */
@@ -139,6 +113,9 @@
 
 #endif
 
+#define	MAX_KB8042_WAIT_MAX_MS	500		/* 500ms total */
+#define	MAX_KB8042_RETRIES	5
+
 enum state_return { STATE_NORMAL, STATE_INTERNAL };
 
 static void kb8042_init(struct kb8042 *kb8042, boolean_t from_resume);
@@ -312,21 +289,24 @@
 	}
 }
 
+/*
+ * kb8042_send_and_expect does all its I/O via polling interfaces
+ */
 static boolean_t
 kb8042_send_and_expect(struct kb8042 *kb8042, uint8_t send, uint8_t expect,
-    boolean_t polled, int timeout, int *error, uint8_t *got)
+    int timeout, int *error, uint8_t *got)
 {
-	int port = (polled == B_TRUE) ? I8042_POLL_INPUT_DATA :
-	    I8042_INT_INPUT_DATA;
 	uint8_t datab;
 	int err;
 	boolean_t rval;
 
-	kb8042_send_to_keyboard(kb8042, send, polled);
+	ddi_put8(kb8042->handle,
+	    kb8042->addr + I8042_POLL_OUTPUT_DATA, send);
 
-	if (kb8042_is_input_avail(kb8042, timeout, polled)) {
+	if (kb8042_is_input_avail(kb8042, timeout, B_TRUE)) {
 		err = 0;
-		datab = ddi_get8(kb8042->handle, kb8042->addr + port);
+		datab = ddi_get8(kb8042->handle,
+		    kb8042->addr + I8042_POLL_INPUT_DATA);
 		rval = ((datab == expect) ? B_TRUE : B_FALSE);
 	} else {
 		err = EAGAIN;
@@ -351,12 +331,16 @@
 	}
 }
 
+/*
+ * kb8042_read_scanset works properly because it is called before ddi_add_intr
+ * (if it is called after ddi_add_intr, i8042_intr would call kb8042_intr
+ * instead of just storing the data that comes in from the keyboard, which
+ * would prevent the code here from getting it.)
+ */
 static int
-kb8042_read_scanset(struct kb8042 *kb8042, boolean_t polled)
+kb8042_read_scanset(struct kb8042 *kb8042)
 {
 	int scanset = -1;
-	int port = (polled == B_TRUE) ? I8042_POLL_INPUT_DATA :
-	    I8042_INT_INPUT_DATA;
 	int err;
 	uint8_t got;
 
@@ -366,8 +350,8 @@
 	 * Send a "change scan code set" command to the keyboard.
 	 * It should respond with an ACK.
 	 */
-	if (kb8042_send_and_expect(kb8042, KB_SET_SCAN, KB_ACK, polled,
-	    MAX_WAIT_USECS, &err, &got) != B_TRUE) {
+	if (kb8042_send_and_expect(kb8042, KB_SET_SCAN, KB_ACK, MAX_WAIT_USECS,
+	    &err, &got) != B_TRUE) {
 		goto fail_read_scanset;
 	}
 
@@ -375,8 +359,8 @@
 	 * Send a 0.  The keyboard should ACK the 0, then it should send the
 	 * scan code set in use.
 	 */
-	if (kb8042_send_and_expect(kb8042, 0, KB_ACK, polled,
-	    MAX_WAIT_USECS, &err, &got) != B_TRUE) {
+	if (kb8042_send_and_expect(kb8042, 0, KB_ACK, MAX_WAIT_USECS, &err,
+	    &got) != B_TRUE) {
 		goto fail_read_scanset;
 	}
 
@@ -386,11 +370,11 @@
 	 * just for fun, so blow past those to get the keyboard scan code.
 	 */
 	while (kb8042_is_input_avail(kb8042, MAX_WAIT_USECS, B_TRUE) &&
-	    (scanset = ddi_get8(kb8042->handle, kb8042->addr + port))
-	    == KB_ACK)
+	    (scanset = ddi_get8(kb8042->handle,
+	    kb8042->addr + I8042_POLL_INPUT_DATA)) == KB_ACK)
 		;
 
-#ifdef KD_DEBUG
+#ifdef DEBUG
 	cmn_err(CE_NOTE, "!Scan code set from keyboard is `%d'.",
 	    scanset);
 #endif
@@ -398,7 +382,7 @@
 	return (scanset);
 
 fail_read_scanset:
-#ifdef KD_DEBUG
+#ifdef DEBUG
 	if (err == 0)
 		cmn_err(CE_NOTE, "Could not read current scan set from "
 		    "keyboard: %s. (Expected 0x%x, but got 0x%x).",
@@ -473,7 +457,7 @@
 	rc = ddi_regs_map_setup(devi, 0, (caddr_t *)&kb8042->addr,
 	    (offset_t)0, (offset_t)0, &attr, &kb8042->handle);
 	if (rc != DDI_SUCCESS) {
-#if	defined(KD_DEBUG)
+#ifdef DEBUG
 		cmn_err(CE_WARN, "kb8042_attach:  can't map registers");
 #endif
 		goto failure;
@@ -490,13 +474,14 @@
 	mutex_init(&kb8042->w_hw_mutex, NULL, MUTEX_DRIVER, kb8042->w_iblock);
 	cv_init(&kb8042->ops_cv, NULL, CV_DRIVER, NULL);
 	cv_init(&kb8042->suspend_cv, NULL, CV_DRIVER, NULL);
+	cv_init(&kb8042->cmd_cv, NULL, CV_DRIVER, NULL);
 	kb8042->init_state |= KB8042_HW_MUTEX_INITTED;
 
 	kb8042_init(kb8042, B_FALSE);
 
 #ifdef __sparc
 	/* Detect the scan code set currently in use */
-	scanset = kb8042_read_scanset(kb8042, B_TRUE);
+	scanset = kb8042_read_scanset(kb8042);
 
 	if (scanset < 0 && kb8042_warn_unknown_scanset) {
 
@@ -542,7 +527,7 @@
 
 	ddi_report_dev(devi);
 
-#ifdef	KD_DEBUG
+#ifdef DEBUG
 	cmn_err(CE_CONT, "?%s instance #%d READY\n",
 	    DRIVER_NAME(devi), ddi_get_instance(devi));
 #endif
@@ -620,15 +605,16 @@
 {
 	ASSERT(kb8042_dip != NULL);
 
+	if (kb8042->init_state & KB8042_INTR_ADDED)
+		ddi_remove_intr(kb8042_dip, 0, kb8042->w_iblock);
+
 	if (kb8042->init_state & KB8042_HW_MUTEX_INITTED) {
+		cv_destroy(&kb8042->cmd_cv);
 		cv_destroy(&kb8042->suspend_cv);
 		cv_destroy(&kb8042->ops_cv);
 		mutex_destroy(&kb8042->w_hw_mutex);
 	}
 
-	if (kb8042->init_state & KB8042_INTR_ADDED)
-		ddi_remove_intr(kb8042_dip, 0, kb8042->w_iblock);
-
 	if (kb8042->init_state & KB8042_REGS_MAPPED)
 		ddi_regs_map_free(&kb8042->handle);
 
@@ -657,8 +643,15 @@
 
 	kb8042->kb_old_key_pos = 0;
 
+	/*
+	 * Explicitly grab and release the 8042 lock outside of
+	 * kb8042_send_to_keyboard, because this is the only situation
+	 * where a polling interface is used with locking required.
+	 */
+	(void) ddi_get8(kb8042->handle, kb8042->addr + I8042_LOCK);
 	/* Set up the command state machine and start it running. */
-	kb8042_send_to_keyboard(kb8042, KB_ENABLE, B_FALSE);
+	kb8042_send_to_keyboard(kb8042, KB_ENABLE, B_TRUE);
+	(void) ddi_get8(kb8042->handle, kb8042->addr + I8042_UNLOCK);
 
 	kb8042->w_init++;
 
@@ -1013,9 +1006,23 @@
 	enum keystate	state;
 	boolean_t	synthetic_release_needed;
 
-#ifdef	KD_DEBUG
-	kb8042_debug_hotkey(scancode);
-#endif
+	/*
+	 * Intercept ACK and RESEND and signal the condition that
+	 * kb8042_send_and_wait is waiting for.
+	 */
+	if (scancode == KB_ACK) {
+		mutex_enter(&kb8042->w_hw_mutex);
+		kb8042->acked = 1;
+		cv_signal(&kb8042->cmd_cv);
+		mutex_exit(&kb8042->w_hw_mutex);
+		return;
+	} else if (scancode == KB_RESEND) {
+		mutex_enter(&kb8042->w_hw_mutex);
+		kb8042->need_retry = 1;
+		cv_signal(&kb8042->cmd_cv);
+		mutex_exit(&kb8042->w_hw_mutex);
+		return;
+	}
 
 	if (!kb8042->w_init)	/* can't do anything anyway */
 		return;
@@ -1025,48 +1032,23 @@
 
 	if (legit == 0) {
 		/* Eaten by translation */
-#ifdef	KD_DEBUG
-		if (kb8042_debug)
-			prom_printf("kb8042_intr: 0x%x -> ignored\n", scancode);
-#endif
 		return;
 	}
 
-#ifdef	KD_DEBUG
-	if (kb8042_debug) {
-		prom_printf("kb8042_intr:  0x%x -> %s %d",
-		    scancode,
-		    state == KEY_RELEASED ? "released" : "pressed",
-		    key_pos);
-	}
-#endif
-
 	/*
 	 * Don't know if we want this permanently, but it seems interesting
 	 * for the moment.
 	 */
 	if (key_pos == kb8042->debugger.mod1) {
-#ifdef	KD_DEBUG
-		if (kb8042_debug)
-			prom_printf(" -> debug mod1");
-#endif
 		kb8042->debugger.mod1_down = (state == KEY_PRESSED);
 	}
 	if (key_pos == kb8042->debugger.mod2) {
-#ifdef	KD_DEBUG
-		if (kb8042_debug)
-			prom_printf(" -> debug mod2");
-#endif
 		kb8042->debugger.mod2_down = (state == KEY_PRESSED);
 	}
 	if (kb8042->debugger.enabled &&
 	    key_pos == kb8042->debugger.trigger &&
 	    kb8042->debugger.mod1_down &&
 	    kb8042->debugger.mod2_down) {
-#ifdef	KD_DEBUG
-		if (kb8042_debug)
-			prom_printf(" -> debugger\n");
-#endif
 		/*
 		 * Require new presses of the modifiers.
 		 */
@@ -1083,10 +1065,6 @@
 	 * Ctrl-Alt-D still works.
 	 */
 	if (kb8042->w_qp == NULL) {
-#ifdef	KD_DEBUG
-		if (kb8042_debug)
-			prom_printf(" -> nobody home\n");
-#endif
 		return;
 	}
 
@@ -1097,27 +1075,11 @@
 	 * Don't think so.)
 	 */
 	if (kb8042_autorepeat_detect(kb8042, key_pos, state)) {
-#ifdef	KD_DEBUG
-		if (kb8042_debug)
-			prom_printf(" -> autorepeat ignored\n");
-#endif
 		return;
 	}
 
-#ifdef	KD_DEBUG
-	if (kb8042_debug)
-		prom_printf(" -> OK\n");
-#endif
 
-#if	defined(KD_DEBUG)
-	if (kb8042_pressrelease_debug) {
-		prom_printf(" %s%d ",
-		    state == KEY_PRESSED ? "+" : "-",
-		    key_pos);
-	}
-#endif
-
-		kb8042_process_key(kb8042, key_pos, state);
+	kb8042_process_key(kb8042, key_pos, state);
 
 	/*
 	 * This is a total hack.  For some stupid reason, the two additional
@@ -1125,12 +1087,6 @@
 	 * only.  We synthesize a release immediately.
 	 */
 	if (synthetic_release_needed) {
-#if	defined(KD_DEBUG)
-		if (kb8042_debug)
-			prom_printf("synthetic release %d\n", key_pos);
-		if (kb8042_pressrelease_debug)
-			prom_printf(" -%d(s) ", key_pos);
-#endif
 		(void) kb8042_autorepeat_detect(kb8042, key_pos, KEY_RELEASED);
 		kb8042_process_key(kb8042, key_pos, state);
 	}
@@ -1179,11 +1135,6 @@
 		scancode = ddi_get8(kb8042->handle,
 		    kb8042->addr + I8042_INT_INPUT_DATA);
 
-#if	defined(KD_DEBUG)
-		if (kb8042_low_level_debug)
-			prom_printf(" <K:%x ", scancode);
-#endif
-
 		kb8042_received_byte(kb8042, scancode);
 	}
 
@@ -1223,10 +1174,6 @@
 		*key = kb8042->polled_synthetic_release_key;
 		*state = KEY_RELEASED;
 		kb8042->polled_synthetic_release_pending = B_FALSE;
-#if	defined(KD_DEBUG)
-		if (kb8042_getchar_debug)
-			prom_printf("synthetic release 0x%x\n", *key);
-#endif
 		(void) kb8042_autorepeat_detect(kb8042, *key, *state);
 		return (B_TRUE);
 	}
@@ -1240,33 +1187,11 @@
 		scancode = ddi_get8(kb8042->handle,
 		    kb8042->addr + I8042_POLL_INPUT_DATA);
 
-#if	defined(KD_DEBUG)
-		if (kb8042_low_level_debug)
-			prom_printf(" g<%x ", scancode);
-#endif
-
-#ifdef	KD_DEBUG
-		kb8042_debug_hotkey(scancode);
-		if (kb8042_getchar_debug)
-			prom_printf("polled 0x%x", scancode);
-#endif
-
 		legit = KeyboardConvertScan(kb8042, scancode, key, state,
 		    &synthetic_release_needed);
 		if (!legit) {
-#ifdef	KD_DEBUG
-			if (kb8042_getchar_debug)
-				prom_printf(" -> ignored\n");
-#endif
 			continue;
 		}
-#ifdef	KD_DEBUG
-		if (kb8042_getchar_debug) {
-			prom_printf(" -> %s %d\n",
-			    *state == KEY_PRESSED ? "pressed" : "released",
-			    *key);
-		}
-#endif
 		/*
 		 * For the moment at least, we rely on hardware autorepeat
 		 * for polled I/O autorepeat.  However, for coordination
@@ -1324,55 +1249,141 @@
 	kb8042_setled(kb8042, led_state, B_FALSE);
 }
 
+
+static int
+kb8042_send_and_wait(struct kb8042 *kb8042, uint8_t u8, boolean_t polled)
+{
+	uint8_t *outp = kb8042->addr +
+	    (polled ? I8042_POLL_OUTPUT_DATA : I8042_INT_OUTPUT_DATA);
+	uint8_t *inavp = kb8042->addr +
+	    (polled ? I8042_POLL_INPUT_AVAIL : I8042_INT_INPUT_AVAIL);
+	uint8_t *inp = kb8042->addr +
+	    (polled ? I8042_POLL_INPUT_DATA : I8042_INT_INPUT_DATA);
+	uint8_t b;
+	int ms_waited;
+	int timedout;
+	int expire;
+	int retries = 0;
+
+	do {
+		kb8042->acked = 0;
+		kb8042->need_retry = 0;
+		ms_waited = 0;		/* Zero it whether polled or not */
+		timedout = 0;
+
+		ddi_put8(kb8042->handle, outp, u8);
+
+		while (!kb8042->acked && !kb8042->need_retry && !timedout) {
+
+			if (polled) {
+				if (ddi_get8(kb8042->handle, inavp)) {
+					b = ddi_get8(kb8042->handle, inp);
+					switch (b) {
+					case KB_ACK:
+						kb8042->acked = 1;
+						break;
+					case KB_RESEND:
+						kb8042->need_retry = 1;
+						break;
+					default:
+						/*
+						 * drop it: We should never
+						 * get scancodes while
+						 * we're in the middle of a
+						 * command anyway.
+						 */
+#ifdef DEBUG
+						cmn_err(CE_WARN, "!Unexpected "
+						    " byte 0x%x", b);
+#endif
+						break;
+					}
+				}
+
+				/*
+				 * Wait 1ms if an ACK wasn't received yet
+				 */
+				if (!kb8042->acked) {
+					drv_usecwait(1000);
+					ms_waited++;
+					if (ms_waited >= MAX_KB8042_WAIT_MAX_MS)
+						timedout = B_TRUE;
+				}
+			} else {
+				/* Interrupt-driven */
+				expire = ddi_get_lbolt() +
+				    drv_usectohz(MAX_KB8042_WAIT_MAX_MS * 1000);
+
+				/*
+				 * If cv_timedwait returned -1 and we neither
+				 * received an ACK nor a RETRY response, then
+				 * we timed out.
+				 */
+				if (cv_timedwait(&kb8042->cmd_cv,
+				    &kb8042->w_hw_mutex, expire) == -1 &&
+				    !kb8042->acked && !kb8042->need_retry) {
+					timedout = B_TRUE;
+				}
+			}
+
+		}
+	} while ((kb8042->need_retry || timedout) &&
+	    ++retries < MAX_KB8042_RETRIES);
+
+	return (kb8042->acked);
+}
+
+/*
+ * kb8042_send_to_keyboard should be called with w_hw_mutex held if
+ * polled is FALSE.
+ */
 static void
 kb8042_send_to_keyboard(struct kb8042 *kb8042, int byte, boolean_t polled)
 {
-	uint8_t led_cmd[4];
 
 	/*
-	 * KB_SET_LED and KB_ENABLE are special commands for which the nexus
-	 * driver is requested to wait for responses before proceeding.
-	 * KB_SET_LED also provides an option byte for the nexus to send to
-	 * the keyboard after the acknowledgement.
+	 * KB_SET_LED and KB_ENABLE are special commands which require blocking
+	 * other 8042 consumers while executing.
 	 *
 	 * Other commands/data are sent using the single put8 I/O access
 	 * function.
 	 */
 	if (byte == KB_SET_LED) {
-		/*
-		 * Initialize the buffer used with _rep_put8.  We
-		 * expect an ACK after the SET_LED command, at which point
-		 * the LED byte should be sent to the keyboard.
-		 */
-		led_cmd[0] = KB_SET_LED;
-		led_cmd[1] = KB_ACK;
-		led_cmd[2] = KB_RESEND;
-		led_cmd[3] = kb8042_xlate_leds(kb8042->leds.desired);
-		if (polled) {
-			ddi_rep_put8(kb8042->handle, &led_cmd[0],
-			    kb8042->addr + I8042_POLL_CMD_PLUS_PARAM, 4, 0);
-		} else {
-			ddi_rep_put8(kb8042->handle, &led_cmd[0],
-			    kb8042->addr + I8042_INT_CMD_PLUS_PARAM, 4, 0);
+
+		if (!polled) {
+			(void) ddi_get8(kb8042->handle, kb8042->addr +
+			    I8042_LOCK);
+		}
+
+		if (kb8042_send_and_wait(kb8042, KB_SET_LED, polled)) {
+			/*
+			 * Ignore return value, as there's nothing we can
+			 * do about it if the SET LED command fails.
+			 */
+			(void) kb8042_send_and_wait(kb8042,
+			    kb8042_xlate_leds(kb8042->leds.desired), polled);
+		}
+
+		if (!polled) {
+			(void) ddi_get8(kb8042->handle, kb8042->addr +
+			    I8042_UNLOCK);
 		}
 		kb8042->leds.commanded = kb8042->leds.desired;
 
 	} else if (byte == KB_ENABLE) {
 
-		/*
-		 * Initialize the buffer used with _rep_put8.  We
-		 * expect an ACK after the KB_ENABLE command.
-		 */
-		led_cmd[0] = KB_ENABLE;
-		led_cmd[1] = KB_ACK;
-		led_cmd[2] = KB_RESEND;
-		if (polled) {
-			ddi_rep_put8(kb8042->handle, &led_cmd[0],
-			    kb8042->addr + I8042_POLL_CMD_PLUS_PARAM, 3, 0);
-		} else {
-			ddi_rep_put8(kb8042->handle, &led_cmd[0],
-			    kb8042->addr + I8042_INT_CMD_PLUS_PARAM, 3, 0);
+		if (!polled) {
+			(void) ddi_get8(kb8042->handle, kb8042->addr +
+			    I8042_LOCK);
 		}
+
+		(void) kb8042_send_and_wait(kb8042, KB_ENABLE, polled);
+
+		if (!polled) {
+			(void) ddi_get8(kb8042->handle, kb8042->addr +
+			    I8042_UNLOCK);
+		}
+
 	} else {
 		/* All other commands use the "normal" virtual output port */
 		if (polled) {
@@ -1383,11 +1394,6 @@
 			    kb8042->addr + I8042_INT_OUTPUT_DATA, byte);
 		}
 	}
-
-#if	defined(KD_DEBUG)
-	if (kb8042_low_level_debug)
-		prom_printf(" >K:%x ", byte);
-#endif
 }
 
 /*
@@ -1404,7 +1410,6 @@
 {
 	int cnt;
 	int ready;
-	unsigned char byt;
 
 	/* wait for up to 250 ms for a response */
 	for (cnt = 0; cnt < 250; cnt++) {
@@ -1421,12 +1426,8 @@
 	 * already.  (On a PC, the BIOS almost certainly did.)
 	 */
 	if (ready != 0) {
-		byt = ddi_get8(kb8042->handle,
+		(void) ddi_get8(kb8042->handle,
 		    kb8042->addr + I8042_INT_INPUT_DATA);
-#if	defined(KD_DEBUG)
-		if (kb8042_low_level_debug)
-			prom_printf(" <K:%x ", byt);
-#endif
 	}
 }
 
@@ -1474,55 +1475,6 @@
 #endif
 }
 
-#if	defined(KD_DEBUG)
-static void
-kb8042_debug_hotkey(int scancode)
-{
-	if (!kb8042_enable_debug_hotkey)
-		return;
-
-	switch (scancode) {
-	case 0x44:	/* F10 in Scan Set 1 code.  (Set 2 code is 0x09)  */
-		if (!kb8042_debug) {
-			prom_printf("\nKeyboard:  normal debugging on\n");
-			kb8042_debug = B_TRUE;
-		}
-		break;
-	case 0x43:	/* F9 in Scan Set 1 code.  (Set 2 code is 0x01) */
-		if (!kb8042_getchar_debug) {
-			prom_printf("\nKeyboard:  getchar debugging on\n");
-			kb8042_getchar_debug = B_TRUE;
-		}
-		break;
-	case 0x42:	/* F8 in Scan Set 1 code.  (Set 2 code is 0x0a) */
-		if (!kb8042_low_level_debug) {
-			prom_printf("\nKeyboard:  low-level debugging on\n");
-			kb8042_low_level_debug = B_TRUE;
-		}
-		break;
-	case 0x41:	/* F7 in Scan Set 1 code.  (Set 2 code is 0x83) */
-		if (!kb8042_pressrelease_debug) {
-			prom_printf(
-			    "\nKeyboard:  press/release debugging on\n");
-			kb8042_pressrelease_debug = B_TRUE;
-		}
-		break;
-	case 0x3b:	/* F1 in Scan Set 1 code.  (Set 2 code is 0x05) */
-		if (kb8042_debug ||
-		    kb8042_getchar_debug ||
-		    kb8042_low_level_debug ||
-		    kb8042_pressrelease_debug) {
-			prom_printf("\nKeyboard:  all debugging off\n");
-			kb8042_debug = B_FALSE;
-			kb8042_getchar_debug = B_FALSE;
-			kb8042_low_level_debug = B_FALSE;
-			kb8042_pressrelease_debug = B_FALSE;
-		}
-		break;
-	}
-}
-#endif
-
 static boolean_t
 kb8042_autorepeat_detect(
     struct kb8042 *kb8042,
--- a/usr/src/uts/common/io/kb8042/kb8042.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/kb8042/kb8042.h	Mon Jul 20 13:07:46 2009 -0400
@@ -24,7 +24,7 @@
 /*	  All Rights Reserved  	*/
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -112,6 +112,9 @@
 	int		ops;
 	kcondvar_t	suspend_cv;
 	kcondvar_t	ops_cv;
+	int		acked;
+	int		need_retry;
+	kcondvar_t	cmd_cv;
 };
 
 extern boolean_t KeyboardConvertScan(struct kb8042 *, unsigned char scan,
--- a/usr/src/uts/common/io/lvm/mirror/mirror_resync.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/lvm/mirror/mirror_resync.c	Mon Jul 20 13:07:46 2009 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -3808,7 +3808,7 @@
 	rw_enter(&un->un_pernode_dirty_mx[node], RW_WRITER);
 	if (un->un_pernode_dirty_bm[node] == NULL) {
 		un->un_pernode_dirty_bm[node] = (uchar_t *)kmem_zalloc(
-		    un->un_rrd_num, KM_SLEEP);
+		    howmany(un->un_rrd_num, NBBY), KM_SLEEP);
 	}
 	rw_exit(&un->un_pernode_dirty_mx[node]);
 
--- a/usr/src/uts/common/io/mouse8042.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/mouse8042.c	Mon Jul 20 13:07:46 2009 -0400
@@ -23,7 +23,7 @@
 /*	  All Rights Reserved  	*/
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -42,6 +42,7 @@
 #include <sys/stream.h>
 #include <sys/stropts.h>
 #include <sys/strtty.h>
+#include <sys/strsun.h>
 #include <sys/debug.h>
 #include <sys/ddi.h>
 #include <sys/stat.h>
@@ -53,17 +54,16 @@
 
 #include <sys/i8042.h>
 #include <sys/note.h>
+#include <sys/mouse.h>
 
 #define	DRIVER_NAME(dip)	ddi_driver_name(dip)
 
-#ifdef	DEBUG
-#define	MOUSE8042_DEBUG
-#endif
-
 #define	MOUSE8042_INTERNAL_OPEN(minor)	(((minor) & 0x1) == 1)
 #define	MOUSE8042_MINOR_TO_INSTANCE(minor)	((minor) / 2)
 #define	MOUSE8042_INTERNAL_MINOR(minor)		((minor) + 1)
 
+#define	MOUSE8042_RESET_TIMEOUT_USECS	500000	/* 500 ms */
+
 extern int ddi_create_internal_pathname(dev_info_t *, char *, int, minor_t);
 extern void consconfig_link(major_t major, minor_t minor);
 extern int consconfig_unlink(major_t major, minor_t minor);
@@ -85,6 +85,17 @@
  */
 static dev_info_t *mouse8042_dip;
 
+/*
+ * RESET states
+ */
+typedef enum {
+	MSE_RESET_IDLE,	/* No reset in progress */
+	MSE_RESET_PRE,	/* Send reset, waiting for ACK */
+	MSE_RESET_ACK,	/* Got ACK, waiting for 0xAA */
+	MSE_RESET_AA,	/* Got 0xAA, waiting for 0x00 */
+	MSE_RESET_FAILED
+} mouse8042_reset_state_e;
+
 struct mouse_state {
 	queue_t	*ms_rqp;
 	queue_t	*ms_wqp;
@@ -95,18 +106,19 @@
 
 	minor_t			ms_minor;
 	boolean_t		ms_opened;
+	kmutex_t		reset_mutex;
+	mouse8042_reset_state_e	reset_state;
+	timeout_id_t		reset_tid;
+	int			ready;
+	mblk_t			*reply_mp;
+	bufcall_id_t		bc_id;
 };
 
-#if	defined(MOUSE8042_DEBUG)
-int mouse8042_debug = 0;
-int mouse8042_debug_minimal = 0;
-#endif
-
 static uint_t mouse8042_intr(caddr_t arg);
 static int mouse8042_open(queue_t *q, dev_t *devp, int flag, int sflag,
 		cred_t *cred_p);
 static int mouse8042_close(queue_t *q, int flag, cred_t *cred_p);
-static int mouse8042_wput(queue_t *q, mblk_t *mp);
+static int mouse8042_wsrv(queue_t *qp);
 
 static int mouse8042_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
 		void *arg, void **result);
@@ -137,8 +149,8 @@
 };
 
 static struct qinit mouse8042_winit = {
-	mouse8042_wput,	/* put */
-	NULL,		/* service */
+	putq,		/* put */
+	mouse8042_wsrv,	/* service */
 	NULL,		/* open */
 	NULL,		/* close */
 	NULL,		/* admin */
@@ -254,15 +266,12 @@
 	int rc;
 
 
-#ifdef MOUSE8042_DEBUG
-	if (mouse8042_debug) {
-		cmn_err(CE_CONT, MODULE_NAME "_attach entry\n");
-	}
-#endif
-
 	if (cmd == DDI_RESUME) {
 		state = (struct mouse_state *)ddi_get_driver_private(dip);
 
+		/* Ready to handle inbound data from mouse8042_intr */
+		state->ready = 1;
+
 		/*
 		 * Send a 0xaa 0x00 upstream.
 		 * This causes the vuid module to reset the mouse.
@@ -289,6 +298,9 @@
 	/* allocate and initialize state structure */
 	state = kmem_zalloc(sizeof (struct mouse_state), KM_SLEEP);
 	state->ms_opened = B_FALSE;
+	state->reset_state = MSE_RESET_IDLE;
+	state->reset_tid = 0;
+	state->bc_id = 0;
 	ddi_set_driver_private(dip, state);
 
 	/*
@@ -310,10 +322,6 @@
 	rc = ddi_create_minor_node(dip, "mouse", S_IFCHR, instance * 2,
 	    DDI_NT_MOUSE, NULL);
 	if (rc != DDI_SUCCESS) {
-#if	defined(MOUSE8042_DEBUG)
-		cmn_err(CE_CONT,
-		    MODULE_NAME "_attach: ddi_create_minor_node failed\n");
-#endif
 		goto fail_1;
 	}
 
@@ -325,41 +333,33 @@
 	rc = ddi_regs_map_setup(dip, 0, (caddr_t *)&state->ms_addr,
 	    (offset_t)0, (offset_t)0, &attr, &state->ms_handle);
 	if (rc != DDI_SUCCESS) {
-#if	defined(MOUSE8042_DEBUG)
-		cmn_err(CE_WARN, MODULE_NAME "_attach:  can't map registers");
-#endif
 		goto fail_2;
 	}
 
 	rc = ddi_get_iblock_cookie(dip, 0, &state->ms_iblock_cookie);
 	if (rc != DDI_SUCCESS) {
-#if	defined(MOUSE8042_DEBUG)
-		cmn_err(CE_WARN,
-		    MODULE_NAME "_attach:  Can't get iblock cookie");
-#endif
 		goto fail_3;
 	}
 
 	mutex_init(&state->ms_mutex, NULL, MUTEX_DRIVER,
 	    state->ms_iblock_cookie);
+	mutex_init(&state->reset_mutex, NULL, MUTEX_DRIVER,
+	    state->ms_iblock_cookie);
 
 	rc = ddi_add_intr(dip, 0,
 	    (ddi_iblock_cookie_t *)NULL, (ddi_idevice_cookie_t *)NULL,
 	    mouse8042_intr, (caddr_t)state);
 	if (rc != DDI_SUCCESS) {
-#if	defined(MOUSE8042_DEBUG)
-		cmn_err(CE_WARN, MODULE_NAME "_attach: cannot add interrupt");
-#endif
 		goto fail_3;
 	}
 
 	mouse8042_dip = dip;
 
+	/* Ready to handle inbound data from mouse8042_intr */
+	state->ready = 1;
+
 	/* Now that we're attached, announce our presence to the world. */
 	ddi_report_dev(dip);
-#if	defined(MOUSE8042_DEBUG)
-	cmn_err(CE_CONT, "?%s #%d\n", DRIVER_NAME(dip), ddi_get_instance(dip));
-#endif
 	return (DDI_SUCCESS);
 
 fail_3:
@@ -383,11 +383,14 @@
 
 	switch (cmd) {
 	case DDI_SUSPEND:
+		/* Ignore all data from mouse8042_intr until we fully resume */
+		state->ready = 0;
 		return (DDI_SUCCESS);
 
 	case DDI_DETACH:
 		ddi_remove_intr(dip, 0, state->ms_iblock_cookie);
 		mouse8042_dip = NULL;
+		mutex_destroy(&state->reset_mutex);
 		mutex_destroy(&state->ms_mutex);
 		ddi_prop_remove_all(dip);
 		ddi_regs_map_free(&state->ms_handle);
@@ -396,12 +399,6 @@
 		return (DDI_SUCCESS);
 
 	default:
-#ifdef MOUSE8042_DEBUG
-		if (mouse8042_debug) {
-			cmn_err(CE_CONT,
-			    "mouse8042_detach: cmd = %d unknown\n", cmd);
-		}
-#endif
 		return (DDI_FAILURE);
 	}
 }
@@ -419,10 +416,6 @@
 	minor_t	minor = getminor(dev);
 	int	instance = MOUSE8042_MINOR_TO_INSTANCE(minor);
 
-#ifdef MOUSE8042_DEBUG
-	if (mouse8042_debug)
-		cmn_err(CE_CONT, "mouse8042_getinfo: call\n");
-#endif
 	switch (infocmd) {
 	case DDI_INFO_DEVT2DEVINFO:
 		if (mouse8042_dip == NULL)
@@ -457,11 +450,6 @@
 
 	state = ddi_get_driver_private(mouse8042_dip);
 
-#ifdef MOUSE8042_DEBUG
-	if (mouse8042_debug)
-		cmn_err(CE_CONT, "mouse8042_open:entered\n");
-#endif
-
 	mutex_enter(&state->ms_mutex);
 
 	if (state->ms_opened) {
@@ -545,15 +533,23 @@
 
 	state = (struct mouse_state *)q->q_ptr;
 
-#ifdef MOUSE8042_DEBUG
-	if (mouse8042_debug)
-		cmn_err(CE_CONT, "mouse8042_close:entered\n");
-#endif
-
 	mutex_enter(&state->ms_mutex);
 
 	qprocsoff(q);
 
+	if (state->reset_tid != 0) {
+		(void) quntimeout(q, state->reset_tid);
+		state->reset_tid = 0;
+	}
+	if (state->bc_id != 0) {
+		(void) qunbufcall(q, state->bc_id);
+		state->bc_id = 0;
+	}
+	if (state->reply_mp != NULL) {
+		freemsg(state->reply_mp);
+		state->reply_mp = NULL;
+	}
+
 	q->q_ptr = NULL;
 	WR(q)->q_ptr = NULL;
 	state->ms_rqp = NULL;
@@ -600,78 +596,267 @@
 	qreply(qp, mp);
 }
 
+static void
+mouse8042_reset_timeout(void *argp)
+{
+	struct mouse_state *state = (struct mouse_state *)argp;
+	mblk_t *mp;
+
+	mutex_enter(&state->reset_mutex);
+
+	/*
+	 * If the interrupt handler hasn't completed the reset handling
+	 * (reset_state would be IDLE or FAILED in that case), then
+	 * drop the 8042 lock, and send a faked retry reply upstream,
+	 * then enable the queue for further message processing.
+	 */
+	if (state->reset_state != MSE_RESET_IDLE &&
+	    state->reset_state != MSE_RESET_FAILED) {
+
+		state->reset_tid = 0;
+		state->reset_state = MSE_RESET_IDLE;
+
+		(void) ddi_get8(state->ms_handle, state->ms_addr +
+		    I8042_UNLOCK);
+
+		mp = state->reply_mp;
+		*mp->b_wptr++ = MSERESEND;
+		state->reply_mp = NULL;
+
+		if (state->ms_rqp != NULL)
+			putnext(state->ms_rqp, mp);
+		else
+			freemsg(mp);
+
+		ASSERT(state->ms_wqp != NULL);
+
+		enableok(state->ms_wqp);
+		qenable(state->ms_wqp);
+	}
+
+	mutex_exit(&state->reset_mutex);
+}
+
+/*
+ * Returns 1 if the caller should put the message (bp) back on the queue
+ */
 static int
-mouse8042_wput(queue_t *q, mblk_t *mp)
+mouse8042_process_reset(queue_t *q, mblk_t *mp, struct mouse_state *state)
 {
-	struct iocblk *iocbp;
+	mutex_enter(&state->reset_mutex);
+	/*
+	 * If we're in the middle of a reset, put the message back on the queue
+	 * for processing later.
+	 */
+	if (state->reset_state != MSE_RESET_IDLE) {
+		/*
+		 * We noenable the queue again here in case it was backenabled
+		 * by an upper-level module.
+		 */
+		noenable(q);
+
+		mutex_exit(&state->reset_mutex);
+		return (1);
+	}
+
+	/*
+	 * Drop the reset state lock before allocating the response message and
+	 * grabbing the 8042 exclusive-access lock (since those operations
+	 * may take an extended period of time to complete).
+	 */
+	mutex_exit(&state->reset_mutex);
+
+	state->reply_mp = allocb(3, BPRI_MED);
+	if (state->reply_mp == NULL) {
+		/*
+		 * Allocation failed -- set up a bufcall to enable the queue
+		 * whenever there is enough memory to allocate the response
+		 * message.
+		 */
+		state->bc_id = qbufcall(q, 3, BPRI_MED,
+		    (void (*)(void *))qenable, q);
+
+		if (state->bc_id == 0) {
+			/*
+			 * If the qbufcall failed, we cannot proceed, so use the
+			 * message we were sent to respond with an error.
+			 */
+			*mp->b_rptr = MSEERROR;
+			mp->b_wptr = mp->b_rptr + 1;
+			qreply(q, mp);
+			return (0);
+		}
+
+		return (1);
+	}
+
+	/*
+	 * Gain exclusive access to the 8042 for the duration of the reset.
+	 * The unlock will occur when the reset has either completed or timed
+	 * out.
+	 */
+	(void) ddi_get8(state->ms_handle,
+	    state->ms_addr + I8042_LOCK);
+
+	mutex_enter(&state->reset_mutex);
+
+	state->reset_state = MSE_RESET_PRE;
+	noenable(q);
+
+	state->reset_tid = qtimeout(q,
+	    mouse8042_reset_timeout,
+	    state,
+	    drv_usectohz(
+	    MOUSE8042_RESET_TIMEOUT_USECS));
+
+	ddi_put8(state->ms_handle,
+	    state->ms_addr +
+	    I8042_INT_OUTPUT_DATA, MSERESET);
+
+	mp->b_rptr++;
+
+	mutex_exit(&state->reset_mutex);
+	return (1);
+}
+
+/*
+ * Returns 1 if the caller should stop processing messages
+ */
+static int
+mouse8042_process_data_msg(queue_t *q, mblk_t *mp, struct mouse_state *state)
+{
 	mblk_t *bp;
 	mblk_t *next;
-	struct mouse_state *state;
+
+	bp = mp;
+	do {
+		while (bp->b_rptr < bp->b_wptr) {
+			/*
+			 * Detect an attempt to reset the mouse.  Lock out any
+			 * further mouse writes until the reset has completed.
+			 */
+			if (*bp->b_rptr == MSERESET) {
 
-	state = (struct mouse_state *)q->q_ptr;
+				/*
+				 * If we couldn't allocate memory and we
+				 * we couldn't register a bufcall,
+				 * mouse8042_process_reset returns 0 and
+				 * has already used the message to send an
+				 * error reply back upstream, so there is no
+				 * need to deallocate or put this message back
+				 * on the queue.
+				 */
+				if (mouse8042_process_reset(q, bp, state) == 0)
+					return (1);
 
-#ifdef MOUSE8042_DEBUG
-	if (mouse8042_debug)
-		cmn_err(CE_CONT, "mouse8042_wput:entered\n");
-#endif
+				/*
+				 * If there's no data remaining in this block,
+				 * free this block and put the following blocks
+				 * of this message back on the queue. If putting
+				 * the rest of the message back on the queue
+				 * fails, free the the message.
+				 */
+				if (MBLKL(bp) == 0) {
+					next = bp->b_cont;
+					freeb(bp);
+					bp = next;
+				}
+				if (bp != NULL) {
+					if (!putbq(q, bp))
+						freemsg(bp);
+				}
+
+				return (1);
+
+			}
+			ddi_put8(state->ms_handle,
+			    state->ms_addr + I8042_INT_OUTPUT_DATA,
+			    *bp->b_rptr++);
+		}
+		next = bp->b_cont;
+		freeb(bp);
+	} while ((bp = next) != NULL);
+
+	return (0);
+}
+
+static int
+mouse8042_process_msg(queue_t *q, mblk_t *mp, struct mouse_state *state)
+{
+	struct iocblk *iocbp;
+	int rv = 0;
+
 	iocbp = (struct iocblk *)mp->b_rptr;
+
 	switch (mp->b_datap->db_type) {
 	case M_FLUSH:
-#ifdef MOUSE8042_DEBUG
-		if (mouse8042_debug)
-			cmn_err(CE_CONT, "mouse8042_wput:M_FLUSH\n");
-#endif
-
-		if (*mp->b_rptr & FLUSHW)
+		if (*mp->b_rptr & FLUSHW) {
 			flushq(q, FLUSHDATA);
-		qreply(q, mp);
+			*mp->b_rptr &= ~FLUSHW;
+		}
+		if (*mp->b_rptr & FLUSHR) {
+			qreply(q, mp);
+		} else
+			freemsg(mp);
 		break;
 	case M_IOCTL:
-#ifdef MOUSE8042_DEBUG
-		if (mouse8042_debug)
-			cmn_err(CE_CONT, "mouse8042_wput:M_IOCTL\n");
-#endif
 		mouse8042_iocnack(q, mp, iocbp, EINVAL, 0);
 		break;
 	case M_IOCDATA:
-#ifdef MOUSE8042_DEBUG
-		if (mouse8042_debug)
-			cmn_err(CE_CONT, "mouse8042_wput:M_IOCDATA\n");
-#endif
 		mouse8042_iocnack(q, mp, iocbp, EINVAL, 0);
 		break;
 	case M_DATA:
-		bp = mp;
-		do {
-			while (bp->b_rptr < bp->b_wptr) {
-#if	defined(MOUSE8042_DEBUG)
-				if (mouse8042_debug) {
-					cmn_err(CE_CONT,
-					    "mouse8042:  send %2x\n",
-					    *bp->b_rptr);
-				}
-				if (mouse8042_debug_minimal) {
-					cmn_err(CE_CONT, ">a:%2x ",
-					    *bp->b_rptr);
-				}
-#endif
-				ddi_put8(state->ms_handle,
-				    state->ms_addr + I8042_INT_OUTPUT_DATA,
-				    *bp->b_rptr++);
-			}
-			next = bp->b_cont;
-			freeb(bp);
-		} while ((bp = next) != NULL);
+		rv = mouse8042_process_data_msg(q, mp, state);
 		break;
 	default:
 		freemsg(mp);
 		break;
 	}
-#ifdef MOUSE8042_DEBUG
-	if (mouse8042_debug)
-		cmn_err(CE_CONT, "mouse8042_wput:leaving\n");
-#endif
-	return (0);	/* ignored */
+
+	return (rv);
+}
+
+static int
+mouse8042_wsrv(queue_t *qp)
+{
+	mblk_t *mp;
+	struct mouse_state *state;
+	state = (struct mouse_state *)qp->q_ptr;
+
+	while ((mp = getq(qp)) != NULL) {
+		if (mouse8042_process_msg(qp, mp, state) != 0)
+			break;
+	}
+
+	return (0);
+}
+
+/*
+ * Returns the next reset state, given the current state and the byte
+ * received from the mouse.  Error and Resend codes are handled by the
+ * caller.
+ */
+static mouse8042_reset_state_e
+mouse8042_reset_fsm(mouse8042_reset_state_e reset_state, uint8_t mdata)
+{
+	switch (reset_state) {
+	case MSE_RESET_PRE:	/* RESET sent, now we expect an ACK */
+		if (mdata == MSE_ACK)	/* Got the ACK */
+			return (MSE_RESET_ACK);
+		break;
+
+	case MSE_RESET_ACK:	/* ACK received; now we expect 0xAA */
+		if (mdata == MSE_AA)	/* Got the 0xAA */
+			return (MSE_RESET_AA);
+		break;
+
+	case MSE_RESET_AA: 	/* 0xAA received; now we expect 0x00 */
+		if (mdata == MSE_00)
+			return (MSE_RESET_IDLE);
+		break;
+	}
+
+	return (reset_state);
 }
 
 static uint_t
@@ -684,10 +869,6 @@
 
 	mutex_enter(&state->ms_mutex);
 
-#if	defined(MOUSE8042_DEBUG)
-	if (mouse8042_debug)
-		cmn_err(CE_CONT, "mouse8042_intr()\n");
-#endif
 	rc = DDI_INTR_UNCLAIMED;
 
 	for (;;) {
@@ -700,24 +881,81 @@
 		mdata = ddi_get8(state->ms_handle,
 		    state->ms_addr + I8042_INT_INPUT_DATA);
 
-#if	defined(MOUSE8042_DEBUG)
-		if (mouse8042_debug)
-			cmn_err(CE_CONT, "mouse8042_intr:  got %2x\n", mdata);
-		if (mouse8042_debug_minimal)
-			cmn_err(CE_CONT, "<A:%2x ", mdata);
-#endif
+		rc = DDI_INTR_CLAIMED;
+
+		/*
+		 * If we're not ready for this data, discard it.
+		 */
+		if (!state->ready)
+			continue;
+
+		mutex_enter(&state->reset_mutex);
+		if (state->reset_state != MSE_RESET_IDLE) {
+
+			if (mdata == MSEERROR || mdata == MSERESET) {
+				state->reset_state = MSE_RESET_FAILED;
+			} else {
+				state->reset_state =
+				    mouse8042_reset_fsm(state->reset_state,
+				    mdata);
+			}
+
+			/*
+			 * If we transitioned back to the idle reset state (or
+			 * the reset failed), disable the timeout, release the
+			 * 8042 exclusive-access lock, then send the response
+			 * the the upper-level modules. Finally, enable the
+			 * queue and schedule queue service procedures so that
+			 * upper-level modules can process the response.
+			 * Otherwise, if we're still in the middle of the
+			 * reset sequence, do not send the data up (since the
+			 * response is sent at the end of the sequence, or
+			 * on timeout/error).
+			 */
+			if (state->reset_state == MSE_RESET_IDLE ||
+			    state->reset_state == MSE_RESET_FAILED) {
 
-		rc = DDI_INTR_CLAIMED;
+				mutex_exit(&state->reset_mutex);
+				(void) quntimeout(state->ms_wqp,
+				    state->reset_tid);
+				mutex_enter(&state->reset_mutex);
+
+				(void) ddi_get8(state->ms_handle,
+				    state->ms_addr + I8042_UNLOCK);
+
+				state->reset_tid = 0;
+				mp = state->reply_mp;
+				if (state->reset_state == MSE_RESET_FAILED) {
+					*mp->b_wptr++ = mdata;
+				} else {
+					*mp->b_wptr++ = MSE_ACK;
+					*mp->b_wptr++ = MSE_AA;
+					*mp->b_wptr++ = MSE_00;
+				}
+				state->reply_mp = NULL;
+
+				state->reset_state = MSE_RESET_IDLE;
+
+				if (state->ms_rqp != NULL)
+					putnext(state->ms_rqp, mp);
+				else
+					freemsg(mp);
+
+				enableok(state->ms_wqp);
+				qenable(state->ms_wqp);
+			}
+
+			mutex_exit(&state->reset_mutex);
+			mutex_exit(&state->ms_mutex);
+			return (rc);
+		}
+		mutex_exit(&state->reset_mutex);
 
 		if (state->ms_rqp != NULL && (mp = allocb(1, BPRI_MED))) {
 			*mp->b_wptr++ = mdata;
 			putnext(state->ms_rqp, mp);
 		}
 	}
-#ifdef MOUSE8042_DEBUG
-	if (mouse8042_debug)
-		cmn_err(CE_CONT, "mouse8042_intr() ok\n");
-#endif
 	mutex_exit(&state->ms_mutex);
 
 	return (rc);
--- a/usr/src/uts/common/io/rwn/rt2860.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/rwn/rt2860.c	Mon Jul 20 13:07:46 2009 -0400
@@ -79,10 +79,10 @@
 #include "fw-rt2860/rt2860.ucode"
 };
 
-static const struct ieee80211_rateset rt2560_rateset_11b =
+static const struct ieee80211_rateset rt2860_rateset_11b =
 	{ 4, { 2, 4, 11, 22 } };
 
-static const struct ieee80211_rateset rt2560_rateset_11g =
+static const struct ieee80211_rateset rt2860_rateset_11g =
 	{ 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
 
 static const struct {
@@ -224,7 +224,7 @@
 
 static struct modldrv rwn_modldrv = {
 	&mod_driverops,		/* Type of module.  This one is a driver */
-	"Ralink RT2700/2800 driver v1.1",	/* short description */
+	"Ralink RT2700/2800 driver v1.2",	/* short description */
 	&rwn_dev_ops		/* driver specific ops */
 };
 
@@ -1116,7 +1116,7 @@
 	m = allocb(msgdsize(mp) + 32, BPRI_MED);
 	if (m == NULL) {
 		RWN_DEBUG(RT2860_DBG_TX, "rwn: rt2860_send():"
-		    "rt2560_mgmt_send: can't alloc mblk.\n");
+		    "rt2860_mgmt_send: can't alloc mblk.\n");
 		err = DDI_FAILURE;
 		goto fail1;
 	}
@@ -1697,6 +1697,7 @@
 	sc->sc_tx_timer = 0;
 	mutex_exit(&sc->sc_txlock);
 }
+
 static void
 rt2860_rx_intr(struct rt2860_softc *sc)
 {
@@ -1769,7 +1770,7 @@
 		}
 
 		ant = rt2860_maxrssi_chain(sc, rxwi);
-		rssi = rxwi->rssi[ant];
+		rssi = RT2860_RSSI_OFFSET - rxwi->rssi[ant];
 		/* grab a reference to the source node */
 		ni = ieee80211_find_rxnode(ic, wh);
 
@@ -2886,6 +2887,9 @@
 	RWN_DEBUG(RT2860_DBG_MSG, "rwn: rt2860_attach(): "
 	    "PCI configuration is done successfully\n");
 
+	sc->amrr.amrr_min_success_threshold =  1;
+	sc->amrr.amrr_max_success_threshold = 15;
+
 	/* wait for NIC to initialize */
 	for (ntries = 0; ntries < 100; ntries++) {
 		sc->mac_rev = RT2860_READ(sc, RT2860_ASIC_VER_ID);
@@ -2958,8 +2962,8 @@
 	ic->ic_caps |= IEEE80211_C_WPA; /* Support WPA/WPA2 */
 
 	/* set supported .11b and .11g rates */
-	ic->ic_sup_rates[IEEE80211_MODE_11B] = rt2560_rateset_11b;
-	ic->ic_sup_rates[IEEE80211_MODE_11G] = rt2560_rateset_11g;
+	ic->ic_sup_rates[IEEE80211_MODE_11B] = rt2860_rateset_11b;
+	ic->ic_sup_rates[IEEE80211_MODE_11G] = rt2860_rateset_11g;
 
 	/* set supported .11b and .11g channels (1 through 14) */
 	for (i = 1; i <= 14; i++) {
@@ -2970,6 +2974,7 @@
 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
 	}
 
+	ic->ic_maxrssi = 63;
 	ic->ic_xmit = rt2860_send;
 
 	ieee80211_attach(ic);
@@ -3070,7 +3075,6 @@
 fail4:
 	while (--qid >= 0)
 		rt2860_free_tx_ring(sc, &sc->txq[qid]);
-
 fail3:
 	ddi_regs_map_free(&sc->sc_io_handle);
 fail2:
--- a/usr/src/uts/common/io/rwn/rt2860_var.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/rwn/rt2860_var.h	Mon Jul 20 13:07:46 2009 -0400
@@ -48,6 +48,8 @@
 
 #define	RT2860_MAX_SCATTER	((RT2860_TX_RING_COUNT * 2) - 1)
 
+#define	RT2860_RSSI_OFFSET	92
+
 /* HW supports up to 255 STAs */
 #define	RT2860_WCID_MAX		254
 #define	RT2860_AID2WCID(aid)	((aid) & 0xff)
--- a/usr/src/uts/common/io/sata/adapters/ahci/ahci.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/sata/adapters/ahci/ahci.c	Mon Jul 20 13:07:46 2009 -0400
@@ -345,9 +345,9 @@
  * End of global tunable variable definition
  */
 
+uint32_t ahci_debug_flags = (AHCIDBG_ERRS|AHCIDBG_TIMEOUT);
+
 #if AHCI_DEBUG
-uint32_t ahci_debug_flags = 0;
-
 /* The following is needed for ahci_log() */
 static kmutex_t ahci_log_mutex;
 static char ahci_log_buf[512];
@@ -439,7 +439,7 @@
 static int
 ahci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 {
-	ahci_ctl_t *ahci_ctlp;
+	ahci_ctl_t *ahci_ctlp = NULL;
 	int instance = ddi_get_instance(dip);
 	int status;
 	int attach_state;
@@ -453,7 +453,8 @@
 	int speed;
 #endif
 
-	AHCIDBG0(AHCIDBG_INIT|AHCIDBG_ENTRY, NULL, "ahci_attach enter");
+	AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "ahci_attach enter",
+	    NULL);
 
 	switch (cmd) {
 	case DDI_ATTACH:
@@ -486,9 +487,9 @@
 		 * suspend/resume.
 		 */
 		if (ahci_initialize_controller(ahci_ctlp) != AHCI_SUCCESS) {
-			AHCIDBG0(AHCIDBG_ERRS|AHCIDBG_PM, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS|AHCIDBG_PM, ahci_ctlp,
 			    "Failed to initialize the controller "
-			    "during DDI_RESUME");
+			    "during DDI_RESUME", NULL);
 			return (DDI_FAILURE);
 		}
 
@@ -559,7 +560,7 @@
 		goto err_out;
 	}
 
-	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "rnumber = %d", rnumber);
+	AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "rnumber = %d", rnumber);
 
 	status = ddi_regs_map_setup(dip,
 	    rnumber,
@@ -596,21 +597,21 @@
 	cap_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
 	    (uint32_t *)AHCI_GLOBAL_CAP(ahci_ctlp));
 
-	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "hba capabilites = 0x%x",
+	AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba capabilites = 0x%x",
 	    cap_status);
 
 #if AHCI_DEBUG
 	/* Get the interface speed supported by the HBA */
 	speed = (cap_status & AHCI_HBA_CAP_ISS) >> AHCI_HBA_CAP_ISS_SHIFT;
 	if (speed == 0x01) {
-		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-		    "hba interface speed support: Gen 1 (1.5Gbps)");
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+		    "hba interface speed support: Gen 1 (1.5Gbps)", NULL);
 	} else if (speed == 0x10) {
-		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-		    "hba interface speed support: Gen 2 (3 Gbps)");
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+		    "hba interface speed support: Gen 2 (3 Gbps)", NULL);
 	} else if (speed == 0x11) {
-		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-		    "hba interface speed support: Gen 3 (6 Gbps)");
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+		    "hba interface speed support: Gen 3 (6 Gbps)", NULL);
 	}
 #endif
 
@@ -619,7 +620,7 @@
 	    ((cap_status & AHCI_HBA_CAP_NCS) >>
 	    AHCI_HBA_CAP_NCS_SHIFT) + 1;
 
-	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "hba number of cmd slots: %d",
+	AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba number of cmd slots: %d",
 	    ahci_ctlp->ahcictl_num_cmd_slots);
 
 	/* Get the bit map which indicates ports implemented by the HBA */
@@ -627,7 +628,7 @@
 	    ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
 	    (uint32_t *)AHCI_GLOBAL_PI(ahci_ctlp));
 
-	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "hba implementation of ports: 0x%x",
+	AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba implementation of ports: 0x%x",
 	    ahci_ctlp->ahcictl_ports_implemented);
 
 	/*
@@ -642,7 +643,7 @@
 	    (cap_status & AHCI_HBA_CAP_NP) + 1,
 	    ddi_fls(ahci_ctlp->ahcictl_ports_implemented));
 
-	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "hba number of ports: %d",
+	AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba number of ports: %d",
 	    ahci_ctlp->ahcictl_num_ports);
 
 	/* Get the number of implemented ports by the HBA */
@@ -650,7 +651,7 @@
 	    ahci_get_num_implemented_ports(
 	    ahci_ctlp->ahcictl_ports_implemented);
 
-	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 	    "hba number of implemented ports: %d",
 	    ahci_ctlp->ahcictl_num_implemented_ports);
 
@@ -658,15 +659,15 @@
 	if (!(cap_status & AHCI_HBA_CAP_S64A)) {
 		ahci_ctlp->ahcictl_cap |= AHCI_CAP_BUF_32BIT_DMA;
 		ahci_ctlp->ahcictl_cap |= AHCI_CAP_COMMU_32BIT_DMA;
-		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-		    "hba does not support 64-bit addressing");
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+		    "hba does not support 64-bit addressing", NULL);
 	}
 
 	/* Checking for Support Command List Override */
 	if (cap_status & AHCI_HBA_CAP_SCLO) {
 		ahci_ctlp->ahcictl_cap |= AHCI_CAP_SCLO;
-		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-		    "hba supports command list override.");
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+		    "hba supports command list override.", NULL);
 	}
 
 	if (pci_config_setup(dip, &ahci_ctlp->ahcictl_pci_conf_handle)
@@ -705,7 +706,7 @@
 		goto err_out;
 	}
 
-	AHCIDBG1(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
 	    "ddi_intr_get_supported_types() returned: 0x%x",
 	    intr_types);
 
@@ -716,27 +717,27 @@
 		if (ahci_add_intrs(ahci_ctlp, DDI_INTR_TYPE_MSI) ==
 		    DDI_SUCCESS) {
 			ahci_ctlp->ahcictl_intr_type = DDI_INTR_TYPE_MSI;
-			AHCIDBG0(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
-			    "Using MSI interrupt type");
+			AHCIDBG(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
+			    "Using MSI interrupt type", NULL);
 			goto intr_done;
 		}
 
-		AHCIDBG0(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
 		    "MSI registration failed, "
-		    "trying FIXED interrupts");
+		    "trying FIXED interrupts", NULL);
 	}
 
 	if (intr_types & DDI_INTR_TYPE_FIXED) {
 		if (ahci_add_intrs(ahci_ctlp, DDI_INTR_TYPE_FIXED) ==
 		    DDI_SUCCESS) {
 			ahci_ctlp->ahcictl_intr_type = DDI_INTR_TYPE_FIXED;
-			AHCIDBG0(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
-			    "Using FIXED interrupt type");
+			AHCIDBG(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
+			    "Using FIXED interrupt type", NULL);
 			goto intr_done;
 		}
 
-		AHCIDBG0(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
-		    "FIXED interrupt registration failed");
+		AHCIDBG(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
+		    "FIXED interrupt registration failed", NULL);
 	}
 
 	cmn_err(CE_WARN, "!ahci%d: Interrupt registration failed", instance);
@@ -763,7 +764,7 @@
 	    (ahci_dma_prdt_number - AHCI_PRDT_NUMBER) *
 	    sizeof (ahci_prdt_item_t));
 
-	AHCIDBG2(AHCIDBG_INIT, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 	    "ahci_attach: ahci_dma_prdt_number set by user is 0x%x,"
 	    " ahci_cmd_table_size is 0x%x",
 	    ahci_dma_prdt_number, ahci_cmd_table_size);
@@ -830,7 +831,7 @@
 
 	ahci_ctlp->ahcictl_flags &= ~AHCI_ATTACH;
 
-	AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, "ahci_attach success!");
+	AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "ahci_attach success!", NULL);
 
 	return (DDI_SUCCESS);
 
@@ -886,7 +887,7 @@
 	instance = ddi_get_instance(dip);
 	ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
 
-	AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp, "ahci_detach enter");
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_detach enter", NULL);
 
 	switch (cmd) {
 	case DDI_DETACH:
@@ -1023,8 +1024,8 @@
 {
 	struct 	sata_hba_tran	*sata_hba_tran;
 
-	AHCIDBG0(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
-	    "ahci_register_sata_hba_tran enter");
+	AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
+	    "ahci_register_sata_hba_tran enter", NULL);
 
 	mutex_enter(&ahci_ctlp->ahcictl_mutex);
 
@@ -1046,8 +1047,8 @@
 	/* Get the data transfer capability for PIO command by the HBA */
 	if (cap_status & AHCI_HBA_CAP_PMD) {
 		ahci_ctlp->ahcictl_cap |= AHCI_CAP_PIO_MDRQ;
-		AHCIDBG0(AHCIDBG_INFO, ahci_ctlp, "HBA supports multiple "
-		    "DRQ block data transfer for PIO command protocol");
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "HBA supports multiple "
+		    "DRQ block data transfer for PIO command protocol", NULL);
 	}
 
 	/*
@@ -1069,8 +1070,8 @@
 	    !(ahci_ctlp->ahcictl_cap & AHCI_CAP_NO_MCMDLIST_NONQUEUE)) {
 		sata_hba_tran->sata_tran_hba_features_support |= SATA_CTLF_NCQ;
 		ahci_ctlp->ahcictl_cap |= AHCI_CAP_NCQ;
-		AHCIDBG0(AHCIDBG_INFO, ahci_ctlp, "HBA supports Native "
-		    "Command Queuing");
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "HBA supports Native "
+		    "Command Queuing", NULL);
 	}
 
 	/* Report the number of command slots */
@@ -1114,8 +1115,8 @@
 static int
 ahci_unregister_sata_hba_tran(ahci_ctl_t *ahci_ctlp)
 {
-	AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp,
-	    "ahci_unregister_sata_hba_tran enter");
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
+	    "ahci_unregister_sata_hba_tran enter", NULL);
 
 	/* Detach from the SATA framework. */
 	if (sata_hba_detach(ahci_ctlp->ahcictl_dip, DDI_DETACH) !=
@@ -1150,10 +1151,8 @@
 	ahci_ctl_t *ahci_ctlp;
 	ahci_port_t *ahci_portp;
 	uint8_t	cport = sd->satadev_addr.cport;
-#if AHCI_DEBUG
 	uint8_t pmport = sd->satadev_addr.pmport;
 	uint8_t qual = sd->satadev_addr.qual;
-#endif
 	uint8_t	device_type;
 	uint32_t port_state;
 	uint8_t port;
@@ -1161,7 +1160,7 @@
 	ahci_ctlp = ddi_get_soft_state(ahci_statep, ddi_get_instance(dip));
 	port = ahci_ctlp->ahcictl_cport_to_port[cport];
 
-	AHCIDBG3(AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_tran_probe_port enter: cport: %d, "
 	    "pmport: %d, qual: %d", cport, pmport, qual);
 
@@ -1174,31 +1173,31 @@
 
 	case SATA_PSTATE_FAILED:
 		sd->satadev_state = SATA_PSTATE_FAILED;
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_tran_probe_port: port %d PORT FAILED", port);
 		goto out;
 
 	case SATA_PSTATE_SHUTDOWN:
 		sd->satadev_state = SATA_PSTATE_SHUTDOWN;
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_tran_probe_port: port %d PORT SHUTDOWN", port);
 		goto out;
 
 	case SATA_PSTATE_PWROFF:
 		sd->satadev_state = SATA_PSTATE_PWROFF;
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_tran_probe_port: port %d PORT PWROFF", port);
 		goto out;
 
 	case SATA_PSTATE_PWRON:
 		sd->satadev_state = SATA_PSTATE_PWRON;
-		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 		    "ahci_tran_probe_port: port %d PORT PWRON", port);
 		break;
 
 	default:
 		sd->satadev_state = port_state;
-		AHCIDBG2(AHCIDBG_INFO, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 		    "ahci_tran_probe_port: port %d PORT NORMAL %x",
 		    port, port_state);
 		break;
@@ -1210,7 +1209,7 @@
 
 	case SATA_DTYPE_ATADISK:
 		sd->satadev_type = SATA_DTYPE_ATADISK;
-		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 		    "ahci_tran_probe_port: port %d DISK found", port);
 		break;
 
@@ -1222,27 +1221,27 @@
 		 * DEVICE data
 		 */
 		sd->satadev_type = SATA_DTYPE_ATAPI;
-		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 		    "ahci_tran_probe_port: port %d ATAPI found", port);
 		break;
 
 	case SATA_DTYPE_PMULT:
 		sd->satadev_type = SATA_DTYPE_PMULT;
-		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 		    "ahci_tran_probe_port: port %d Port Multiplier found",
 		    port);
 		break;
 
 	case SATA_DTYPE_UNKNOWN:
 		sd->satadev_type = SATA_DTYPE_UNKNOWN;
-		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 		    "ahci_tran_probe_port: port %d Unknown device found", port);
 		break;
 
 	default:
 		/* we don't support any other device types */
 		sd->satadev_type = SATA_DTYPE_NONE;
-		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 		    "ahci_tran_probe_port: port %d No device found", port);
 		break;
 	}
@@ -1294,7 +1293,7 @@
 	ahci_ctlp = ddi_get_soft_state(ahci_statep, ddi_get_instance(dip));
 	port = ahci_ctlp->ahcictl_cport_to_port[cport];
 
-	AHCIDBG2(AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_tran_start enter: cport %d satapkt 0x%p",
 	    cport, (void *)spkt);
 
@@ -1315,7 +1314,7 @@
 		    ahci_portp->ahciport_port_state;
 		ahci_update_sata_registers(ahci_ctlp, port,
 		    &spkt->satapkt_device);
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_tran_start returning PORT_ERROR while "
 		    "port in FAILED/SHUTDOWN/PWROFF state: "
 		    "port: %d", port);
@@ -1334,7 +1333,7 @@
 		    ahci_portp->ahciport_port_state;
 		ahci_update_sata_registers(ahci_ctlp, port,
 		    &spkt->satapkt_device);
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_tran_start returning PORT_ERROR while "
 		    "no device attached: port: %d", port);
 		mutex_exit(&ahci_portp->ahciport_mutex);
@@ -1354,7 +1353,7 @@
 	 */
 	if (spkt->satapkt_cmd.satacmd_flags.sata_clear_dev_reset) {
 		ahci_portp->ahciport_reset_in_progress = 0;
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_tran_start clearing the "
 		    "reset_in_progress for port: %d", port);
 	}
@@ -1363,7 +1362,7 @@
 	    ! spkt->satapkt_cmd.satacmd_flags.sata_ignore_dev_reset &&
 	    ! ddi_in_panic()) {
 		spkt->satapkt_reason = SATA_PKT_BUSY;
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_tran_start returning BUSY while "
 		    "reset in progress: port: %d", port);
 		mutex_exit(&ahci_portp->ahciport_mutex);
@@ -1372,7 +1371,7 @@
 
 	if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
 		spkt->satapkt_reason = SATA_PKT_BUSY;
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_tran_start returning BUSY while "
 		    "mopping in progress: port: %d", port);
 		mutex_exit(&ahci_portp->ahciport_mutex);
@@ -1388,7 +1387,7 @@
 		if (!(spkt->satapkt_op_mode & SATA_OPMODE_POLLING) &&
 		    servicing_interrupt()) {
 			spkt->satapkt_reason = SATA_PKT_BUSY;
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 			    "ahci_tran_start returning BUSY while "
 			    "sending SYNC mode under interrupt context: "
 			    "port : %d", port);
@@ -1399,7 +1398,7 @@
 		/* We need to do the sync start now */
 		if (ahci_do_sync_start(ahci_ctlp, ahci_portp, port,
 		    spkt) == AHCI_FAILURE) {
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start "
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start "
 			    "return QUEUE_FULL: port %d", port);
 			mutex_exit(&ahci_portp->ahciport_mutex);
 			return (SATA_TRAN_QUEUE_FULL);
@@ -1409,14 +1408,14 @@
 		if (ahci_deliver_satapkt(ahci_ctlp, ahci_portp, port, spkt)
 		    == AHCI_FAILURE) {
 			spkt->satapkt_reason = SATA_PKT_QUEUE_FULL;
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start "
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start "
 			    "returning QUEUE_FULL: port %d", port);
 			mutex_exit(&ahci_portp->ahciport_mutex);
 			return (SATA_TRAN_QUEUE_FULL);
 		}
 	}
 
-	AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, "ahci_tran_start "
+	AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_tran_start "
 	    "sata tran accepted: port %d", port);
 
 	mutex_exit(&ahci_portp->ahciport_mutex);
@@ -1441,7 +1440,7 @@
 	int rval;
 	int instance = ddi_get_instance(ahci_ctlp->ahcictl_dip);
 
-	AHCIDBG2(AHCIDBG_ENTRY, ahci_ctlp, "ahci_do_sync_start enter: "
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_do_sync_start enter: "
 	    "port %d spkt 0x%p", port, spkt);
 
 	if (spkt->satapkt_op_mode & SATA_OPMODE_POLLING) {
@@ -1549,7 +1548,7 @@
 	uint32_t free_slots;
 	int slot;
 
-	AHCIDBG2(AHCIDBG_ENTRY, ahci_ctlp, "ahci_claim_free_slot enter "
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_claim_free_slot enter "
 	    "ahciport_pending_tags = 0x%x "
 	    "ahciport_pending_ncq_tags = 0x%x",
 	    ahci_portp->ahciport_pending_tags,
@@ -1563,18 +1562,19 @@
 	if (command_type == AHCI_NON_NCQ_CMD) {
 		/* Non-NCQ command request */
 		if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
-			AHCIDBG0(AHCIDBG_INFO|AHCIDBG_NCQ, ahci_ctlp,
+			AHCIDBG(AHCIDBG_INFO|AHCIDBG_NCQ, ahci_ctlp,
 			    "ahci_claim_free_slot: there is still pending "
 			    "queued command(s) in the command list, "
 			    "so no available slot for the non-queued "
-			    "command");
+			    "command", NULL);
 			return (AHCI_FAILURE);
 		}
 		if ((ahci_ctlp->ahcictl_cap & AHCI_CAP_NO_MCMDLIST_NONQUEUE) &&
 		    NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
-			AHCIDBG0(AHCIDBG_INFO, ahci_ctlp,
+			AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 			    "ahci_claim_free_slot: HBA cannot support multiple-"
-			    "use of the command list for non-queued commands");
+			    "use of the command list for non-queued commands",
+			    NULL);
 			return (AHCI_FAILURE);
 		}
 		free_slots = (~ahci_portp->ahciport_pending_tags) &
@@ -1582,27 +1582,28 @@
 	} else if (command_type == AHCI_NCQ_CMD) {
 		/* NCQ command request */
 		if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
-			AHCIDBG0(AHCIDBG_INFO|AHCIDBG_NCQ, ahci_ctlp,
+			AHCIDBG(AHCIDBG_INFO|AHCIDBG_NCQ, ahci_ctlp,
 			    "ahci_claim_free_slot: there is still pending "
 			    "non-queued command(s) in the command list, "
-			    "so no available slot for the queued command");
+			    "so no available slot for the queued command",
+			    NULL);
 			return (AHCI_FAILURE);
 		}
 		free_slots = (~ahci_portp->ahciport_pending_ncq_tags) &
 		    AHCI_NCQ_SLOT_MASK(ahci_portp);
 	} else if (command_type == AHCI_ERR_RETRI_CMD) {
 		/* Error retrieval command request */
-		AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_claim_free_slot: slot 0 is allocated for REQUEST "
-		    "SENSE or READ LOG EXT command");
+		    "SENSE or READ LOG EXT command", NULL);
 		slot = 0;
 		goto out;
 	}
 
 	slot = ddi_ffs(free_slots) - 1;
 	if (slot == -1) {
-		AHCIDBG0(AHCIDBG_VERBOSE, ahci_ctlp,
-		    "ahci_claim_free_slot: no empty slots");
+		AHCIDBG(AHCIDBG_VERBOSE, ahci_ctlp,
+		    "ahci_claim_free_slot: no empty slots", NULL);
 		return (AHCI_FAILURE);
 	}
 
@@ -1620,7 +1621,7 @@
 	ahci_portp->ahciport_pending_tags |= (0x1 << slot);
 
 out:
-	AHCIDBG1(AHCIDBG_VERBOSE, ahci_ctlp,
+	AHCIDBG(AHCIDBG_VERBOSE, ahci_ctlp,
 	    "ahci_claim_free_slot: found slot: 0x%x", slot);
 
 	return (slot);
@@ -1680,7 +1681,7 @@
 		 */
 		if (ahci_portp->ahciport_max_ncq_tags == 0) {
 			ahci_portp->ahciport_max_ncq_tags = ncq_qdepth;
-			AHCIDBG2(AHCIDBG_NCQ, ahci_ctlp,
+			AHCIDBG(AHCIDBG_NCQ, ahci_ctlp,
 			    "ahci_deliver_satapkt: port %d the max tags for "
 			    "NCQ command is %d", port, ncq_qdepth);
 		} else {
@@ -1705,11 +1706,11 @@
 	/* Check if there is an empty command slot */
 	cmd_slot = ahci_claim_free_slot(ahci_ctlp, ahci_portp, command_type);
 	if (cmd_slot == AHCI_FAILURE) {
-		AHCIDBG0(AHCIDBG_INFO, ahci_ctlp, "no free command slot");
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "no free command slot", NULL);
 		return (AHCI_FAILURE);
 	}
 
-	AHCIDBG4(AHCIDBG_ENTRY|AHCIDBG_INFO, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INFO, ahci_ctlp,
 	    "ahci_deliver_satapkt enter: cmd_reg: 0x%x, cmd_slot: 0x%x, "
 	    "port: %d, satapkt: 0x%p", scmd->satacmd_cmd_reg,
 	    cmd_slot, port, (void *)spkt);
@@ -1818,7 +1819,7 @@
 	}
 
 	ncookies = scmd->satacmd_num_dma_cookies;
-	AHCIDBG2(AHCIDBG_PRDT, ahci_ctlp,
+	AHCIDBG(AHCIDBG_PRDT, ahci_ctlp,
 	    "ncookies = 0x%x, ahci_dma_prdt_number = 0x%x",
 	    ncookies, ahci_dma_prdt_number);
 
@@ -1837,7 +1838,7 @@
 		    scmd->satacmd_dma_cookie_list[i].dmac_size;
 	}
 
-	AHCIDBG2(AHCIDBG_PRDT, ahci_ctlp,
+	AHCIDBG(AHCIDBG_PRDT, ahci_ctlp,
 	    "ahciport_prd_bytecounts 0x%x for cmd_slot 0x%x",
 	    ahci_portp->ahciport_prd_bytecounts[cmd_slot], cmd_slot);
 
@@ -1858,7 +1859,7 @@
 	/* Set the length of the command in the CFIS area */
 	SET_COMMAND_FIS_LENGTH(cmd_header, AHCI_H2D_REGISTER_FIS_LENGTH);
 
-	AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, "command data direction is "
+	AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "command data direction is "
 	    "sata_data_direction = 0x%x",
 	    scmd->satacmd_flags.sata_data_direction);
 
@@ -1957,7 +1958,7 @@
 	    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port),
 	    (0x1 << cmd_slot));
 
-	AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, "ahci_deliver_satapkt "
+	AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_deliver_satapkt "
 	    "exit: port %d", port);
 
 	return (cmd_slot);
@@ -1984,7 +1985,7 @@
 	ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
 	port = ahci_ctlp->ahcictl_cport_to_port[cport];
 
-	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_tran_abort enter: port %d", port);
 
 	ahci_portp = ahci_ctlp->ahcictl_ports[port];
@@ -1995,7 +1996,7 @@
 	 * commands are being mopped, therefore there is nothing else to do
 	 */
 	if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
-		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 		    "ahci_tran_abort: port %d is in "
 		    "mopping process, so just return directly ", port);
 		mutex_exit(&ahci_portp->ahciport_mutex);
@@ -2015,7 +2016,7 @@
 		    ahci_portp->ahciport_port_state;
 		ahci_update_sata_registers(ahci_ctlp, port,
 		    &spkt->satapkt_device);
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_tran_abort returning SATA_FAILURE while "
 		    "port in FAILED/SHUTDOWN/PWROFF state: "
 		    "port: %d", port);
@@ -2034,7 +2035,7 @@
 		    ahci_portp->ahciport_port_state;
 		ahci_update_sata_registers(ahci_ctlp, port,
 		    &spkt->satapkt_device);
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_tran_abort returning SATA_FAILURE while "
 		    "no device attached: port: %d", port);
 		mutex_exit(&ahci_portp->ahciport_mutex);
@@ -2065,7 +2066,7 @@
 
 		if (aborted_tags == 0xffffffff) {
 			/* request packet is not on the pending list */
-			AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
+			AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 			    "Cannot find the aborting pkt 0x%p on the "
 			    "pending list", (void *)spkt);
 			ahci_update_sata_registers(ahci_ctlp, port,
@@ -2146,7 +2147,7 @@
 	sata_device_t sdevice;
 	int ret;
 
-	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_reset_device_reject_pkts on port: %d", port);
 
 	/*
@@ -2154,7 +2155,7 @@
 	 * commands are being mopped, therefore there is nothing else to do
 	 */
 	if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_reset_device_reject_pkts: port %d is in "
 		    "mopping process, so return directly ", port);
 		return (SATA_SUCCESS);
@@ -2172,12 +2173,12 @@
 
 	if (ahci_software_reset(ahci_ctlp, ahci_portp, port)
 	    != AHCI_SUCCESS) {
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "Try to do a port reset after software "
 		    "reset failed", port);
 		ret = ahci_port_reset(ahci_ctlp, ahci_portp, port);
 		if (ret != AHCI_SUCCESS) {
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 			    "ahci_reset_device_reject_pkts: port %d "
 			    "failed", port);
 			return (SATA_FAILURE);
@@ -2204,7 +2205,7 @@
 	    SATA_EVNT_DEVICE_RESET);
 	mutex_enter(&ahci_portp->ahciport_mutex);
 
-	AHCIDBG1(AHCIDBG_EVENT, ahci_ctlp,
+	AHCIDBG(AHCIDBG_EVENT, ahci_ctlp,
 	    "port %d sending event up: SATA_EVNT_RESET", port);
 
 	/* Next try to mop the pending commands */
@@ -2242,7 +2243,7 @@
 	uint32_t reset_tags = 0;
 	uint32_t finished_tags = 0;
 
-	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_reset_port_reject_pkts on port: %d", port);
 
 	/*
@@ -2250,7 +2251,7 @@
 	 * commands are being mopped, therefore there is nothing else to do
 	 */
 	if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_reset_port_reject_pkts: port %d is in "
 		    "mopping process, so return directly ", port);
 		return (SATA_SUCCESS);
@@ -2308,8 +2309,8 @@
 	uint8_t port;
 	int ret = SATA_SUCCESS;
 
-	AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp,
-	    "ahci_reset_hba_reject_pkts enter");
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
+	    "ahci_reset_hba_reject_pkts enter", NULL);
 
 	for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
 		if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
@@ -2353,7 +2354,7 @@
 		 * check AHCI_PORT_FLAG_MOPPING flag.
 		 */
 		if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 			    "ahci_reset_hba_reject_pkts: port %d is in "
 			    "mopping process, so return directly ", port);
 			mutex_exit(&ahci_portp->ahciport_mutex);
@@ -2403,7 +2404,7 @@
 	ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
 	port = ahci_ctlp->ahcictl_cport_to_port[cport];
 
-	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_tran_reset_port enter: cport: %d", cport);
 
 	switch (sd->satadev_addr.qual) {
@@ -2436,7 +2437,7 @@
 			 */
 			sd->satadev_state = ahci_portp->ahciport_port_state;
 			ahci_update_sata_registers(ahci_ctlp, port, sd);
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 			    "ahci_tran_reset_dport returning SATA_FAILURE "
 			    "while port in FAILED/SHUTDOWN/PWROFF state: "
 			    "port: %d", port);
@@ -2453,7 +2454,7 @@
 			sd->satadev_type = SATA_DTYPE_NONE;
 			sd->satadev_state = ahci_portp->ahciport_port_state;
 			ahci_update_sata_registers(ahci_ctlp, port, sd);
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 			    "ahci_tran_reset_dport returning SATA_FAILURE "
 			    "while no device attached: port: %d", port);
 			mutex_exit(&ahci_portp->ahciport_mutex);
@@ -2475,9 +2476,9 @@
 
 	case SATA_ADDR_PMPORT:
 	case SATA_ADDR_DPMPORT:
-		AHCIDBG0(AHCIDBG_INFO, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 		    "ahci_tran_reset_dport: port multiplier will be "
-		    "supported later");
+		    "supported later", NULL);
 		/* FALLTHRU */
 	default:
 		ret = SATA_FAILURE;
@@ -2503,7 +2504,7 @@
 	ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
 	port = ahci_ctlp->ahcictl_cport_to_port[cport];
 
-	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_tran_hotplug_port_activate cport %d enter", cport);
 
 	ahci_portp = ahci_ctlp->ahcictl_ports[port];
@@ -2557,7 +2558,7 @@
 	ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
 	port = ahci_ctlp->ahcictl_cport_to_port[cport];
 
-	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_tran_hotplug_port_deactivate cport %d enter", cport);
 
 	ahci_portp = ahci_ctlp->ahcictl_ports[port];
@@ -2610,7 +2611,7 @@
 	uint32_t slot_status = 0;
 	uint32_t abort_tags = 0;
 
-	AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp,
 	    "ahci_reject_all_abort_pkts on port: %d", port);
 
 	/*
@@ -2625,7 +2626,7 @@
 			abort_tags = 0x1;
 			goto out;
 		} else {
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 			    "ahci_reject_all_abort_pkts return directly "
 			    "port %d no needs to reject any outstanding "
 			    "commands", port);
@@ -2675,15 +2676,15 @@
 {
 	int port, cport = 0;
 
-	AHCIDBG0(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
-	    "ahci_alloc_ports_state enter");
+	AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
+	    "ahci_alloc_ports_state enter", NULL);
 
 	mutex_enter(&ahci_ctlp->ahcictl_mutex);
 
 	/* Allocate structures only for the implemented ports */
 	for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
 		if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
-			AHCIDBG1(AHCIDBG_INIT, ahci_ctlp,
+			AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 			    "hba port %d not implemented", port);
 			continue;
 		}
@@ -2769,8 +2770,8 @@
 	uint32_t ghc_control;
 	int port;
 
-	AHCIDBG0(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
-	    "ahci_initialize_controller enter");
+	AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
+	    "ahci_initialize_controller enter", NULL);
 
 	mutex_enter(&ahci_ctlp->ahcictl_mutex);
 
@@ -2803,7 +2804,7 @@
 		 */
 		if (ahci_initialize_port(ahci_ctlp, ahci_portp, port)
 		    != AHCI_SUCCESS) {
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 			    "ahci_initialize_controller: failed to "
 			    "initialize port %d", port);
 			/*
@@ -2835,8 +2836,8 @@
 	ahci_port_t *ahci_portp;
 	int port;
 
-	AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-	    "ahci_uninitialize_controller enter");
+	AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+	    "ahci_uninitialize_controller enter", NULL);
 
 	/* disable all the interrupts. */
 	mutex_enter(&ahci_ctlp->ahcictl_mutex);
@@ -2884,7 +2885,7 @@
 	port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
 	    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
 
-	AHCIDBG2(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_initialize_port: port %d "
 	    "port_cmd_status = 0x%x", port, port_cmd_status);
 	/*
@@ -2924,7 +2925,7 @@
 
 		/* Does port reset succeed on HBA port? */
 		if (ret != AHCI_SUCCESS) {
-			AHCIDBG1(AHCIDBG_INIT|AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_INIT|AHCIDBG_ERRS, ahci_ctlp,
 			    "ahci_initialize_port:"
 			    "port reset faild at port %d", port);
 			return (AHCI_FAILURE);
@@ -2932,7 +2933,7 @@
 
 		/* Is port failed? */
 		if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED) {
-			AHCIDBG2(AHCIDBG_INIT|AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_INIT|AHCIDBG_ERRS, ahci_ctlp,
 			    "ahci_initialize_port: port %d state 0x%x",
 			    port, ahci_portp->ahciport_port_state);
 			return (AHCI_FAILURE);
@@ -2941,7 +2942,7 @@
 
 	ahci_portp->ahciport_port_state = SATA_STATE_READY;
 
-	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "port %d is ready now.", port);
+	AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "port %d is ready now.", port);
 
 	/*
 	 * At the time being, only probe ports/devices and get the types of
@@ -2963,12 +2964,12 @@
 		 * and PxFBU registers in case these registers were cleared
 		 * during the suspend.
 		 */
-		AHCIDBG1(AHCIDBG_PM, ahci_ctlp,
+		AHCIDBG(AHCIDBG_PM, ahci_ctlp,
 		    "ahci_initialize_port: port %d "
 		    "reset the port during resume", port);
 		(void) ahci_port_reset(ahci_ctlp, ahci_portp, port);
 
-		AHCIDBG1(AHCIDBG_PM, ahci_ctlp,
+		AHCIDBG(AHCIDBG_PM, ahci_ctlp,
 		    "ahci_initialize_port: port %d "
 		    "set PxCLB, PxCLBU, PxFB and PxFBU "
 		    "during resume", port);
@@ -2986,7 +2987,7 @@
 
 	/* Return directly if no device connected */
 	if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
-		AHCIDBG1(AHCIDBG_INIT, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 		    "No device connected to port %d", port);
 		goto out;
 	}
@@ -2994,7 +2995,7 @@
 	/* Try to start the port */
 	if (ahci_start_port(ahci_ctlp, ahci_portp, port)
 	    != AHCI_SUCCESS) {
-		AHCIDBG1(AHCIDBG_INIT, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 		    "failed to start port %d", port);
 		return (AHCI_FAILURE);
 	}
@@ -3039,18 +3040,18 @@
 	if (venid == VIA_VENID) {
 		revision = pci_config_get8(ahci_ctlp->ahcictl_pci_conf_handle,
 		    PCI_CONF_REVID);
-		AHCIDBG1(AHCIDBG_INIT, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 		    "revision id = 0x%x", revision);
 		if (revision == 0x00) {
 			ahci_ctlp->ahcictl_buffer_dma_attr.dma_attr_align = 0x4;
-			AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-			    "change ddi_attr_align to 0x4");
+			AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+			    "change ddi_attr_align to 0x4", NULL);
 		}
 
 		ahci_ctlp->ahcictl_cap = AHCI_CAP_NO_MCMDLIST_NONQUEUE;
-		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 		    "VT8251 cannot use multiple command lists for "
-		    "non-queued commands");
+		    "non-queued commands", NULL);
 	}
 
 	/*
@@ -3059,10 +3060,10 @@
 	 * though S64A bit of CAP register declares the support.
 	 */
 	if (venid == 0x1002 && devid == 0x4380) {
-		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 		    "ATI SB600 cannot do 64-bit DMA for both data buffer "
 		    "and communication memory descriptors though CAP indicates "
-		    "support, so force it to use 32-bit DMA");
+		    "support, so force it to use 32-bit DMA", NULL);
 		ahci_ctlp->ahcictl_cap |= AHCI_CAP_BUF_32BIT_DMA;
 		ahci_ctlp->ahcictl_cap |= AHCI_CAP_COMMU_32BIT_DMA;
 	}
@@ -3074,10 +3075,10 @@
 	 * 64-bit DMA for data buffer.
 	 */
 	if (venid == 0x1002 && devid == 0x4391) {
-		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 		    "ATI SB700/750 cannot do 64-bit DMA for communication "
 		    "memory descriptors though CAP indicates support, "
-		    "so force it to use 32-bit DMA");
+		    "so force it to use 32-bit DMA", NULL);
 		ahci_ctlp->ahcictl_cap |= AHCI_CAP_COMMU_32BIT_DMA;
 	}
 
@@ -3087,9 +3088,9 @@
 	 * on most Nvidia boards) is fixed.
 	 */
 	if (venid == 0x10de && devid == 0x0ad4) {
-		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 		    "Force nVidia MCP78 AHCI controller to use "
-		    "fixed interrupts");
+		    "fixed interrupts", NULL);
 		ahci_msi_enabled = B_FALSE;
 	}
 
@@ -3116,12 +3117,12 @@
 		 * capabilities and that the pointer is in a valid range.
 		 */
 		if (++cap_count > PCI_CAP_MAX_PTR) {
-			AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp,
-			    "too many device capabilities");
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
+			    "too many device capabilities", NULL);
 			return (AHCI_FAILURE);
 		}
 		if (caps_ptr < PCI_CAP_PTR_OFF) {
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 			    "capabilities pointer 0x%x out of range",
 			    caps_ptr);
 			return (AHCI_FAILURE);
@@ -3149,13 +3150,13 @@
 			pmcsr = pci_config_get16(
 			    ahci_ctlp->ahcictl_pci_conf_handle,
 			    ahci_ctlp->ahcictl_pmcsr_offset);
-			AHCIDBG2(AHCIDBG_PM, ahci_ctlp,
+			AHCIDBG(AHCIDBG_PM, ahci_ctlp,
 			    "Power Management capability found PCI_PMCAP "
 			    "= 0x%x PCI_PMCSR = 0x%x", pmcap, pmcsr);
 			if ((pmcap & 0x3) == 0x3)
-				AHCIDBG0(AHCIDBG_PM, ahci_ctlp,
+				AHCIDBG(AHCIDBG_PM, ahci_ctlp,
 				    "PCI Power Management Interface "
-				    "spec 1.2 compliant");
+				    "spec 1.2 compliant", NULL);
 #endif
 			break;
 
@@ -3164,41 +3165,41 @@
 			msimc = pci_config_get16(
 			    ahci_ctlp->ahcictl_pci_conf_handle,
 			    caps_ptr + PCI_MSI_CTRL);
-			AHCIDBG1(AHCIDBG_MSI, ahci_ctlp,
+			AHCIDBG(AHCIDBG_MSI, ahci_ctlp,
 			    "Message Signaled Interrupt capability found "
 			    "MSICAP_MC.MMC = 0x%x", (msimc & 0xe) >> 1);
 #endif
-			AHCIDBG0(AHCIDBG_MSI, ahci_ctlp,
-			    "MSI capability found");
+			AHCIDBG(AHCIDBG_MSI, ahci_ctlp,
+			    "MSI capability found", NULL);
 			break;
 
 		case PCI_CAP_ID_PCIX:
-			AHCIDBG0(AHCIDBG_PM, ahci_ctlp,
-			    "PCI-X capability found");
+			AHCIDBG(AHCIDBG_PM, ahci_ctlp,
+			    "PCI-X capability found", NULL);
 			break;
 
 		case PCI_CAP_ID_PCI_E:
-			AHCIDBG0(AHCIDBG_PM, ahci_ctlp,
-			    "PCI Express capability found");
+			AHCIDBG(AHCIDBG_PM, ahci_ctlp,
+			    "PCI Express capability found", NULL);
 			break;
 
 		case PCI_CAP_ID_MSI_X:
-			AHCIDBG0(AHCIDBG_PM, ahci_ctlp,
-			    "MSI-X capability found");
+			AHCIDBG(AHCIDBG_PM, ahci_ctlp,
+			    "MSI-X capability found", NULL);
 			break;
 
 		case PCI_CAP_ID_SATA:
-			AHCIDBG0(AHCIDBG_PM, ahci_ctlp,
-			    "SATA capability found");
+			AHCIDBG(AHCIDBG_PM, ahci_ctlp,
+			    "SATA capability found", NULL);
 			break;
 
 		case PCI_CAP_ID_VS:
-			AHCIDBG0(AHCIDBG_PM, ahci_ctlp,
-			    "Vendor Specific capability found");
+			AHCIDBG(AHCIDBG_PM, ahci_ctlp,
+			    "Vendor Specific capability found", NULL);
 			break;
 
 		default:
-			AHCIDBG1(AHCIDBG_PM, ahci_ctlp,
+			AHCIDBG(AHCIDBG_PM, ahci_ctlp,
 			    "unrecognized capability 0x%x", cap);
 			break;
 		}
@@ -3239,13 +3240,13 @@
 	int slot, loop_count;
 	int rval = AHCI_FAILURE;
 
-	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
 	    "Port %d device resetting", port);
 
 	/* First clear PxCMD.ST (AHCI v1.2 10.4.1) */
 	if (ahci_put_port_into_notrunning_state(ahci_ctlp, ahci_portp,
 	    port) != AHCI_SUCCESS) {
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_software_reset: cannot stop HBA port %d.", port);
 		goto out;
 	}
@@ -3257,7 +3258,7 @@
 	if (port_task_file & AHCI_TFD_STS_BSY ||
 	    port_task_file & AHCI_TFD_STS_DRQ) {
 		if (!(ahci_ctlp->ahcictl_cap & AHCI_CAP_SCLO)) {
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 			    "PxTFD.STS.BSY/DRQ is set (PxTFD=0x%x), "
 			    "cannot issue a software reset.", port_task_file);
 			goto out;
@@ -3268,8 +3269,8 @@
 		 * set), PxCMD.CLO bit should be set before set PxCMD.ST, in
 		 * order to clear PxTFD.STS.BSY and PxTFD.STS.DRQ.
 		 */
-		AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp,
-		    "PxTFD.STS.BSY/DRQ is set, try SCLO.")
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
+		    "PxTFD.STS.BSY/DRQ is set, try SCLO.", NULL)
 
 		port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
 		    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
@@ -3285,7 +3286,7 @@
 
 			/* We are effectively timing out after 1 sec. */
 			if (loop_count++ > 100) {
-				AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+				AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 				    "SCLO time out. port %d is busy.", port);
 				goto out;
 			}
@@ -3300,7 +3301,7 @@
 		    (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port));
 		if (port_task_file & AHCI_TFD_STS_BSY ||
 		    port_task_file & AHCI_TFD_STS_DRQ) {
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 			    "SCLO cannot clear PxTFD.STS.BSY/DRQ (PxTFD=0x%x)",
 			    port_task_file);
 			goto out;
@@ -3310,7 +3311,7 @@
 	/* Then start port */
 	if (ahci_start_port(ahci_ctlp, ahci_portp, port)
 	    != AHCI_SUCCESS) {
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_software_reset: cannot start AHCI port %d.", port);
 		goto out;
 	}
@@ -3369,7 +3370,7 @@
 
 		/* We are effectively timing out after 1 sec. */
 		if (loop_count++ > AHCI_POLLRATE_PORT_SOFTRESET) {
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 			    "the first SRST FIS is timed out, "
 			    "loop_count = %d", loop_count);
 			goto out;
@@ -3379,7 +3380,7 @@
 		delay(AHCI_10MS_TICKS);
 	} while (port_cmd_issue & AHCI_SLOT_MASK(ahci_ctlp) & (0x1 << slot));
 
-	AHCIDBG3(AHCIDBG_POLL_LOOP, ahci_ctlp,
+	AHCIDBG(AHCIDBG_POLL_LOOP, ahci_ctlp,
 	    "ahci_software_reset: 1st loop count: %d, "
 	    "port_cmd_issue = 0x%x, slot = 0x%x",
 	    loop_count, port_cmd_issue, slot);
@@ -3428,7 +3429,7 @@
 
 		/* We are effectively timing out after 1 sec. */
 		if (loop_count++ > AHCI_POLLRATE_PORT_SOFTRESET) {
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 			    "the second SRST FIS is timed out, "
 			    "loop_count = %d", loop_count);
 			goto out;
@@ -3438,7 +3439,7 @@
 		delay(AHCI_10MS_TICKS);
 	} while (port_cmd_issue & AHCI_SLOT_MASK(ahci_ctlp) & (0x1 << slot));
 
-	AHCIDBG3(AHCIDBG_POLL_LOOP, ahci_ctlp,
+	AHCIDBG(AHCIDBG_POLL_LOOP, ahci_ctlp,
 	    "ahci_software_reset: 2nd loop count: %d, "
 	    "port_cmd_issue = 0x%x, slot = 0x%x",
 	    loop_count, port_cmd_issue, slot);
@@ -3447,7 +3448,7 @@
 
 	rval = AHCI_SUCCESS;
 out:
-	AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 	    "ahci_software_reset: %s at port %d",
 	    rval == AHCI_SUCCESS ? "succeed" : "failed",
 	    port);
@@ -3485,7 +3486,7 @@
 	int loop_count;
 	int instance = ddi_get_instance(ahci_ctlp->ahcictl_dip);
 
-	AHCIDBG1(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
 	    "Port %d port resetting...", port);
 	ahci_portp->ahciport_port_state = 0;
 
@@ -3503,7 +3504,7 @@
 		if (!(port_cmd_status & AHCI_CMD_STATUS_SUD)) {
 			if (!(ahci_portp->ahciport_flags
 			    & AHCI_PORT_FLAG_SPINUP)) {
-				AHCIDBG1(AHCIDBG_INIT, ahci_ctlp,
+				AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 				    "Port %d PxCMD.SUD is zero, force "
 				    "it to do spin-up", port);
 				ahci_portp->ahciport_flags |=
@@ -3517,9 +3518,9 @@
 		 */
 		if (ahci_portp->ahciport_flags &
 		    AHCI_PORT_FLAG_SPINUP) {
-			AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
+			AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 			    "HBA does not support staggered spin-up "
-			    "force it to do normal COMRESET");
+			    "force it to do normal COMRESET", NULL);
 			ahci_portp->ahciport_flags &=
 			    ~AHCI_PORT_FLAG_SPINUP;
 		}
@@ -3527,7 +3528,7 @@
 
 	if (!(ahci_portp->ahciport_flags & AHCI_PORT_FLAG_SPINUP)) {
 		/* Do normal COMRESET */
-		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 		    "ahci_port_reset: do normal COMRESET", port);
 
 		/*
@@ -3537,7 +3538,7 @@
 		 */
 #if AHCI_DEBUG
 		if (!(port_cmd_status & AHCI_CMD_STATUS_SUD))
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 			    "port %d SUD bit not set", port)
 #endif
 
@@ -3641,7 +3642,7 @@
 		delay(AHCI_10MS_TICKS);
 	} while (SSTATUS_GET_DET(port_sstatus) != SSTATUS_DET_DEVPRE_PHYCOM);
 
-	AHCIDBG3(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
 	    "ahci_port_reset: 1st loop count: %d, "
 	    "port_sstatus = 0x%x port %d",
 	    loop_count, port_sstatus, port);
@@ -3687,7 +3688,7 @@
 	port_task_file = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
 	    (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port));
 	if (!(port_task_file & AHCI_TFD_STS_BSY)) {
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_port_reset: "
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_port_reset: "
 		    "port %d BSY bit is not set after COMINIT signal "
 		    "is received", port);
 	}
@@ -3720,7 +3721,7 @@
 			    "the power-up diagnostics failed",
 			    instance, port);
 
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_port_reset: "
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_port_reset: "
 			    "port %d PxTFD.STS.ERR is not set, we need another "
 			    "software reset.", port);
 
@@ -3752,7 +3753,7 @@
 	} while (((port_task_file & AHCI_TFD_ERR_MASK)
 	    >> AHCI_TFD_ERR_SHIFT) != AHCI_TFD_ERR_SGS);
 
-	AHCIDBG3(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
 	    "ahci_port_reset: 2nd loop count: %d, "
 	    "port_task_file = 0x%x port %d",
 	    loop_count, port_task_file, port);
@@ -3765,7 +3766,7 @@
 	/* Set port as ready */
 	ahci_portp->ahciport_port_state |= SATA_STATE_READY;
 
-	AHCIDBG1(AHCIDBG_INFO|AHCIDBG_ERRS, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INFO|AHCIDBG_ERRS, ahci_ctlp,
 	    "ahci_port_reset: succeed at port %d.", port);
 	return (AHCI_SUCCESS);
 }
@@ -3793,7 +3794,8 @@
 	int loop_count;
 	int rval = AHCI_SUCCESS;
 
-	AHCIDBG0(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "HBA resetting");
+	AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "HBA resetting",
+	    NULL);
 
 	mutex_enter(&ahci_ctlp->ahcictl_mutex);
 
@@ -3814,7 +3816,7 @@
 		    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
 
 		if (loop_count++ > AHCI_POLLRATE_HBA_RESET) {
-			AHCIDBG1(AHCIDBG_INIT, ahci_ctlp,
+			AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 			    "ahci hba reset is timing out, "
 			    "ghc_control = 0x%x", ghc_control);
 			/* We are effectively timing out after 1 sec. */
@@ -3825,14 +3827,14 @@
 		delay(AHCI_10MS_TICKS);
 	} while (ghc_control & AHCI_HBA_GHC_HR);
 
-	AHCIDBG2(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
 	    "ahci_hba_reset: 1st loop count: %d, "
 	    "ghc_control = 0x%x", loop_count, ghc_control);
 
 	if (ghc_control & AHCI_HBA_GHC_HR) {
 		/* The hba is not reset for some reasons */
-		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-		    "hba reset failed: HBA in a hung or locked state");
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+		    "hba reset failed: HBA in a hung or locked state", NULL);
 		mutex_exit(&ahci_ctlp->ahcictl_mutex);
 		return (AHCI_FAILURE);
 	}
@@ -3849,7 +3851,7 @@
 		if (ahci_port_reset(ahci_ctlp, ahci_portp, port)
 		    != AHCI_SUCCESS) {
 			rval = AHCI_FAILURE;
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 			    "ahci_hba_reset: port %d failed", port);
 		}
 
@@ -3890,7 +3892,7 @@
 {
 	uint32_t signature;
 
-	AHCIDBG1(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_find_dev_signature enter: port %d", port);
 
 	ahci_portp->ahciport_device_type = SATA_DTYPE_UNKNOWN;
@@ -3898,7 +3900,7 @@
 	/* Issue a software reset to get the signature */
 	if (ahci_software_reset(ahci_ctlp, ahci_portp, port)
 	    != AHCI_SUCCESS) {
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_find_dev_signature: software reset failed "
 		    "at port %d, cannot get signature.", port);
 		ahci_portp->ahciport_port_state = SATA_PSTATE_FAILED;
@@ -3911,7 +3913,7 @@
 	 */
 	if (ahci_put_port_into_notrunning_state(ahci_ctlp, ahci_portp, port)
 	    != AHCI_SUCCESS) {
-		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 		    "ahci_find_dev_signature: cannot stop port %d.", port);
 		ahci_portp->ahciport_port_state = SATA_PSTATE_FAILED;
 		return;
@@ -3921,7 +3923,7 @@
 	signature = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
 	    (uint32_t *)AHCI_PORT_PxSIG(ahci_ctlp, port));
 
-	AHCIDBG2(AHCIDBG_INIT|AHCIDBG_INFO, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INIT|AHCIDBG_INFO, ahci_ctlp,
 	    "ahci_find_dev_signature: port %d signature = 0x%x",
 	    port, signature);
 
@@ -3929,25 +3931,25 @@
 
 	case AHCI_SIGNATURE_DISK:
 		ahci_portp->ahciport_device_type = SATA_DTYPE_ATADISK;
-		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 		    "Disk is found at port: %d", port);
 		break;
 
 	case AHCI_SIGNATURE_ATAPI:
 		ahci_portp->ahciport_device_type = SATA_DTYPE_ATAPI;
-		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 		    "ATAPI device is found at port: %d", port);
 		break;
 
 	case AHCI_SIGNATURE_PORT_MULTIPLIER:
 		ahci_portp->ahciport_device_type = SATA_DTYPE_PMULT;
-		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 		    "Port Multiplier is found at port: %d", port);
 		break;
 
 	default:
 		ahci_portp->ahciport_device_type = SATA_DTYPE_UNKNOWN;
-		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
 		    "Unknown device is found at port: %d", port);
 	}
 }
@@ -4004,17 +4006,17 @@
 {
 	uint32_t port_cmd_status;
 
-	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, "ahci_start_port: %d enter", port);
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_start_port: %d enter", port);
 
 	if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED) {
-		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port failed "
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port failed "
 		    "the state for port %d is 0x%x",
 		    port, ahci_portp->ahciport_port_state);
 		return (AHCI_FAILURE);
 	}
 
 	if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port failed "
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port failed "
 		    "no device is attached at port %d", port);
 		return (AHCI_FAILURE);
 	}
@@ -4041,7 +4043,7 @@
 
 	ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_STARTED;
 
-	AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port: "
+	AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port: "
 	    "PxCMD.ST set to '1' at port %d", port);
 
 	return (AHCI_SUCCESS);
@@ -4183,8 +4185,8 @@
 	    NULL,
 	    &ahci_portp->ahciport_rcvd_fis_dma_handle) !=
 	    DDI_SUCCESS) {
-		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-		    "rcvd FIS dma handle alloc failed");
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+		    "rcvd FIS dma handle alloc failed", NULL);
 
 		return (AHCI_FAILURE);
 	}
@@ -4199,8 +4201,8 @@
 	    &ret_len,
 	    &ahci_portp->ahciport_rcvd_fis_acc_handle) != NULL) {
 
-		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-		    "rcvd FIS dma mem alloc fail");
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+		    "rcvd FIS dma mem alloc fail", NULL);
 		/* error.. free the dma handle. */
 		ddi_dma_free_handle(&ahci_portp->ahciport_rcvd_fis_dma_handle);
 		return (AHCI_FAILURE);
@@ -4216,8 +4218,8 @@
 	    &ahci_portp->ahciport_rcvd_fis_dma_cookie,
 	    &cookie_count) !=  DDI_DMA_MAPPED) {
 
-		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-		    "rcvd FIS dma handle bind fail");
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+		    "rcvd FIS dma handle bind fail", NULL);
 		/*  error.. free the dma handle & free the memory. */
 		ddi_dma_mem_free(&ahci_portp->ahciport_rcvd_fis_acc_handle);
 		ddi_dma_free_handle(&ahci_portp->ahciport_rcvd_fis_dma_handle);
@@ -4231,9 +4233,9 @@
 	    (uint64_t *)AHCI_PORT_PxFB(ahci_ctlp, port),
 	    ahci_portp->ahciport_rcvd_fis_dma_cookie.dmac_laddress);
 
-	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "64-bit, dma address: 0x%llx",
+	AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "64-bit, dma address: 0x%llx",
 	    ahci_portp->ahciport_rcvd_fis_dma_cookie.dmac_laddress);
-	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "32-bit, dma address: 0x%x",
+	AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "32-bit, dma address: 0x%x",
 	    ahci_portp->ahciport_rcvd_fis_dma_cookie.dmac_address);
 
 	return (AHCI_SUCCESS);
@@ -4284,8 +4286,8 @@
 	    NULL,
 	    &ahci_portp->ahciport_cmd_list_dma_handle) != DDI_SUCCESS) {
 
-		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-		    "cmd list dma handle alloc failed");
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+		    "cmd list dma handle alloc failed", NULL);
 		return (AHCI_FAILURE);
 	}
 
@@ -4299,8 +4301,8 @@
 	    &ret_len,
 	    &ahci_portp->ahciport_cmd_list_acc_handle) != NULL) {
 
-		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-		    "cmd list dma mem alloc fail");
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+		    "cmd list dma mem alloc fail", NULL);
 		/* error.. free the dma handle. */
 		ddi_dma_free_handle(&ahci_portp->ahciport_cmd_list_dma_handle);
 		return (AHCI_FAILURE);
@@ -4316,8 +4318,8 @@
 	    &ahci_portp->ahciport_cmd_list_dma_cookie,
 	    &cookie_count) !=  DDI_DMA_MAPPED) {
 
-		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-		    "cmd list dma handle bind fail");
+		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+		    "cmd list dma handle bind fail", NULL);
 		/*  error.. free the dma handle & free the memory. */
 		ddi_dma_mem_free(&ahci_portp->ahciport_cmd_list_acc_handle);
 		ddi_dma_free_handle(&ahci_portp->ahciport_cmd_list_dma_handle);
@@ -4331,10 +4333,10 @@
 	    (uint64_t *)AHCI_PORT_PxCLB(ahci_ctlp, port),
 	    ahci_portp->ahciport_cmd_list_dma_cookie.dmac_laddress);
 
-	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "64-bit, dma address: 0x%llx",
+	AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "64-bit, dma address: 0x%llx",
 	    ahci_portp->ahciport_cmd_list_dma_cookie.dmac_laddress);
 
-	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "32-bit, dma address: 0x%x",
+	AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "32-bit, dma address: 0x%x",
 	    ahci_portp->ahciport_cmd_list_dma_cookie.dmac_address);
 
 	if (ahci_alloc_cmd_tables(ahci_ctlp, ahci_portp) != AHCI_SUCCESS) {
@@ -4393,7 +4395,7 @@
 	uint_t cookie_count;
 	int slot;
 
-	AHCIDBG1(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_alloc_cmd_tables: port %d enter",
 	    ahci_portp->ahciport_port_num);
 
@@ -4406,8 +4408,8 @@
 		    &ahci_portp->ahciport_cmd_tables_dma_handle[slot]) !=
 		    DDI_SUCCESS) {
 
-			AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-			    "cmd table dma handle alloc failed");
+			AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+			    "cmd table dma handle alloc failed", NULL);
 
 			goto err_out;
 		}
@@ -4424,8 +4426,8 @@
 		    &ahci_portp->ahciport_cmd_tables_acc_handle[slot]) !=
 		    NULL) {
 
-			AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-			    "cmd table dma mem alloc fail");
+			AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+			    "cmd table dma mem alloc fail", NULL);
 
 			/* error.. free the dma handle. */
 			ddi_dma_free_handle(
@@ -4444,8 +4446,8 @@
 		    &cmd_table_dma_cookie,
 		    &cookie_count) !=  DDI_DMA_MAPPED) {
 
-			AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
-			    "cmd table dma handle bind fail");
+			AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
+			    "cmd table dma handle bind fail", NULL);
 			/*  error.. free the dma handle & free the memory. */
 			ddi_dma_mem_free(
 			    &ahci_portp->ahciport_cmd_tables_acc_handle[slot]);
@@ -4500,7 +4502,7 @@
 {
 	int slot;
 
-	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_dealloc_cmd_tables: %d enter",
 	    ahci_portp->ahciport_port_num);
 
@@ -4550,7 +4552,7 @@
 	uint32_t port_intr_status;
 	uint32_t port_intr_enable;
 
-	AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_port_intr enter: port %d", port);
 
 	mutex_enter(&ahci_portp->ahciport_mutex);
@@ -4588,7 +4590,7 @@
 	port_intr_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
 	    (uint32_t *)AHCI_PORT_PxIS(ahci_ctlp, port));
 
-	AHCIDBG3(AHCIDBG_INTR, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
 	    "ahci_port_intr: port %d, port_intr_status = 0x%x, "
 	    "port_intr_enable = 0x%x",
 	    port, port_intr_status, port_intr_enable);
@@ -4785,7 +4787,7 @@
 	if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
 		/* Slot 0 is always used during error recovery */
 		finished_tags = 0x1 & ~port_cmd_issue;
-		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_intr_cmd_cmplt: port %d the sata pkt for error "
 		    "retrieval is finished, and finished_tags = 0x%x",
 		    port, finished_tags);
@@ -4794,7 +4796,7 @@
 		    ~port_cmd_issue & AHCI_SLOT_MASK(ahci_ctlp);
 	}
 
-	AHCIDBG3(AHCIDBG_INTR, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
 	    "ahci_intr_cmd_cmplt: pending_tags = 0x%x, "
 	    "port_cmd_issue = 0x%x finished_tags = 0x%x",
 	    ahci_portp->ahciport_pending_tags, port_cmd_issue,
@@ -4805,7 +4807,7 @@
 		satapkt = ahci_portp->ahciport_err_retri_pkt;
 		ASSERT(satapkt != NULL);
 
-		AHCIDBG1(AHCIDBG_INTR, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
 		    "ahci_intr_cmd_cmplt: sending up pkt 0x%p "
 		    "with SATA_PKT_COMPLETED", (void *)satapkt);
 
@@ -4850,7 +4852,7 @@
 		if (cmd_dmacount) {
 			cmd_header =
 			    &ahci_portp->ahciport_cmd_list[finished_slot];
-			AHCIDBG3(AHCIDBG_INTR|AHCIDBG_PRDT, ahci_ctlp,
+			AHCIDBG(AHCIDBG_INTR|AHCIDBG_PRDT, ahci_ctlp,
 			    "ahci_intr_cmd_cmplt: port %d, "
 			    "PRD Byte Count = 0x%x, "
 			    "ahciport_prd_bytecounts = 0x%x", port,
@@ -4858,7 +4860,7 @@
 			    cmd_dmacount);
 
 			if (cmd_header->ahcich_prd_byte_count != cmd_dmacount) {
-				AHCIDBG1(AHCIDBG_UNDERFLOW, ahci_ctlp,
+				AHCIDBG(AHCIDBG_UNDERFLOW, ahci_ctlp,
 				    "ahci_intr_cmd_cmplt: port %d, "
 				    "an underflow occurred", port);
 			}
@@ -4887,7 +4889,7 @@
 			ahci_copy_out_regs(&satapkt->satapkt_cmd, rcvd_fisp);
 		}
 
-		AHCIDBG1(AHCIDBG_INTR, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
 		    "ahci_intr_cmd_cmplt: sending up pkt 0x%p "
 		    "with SATA_PKT_COMPLETED", (void *)satapkt);
 
@@ -4898,7 +4900,7 @@
 		SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_COMPLETED);
 	}
 out:
-	AHCIDBG1(AHCIDBG_PKTCOMP, ahci_ctlp,
+	AHCIDBG(AHCIDBG_PKTCOMP, ahci_ctlp,
 	    "ahci_intr_cmd_cmplt: pending_tags = 0x%x",
 	    ahci_portp->ahciport_pending_tags);
 
@@ -4939,7 +4941,7 @@
 	int finished_slot;
 	sata_pkt_t *satapkt;
 
-	AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
 	    "ahci_intr_set_device_bits enter: port %d", port);
 
 	mutex_enter(&ahci_portp->ahciport_mutex);
@@ -4958,12 +4960,12 @@
 	finished_tags = ahci_portp->ahciport_pending_ncq_tags &
 	    ~port_sactive & AHCI_NCQ_SLOT_MASK(ahci_portp);
 
-	AHCIDBG3(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
 	    "ahci_intr_set_device_bits: port %d pending_ncq_tags = 0x%x "
 	    "port_sactive = 0x%x", port,
 	    ahci_portp->ahciport_pending_ncq_tags, port_sactive);
 
-	AHCIDBG1(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
 	    "ahci_intr_set_device_bits: finished_tags = 0x%x", finished_tags);
 
 	/*
@@ -4976,12 +4978,12 @@
 	issued_tags = ahci_portp->ahciport_pending_tags &
 	    ~port_cmd_issue & AHCI_SLOT_MASK(ahci_ctlp);
 
-	AHCIDBG3(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
 	    "ahci_intr_set_device_bits: port %d pending_tags = 0x%x "
 	    "port_cmd_issue = 0x%x", port,
 	    ahci_portp->ahciport_pending_tags, port_cmd_issue);
 
-	AHCIDBG1(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
 	    "ahci_intr_set_device_bits: issued_tags = 0x%x", issued_tags);
 
 	/*
@@ -5011,7 +5013,7 @@
 		satapkt = ahci_portp->ahciport_slot_pkts[finished_slot];
 		ASSERT(satapkt != NULL);
 
-		AHCIDBG1(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
 		    "ahci_intr_set_device_bits: sending up pkt 0x%p "
 		    "with SATA_PKT_COMPLETED", (void *)satapkt);
 
@@ -5022,7 +5024,7 @@
 		SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_COMPLETED);
 	}
 out:
-	AHCIDBG3(AHCIDBG_PKTCOMP|AHCIDBG_NCQ, ahci_ctlp,
+	AHCIDBG(AHCIDBG_PKTCOMP|AHCIDBG_NCQ, ahci_ctlp,
 	    "ahci_intr_set_device_bits: port %d "
 	    "pending_ncq_tags = 0x%x pending_tags = 0x%x",
 	    port, ahci_portp->ahciport_pending_ncq_tags,
@@ -5065,7 +5067,7 @@
 	port_serror = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
 	    (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port));
 
-	AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_intr_port_connect_change: port %d, "
 	    "port_serror = 0x%x", port, port_serror);
 #endif
@@ -5098,7 +5100,7 @@
 {
 	uint32_t cap_status, port_cmd_status;
 
-	AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_intr_device_mechanical_presence_status enter, "
 	    "port %d", port);
 
@@ -5111,7 +5113,7 @@
 
 	if (!(cap_status & AHCI_HBA_CAP_SMPS) ||
 	    !(port_cmd_status & AHCI_CMD_STATUS_MPSP)) {
-		AHCIDBG2(AHCIDBG_INTR, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
 		    "CAP.SMPS or PxCMD.MPSP is not set, so just ignore "
 		    "the interrupt: cap_status = 0x%x, "
 		    "port_cmd_status = 0x%x", cap_status, port_cmd_status);
@@ -5122,12 +5124,12 @@
 
 #if AHCI_DEBUG
 	if (port_cmd_status & AHCI_CMD_STATUS_MPSS) {
-		AHCIDBG2(AHCIDBG_INTR, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
 		    "The mechanical presence switch is open: "
 		    "port %d, port_cmd_status = 0x%x",
 		    port, port_cmd_status);
 	} else {
-		AHCIDBG2(AHCIDBG_INTR, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
 		    "The mechanical presence switch is close: "
 		    "port %d, port_cmd_status = 0x%x",
 		    port, port_cmd_status);
@@ -5167,7 +5169,7 @@
 	int dev_exists_now = 0;
 	int dev_existed_previously = 0;
 
-	AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_intr_phyrdy_change enter, port %d", port);
 
 	/* Clear PxSERR.DIAG.N to clear the interrupt bit */
@@ -5202,7 +5204,7 @@
 
 	if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_NODEV) {
 		ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_NODEV;
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_intr_phyrdy_change: port %d "
 		    "AHCI_PORT_FLAG_NODEV is cleared", port);
 		if (dev_exists_now == 0)
@@ -5219,7 +5221,7 @@
 	if (dev_exists_now) {
 		if (dev_existed_previously) {
 			/* Things are fine now. The loss was temporary. */
-			AHCIDBG1(AHCIDBG_EVENT, ahci_ctlp,
+			AHCIDBG(AHCIDBG_EVENT, ahci_ctlp,
 			    "ahci_intr_phyrdy_change  port %d "
 			    "device link lost/established", port);
 
@@ -5231,7 +5233,7 @@
 			mutex_enter(&ahci_portp->ahciport_mutex);
 
 		} else {
-			AHCIDBG1(AHCIDBG_EVENT, ahci_ctlp,
+			AHCIDBG(AHCIDBG_EVENT, ahci_ctlp,
 			    "ahci_intr_phyrdy_change: port %d "
 			    "device link established", port);
 
@@ -5243,7 +5245,7 @@
 			if (ahci_start_port(ahci_ctlp, ahci_portp, port)
 			    != AHCI_SUCCESS) {
 				sdevice.satadev_state |= SATA_PSTATE_FAILED;
-				AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+				AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 				    "ahci_intr_phyrdy_change: port %d failed "
 				    "at start port", port);
 			}
@@ -5262,7 +5264,7 @@
 	} else { /* No device exists now */
 
 		if (dev_existed_previously) {
-			AHCIDBG1(AHCIDBG_EVENT, ahci_ctlp,
+			AHCIDBG(AHCIDBG_EVENT, ahci_ctlp,
 			    "ahci_intr_phyrdy_change: port %d "
 			    "device link lost", port);
 
@@ -5345,14 +5347,14 @@
 	port_serror = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
 	    (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port));
 
-	AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ENTRY|AHCIDBG_ERRS, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INTR|AHCIDBG_ENTRY|AHCIDBG_ERRS, ahci_ctlp,
 	    "ahci_intr_non_fatal_error: port %d, "
 	    "port_serror = 0x%x", port, port_serror);
 
 	ahci_log_serror_message(ahci_ctlp, port, port_serror, 1);
 
 	if (intr_status & AHCI_INTR_STATUS_UFS) {
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci port %d has unknown FIS error", port);
 
 		/* Clear the interrupt bit by clearing PxSERR.DIAG.F */
@@ -5363,12 +5365,12 @@
 
 #if AHCI_DEBUG
 	if (intr_status & AHCI_INTR_STATUS_OFS) {
-		AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci port %d has overflow error", port);
 	}
 
 	if (intr_status & AHCI_INTR_STATUS_INFS) {
-		AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci port %d has interface non fatal error", port);
 	}
 
@@ -5392,12 +5394,12 @@
 		}
 
 		if (satapkt != NULL) {
-			AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
 			    "ahci_intr_non_fatal_error: pending_tags = 0x%x "
 			    "cmd 0x%x", ahci_portp->ahciport_pending_tags,
 			    satapkt->satapkt_cmd.satacmd_cmd_reg);
 
-			AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
 			    "ahci_intr_non_fatal_error: port %d, "
 			    "satapkt 0x%p is being processed when error occurs",
 			    port, (void *)satapkt);
@@ -5413,7 +5415,7 @@
 			if (cmd_dmacount) {
 				cmd_header = &ahci_portp->
 				    ahciport_cmd_list[current_slot];
-				AHCIDBG3(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
+				AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
 				    "ahci_intr_non_fatal_error: port %d, "
 				    "PRD Byte Count = 0x%x, "
 				    "ahciport_prd_bytecounts = 0x%x", port,
@@ -5432,7 +5434,7 @@
 		port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
 		    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
 
-		AHCIDBG3(AHCIDBG_INTR|AHCIDBG_NCQ|AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ|AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_intr_non_fatal_error: pending_ncq_tags = 0x%x "
 		    "port_sactive = 0x%x port_cmd_issue = 0x%x",
 		    ahci_portp->ahciport_pending_ncq_tags,
@@ -5449,7 +5451,7 @@
 			}
 
 			satapkt = ahci_portp->ahciport_slot_pkts[current_slot];
-			AHCIDBG2(AHCIDBG_INTR|AHCIDBG_NCQ|AHCIDBG_ERRS,
+			AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ|AHCIDBG_ERRS,
 			    ahci_ctlp, "ahci_intr_non_fatal_error: "
 			    "port %d, satapkt 0x%p is outstanding when "
 			    "error occurs", port, (void *)satapkt);
@@ -5564,7 +5566,7 @@
 	 * SATA_DTYPE_NONE.
 	 */
 	if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
-		AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp,
 		    "ahci_intr_fatal_error: port %d no device attached, "
 		    "and just return without doing anything", port);
 		goto out0;
@@ -5573,7 +5575,7 @@
 	if (intr_status & AHCI_INTR_STATUS_TFES) {
 		task_file_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
 		    (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port));
-		AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_intr_fatal_error: port %d "
 		    "task_file_status = 0x%x", port, task_file_status);
 	}
@@ -5589,7 +5591,7 @@
 		    AHCI_CMD_STATUS_CCS_SHIFT;
 
 		spkt = ahci_portp->ahciport_slot_pkts[failed_slot];
-		AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_intr_fatal_error: spkt 0x%p is being processed when "
 		    "fatal error occurred for port %d", spkt, port);
 
@@ -5670,7 +5672,7 @@
 	uint32_t port_cmd_status;
 	sata_device_t sdevice;
 
-	AHCIDBG1(AHCIDBG_INTR, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
 	    "ahci_intr_cold_port_detect enter, port %d", port);
 
 	mutex_enter(&ahci_portp->ahciport_mutex);
@@ -5678,14 +5680,14 @@
 	port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
 	    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
 	if (!(port_cmd_status & AHCI_CMD_STATUS_CPD)) {
-		AHCIDBG1(AHCIDBG_INTR, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
 		    "port %d does not support cold presence detect, so "
 		    "we just ignore this interrupt", port);
 		mutex_exit(&ahci_portp->ahciport_mutex);
 		return (AHCI_SUCCESS);
 	}
 
-	AHCIDBG1(AHCIDBG_INTR, ahci_ctlp,
+	AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
 	    "port %d device status has changed", port);
 
 	bzero((void *)&sdevice, sizeof (sata_device_t));
@@ -5695,7 +5697,7 @@
 	sdevice.satadev_state = SATA_PSTATE_PWRON;
 
 	if (port_cmd_status & AHCI_CMD_STATUS_CPS) {
-		AHCIDBG1(AHCIDBG_INTR, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
 		    "port %d: a device is hot plugged", port);
 		mutex_exit(&ahci_portp->ahciport_mutex);
 		sata_hba_event_notify(
@@ -5705,7 +5707,7 @@
 		mutex_enter(&ahci_portp->ahciport_mutex);
 
 	} else {
-		AHCIDBG1(AHCIDBG_INTR, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
 		    "port %d: a device is hot unplugged", port);
 		mutex_exit(&ahci_portp->ahciport_mutex);
 		sata_hba_event_notify(
@@ -5729,7 +5731,7 @@
 static void
 ahci_enable_port_intrs(ahci_ctl_t *ahci_ctlp, uint8_t port)
 {
-	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_enable_port_intrs enter, port %d", port);
 
 	/*
@@ -5788,7 +5790,7 @@
 {
 	uint32_t ghc_control;
 
-	AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp, "ahci_enable_all_intrs enter");
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_enable_all_intrs enter", NULL);
 
 	ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
 	    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
@@ -5808,7 +5810,7 @@
 static void
 ahci_disable_port_intrs(ahci_ctl_t *ahci_ctlp, uint8_t port)
 {
-	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_disable_port_intrs enter, port %d", port);
 
 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
@@ -5829,7 +5831,8 @@
 {
 	uint32_t ghc_control;
 
-	AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp, "ahci_disable_all_intrs enter");
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_disable_all_intrs enter",
+	    NULL);
 
 	ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
 	    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
@@ -5887,13 +5890,13 @@
 	int		count, avail, actual;
 	int		i, rc;
 
-	AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
 	    "ahci_add_intrs enter interrupt type 0x%x", intr_type);
 
 	/* get number of interrupts. */
 	rc = ddi_intr_get_nintrs(dip, intr_type, &count);
 	if ((rc != DDI_SUCCESS) || (count == 0)) {
-		AHCIDBG2(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
 		    "ddi_intr_get_nintrs() failed, "
 		    "rc %d count %d\n", rc, count);
 		return (DDI_FAILURE);
@@ -5902,7 +5905,7 @@
 	/* get number of available interrupts. */
 	rc = ddi_intr_get_navail(dip, intr_type, &avail);
 	if ((rc != DDI_SUCCESS) || (avail == 0)) {
-		AHCIDBG2(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
 		    "ddi_intr_get_navail() failed, "
 		    "rc %d avail %d\n", rc, avail);
 		return (DDI_FAILURE);
@@ -5910,7 +5913,7 @@
 
 #if AHCI_DEBUG
 	if (avail < count) {
-		AHCIDBG2(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
 		    "ddi_intr_get_nintrs returned %d, navail() returned %d",
 		    count, avail);
 	}
@@ -5925,7 +5928,7 @@
 	 * performance.
 	 */
 	if ((intr_type == DDI_INTR_TYPE_MSI) && (count > 1)) {
-		AHCIDBG1(AHCIDBG_INTR, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
 		    "force to use one interrupt routine though the "
 		    "HBA supports %d interrupt", count);
 		count = 1;
@@ -5941,7 +5944,7 @@
 	    intr_type, 0, count, &actual, DDI_INTR_ALLOC_NORMAL);
 
 	if ((rc != DDI_SUCCESS) || (actual == 0)) {
-		AHCIDBG4(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
 		    "ddi_intr_alloc() failed, rc %d count %d actual %d "
 		    "avail %d\n", rc, count, actual, avail);
 		kmem_free(ahci_ctlp->ahcictl_intr_htable,
@@ -5952,7 +5955,7 @@
 	/* use interrupt count returned */
 #if AHCI_DEBUG
 	if (actual < count) {
-		AHCIDBG2(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
 		    "Requested: %d, Received: %d", count, actual);
 	}
 #endif
@@ -5964,8 +5967,8 @@
 	 */
 	if (ddi_intr_get_pri(ahci_ctlp->ahcictl_intr_htable[0],
 	    &ahci_ctlp->ahcictl_intr_pri) != DDI_SUCCESS) {
-		AHCIDBG0(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
-		    "ddi_intr_get_pri() failed");
+		AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
+		    "ddi_intr_get_pri() failed", NULL);
 
 		/* Free already allocated intr. */
 		for (i = 0; i < actual; i++) {
@@ -5979,8 +5982,8 @@
 
 	/* Test for high level interrupt. */
 	if (ahci_ctlp->ahcictl_intr_pri >= ddi_intr_get_hilevel_pri()) {
-		AHCIDBG0(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
-		    "ahci_add_intrs: Hi level intr not supported");
+		AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
+		    "ahci_add_intrs: Hi level intr not supported", NULL);
 
 		/* Free already allocated intr. */
 		for (i = 0; i < actual; i++) {
@@ -5997,8 +6000,8 @@
 	for (i = 0; i < actual; i++) {
 		if (ddi_intr_add_handler(ahci_ctlp->ahcictl_intr_htable[i],
 		    ahci_intr, (caddr_t)ahci_ctlp, NULL) != DDI_SUCCESS) {
-			AHCIDBG0(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
-			    "ddi_intr_add_handler() failed");
+			AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
+			    "ddi_intr_add_handler() failed", NULL);
 
 			/* Free already allocated intr. */
 			for (i = 0; i < actual; i++) {
@@ -6014,8 +6017,8 @@
 
 	if (ddi_intr_get_cap(ahci_ctlp->ahcictl_intr_htable[0],
 	    &ahci_ctlp->ahcictl_intr_cap) != DDI_SUCCESS) {
-		AHCIDBG0(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
-		    "ddi_intr_get_cap() failed");
+		AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
+		    "ddi_intr_get_cap() failed", NULL);
 
 		/* Free already allocated intr. */
 		for (i = 0; i < actual; i++) {
@@ -6055,7 +6058,7 @@
 {
 	int x;
 
-	AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp, "ahci_rem_intrs entered");
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_rem_intrs entered", NULL);
 
 	/* Disable all interrupts. */
 	if ((ahci_ctlp->ahcictl_intr_type == DDI_INTR_TYPE_MSI) &&
@@ -6095,7 +6098,7 @@
 	uint32_t port_cmd_status;
 	int loop_count;
 
-	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_put_port_into_notrunning_state enter: port %d", port);
 
 	port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
@@ -6113,7 +6116,7 @@
 		    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
 
 		if (loop_count++ > AHCI_POLLRATE_PORT_IDLE) {
-			AHCIDBG2(AHCIDBG_INIT, ahci_ctlp,
+			AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 			    "clearing port %d CMD.CR timeout, "
 			    "port_cmd_status = 0x%x", port,
 			    port_cmd_status);
@@ -6131,13 +6134,13 @@
 	ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_STARTED;
 
 	if (port_cmd_status & AHCI_CMD_STATUS_CR) {
-		AHCIDBG2(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
 		    "ahci_put_port_into_notrunning_state: failed to clear "
 		    "PxCMD.CR to '0' after loop count: %d, and "
 		    "port_cmd_status = 0x%x", loop_count, port_cmd_status);
 		return (AHCI_FAILURE);
 	} else {
-		AHCIDBG2(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
+		AHCIDBG(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
 		    "ahci_put_port_into_notrunning_state: succeeded to clear "
 		    "PxCMD.CR to '0' after loop count: %d, and "
 		    "port_cmd_status = 0x%x", loop_count, port_cmd_status);
@@ -6189,7 +6192,7 @@
 	int dev_exists_begin = 0;
 	int dev_exists_end = 0;
 
-	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_restart_port_wait_till_ready: port %d enter", port);
 
 	if (ahci_portp->ahciport_device_type != SATA_DTYPE_NONE)
@@ -6257,7 +6260,7 @@
 			mutex_enter(&ahci_portp->ahciport_mutex);
 		}
 
-		AHCIDBG1(AHCIDBG_EVENT, ahci_ctlp,
+		AHCIDBG(AHCIDBG_EVENT, ahci_ctlp,
 		    "port %d sending event up: SATA_EVNT_RESET", port);
 	} else {
 		ahci_portp->ahciport_reset_in_progress = 0;
@@ -6277,11 +6280,11 @@
 
 	/* Check whether a hot plug event happened */
 	if (dev_exists_begin == 1 && dev_exists_end == 0) {
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_restart_port_wait_till_ready: port %d "
 		    "device is removed", port);
 		ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_NODEV;
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_restart_port_wait_till_ready: port %d "
 		    "AHCI_PORT_FLAG_NODEV flag is set", port);
 		mutex_exit(&ahci_portp->ahciport_mutex);
@@ -6320,11 +6323,11 @@
 	int ncq_cmd_in_progress = 0;
 	int err_retri_cmd_in_progress = 0;
 
-	AHCIDBG2(AHCIDBG_ERRS|AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ERRS|AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_mop_commands entered: port: %d slot_status: 0x%x",
 	    ahci_portp->ahciport_port_num, slot_status);
 
-	AHCIDBG4(AHCIDBG_ERRS|AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ERRS|AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_mop_commands: failed_tags: 0x%x, "
 	    "timeout_tags: 0x%x aborted_tags: 0x%x, "
 	    "reset_tags: 0x%x", failed_tags,
@@ -6367,7 +6370,7 @@
 		 * Please note that the command is always sent down in Slot 0
 		 */
 		err_retri_cmd_in_progress = 1;
-		AHCIDBG2(AHCIDBG_ERRS|AHCIDBG_NCQ, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS|AHCIDBG_NCQ, ahci_ctlp,
 		    "ahci_mop_commands is called for port %d while "
 		    "REQUEST SENSE or READ LOG EXT for error retrieval "
 		    "is being executed slot_status = 0x%x",
@@ -6386,7 +6389,7 @@
 		satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
 		ASSERT(satapkt != NULL);
 
-		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, "ahci_mop_commands: "
+		AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_mop_commands: "
 		    "sending up pkt 0x%p with SATA_PKT_COMPLETED",
 		    (void *)satapkt);
 
@@ -6418,7 +6421,7 @@
 			ASSERT(satapkt != NULL);
 			ASSERT(failed_tags == 0x1);
 
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
 			    "sending up pkt 0x%p with SATA_PKT_DEV_ERROR",
 			    (void *)satapkt);
 			SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_DEV_ERROR);
@@ -6433,7 +6436,7 @@
 		satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
 		ASSERT(satapkt != NULL);
 
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
 		    "sending up pkt 0x%p with SATA_PKT_DEV_ERROR",
 		    (void *)satapkt);
 
@@ -6454,7 +6457,7 @@
 			ASSERT(satapkt != NULL);
 			ASSERT(timeout_tags == 0x1);
 
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
 			    "sending up pkt 0x%p with SATA_PKT_TIMEOUT",
 			    (void *)satapkt);
 			SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_TIMEOUT);
@@ -6469,7 +6472,7 @@
 		satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
 		ASSERT(satapkt != NULL);
 
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
 		    "sending up pkt 0x%p with SATA_PKT_TIMEOUT",
 		    (void *)satapkt);
 
@@ -6490,7 +6493,7 @@
 			ASSERT(satapkt != NULL);
 			ASSERT(aborted_tags == 0x1);
 
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
 			    "sending up pkt 0x%p with SATA_PKT_ABORTED",
 			    (void *)satapkt);
 			SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_ABORTED);
@@ -6505,7 +6508,7 @@
 		satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
 		ASSERT(satapkt != NULL);
 
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
 		    "sending up pkt 0x%p with SATA_PKT_ABORTED",
 		    (void *)satapkt);
 
@@ -6529,7 +6532,7 @@
 		satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
 		ASSERT(satapkt != NULL);
 
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
 		    "sending up pkt 0x%p with SATA_PKT_RESET",
 		    (void *)satapkt);
 
@@ -6553,7 +6556,7 @@
 		satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
 		ASSERT(satapkt != NULL);
 
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
 		    "sending up pkt 0x%p with SATA_PKT_RESET",
 		    (void *)satapkt);
 
@@ -6592,7 +6595,7 @@
 	uint32_t	failed_tags = 0;
 	struct sata_ncq_error_recovery_page *ncq_err_page;
 
-	AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_NCQ, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_NCQ, ahci_ctlp,
 	    "ahci_get_rdlogext_data enter: port %d", port);
 
 	/* Prepare the sdevice data */
@@ -6616,7 +6619,7 @@
 			goto loop;
 		}
 		/* Timed out after 1s */
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "failed to get rdlog spkt for port %d", port);
 		return (failed_tags);
 	}
@@ -6653,23 +6656,23 @@
 
 			/* Get the failed tag */
 			failed_slot = ncq_err_page->ncq_tag;
-			AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 			    "ahci_get_rdlogext_data: port %d "
 			    "failed slot %d", port, failed_slot);
 			if (failed_slot & NQ) {
-				AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp,
-				    "the failed slot is not a valid tag");
+				AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
+				    "the failed slot is not a valid tag", NULL);
 				goto out;
 			}
 
 			failed_slot &= NCQ_TAG_MASK;
 			spkt = ahci_portp->ahciport_slot_pkts[failed_slot];
-			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 			    "ahci_get_rdlogext_data: failed spkt 0x%p",
 			    (void *)spkt);
 			if (spkt == NULL) {
-				AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp,
-				    "the failed slot spkt is NULL")
+				AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
+				    "the failed slot spkt is NULL", NULL);
 				goto out;
 			}
 
@@ -6707,7 +6710,7 @@
 	struct scsi_extended_sense *rqsense;
 #endif
 
-	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_get_rqsense_data enter: port %d", port);
 
 	/* Prepare the sdevice data */
@@ -6734,7 +6737,7 @@
 
 		}
 		/* Timed out after 1s */
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "failed to get rs spkt for port %d", port);
 		return;
 	}
@@ -6774,11 +6777,11 @@
 		    sata_cmd->satacmd_rqsense;
 
 		/* Dump the sense data */
-		AHCIDBG0(AHCIDBG_SENSEDATA, ahci_ctlp, "\n");
-		AHCIDBG2(AHCIDBG_SENSEDATA, ahci_ctlp,
+		AHCIDBG(AHCIDBG_SENSEDATA, ahci_ctlp, "\n", NULL);
+		AHCIDBG(AHCIDBG_SENSEDATA, ahci_ctlp,
 		    "Sense data for satapkt %p ATAPI cmd 0x%x",
 		    spkt, sata_cmd->satacmd_acdb[0]);
-		AHCIDBG5(AHCIDBG_SENSEDATA, ahci_ctlp,
+		AHCIDBG(AHCIDBG_SENSEDATA, ahci_ctlp,
 		    "  es_code 0x%x es_class 0x%x "
 		    "es_key 0x%x es_add_code 0x%x "
 		    "es_qual_code 0x%x",
@@ -6832,7 +6835,7 @@
 	ahci_cmd_header_t *cmd_header;
 #endif
 
-	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_fatal_error_recovery_handler enter: port %d", port);
 
 	if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp) ||
@@ -6869,7 +6872,7 @@
 		if (ahci_portp->ahciport_prd_bytecounts[failed_slot]) {
 			cmd_header =
 			    &ahci_portp->ahciport_cmd_list[failed_slot];
-			AHCIDBG3(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
+			AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
 			    "ahci_fatal_error_recovery_handler: port %d, "
 			    "PRD Byte Count = 0x%x, "
 			    "ahciport_prd_bytecounts = 0x%x", port,
@@ -6913,7 +6916,7 @@
 	 * supposed to be REQUEST SENSE command or READ LOG EXT command.
 	 */
 	if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
-		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 		    "ahci_fatal_error_recovery_handler: port %d REQUEST SENSE "
 		    "command or READ LOG EXT command for error data retrieval "
 		    "failed", port);
@@ -6964,7 +6967,7 @@
 	if (spkt && ahci_portp->ahciport_device_type == SATA_DTYPE_ATAPI)
 		ahci_get_rqsense_data(ahci_ctlp, ahci_portp, port, spkt);
 out:
-	AHCIDBG5(AHCIDBG_ERRS, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
 	    "ahci_fatal_error_recovery_handler: port %d fatal error "
 	    "occurred slot_status = 0x%x, pending_tags = 0x%x, "
 	    "pending_ncq_tags = 0x%x failed_tags = 0x%x",
@@ -6999,7 +7002,7 @@
 	event = ahci_event_arg->ahciea_event;
 	port = ahci_portp->ahciport_port_num;
 
-	AHCIDBG2(AHCIDBG_ENTRY|AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
+	AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
 	    "ahci_events_handler enter: port %d intr_status = 0x%x",
 	    port, event);
 
@@ -7010,7 +7013,7 @@
 	 * SATA_DTYPE_NONE.
 	 */
 	if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
-		AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp,
 		    "ahci_events_handler: port %d no device attached, "
 		    "and just return without doing anything", port);
 		goto out;
@@ -7039,7 +7042,7 @@
 	uint32_t finished_tags = 0;
 	uint32_t timeout_tags = 0;
 
-	AHCIDBG1(AHCIDBG_TIMEOUT|AHCIDBG_ENTRY, ahci_ctlp,
+	AHCIDBG(AHCIDBG_TIMEOUT|AHCIDBG_ENTRY, ahci_ctlp,
 	    "ahci_timeout_pkts enter: port %d", port);
 
 	mutex_enter(&ahci_portp->ahciport_mutex);
@@ -7064,7 +7067,7 @@
 	 * supposed to be REQUEST SENSE command or READ LOG EXT command.
 	 */
 	if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
-		AHCIDBG4(AHCIDBG_ERRS|AHCIDBG_TIMEOUT, ahci_ctlp,
+		AHCIDBG(AHCIDBG_ERRS|AHCIDBG_TIMEOUT, ahci_ctlp,
 		    "ahci_timeout_pkts called while REQUEST SENSE "
 		    "command or READ LOG EXT command for error recovery "
 		    "timed out timeout_tags = 0x%x, slot_status = 0x%x, "
@@ -7091,7 +7094,7 @@
 		    ~slot_status & AHCI_SLOT_MASK(ahci_ctlp);
 		timeout_tags = tmp_timeout_tags & ~finished_tags;
 
-		AHCIDBG5(AHCIDBG_TIMEOUT, ahci_ctlp,
+		AHCIDBG(AHCIDBG_TIMEOUT, ahci_ctlp,
 		    "ahci_timeout_pkts: port %d, finished_tags = 0x%x, "
 		    "timeout_tags = 0x%x, port_cmd_issue = 0x%x, "
 		    "pending_tags = 0x%x ",
@@ -7102,7 +7105,7 @@
 		    ~slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
 		timeout_tags = tmp_timeout_tags & ~finished_tags;
 
-		AHCIDBG5(AHCIDBG_TIMEOUT|AHCIDBG_NCQ, ahci_ctlp,
+		AHCIDBG(AHCIDBG_TIMEOUT|AHCIDBG_NCQ, ahci_ctlp,
 		    "ahci_timeout_pkts: port %d, finished_tags = 0x%x, "
 		    "timeout_tags = 0x%x, port_sactive = 0x%x, "
 		    "pending_ncq_tags = 0x%x ",
@@ -7149,8 +7152,8 @@
 
 	mutex_enter(&ahci_ctlp->ahcictl_mutex);
 
-	AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp,
-	    "ahci_watchdog_handler entered");
+	AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
+	    "ahci_watchdog_handler entered", NULL);
 
 	for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
 		if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
@@ -7231,11 +7234,11 @@
 
 #if AHCI_DEBUG
 				if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
-					AHCIDBG1(AHCIDBG_ERRS|AHCIDBG_TIMEOUT,
+					AHCIDBG(AHCIDBG_ERRS|AHCIDBG_TIMEOUT,
 					    ahci_ctlp, "watchdog: the current "
 					    "tags is 0x%x", current_tags);
 				} else {
-					AHCIDBG1(AHCIDBG_ERRS|AHCIDBG_TIMEOUT,
+					AHCIDBG(AHCIDBG_ERRS|AHCIDBG_TIMEOUT,
 					    ahci_ctlp, "watchdog: the current "
 					    "slot is %d", current_slot);
 				}
@@ -7473,14 +7476,22 @@
 
 	if (debug_only) {
 		(void) sprintf(err_msg_header, "port %d", port);
-		AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp, err_msg_header);
-		AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp, err_msg);
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, err_msg_header, NULL);
+		AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, err_msg, NULL);
 	} else if (ahci_ctlp) {
 		cmn_err(CE_WARN, "!ahci%d: %s %s",
 		    ddi_get_instance(ahci_ctlp->ahcictl_dip),
 		    err_msg_header, err_msg);
+
+		/* sata trace debug */
+		sata_trace_debug(ahci_ctlp->ahcictl_dip,
+		    "ahci%d: %s %s", ddi_get_instance(ahci_ctlp->ahcictl_dip),
+		    err_msg_header, err_msg);
 	} else {
 		cmn_err(CE_WARN, "!ahci: %s %s", err_msg_header, err_msg);
+
+		/* sata trace debug */
+		sata_trace_debug(NULL, "ahci: %s %s", err_msg_header, err_msg);
 	}
 }
 
--- a/usr/src/uts/common/io/sata/impl/sata.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/sata/impl/sata.c	Mon Jul 20 13:07:46 2009 -0400
@@ -102,7 +102,7 @@
     sata_save_atapi_trace(spx, count);
 
 #else
-#define	SATA_LOG_D(arg)
+#define	SATA_LOG_D(args)	sata_trace_log args
 #define	SATAATAPITRACE(spx, count)
 #endif
 
@@ -189,29 +189,30 @@
 static	int sata_txlt_start_stop_unit(sata_pkt_txlate_t *);
 static	int sata_txlt_read_capacity(sata_pkt_txlate_t *);
 static	int sata_txlt_request_sense(sata_pkt_txlate_t *);
-static 	int sata_txlt_read(sata_pkt_txlate_t *);
-static 	int sata_txlt_write(sata_pkt_txlate_t *);
-static 	int sata_txlt_log_sense(sata_pkt_txlate_t *);
-static 	int sata_txlt_log_select(sata_pkt_txlate_t *);
-static 	int sata_txlt_mode_sense(sata_pkt_txlate_t *);
-static 	int sata_txlt_mode_select(sata_pkt_txlate_t *);
-static 	int sata_txlt_synchronize_cache(sata_pkt_txlate_t *);
-static 	int sata_txlt_write_buffer(sata_pkt_txlate_t *);
-static 	int sata_txlt_nodata_cmd_immediate(sata_pkt_txlate_t *);
-
-static 	int sata_hba_start(sata_pkt_txlate_t *, int *);
+static	int sata_txlt_read(sata_pkt_txlate_t *);
+static	int sata_txlt_write(sata_pkt_txlate_t *);
+static	int sata_txlt_log_sense(sata_pkt_txlate_t *);
+static	int sata_txlt_log_select(sata_pkt_txlate_t *);
+static	int sata_txlt_mode_sense(sata_pkt_txlate_t *);
+static	int sata_txlt_mode_select(sata_pkt_txlate_t *);
+static	int sata_txlt_synchronize_cache(sata_pkt_txlate_t *);
+static	int sata_txlt_write_buffer(sata_pkt_txlate_t *);
+static	int sata_txlt_nodata_cmd_immediate(sata_pkt_txlate_t *);
+
+static	int sata_hba_start(sata_pkt_txlate_t *, int *);
 static	int sata_txlt_invalid_command(sata_pkt_txlate_t *);
+static	int sata_txlt_check_condition(sata_pkt_txlate_t *, uchar_t, uchar_t);
 static	int sata_txlt_lba_out_of_range(sata_pkt_txlate_t *);
-static 	void sata_txlt_rw_completion(sata_pkt_t *);
-static 	void sata_txlt_nodata_cmd_completion(sata_pkt_t *);
-static 	void sata_txlt_download_mcode_cmd_completion(sata_pkt_t *);
-static 	int sata_emul_rw_completion(sata_pkt_txlate_t *);
-static 	struct scsi_extended_sense *sata_immediate_error_response(
+static	void sata_txlt_rw_completion(sata_pkt_t *);
+static	void sata_txlt_nodata_cmd_completion(sata_pkt_t *);
+static	void sata_txlt_download_mcode_cmd_completion(sata_pkt_t *);
+static	int sata_emul_rw_completion(sata_pkt_txlate_t *);
+static	struct scsi_extended_sense *sata_immediate_error_response(
     sata_pkt_txlate_t *, int);
 static	struct scsi_extended_sense *sata_arq_sense(sata_pkt_txlate_t *);
 
-static 	int sata_txlt_atapi(sata_pkt_txlate_t *);
-static 	void sata_txlt_atapi_completion(sata_pkt_t *);
+static	int sata_txlt_atapi(sata_pkt_txlate_t *);
+static	void sata_txlt_atapi_completion(sata_pkt_t *);
 
 /*
  * Local functions for ioctl
@@ -291,11 +292,13 @@
 static	int sata_build_msense_page_8(sata_drive_info_t *, int, uint8_t *);
 static	int sata_build_msense_page_1a(sata_drive_info_t *, int, uint8_t *);
 static	int sata_build_msense_page_1c(sata_drive_info_t *, int, uint8_t *);
+static	int sata_build_msense_page_30(sata_drive_info_t *, int, uint8_t *);
 static	int sata_mode_select_page_8(sata_pkt_txlate_t *,
     struct mode_cache_scsi3 *, int, int *, int *, int *);
+static	int sata_mode_select_page_1a(sata_pkt_txlate_t *,
+    struct mode_info_power_cond *, int, int *, int *, int *);
 static	int sata_mode_select_page_1c(sata_pkt_txlate_t *,
     struct mode_info_excpt_page *, int, int *, int *, int *);
-static	int sata_build_msense_page_30(sata_drive_info_t *, int, uint8_t *);
 static	int sata_mode_select_page_30(sata_pkt_txlate_t *,
     struct mode_acoustic_management *, int, int *, int *, int *);
 
@@ -306,9 +309,18 @@
     sata_hba_inst_t *);
 static	int sata_build_lsense_page_30(sata_drive_info_t *, uint8_t *,
     sata_hba_inst_t *);
+static	int sata_build_lsense_page_0e(sata_drive_info_t *, uint8_t *,
+    sata_pkt_txlate_t *);
+
+static	void sata_set_arq_data(sata_pkt_t *);
+static	void sata_build_read_verify_cmd(sata_cmd_t *, uint16_t, uint64_t);
+static	void sata_build_generic_cmd(sata_cmd_t *, uint8_t);
+static	uint8_t sata_get_standby_timer(uint8_t *timer);
+
 static	void sata_save_drive_settings(sata_drive_info_t *);
 static	void sata_show_drive_info(sata_hba_inst_t *, sata_drive_info_t *);
 static	void sata_log(sata_hba_inst_t *, uint_t, char *fmt, ...);
+static	void sata_trace_log(sata_hba_inst_t *, uint_t, const char *fmt, ...);
 static	int sata_fetch_smart_return_status(sata_hba_inst_t *,
     sata_drive_info_t *);
 static	int sata_fetch_smart_data(sata_hba_inst_t *, sata_drive_info_t *,
@@ -411,6 +423,17 @@
 
 static 	char sata_log_buf[256];
 
+/*
+ * sata trace debug
+ */
+static	sata_trace_rbuf_t *sata_debug_rbuf;
+static	sata_trace_dmsg_t *sata_trace_dmsg_alloc(void);
+static	void sata_trace_dmsg_free(void);
+static	void sata_trace_rbuf_alloc(void);
+static	void sata_trace_rbuf_free(void);
+
+int	dmsg_ring_size = DMSG_RING_SIZE;
+
 /* Default write cache setting for SATA hard disks */
 int	sata_write_cache = 1;		/* enabled */
 
@@ -543,10 +566,12 @@
 	mutex_init(&sata_event_mutex, NULL, MUTEX_DRIVER, NULL);
 	mutex_init(&sata_log_mutex, NULL, MUTEX_DRIVER, NULL);
 	cv_init(&sata_event_cv, NULL, CV_DRIVER, NULL);
+	sata_trace_rbuf_alloc();
 	if ((rval = mod_install(&modlinkage)) != 0) {
 #ifdef SATA_DEBUG
 		cmn_err(CE_WARN, "sata: _init: mod_install failed\n");
 #endif
+		sata_trace_rbuf_free();
 		mutex_destroy(&sata_log_mutex);
 		cv_destroy(&sata_event_cv);
 		mutex_destroy(&sata_event_mutex);
@@ -563,6 +588,7 @@
 	if ((rval = mod_remove(&modlinkage)) != 0)
 		return (rval);
 
+	sata_trace_rbuf_free();
 	mutex_destroy(&sata_log_mutex);
 	cv_destroy(&sata_event_cv);
 	mutex_destroy(&sata_event_mutex);
@@ -1794,8 +1820,11 @@
 	sata_hba_inst_t *sata_hba_inst =
 	    (sata_hba_inst_t *)(sd->sd_address.a_hba_tran->tran_hba_private);
 	int rval;
+	uint32_t pm_cap;
 
 	rval = scsi_hba_probe(sd, callback);
+	pm_cap = SATA_CAP_POWER_CONDITON | SATA_CAP_SMART_PAGE |
+	    SATA_CAP_LOG_SENSE;
 
 	if (rval == SCSIPROBE_EXISTS) {
 		/*
@@ -1804,7 +1833,7 @@
 		 * before enabling device power-management.
 		 */
 		if ((ddi_prop_update_int(DDI_DEV_T_NONE, sd->sd_dev,
-		    "pm-capable", 1)) != DDI_PROP_SUCCESS) {
+		    "pm-capable", pm_cap)) != DDI_PROP_SUCCESS) {
 			sata_log(sata_hba_inst, CE_WARN,
 			    "SATA device at port %d: "
 			    "will not be power-managed ",
@@ -2148,6 +2177,20 @@
 	}
 	mutex_exit(&(SATA_CPORT_MUTEX(sata_hba_inst, cport)));
 
+	/*
+	 * Checking for power state, if it was on
+	 * STOPPED state, then the drive is not capable
+	 * of processing media access command.  And
+	 * TEST_UNIT_READY, REQUEST_SENSE has special handling
+	 * in the function for different power state.
+	 */
+	if (((sdinfo->satadrv_power_level == SATA_POWER_STANDBY) ||
+	    (sdinfo->satadrv_power_level == SATA_POWER_STOPPED)) &&
+	    (SATA_IS_MEDIUM_ACCESS_CMD(pkt->pkt_cdbp[0]))) {
+		return (sata_txlt_check_condition(spx, KEY_NOT_READY,
+		    SD_SCSI_ASC_LU_NOT_READY));
+	}
+
 	/* ATA Disk commands processing starts here */
 
 	bp = spx->txlt_sata_pkt->satapkt_cmd.satacmd_bp;
@@ -3012,12 +3055,53 @@
 }
 
 /*
+ * Scsi response set up for check condition with special sense key
+ * and additional sense code.
+ *
+ * Returns TRAN_ACCEPT and appropriate values in scsi_pkt fields.
+ */
+static int
+sata_txlt_check_condition(sata_pkt_txlate_t *spx, uchar_t key, uchar_t code)
+{
+	sata_hba_inst_t *shi = SATA_TXLT_HBA_INST(spx);
+	int cport = SATA_TXLT_CPORT(spx);
+	struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt;
+	struct scsi_extended_sense *sense;
+
+	mutex_enter(&SATA_CPORT_MUTEX(shi, cport));
+	scsipkt->pkt_reason = CMD_CMPLT;
+	scsipkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
+	    STATE_SENT_CMD | STATE_GOT_STATUS;
+
+	*scsipkt->pkt_scbp = STATUS_CHECK;
+
+	sense = sata_arq_sense(spx);
+	sense->es_key = key;
+	sense->es_add_code = code;
+
+	mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+
+	SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
+	    "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason);
+
+	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0)
+		/* scsi callback required */
+		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		    (task_func_t *)scsi_hba_pkt_comp,
+		    (void *)spx->txlt_scsi_pkt,
+		    TQ_SLEEP) == NULL)
+			/* Scheduling the callback failed */
+			return (TRAN_BUSY);
+	return (TRAN_ACCEPT);
+}
+
+/*
  * Scsi response setup for
  * emulated non-data command that requires no action/return data
  *
  * Returns TRAN_ACCEPT and appropriate values in scsi_pkt fields.
  */
-static 	int
+static	int
 sata_txlt_nodata_cmd_immediate(sata_pkt_txlate_t *spx)
 {
 	int rval;
@@ -3274,10 +3358,10 @@
 
 /*
  * SATA translate command: Request Sense.
- * Emulated command (ATA version for SATA hard disks)
- * Always NO SENSE, because any sense data should be reported by ARQ sense.
  *
  * Returns TRAN_ACCEPT and appropriate values in scsi_pkt fields.
+ * At the moment this is an emulated command (ATA version for SATA hard disks).
+ * May be translated into Check Power Mode command in the future.
  *
  * Note: There is a mismatch between already implemented Informational
  * Exception Mode Select page 0x1C and this function.
@@ -3291,7 +3375,9 @@
 	struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt;
 	struct scsi_extended_sense sense;
 	struct buf *bp = spx->txlt_sata_pkt->satapkt_cmd.satacmd_bp;
-	int rval, reason;
+	sata_drive_info_t *sdinfo;
+	sata_cmd_t *scmd = &spx->txlt_sata_pkt->satapkt_cmd;
+	int rval, reason, power_state = 0;
 
 	mutex_enter(&(SATA_TXLT_CPORT_MUTEX(spx)));
 
@@ -3300,14 +3386,68 @@
 		mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
 		return (rval);
 	}
-	mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
-
 
 	scsipkt->pkt_reason = CMD_CMPLT;
 	scsipkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
 	    STATE_SENT_CMD | STATE_GOT_STATUS;
 	*scsipkt->pkt_scbp = STATUS_GOOD;
 
+	/*
+	 * when CONTROL field's NACA bit == 1
+	 * return ILLEGAL_REQUEST
+	 */
+	if (scsipkt->pkt_cdbp[5] & CTL_BYTE_NACA_MASK) {
+		mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+		return (sata_txlt_check_condition(spx, KEY_ILLEGAL_REQUEST,
+		    SD_SCSI_ASC_CMD_SEQUENCE_ERR));
+	}
+
+	sdinfo = sata_get_device_info(spx->txlt_sata_hba_inst,
+	    &spx->txlt_sata_pkt->satapkt_device);
+	ASSERT(sdinfo != NULL);
+
+	spx->txlt_sata_pkt->satapkt_op_mode = SATA_OPMODE_SYNCH;
+
+	sata_build_generic_cmd(scmd, SATAC_CHECK_POWER_MODE);
+	scmd->satacmd_flags.sata_copy_out_sec_count_lsb = B_TRUE;
+	scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+	if (sata_hba_start(spx, &rval) != 0) {
+		mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+		return (rval);
+	} else {
+		if (scmd->satacmd_error_reg != 0) {
+			mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+			return (sata_txlt_check_condition(spx, KEY_NO_SENSE,
+			    SD_SCSI_ASC_NO_ADD_SENSE));
+		}
+	}
+
+	switch (scmd->satacmd_sec_count_lsb) {
+	case SATA_PWRMODE_STANDBY: /* device in standby mode */
+		if (sdinfo->satadrv_power_level == SATA_POWER_STOPPED)
+			power_state = SATA_POWER_STOPPED;
+		else {
+			power_state = SATA_POWER_STANDBY;
+			sdinfo->satadrv_power_level = SATA_POWER_STANDBY;
+		}
+		break;
+	case SATA_PWRMODE_IDLE: /* device in idle mode */
+		power_state = SATA_POWER_IDLE;
+		sdinfo->satadrv_power_level = SATA_POWER_IDLE;
+		break;
+	case SATA_PWRMODE_ACTIVE: /* device in active or idle mode */
+	default:		  /* 0x40, 0x41 active mode */
+		if (sdinfo->satadrv_power_level == SATA_POWER_IDLE)
+			power_state = SATA_POWER_IDLE;
+		else {
+			power_state = SATA_POWER_ACTIVE;
+			sdinfo->satadrv_power_level = SATA_POWER_ACTIVE;
+		}
+		break;
+	}
+
+	mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+
 	if (bp != NULL && bp->b_un.b_addr && bp->b_bcount) {
 		/*
 		 * Because it is fully emulated command storing data
@@ -3327,17 +3467,29 @@
 		bcopy(&sense, bp->b_un.b_addr, count);
 		scsipkt->pkt_state |= STATE_XFERRED_DATA;
 		scsipkt->pkt_resid = 0;
+		switch (power_state) {
+		case SATA_POWER_IDLE:
+		case SATA_POWER_STANDBY:
+			sense.es_add_code =
+			    SD_SCSI_ASC_LOW_POWER_CONDITION_ON;
+			break;
+		case SATA_POWER_STOPPED:
+			sense.es_add_code = SD_SCSI_ASC_NO_ADD_SENSE;
+			break;
+		case SATA_POWER_ACTIVE:
+		default:
+			break;
+		}
 	}
 
 	SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
 	    "Scsi_pkt completion reason %x\n",
 	    scsipkt->pkt_reason);
 
-	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
-	    scsipkt->pkt_comp != NULL)
+	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0)
 		/* scsi callback required */
 		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-		    (task_func_t *)scsipkt->pkt_comp, (void *) scsipkt,
+		    (task_func_t *)scsi_hba_pkt_comp, (void *) scsipkt,
 		    TQ_SLEEP) == NULL)
 			/* Scheduling the callback failed */
 			return (TRAN_BUSY);
@@ -3356,6 +3508,8 @@
 {
 	struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt;
 	struct scsi_extended_sense *sense;
+	sata_cmd_t *scmd = &spx->txlt_sata_pkt->satapkt_cmd;
+	sata_drive_info_t *sdinfo;
 	int power_state;
 	int rval, reason;
 
@@ -3366,37 +3520,59 @@
 		mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
 		return (rval);
 	}
-	mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
-
-	/* At this moment, emulate it rather than execute anything */
-	power_state = SATA_PWRMODE_ACTIVE;
+
+	sdinfo = sata_get_device_info(spx->txlt_sata_hba_inst,
+	    &spx->txlt_sata_pkt->satapkt_device);
+	ASSERT(sdinfo != NULL);
+
+	spx->txlt_sata_pkt->satapkt_op_mode = SATA_OPMODE_SYNCH;
+
+	/* send CHECK POWER MODE command */
+	sata_build_generic_cmd(scmd, SATAC_CHECK_POWER_MODE);
+	scmd->satacmd_flags.sata_copy_out_sec_count_lsb = B_TRUE;
+	scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+	if (sata_hba_start(spx, &rval) != 0) {
+		mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+		return (rval);
+	} else {
+		if (scmd->satacmd_error_reg != 0) {
+			mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+			return (sata_txlt_check_condition(spx, KEY_NOT_READY,
+			    SD_SCSI_ASC_LU_NOT_RESPONSE));
+		}
+	}
+
+	power_state = scmd->satacmd_sec_count_lsb;
+
+	/*
+	 * return NOT READY when device in STOPPED mode
+	 */
+	if (power_state == SATA_PWRMODE_STANDBY &&
+	    sdinfo->satadrv_power_level == SATA_POWER_STOPPED) {
+		*scsipkt->pkt_scbp = STATUS_CHECK;
+		sense = sata_arq_sense(spx);
+		sense->es_key = KEY_NOT_READY;
+		sense->es_add_code = SD_SCSI_ASC_LU_NOT_READY;
+	} else {
+		/*
+		 * For other power mode, return GOOD status
+		 */
+		*scsipkt->pkt_scbp = STATUS_GOOD;
+	}
 
 	scsipkt->pkt_reason = CMD_CMPLT;
 	scsipkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
 	    STATE_SENT_CMD | STATE_GOT_STATUS;
 
-	switch (power_state) {
-	case SATA_PWRMODE_ACTIVE:
-	case SATA_PWRMODE_IDLE:
-		*scsipkt->pkt_scbp = STATUS_GOOD;
-		break;
-	default:
-		/* PWR mode standby */
-		*scsipkt->pkt_scbp = STATUS_CHECK;
-		sense = sata_arq_sense(spx);
-		sense->es_key = KEY_NOT_READY;
-		sense->es_add_code = SD_SCSI_ASC_LU_NOT_READY;
-		break;
-	}
+	mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
 
 	SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
 	    "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason);
 
-	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
-	    scsipkt->pkt_comp != NULL)
+	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0)
 		/* scsi callback required */
 		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-		    (task_func_t *)scsipkt->pkt_comp, (void *) scsipkt,
+		    (task_func_t *)scsi_hba_pkt_comp, (void *) scsipkt,
 		    TQ_SLEEP) == NULL)
 			/* Scheduling the callback failed */
 			return (TRAN_BUSY);
@@ -3404,16 +3580,26 @@
 	return (TRAN_ACCEPT);
 }
 
-
 /*
  * SATA translate command: Start Stop Unit
  * Translation depends on a command:
- *	Start Unit translated into Idle Immediate
- *	Stop Unit translated into Standby Immediate
+ *
+ * Power condition bits will be supported
+ * and the power level should be maintained by SATL,
+ * When SATL received a command, it will check the
+ * power level firstly, and return the status according
+ * to SAT2 v2.6 and SAT-2 Standby Modifications
+ *
+ * SPC-4/SBC-3      SATL    ATA power condition  SATL      SPC/SBC
+ * -----------------------------------------------------------------------
+ * SSU_PC1 Active   <==>     ATA  Active         <==>     SSU:start_bit =1
+ * SSU_PC2 Idle     <==>     ATA  Idle           <==>     N/A
+ * SSU_PC3 Standby  <==>     ATA  Standby        <==>     N/A
+ * SSU_PC4 Stopped  <==>     ATA  Standby        <==>     SSU:start_bit = 0
+ *
  *	Unload Media / NOT SUPPORTED YET
  *	Load Media / NOT SUPPROTED YET
- * Power condition bits are ignored, so is Immediate bit
- * Requesting synchronous execution.
+ *	Immediate bit / NOT SUPPORTED YET (deferred error)
  *
  * Returns TRAN_ACCEPT or code returned by sata_hba_start() and
  * appropriate values in scsi_pkt fields.
@@ -3423,11 +3609,11 @@
 {
 	struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt;
 	sata_cmd_t *scmd = &spx->txlt_sata_pkt->satapkt_cmd;
-	struct scsi_extended_sense *sense;
 	sata_hba_inst_t *shi = SATA_TXLT_HBA_INST(spx);
 	int cport = SATA_TXLT_CPORT(spx);
 	int rval, reason;
-	int synch;
+	sata_drive_info_t *sdinfo;
+	sata_id_t *sata_id;
 
 	SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
 	    "sata_txlt_start_stop_unit: %d\n", scsipkt->pkt_scbp[4] & 1);
@@ -3440,81 +3626,304 @@
 		return (rval);
 	}
 
-	if (scsipkt->pkt_cdbp[4] & 2) {
-		/* Load/Unload Media - invalid request */
-		*scsipkt->pkt_scbp = STATUS_CHECK;
-		sense = sata_arq_sense(spx);
-		sense->es_key = KEY_ILLEGAL_REQUEST;
-		sense->es_add_code = SD_SCSI_ASC_INVALID_FIELD_IN_CDB;
-		mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
-
-		SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
-		    "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason);
-
-		if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
-		    scsipkt->pkt_comp != NULL)
-			/* scsi callback required */
-			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-			    (task_func_t *)scsipkt->pkt_comp, (void *) scsipkt,
-			    TQ_SLEEP) == NULL)
-				/* Scheduling the callback failed */
-				return (TRAN_BUSY);
-
-		return (TRAN_ACCEPT);
-	}
-	scmd->satacmd_addr_type = 0;
-	scmd->satacmd_sec_count_lsb = 0;
-	scmd->satacmd_lba_low_lsb = 0;
-	scmd->satacmd_lba_mid_lsb = 0;
-	scmd->satacmd_lba_high_lsb = 0;
-	scmd->satacmd_features_reg = 0;
-	scmd->satacmd_device_reg = 0;
-	scmd->satacmd_status_reg = 0;
-	if (scsipkt->pkt_cdbp[4] & 1) {
-		/* Start Unit */
-		scmd->satacmd_cmd_reg = SATAC_IDLE_IM;
-	} else {
-		/* Stop Unit */
-		scmd->satacmd_cmd_reg = SATAC_STANDBY_IM;
-	}
-
-	if (!(spx->txlt_sata_pkt->satapkt_op_mode & SATA_OPMODE_SYNCH)) {
-		/* Need to set-up a callback function */
-		spx->txlt_sata_pkt->satapkt_comp =
-		    sata_txlt_nodata_cmd_completion;
-		synch = FALSE;
-	} else {
-		spx->txlt_sata_pkt->satapkt_op_mode = SATA_OPMODE_SYNCH;
-		synch = TRUE;
-	}
-
-	/* Transfer command to HBA */
-	if (sata_hba_start(spx, &rval) != 0) {
-		/* Pkt not accepted for execution */
+	if (scsipkt->pkt_cdbp[1] & START_STOP_IMMED_MASK) {
+		/* IMMED bit - not supported */
 		mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
-		return (rval);
-	}
-
-	/*
-	 * If execution is non-synchronous,
-	 * a callback function will handle potential errors, translate
-	 * the response and will do a callback to a target driver.
-	 * If it was synchronous, check execution status using the same
-	 * framework callback.
+		return (sata_txlt_check_condition(spx, KEY_ILLEGAL_REQUEST,
+		    SD_SCSI_ASC_INVALID_FIELD_IN_CDB));
+	}
+
+	spx->txlt_sata_pkt->satapkt_op_mode = SATA_OPMODE_SYNCH;
+	spx->txlt_sata_pkt->satapkt_comp = NULL;
+
+	sdinfo = sata_get_device_info(spx->txlt_sata_hba_inst,
+	    &spx->txlt_sata_pkt->satapkt_device);
+	ASSERT(sdinfo != NULL);
+	sata_id = &sdinfo->satadrv_id;
+
+	switch ((scsipkt->pkt_cdbp[4] & START_STOP_POWER_COND_MASK) >> 4) {
+	case 0:
+		if (scsipkt->pkt_cdbp[4] & START_STOP_LOEJ_MASK) {
+			/* Load/Unload Media - invalid request */
+			goto err_out;
+		}
+		if (scsipkt->pkt_cdbp[4] & START_STOP_START_MASK) {
+			/* Start Unit */
+			sata_build_read_verify_cmd(scmd, 1, 5);
+			scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+			/* Transfer command to HBA */
+			if (sata_hba_start(spx, &rval) != 0) {
+				/* Pkt not accepted for execution */
+				mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+				return (rval);
+			} else {
+				if (scmd->satacmd_error_reg != 0) {
+					goto err_out;
+				}
+			}
+			sdinfo->satadrv_power_level = SATA_POWER_ACTIVE;
+		} else {
+			/* Stop Unit */
+			sata_build_generic_cmd(scmd, SATAC_FLUSH_CACHE);
+			scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+			if (sata_hba_start(spx, &rval) != 0) {
+				mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+				return (rval);
+			} else {
+				if (scmd->satacmd_error_reg != 0) {
+					goto err_out;
+				}
+			}
+			/* ata standby immediate command */
+			sata_build_generic_cmd(scmd, SATAC_STANDBY_IM);
+			scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+			if (sata_hba_start(spx, &rval) != 0) {
+				mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+				return (rval);
+			} else {
+				if (scmd->satacmd_error_reg != 0) {
+					goto err_out;
+				}
+			}
+			sdinfo->satadrv_power_level = SATA_POWER_STOPPED;
+		}
+		break;
+	case 0x1:
+		sata_build_generic_cmd(scmd, SATAC_IDLE);
+		scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+		if (sata_hba_start(spx, &rval) != 0) {
+			mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+			return (rval);
+		} else {
+			if (scmd->satacmd_error_reg != 0) {
+				goto err_out;
+			}
+		}
+		sata_build_read_verify_cmd(scmd, 1, 5);
+		scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+		/* Transfer command to HBA */
+		if (sata_hba_start(spx, &rval) != 0) {
+			/* Pkt not accepted for execution */
+			mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+			return (rval);
+		} else {
+			if (scmd->satacmd_error_reg != 0) {
+				goto err_out;
+			}
+		}
+		sdinfo->satadrv_power_level = SATA_POWER_ACTIVE;
+		break;
+	case 0x2:
+		sata_build_generic_cmd(scmd, SATAC_FLUSH_CACHE);
+		scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+		if (!(scsipkt->pkt_cdbp[4] & START_STOP_NOFLUSH_MASK)) {
+			if (sata_hba_start(spx, &rval) != 0) {
+				mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+				return (rval);
+			} else {
+				if (scmd->satacmd_error_reg != 0) {
+					goto err_out;
+				}
+			}
+		}
+		sata_build_generic_cmd(scmd, SATAC_IDLE);
+		scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+		if (sata_hba_start(spx, &rval) != 0) {
+			mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+			return (rval);
+		} else {
+			if (scmd->satacmd_error_reg != 0) {
+				goto err_out;
+			}
+		}
+		if ((scsipkt->pkt_cdbp[3] & START_STOP_MODIFIER_MASK)) {
+			/*
+			 *  POWER CONDITION MODIFIER bit set
+			 *  to 0x1 or larger it will be handled
+			 *  on the same way as bit = 0x1
+			 */
+			if (!(sata_id->ai_cmdset84 &
+			    SATA_IDLE_UNLOAD_SUPPORTED)) {
+				sdinfo->satadrv_power_level = SATA_POWER_IDLE;
+				break;
+			}
+			sata_build_generic_cmd(scmd, SATAC_IDLE_IM);
+			scmd->satacmd_features_reg = 0x44;
+			scmd->satacmd_lba_low_lsb = 0x4c;
+			scmd->satacmd_lba_mid_lsb = 0x4e;
+			scmd->satacmd_lba_high_lsb = 0x55;
+			scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+			if (sata_hba_start(spx, &rval) != 0) {
+				mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+				return (rval);
+			} else {
+				if (scmd->satacmd_error_reg != 0) {
+					goto err_out;
+				}
+			}
+		}
+		sdinfo->satadrv_power_level = SATA_POWER_IDLE;
+		break;
+	case 0x3:
+		sata_build_generic_cmd(scmd, SATAC_FLUSH_CACHE);
+		scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+		if (!(scsipkt->pkt_cdbp[4] & START_STOP_NOFLUSH_MASK)) {
+			if (sata_hba_start(spx, &rval) != 0) {
+				mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+				return (rval);
+			} else {
+				if (scmd->satacmd_error_reg != 0) {
+					goto err_out;
+				}
+			}
+		}
+		sata_build_generic_cmd(scmd, SATAC_STANDBY);
+		scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+		if (sata_hba_start(spx, &rval) != 0) {
+			mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+			return (rval);
+		} else {
+			if (scmd->satacmd_error_reg != 0) {
+				goto err_out;
+			}
+		}
+		sdinfo->satadrv_power_level = SATA_POWER_STANDBY;
+		break;
+	case 0x7:
+		sata_build_generic_cmd(scmd, SATAC_CHECK_POWER_MODE);
+		scmd->satacmd_flags.sata_copy_out_sec_count_lsb = B_TRUE;
+		scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+		if (sata_hba_start(spx, &rval) != 0) {
+			mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+			return (rval);
+		} else {
+			if (scmd->satacmd_error_reg != 0) {
+				goto err_out;
+			}
+		}
+		switch (scmd->satacmd_sec_count_lsb) {
+		case SATA_PWRMODE_STANDBY:
+			sata_build_generic_cmd(scmd, SATAC_STANDBY);
+			scmd->satacmd_sec_count_msb = sata_get_standby_timer(
+			    sdinfo->satadrv_standby_timer);
+			scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+			if (sata_hba_start(spx, &rval) != 0) {
+				mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+				return (rval);
+			} else {
+				if (scmd->satacmd_error_reg != 0) {
+					goto err_out;
+				}
+			}
+			break;
+		case SATA_PWRMODE_IDLE:
+			sata_build_generic_cmd(scmd, SATAC_IDLE);
+			scmd->satacmd_sec_count_msb = sata_get_standby_timer(
+			    sdinfo->satadrv_standby_timer);
+			scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+			if (sata_hba_start(spx, &rval) != 0) {
+				mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+				return (rval);
+			} else {
+				if (scmd->satacmd_error_reg != 0) {
+					goto err_out;
+				}
+			}
+			break;
+		case SATA_PWRMODE_ACTIVE_SPINDOWN:
+		case SATA_PWRMODE_ACTIVE_SPINUP:
+		case SATA_PWRMODE_ACTIVE:
+			sata_build_generic_cmd(scmd, SATAC_IDLE);
+			scmd->satacmd_sec_count_msb = sata_get_standby_timer(
+			    sdinfo->satadrv_standby_timer);
+			scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+			if (sata_hba_start(spx, &rval) != 0) {
+				mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+				return (rval);
+			} else {
+				if (scmd->satacmd_error_reg != 0) {
+					goto err_out;
+				}
+			}
+			sata_build_read_verify_cmd(scmd, 1, 5);
+			scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+			if (sata_hba_start(spx, &rval) != 0) {
+				mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+				return (rval);
+			} else {
+				if (scmd->satacmd_error_reg != 0) {
+					goto err_out;
+				}
+			}
+			break;
+		default:
+			goto err_out;
+		}
+		break;
+	case 0xb:
+		if ((sata_get_standby_timer(sdinfo->satadrv_standby_timer) ==
+		    0) || (!(sata_id->ai_cap & SATA_STANDBYTIMER))) {
+			mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+			return (sata_txlt_check_condition(spx,
+			    KEY_ILLEGAL_REQUEST,
+			    SD_SCSI_ASC_INVALID_FIELD_IN_CDB));
+		}
+		sata_build_generic_cmd(scmd, SATAC_FLUSH_CACHE);
+		scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+		if (!(scsipkt->pkt_cdbp[4] & START_STOP_NOFLUSH_MASK)) {
+			if (sata_hba_start(spx, &rval) != 0) {
+				mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+				return (rval);
+			} else {
+				if (scmd->satacmd_error_reg != 0) {
+					goto err_out;
+				}
+			}
+			sata_build_generic_cmd(scmd, SATAC_STANDBY_IM);
+			scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+			if (sata_hba_start(spx, &rval) != 0) {
+				mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+				return (rval);
+			} else {
+				if (scmd->satacmd_error_reg != 0) {
+					goto err_out;
+				}
+			}
+		}
+		bzero(sdinfo->satadrv_standby_timer, sizeof (uchar_t) * 4);
+		break;
+	default:
+err_out:
+		mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
+		return (sata_txlt_check_condition(spx, KEY_ILLEGAL_REQUEST,
+		    SD_SCSI_ASC_INVALID_FIELD_IN_CDB));
+	}
+
+	/*
+	 * since it was synchronous commands,
+	 * a callback function will be called directely.
 	 */
 	mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
-	if (synch) {
-		SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
-		    "synchronous execution status %x\n",
-		    spx->txlt_sata_pkt->satapkt_reason);
+	SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
+	    "synchronous execution status %x\n",
+	    spx->txlt_sata_pkt->satapkt_reason);
+
+	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0) {
+		sata_set_arq_data(spx->txlt_sata_pkt);
+		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		    (task_func_t *)scsi_hba_pkt_comp, (void *) scsipkt,
+		    TQ_SLEEP) == 0) {
+			return (TRAN_BUSY);
+		}
+	}
+	else
 
 		sata_txlt_nodata_cmd_completion(spx->txlt_sata_pkt);
-	}
+
 	return (TRAN_ACCEPT);
 
 }
 
-
 /*
  * SATA translate command:  Read Capacity.
  * Emulated command for SATA disks.
@@ -3666,7 +4075,7 @@
 		/* Build mode parameter header */
 		if (spx->txlt_scsi_pkt->pkt_cdbp[0] == SCMD_MODE_SENSE) {
 			/* 4-byte mode parameter header */
-			buf[len++] = 0;   	/* mode data length */
+			buf[len++] = 0;		/* mode data length */
 			buf[len++] = 0;		/* medium type */
 			buf[len++] = 0;		/* dev-specific param */
 			buf[len++] = bdlen;	/* Block Descriptor length */
@@ -3822,7 +4231,7 @@
 		/* fix total mode data length */
 		if (spx->txlt_scsi_pkt->pkt_cdbp[0] == SCMD_MODE_SENSE) {
 			/* 4-byte mode parameter header */
-			buf[0] = len - 1;   	/* mode data length */
+			buf[0] = len - 1;	/* mode data length */
 		} else {
 			buf[0] = (len -2) >> 8;
 			buf[1] = (len -2) & 0xff;
@@ -3887,6 +4296,7 @@
  * - caching page
  * - informational exception page
  * - acoustic management page
+ * - power condition page
  * Caching setup is remembered so it could be re-stored in case of
  * an unexpected device reset.
  *
@@ -4086,6 +4496,30 @@
 				}
 
 				break;
+			case MODEPAGE_POWER_COND:
+				stat = sata_mode_select_page_1a(spx,
+				    (struct mode_info_power_cond *)&buf[len],
+				    pllen, &pagelen, &rval, &dmod);
+				/*
+				 * The pagelen value indicates the number of
+				 * parameter bytes already processed.
+				 * The rval is the return value from
+				 * sata_tran_start().
+				 * The stat indicates the overall status of
+				 * the operation(s).
+				 */
+				if (stat != SATA_SUCCESS)
+					/*
+					 * Page processing did not succeed -
+					 * all error info is already set-up,
+					 * just return
+					 */
+					pllen = 0; /* this breaks the loop */
+				else {
+					len += pagelen;
+					pllen -= pagelen;
+				}
+				break;
 			default:
 				*scsipkt->pkt_scbp = STATUS_CHECK;
 				sense = sata_arq_sense(spx);
@@ -4246,6 +4680,7 @@
 	case PAGE_CODE_SELF_TEST_RESULTS:
 	case PAGE_CODE_INFORMATION_EXCEPTIONS:
 	case PAGE_CODE_SMART_READ_DATA:
+	case PAGE_CODE_START_STOP_CYCLE_COUNTER:
 		break;
 	default:
 		*scsipkt->pkt_scbp = STATUS_CHECK;
@@ -4356,6 +4791,30 @@
 			len = sata_build_lsense_page_30(sdinfo, buf,
 			    spx->txlt_sata_hba_inst);
 			goto no_header;
+		case PAGE_CODE_START_STOP_CYCLE_COUNTER:
+			sata_id = &sdinfo->satadrv_id;
+			if (! (sata_id->ai_cmdset82 & SATA_SMART_SUPPORTED)) {
+				*scsipkt->pkt_scbp = STATUS_CHECK;
+				sense = sata_arq_sense(spx);
+				sense->es_key = KEY_ILLEGAL_REQUEST;
+				sense->es_add_code =
+				    SD_SCSI_ASC_INVALID_FIELD_IN_CDB;
+
+				goto done;
+			}
+			if (! (sata_id->ai_features85 & SATA_SMART_ENABLED)) {
+				*scsipkt->pkt_scbp = STATUS_CHECK;
+				sense = sata_arq_sense(spx);
+				sense->es_key = KEY_ABORTED_COMMAND;
+				sense->es_add_code =
+				    SCSI_ASC_ATA_DEV_FEAT_NOT_ENABLED;
+				sense->es_qual_code =
+				    SCSI_ASCQ_ATA_DEV_FEAT_NOT_ENABLED;
+
+				goto done;
+			}
+			len = sata_build_lsense_page_0e(sdinfo, buf, spx);
+			goto no_header;
 		default:
 			/* Invalid request */
 			*scsipkt->pkt_scbp = STATUS_CHECK;
@@ -4414,7 +4873,7 @@
  * Translate command: Log Select
  * Not implemented at this time - returns invalid command response.
  */
-static 	int
+static	int
 sata_txlt_log_select(sata_pkt_txlate_t *spx)
 {
 	SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
@@ -5831,12 +6290,26 @@
  * This function may be used only if scsi_pkt is non-NULL.
  */
 
-static 	void
+static	void
 sata_txlt_nodata_cmd_completion(sata_pkt_t *sata_pkt)
 {
 	sata_pkt_txlate_t *spx =
 	    (sata_pkt_txlate_t *)sata_pkt->satapkt_framework_private;
 	struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt;
+
+	sata_set_arq_data(sata_pkt);
+
+	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0)
+		/* scsi callback required */
+		scsi_hba_pkt_comp(scsipkt);
+}
+
+static	void
+sata_set_arq_data(sata_pkt_t *sata_pkt)
+{
+	sata_pkt_txlate_t *spx =
+	    (sata_pkt_txlate_t *)sata_pkt->satapkt_framework_private;
+	struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt;
 	struct scsi_extended_sense *sense;
 
 	scsipkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
@@ -5902,10 +6375,6 @@
 	}
 	SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
 	    "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason);
-
-	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0)
-		/* scsi callback required */
-		scsi_hba_pkt_comp(scsipkt);
 }
 
 
@@ -6082,20 +6551,36 @@
 
 
 /*
- * Build Mode sense power condition page
- * NOT IMPLEMENTED.
+ * Build Mode sense power condition page.
  */
 static int
 sata_build_msense_page_1a(sata_drive_info_t *sdinfo, int pcntrl, uint8_t *buf)
 {
-#ifndef __lock_lint
-	_NOTE(ARGUNUSED(sdinfo))
-	_NOTE(ARGUNUSED(pcntrl))
-	_NOTE(ARGUNUSED(buf))
-#endif
-	return (0);
-}
-
+	struct mode_info_power_cond *page = (struct mode_info_power_cond *)buf;
+	sata_id_t *sata_id = &sdinfo->satadrv_id;
+
+	/*
+	 * Most of the fields are set to 0, being not supported and/or disabled
+	 * power condition page length was 0x0a
+	 */
+	bzero(buf, sizeof (struct mode_info_power_cond));
+
+	if (pcntrl == P_CNTRL_DEFAULT) {
+		/*  default paramters not supported */
+		return (0);
+	}
+
+	page->mode_page.code = MODEPAGE_POWER_COND;
+	page->mode_page.length = sizeof (struct mode_info_power_cond);
+
+	if (sata_id->ai_cap && SATA_STANDBYTIMER) {
+		page->standby = 1;
+		bcopy(sdinfo->satadrv_standby_timer, page->standby_cond_timer,
+		    sizeof (uchar_t) * 4);
+	}
+
+	return (sizeof (struct mode_info_power_cond));
+}
 
 /*
  * Process mode select caching page 8 (scsi3 format only).
@@ -6453,16 +6938,96 @@
 	return (SATA_SUCCESS);
 }
 
-
-
+/*
+ * Process mode select power condition page 0x1a
+ *
+ * This function has to be called with a port mutex held.
+ *
+ * Returns SATA_SUCCESS if operation was successful, SATA_FAILURE otherwise.
+ *
+ * Cannot be called in the interrupt context.
+ */
+int
+sata_mode_select_page_1a(sata_pkt_txlate_t *spx, struct
+    mode_info_power_cond *page, int parmlen, int *pagelen,
+    int *rval, int *dmod)
+{
+	struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt;
+	sata_drive_info_t *sdinfo;
+	sata_cmd_t *scmd = &spx->txlt_sata_pkt->satapkt_cmd;
+	sata_id_t *sata_id;
+	struct scsi_extended_sense *sense;
+	uint8_t ata_count;
+	int i, len;
+
+	sdinfo = sata_get_device_info(spx->txlt_sata_hba_inst,
+	    &spx->txlt_sata_pkt->satapkt_device);
+	sata_id = &sdinfo->satadrv_id;
+	*dmod = 0;
+
+	len = sizeof (struct mode_info_power_cond);
+	len += sizeof (struct mode_page);
+
+	/* If parmlen is too short or the feature is not supported, drop it */
+	if ((len < parmlen) || (page->idle == 1) ||
+	    (!(sata_id->ai_cap && SATA_STANDBYTIMER) && page->standby == 1)) {
+		*scsipkt->pkt_scbp = STATUS_CHECK;
+		sense = sata_arq_sense(spx);
+		sense->es_key = KEY_ILLEGAL_REQUEST;
+		sense->es_add_code = SD_SCSI_ASC_INVALID_FIELD_IN_PARAMS_LIST;
+		*pagelen = parmlen;
+		*rval = TRAN_ACCEPT;
+		return (SATA_FAILURE);
+	}
+
+	*pagelen = len;
+
+	/*
+	 * Set-up Internal STANDBY command(s)
+	 */
+	if (page->standby == 0)
+		goto out;
+
+	ata_count = sata_get_standby_timer(page->standby_cond_timer);
+
+	scmd->satacmd_addr_type = 0;
+	scmd->satacmd_sec_count_lsb = ata_count;
+	scmd->satacmd_lba_low_lsb = 0;
+	scmd->satacmd_lba_mid_lsb = 0;
+	scmd->satacmd_lba_high_lsb = 0;
+	scmd->satacmd_features_reg = 0;
+	scmd->satacmd_device_reg = 0;
+	scmd->satacmd_status_reg = 0;
+	scmd->satacmd_cmd_reg = SATAC_STANDBY;
+	scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE;
+
+	/* Transfer command to HBA */
+	if (sata_hba_start(spx, rval) != 0) {
+		return (SATA_FAILURE);
+	} else {
+		if ((scmd->satacmd_error_reg != 0) ||
+		    (spx->txlt_sata_pkt->satapkt_reason !=
+		    SATA_PKT_COMPLETED)) {
+			sata_xlate_errors(spx);
+			return (SATA_FAILURE);
+		}
+	}
+
+	for (i = 0; i < 4; i++) {
+		sdinfo->satadrv_standby_timer[i] = page->standby_cond_timer[i];
+	}
+out:
+	*dmod = 1;
+	return (SATA_SUCCESS);
+}
 
 /*
  * sata_build_lsense_page0() is used to create the
  * SCSI LOG SENSE page 0 (supported log pages)
  *
- * Currently supported pages are 0, 0x10, 0x2f and 0x30
+ * Currently supported pages are 0, 0x10, 0x2f, 0x30 and 0x0e
  * (supported log pages, self-test results, informational exceptions
- *  and Sun vendor specific ATA SMART data).
+ * Sun vendor specific ATA SMART data, and start stop cycle counter).
  *
  * Takes a sata_drive_info t * and the address of a buffer
  * in which to create the page information.
@@ -6491,6 +7056,8 @@
 		++num_pages_supported;
 		*page_ptr++ = PAGE_CODE_SMART_READ_DATA;
 		++num_pages_supported;
+		*page_ptr++ = PAGE_CODE_START_STOP_CYCLE_COUNTER;
+		++num_pages_supported;
 	}
 
 	lpp->param_len = num_pages_supported;
@@ -7022,6 +7589,171 @@
 	return (sizeof (struct smart_data));
 }
 
+/*
+ * sata_build_lsense_page_0e() is used to create the
+ * SCSI LOG SENSE page 0e (supported log pages)
+ *
+ * Date of Manufacture (0x0001)
+ *	YEAR = "0000"
+ *	WEEK = "00"
+ * Accounting Date (0x0002)
+ *	6 ASCII space character(20h)
+ * Specified cycle count over device lifetime
+ *	VALUE - THRESH - the delta between max and min;
+ * Accumulated start-stop cycles
+ *	VALUE - WORST - the accumulated cycles;
+ *
+ * ID FLAG THRESH VALUE WORST RAW on start/stop counter attribute
+ *
+ * Takes a sata_drive_info t * and the address of a buffer
+ * in which to create the page information as well as a sata_hba_inst_t *.
+ *
+ * Returns the number of bytes valid in the buffer.
+ */
+static	int
+sata_build_lsense_page_0e(sata_drive_info_t *sdinfo, uint8_t *buf,
+	sata_pkt_txlate_t *spx)
+{
+	struct start_stop_cycle_counter_log *log_page;
+	int i, rval, index;
+	uint8_t smart_data[512], id, value, worst, thresh;
+	uint32_t max_count, cycles;
+
+	/* Now do the SMART READ DATA */
+	rval = sata_fetch_smart_data(spx->txlt_sata_hba_inst, sdinfo,
+	    (struct smart_data *)smart_data);
+	if (rval == -1)
+		return (0);
+	for (i = 0, id = 0; i < SMART_START_STOP_COUNT_ID * 2; i++) {
+		index = (i * 12) + 2;
+		id = smart_data[index];
+		if (id != SMART_START_STOP_COUNT_ID)
+			continue;
+		else {
+			thresh = smart_data[index + 2];
+			value = smart_data[index + 3];
+			worst = smart_data[index + 4];
+			break;
+		}
+	}
+	if (id != SMART_START_STOP_COUNT_ID)
+		return (0);
+	max_count = value - thresh;
+	cycles = value - worst;
+
+	log_page = (struct start_stop_cycle_counter_log *)buf;
+	bzero(log_page, sizeof (struct start_stop_cycle_counter_log));
+	log_page->code = 0x0e;
+	log_page->page_len_low = 0x24;
+
+	log_page->manufactor_date_low = 0x1;
+	log_page->param_1.fmt_link = 0x1; /* 01b */
+	log_page->param_len_1 = 0x06;
+	for (i = 0; i < 4; i++) {
+		log_page->year_manu[i] = 0x30;
+		if (i < 2)
+			log_page->week_manu[i] = 0x30;
+	}
+
+	log_page->account_date_low = 0x02;
+	log_page->param_2.fmt_link = 0x01; /* 01b */
+	log_page->param_len_2 = 0x06;
+	for (i = 0; i < 4; i++) {
+		log_page->year_account[i] = 0x20;
+		if (i < 2)
+			log_page->week_account[i] = 0x20;
+	}
+
+	log_page->lifetime_code_low = 0x03;
+	log_page->param_3.fmt_link = 0x03; /* 11b */
+	log_page->param_len_3 = 0x04;
+	/* VALUE - THRESH - the delta between max and min */
+	log_page->cycle_code_low = 0x04;
+	log_page->param_4.fmt_link = 0x03; /* 11b */
+	log_page->param_len_4 = 0x04;
+	/* WORST - THRESH - the distance from 'now' to min */
+
+	for (i = 0; i < 4; i++) {
+		log_page->cycle_lifetime[i] =
+		    (max_count >> (8 * (3 - i))) & 0xff;
+		log_page->cycle_accumulated[i] =
+		    (cycles >> (8 * (3 - i))) & 0xff;
+	}
+
+	return (sizeof (struct start_stop_cycle_counter_log));
+}
+
+/*
+ * This function was used for build a ATA read verify sector command
+ */
+static void
+sata_build_read_verify_cmd(sata_cmd_t *scmd, uint16_t sec, uint64_t lba)
+{
+	scmd->satacmd_cmd_reg = SATAC_RDVER;
+	scmd->satacmd_addr_type = ATA_ADDR_LBA28;
+
+	scmd->satacmd_sec_count_lsb = sec & 0xff;
+	scmd->satacmd_lba_low_lsb = lba & 0xff;
+	scmd->satacmd_lba_mid_lsb = (lba >> 8) & 0xff;
+	scmd->satacmd_lba_high_lsb = (lba >> 16) & 0xff;
+	scmd->satacmd_device_reg = (SATA_ADH_LBA | (lba >> 24) & 0xf);
+	scmd->satacmd_features_reg = 0;
+	scmd->satacmd_status_reg = 0;
+	scmd->satacmd_error_reg = 0;
+}
+
+/*
+ * This function was used for building an ATA
+ * command, and only command register need to
+ * be defined, other register will be zero or na.
+ */
+static void
+sata_build_generic_cmd(sata_cmd_t *scmd, uint8_t cmd)
+{
+	scmd->satacmd_addr_type = 0;
+	scmd->satacmd_cmd_reg = cmd;
+	scmd->satacmd_device_reg = 0;
+	scmd->satacmd_sec_count_lsb = 0;
+	scmd->satacmd_lba_low_lsb = 0;
+	scmd->satacmd_lba_mid_lsb = 0;
+	scmd->satacmd_lba_high_lsb = 0;
+	scmd->satacmd_features_reg = 0;
+	scmd->satacmd_status_reg = 0;
+	scmd->satacmd_error_reg = 0;
+}
+
+/*
+ * This function was used for changing the standby
+ * timer format from SCSI to ATA.
+ */
+static uint8_t
+sata_get_standby_timer(uint8_t *timer)
+{
+	uint32_t i = 0, count = 0;
+	uint8_t ata_count;
+
+	for (i = 0; i < 4; i++) {
+		count = count << 8 | timer[i];
+	}
+
+	if (count == 0)
+		return (0);
+
+	if (count >= 1 && count <= 12000)
+		ata_count = (count -1) / 50 + 1;
+	else if (count > 12000 && count <= 12600)
+		ata_count = 0xfc;
+	else if (count > 12601 && count <= 12750)
+		ata_count = 0xff;
+	else if (count > 12750 && count <= 17999)
+		ata_count = 0xf1;
+	else if (count > 18000 && count <= 198000)
+		ata_count = count / 18000 + 240;
+	else
+		ata_count = 0xfd;
+	return (ata_count);
+}
+
 /* ************************** ATAPI-SPECIFIC FUNCTIONS ********************** */
 
 /*
@@ -8967,6 +9699,10 @@
 		/* DMA supported, not no DMA transfer mode is selected !? */
 		sdinfo->satadrv_settings &= ~SATA_DEV_DMA;
 
+	if ((sdinfo->satadrv_id.ai_cmdset83 & 0x20) &&
+	    (sdinfo->satadrv_id.ai_features86 & 0x20))
+		sdinfo->satadrv_power_level = SATA_POWER_STANDBY;
+
 	return (rval);
 }
 
@@ -13825,7 +14561,7 @@
 sata_log(sata_hba_inst_t *sata_hba_inst, uint_t level, char *fmt, ...)
 {
 	char pathname[128];
-	dev_info_t *dip;
+	dev_info_t *dip = NULL;
 	va_list ap;
 
 	mutex_enter(&sata_log_mutex);
@@ -13854,6 +14590,9 @@
 		}
 	}
 
+	/* sata trace debug */
+	sata_trace_debug(dip, sata_log_buf);
+
 	mutex_exit(&sata_log_mutex);
 }
 
@@ -15835,7 +16574,7 @@
  */
 
 
-static	void
+static void
 sata_inject_pkt_fault(sata_pkt_t *spkt, int *rval, int fault)
 {
 
@@ -15950,3 +16689,232 @@
 }
 
 #endif
+
+/*
+ * SATA Trace Ring Buffer
+ * ----------------------
+ *
+ * Overview
+ *
+ * The SATA trace ring buffer is a ring buffer created and managed by
+ * the SATA framework module that can be used by any module or driver
+ * within the SATA framework to store debug messages.
+ *
+ * Ring Buffer Interfaces:
+ *
+ *	sata_vtrace_debug()	<-- Adds debug message to ring buffer
+ *	sata_trace_debug()	<-- Wraps varargs into sata_vtrace_debug()
+ *
+ *	Note that the sata_trace_debug() interface was created to give
+ *	consumers the flexibilty of sending debug messages to ring buffer
+ *	as variable arguments.  Consumers can send type va_list debug
+ *	messages directly to sata_vtrace_debug(). The sata_trace_debug()
+ *	and sata_vtrace_debug() relationship is similar to that of
+ *	cmn_err(9F) and vcmn_err(9F).
+ *
+ * Below is a diagram of the SATA trace ring buffer interfaces and
+ * sample consumers:
+ *
+ * +---------------------------------+
+ * |    o  o  SATA Framework Module  |
+ * | o  SATA  o     +------------------+      +------------------+
+ * |o   Trace  o <--|sata_vtrace_debug/|<-----|SATA HBA Driver #1|
+ * |o   R-Buf  o    |sata_trace_debug  |<--+  +------------------+
+ * | o        o     +------------------+   |  +------------------+
+ * |    o  o                ^        |     +--|SATA HBA Driver #2|
+ * |                        |        |        +------------------+
+ * |           +------------------+  |
+ * |           |SATA Debug Message|  |
+ * |           +------------------+  |
+ * +---------------------------------+
+ *
+ * Supporting Routines:
+ *
+ *	sata_trace_rbuf_alloc()	<-- Initializes ring buffer
+ *	sata_trace_rbuf_free()	<-- Destroys ring buffer
+ *	sata_trace_dmsg_alloc() <-- Creates or reuses buffer in ring buffer
+ *	sata_trace_dmsg_free()	<-- Destroys content of ring buffer
+ *
+ * The default SATA trace ring buffer size is defined by DMSG_RING_SIZE.
+ * The ring buffer size can be adjusted by setting dmsg_ring_size in
+ * /etc/system to desired size in unit of bytes.
+ *
+ * The individual debug message size in the ring buffer is restricted
+ * to DMSG_BUF_SIZE.
+ */
+void
+sata_vtrace_debug(dev_info_t *dip, const char *fmt, va_list ap)
+{
+	sata_trace_dmsg_t *dmsg;
+
+	if (sata_debug_rbuf == NULL) {
+		return;
+	}
+
+	/*
+	 * If max size of ring buffer is smaller than size
+	 * required for one debug message then just return
+	 * since we have no room for the debug message.
+	 */
+	if (sata_debug_rbuf->maxsize < (sizeof (sata_trace_dmsg_t))) {
+		return;
+	}
+
+	mutex_enter(&sata_debug_rbuf->lock);
+
+	/* alloc or reuse on ring buffer */
+	dmsg = sata_trace_dmsg_alloc();
+
+	if (dmsg == NULL) {
+		/* resource allocation failed */
+		mutex_exit(&sata_debug_rbuf->lock);
+		return;
+	}
+
+	dmsg->dip = dip;
+	gethrestime(&dmsg->timestamp);
+
+	(void) vsnprintf(dmsg->buf, sizeof (dmsg->buf), fmt, ap);
+
+	mutex_exit(&sata_debug_rbuf->lock);
+}
+
+void
+sata_trace_debug(dev_info_t *dip, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	sata_vtrace_debug(dip, fmt, ap);
+	va_end(ap);
+}
+
+/*
+ * This routine is used to manage debug messages
+ * on ring buffer.
+ */
+static sata_trace_dmsg_t *
+sata_trace_dmsg_alloc(void)
+{
+	sata_trace_dmsg_t *dmsg_alloc, *dmsg = sata_debug_rbuf->dmsgp;
+
+	if (sata_debug_rbuf->looped == TRUE) {
+		sata_debug_rbuf->dmsgp = dmsg->next;
+		return (sata_debug_rbuf->dmsgp);
+	}
+
+	/*
+	 * If we're looping for the first time,
+	 * connect the ring.
+	 */
+	if (((sata_debug_rbuf->size + (sizeof (sata_trace_dmsg_t))) >
+	    sata_debug_rbuf->maxsize) && (sata_debug_rbuf->dmsgh != NULL)) {
+		dmsg->next = sata_debug_rbuf->dmsgh;
+		sata_debug_rbuf->dmsgp = sata_debug_rbuf->dmsgh;
+		sata_debug_rbuf->looped = TRUE;
+		return (sata_debug_rbuf->dmsgp);
+	}
+
+	/* If we've gotten this far then memory allocation is needed */
+	dmsg_alloc = kmem_zalloc(sizeof (sata_trace_dmsg_t), KM_NOSLEEP);
+	if (dmsg_alloc == NULL) {
+		sata_debug_rbuf->allocfailed++;
+		return (dmsg_alloc);
+	} else {
+		sata_debug_rbuf->size += sizeof (sata_trace_dmsg_t);
+	}
+
+	if (sata_debug_rbuf->dmsgp != NULL) {
+		dmsg->next = dmsg_alloc;
+		sata_debug_rbuf->dmsgp = dmsg->next;
+		return (sata_debug_rbuf->dmsgp);
+	} else {
+		/*
+		 * We should only be here if we're initializing
+		 * the ring buffer.
+		 */
+		if (sata_debug_rbuf->dmsgh == NULL) {
+			sata_debug_rbuf->dmsgh = dmsg_alloc;
+		} else {
+			/* Something is wrong */
+			kmem_free(dmsg_alloc, sizeof (sata_trace_dmsg_t));
+			return (NULL);
+		}
+
+		sata_debug_rbuf->dmsgp = dmsg_alloc;
+		return (sata_debug_rbuf->dmsgp);
+	}
+}
+
+
+/*
+ * Free all messages on debug ring buffer.
+ */
+static void
+sata_trace_dmsg_free(void)
+{
+	sata_trace_dmsg_t *dmsg_next, *dmsg = sata_debug_rbuf->dmsgh;
+
+	while (dmsg != NULL) {
+		dmsg_next = dmsg->next;
+		kmem_free(dmsg, sizeof (sata_trace_dmsg_t));
+
+		/*
+		 * If we've looped around the ring than we're done.
+		 */
+		if (dmsg_next == sata_debug_rbuf->dmsgh) {
+			break;
+		} else {
+			dmsg = dmsg_next;
+		}
+	}
+}
+
+
+/*
+ * This function can block
+ */
+static void
+sata_trace_rbuf_alloc(void)
+{
+	sata_debug_rbuf = kmem_zalloc(sizeof (sata_trace_rbuf_t), KM_SLEEP);
+
+	mutex_init(&sata_debug_rbuf->lock, NULL, MUTEX_DRIVER, NULL);
+
+	if (dmsg_ring_size > 0) {
+		sata_debug_rbuf->maxsize = (size_t)dmsg_ring_size;
+	}
+}
+
+
+static void
+sata_trace_rbuf_free(void)
+{
+	sata_trace_dmsg_free();
+	mutex_destroy(&sata_debug_rbuf->lock);
+	kmem_free(sata_debug_rbuf, sizeof (sata_trace_rbuf_t));
+}
+
+/*
+ * If SATA_DEBUG is not defined then this routine is called instead
+ * of sata_log() via the SATA_LOG_D macro.
+ */
+static void
+sata_trace_log(sata_hba_inst_t *sata_hba_inst, uint_t level,
+    const char *fmt, ...)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(level))
+#endif
+
+	dev_info_t *dip = NULL;
+	va_list ap;
+
+	if (sata_hba_inst != NULL) {
+		dip = SATA_DIP(sata_hba_inst);
+	}
+
+	va_start(ap, fmt);
+	sata_vtrace_debug(dip, fmt, ap);
+	va_end(ap);
+}
--- a/usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci.c	Mon Jul 20 13:07:46 2009 -0400
@@ -7201,7 +7201,8 @@
 	}
 	dvlp->svl_fops_name = NULL;
 
-	if (dvlp->svl_fops_ctpriv != NULL) {
+	if (dvlp->svl_fops_ctpriv != NULL &&
+	    dvlp->svl_fops != NULL) {
 		dvlp->svl_fops->sfo_device_unprobe(sd, dvlp->svl_fops_ctpriv);
 	}
 
--- a/usr/src/uts/common/io/scsi/targets/sd.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/scsi/targets/sd.c	Mon Jul 20 13:07:46 2009 -0400
@@ -354,6 +354,33 @@
 _NOTE(MUTEX_PROTECTS_DATA(sd_scsi_probe_cache_mutex,
     sd_scsi_probe_cache_head))
 
+/*
+ * Power attribute table
+ */
+static sd_power_attr_ss sd_pwr_ss = {
+	{ "NAME=spindle-motor", "0=off", "1=on", NULL },
+	{0, 100},
+	{30, 0},
+	{20000, 0}
+};
+
+static sd_power_attr_pc sd_pwr_pc = {
+	{ "NAME=spindle-motor", "0=stopped", "1=standby", "2=idle",
+		"3=active", NULL },
+	{0, 0, 0, 100},
+	{90, 90, 20, 0},
+	{15000, 15000, 1000, 0}
+};
+
+/*
+ * Power level to power condition
+ */
+static int sd_pl2pc[] = {
+	SD_TARGET_START_VALID,
+	SD_TARGET_STANDBY,
+	SD_TARGET_IDLE,
+	SD_TARGET_ACTIVE
+};
 
 /*
  * Vendor specific data name property declarations
@@ -707,6 +734,7 @@
 		SD_CONF_BSET_LUN_RESET_ENABLED,
 		&pirus_properties },
 	{ "SUN     STK6580_6780", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
+	{ "SUN     SUN_6180", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
 	{ "STK     OPENstorage", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
 	{ "STK     OpenStorage", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
 	{ "STK     BladeCtlr",	SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
@@ -863,9 +891,8 @@
 #define	sd_setup_pm			ssd_setup_pm
 #define	sd_create_pm_components		ssd_create_pm_components
 #define	sd_ddi_suspend			ssd_ddi_suspend
-#define	sd_ddi_pm_suspend		ssd_ddi_pm_suspend
 #define	sd_ddi_resume			ssd_ddi_resume
-#define	sd_ddi_pm_resume		ssd_ddi_pm_resume
+#define	sd_pm_state_change		ssd_pm_state_change
 #define	sdpower				ssdpower
 #define	sdattach			ssdattach
 #define	sddetach			ssddetach
@@ -1205,9 +1232,8 @@
 static void sd_create_pm_components(dev_info_t *devi, struct sd_lun *un);
 
 static int  sd_ddi_suspend(dev_info_t *devi);
-static int  sd_ddi_pm_suspend(struct sd_lun *un);
 static int  sd_ddi_resume(dev_info_t *devi);
-static int  sd_ddi_pm_resume(struct sd_lun *un);
+static int  sd_pm_state_change(struct sd_lun *un, int level, int flag);
 static int  sdpower(dev_info_t *devi, int component, int level);
 
 static int  sdattach(dev_info_t *devi, ddi_attach_cmd_t cmd);
@@ -1466,8 +1492,8 @@
 	uint32_t *lbap, int path_flag);
 static int sd_send_scsi_READ_CAPACITY_16(sd_ssc_t *ssc, uint64_t *capp,
 	uint32_t *lbap, uint32_t *psp, int path_flag);
-static int sd_send_scsi_START_STOP_UNIT(sd_ssc_t *ssc, int flag,
-	int path_flag);
+static int sd_send_scsi_START_STOP_UNIT(sd_ssc_t *ssc, int pc_flag,
+	int flag, int path_flag);
 static int sd_send_scsi_INQUIRY(sd_ssc_t *ssc, uchar_t *bufaddr,
 	size_t buflen, uchar_t evpd, uchar_t page_code, size_t *residp);
 static int sd_send_scsi_TEST_UNIT_READY(sd_ssc_t *ssc, int flag);
@@ -3176,9 +3202,11 @@
 	 * condition (0x2/0x4/0x3) if the device is "inactive," but
 	 * we don't want to fail the attach because it may become
 	 * "active" later.
-	 */
-	status = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_START,
-	    SD_PATH_DIRECT);
+	 * We don't know if power condition is supported or not at
+	 * this stage, use START STOP bit.
+	 */
+	status = sd_send_scsi_START_STOP_UNIT(ssc, SD_START_STOP,
+	    SD_TARGET_START, SD_PATH_DIRECT);
 
 	if (status != 0) {
 		if (status == EACCES)
@@ -4021,6 +4049,20 @@
 		return;
 	}
 
+	if (strcasecmp(name, "power-condition") == 0) {
+		if (strcasecmp(value, "true") == 0) {
+			un->un_f_power_condition_disabled = FALSE;
+		} else if (strcasecmp(value, "false") == 0) {
+			un->un_f_power_condition_disabled = TRUE;
+		} else {
+			goto value_invalid;
+		}
+		SD_INFO(SD_LOG_ATTACH_DETACH, un, "sd_set_properties: "
+		    "power condition disabled flag set to %d\n",
+		    un->un_f_power_condition_disabled);
+		return;
+	}
+
 	if (strcasecmp(name, "timeout-releasereservation") == 0) {
 		if (ddi_strtol(value, &endptr, 0, &val) == 0) {
 			un->un_reserve_release_time = val;
@@ -4232,6 +4274,12 @@
 			    suppress_cache_flush = %d"
 			    "\n", values->sdt_suppress_cache_flush);
 			break;
+		case SD_CONF_BSET_PC_DISABLED:
+			values->sdt_disk_sort_dis = data_list[i];
+			SD_INFO(SD_LOG_ATTACH_DETACH, un,
+			    "sd_get_tunables_from_conf: power_condition_dis = "
+			    "%d\n", values->sdt_power_condition_dis);
+			break;
 		}
 	}
 }
@@ -4713,6 +4761,16 @@
 		    prop_list->sdt_suppress_cache_flush);
 	}
 
+	if (flags & SD_CONF_BSET_PC_DISABLED) {
+		un->un_f_power_condition_disabled =
+		    (prop_list->sdt_power_condition_dis != 0) ?
+		    TRUE : FALSE;
+		SD_INFO(SD_LOG_ATTACH_DETACH, un,
+		    "sd_set_vers1_properties: power_condition_disabled "
+		    "flag set to %d\n",
+		    prop_list->sdt_power_condition_dis);
+	}
+
 	/*
 	 * Validate the throttle values.
 	 * If any of the numbers are invalid, set everything to defaults.
@@ -5751,6 +5809,9 @@
 	 * This complies with the new power management framework
 	 * for certain desktop machines. Create the pm_components
 	 * property as a string array property.
+	 * If un_f_pm_supported is TRUE, that means the disk
+	 * attached HBA has set the "pm-capable" property and
+	 * the value of this property is bigger than 0.
 	 */
 	if (un->un_f_pm_supported) {
 		/*
@@ -5761,9 +5822,19 @@
 		 * device has a motor.
 		 */
 		un->un_f_start_stop_supported = TRUE;
-		rval = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_START,
-		    SD_PATH_DIRECT);
-
+
+		if (un->un_f_power_condition_supported) {
+			rval = sd_send_scsi_START_STOP_UNIT(ssc,
+			    SD_POWER_CONDITION, SD_TARGET_ACTIVE,
+			    SD_PATH_DIRECT);
+			if (rval != 0) {
+				un->un_f_power_condition_supported = FALSE;
+			}
+		}
+		if (!un->un_f_power_condition_supported) {
+			rval = sd_send_scsi_START_STOP_UNIT(ssc,
+			    SD_START_STOP, SD_TARGET_START, SD_PATH_DIRECT);
+		}
 		if (rval != 0) {
 			sd_ssc_assessment(ssc, SD_FMT_IGNORE);
 			un->un_f_start_stop_supported = FALSE;
@@ -5773,11 +5844,39 @@
 		 * create pm properties anyways otherwise the parent can't
 		 * go to sleep
 		 */
+		un->un_f_pm_is_enabled = TRUE;
 		(void) sd_create_pm_components(devi, un);
-		un->un_f_pm_is_enabled = TRUE;
-		return;
-	}
-
+
+		/*
+		 * If it claims that log sense is supported, check it out.
+		 */
+		if (un->un_f_log_sense_supported) {
+			rval = sd_log_page_supported(ssc,
+			    START_STOP_CYCLE_PAGE);
+			if (rval == 1) {
+				/* Page found, use it. */
+				un->un_start_stop_cycle_page =
+				    START_STOP_CYCLE_PAGE;
+			} else {
+				/*
+				 * Page not found or log sense is not
+				 * supported.
+				 * Notice we do not check the old style
+				 * START_STOP_CYCLE_VU_PAGE because this
+				 * code path does not apply to old disks.
+				 */
+				un->un_f_log_sense_supported = FALSE;
+				un->un_f_pm_log_sense_smart = FALSE;
+			}
+		}
+
+		return;
+	}
+
+	/*
+	 * For the disk whose attached HBA has not set the "pm-capable"
+	 * property, check if it supports the power management.
+	 */
 	if (!un->un_f_log_sense_supported) {
 		un->un_power_level = SD_SPINDLE_ON;
 		un->un_f_pm_is_enabled = FALSE;
@@ -5795,7 +5894,7 @@
 
 	/*
 	 * If the start-stop cycle counter log page is not supported
-	 * or if the pm-capable property is SD_PM_CAPABLE_FALSE (0)
+	 * or if the pm-capable property is set to be false (0),
 	 * then we should not create the pm_components property.
 	 */
 	if (rval == -1) {
@@ -5885,44 +5984,53 @@
 static void
 sd_create_pm_components(dev_info_t *devi, struct sd_lun *un)
 {
-	char *pm_comp[] = { "NAME=spindle-motor", "0=off", "1=on", NULL };
-
-	ASSERT(!mutex_owned(SD_MUTEX(un)));
-
-	if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi,
-	    "pm-components", pm_comp, 3) == DDI_PROP_SUCCESS) {
-		/*
-		 * When components are initially created they are idle,
-		 * power up any non-removables.
-		 * Note: the return value of pm_raise_power can't be used
-		 * for determining if PM should be enabled for this device.
-		 * Even if you check the return values and remove this
-		 * property created above, the PM framework will not honor the
-		 * change after the first call to pm_raise_power. Hence,
-		 * removal of that property does not help if pm_raise_power
-		 * fails. In the case of removable media, the start/stop
-		 * will fail if the media is not present.
-		 */
-		if (un->un_f_attach_spinup && (pm_raise_power(SD_DEVINFO(un), 0,
-		    SD_SPINDLE_ON) == DDI_SUCCESS)) {
-			mutex_enter(SD_MUTEX(un));
+	ASSERT(!mutex_owned(SD_MUTEX(un)));
+
+	if (un->un_f_power_condition_supported) {
+		if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi,
+		    "pm-components", sd_pwr_pc.pm_comp, 5)
+		    != DDI_PROP_SUCCESS) {
+			un->un_power_level = SD_SPINDLE_ACTIVE;
+			un->un_f_pm_is_enabled = FALSE;
+			return;
+		}
+	} else {
+		if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi,
+		    "pm-components", sd_pwr_ss.pm_comp, 3)
+		    != DDI_PROP_SUCCESS) {
 			un->un_power_level = SD_SPINDLE_ON;
-			mutex_enter(&un->un_pm_mutex);
-			/* Set to on and not busy. */
-			un->un_pm_count = 0;
-		} else {
-			mutex_enter(SD_MUTEX(un));
-			un->un_power_level = SD_SPINDLE_OFF;
-			mutex_enter(&un->un_pm_mutex);
-			/* Set to off. */
-			un->un_pm_count = -1;
-		}
-		mutex_exit(&un->un_pm_mutex);
-		mutex_exit(SD_MUTEX(un));
-	} else {
-		un->un_power_level = SD_SPINDLE_ON;
-		un->un_f_pm_is_enabled = FALSE;
-	}
+			un->un_f_pm_is_enabled = FALSE;
+			return;
+		}
+	}
+	/*
+	 * When components are initially created they are idle,
+	 * power up any non-removables.
+	 * Note: the return value of pm_raise_power can't be used
+	 * for determining if PM should be enabled for this device.
+	 * Even if you check the return values and remove this
+	 * property created above, the PM framework will not honor the
+	 * change after the first call to pm_raise_power. Hence,
+	 * removal of that property does not help if pm_raise_power
+	 * fails. In the case of removable media, the start/stop
+	 * will fail if the media is not present.
+	 */
+	if (un->un_f_attach_spinup && (pm_raise_power(SD_DEVINFO(un), 0,
+	    SD_PM_STATE_ACTIVE(un)) == DDI_SUCCESS)) {
+		mutex_enter(SD_MUTEX(un));
+		un->un_power_level = SD_PM_STATE_ACTIVE(un);
+		mutex_enter(&un->un_pm_mutex);
+		/* Set to on and not busy. */
+		un->un_pm_count = 0;
+	} else {
+		mutex_enter(SD_MUTEX(un));
+		un->un_power_level = SD_PM_STATE_STOPPED(un);
+		mutex_enter(&un->un_pm_mutex);
+		/* Set to off. */
+		un->un_pm_count = -1;
+	}
+	mutex_exit(&un->un_pm_mutex);
+	mutex_exit(SD_MUTEX(un));
 }
 
 
@@ -6126,69 +6234,6 @@
 
 
 /*
- *    Function: sd_ddi_pm_suspend
- *
- * Description: Set the drive state to low power.
- *		Someone else is required to actually change the drive
- *		power level.
- *
- *   Arguments: un - driver soft state (unit) structure
- *
- * Return Code: DDI_FAILURE or DDI_SUCCESS
- *
- *     Context: Kernel thread context
- */
-
-static int
-sd_ddi_pm_suspend(struct sd_lun *un)
-{
-	ASSERT(un != NULL);
-	SD_TRACE(SD_LOG_POWER, un, "sd_ddi_pm_suspend: entry\n");
-
-	ASSERT(!mutex_owned(SD_MUTEX(un)));
-	mutex_enter(SD_MUTEX(un));
-
-	/*
-	 * Exit if power management is not enabled for this device, or if
-	 * the device is being used by HA.
-	 */
-	if ((un->un_f_pm_is_enabled == FALSE) || (un->un_resvd_status &
-	    (SD_RESERVE | SD_WANT_RESERVE | SD_LOST_RESERVE))) {
-		mutex_exit(SD_MUTEX(un));
-		SD_TRACE(SD_LOG_POWER, un, "sd_ddi_pm_suspend: exiting\n");
-		return (DDI_SUCCESS);
-	}
-
-	SD_INFO(SD_LOG_POWER, un, "sd_ddi_pm_suspend: un_ncmds_in_driver=%ld\n",
-	    un->un_ncmds_in_driver);
-
-	/*
-	 * See if the device is not busy, ie.:
-	 *    - we have no commands in the driver for this device
-	 *    - not waiting for resources
-	 */
-	if ((un->un_ncmds_in_driver == 0) &&
-	    (un->un_state != SD_STATE_RWAIT)) {
-		/*
-		 * The device is not busy, so it is OK to go to low power state.
-		 * Indicate low power, but rely on someone else to actually
-		 * change it.
-		 */
-		mutex_enter(&un->un_pm_mutex);
-		un->un_pm_count = -1;
-		mutex_exit(&un->un_pm_mutex);
-		un->un_power_level = SD_SPINDLE_OFF;
-	}
-
-	mutex_exit(SD_MUTEX(un));
-
-	SD_TRACE(SD_LOG_POWER, un, "sd_ddi_pm_suspend: exit\n");
-
-	return (DDI_SUCCESS);
-}
-
-
-/*
  *    Function: sd_ddi_resume
  *
  * Description: Performs system power-up operations..
@@ -6244,7 +6289,8 @@
 	 */
 	if (un->un_f_attach_spinup) {
 		mutex_exit(SD_MUTEX(un));
-		(void) pm_raise_power(SD_DEVINFO(un), 0, SD_SPINDLE_ON);
+		(void) pm_raise_power(SD_DEVINFO(un), 0,
+		    SD_PM_STATE_ACTIVE(un));
 		mutex_enter(SD_MUTEX(un));
 	}
 
@@ -6294,42 +6340,76 @@
 
 
 /*
- *    Function: sd_ddi_pm_resume
- *
- * Description: Set the drive state to powered on.
- *		Someone else is required to actually change the drive
- *		power level.
+ *    Function: sd_pm_state_change
+ *
+ * Description: Change the driver power state.
+ * 		Someone else is required to actually change the driver
+ * 		power level.
  *
  *   Arguments: un - driver soft state (unit) structure
+ *              level - the power level that is changed to
+ *              flag - to decide how to change the power state
  *
  * Return Code: DDI_SUCCESS
  *
  *     Context: Kernel thread context
  */
-
-static int
-sd_ddi_pm_resume(struct sd_lun *un)
-{
-	ASSERT(un != NULL);
-
-	ASSERT(!mutex_owned(SD_MUTEX(un)));
-	mutex_enter(SD_MUTEX(un));
-	un->un_power_level = SD_SPINDLE_ON;
-
-	ASSERT(!mutex_owned(&un->un_pm_mutex));
-	mutex_enter(&un->un_pm_mutex);
-	if (SD_DEVICE_IS_IN_LOW_POWER(un)) {
-		un->un_pm_count++;
-		ASSERT(un->un_pm_count == 0);
-		/*
-		 * Note: no longer do the cv_broadcast on un_suspend_cv. The
-		 * un_suspend_cv is for a system resume, not a power management
-		 * device resume. (4297749)
-		 *	 cv_broadcast(&un->un_suspend_cv);
-		 */
-	}
-	mutex_exit(&un->un_pm_mutex);
-	mutex_exit(SD_MUTEX(un));
+static int
+sd_pm_state_change(struct sd_lun *un, int level, int flag)
+{
+	ASSERT(un != NULL);
+	SD_TRACE(SD_LOG_POWER, un, "sd_pm_state_change: entry\n");
+
+	ASSERT(!mutex_owned(SD_MUTEX(un)));
+	mutex_enter(SD_MUTEX(un));
+
+	if (flag == SD_PM_STATE_ROLLBACK || SD_PM_IS_IO_CAPABLE(un, level)) {
+		un->un_power_level = level;
+		ASSERT(!mutex_owned(&un->un_pm_mutex));
+		mutex_enter(&un->un_pm_mutex);
+		if (SD_DEVICE_IS_IN_LOW_POWER(un)) {
+			un->un_pm_count++;
+			ASSERT(un->un_pm_count == 0);
+		}
+		mutex_exit(&un->un_pm_mutex);
+	} else {
+		/*
+		 * Exit if power management is not enabled for this device,
+		 * or if the device is being used by HA.
+		 */
+		if ((un->un_f_pm_is_enabled == FALSE) || (un->un_resvd_status &
+		    (SD_RESERVE | SD_WANT_RESERVE | SD_LOST_RESERVE))) {
+			mutex_exit(SD_MUTEX(un));
+			SD_TRACE(SD_LOG_POWER, un,
+			    "sd_pm_state_change: exiting\n");
+			return (DDI_FAILURE);
+		}
+
+		SD_INFO(SD_LOG_POWER, un, "sd_pm_state_change: "
+		    "un_ncmds_in_driver=%ld\n", un->un_ncmds_in_driver);
+
+		/*
+		 * See if the device is not busy, ie.:
+		 *    - we have no commands in the driver for this device
+		 *    - not waiting for resources
+		 */
+		if ((un->un_ncmds_in_driver == 0) &&
+		    (un->un_state != SD_STATE_RWAIT)) {
+			/*
+			 * The device is not busy, so it is OK to go to low
+			 * power state. Indicate low power, but rely on someone
+			 * else to actually change it.
+			 */
+			mutex_enter(&un->un_pm_mutex);
+			un->un_pm_count = -1;
+			mutex_exit(&un->un_pm_mutex);
+			un->un_power_level = level;
+		}
+	}
+
+	mutex_exit(SD_MUTEX(un));
+
+	SD_TRACE(SD_LOG_POWER, un, "sd_pm_state_change: exit\n");
 
 	return (DDI_SUCCESS);
 }
@@ -6451,12 +6531,12 @@
 	uchar_t		state_before_pm;
 	int		got_semaphore_here;
 	sd_ssc_t	*ssc;
+	int	last_power_level;
 
 	instance = ddi_get_instance(devi);
 
 	if (((un = ddi_get_soft_state(sd_state, instance)) == NULL) ||
-	    (SD_SPINDLE_OFF > level) || (level > SD_SPINDLE_ON) ||
-	    component != 0) {
+	    !SD_PM_IS_LEVEL_VALID(un, level) || component != 0) {
 		return (DDI_FAILURE);
 	}
 
@@ -6487,10 +6567,11 @@
 	 * If un_ncmds_in_driver is non-zero it indicates commands are
 	 * already being processed in the driver, or if the semaphore was
 	 * not gotten here it indicates an open or close is being processed.
-	 * At the same time somebody is requesting to go low power which
-	 * can't happen, therefore we need to return failure.
-	 */
-	if ((level == SD_SPINDLE_OFF) &&
+	 * At the same time somebody is requesting to go to a lower power
+	 * that can't perform I/O, which can't happen, therefore we need to
+	 * return failure.
+	 */
+	if ((!SD_PM_IS_IO_CAPABLE(un, level)) &&
 	    ((un->un_ncmds_in_driver != 0) || (got_semaphore_here == 0))) {
 		mutex_exit(SD_MUTEX(un));
 
@@ -6536,11 +6617,12 @@
 	mutex_exit(SD_MUTEX(un));
 
 	/*
-	 * If "pm-capable" property is set to TRUE by HBA drivers,
-	 * bypass the following checking, otherwise, check the log
-	 * sense information for this device
-	 */
-	if ((level == SD_SPINDLE_OFF) && un->un_f_log_sense_supported) {
+	 * If log sense command is not supported, bypass the
+	 * following checking, otherwise, check the log sense
+	 * information for this device.
+	 */
+	if (SD_PM_STOP_MOTOR_NEEDED(un, level) &&
+	    un->un_f_log_sense_supported) {
 		/*
 		 * Get the log sense information to understand whether the
 		 * the powercycle counts have gone beyond the threshhold.
@@ -6601,17 +6683,24 @@
 		    (log_page_data[0x1c] << 24) | (log_page_data[0x1d] << 16) |
 		    (log_page_data[0x1E] << 8)  | log_page_data[0x1F];
 
-		sd_pm_tran_data.un.scsi_cycles.lifemax = maxcycles;
-
 		ncycles =
 		    (log_page_data[0x24] << 24) | (log_page_data[0x25] << 16) |
 		    (log_page_data[0x26] << 8)  | log_page_data[0x27];
 
-		sd_pm_tran_data.un.scsi_cycles.ncycles = ncycles;
-
-		for (i = 0; i < DC_SCSI_MFR_LEN; i++) {
-			sd_pm_tran_data.un.scsi_cycles.svc_date[i] =
-			    log_page_data[8+i];
+		if (un->un_f_pm_log_sense_smart) {
+			sd_pm_tran_data.un.smart_count.allowed = maxcycles;
+			sd_pm_tran_data.un.smart_count.consumed = ncycles;
+			sd_pm_tran_data.un.smart_count.flag = 0;
+			sd_pm_tran_data.format = DC_SMART_FORMAT;
+		} else {
+			sd_pm_tran_data.un.scsi_cycles.lifemax = maxcycles;
+			sd_pm_tran_data.un.scsi_cycles.ncycles = ncycles;
+			for (i = 0; i < DC_SCSI_MFR_LEN; i++) {
+				sd_pm_tran_data.un.scsi_cycles.svc_date[i] =
+				    log_page_data[8+i];
+			}
+			sd_pm_tran_data.un.scsi_cycles.flag = 0;
+			sd_pm_tran_data.format = DC_SCSI_FORMAT;
 		}
 
 		kmem_free(log_page_data, log_page_size);
@@ -6620,10 +6709,6 @@
 		 * Call pm_trans_check routine to get the Ok from
 		 * the global policy
 		 */
-
-		sd_pm_tran_data.format = DC_SCSI_FORMAT;
-		sd_pm_tran_data.un.scsi_cycles.flag = 0;
-
 		rval = pm_trans_check(&sd_pm_tran_data, &intvlp);
 #ifdef	SDDEBUG
 		if (sd_force_pm_supported) {
@@ -6704,13 +6789,14 @@
 		}
 	}
 
-	if (level == SD_SPINDLE_OFF) {
+	if (!SD_PM_IS_IO_CAPABLE(un, level)) {
 		/*
 		 * Save the last state... if the STOP FAILS we need it
 		 * for restoring
 		 */
 		mutex_enter(SD_MUTEX(un));
 		save_state = un->un_last_state;
+		last_power_level = un->un_power_level;
 		/*
 		 * There must not be any cmds. getting processed
 		 * in the driver when we get here. Power to the
@@ -6720,10 +6806,11 @@
 		mutex_exit(SD_MUTEX(un));
 
 		/*
-		 * For now suspend the device completely before spindle is
+		 * For now PM suspend the device completely before spindle is
 		 * turned off
 		 */
-		if ((rval = sd_ddi_pm_suspend(un)) == DDI_FAILURE) {
+		if ((rval = sd_pm_state_change(un, level, SD_PM_STATE_CHANGE))
+		    == DDI_FAILURE) {
 			if (got_semaphore_here != 0) {
 				sema_v(&un->un_semoclose);
 			}
@@ -6734,6 +6821,7 @@
 			 */
 			mutex_enter(SD_MUTEX(un));
 			un->un_state = state_before_pm;
+			un->un_power_level = last_power_level;
 			cv_broadcast(&un->un_suspend_cv);
 			mutex_exit(SD_MUTEX(un));
 			SD_TRACE(SD_LOG_IO_PM, un,
@@ -6756,19 +6844,28 @@
 	 * attention.  Don't do retries. Bypass the PM layer, otherwise
 	 * a deadlock on un_pm_busy_cv will occur.
 	 */
-	if (level == SD_SPINDLE_ON) {
+	if (SD_PM_IS_IO_CAPABLE(un, level)) {
 		sval = sd_send_scsi_TEST_UNIT_READY(ssc,
 		    SD_DONT_RETRY_TUR | SD_BYPASS_PM);
 		if (sval != 0)
 			sd_ssc_assessment(ssc, SD_FMT_IGNORE);
 	}
 
-	SD_TRACE(SD_LOG_IO_PM, un, "sdpower: sending \'%s\' unit\n",
-	    ((level == SD_SPINDLE_ON) ? "START" : "STOP"));
-
-	sval = sd_send_scsi_START_STOP_UNIT(ssc,
-	    ((level == SD_SPINDLE_ON) ? SD_TARGET_START : SD_TARGET_STOP),
-	    SD_PATH_DIRECT);
+	if (un->un_f_power_condition_supported) {
+		char *pm_condition_name[] = {"STOPPED", "STANDBY",
+		    "IDLE", "ACTIVE"};
+		SD_TRACE(SD_LOG_IO_PM, un,
+		    "sdpower: sending \'%s\' power condition",
+		    pm_condition_name[level]);
+		sval = sd_send_scsi_START_STOP_UNIT(ssc, SD_POWER_CONDITION,
+		    sd_pl2pc[level], SD_PATH_DIRECT);
+	} else {
+		SD_TRACE(SD_LOG_IO_PM, un, "sdpower: sending \'%s\' unit\n",
+		    ((level == SD_SPINDLE_ON) ? "START" : "STOP"));
+		sval = sd_send_scsi_START_STOP_UNIT(ssc, SD_START_STOP,
+		    ((level == SD_SPINDLE_ON) ? SD_TARGET_START :
+		    SD_TARGET_STOP), SD_PATH_DIRECT);
+	}
 	if (sval != 0) {
 		if (sval == EIO)
 			sd_ssc_assessment(ssc, SD_FMT_STATUS_CHECK);
@@ -6790,8 +6887,7 @@
 	 * In all other cases we setup for the new state
 	 * and return success.
 	 */
-	switch (level) {
-	case SD_SPINDLE_OFF:
+	if (!SD_PM_IS_IO_CAPABLE(un, level)) {
 		if ((medium_present == TRUE) && (sval != 0)) {
 			/* The stop command from above failed */
 			rval = DDI_FAILURE;
@@ -6801,17 +6897,14 @@
 			 * sd_pm_resume() and set the state back to
 			 * it's previous value.
 			 */
-			(void) sd_ddi_pm_resume(un);
+			(void) sd_pm_state_change(un, last_power_level,
+			    SD_PM_STATE_ROLLBACK);
 			mutex_enter(SD_MUTEX(un));
 			un->un_last_state = save_state;
 			mutex_exit(SD_MUTEX(un));
-			break;
-		}
-		/*
-		 * The stop command from above succeeded.
-		 */
-		if (un->un_f_monitor_media_state) {
-			/*
+		} else if (un->un_f_monitor_media_state) {
+			/*
+			 * The stop command from above succeeded.
 			 * Terminate watch thread in case of removable media
 			 * devices going into low power state. This is as per
 			 * the requirements of pm framework, otherwise commands
@@ -6831,10 +6924,9 @@
 				mutex_exit(SD_MUTEX(un));
 			}
 		}
-		break;
-
-	default:	/* The level requested is spindle on... */
-		/*
+	} else {
+		/*
+		 * The level requested is I/O capable.
 		 * Legacy behavior: return success on a failed spinup
 		 * if there is no media in the drive.
 		 * Do this by looking at medium_present here.
@@ -6842,37 +6934,39 @@
 		if ((sval != 0) && medium_present) {
 			/* The start command from above failed */
 			rval = DDI_FAILURE;
-			break;
-		}
-		/*
-		 * The start command from above succeeded
-		 * Resume the devices now that we have
-		 * started the disks
-		 */
-		(void) sd_ddi_pm_resume(un);
-
-		/*
-		 * Resume the watch thread since it was suspended
-		 * when the device went into low power mode.
-		 */
-		if (un->un_f_monitor_media_state) {
-			mutex_enter(SD_MUTEX(un));
-			if (un->un_f_watcht_stopped == TRUE) {
-				opaque_t temp_token;
-
-				un->un_f_watcht_stopped = FALSE;
+		} else {
+			/*
+			 * The start command from above succeeded
+			 * PM resume the devices now that we have
+			 * started the disks
+			 */
+			(void) sd_pm_state_change(un, level,
+			    SD_PM_STATE_CHANGE);
+
+			/*
+			 * Resume the watch thread since it was suspended
+			 * when the device went into low power mode.
+			 */
+			if (un->un_f_monitor_media_state) {
+				mutex_enter(SD_MUTEX(un));
+				if (un->un_f_watcht_stopped == TRUE) {
+					opaque_t temp_token;
+
+					un->un_f_watcht_stopped = FALSE;
+					mutex_exit(SD_MUTEX(un));
+					temp_token = scsi_watch_request_submit(
+					    SD_SCSI_DEVP(un),
+					    sd_check_media_time,
+					    SENSE_LENGTH, sd_media_watch_cb,
+					    (caddr_t)dev);
+					mutex_enter(SD_MUTEX(un));
+					un->un_swr_token = temp_token;
+				}
 				mutex_exit(SD_MUTEX(un));
-				temp_token = scsi_watch_request_submit(
-				    SD_SCSI_DEVP(un),
-				    sd_check_media_time,
-				    SENSE_LENGTH, sd_media_watch_cb,
-				    (caddr_t)dev);
-				mutex_enter(SD_MUTEX(un));
-				un->un_swr_token = temp_token;
-			}
-			mutex_exit(SD_MUTEX(un));
-		}
-	}
+			}
+		}
+	}
+
 	if (got_semaphore_here != 0) {
 		sema_v(&un->un_semoclose);
 	}
@@ -8593,8 +8687,8 @@
 	} else {
 		mutex_exit(&un->un_pm_mutex);
 		if ((un->un_f_pm_is_enabled == TRUE) &&
-		    (pm_lower_power(SD_DEVINFO(un), 0, SD_SPINDLE_OFF) !=
-		    DDI_SUCCESS)) {
+		    (pm_lower_power(SD_DEVINFO(un), 0, SD_PM_STATE_STOPPED(un))
+		    != DDI_SUCCESS)) {
 			SD_ERROR(SD_LOG_ATTACH_DETACH, un,
 		    "sd_dr_detach: Lower power request failed, ignoring.\n");
 			/*
@@ -9718,12 +9812,11 @@
 			/*
 			 * pm_raise_power will cause sdpower to be called
 			 * which brings the device power level to the
-			 * desired state, ON in this case. If successful,
-			 * un_pm_count and un_power_level will be updated
-			 * appropriately.
+			 * desired state, If successful, un_pm_count and
+			 * un_power_level will be updated appropriately.
 			 */
 			return_status = pm_raise_power(SD_DEVINFO(un), 0,
-			    SD_SPINDLE_ON);
+			    SD_PM_STATE_ACTIVE(un));
 
 			mutex_enter(&un->un_pm_mutex);
 
@@ -11724,6 +11817,7 @@
  * Return Code: 0 -  successful completion of the given command
  *		EIO - scsi_uscsi_handle_command() failed
  *		ENXIO  - soft state not found for specified dev
+ *		ECANCELED - command cancelled due to low power
  *		EINVAL
  *		EFAULT - copyin/copyout error
  *		return code of scsi_uscsi_handle_command():
@@ -11779,6 +11873,23 @@
 	 */
 	ssc->ssc_flags |= SSC_FLAGS_NEED_ASSESSMENT;
 
+	/*
+	 * if USCSI_PMFAILFAST is set and un is in low power, fail the
+	 * command immediately.
+	 */
+	mutex_enter(SD_MUTEX(un));
+	mutex_enter(&un->un_pm_mutex);
+	if ((uscmd->uscsi_flags & USCSI_PMFAILFAST) &&
+	    SD_DEVICE_IS_IN_LOW_POWER(un)) {
+		SD_TRACE(SD_LOG_IO, un, "sd_ssc_send:"
+		    "un:0x%p is in low power\n", un);
+		mutex_exit(&un->un_pm_mutex);
+		mutex_exit(SD_MUTEX(un));
+		return (ECANCELED);
+	}
+	mutex_exit(&un->un_pm_mutex);
+	mutex_exit(SD_MUTEX(un));
+
 #ifdef SDDEBUG
 	switch (dataspace) {
 	case UIO_USERSPACE:
@@ -20059,6 +20170,8 @@
  *
  *   Arguments: ssc    - ssc contatins pointer to driver soft state (unit)
  *                       structure for this target.
+ *      pc_flag - SD_POWER_CONDITION
+ *                SD_START_STOP
  *		flag  - SD_TARGET_START
  *			SD_TARGET_STOP
  *			SD_TARGET_EJECT
@@ -20078,7 +20191,8 @@
  */
 
 static int
-sd_send_scsi_START_STOP_UNIT(sd_ssc_t *ssc, int flag, int path_flag)
+sd_send_scsi_START_STOP_UNIT(sd_ssc_t *ssc, int pc_flag, int flag,
+    int path_flag)
 {
 	struct	scsi_extended_sense	sense_buf;
 	union scsi_cdb		cdb;
@@ -20095,7 +20209,7 @@
 	    "sd_send_scsi_START_STOP_UNIT: entry: un:0x%p\n", un);
 
 	if (un->un_f_check_start_stop &&
-	    ((flag == SD_TARGET_START) || (flag == SD_TARGET_STOP)) &&
+	    ((pc_flag == SD_START_STOP) && (flag != SD_TARGET_EJECT)) &&
 	    (un->un_f_start_stop_supported != TRUE)) {
 		return (0);
 	}
@@ -20119,7 +20233,8 @@
 	bzero(&sense_buf, sizeof (struct scsi_extended_sense));
 
 	cdb.scc_cmd = SCMD_START_STOP;
-	cdb.cdb_opaque[4] = (uchar_t)flag;
+	cdb.cdb_opaque[4] = (pc_flag == SD_POWER_CONDITION) ?
+	    (uchar_t)(flag << 4) : (uchar_t)flag;
 
 	ucmd_buf.uscsi_cdb	= (char *)&cdb;
 	ucmd_buf.uscsi_cdblen	= CDB_GROUP0;
@@ -20214,6 +20329,7 @@
 {
 	struct sd_lun	*un = arg;
 	sd_ssc_t	*ssc;
+	int		power_level;
 	int		rval;
 
 	ASSERT(un != NULL);
@@ -20232,16 +20348,30 @@
 	}
 	mutex_exit(SD_MUTEX(un));
 
+	ssc = sd_ssc_init(un);
 	/*
 	 * When a START STOP command is issued from here, it is part of a
 	 * failure recovery operation and must be issued before any other
 	 * commands, including any pending retries. Thus it must be sent
 	 * using SD_PATH_DIRECT_PRIORITY. It doesn't matter if the spin up
 	 * succeeds or not, we will start I/O after the attempt.
-	 */
-	ssc = sd_ssc_init(un);
-	rval = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_START,
-	    SD_PATH_DIRECT_PRIORITY);
+	 * If power condition is supported and the current power level
+	 * is capable of performing I/O, we should set the power condition
+	 * to that level. Otherwise, set the power condition to ACTIVE.
+	 */
+	if (un->un_f_power_condition_supported) {
+		mutex_enter(SD_MUTEX(un));
+		ASSERT(SD_PM_IS_LEVEL_VALID(un, un->un_power_level));
+		power_level = sd_pwr_pc.ran_perf[un->un_power_level]
+		    > 0 ? un->un_power_level : SD_SPINDLE_ACTIVE;
+		mutex_exit(SD_MUTEX(un));
+		rval = sd_send_scsi_START_STOP_UNIT(ssc, SD_POWER_CONDITION,
+		    sd_pl2pc[power_level], SD_PATH_DIRECT_PRIORITY);
+	} else {
+		rval = sd_send_scsi_START_STOP_UNIT(ssc, SD_START_STOP,
+		    SD_TARGET_START, SD_PATH_DIRECT_PRIORITY);
+	}
+
 	if (rval != 0)
 		sd_ssc_assessment(ssc, SD_FMT_IGNORE);
 	sd_ssc_fini(ssc);
@@ -22285,8 +22415,8 @@
 		if (!ISCD(un)) {
 			err = ENOTTY;
 		} else {
-			err = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_STOP,
-			    SD_PATH_STANDARD);
+			err = sd_send_scsi_START_STOP_UNIT(ssc, SD_START_STOP,
+			    SD_TARGET_STOP, SD_PATH_STANDARD);
 			goto done_with_assess;
 		}
 		break;
@@ -22296,8 +22426,8 @@
 		if (!ISCD(un)) {
 			err = ENOTTY;
 		} else {
-			err = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_START,
-			    SD_PATH_STANDARD);
+			err = sd_send_scsi_START_STOP_UNIT(ssc, SD_START_STOP,
+			    SD_TARGET_START, SD_PATH_STANDARD);
 			goto done_with_assess;
 		}
 		break;
@@ -22307,8 +22437,8 @@
 		if (!ISCD(un)) {
 			err = ENOTTY;
 		} else {
-			err = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_CLOSE,
-			    SD_PATH_STANDARD);
+			err = sd_send_scsi_START_STOP_UNIT(ssc, SD_START_STOP,
+			    SD_TARGET_CLOSE, SD_PATH_STANDARD);
 			goto done_with_assess;
 		}
 		break;
@@ -25345,7 +25475,8 @@
 		/*
 		 * use pm framework to power on HBA 1st
 		 */
-		(void) pm_raise_power(SD_DEVINFO(un), 0, SD_SPINDLE_ON);
+		(void) pm_raise_power(SD_DEVINFO(un), 0,
+		    SD_PM_STATE_ACTIVE(un));
 
 		/*
 		 * Dump no long uses sdpower to power on a device, it's
@@ -25378,7 +25509,8 @@
 			return (EIO);
 		}
 		scsi_destroy_pkt(start_pktp);
-		(void) sd_ddi_pm_resume(un);
+		(void) sd_pm_state_change(un, SD_PM_STATE_ACTIVE(un),
+		    SD_PM_STATE_CHANGE);
 	} else {
 		mutex_exit(&un->un_pm_mutex);
 	}
@@ -28358,8 +28490,8 @@
 	}
 
 	ssc = sd_ssc_init(un);
-	rval = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_EJECT,
-	    SD_PATH_STANDARD);
+	rval = sd_send_scsi_START_STOP_UNIT(ssc, SD_START_STOP,
+	    SD_TARGET_EJECT, SD_PATH_STANDARD);
 	sd_ssc_fini(ssc);
 
 	if (rval == 0) {
@@ -30306,7 +30438,7 @@
 static void
 sd_set_unit_attributes(struct sd_lun *un, dev_info_t *devi)
 {
-	int	pm_capable_prop;
+	int	pm_cap;
 
 	ASSERT(un->un_sd);
 	ASSERT(un->un_sd->sd_inq);
@@ -30426,33 +30558,47 @@
 		 * power manage the device without checking the start/stop
 		 * cycle count log sense page.
 		 *
-		 * If "pm-capable" exists and is SD_PM_CAPABLE_FALSE (0)
+		 * If "pm-capable" exists and is set to be false (0),
 		 * then we should not power manage the device.
 		 *
-		 * If "pm-capable" doesn't exist then pm_capable_prop will
+		 * If "pm-capable" doesn't exist then pm_cap will
 		 * be set to SD_PM_CAPABLE_UNDEFINED (-1).  In this case,
 		 * sd will check the start/stop cycle count log sense page
 		 * and power manage the device if the cycle count limit has
 		 * not been exceeded.
 		 */
-		pm_capable_prop = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
+		pm_cap = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
 		    DDI_PROP_DONTPASS, "pm-capable", SD_PM_CAPABLE_UNDEFINED);
-		if (pm_capable_prop == SD_PM_CAPABLE_UNDEFINED) {
+		if (SD_PM_CAPABLE_IS_UNDEFINED(pm_cap)) {
 			un->un_f_log_sense_supported = TRUE;
+			if (!un->un_f_power_condition_disabled &&
+			    SD_INQUIRY(un)->inq_ansi == 6) {
+				un->un_f_power_condition_supported = TRUE;
+			}
 		} else {
 			/*
 			 * pm-capable property exists.
 			 *
-			 * Convert "TRUE" values for pm_capable_prop to
-			 * SD_PM_CAPABLE_TRUE (1) to make it easier to check
-			 * later. "TRUE" values are any values except
-			 * SD_PM_CAPABLE_FALSE (0) and
-			 * SD_PM_CAPABLE_UNDEFINED (-1)
-			 */
-			if (pm_capable_prop == SD_PM_CAPABLE_FALSE) {
+			 * Convert "TRUE" values for pm_cap to
+			 * SD_PM_CAPABLE_IS_TRUE to make it easier to check
+			 * later. "TRUE" values are any values defined in
+			 * inquiry.h.
+			 */
+			if (SD_PM_CAPABLE_IS_FALSE(pm_cap)) {
 				un->un_f_log_sense_supported = FALSE;
 			} else {
+				/* SD_PM_CAPABLE_IS_TRUE case */
 				un->un_f_pm_supported = TRUE;
+				if (!un->un_f_power_condition_disabled &&
+				    SD_PM_CAPABLE_IS_SPC_4(pm_cap)) {
+					un->un_f_power_condition_supported =
+					    TRUE;
+				}
+				if (SD_PM_CAP_LOG_SUPPORTED(pm_cap)) {
+					un->un_f_log_sense_supported = TRUE;
+					un->un_f_pm_log_sense_smart =
+					    SD_PM_CAP_SMART_LOG(pm_cap);
+				}
 			}
 
 			SD_INFO(SD_LOG_ATTACH_DETACH, un,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/uath/THIRDPARTYLICENSE	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2006 Sam Leffler, Errno Consulting
+ * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/*
+ * This driver is distantly derived from a driver of the same name
+ * by Damien Bergamini.  The original copyright is included below:
+ *
+ * Copyright (c) 2006
+ *	Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/uath/THIRDPARTYLICENSE.descrip	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,1 @@
+ATHEROS AR5523 USB WIFI DRIVER
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/uath/uath.c	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,3370 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2006 Sam Leffler, Errno Consulting
+ * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/*
+ * This driver is distantly derived from a driver of the same name
+ * by Damien Bergamini.  The original copyright is included below:
+ *
+ * Copyright (c) 2006
+ *	Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/strsubr.h>
+#include <sys/strsun.h>
+#include <sys/modctl.h>
+#include <sys/devops.h>
+#include <sys/mac_provider.h>
+#include <sys/mac_wifi.h>
+#include <sys/net80211.h>
+
+#define	USBDRV_MAJOR_VER	2
+#define	USBDRV_MINOR_VER	0
+#include <sys/usb/usba.h>
+#include <sys/usb/usba/usba_types.h>
+
+#include "uath_reg.h"
+#include "uath_var.h"
+
+static void *uath_soft_state_p = NULL;
+
+/*
+ * Bit flags in the ral_dbg_flags
+ */
+#define	UATH_DBG_MSG		0x000001
+#define	UATH_DBG_ERR		0x000002
+#define	UATH_DBG_USB		0x000004
+#define	UATH_DBG_TX		0x000008
+#define	UATH_DBG_RX		0x000010
+#define	UATH_DBG_FW		0x000020
+#define	UATH_DBG_TX_CMD		0x000040
+#define	UATH_DBG_RX_CMD		0x000080
+#define	UATH_DBG_ALL		0x000fff
+
+uint32_t uath_dbg_flags = 0;
+
+#ifdef DEBUG
+#define	UATH_DEBUG \
+	uath_debug
+#else
+#define	UATH_DEBUG
+#endif
+
+/*
+ * Various supported device vendors/products.
+ * UB51: AR5005UG 802.11b/g, UB52: AR5005UX 802.11b/g
+ */
+#define	UATH_FLAG_PRE_FIRMWARE	(1 << 0)
+#define	UATH_FLAG_ABG		(1 << 1)
+#define	UATH_FLAG_ERR		(1 << 2)
+#define	UATH_DEV(v, p, f)						\
+	{ { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, (f) },		\
+	{ { USB_VENDOR_##v, USB_PRODUCT_##v##_##p##_NF },		\
+	    (f) | UATH_FLAG_PRE_FIRMWARE }
+#define	UATH_DEV_UG(v, p)	UATH_DEV(v, p, 0)
+#define	UATH_DEV_UX(v, p)	UATH_DEV(v, p, UATH_FLAG_ABG)
+
+struct uath_devno {
+	uint16_t vendor_id;
+	uint16_t product_id;
+};
+
+static const struct uath_type {
+	struct uath_devno	dev;
+	uint8_t			flags;
+} uath_devs[] = {
+	UATH_DEV_UG(ACCTON,		SMCWUSBTG2),
+	UATH_DEV_UG(ATHEROS,		AR5523),
+	UATH_DEV_UG(ATHEROS2,		AR5523_1),
+	UATH_DEV_UG(ATHEROS2,		AR5523_2),
+	UATH_DEV_UX(ATHEROS2,		AR5523_3),
+	UATH_DEV_UG(CONCEPTRONIC,	AR5523_1),
+	UATH_DEV_UX(CONCEPTRONIC,	AR5523_2),
+	UATH_DEV_UX(DLINK,		DWLAG122),
+	UATH_DEV_UX(DLINK,		DWLAG132),
+	UATH_DEV_UG(DLINK,		DWLG132),
+	UATH_DEV_UG(GIGASET,		AR5523),
+	UATH_DEV_UG(GIGASET,		SMCWUSBTG),
+	UATH_DEV_UG(GLOBALSUN,		AR5523_1),
+	UATH_DEV_UX(GLOBALSUN,		AR5523_2),
+	UATH_DEV_UG(IODATA,		USBWNG54US),
+	UATH_DEV_UG(MELCO,		WLIU2KAMG54),
+	UATH_DEV_UX(NETGEAR,		WG111U),
+	UATH_DEV_UG(NETGEAR3,		WG111T),
+	UATH_DEV_UG(NETGEAR3,		WPN111),
+	UATH_DEV_UG(PHILIPS,		SNU6500),
+	UATH_DEV_UX(UMEDIA,		AR5523_2),
+	UATH_DEV_UG(UMEDIA,		TEW444UBEU),
+	UATH_DEV_UG(WISTRONNEWEB,	AR5523_1),
+	UATH_DEV_UX(WISTRONNEWEB,	AR5523_2),
+	UATH_DEV_UG(ZCOM,		AR5523)
+};
+
+static char uath_fwmod[] = "uathfw";
+static char uath_binmod[] = "uathbin";
+
+/*
+ * Supported rates for 802.11b/g modes (in 500Kbps unit).
+ */
+static const struct ieee80211_rateset uath_rateset_11b =
+	{ 4, { 2, 4, 11, 22 } };
+
+static const struct ieee80211_rateset uath_rateset_11g =
+	{ 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
+
+/*
+ * device operations
+ */
+static int uath_attach(dev_info_t *, ddi_attach_cmd_t);
+static int uath_detach(dev_info_t *, ddi_detach_cmd_t);
+
+/*
+ * Module Loading Data & Entry Points
+ */
+DDI_DEFINE_STREAM_OPS(uath_dev_ops, nulldev, nulldev, uath_attach,
+    uath_detach, nodev, NULL, D_MP, NULL, ddi_quiesce_not_needed);
+
+static struct modldrv uath_modldrv = {
+	&mod_driverops,		/* Type of module.  This one is a driver */
+	"Atheros AR5523 USB Driver v1.1",	/* short description */
+	&uath_dev_ops		/* driver specific ops */
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1,
+	(void *)&uath_modldrv,
+	NULL
+};
+
+static int	uath_m_stat(void *,  uint_t, uint64_t *);
+static int	uath_m_start(void *);
+static void	uath_m_stop(void *);
+static int	uath_m_promisc(void *, boolean_t);
+static int	uath_m_multicst(void *, boolean_t, const uint8_t *);
+static int	uath_m_unicst(void *, const uint8_t *);
+static mblk_t	*uath_m_tx(void *, mblk_t *);
+static void	uath_m_ioctl(void *, queue_t *, mblk_t *);
+static int	uath_m_setprop(void *, const char *, mac_prop_id_t,
+		    uint_t, const void *);
+static int	uath_m_getprop(void *, const char *, mac_prop_id_t,
+		    uint_t, uint_t, void *, uint_t *);
+
+static mac_callbacks_t uath_m_callbacks = {
+	MC_IOCTL | MC_SETPROP | MC_GETPROP,
+	uath_m_stat,
+	uath_m_start,
+	uath_m_stop,
+	uath_m_promisc,
+	uath_m_multicst,
+	uath_m_unicst,
+	uath_m_tx,
+	uath_m_ioctl,
+	NULL,
+	NULL,
+	NULL,
+	uath_m_setprop,
+	uath_m_getprop
+};
+
+static usb_alt_if_data_t *
+		uath_lookup_alt_if(usb_client_dev_data_t *,
+		    uint_t, uint_t, uint_t);
+static usb_ep_data_t *
+		uath_lookup_ep_data(dev_info_t *,
+		    usb_client_dev_data_t *, uint_t, uint_t, uint8_t, uint8_t);
+static const char *
+		uath_codename(int code);
+
+static uint_t	uath_lookup(uint16_t, uint16_t);
+static void	uath_list_all_eps(usb_alt_if_data_t *);
+static int	uath_open_pipes(struct uath_softc *);
+static void	uath_close_pipes(struct uath_softc *);
+static int	uath_fw_send(struct uath_softc *,
+		    usb_pipe_handle_t, const void *, size_t);
+static int	uath_fw_ack(struct uath_softc *, int);
+static int	uath_loadsym(ddi_modhandle_t, char *, char **, size_t *);
+static int	uath_loadfirmware(struct uath_softc *);
+static int	uath_alloc_cmd_list(struct uath_softc *,
+		    struct uath_cmd *, int, int);
+static int 	uath_init_cmd_list(struct uath_softc *);
+static void	uath_free_cmd_list(struct uath_cmd *, int);
+static int	uath_host_available(struct uath_softc *);
+static void	uath_get_capability(struct uath_softc *, uint32_t, uint32_t *);
+static int	uath_get_devcap(struct uath_softc *);
+static int	uath_get_devstatus(struct uath_softc *, uint8_t *);
+static int	uath_get_status(struct uath_softc *, uint32_t, void *, int);
+
+static void	uath_cmd_lock_init(struct uath_cmd_lock *);
+static void	uath_cmd_lock_destroy(struct uath_cmd_lock *);
+static int	uath_cmd_lock_wait(struct uath_cmd_lock *, clock_t);
+static void	uath_cmd_lock_signal(struct uath_cmd_lock *);
+
+static int	uath_cmd_read(struct uath_softc *, uint32_t, const void *,
+		    int, void *, int, int);
+static int	uath_cmd_write(struct uath_softc *, uint32_t, const void *,
+		    int, int);
+static int	uath_cmdsend(struct uath_softc *, uint32_t,
+		    const void *, int, void *, int, int);
+static int	uath_rx_cmd_xfer(struct uath_softc *);
+static int	uath_tx_cmd_xfer(struct uath_softc *,
+		    usb_pipe_handle_t, const void *, uint_t);
+static void	uath_cmd_txeof(usb_pipe_handle_t, struct usb_bulk_req *);
+static void	uath_cmd_rxeof(usb_pipe_handle_t, usb_bulk_req_t *);
+static void	uath_cmdeof(struct uath_softc *, struct uath_cmd *);
+
+static void	uath_init_data_queue(struct uath_softc *);
+static int	uath_rx_data_xfer(struct uath_softc *sc);
+static int	uath_tx_data_xfer(struct uath_softc *, mblk_t *);
+static void	uath_data_txeof(usb_pipe_handle_t, usb_bulk_req_t *);
+static void	uath_data_rxeof(usb_pipe_handle_t, usb_bulk_req_t *);
+
+static int	uath_create_connection(struct uath_softc *, uint32_t);
+static int	uath_set_rates(struct uath_softc *,
+		    const struct ieee80211_rateset *);
+static int	uath_write_associd(struct uath_softc *);
+static int	uath_set_ledsteady(struct uath_softc *, int, int);
+static int	uath_set_ledblink(struct uath_softc *, int, int, int, int);
+static void	uath_update_rxstat(struct uath_softc *, uint32_t);
+static int	uath_send(ieee80211com_t *, mblk_t *, uint8_t);
+static int	uath_reconnect(dev_info_t *);
+static int	uath_disconnect(dev_info_t *);
+static int	uath_newstate(struct ieee80211com *, enum ieee80211_state, int);
+
+static int	uath_dataflush(struct uath_softc *);
+static int	uath_cmdflush(struct uath_softc *);
+static int	uath_flush(struct uath_softc *);
+static int	uath_set_ledstate(struct uath_softc *, int);
+static int	uath_set_chan(struct uath_softc *, struct ieee80211_channel *);
+static int	uath_reset_tx_queues(struct uath_softc *);
+static int	uath_wme_init(struct uath_softc *);
+static int	uath_config_multi(struct uath_softc *,
+		    uint32_t, const void *, int);
+static void	uath_config(struct uath_softc *, uint32_t, uint32_t);
+static int	uath_switch_channel(struct uath_softc *,
+		    struct ieee80211_channel *);
+static int	uath_set_rxfilter(struct uath_softc *, uint32_t, uint32_t);
+static int	uath_init_locked(void *);
+static void	uath_stop_locked(void *);
+static int	uath_init(struct uath_softc *);
+static void	uath_stop(struct uath_softc *);
+static void	uath_resume(struct uath_softc *);
+
+static void
+uath_debug(uint32_t dbg_flags, const int8_t *fmt, ...)
+{
+	va_list args;
+
+	if (dbg_flags & uath_dbg_flags) {
+		va_start(args, fmt);
+		vcmn_err(CE_CONT, fmt, args);
+		va_end(args);
+	}
+}
+
+static uint_t
+uath_lookup(uint16_t vendor_id, uint16_t product_id)
+{
+	int i, size;
+
+	size = sizeof (uath_devs) / sizeof (struct uath_type);
+
+	for (i = 0; i < size; i++) {
+		if ((vendor_id == uath_devs[i].dev.vendor_id) &&
+		    (product_id == uath_devs[i].dev.product_id))
+			return (uath_devs[i].flags);
+	}
+	return (UATH_FLAG_ERR);
+}
+
+/*
+ * Return a specific alt_if from the device descriptor tree.
+ */
+static usb_alt_if_data_t *
+uath_lookup_alt_if(usb_client_dev_data_t *dev_data, uint_t config,
+    uint_t interface, uint_t alt)
+{
+	usb_cfg_data_t *cfg_data;
+	usb_if_data_t *if_data;
+	usb_alt_if_data_t *if_alt_data;
+
+	/*
+	 * Assume everything is in the tree for now,
+	 * (USB_PARSE_LVL_ALL)
+	 * so we can directly index the array.
+	 */
+
+	/* Descend to configuration, configs are 1-based */
+	if (config < 1 || config > dev_data->dev_n_cfg)
+		return (NULL);
+	cfg_data = &dev_data->dev_cfg[config - 1];
+
+	/* Descend to interface */
+	if (interface > cfg_data->cfg_n_if - 1)
+		return (NULL);
+	if_data = &cfg_data->cfg_if[interface];
+
+	/* Descend to alt */
+	if (alt > if_data->if_n_alt - 1)
+		return (NULL);
+	if_alt_data = &if_data->if_alt[alt];
+
+	return (if_alt_data);
+}
+
+/*
+ * Print all endpoints of an alt_if.
+ */
+static void
+uath_list_all_eps(usb_alt_if_data_t *ifalt)
+{
+	usb_ep_data_t *ep_data;
+	usb_ep_descr_t *ep_descr;
+	int i;
+
+	for (i = 0; i < ifalt->altif_n_ep; i++) {
+		ep_data = &ifalt->altif_ep[i];
+		ep_descr = &ep_data->ep_descr;
+		UATH_DEBUG(UATH_DBG_USB,
+		    "uath: uath_list_all_endpoint: "
+		    "ep addresa[%x] is %x",
+		    i, ep_descr->bEndpointAddress);
+	}
+}
+
+static usb_ep_data_t *
+uath_lookup_ep_data(dev_info_t *dip,
+    usb_client_dev_data_t *dev_datap,
+    uint_t interface,
+    uint_t alternate,
+    uint8_t address,
+    uint8_t type)
+{
+	usb_alt_if_data_t *altif_data;
+	int i;
+
+	if ((dip == NULL) || (dev_datap == NULL))
+		return (NULL);
+
+	altif_data = &dev_datap->dev_curr_cfg->
+	    cfg_if[interface].if_alt[alternate];
+
+	for (i = 0; i < altif_data->altif_n_ep; i++) {
+		usb_ep_descr_t *ept = &altif_data->altif_ep[i].ep_descr;
+		uint8_t ept_type = ept->bmAttributes & USB_EP_ATTR_MASK;
+		uint8_t ept_address = ept->bEndpointAddress;
+
+		if (ept->bLength == 0)
+			continue;
+		if ((ept_type == type) &&
+		    ((type == USB_EP_ATTR_CONTROL) || (address == ept_address)))
+			return (&altif_data->altif_ep[i]);
+	}
+	return (NULL);
+}
+
+/*
+ * Open communication pipes.
+ * The following pipes are used by the AR5523:
+ * ep0: 0x81 IN  Rx cmd
+ * ep1: 0x01 OUT Tx cmd
+ * ep2: 0x82 IN  Rx data
+ * ep3: 0x02 OUT Tx data
+ */
+static int
+uath_open_pipes(struct uath_softc *sc)
+{
+	usb_ep_data_t *ep_node;
+	usb_ep_descr_t *ep_descr;
+	usb_pipe_policy_t policy;
+	int err;
+
+#ifdef DEBUG
+	usb_alt_if_data_t *altif_data;
+
+	altif_data = uath_lookup_alt_if(sc->sc_udev, UATH_CONFIG_NO,
+	    UATH_IFACE_INDEX, UATH_ALT_IF_INDEX);
+	if (altif_data == NULL) {
+		UATH_DEBUG(UATH_DBG_ERR, "alt_if not found");
+		return (USB_FAILURE);
+	}
+
+	uath_list_all_eps(altif_data);
+#endif
+
+	/*
+	 * XXX pipes numbers are hardcoded because we don't have any way
+	 * to distinguish the data pipes from the firmware command pipes
+	 * (both are bulk pipes) using the endpoints descriptors.
+	 */
+	ep_node = uath_lookup_ep_data(sc->sc_dev, sc->sc_udev,
+	    0, 0, 0x81, USB_EP_ATTR_BULK);
+	ep_descr = &ep_node->ep_descr;
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_open_pipes(): "
+	    "find pipe %x\n", ep_descr->bEndpointAddress);
+
+	bzero(&policy, sizeof (usb_pipe_policy_t));
+	policy.pp_max_async_reqs = UATH_CMD_LIST_COUNT;
+
+	err = usb_pipe_open(sc->sc_dev, &ep_node->ep_descr,
+	    &policy, USB_FLAGS_SLEEP, &sc->rx_cmd_pipe);
+	if (err != USB_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
+		    "failed to open rx data pipe, err = %x\n",
+		    err);
+		goto fail;
+	}
+
+
+	ep_node = uath_lookup_ep_data(sc->sc_dev, sc->sc_udev,
+	    0, 0, 0x01, USB_EP_ATTR_BULK);
+	ep_descr = &ep_node->ep_descr;
+	UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
+	    "find pipe %x\n",
+	    ep_descr->bEndpointAddress);
+
+	bzero(&policy, sizeof (usb_pipe_policy_t));
+	policy.pp_max_async_reqs = UATH_CMD_LIST_COUNT;
+
+	err = usb_pipe_open(sc->sc_dev, &ep_node->ep_descr,
+	    &policy, USB_FLAGS_SLEEP, &sc->tx_cmd_pipe);
+	if (err != USB_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
+		    "failed to open tx command pipe, err = %x\n",
+		    err);
+		goto fail;
+	}
+
+	ep_node = uath_lookup_ep_data(sc->sc_dev, sc->sc_udev,
+	    0, 0, 0x82, USB_EP_ATTR_BULK);
+	ep_descr = &ep_node->ep_descr;
+	UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
+	    "find pipe %x\n",
+	    ep_descr->bEndpointAddress);
+
+	bzero(&policy, sizeof (usb_pipe_policy_t));
+	policy.pp_max_async_reqs = UATH_RX_DATA_LIST_COUNT;
+
+	err = usb_pipe_open(sc->sc_dev, &ep_node->ep_descr,
+	    &policy, USB_FLAGS_SLEEP, &sc->rx_data_pipe);
+	if (err != USB_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
+		    "failed to open tx pipe, err = %x\n",
+		    err);
+		goto fail;
+	}
+
+	ep_node = uath_lookup_ep_data(sc->sc_dev, sc->sc_udev,
+	    0, 0, 0x02, USB_EP_ATTR_BULK);
+	ep_descr = &ep_node->ep_descr;
+	UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
+	    "find pipe %x\n",
+	    ep_descr->bEndpointAddress);
+
+	bzero(&policy, sizeof (usb_pipe_policy_t));
+	policy.pp_max_async_reqs = UATH_TX_DATA_LIST_COUNT;
+
+	err = usb_pipe_open(sc->sc_dev, &ep_node->ep_descr,
+	    &policy, USB_FLAGS_SLEEP, &sc->tx_data_pipe);
+	if (err != USB_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
+		    "failed to open rx command pipe, err = %x\n",
+		    err);
+		goto fail;
+	}
+
+	return (UATH_SUCCESS);
+fail:
+	uath_close_pipes(sc);
+	return (err);
+}
+
+static void
+uath_close_pipes(struct uath_softc *sc)
+{
+	usb_flags_t flags = USB_FLAGS_SLEEP;
+
+	if (sc->rx_cmd_pipe != NULL) {
+		usb_pipe_reset(sc->sc_dev, sc->rx_cmd_pipe, flags, NULL, 0);
+		usb_pipe_close(sc->sc_dev, sc->rx_cmd_pipe, flags, NULL, 0);
+		sc->rx_cmd_pipe = NULL;
+	}
+
+	if (sc->tx_cmd_pipe != NULL) {
+		usb_pipe_reset(sc->sc_dev, sc->tx_cmd_pipe, flags, NULL, 0);
+		usb_pipe_close(sc->sc_dev, sc->tx_cmd_pipe, flags, NULL, 0);
+		sc->tx_cmd_pipe = NULL;
+	}
+
+	if (sc->rx_data_pipe != NULL) {
+		usb_pipe_reset(sc->sc_dev, sc->rx_data_pipe, flags, NULL, 0);
+		usb_pipe_close(sc->sc_dev, sc->rx_data_pipe, flags, NULL, 0);
+		sc->rx_data_pipe = NULL;
+	}
+
+	if (sc->tx_data_pipe != NULL) {
+		usb_pipe_reset(sc->sc_dev, sc->tx_data_pipe, flags, NULL, 0);
+		usb_pipe_close(sc->sc_dev, sc->tx_data_pipe, flags, NULL, 0);
+		sc->tx_data_pipe = NULL;
+	}
+
+}
+
+static const char *
+uath_codename(int code)
+{
+#define	N(a)	(sizeof (a)/sizeof (a[0]))
+	static const char *names[] = {
+	    "0x00",
+	    "HOST_AVAILABLE",
+	    "BIND",
+	    "TARGET_RESET",
+	    "TARGET_GET_CAPABILITY",
+	    "TARGET_SET_CONFIG",
+	    "TARGET_GET_STATUS",
+	    "TARGET_GET_STATS",
+	    "TARGET_START",
+	    "TARGET_STOP",
+	    "TARGET_ENABLE",
+	    "TARGET_DISABLE",
+	    "CREATE_CONNECTION",
+	    "UPDATE_CONNECT_ATTR",
+	    "DELETE_CONNECT",
+	    "SEND",
+	    "FLUSH",
+	    "STATS_UPDATE",
+	    "BMISS",
+	    "DEVICE_AVAIL",
+	    "SEND_COMPLETE",
+	    "DATA_AVAIL",
+	    "SET_PWR_MODE",
+	    "BMISS_ACK",
+	    "SET_LED_STEADY",
+	    "SET_LED_BLINK",
+	    "SETUP_BEACON_DESC",
+	    "BEACON_INIT",
+	    "RESET_KEY_CACHE",
+	    "RESET_KEY_CACHE_ENTRY",
+	    "SET_KEY_CACHE_ENTRY",
+	    "SET_DECOMP_MASK",
+	    "SET_REGULATORY_DOMAIN",
+	    "SET_LED_STATE",
+	    "WRITE_ASSOCID",
+	    "SET_STA_BEACON_TIMERS",
+	    "GET_TSF",
+	    "RESET_TSF",
+	    "SET_ADHOC_MODE",
+	    "SET_BASIC_RATE",
+	    "MIB_CONTROL",
+	    "GET_CHANNEL_DATA",
+	    "GET_CUR_RSSI",
+	    "SET_ANTENNA_SWITCH",
+	    "0x2c", "0x2d", "0x2e",
+	    "USE_SHORT_SLOT_TIME",
+	    "SET_POWER_MODE",
+	    "SETUP_PSPOLL_DESC",
+	    "SET_RX_MULTICAST_FILTER",
+	    "RX_FILTER",
+	    "PER_CALIBRATION",
+	    "RESET",
+	    "DISABLE",
+	    "PHY_DISABLE",
+	    "SET_TX_POWER_LIMIT",
+	    "SET_TX_QUEUE_PARAMS",
+	    "SETUP_TX_QUEUE",
+	    "RELEASE_TX_QUEUE",
+	};
+	static char buf[8];
+
+	if (code < N(names))
+		return (names[code]);
+	if (code == WDCMSG_SET_DEFAULT_KEY)
+		return ("SET_DEFAULT_KEY");
+
+	(void) snprintf(buf, sizeof (buf), "0x%02x", code);
+	return (buf);
+#undef N
+}
+
+static int
+uath_fw_send(struct uath_softc *sc, usb_pipe_handle_t pipe,
+    const void *data, size_t len)
+{
+	usb_bulk_req_t *send_req;
+	mblk_t *mblk;
+	int res;
+
+	send_req = usb_alloc_bulk_req(sc->sc_dev, len, USB_FLAGS_SLEEP);
+
+	send_req->bulk_len = (int)len;
+	send_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
+	send_req->bulk_timeout = UATH_CMD_TIMEOUT;
+
+	mblk = send_req->bulk_data;
+	bcopy(data, mblk->b_wptr, len);
+	mblk->b_wptr += len;
+
+	res = usb_pipe_bulk_xfer(pipe, send_req, USB_FLAGS_SLEEP);
+	if (res != USB_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_FW, "uath: uath_fw_send(): "
+		    "Error %x writing data to bulk/out pipe", res);
+		return (UATH_FAILURE);
+	}
+
+	usb_free_bulk_req(send_req);
+	return (UATH_SUCCESS);
+}
+
+static int
+uath_fw_ack(struct uath_softc *sc, int len)
+{
+	struct uath_fwblock *rxblock;
+	usb_bulk_req_t *req;
+	mblk_t *mp;
+	int err;
+
+	req = usb_alloc_bulk_req(sc->sc_dev, len, USB_FLAGS_SLEEP);
+	if (req == NULL) {
+		UATH_DEBUG(UATH_DBG_FW,
+		    "uath: uath_fw_ack(): "
+		    "uath_rx_transfer(): failed to allocate req");
+		return (UATH_FAILURE);
+	}
+
+	req->bulk_len			= len;
+	req->bulk_client_private	= (usb_opaque_t)sc;
+	req->bulk_timeout		= 0;
+	req->bulk_attributes		= USB_ATTRS_SHORT_XFER_OK
+	    | USB_ATTRS_AUTOCLEARING;
+
+	err = usb_pipe_bulk_xfer(sc->rx_cmd_pipe, req, USB_FLAGS_SLEEP);
+	if (err != USB_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_FW, "uath: uath_fw_ack(): "
+		    "failed to do rx xfer, %d", err);
+		usb_free_bulk_req(req);
+		return (UATH_FAILURE);
+	}
+
+	mp = req->bulk_data;
+	req->bulk_data = NULL;
+
+	rxblock = (struct uath_fwblock *)mp->b_rptr;
+	UATH_DEBUG(UATH_DBG_FW, "uath: uath_fw_ack() "
+	    "rxblock flags=0x%x total=%d\n",
+	    BE_32(rxblock->flags), BE_32(rxblock->rxtotal));
+
+	freemsg(mp);
+	usb_free_bulk_req(req);
+
+	return (UATH_SUCCESS);
+}
+
+/*
+ * find uath firmware module's "_start" "_end" symbols
+ * and get its size.
+ */
+static int
+uath_loadsym(ddi_modhandle_t modp, char *sym, char **start, size_t *len)
+{
+	char start_sym[64];
+	char end_sym[64];
+	char *p, *end;
+	int rv;
+	size_t n;
+
+	(void) snprintf(start_sym, sizeof (start_sym), "%s_start", sym);
+	(void) snprintf(end_sym, sizeof (end_sym), "%s_end", sym);
+
+	p = (char *)ddi_modsym(modp, start_sym, &rv);
+	if (p == NULL || rv != 0) {
+		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_loadsym(): "
+		    "mod %s: symbol %s not found\n", uath_fwmod, start_sym);
+		return (UATH_FAILURE);
+	}
+
+	end = (char *)ddi_modsym(modp, end_sym, &rv);
+	if (end == NULL || rv != 0) {
+		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_loadsym(): "
+		    "mod %s: symbol %s not found\n", uath_fwmod, end_sym);
+		return (UATH_FAILURE);
+	}
+
+	n = _PTRDIFF(end, p);
+	*start = p;
+	*len = n;
+
+	return (UATH_SUCCESS);
+}
+
+/*
+ * Load the MIPS R4000 microcode into the device.  Once the image is loaded,
+ * the device will detach itself from the bus and reattach later with a new
+ * product Id (a la ezusb).  XXX this could also be implemented in userland
+ * through /dev/ugen.
+ */
+static int
+uath_loadfirmware(struct uath_softc *sc)
+{
+	struct uath_fwblock txblock;
+	ddi_modhandle_t modp;
+	char *fw_index, *fw_image = NULL;
+	size_t fw_size, len;
+	int err = DDI_SUCCESS, rv = 0;
+
+	modp = ddi_modopen(uath_fwmod, KRTLD_MODE_FIRST, &rv);
+	if (modp == NULL) {
+		cmn_err(CE_WARN, "uath: uath_loadfirmware(): "
+		    "module %s not found\n", uath_fwmod);
+		goto label;
+	}
+
+	err = uath_loadsym(modp, uath_binmod, &fw_index, &fw_size);
+	if (err != UATH_SUCCESS) {
+		cmn_err(CE_WARN, "uath: uath_loadfirmware(): "
+		    "could not get firmware\n");
+		goto label;
+	}
+
+	fw_image = (char *)kmem_alloc(fw_size, KM_SLEEP);
+	if (fw_image == NULL) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_loadfirmware(): "
+		    "failed to alloc firmware memory\n");
+		err = UATH_FAILURE;
+		goto label;
+	}
+
+	(void) memcpy(fw_image, fw_index, fw_size);
+	fw_index = fw_image;
+	len = fw_size;
+	UATH_DEBUG(UATH_DBG_MSG, "loading firmware size = %lu\n", fw_size);
+
+	/* bzero(txblock, sizeof (struct uath_fwblock)); */
+	txblock.flags = BE_32(UATH_WRITE_BLOCK);
+	txblock.total = BE_32(fw_size);
+
+	while (len > 0) {
+		size_t mlen = min(len, UATH_MAX_FWBLOCK_SIZE);
+
+		txblock.remain = BE_32(len - mlen);
+		txblock.len = BE_32(mlen);
+
+		UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware(): "
+		    "sending firmware block: %d bytes sending\n", mlen);
+		UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware(): "
+		    "sending firmware block: %d bytes remaining\n",
+		    len - mlen);
+
+		/* send firmware block meta-data */
+		err = uath_fw_send(sc, sc->tx_cmd_pipe, &txblock,
+		    sizeof (struct uath_fwblock));
+		if (err != UATH_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware(): "
+			    "send block meta-data error");
+			goto label;
+		}
+
+		/* send firmware block data */
+		err = uath_fw_send(sc, sc->tx_data_pipe, fw_index, mlen);
+		if (err != UATH_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware() "
+			    "send block data err");
+			goto label;
+		}
+
+		/* wait for ack from firmware */
+		err = uath_fw_ack(sc, sizeof (struct uath_fwblock));
+		if (err != UATH_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware() "
+			    "rx block ack err");
+			goto label;
+		}
+
+		fw_index += mlen;
+		len -= mlen;
+	}
+
+label:
+	if (fw_image != NULL)
+		kmem_free(fw_image, fw_size);
+	fw_image = fw_index = NULL;
+	if (modp != NULL)
+		(void) ddi_modclose(modp);
+	return (err);
+}
+
+static int
+uath_alloc_cmd_list(struct uath_softc *sc, struct uath_cmd cmds[],
+    int ncmd, int maxsz)
+{
+	int i, err;
+
+	for (i = 0; i < ncmd; i++) {
+		struct uath_cmd *cmd = &cmds[i];
+
+		cmd->sc = sc;	/* backpointer for callbacks */
+		cmd->msgid = i;
+		cmd->buf = kmem_zalloc(maxsz, KM_NOSLEEP);
+		if (cmd->buf == NULL) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_alloc_cmd_list(): "
+			    "could not allocate xfer buffer\n");
+			err = DDI_ENOMEM;
+			goto fail;
+		}
+	}
+	return (UATH_SUCCESS);
+
+fail:
+	uath_free_cmd_list(cmds, ncmd);
+	return (err);
+}
+
+static int
+uath_init_cmd_list(struct uath_softc *sc)
+{
+	int i;
+
+	sc->sc_cmdid = sc->rx_cmd_queued = sc->tx_cmd_queued = 0;
+	for (i = 0; i < UATH_CMD_LIST_COUNT; i++) {
+		if (uath_rx_cmd_xfer(sc) != UATH_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init_cmd_list(): "
+			    "failed to init cmd list %x\n", i);
+			return (UATH_FAILURE);
+		}
+	}
+	return (UATH_SUCCESS);
+}
+
+static void
+uath_free_cmd_list(struct uath_cmd cmds[], int ncmd)
+{
+	int i;
+
+	for (i = 0; i < ncmd; i++)
+		if (cmds[i].buf != NULL) {
+			kmem_free(cmds[i].buf, UATH_MAX_CMDSZ);
+			cmds[i].buf = NULL;
+		}
+}
+
+static int
+uath_host_available(struct uath_softc *sc)
+{
+	struct uath_cmd_host_available setup;
+
+	/* inform target the host is available */
+	setup.sw_ver_major = BE_32(ATH_SW_VER_MAJOR);
+	setup.sw_ver_minor = BE_32(ATH_SW_VER_MINOR);
+	setup.sw_ver_patch = BE_32(ATH_SW_VER_PATCH);
+	setup.sw_ver_build = BE_32(ATH_SW_VER_BUILD);
+	return (uath_cmd_read(sc, WDCMSG_HOST_AVAILABLE,
+	    &setup, sizeof (setup), NULL, 0, 0));
+}
+
+static void
+uath_get_capability(struct uath_softc *sc, uint32_t cap, uint32_t *val)
+{
+	int err;
+
+	cap = BE_32(cap);
+	err = uath_cmd_read(sc, WDCMSG_TARGET_GET_CAPABILITY, &cap,
+	    sizeof (cap), val, sizeof (uint32_t), UATH_CMD_FLAG_MAGIC);
+	if (err == UATH_SUCCESS)
+		*val = BE_32(*val);
+	else
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_get_capability(): "
+		    "could not read capability %u\n", BE_32(cap));
+}
+
+static int
+uath_get_devcap(struct uath_softc *sc)
+{
+	struct uath_devcap *cap = &sc->sc_devcap;
+
+	/* collect device capabilities */
+	uath_get_capability(sc, CAP_TARGET_VERSION,
+	    &cap->targetVersion);
+	uath_get_capability(sc, CAP_TARGET_REVISION,
+	    &cap->targetRevision);
+	uath_get_capability(sc, CAP_MAC_VERSION,
+	    &cap->macVersion);
+	uath_get_capability(sc, CAP_MAC_REVISION,
+	    &cap->macRevision);
+	uath_get_capability(sc, CAP_PHY_REVISION,
+	    &cap->phyRevision);
+	uath_get_capability(sc, CAP_ANALOG_5GHz_REVISION,
+	    &cap->analog5GhzRevision);
+	uath_get_capability(sc, CAP_ANALOG_2GHz_REVISION,
+	    &cap->analog2GhzRevision);
+	uath_get_capability(sc, CAP_REG_DOMAIN,
+	    &cap->regDomain);
+	uath_get_capability(sc, CAP_REG_CAP_BITS,
+	    &cap->regCapBits);
+
+	/* NB: not supported in rev 1.5 */
+	/* uath_get_capability(sc, CAP_COUNTRY_CODE, cap->countryCode); */
+
+	uath_get_capability(sc, CAP_WIRELESS_MODES,
+	    &cap->wirelessModes);
+	uath_get_capability(sc, CAP_CHAN_SPREAD_SUPPORT,
+	    &cap->chanSpreadSupport);
+	uath_get_capability(sc, CAP_COMPRESS_SUPPORT,
+	    &cap->compressSupport);
+	uath_get_capability(sc, CAP_BURST_SUPPORT,
+	    &cap->burstSupport);
+	uath_get_capability(sc, CAP_FAST_FRAMES_SUPPORT,
+	    &cap->fastFramesSupport);
+	uath_get_capability(sc, CAP_CHAP_TUNING_SUPPORT,
+	    &cap->chapTuningSupport);
+	uath_get_capability(sc, CAP_TURBOG_SUPPORT,
+	    &cap->turboGSupport);
+	uath_get_capability(sc, CAP_TURBO_PRIME_SUPPORT,
+	    &cap->turboPrimeSupport);
+	uath_get_capability(sc, CAP_DEVICE_TYPE,
+	    &cap->deviceType);
+	uath_get_capability(sc, CAP_WME_SUPPORT,
+	    &cap->wmeSupport);
+	uath_get_capability(sc, CAP_TOTAL_QUEUES,
+	    &cap->numTxQueues);
+	uath_get_capability(sc, CAP_CONNECTION_ID_MAX,
+	    &cap->connectionIdMax);
+
+	uath_get_capability(sc, CAP_LOW_5GHZ_CHAN,
+	    &cap->low5GhzChan);
+	uath_get_capability(sc, CAP_HIGH_5GHZ_CHAN,
+	    &cap->high5GhzChan);
+	uath_get_capability(sc, CAP_LOW_2GHZ_CHAN,
+	    &cap->low2GhzChan);
+	uath_get_capability(sc, CAP_HIGH_2GHZ_CHAN,
+	    &cap->high2GhzChan);
+	uath_get_capability(sc, CAP_TWICE_ANTENNAGAIN_5G,
+	    &cap->twiceAntennaGain5G);
+	uath_get_capability(sc, CAP_TWICE_ANTENNAGAIN_2G,
+	    &cap->twiceAntennaGain2G);
+
+	uath_get_capability(sc, CAP_CIPHER_AES_CCM,
+	    &cap->supportCipherAES_CCM);
+	uath_get_capability(sc, CAP_CIPHER_TKIP,
+	    &cap->supportCipherTKIP);
+	uath_get_capability(sc, CAP_MIC_TKIP,
+	    &cap->supportMicTKIP);
+
+	cap->supportCipherWEP = 1;	/* NB: always available */
+	return (UATH_SUCCESS);
+}
+
+static int
+uath_get_status(struct uath_softc *sc, uint32_t which, void *odata, int olen)
+{
+	int err;
+
+	which = BE_32(which);
+	err = uath_cmd_read(sc, WDCMSG_TARGET_GET_STATUS,
+	    &which, sizeof (which), odata, olen, UATH_CMD_FLAG_MAGIC);
+	if (err != UATH_SUCCESS)
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_get_status(): "
+		    "could not read EEPROM offset 0x%02x\n", BE_32(which));
+	return (err);
+}
+
+static int
+uath_get_devstatus(struct uath_softc *sc, uint8_t macaddr[IEEE80211_ADDR_LEN])
+{
+	int err;
+
+	/* retrieve MAC address */
+	err = uath_get_status(sc, ST_MAC_ADDR, macaddr, IEEE80211_ADDR_LEN);
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_get_devstatus(): "
+		    "could not read MAC address\n");
+		return (err);
+	}
+
+	err = uath_get_status(sc, ST_SERIAL_NUMBER,
+	    &sc->sc_serial[0], sizeof (sc->sc_serial));
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_get_devstatus(): "
+		    "could not read device serial number\n");
+		return (err);
+	}
+
+	return (UATH_SUCCESS);
+}
+
+/*
+ * uath_cmd_lock: a special signal structure that is used for notification
+ * that a callback function has been called.
+ */
+
+/* Initializes the uath_cmd_lock structure. */
+static void
+uath_cmd_lock_init(struct uath_cmd_lock *lock)
+{
+	ASSERT(lock != NULL);
+	mutex_init(&lock->mutex, NULL, MUTEX_DRIVER, NULL);
+	cv_init(&lock->cv, NULL, CV_DRIVER, NULL);
+	lock->done = B_FALSE;
+}
+
+/* Deinitalizes the uath_cb_lock structure. */
+void
+uath_cmd_lock_destroy(struct uath_cmd_lock *lock)
+{
+	ASSERT(lock != NULL);
+	mutex_destroy(&lock->mutex);
+	cv_destroy(&lock->cv);
+}
+
+/*
+ * Wait on lock until someone calls the "signal" function or the timeout
+ * expires. Note: timeout is in microseconds.
+ */
+static int
+uath_cmd_lock_wait(struct uath_cmd_lock *lock, clock_t timeout)
+{
+	int res, cv_res;
+	clock_t etime;
+
+	ASSERT(lock != NULL);
+	mutex_enter(&lock->mutex);
+
+	if (timeout < 0) {
+		/* no timeout - wait as long as needed */
+		while (lock->done == B_FALSE)
+			cv_wait(&lock->cv, &lock->mutex);
+	} else {
+		/* wait with timeout (given in usec) */
+		etime = ddi_get_lbolt() + drv_usectohz(timeout);
+		while (lock->done == B_FALSE) {
+			cv_res = cv_timedwait_sig(&lock->cv,
+			    &lock->mutex, etime);
+			if (cv_res <= 0) break;
+		}
+	}
+
+	res = (lock->done == B_TRUE) ? UATH_SUCCESS : UATH_FAILURE;
+	mutex_exit(&lock->mutex);
+
+	return (res);
+}
+
+/* Signal that the job (eg. callback) is done and unblock anyone who waits. */
+static void
+uath_cmd_lock_signal(struct uath_cmd_lock *lock)
+{
+	ASSERT(lock != NULL);
+
+	mutex_enter(&lock->mutex);
+	lock->done = B_TRUE;
+	cv_broadcast(&lock->cv);
+	mutex_exit(&lock->mutex);
+}
+
+static int
+uath_cmd_read(struct uath_softc *sc, uint32_t code, const void *idata,
+    int ilen, void *odata, int olen, int flags)
+{
+	flags |= UATH_CMD_FLAG_READ;
+	return (uath_cmdsend(sc, code, idata, ilen, odata, olen, flags));
+}
+
+static int
+uath_cmd_write(struct uath_softc *sc, uint32_t code, const void *data,
+    int len, int flags)
+{
+	flags &= ~UATH_CMD_FLAG_READ;
+	return (uath_cmdsend(sc, code, data, len, NULL, 0, flags));
+}
+
+/*
+ * Low-level function to send read or write commands to the firmware.
+ */
+static int
+uath_cmdsend(struct uath_softc *sc, uint32_t code, const void *idata, int ilen,
+    void *odata, int olen, int flags)
+{
+	struct uath_cmd_hdr *hdr;
+	struct uath_cmd *cmd;
+	int err;
+
+	/* grab a xfer */
+	cmd = &sc->sc_cmd[sc->sc_cmdid];
+
+	cmd->flags = flags;
+	/* always bulk-out a multiple of 4 bytes */
+	cmd->buflen = (sizeof (struct uath_cmd_hdr) + ilen + 3) & ~3;
+
+	hdr = (struct uath_cmd_hdr *)cmd->buf;
+	bzero(hdr, sizeof (struct uath_cmd_hdr));
+	hdr->len   = BE_32(cmd->buflen);
+	hdr->code  = BE_32(code);
+	hdr->msgid = cmd->msgid;	/* don't care about endianness */
+	hdr->magic = BE_32((cmd->flags & UATH_CMD_FLAG_MAGIC) ? 1 << 24 : 0);
+	bcopy(idata, (uint8_t *)(hdr + 1), ilen);
+
+	UATH_DEBUG(UATH_DBG_TX_CMD, "uath: uath_cmdsend(): "
+	    "queue %x send %s [flags 0x%x] olen %d\n",
+	    cmd->msgid, uath_codename(code), cmd->flags, olen);
+
+	cmd->odata = odata;
+	if (odata == NULL)
+		UATH_DEBUG(UATH_DBG_TX_CMD, "uath: uath_cmdsend(): "
+		    "warning - odata is NULL\n");
+	else if (olen < UATH_MAX_CMDSZ - sizeof (*hdr) + sizeof (uint32_t))
+		UATH_DEBUG(UATH_DBG_TX_CMD, "uath: uath_cmdsend(): "
+		    "warning - olen %x is short\n, olen");
+	cmd->olen = olen;
+
+	err = uath_tx_cmd_xfer(sc, sc->tx_cmd_pipe, cmd->buf, cmd->buflen);
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_cmdsend(): "
+		    "Error writing command\n");
+		return (UATH_FAILURE);
+	}
+
+	sc->sc_cmdid = (sc->sc_cmdid + 1) % UATH_CMD_LIST_COUNT;
+
+	if (cmd->flags & UATH_CMD_FLAG_READ) {
+		/* wait at most two seconds for command reply */
+		uath_cmd_lock_init(&sc->rlock);
+		err = uath_cmd_lock_wait(&sc->rlock, 2000000);
+		cmd->odata = NULL;	/* in case reply comes too late */
+		if (err != UATH_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_cmdsend(): "
+			    "timeout waiting for reply, "
+			    "to cmd 0x%x (%u), queue %x\n",
+			    code, code, cmd->msgid);
+			err = UATH_FAILURE;
+		} else if (cmd->olen != olen) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_cmdsend(): "
+			    "unexpected reply data count "
+			    "to cmd 0x%x (%x), got %u, expected %u\n",
+			    code, cmd->msgid, cmd->olen, olen);
+			err = UATH_FAILURE;
+		}
+		uath_cmd_lock_destroy(&sc->rlock);
+		return (err);
+	}
+
+	return (UATH_SUCCESS);
+}
+
+/* ARGSUSED */
+static void
+uath_cmd_txeof(usb_pipe_handle_t pipe, struct usb_bulk_req *req)
+{
+	struct uath_softc *sc = (struct uath_softc *)req->bulk_client_private;
+
+	UATH_DEBUG(UATH_DBG_TX_CMD, "uath: uath_cmd_txeof(): "
+	    "cr:%s(%d), flags:0x%x, tx queued %d\n",
+	    usb_str_cr(req->bulk_completion_reason),
+	    req->bulk_completion_reason,
+	    req->bulk_cb_flags,
+	    sc->tx_cmd_queued);
+
+	if (req->bulk_completion_reason != USB_CR_OK)
+		sc->sc_tx_err++;
+
+	mutex_enter(&sc->sc_txlock_cmd);
+	sc->tx_cmd_queued--;
+	mutex_exit(&sc->sc_txlock_cmd);
+	usb_free_bulk_req(req);
+}
+
+static int
+uath_tx_cmd_xfer(struct uath_softc *sc,
+    usb_pipe_handle_t pipe, const void *data, uint_t len)
+{
+	usb_bulk_req_t *send_req;
+	mblk_t *mblk;
+	int res;
+
+	send_req = usb_alloc_bulk_req(sc->sc_dev, len, USB_FLAGS_SLEEP);
+
+	send_req->bulk_client_private		= (usb_opaque_t)sc;
+	send_req->bulk_len			= (int)len;
+	send_req->bulk_attributes		= USB_ATTRS_AUTOCLEARING;
+	send_req->bulk_timeout			= UATH_CMD_TIMEOUT;
+	send_req->bulk_cb			= uath_cmd_txeof;
+	send_req->bulk_exc_cb			= uath_cmd_txeof;
+	send_req->bulk_completion_reason	= 0;
+	send_req->bulk_cb_flags			= 0;
+
+	mblk = send_req->bulk_data;
+	bcopy(data, mblk->b_rptr, len);
+	mblk->b_wptr += len;
+
+	res = usb_pipe_bulk_xfer(pipe, send_req, USB_FLAGS_NOSLEEP);
+	if (res != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_tx_cmd_xfer(): "
+		    "Error %x writing cmd to bulk/out pipe", res);
+		return (UATH_FAILURE);
+	}
+
+	mutex_enter(&sc->sc_txlock_cmd);
+	sc->tx_cmd_queued++;
+	mutex_exit(&sc->sc_txlock_cmd);
+	return (UATH_SUCCESS);
+}
+
+static void
+uath_cmdeof(struct uath_softc *sc, struct uath_cmd *cmd)
+{
+	struct uath_cmd_hdr *hdr;
+	int dlen;
+
+	hdr = (struct uath_cmd_hdr *)cmd->buf;
+
+	hdr->code = BE_32(hdr->code);
+	hdr->len = BE_32(hdr->len);
+	hdr->magic = BE_32(hdr->magic);	/* target status on return */
+
+	/* NB: msgid is passed thru w/o byte swapping */
+	UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): "
+	    "%s: [ix %x] len=%x status %x\n",
+	    uath_codename(hdr->code),
+	    hdr->msgid,
+	    hdr->len,
+	    hdr->magic);
+
+	switch (hdr->code & 0xff) {
+	/* reply to a read command */
+	default:
+		dlen = hdr->len - sizeof (*hdr);
+		UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): "
+		    "code %x data len %u\n",
+		    hdr->code & 0xff, dlen);
+
+		/*
+		 * The first response from the target after the
+		 * HOST_AVAILABLE has an invalid msgid so we must
+		 * treat it specially.
+		 */
+		if ((hdr->msgid < UATH_CMD_LIST_COUNT) && (hdr->code != 0x13)) {
+			uint32_t *rp = (uint32_t *)(hdr + 1);
+			uint_t olen;
+
+			if (!(sizeof (*hdr) <= hdr->len &&
+			    hdr->len < UATH_MAX_CMDSZ)) {
+				UATH_DEBUG(UATH_DBG_RX_CMD,
+				    "uath: uath_cmdeof(): "
+				    "invalid WDC msg length %u; "
+				    "msg ignored\n",
+				    hdr->len);
+				return;
+			}
+
+			/*
+			 * Calculate return/receive payload size; the
+			 * first word, if present, always gives the
+			 * number of bytes--unless it's 0 in which
+			 * case a single 32-bit word should be present.
+			 */
+			if (dlen >= sizeof (uint32_t)) {
+				olen = BE_32(rp[0]);
+				dlen -= sizeof (uint32_t);
+				if (olen == 0) {
+					/* convention is 0 =>'s one word */
+					olen = sizeof (uint32_t);
+					/* XXX KASSERT(olen == dlen ) */
+				}
+			} else
+				olen = 0;
+
+			if (cmd->odata != NULL) {
+				/* NB: cmd->olen validated in uath_cmd */
+				if (olen > cmd->olen) {
+					/* XXX complain? */
+					UATH_DEBUG(UATH_DBG_RX_CMD,
+					    "uath: uath_cmdeof(): "
+					    "cmd 0x%x olen %u cmd olen %u\n",
+					    hdr->code, olen, cmd->olen);
+					olen = cmd->olen;
+				}
+				if (olen > dlen) {
+					/* XXX complain, shouldn't happen */
+					UATH_DEBUG(UATH_DBG_RX_CMD,
+					    "uath: uath_cmdeof(): "
+					    "cmd 0x%x olen %u dlen %u\n",
+					    hdr->code, olen, dlen);
+					olen = dlen;
+				}
+				/* XXX have submitter do this */
+				/* copy answer into caller's supplied buffer */
+				bcopy(&rp[1], cmd->odata, olen);
+				cmd->olen = olen;
+			}
+		}
+
+		/* Just signal that something happened */
+		uath_cmd_lock_signal(&sc->rlock);
+		break;
+
+	case WDCMSG_TARGET_START:
+		UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): "
+		    "receive TARGET STAERT\n");
+
+		if (hdr->msgid >= UATH_CMD_LIST_COUNT) {
+			/* XXX */
+			return;
+		}
+		dlen = hdr->len - sizeof (*hdr);
+		if (dlen != sizeof (uint32_t)) {
+			/* XXX something wrong */
+			return;
+		}
+		/* XXX have submitter do this */
+		/* copy answer into caller's supplied buffer */
+		bcopy(hdr + 1, cmd->odata, sizeof (uint32_t));
+		cmd->olen = sizeof (uint32_t);
+
+		/* wake up caller */
+		uath_cmd_lock_signal(&sc->rlock);
+		break;
+
+	case WDCMSG_SEND_COMPLETE:
+		/* this notification is sent when UATH_TX_NOTIFY is set */
+		UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): "
+		    "receive Tx notification\n");
+		break;
+
+	case WDCMSG_TARGET_GET_STATS:
+		UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): "
+		    "received device statistics\n");
+		break;
+	}
+}
+
+/* ARGSUSED */
+static void
+uath_cmd_rxeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
+{
+	struct uath_softc *sc = (struct uath_softc *)req->bulk_client_private;
+	struct uath_cmd_hdr *hdr;
+	struct uath_cmd *cmd;
+	mblk_t *m, *mp;
+	int len;
+
+	UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmd_rxeof(): "
+	    "cr:%s(%d), flags:0x%x, rx queued %d\n",
+	    usb_str_cr(req->bulk_completion_reason),
+	    req->bulk_completion_reason,
+	    req->bulk_cb_flags,
+	    sc->rx_cmd_queued);
+
+	m = req->bulk_data;
+	req->bulk_data = NULL;
+
+	if (req->bulk_completion_reason != USB_CR_OK) {
+		UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmd_rxeof(): "
+		    "USB CR is not OK\n");
+		goto fail;
+	}
+
+	if (m->b_cont != NULL) {
+		/* Fragmented message, concatenate */
+		mp = msgpullup(m, -1);
+		freemsg(m);
+		m = mp;
+		mp = NULL;
+	}
+
+	len = msgdsize(m);
+	if (len < sizeof (struct uath_cmd_hdr)) {
+		UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_rx_cmdeof(): "
+		    "short xfer error\n");
+		goto fail;
+	}
+
+	hdr = (struct uath_cmd_hdr *)m->b_rptr;
+	if (BE_32(hdr->code) == 0x13)
+		cmd = &sc->sc_cmd[0];
+	else
+		cmd = &sc->sc_cmd[hdr->msgid];
+
+	bcopy(m->b_rptr, cmd->buf, len);
+	uath_cmdeof(sc, cmd);
+	(void) uath_rx_cmd_xfer(sc);
+fail:
+	mutex_enter(&sc->sc_rxlock_cmd);
+	sc->rx_cmd_queued--;
+	mutex_exit(&sc->sc_rxlock_cmd);
+	if (m) freemsg(m);
+	usb_free_bulk_req(req);
+}
+
+static int
+uath_rx_cmd_xfer(struct uath_softc *sc)
+{
+	usb_bulk_req_t *req;
+	int err;
+
+	req = usb_alloc_bulk_req(sc->sc_dev, UATH_MAX_CMDSZ, USB_FLAGS_SLEEP);
+	if (req == NULL) {
+		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_rx_cmd_xfer(): "
+		    "failed to allocate req");
+		return (UATH_FAILURE);
+	}
+
+	req->bulk_len			= UATH_MAX_CMDSZ;
+	req->bulk_client_private	= (usb_opaque_t)sc;
+	req->bulk_cb			= uath_cmd_rxeof;
+	req->bulk_exc_cb		= uath_cmd_rxeof;
+	req->bulk_timeout		= 0;
+	req->bulk_completion_reason	= 0;
+	req->bulk_cb_flags		= 0;
+	req->bulk_attributes		= USB_ATTRS_SHORT_XFER_OK
+	    | USB_ATTRS_AUTOCLEARING;
+
+	err = usb_pipe_bulk_xfer(sc->rx_cmd_pipe, req, USB_FLAGS_NOSLEEP);
+	if (err != USB_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_rx_cmd_xfer(): "
+		    "failed to do rx xfer, %d", err);
+		usb_free_bulk_req(req);
+		return (UATH_FAILURE);
+	}
+
+	mutex_enter(&sc->sc_rxlock_cmd);
+	sc->rx_cmd_queued++;
+	mutex_exit(&sc->sc_rxlock_cmd);
+	return (UATH_SUCCESS);
+}
+
+static void
+uath_init_data_queue(struct uath_softc *sc)
+{
+	sc->tx_data_queued = sc->rx_data_queued = 0;
+}
+
+/* ARGSUSED */
+static void
+uath_data_txeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
+{
+	struct uath_softc *sc = (struct uath_softc *)req->bulk_client_private;
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	UATH_DEBUG(UATH_DBG_TX, "uath: uath_data_txeof(): "
+	    "uath_txeof(): cr:%s(%d), flags:0x%x, tx_data_queued %d\n",
+	    usb_str_cr(req->bulk_completion_reason),
+	    req->bulk_completion_reason,
+	    req->bulk_cb_flags,
+	    sc->tx_data_queued);
+
+	if (req->bulk_completion_reason != USB_CR_OK)
+		sc->sc_tx_err++;
+
+	mutex_enter(&sc->sc_txlock_data);
+	sc->tx_data_queued--;
+
+	if (sc->sc_need_sched) {
+		sc->sc_need_sched = 0;
+		mac_tx_update(ic->ic_mach);
+	}
+
+	mutex_exit(&sc->sc_txlock_data);
+	usb_free_bulk_req(req);
+}
+
+static int
+uath_tx_data_xfer(struct uath_softc *sc, mblk_t *mp)
+{
+	usb_bulk_req_t *req;
+	int err;
+
+	req = usb_alloc_bulk_req(sc->sc_dev, 0, USB_FLAGS_SLEEP);
+	if (req == NULL) {
+		UATH_DEBUG(UATH_DBG_TX, "uath: uath_tx_data_xfer(): "
+		    "uath_tx_data_xfer(): failed to allocate req");
+		freemsg(mp);
+		return (UATH_FAILURE);
+	}
+
+	req->bulk_len			= msgdsize(mp);
+	req->bulk_data			= mp;
+	req->bulk_client_private 	= (usb_opaque_t)sc;
+	req->bulk_timeout		= UATH_DATA_TIMEOUT;
+	req->bulk_attributes		= USB_ATTRS_AUTOCLEARING;
+	req->bulk_cb			= uath_data_txeof;
+	req->bulk_exc_cb		= uath_data_txeof;
+	req->bulk_completion_reason 	= 0;
+	req->bulk_cb_flags		= 0;
+
+	if ((err = usb_pipe_bulk_xfer(sc->tx_data_pipe, req, 0)) !=
+	    USB_SUCCESS) {
+
+		UATH_DEBUG(UATH_DBG_TX, "uath: uath_tx_data_xfer(): "
+		    "failed to do tx xfer, %d", err);
+		usb_free_bulk_req(req);
+		return (UATH_FAILURE);
+	}
+
+	sc->tx_data_queued++;
+	return (UATH_SUCCESS);
+}
+
+/* ARGSUSED */
+static void
+uath_data_rxeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
+{
+	struct uath_softc *sc = (struct uath_softc *)req->bulk_client_private;
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct uath_chunk *chunk;
+	struct uath_rx_desc *desc;
+	struct ieee80211_frame *wh;
+	struct ieee80211_node *ni;
+
+	mblk_t *m, *mp;
+	uint8_t *rxbuf;
+	int actlen, pktlen;
+
+	mutex_enter(&sc->sc_rxlock_data);
+
+	UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
+	    "cr:%s(%d), flags:0x%x, rx_data_queued %d\n",
+	    usb_str_cr(req->bulk_completion_reason),
+	    req->bulk_completion_reason,
+	    req->bulk_cb_flags,
+	    sc->rx_data_queued);
+
+	mp = req->bulk_data;
+	req->bulk_data = NULL;
+
+	if (req->bulk_completion_reason != USB_CR_OK) {
+		UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
+		    "USB CR is not OK\n");
+		sc->sc_rx_err++;
+		goto fail;
+	}
+
+	rxbuf = (uint8_t *)mp->b_rptr;
+	actlen = (uintptr_t)mp->b_wptr - (uintptr_t)mp->b_rptr;
+	if (actlen < UATH_MIN_RXBUFSZ) {
+		UATH_DEBUG(UATH_DBG_RX, "uath_data_rxeof(): "
+		    "wrong recv size %d\n", actlen);
+		sc->sc_rx_err++;
+		goto fail;
+	}
+
+	chunk = (struct uath_chunk *)rxbuf;
+	if (chunk->seqnum == 0 && chunk->flags == 0 && chunk->length == 0) {
+		UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
+		    "strange response\n");
+		UATH_RESET_INTRX(sc);
+		sc->sc_rx_err++;
+		goto fail;
+	}
+
+	if (chunk->seqnum != sc->sc_intrx_nextnum) {
+		UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
+		    "invalid seqnum %d, expected %d\n",
+		    chunk->seqnum, sc->sc_intrx_nextnum);
+		UATH_STAT_INC(sc, st_badchunkseqnum);
+		UATH_RESET_INTRX(sc);
+		sc->sc_rx_err++;
+		goto fail;
+	}
+
+	/* check multi-chunk frames  */
+	if ((chunk->seqnum == 0 && !(chunk->flags & UATH_CFLAGS_FINAL)) ||
+	    (chunk->seqnum != 0 && (chunk->flags & UATH_CFLAGS_FINAL)) ||
+	    chunk->flags & UATH_CFLAGS_RXMSG) {
+		UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
+		    "receive multi-chunk frames "
+		    "chunk seqnum %x, flags %x, length %u\n",
+		    chunk->seqnum, chunk->flags, BE_16(chunk->length));
+		UATH_STAT_INC(sc, st_multichunk);
+	}
+
+
+	/* if the frame is not final continue the transfer  */
+	if (!(chunk->flags & UATH_CFLAGS_FINAL))
+		sc->sc_intrx_nextnum++;
+
+	/*
+	 * if the frame is not set UATH_CFLAGS_RXMSG, then rx descriptor is
+	 * located at the end, 32-bit aligned
+	 */
+	desc = (chunk->flags & UATH_CFLAGS_RXMSG) ?
+	    (struct uath_rx_desc *)(chunk + 1) :
+	    (struct uath_rx_desc *)(((uint8_t *)chunk) +
+	    sizeof (struct uath_chunk) + BE_16(chunk->length) -
+	    sizeof (struct uath_rx_desc));
+
+	UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
+	    "frame len %u code %u status %u rate %u antenna %u "
+	    "rssi %d channel %u phyerror %u connix %u "
+	    "decrypterror %u keycachemiss %u\n",
+	    BE_32(desc->framelen), BE_32(desc->code), BE_32(desc->status),
+	    BE_32(desc->rate), BE_32(desc->antenna), BE_32(desc->rssi),
+	    BE_32(desc->channel), BE_32(desc->phyerror), BE_32(desc->connix),
+	    BE_32(desc->decrypterror), BE_32(desc->keycachemiss));
+
+	if (BE_32(desc->len) > IEEE80211_MAX_LEN) {
+		UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
+		    "bad descriptor (len=%d)\n", BE_32(desc->len));
+		UATH_STAT_INC(sc, st_toobigrxpkt);
+		goto fail;
+	}
+
+	uath_update_rxstat(sc, BE_32(desc->status));
+
+	pktlen = BE_32(desc->framelen) - UATH_RX_DUMMYSIZE;
+
+	if ((m = allocb(pktlen, BPRI_MED)) == NULL) {
+		UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
+		    "allocate mblk failed.\n");
+		sc->sc_rx_nobuf++;
+		goto fail;
+	}
+	bcopy((rxbuf + sizeof (struct uath_chunk)), m->b_rptr, pktlen);
+
+	m->b_wptr = m->b_rptr + pktlen;
+	wh = (struct ieee80211_frame *)m->b_rptr;
+	ni = ieee80211_find_rxnode(ic, wh);
+
+	/* send the frame to the 802.11 layer */
+	(void) ieee80211_input(ic, m, ni, (int)BE_32(desc->rssi), 0);
+
+	/* node is no longer needed */
+	ieee80211_free_node(ni);
+fail:
+	sc->rx_data_queued--;
+	if (mp) freemsg(mp);
+	usb_free_bulk_req(req);
+	mutex_exit(&sc->sc_rxlock_data);
+	if (UATH_IS_RUNNING(sc) && !UATH_IS_SUSPEND(sc)) {
+		(void) uath_rx_data_xfer(sc);
+	}
+}
+
+static int
+uath_rx_data_xfer(struct uath_softc *sc)
+{
+	usb_bulk_req_t *req;
+	int err;
+
+	req = usb_alloc_bulk_req(sc->sc_dev,
+	    IEEE80211_MAX_LEN, USB_FLAGS_SLEEP);
+	if (req == NULL) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_rx_data_xfer(): "
+		    "failed to allocate req");
+		return (UATH_SUCCESS);
+	}
+
+	req->bulk_len			= IEEE80211_MAX_LEN;
+	req->bulk_cb			= uath_data_rxeof;
+	req->bulk_exc_cb		= uath_data_rxeof;
+	req->bulk_client_private	= (usb_opaque_t)sc;
+	req->bulk_timeout		= 0;
+	req->bulk_completion_reason	= 0;
+	req->bulk_cb_flags		= 0;
+	req->bulk_attributes		= USB_ATTRS_SHORT_XFER_OK
+	    | USB_ATTRS_AUTOCLEARING;
+
+	err = usb_pipe_bulk_xfer(sc->rx_data_pipe, req, 0);
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_rx_data_xfer(): "
+		    "failed to do rx xfer, %d", err);
+		usb_free_bulk_req(req);
+		return (UATH_FAILURE);
+	}
+
+	mutex_enter(&sc->sc_rxlock_data);
+	sc->rx_data_queued++;
+	mutex_exit(&sc->sc_rxlock_data);
+	return (UATH_SUCCESS);
+}
+
+static void
+uath_update_rxstat(struct uath_softc *sc, uint32_t status)
+{
+
+	switch (status) {
+	case UATH_STATUS_STOP_IN_PROGRESS:
+		UATH_STAT_INC(sc, st_stopinprogress);
+		break;
+	case UATH_STATUS_CRC_ERR:
+		UATH_STAT_INC(sc, st_crcerr);
+		break;
+	case UATH_STATUS_PHY_ERR:
+		UATH_STAT_INC(sc, st_phyerr);
+		break;
+	case UATH_STATUS_DECRYPT_CRC_ERR:
+		UATH_STAT_INC(sc, st_decrypt_crcerr);
+		break;
+	case UATH_STATUS_DECRYPT_MIC_ERR:
+		UATH_STAT_INC(sc, st_decrypt_micerr);
+		break;
+	case UATH_STATUS_DECOMP_ERR:
+		UATH_STAT_INC(sc, st_decomperr);
+		break;
+	case UATH_STATUS_KEY_ERR:
+		UATH_STAT_INC(sc, st_keyerr);
+		break;
+	case UATH_STATUS_ERR:
+		UATH_STAT_INC(sc, st_err);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+uath_next_scan(void *arg)
+{
+	struct uath_softc	*sc = arg;
+	struct ieee80211com	*ic = &sc->sc_ic;
+
+	if (ic->ic_state == IEEE80211_S_SCAN)
+		ieee80211_next_scan(ic);
+
+	sc->sc_scan_id = 0;
+}
+
+static int
+uath_create_connection(struct uath_softc *sc, uint32_t connid)
+{
+	const struct ieee80211_rateset *rs;
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211_node *ni = ic->ic_bss;
+	struct uath_cmd_create_connection create;
+	int err;
+
+	bzero(&create, sizeof (create));
+	create.connid = BE_32(connid);
+	create.bssid = BE_32(0);
+	/* XXX packed or not?  */
+	create.size = BE_32(sizeof (struct uath_cmd_rateset));
+
+	rs = &ni->in_rates;
+	create.connattr.rateset.length = rs->ir_nrates;
+	bcopy(rs->ir_rates, &create.connattr.rateset.set[0],
+	    rs->ir_nrates);
+
+	/* XXX turbo */
+	if (UATH_IS_CHAN_A(ni->in_chan))
+		create.connattr.wlanmode = BE_32(WLAN_MODE_11a);
+	else if (UATH_IS_CHAN_ANYG(ni->in_chan))
+		create.connattr.wlanmode = BE_32(WLAN_MODE_11g);
+	else
+		create.connattr.wlanmode = BE_32(WLAN_MODE_11b);
+
+	err = uath_cmd_write(sc, WDCMSG_CREATE_CONNECTION, &create,
+	    sizeof (create), 0);
+	return (err);
+}
+
+static int
+uath_set_rates(struct uath_softc *sc, const struct ieee80211_rateset *rs)
+{
+	struct uath_cmd_rates rates;
+	int err;
+
+	bzero(&rates, sizeof (rates));
+	rates.connid = BE_32(UATH_ID_BSS);		/* XXX */
+	rates.size   = BE_32(sizeof (struct uath_cmd_rateset));
+	/* XXX bounds check rs->rs_nrates */
+	rates.rateset.length = rs->ir_nrates;
+	bcopy(rs->ir_rates, &rates.rateset.set[0], rs->ir_nrates);
+
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_rates(): "
+	    "setting supported rates nrates=%d\n", rs->ir_nrates);
+	err = uath_cmd_write(sc, WDCMSG_SET_BASIC_RATE,
+	    &rates, sizeof (rates), 0);
+	return (err);
+}
+
+static int
+uath_write_associd(struct uath_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211_node *ni = ic->ic_bss;
+	struct uath_cmd_set_associd associd;
+	int err;
+
+	bzero(&associd, sizeof (associd));
+	associd.defaultrateix = BE_32(1);	/* XXX */
+	associd.associd = BE_32(ni->in_associd);
+	associd.timoffset = BE_32(0x3b);	/* XXX */
+	IEEE80211_ADDR_COPY(associd.bssid, ni->in_bssid);
+	err = uath_cmd_write(sc, WDCMSG_WRITE_ASSOCID, &associd,
+	    sizeof (associd), 0);
+	return (err);
+}
+
+static int
+uath_set_ledsteady(struct uath_softc *sc, int lednum, int ledmode)
+{
+	struct uath_cmd_ledsteady led;
+	int err;
+
+	led.lednum = BE_32(lednum);
+	led.ledmode = BE_32(ledmode);
+
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_ledsteady(): "
+	    "set %s led %s (steady)\n",
+	    (lednum == UATH_LED_LINK) ? "link" : "activity",
+	    ledmode ? "on" : "off");
+	err = uath_cmd_write(sc, WDCMSG_SET_LED_STEADY, &led, sizeof (led), 0);
+	return (err);
+}
+
+static int
+uath_set_ledblink(struct uath_softc *sc, int lednum, int ledmode,
+    int blinkrate, int slowmode)
+{
+	struct uath_cmd_ledblink led;
+	int err;
+
+	led.lednum = BE_32(lednum);
+	led.ledmode = BE_32(ledmode);
+	led.blinkrate = BE_32(blinkrate);
+	led.slowmode = BE_32(slowmode);
+
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_ledblink(): "
+	    "set %s led %s (blink)\n",
+	    (lednum == UATH_LED_LINK) ? "link" : "activity",
+	    ledmode ? "on" : "off");
+
+	err = uath_cmd_write(sc, WDCMSG_SET_LED_BLINK,
+	    &led, sizeof (led), 0);
+	return (err);
+}
+
+
+static int
+uath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
+{
+	struct uath_softc *sc = (struct uath_softc *)ic;
+	struct ieee80211_node *ni = ic->ic_bss;
+	enum ieee80211_state ostate;
+	int err;
+
+	ostate = ic->ic_state;
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_newstate(): "
+	    "%d -> %d\n", ostate, nstate);
+
+	if (sc->sc_scan_id != 0) {
+		(void) untimeout(sc->sc_scan_id);
+		sc->sc_scan_id = 0;
+	}
+
+	UATH_LOCK(sc);
+
+	if (UATH_IS_DISCONNECT(sc) && (nstate != IEEE80211_S_INIT)) {
+		UATH_UNLOCK(sc);
+		return (DDI_SUCCESS);
+	}
+
+	if (UATH_IS_SUSPEND(sc) && (nstate != IEEE80211_S_INIT)) {
+		UATH_UNLOCK(sc);
+		return (DDI_SUCCESS);
+	}
+
+	switch (nstate) {
+	case IEEE80211_S_INIT:
+		if (ostate == IEEE80211_S_RUN) {
+			/* turn link and activity LEDs off */
+			(void) uath_set_ledstate(sc, 0);
+		}
+		break;
+	case IEEE80211_S_SCAN:
+		if (uath_switch_channel(sc, ic->ic_curchan) != UATH_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): "
+			    "could not switch channel\n");
+			break;
+		}
+		sc->sc_scan_id = timeout(uath_next_scan, (void *)sc,
+		    drv_usectohz(250000));
+		break;
+	case IEEE80211_S_AUTH:
+		/* XXX good place?  set RTS threshold  */
+		uath_config(sc, CFG_USER_RTS_THRESHOLD, ic->ic_rtsthreshold);
+
+		if (uath_switch_channel(sc, ni->in_chan) != 0) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): "
+			    "could not switch channel\n");
+			break;
+		}
+		if (uath_create_connection(sc, UATH_ID_BSS) != 0) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): "
+			    "could not create connection\n");
+			break;
+		}
+		break;
+	case IEEE80211_S_ASSOC:
+		if (uath_set_rates(sc, &ni->in_rates) != 0) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): "
+			    "could not set negotiated rate set\n");
+			break;
+		}
+		break;
+	case IEEE80211_S_RUN:
+		/* XXX monitor mode doesn't be supported  */
+		if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+			(void) uath_set_ledstate(sc, 1);
+			break;
+		}
+
+		/*
+		 * Tx rate is controlled by firmware, report the maximum
+		 * negotiated rate in ifconfig output.
+		 */
+		ni->in_txrate = ni->in_rates.ir_nrates - 1;
+
+		if (uath_write_associd(sc) != 0) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): "
+			    "could not write association id\n");
+			break;
+		}
+		/* turn link LED on */
+		(void) uath_set_ledsteady(sc, UATH_LED_LINK, UATH_LED_ON);
+		/* make activity LED blink */
+		(void) uath_set_ledblink(sc, UATH_LED_ACTIVITY,
+		    UATH_LED_ON, 1, 2);
+		/* set state to associated */
+		(void) uath_set_ledstate(sc, 1);
+		break;
+	}
+
+	UATH_UNLOCK(sc);
+
+	err = sc->sc_newstate(ic, nstate, arg);
+	return (err);
+}
+
+static int
+uath_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
+{
+	struct uath_softc *sc = (struct uath_softc *)ic;
+	struct uath_chunk *chunk;
+	struct uath_tx_desc *desc;
+	struct ieee80211_frame *wh;
+	struct ieee80211_node *ni = NULL;
+	struct ieee80211_key *k;
+
+	mblk_t *m, *m0;
+	int err, off, mblen;
+	int pktlen, framelen, msglen;
+
+	err = UATH_SUCCESS;
+
+	mutex_enter(&sc->sc_txlock_data);
+
+	if (UATH_IS_SUSPEND(sc)) {
+		err = 0;
+		goto fail;
+	}
+
+	if (sc->tx_data_queued > UATH_TX_DATA_LIST_COUNT) {
+		UATH_DEBUG(UATH_DBG_TX, "uath: uath_send(): "
+		    "no TX buffer available!\n");
+		if ((type & IEEE80211_FC0_TYPE_MASK) ==
+		    IEEE80211_FC0_TYPE_DATA) {
+			sc->sc_need_sched = 1;
+		}
+		sc->sc_tx_nobuf++;
+		err = ENOMEM;
+		goto fail;
+	}
+
+	m = allocb(UATH_MAX_TXBUFSZ, BPRI_MED);
+	if (m == NULL) {
+		UATH_DEBUG(UATH_DBG_TX, "uath: uath_send(): "
+		    "can't alloc mblk.\n");
+		err = DDI_FAILURE;
+		goto fail;
+	}
+
+	/* skip TX descriptor */
+	m->b_rptr += sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc);
+	m->b_wptr += sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc);
+
+	for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
+		mblen = (uintptr_t)m0->b_wptr - (uintptr_t)m0->b_rptr;
+		(void) memcpy(m->b_rptr + off, m0->b_rptr, mblen);
+		off += mblen;
+	}
+	m->b_wptr += off;
+
+	wh = (struct ieee80211_frame *)m->b_rptr;
+
+	ni = ieee80211_find_txnode(ic, wh->i_addr1);
+	if (ni == NULL) {
+		err = DDI_FAILURE;
+		freemsg(m);
+		goto fail;
+	}
+
+	if ((type & IEEE80211_FC0_TYPE_MASK) ==
+	    IEEE80211_FC0_TYPE_DATA) {
+		(void) ieee80211_encap(ic, m, ni);
+	}
+
+	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+		k = ieee80211_crypto_encap(ic, m);
+		if (k == NULL) {
+			freemsg(m);
+			err = DDI_FAILURE;
+			goto fail;
+		}
+		/* packet header may have moved, reset our local pointer */
+		wh = (struct ieee80211_frame *)m->b_rptr;
+	}
+
+	pktlen = (uintptr_t)m->b_wptr - (uintptr_t)m->b_rptr;
+	framelen = pktlen + IEEE80211_CRC_LEN;
+	msglen = framelen + sizeof (struct uath_tx_desc);
+
+	m->b_rptr -= sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc);
+
+	chunk = (struct uath_chunk *)m->b_rptr;
+	desc = (struct uath_tx_desc *)(chunk + 1);
+
+	/* one chunk only for now */
+	chunk->seqnum = 0;
+	chunk->flags = UATH_CFLAGS_FINAL;
+	chunk->length = BE_16(msglen);
+
+	/* fill Tx descriptor */
+	desc->msglen = BE_32(msglen);
+	/* NB: to get UATH_TX_NOTIFY reply, `msgid' must be larger than 0  */
+	desc->msgid  = sc->sc_msgid; /* don't care about endianness */
+	desc->type   = BE_32(WDCMSG_SEND);
+	switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
+	case IEEE80211_FC0_TYPE_CTL:
+	case IEEE80211_FC0_TYPE_MGT:
+		/* NB: force all management frames to highest queue */
+		if (ni->in_flags & UATH_NODE_QOS) {
+			/* NB: force all management frames to highest queue */
+			desc->txqid = BE_32(WME_AC_VO | UATH_TXQID_MINRATE);
+		} else
+			desc->txqid = BE_32(WME_AC_BE | UATH_TXQID_MINRATE);
+		break;
+	case IEEE80211_FC0_TYPE_DATA:
+		/* XXX multicast frames should honor mcastrate */
+		desc->txqid = BE_32(WME_AC_BE);
+		break;
+	default:
+		UATH_DEBUG(UATH_DBG_TX, "uath: uath_send(): "
+		    "bogus frame type 0x%x (%s)\n",
+		    wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
+		err = EIO;
+		goto fail;
+	}
+
+	if (ic->ic_state == IEEE80211_S_AUTH ||
+	    ic->ic_state == IEEE80211_S_ASSOC ||
+	    ic->ic_state == IEEE80211_S_RUN)
+		desc->connid = BE_32(UATH_ID_BSS);
+	else
+		desc->connid = BE_32(UATH_ID_INVALID);
+	desc->flags  = BE_32(0 /* no UATH_TX_NOTIFY */);
+	desc->buflen = BE_32(pktlen);
+
+	(void) uath_tx_data_xfer(sc, m);
+
+	sc->sc_msgid = (sc->sc_msgid + 1) % UATH_TX_DATA_LIST_COUNT;
+
+	ic->ic_stats.is_tx_frags++;
+	ic->ic_stats.is_tx_bytes += pktlen;
+
+fail:
+	if (ni != NULL)
+		ieee80211_free_node(ni);
+	if ((mp) &&
+	    ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA ||
+	    err == 0)) {
+		freemsg(mp);
+	}
+	mutex_exit(&sc->sc_txlock_data);
+	return (err);
+}
+
+static int
+uath_reconnect(dev_info_t *devinfo)
+{
+	struct uath_softc *sc;
+	struct ieee80211com *ic;
+	int err;
+	uint16_t vendor_id, product_id;
+
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_reconnect(): "
+	    "uath online\n");
+
+	sc = ddi_get_soft_state(uath_soft_state_p, ddi_get_instance(devinfo));
+	ASSERT(sc != NULL);
+	ic = (struct ieee80211com *)&sc->sc_ic;
+
+	if (!UATH_IS_RECONNECT(sc)) {
+		err = uath_open_pipes(sc);
+		if (err != UATH_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
+			    "could not open pipes\n");
+			return (DDI_FAILURE);
+		}
+
+		err = uath_loadfirmware(sc);
+		if (err != DDI_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
+			    "could not download firmware\n");
+			return (DDI_FAILURE);
+		}
+
+		uath_close_pipes(sc);
+		usb_client_detach(sc->sc_dev, sc->sc_udev);
+
+		/* reset device */
+		err = usb_reset_device(sc->sc_dev, USB_RESET_LVL_DEFAULT);
+		if (err != USB_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
+			    "could not reset device %x\n", err);
+		}
+
+		err = usb_client_attach(devinfo, USBDRV_VERSION, 0);
+		if (err != USB_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
+			    "usb_client_attach failed\n");
+		}
+
+		err = usb_get_dev_data(devinfo, &sc->sc_udev,
+		    USB_PARSE_LVL_ALL, 0);
+		if (err != USB_SUCCESS) {
+			sc->sc_udev = NULL;
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
+			    "usb_get_dev_data failed\n");
+		}
+
+		vendor_id = sc->sc_udev->dev_descr->idVendor;
+		product_id = sc->sc_udev->dev_descr->idProduct;
+		sc->dev_flags = uath_lookup(vendor_id, product_id);
+		if (sc->dev_flags == UATH_FLAG_ERR) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
+			    "HW does not match\n");
+		}
+
+		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_reconnect(): "
+		    "vendorId = %x,deviceID = %x, flags = %x\n",
+		    vendor_id, product_id, sc->dev_flags);
+
+		UATH_LOCK(sc);
+		sc->sc_flags |= UATH_FLAG_RECONNECT;
+		UATH_UNLOCK(sc);
+
+	} else {
+		err = uath_open_pipes(sc);
+		if (err != UATH_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
+			    "could not open pipes\n");
+			return (DDI_FAILURE);
+		}
+
+		/*
+		 * Allocate xfers for firmware commands.
+		 */
+		err = uath_alloc_cmd_list(sc, sc->sc_cmd, UATH_CMD_LIST_COUNT,
+		    UATH_MAX_CMDSZ);
+		if (err != UATH_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
+			    "could not allocate Tx command list\n");
+			return (DDI_FAILURE);
+		}
+
+		err = uath_init_cmd_list(sc);
+		if (err != UATH_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
+			    "could not init RX command list\n");
+			return (DDI_FAILURE);
+		}
+
+		/*
+		 * We're now ready to send+receive firmware commands.
+		 */
+		err = uath_host_available(sc);
+		if (err != UATH_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
+			    "could not initialize adapter\n");
+			return (DDI_FAILURE);
+		}
+
+		err = uath_get_devcap(sc);
+		if (err != UATH_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
+			    "could not get device capabilities\n");
+			return (DDI_FAILURE);
+		}
+
+		err = uath_get_devstatus(sc, ic->ic_macaddr);
+		if (err != UATH_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
+			    "could not get dev status\n");
+			return (DDI_FAILURE);
+		}
+
+		err = usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1,
+		    USB_CHK_BASIC, NULL);
+		if (err != USB_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
+			    "different device connected %x\n", err);
+			return (DDI_FAILURE);
+		}
+
+		err = uath_init(sc);
+		if (err != UATH_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
+			    "device re-connect failed\n");
+			return (DDI_FAILURE);
+		}
+
+		UATH_LOCK(sc);
+		sc->sc_flags &= ~UATH_FLAG_RECONNECT;
+		sc->sc_flags &= ~UATH_FLAG_DISCONNECT;
+		sc->sc_flags |= UATH_FLAG_RUNNING;
+		UATH_UNLOCK(sc);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+static int
+uath_disconnect(dev_info_t *devinfo)
+{
+	struct uath_softc *sc;
+	struct ieee80211com *ic;
+
+	/*
+	 * We can't call uath_stop() here, since the hardware is removed,
+	 * we can't access the register anymore.
+	 */
+	sc = ddi_get_soft_state(uath_soft_state_p, ddi_get_instance(devinfo));
+	ASSERT(sc != NULL);
+
+	if (sc->sc_flags & UATH_FLAG_RECONNECT) {
+		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_disconnect(): "
+		    "stage 0 in re-connect\n");
+		uath_close_pipes(sc);
+		return (DDI_SUCCESS);
+	}
+
+	UATH_LOCK(sc);
+	sc->sc_flags |= UATH_FLAG_DISCONNECT;
+	UATH_UNLOCK(sc);
+
+	ic = (struct ieee80211com *)&sc->sc_ic;
+	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+
+	UATH_LOCK(sc);
+	sc->sc_flags &= ~UATH_FLAG_RUNNING;	/* STOP */
+	UATH_UNLOCK(sc);
+
+	/* abort and free xfers */
+	uath_free_cmd_list(sc->sc_cmd, UATH_CMD_LIST_COUNT);
+
+	/* close Tx/Rx pipes */
+	uath_close_pipes(sc);
+
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_disconnect(): "
+	    "offline success\n");
+
+	return (DDI_SUCCESS);
+}
+
+static int
+uath_dataflush(struct uath_softc *sc)
+{
+	struct uath_chunk *chunk;
+	struct uath_tx_desc *desc;
+	uint8_t *buf;
+	int err;
+
+	buf = kmem_alloc(UATH_MAX_TXBUFSZ, KM_NOSLEEP);
+	if (buf == NULL) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_dataflush(): "
+		    "no bufs\n");
+		return (ENOBUFS);
+	}
+
+	chunk = (struct uath_chunk *)buf;
+	desc = (struct uath_tx_desc *)(chunk + 1);
+
+	/* one chunk only */
+	chunk->seqnum = 0;
+	chunk->flags = UATH_CFLAGS_FINAL;
+	chunk->length = BE_16(sizeof (struct uath_tx_desc));
+
+	bzero(desc, sizeof (struct uath_tx_desc));
+	desc->msglen = BE_32(sizeof (struct uath_tx_desc));
+	desc->msgid  = sc->sc_msgid; /* don't care about endianness */
+	desc->type   = BE_32(WDCMSG_FLUSH);
+	desc->txqid  = BE_32(0);
+	desc->connid = BE_32(0);
+	desc->flags  = BE_32(0);
+
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_dataflush(): "
+	    "send flush ix %d\n", desc->msgid);
+
+	err = uath_fw_send(sc, sc->tx_data_pipe, buf,
+	    sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc));
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_dataflush(): "
+		    "data flush error");
+		return (UATH_FAILURE);
+	}
+
+	kmem_free(buf, UATH_MAX_TXBUFSZ);
+	sc->sc_msgid = (sc->sc_msgid + 1) % UATH_TX_DATA_LIST_COUNT;
+
+	return (UATH_SUCCESS);
+}
+
+static int
+uath_cmdflush(struct uath_softc *sc)
+{
+	return (uath_cmd_write(sc, WDCMSG_FLUSH, NULL, 0, 0));
+}
+
+static int
+uath_flush(struct uath_softc *sc)
+{
+	int err;
+
+	err = uath_dataflush(sc);
+	if (err != UATH_SUCCESS)
+		goto failed;
+
+	err = uath_cmdflush(sc);
+	if (err != UATH_SUCCESS)
+		goto failed;
+
+	return (UATH_SUCCESS);
+failed:
+	return (err);
+}
+
+static int
+uath_set_ledstate(struct uath_softc *sc, int connected)
+{
+	int err;
+
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_ledstate(): "
+	    "set led state %sconnected\n", connected ? "" : "!");
+
+	connected = BE_32(connected);
+	err = uath_cmd_write(sc, WDCMSG_SET_LED_STATE,
+	    &connected, sizeof (connected), 0);
+	return (err);
+}
+
+static int
+uath_config_multi(struct uath_softc *sc, uint32_t reg, const void *data,
+    int len)
+{
+	struct uath_write_mac write;
+	int err;
+
+	write.reg = BE_32(reg);
+	write.len = BE_32(len);
+	bcopy(data, write.data, len);
+
+	/* properly handle the case where len is zero (reset) */
+	err = uath_cmd_write(sc, WDCMSG_TARGET_SET_CONFIG, &write,
+	    (len == 0) ? sizeof (uint32_t) : 2 * sizeof (uint32_t) + len, 0);
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_config_multi(): "
+		    "could not write %d bytes to register 0x%02x\n", len, reg);
+	}
+	return (err);
+}
+
+static void
+uath_config(struct uath_softc *sc, uint32_t reg, uint32_t val)
+{
+	struct uath_write_mac write;
+	int err;
+
+	write.reg = BE_32(reg);
+	write.len = BE_32(0);	/* 0 = single write */
+	*(uint32_t *)write.data = BE_32(val);
+
+	err = uath_cmd_write(sc, WDCMSG_TARGET_SET_CONFIG, &write,
+	    3 * sizeof (uint32_t), 0);
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_config(): "
+		    "could not write register 0x%02x\n",
+		    reg);
+	}
+}
+
+static int
+uath_switch_channel(struct uath_softc *sc, struct ieee80211_channel *c)
+{
+	int err;
+
+	/* set radio frequency */
+	err = uath_set_chan(sc, c);
+	if (err) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): "
+		    "could not set channel\n");
+		goto failed;
+	}
+
+	/* reset Tx rings */
+	err = uath_reset_tx_queues(sc);
+	if (err) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): "
+		    "could not reset Tx queues\n");
+		goto failed;
+	}
+
+	/* set Tx rings WME properties */
+	err = uath_wme_init(sc);
+	if (err) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): "
+		    "could not init Tx queues\n");
+		goto failed;
+	}
+
+	err = uath_set_ledstate(sc, 0);
+	if (err) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): "
+		    "could not set led state\n");
+		goto failed;
+	}
+
+	err = uath_flush(sc);
+	if (err) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): "
+		    "could not flush pipes\n");
+		goto failed;
+	}
+
+failed:
+	return (err);
+}
+
+static int
+uath_set_rxfilter(struct uath_softc *sc, uint32_t bits, uint32_t op)
+{
+	struct uath_cmd_rx_filter rxfilter;
+
+	rxfilter.bits = BE_32(bits);
+	rxfilter.op = BE_32(op);
+
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_rxfilter(): "
+	    "setting Rx filter=0x%x flags=0x%x\n", bits, op);
+
+	return ((uath_cmd_write(sc, WDCMSG_RX_FILTER, &rxfilter,
+	    sizeof (rxfilter), 0)));
+}
+
+static int
+uath_set_chan(struct uath_softc *sc, struct ieee80211_channel *c)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct uath_cmd_reset reset;
+
+	bzero(&reset, sizeof (reset));
+	if (IEEE80211_IS_CHAN_2GHZ(c))
+		reset.flags |= BE_32(UATH_CHAN_2GHZ);
+	if (IEEE80211_IS_CHAN_5GHZ(c))
+		reset.flags |= BE_32(UATH_CHAN_5GHZ);
+	/* NB: 11g =>'s 11b so don't specify both OFDM and CCK */
+	if (UATH_IS_CHAN_OFDM(c))
+		reset.flags |= BE_32(UATH_CHAN_OFDM);
+	else if (UATH_IS_CHAN_CCK(c))
+		reset.flags |= BE_32(UATH_CHAN_CCK);
+	/* turbo can be used in either 2GHz or 5GHz */
+	if (c->ich_flags & IEEE80211_CHAN_TURBO)
+		reset.flags |= BE_32(UATH_CHAN_TURBO);
+
+	reset.freq = BE_32(c->ich_freq);
+	reset.maxrdpower = BE_32(50);	/* XXX */
+	reset.channelchange = BE_32(1);
+	reset.keeprccontent = BE_32(0);
+
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_chan(): "
+	    "set channel %d, flags 0x%x freq %u\n",
+	    ieee80211_chan2ieee(ic, c),
+	    BE_32(reset.flags), BE_32(reset.freq));
+
+	return (uath_cmd_write(sc, WDCMSG_RESET, &reset, sizeof (reset), 0));
+}
+
+static int
+uath_reset_tx_queues(struct uath_softc *sc)
+{
+	int ac, err;
+
+	for (ac = 0; ac < 4; ac++) {
+		const uint32_t qid = BE_32(ac);
+		err = uath_cmd_write(sc, WDCMSG_RELEASE_TX_QUEUE, &qid,
+		    sizeof (qid), 0);
+		if (err != UATH_SUCCESS)
+			break;
+	}
+	return (err);
+}
+
+static int
+uath_wme_init(struct uath_softc *sc)
+{
+	/* XXX get from net80211 */
+	static const struct uath_wme_settings uath_wme_11g[4] = {
+		{ 7, 4, 10,  0, 0 },	/* Background */
+		{ 3, 4, 10,  0, 0 },	/* Best-Effort */
+		{ 3, 3,  4, 26, 0 },	/* Video */
+		{ 2, 2,  3, 47, 0 }	/* Voice */
+	};
+
+	struct uath_cmd_txq_setup qinfo;
+	int ac, err;
+
+	for (ac = 0; ac < 4; ac++) {
+		qinfo.qid		= BE_32(ac);
+		qinfo.len		= BE_32(sizeof (qinfo.attr));
+		qinfo.attr.priority	= BE_32(ac);	/* XXX */
+		qinfo.attr.aifs		= BE_32(uath_wme_11g[ac].aifsn);
+		qinfo.attr.logcwmin	= BE_32(uath_wme_11g[ac].logcwmin);
+		qinfo.attr.logcwmax	= BE_32(uath_wme_11g[ac].logcwmax);
+		qinfo.attr.mode		= BE_32(uath_wme_11g[ac].acm);
+		qinfo.attr.qflags	= BE_32(1);
+		qinfo.attr.bursttime	=
+		    BE_32(UATH_TXOP_TO_US(uath_wme_11g[ac].txop));
+
+		err = uath_cmd_write(sc, WDCMSG_SETUP_TX_QUEUE, &qinfo,
+		    sizeof (qinfo), 0);
+		if (err != UATH_SUCCESS)
+			break;
+	}
+	return (err);
+}
+
+static void
+uath_stop_locked(void *arg)
+{
+	struct uath_softc *sc = (struct uath_softc *)arg;
+
+	/* flush data & control requests into the target  */
+	(void) uath_flush(sc);
+
+	/* set a LED status to the disconnected.  */
+	(void) uath_set_ledstate(sc, 0);
+
+	/* stop the target  */
+	(void) uath_cmd_write(sc, WDCMSG_TARGET_STOP, NULL, 0, 0);
+
+	/* abort any pending transfers */
+	usb_pipe_reset(sc->sc_dev, sc->rx_data_pipe, USB_FLAGS_SLEEP, NULL, 0);
+	usb_pipe_reset(sc->sc_dev, sc->tx_data_pipe, USB_FLAGS_SLEEP, NULL, 0);
+	usb_pipe_reset(sc->sc_dev, sc->tx_cmd_pipe, USB_FLAGS_SLEEP, NULL, 0);
+}
+
+static int
+uath_init_locked(void *arg)
+{
+	struct uath_softc *sc = arg;
+	struct ieee80211com *ic = &sc->sc_ic;
+	uint32_t val;
+	int i, err;
+
+	if (UATH_IS_RUNNING(sc))
+		uath_stop_locked(sc);
+
+	uath_init_data_queue(sc);
+
+	/* reset variables */
+	sc->sc_intrx_nextnum = sc->sc_msgid = 0;
+
+	val = BE_32(0);
+	(void) uath_cmd_write(sc, WDCMSG_BIND, &val, sizeof (val), 0);
+
+	/* set MAC address */
+	(void) uath_config_multi(sc, CFG_MAC_ADDR,
+	    ic->ic_macaddr, IEEE80211_ADDR_LEN);
+
+	/* XXX honor net80211 state */
+	uath_config(sc, CFG_RATE_CONTROL_ENABLE, 0x00000001);
+	uath_config(sc, CFG_DIVERSITY_CTL, 0x00000001);
+	uath_config(sc, CFG_ABOLT, 0x0000003f);
+	uath_config(sc, CFG_WME_ENABLED, 0x00000001);
+
+	uath_config(sc, CFG_SERVICE_TYPE, 1);
+	uath_config(sc, CFG_TP_SCALE, 0x00000000);
+	uath_config(sc, CFG_TPC_HALF_DBM5, 0x0000003c);
+	uath_config(sc, CFG_TPC_HALF_DBM2, 0x0000003c);
+	uath_config(sc, CFG_OVERRD_TX_POWER, 0x00000000);
+	uath_config(sc, CFG_GMODE_PROTECTION, 0x00000000);
+	uath_config(sc, CFG_GMODE_PROTECT_RATE_INDEX, 0x00000003);
+	uath_config(sc, CFG_PROTECTION_TYPE, 0x00000000);
+	uath_config(sc, CFG_MODE_CTS, 0x00000002);
+
+	err = uath_cmd_read(sc, WDCMSG_TARGET_START, NULL, 0,
+	    &val, sizeof (val), UATH_CMD_FLAG_MAGIC);
+	if (err) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init_locked(): "
+		    "could not start target\n");
+		goto fail;
+	}
+
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_init_locked(): "
+	    "%s returns handle: 0x%x\n",
+	    uath_codename(WDCMSG_TARGET_START), BE_32(val));
+
+	/* set default channel */
+	err = uath_switch_channel(sc, ic->ic_curchan);
+	if (err) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init_locked(): "
+		    "could not switch channel, error %d\n", err);
+		goto fail;
+	}
+
+	val = BE_32(TARGET_DEVICE_AWAKE);
+	(void) uath_cmd_write(sc, WDCMSG_SET_PWR_MODE, &val, sizeof (val), 0);
+	/* XXX? check */
+	(void) uath_cmd_write(sc, WDCMSG_RESET_KEY_CACHE, NULL, 0, 0);
+
+	for (i = 0; i < UATH_RX_DATA_LIST_COUNT; i++) {
+		err = uath_rx_data_xfer(sc);
+		if (err != UATH_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init_locked(): "
+			    "could not alloc rx xfer %x\n", i);
+			goto fail;
+		}
+	}
+
+	/* enable Rx */
+	(void) uath_set_rxfilter(sc, 0x0, UATH_FILTER_OP_INIT);
+	(void) uath_set_rxfilter(sc,
+	    UATH_FILTER_RX_UCAST | UATH_FILTER_RX_MCAST |
+	    UATH_FILTER_RX_BCAST | UATH_FILTER_RX_BEACON,
+	    UATH_FILTER_OP_SET);
+
+	return (UATH_SUCCESS);
+
+fail:
+	uath_stop_locked(sc);
+	return (err);
+}
+
+static int
+uath_init(struct uath_softc *sc)
+{
+	int err;
+
+	UATH_LOCK(sc);
+	err = uath_init_locked(sc);
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init(): "
+		    "failed to initialize uath hardware\n");
+		UATH_UNLOCK(sc);
+		return (DDI_FAILURE);
+	}
+	UATH_UNLOCK(sc);
+	return (DDI_SUCCESS);
+}
+
+static void
+uath_stop(struct uath_softc *sc)
+{
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_stop(): "
+	    "uath stop now\n");
+
+	UATH_LOCK(sc);
+	uath_stop_locked(sc);
+	UATH_UNLOCK(sc);
+}
+
+static void
+uath_resume(struct uath_softc *sc)
+{
+	int err;
+
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_resume(): "
+	    "uath resume now\n");
+
+	/* check device changes after suspend */
+	if (usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1,
+	    USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_resume: "
+		    "no or different device connected\n");
+		return;
+	}
+
+	/*
+	 * initialize hardware
+	 */
+	err = uath_init_cmd_list(sc);
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_resume(): "
+		    "could not init RX command list\n");
+		return;
+	}
+
+	err = uath_init(sc);
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_resume(): "
+		    "hardware init failed\n");
+		uath_stop(sc);
+		return;
+	}
+
+	ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
+	UATH_LOCK(sc);
+	sc->sc_flags &= ~UATH_FLAG_SUSPEND;
+	sc->sc_flags |= UATH_FLAG_RUNNING;
+	UATH_UNLOCK(sc);
+}
+
+static int
+uath_m_start(void *arg)
+{
+	struct uath_softc *sc = (struct uath_softc *)arg;
+	struct ieee80211com *ic = &sc->sc_ic;
+	int err;
+
+	/*
+	 * initialize hardware
+	 */
+	err = uath_init(sc);
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_m_start(): "
+		    "device configuration failed\n");
+		uath_stop(sc);
+		return (err);
+	}
+
+	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+
+	UATH_LOCK(sc);
+	sc->sc_flags |= UATH_FLAG_RUNNING;
+	UATH_UNLOCK(sc);
+	return (DDI_SUCCESS);
+}
+
+static void
+uath_m_stop(void *arg)
+{
+	struct uath_softc *sc = (struct uath_softc *)arg;
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+
+	if (!UATH_IS_DISCONNECT(sc))
+		uath_stop(sc);
+
+	UATH_LOCK(sc);
+	sc->sc_flags &= ~UATH_FLAG_RUNNING;
+	UATH_UNLOCK(sc);
+}
+
+static void
+uath_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
+{
+	struct uath_softc *sc = (struct uath_softc *)arg;
+	struct ieee80211com *ic = &sc->sc_ic;
+	int err;
+
+	err = ieee80211_ioctl(ic, wq, mp);
+	UATH_LOCK(sc);
+	if (err == ENETRESET) {
+		if (ic->ic_des_esslen) {
+			if (UATH_IS_RUNNING(sc)) {
+				UATH_UNLOCK(sc);
+				(void) uath_init(sc);
+				(void) ieee80211_new_state(ic,
+				    IEEE80211_S_SCAN, -1);
+				UATH_LOCK(sc);
+			}
+		}
+	}
+	UATH_UNLOCK(sc);
+}
+
+/*ARGSUSED*/
+static int
+uath_m_unicst(void *arg, const uint8_t *macaddr)
+{
+	return (0);
+}
+
+/*ARGSUSED*/
+static int
+uath_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
+{
+	return (0);
+}
+
+/*ARGSUSED*/
+static int
+uath_m_promisc(void *arg, boolean_t on)
+{
+	return (0);
+}
+
+/*
+ * callback functions for /get/set properties
+ */
+static int
+uath_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
+    uint_t wldp_length, const void *wldp_buf)
+{
+	struct uath_softc *sc = (struct uath_softc *)arg;
+	struct ieee80211com *ic = &sc->sc_ic;
+	int err;
+
+	err = ieee80211_setprop(ic, pr_name, wldp_pr_num,
+	    wldp_length, wldp_buf);
+	UATH_LOCK(sc);
+	if (err == ENETRESET) {
+		if (ic->ic_des_esslen && UATH_IS_RUNNING(sc)) {
+			UATH_UNLOCK(sc);
+			(void) uath_init(sc);
+			(void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+			UATH_LOCK(sc);
+		}
+		err = 0;
+	}
+	UATH_UNLOCK(sc);
+	return (err);
+}
+
+static int
+uath_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
+    uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm)
+{
+	struct uath_softc *sc = (struct uath_softc *)arg;
+	int err;
+
+	err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
+	    pr_flags, wldp_length, wldp_buf, perm);
+	return (err);
+}
+
+static int
+uath_m_stat(void *arg, uint_t stat, uint64_t *val)
+{
+	struct uath_softc *sc  = (struct uath_softc *)arg;
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211_node *ni = NULL;
+	struct ieee80211_rateset *rs = NULL;
+
+	UATH_LOCK(sc);
+	switch (stat) {
+	case MAC_STAT_IFSPEED:
+		ni = ic->ic_bss;
+		rs = &ni->in_rates;
+		*val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
+		    (rs->ir_rates[ni->in_txrate] & IEEE80211_RATE_VAL)
+		    : ic->ic_fixed_rate) * 5000000ull;
+		break;
+	case MAC_STAT_NOXMTBUF:
+		*val = sc->sc_tx_nobuf;
+		break;
+	case MAC_STAT_NORCVBUF:
+		*val = sc->sc_rx_nobuf;
+		break;
+	case MAC_STAT_IERRORS:
+		*val = sc->sc_rx_err;
+		break;
+	case MAC_STAT_RBYTES:
+		*val = ic->ic_stats.is_rx_bytes;
+		break;
+	case MAC_STAT_IPACKETS:
+		*val = ic->ic_stats.is_rx_frags;
+		break;
+	case MAC_STAT_OBYTES:
+		*val = ic->ic_stats.is_tx_bytes;
+		break;
+	case MAC_STAT_OPACKETS:
+		*val = ic->ic_stats.is_tx_frags;
+		break;
+	case MAC_STAT_OERRORS:
+	case WIFI_STAT_TX_FAILED:
+		*val = sc->sc_tx_err;
+		break;
+	case WIFI_STAT_TX_RETRANS:
+		*val = sc->sc_tx_retries;
+		break;
+	case WIFI_STAT_FCS_ERRORS:
+	case WIFI_STAT_WEP_ERRORS:
+	case WIFI_STAT_TX_FRAGS:
+	case WIFI_STAT_MCAST_TX:
+	case WIFI_STAT_RTS_SUCCESS:
+	case WIFI_STAT_RTS_FAILURE:
+	case WIFI_STAT_ACK_FAILURE:
+	case WIFI_STAT_RX_FRAGS:
+	case WIFI_STAT_MCAST_RX:
+	case WIFI_STAT_RX_DUPS:
+		UATH_UNLOCK(sc);
+		return (ieee80211_stat(ic, stat, val));
+	default:
+		UATH_UNLOCK(sc);
+		return (ENOTSUP);
+	}
+	UATH_UNLOCK(sc);
+
+	return (0);
+}
+
+static mblk_t *
+uath_m_tx(void *arg, mblk_t *mp)
+{
+	struct uath_softc *sc = (struct uath_softc *)arg;
+	struct ieee80211com *ic = &sc->sc_ic;
+	mblk_t *next;
+
+	/*
+	 * No data frames go out unless we're associated; this
+	 * should not happen as the 802.11 layer does not enable
+	 * the xmit queue until we enter the RUN state.
+	 */
+	if ((ic->ic_state != IEEE80211_S_RUN) ||
+	    UATH_IS_SUSPEND(sc)) {
+		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_m_tx(): "
+		    "discard, state %u\n", ic->ic_state);
+		freemsgchain(mp);
+		return (NULL);
+	}
+
+	while (mp != NULL) {
+		next = mp->b_next;
+		mp->b_next = NULL;
+		if (uath_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != DDI_SUCCESS) {
+			mp->b_next = next;
+			break;
+		}
+		mp = next;
+	}
+	return (mp);
+}
+
+static int
+uath_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
+{
+	struct uath_softc *sc;
+	struct ieee80211com *ic;
+
+	int i, err, instance;
+	char strbuf[32];
+	uint16_t vendor_id, product_id;
+
+	wifi_data_t wd = { 0 };
+	mac_register_t *macp;
+
+	switch (cmd) {
+	case DDI_ATTACH:
+		break;
+	case DDI_RESUME:
+		sc = ddi_get_soft_state(uath_soft_state_p,
+		    ddi_get_instance(devinfo));
+		ASSERT(sc != NULL);
+		uath_resume(sc);
+		return (DDI_SUCCESS);
+	default:
+		return (DDI_FAILURE);
+	}
+
+	instance = ddi_get_instance(devinfo);
+	err = ddi_soft_state_zalloc(uath_soft_state_p, instance);
+	if (err != DDI_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
+		    "ddi_soft_state_zalloc failed\n");
+		return (DDI_FAILURE);
+	}
+
+	sc = ddi_get_soft_state(uath_soft_state_p, instance);
+	ic = (ieee80211com_t *)&sc->sc_ic;
+	sc->sc_dev = devinfo;
+
+	err = usb_client_attach(devinfo, USBDRV_VERSION, 0);
+	if (err != USB_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
+		    "usb_client_attach failed\n");
+		goto fail1;
+	}
+
+	err = usb_get_dev_data(devinfo, &sc->sc_udev, USB_PARSE_LVL_ALL, 0);
+	if (err != USB_SUCCESS) {
+		sc->sc_udev = NULL;
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
+		    "usb_get_dev_data failed\n");
+		goto fail2;
+	}
+
+	vendor_id = sc->sc_udev->dev_descr->idVendor;
+	product_id = sc->sc_udev->dev_descr->idProduct;
+	sc->dev_flags = uath_lookup(vendor_id, product_id);
+	if (sc->dev_flags == UATH_FLAG_ERR) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
+		    "HW does not match\n");
+		goto fail2;
+	}
+
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_attach(): "
+	    "vendorId = %x,deviceID = %x, flags = %x\n",
+	    vendor_id, product_id, sc->dev_flags);
+
+	/*
+	 * We must open the pipes early because they're used to upload the
+	 * firmware (pre-firmware devices) or to send firmware commands.
+	 */
+	err = uath_open_pipes(sc);
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
+		    "could not open pipes\n");
+		goto fail3;
+	}
+
+	if (sc->dev_flags & UATH_FLAG_PRE_FIRMWARE) {
+		err = uath_loadfirmware(sc);
+		if (err != DDI_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
+			    "could not read firmware %s, err %d\n",
+			    "uath-ar5523", err);
+			goto fail3;
+		}
+
+		uath_close_pipes(sc);
+		usb_client_detach(sc->sc_dev, sc->sc_udev);
+
+		err = usb_reset_device(devinfo, USB_RESET_LVL_REATTACH);
+		if (err != USB_SUCCESS) {
+			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
+			    "could not re-attach, err %d\n", err);
+			goto fail1;
+		}
+		return (DDI_SUCCESS);
+	}
+
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_attach(): "
+	    "firmware download and re-attach successfully\n");
+
+	/*
+	 * Only post-firmware devices here.
+	 */
+	mutex_init(&sc->sc_genlock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&sc->sc_rxlock_cmd, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&sc->sc_txlock_cmd, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&sc->sc_rxlock_data, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&sc->sc_txlock_data, NULL, MUTEX_DRIVER, NULL);
+
+	/*
+	 * Allocate xfers for firmware commands.
+	 */
+	err = uath_alloc_cmd_list(sc, sc->sc_cmd, UATH_CMD_LIST_COUNT,
+	    UATH_MAX_CMDSZ);
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
+		    "could not allocate Tx command list\n");
+		goto fail4;
+	}
+
+	err = uath_init_cmd_list(sc);
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
+		    "could not init RX command list\n");
+		goto fail5;
+	}
+
+	/*
+	 * We're now ready to send+receive firmware commands.
+	 */
+	err = uath_host_available(sc);
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
+		    "could not initialize adapter\n");
+		goto fail5;
+	}
+
+	err = uath_get_devcap(sc);
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
+		    "could not get device capabilities\n");
+		goto fail5;
+	}
+
+	err = uath_get_devstatus(sc, ic->ic_macaddr);
+	if (err != UATH_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
+		    "could not get dev status\n");
+		goto fail5;
+	}
+
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_attach(): "
+	    "MAC address is: %x:%x:%x:%x:%x:%x\n",
+	    ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2],
+	    ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5]);
+
+	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
+	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
+	ic->ic_state = IEEE80211_S_INIT;
+
+	ic->ic_maxrssi = 40;
+
+	ic->ic_xmit = uath_send;
+
+	/* set device capabilities */
+	ic->ic_caps =
+	    IEEE80211_C_TXPMGT |	/* tx power management */
+	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
+	    IEEE80211_C_SHSLOT;		/* short slot time supported */
+
+	ic->ic_caps |= IEEE80211_C_WPA;  /* Support WPA/WPA2 */
+
+	/* set supported .11b and .11g rates */
+	ic->ic_sup_rates[IEEE80211_MODE_11B] = uath_rateset_11b;
+	ic->ic_sup_rates[IEEE80211_MODE_11G] = uath_rateset_11g;
+
+	/* set supported .11b and .11g channels (1 through 11) */
+	for (i = 1; i <= 11; i++) {
+		ic->ic_sup_channels[i].ich_freq =
+		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
+		ic->ic_sup_channels[i].ich_flags =
+		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
+		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
+	}
+
+	ieee80211_attach(ic);
+
+	/* register WPA door */
+	ieee80211_register_door(ic, ddi_driver_name(devinfo),
+	    ddi_get_instance(devinfo));
+
+	/* override state transition machine */
+	sc->sc_newstate = ic->ic_newstate;
+	ic->ic_newstate = uath_newstate;
+	ieee80211_media_init(ic);
+	ic->ic_def_txkey = 0;
+
+	sc->sc_flags = 0;
+
+	/*
+	 * Provide initial settings for the WiFi plugin; whenever this
+	 * information changes, we need to call mac_plugindata_update()
+	 */
+	wd.wd_opmode = ic->ic_opmode;
+	wd.wd_secalloc = WIFI_SEC_NONE;
+	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
+
+	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath_attach(): "
+		    "MAC version mismatch\n");
+		goto fail5;
+	}
+
+	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
+	macp->m_driver		= sc;
+	macp->m_dip		= devinfo;
+	macp->m_src_addr	= ic->ic_macaddr;
+	macp->m_callbacks	= &uath_m_callbacks;
+	macp->m_min_sdu		= 0;
+	macp->m_max_sdu		= IEEE80211_MTU;
+	macp->m_pdata		= &wd;
+	macp->m_pdata_size	= sizeof (wd);
+
+	err = mac_register(macp, &ic->ic_mach);
+	mac_free(macp);
+	if (err != 0) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath_attach(): "
+		    "mac_register() error %x\n", err);
+		goto fail5;
+	};
+
+	err = usb_register_hotplug_cbs(devinfo,
+	    uath_disconnect, uath_reconnect);
+	if (err != USB_SUCCESS) {
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
+		    "failed to register events\n");
+		goto fail6;
+	}
+
+	/*
+	 * Create minor node of type DDI_NT_NET_WIFI
+	 */
+	(void) snprintf(strbuf, sizeof (strbuf), "%s%d",
+	    "uath", instance);
+	err = ddi_create_minor_node(devinfo, strbuf, S_IFCHR,
+	    instance + 1, DDI_NT_NET_WIFI, 0);
+	if (err != DDI_SUCCESS)
+		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
+		    "ddi_create_minor_node() failed\n");
+
+	/*
+	 * Notify link is down now
+	 */
+	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
+
+	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_attach(): "
+	    "attach success\n");
+	return (DDI_SUCCESS);
+
+fail6:
+	(void) mac_unregister(ic->ic_mach);
+fail5:
+	uath_free_cmd_list(sc->sc_cmd, UATH_CMD_LIST_COUNT);
+fail4:
+	mutex_destroy(&sc->sc_genlock);
+	mutex_destroy(&sc->sc_rxlock_cmd);
+	mutex_destroy(&sc->sc_rxlock_data);
+	mutex_destroy(&sc->sc_txlock_cmd);
+	mutex_destroy(&sc->sc_txlock_data);
+fail3:
+	uath_close_pipes(sc);
+fail2:
+	usb_client_detach(sc->sc_dev, sc->sc_udev);
+fail1:
+	ddi_soft_state_free(uath_soft_state_p, ddi_get_instance(devinfo));
+	return (DDI_FAILURE);
+}
+
+static int
+uath_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
+{
+	struct uath_softc *sc;
+
+	sc = ddi_get_soft_state(uath_soft_state_p, ddi_get_instance(devinfo));
+	ASSERT(sc != NULL);
+
+	switch (cmd) {
+	case DDI_DETACH:
+		break;
+	case DDI_SUSPEND:
+		if (UATH_IS_RUNNING(sc)) {
+			ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
+			uath_stop(sc);
+		}
+		UATH_LOCK(sc);
+		sc->sc_flags &= ~UATH_FLAG_RUNNING;
+		sc->sc_flags |= UATH_FLAG_SUSPEND;
+		UATH_UNLOCK(sc);
+		return (DDI_SUCCESS);
+	default:
+		return (DDI_FAILURE);
+	}
+
+	if (sc->dev_flags & UATH_FLAG_PRE_FIRMWARE) {
+		ddi_soft_state_free(uath_soft_state_p,
+		    ddi_get_instance(devinfo));
+		return (DDI_SUCCESS);
+	}
+
+	if (!UATH_IS_DISCONNECT(sc) && UATH_IS_RUNNING(sc))
+		uath_stop(sc);
+
+	uath_free_cmd_list(sc->sc_cmd, UATH_CMD_LIST_COUNT);
+
+	if (mac_disable(sc->sc_ic.ic_mach) != 0)
+		return (DDI_FAILURE);
+
+	/*
+	 * Unregister from the MAC layer subsystem
+	 */
+	if (mac_unregister(sc->sc_ic.ic_mach) != 0)
+		return (DDI_FAILURE);
+
+	/*
+	 * detach ieee80211 layer
+	 */
+	ieee80211_detach(&sc->sc_ic);
+
+	/* close Tx/Rx pipes */
+	uath_close_pipes(sc);
+	usb_unregister_hotplug_cbs(devinfo);
+
+	mutex_destroy(&sc->sc_genlock);
+	mutex_destroy(&sc->sc_rxlock_cmd);
+	mutex_destroy(&sc->sc_rxlock_data);
+	mutex_destroy(&sc->sc_txlock_cmd);
+	mutex_destroy(&sc->sc_txlock_data);
+
+	/* pipes will be close in uath_stop() */
+	usb_client_detach(devinfo, sc->sc_udev);
+	sc->sc_udev = NULL;
+
+	ddi_remove_minor_node(devinfo, NULL);
+	ddi_soft_state_free(uath_soft_state_p, ddi_get_instance(devinfo));
+
+	return (DDI_SUCCESS);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+int
+_init(void)
+{
+	int status;
+
+	status = ddi_soft_state_init(&uath_soft_state_p,
+	    sizeof (struct uath_softc), 1);
+	if (status != 0)
+		return (status);
+
+	mac_init_ops(&uath_dev_ops, "uath");
+	status = mod_install(&modlinkage);
+	if (status != 0) {
+		mac_fini_ops(&uath_dev_ops);
+		ddi_soft_state_fini(&uath_soft_state_p);
+	}
+	return (status);
+}
+
+int
+_fini(void)
+{
+	int status;
+
+	status = mod_remove(&modlinkage);
+	if (status == 0) {
+		mac_fini_ops(&uath_dev_ops);
+		ddi_soft_state_fini(&uath_soft_state_p);
+	}
+	return (status);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/uath/uath_fw/LICENSE	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2002-2008 Atheros Communications, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the following conditions are met:
+ * 1. The materials contained herein are unmodified and are used
+ *    unmodified.
+ * 2. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following NO
+ *    ''WARRANTY'' disclaimer below (''Disclaimer''), without
+ *    modification.
+ * 3. Redistributions in binary form must reproduce at minimum a
+ *    disclaimer similar to the Disclaimer below and any redistribution
+ *    must be conditioned upon including a substantially similar
+ *    Disclaimer requirement for further binary redistribution.
+ * 4. Neither the names of the above-listed copyright holders nor the
+ *    names of any contributors may be used to endorse or promote
+ *    product derived from this software without specific prior written
+ *    permission.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT,
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
+ * FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGES.
+ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/uath/uath_fw/LICENSE.descrip	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,1 @@
+ATHEROS AR5523 USB FIRMWARE
Binary file usr/src/uts/common/io/uath/uath_fw/uathfw.bin has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/uath/uath_fw/uathfw_mod.c	Mon Jul 20 13:07:46 2009 -0400
@@ -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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * misc module wrapper for a firmware module for uath driver
+ * User must use elfwrap(1) to convert raw firmware data file to
+ * ELF object file. Then use ld(1) to link the ELF object file and
+ * this module to produce a kernel loadable module.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/modctl.h>
+
+
+extern struct mod_ops mod_miscops;
+static struct modlmisc modlmisc = {
+	&mod_miscops,
+	"uath firmware wrapper module 1.1"
+};
+static struct modlinkage modlinkage = {
+	MODREV_1,
+	&modlmisc,
+	0
+};
+
+int
+_init(void)
+{
+	return (mod_install(&modlinkage));
+}
+
+int
+_fini(void)
+{
+	return (mod_remove(&modlinkage));
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/uath/uath_reg.h	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,567 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2006
+ *	Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2006 Sam Leffler, Errno Consulting
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef _UATH_REG_H
+#define	_UATH_REG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Location in the endpoint descriptor tree used by the device */
+#define	UATH_CONFIG_NO		1
+#define	UATH_IFACE_INDEX	0
+#define	UATH_ALT_IF_INDEX	0
+
+/* all fields are big endian */
+#pragma pack(1)
+struct uath_fwblock {
+	uint32_t	flags;
+#define	UATH_WRITE_BLOCK	(1 << 4)
+	uint32_t	len;
+#define	UATH_MAX_FWBLOCK_SIZE	2048
+	uint32_t	total;
+	uint32_t	remain;
+	uint32_t	rxtotal;
+	uint32_t	pad[123];
+};
+#pragma pack()
+
+#define	UATH_MAX_CMDSZ		512
+
+/*
+ * Messages are passed in Target Endianness.  All fixed-size
+ * fields of a WDS Control Message are treated as 32-bit
+ * values and Control Msgs are guaranteed to be 32-bit aligned.
+ *
+ * The format of a WDS Control Message is as follows:
+ *    Message Length	32 bits
+ *    Message Opcode	32 bits
+ *    Message ID	32 bits
+ *    parameter 1
+ *    parameter 2
+ *       ...
+ *
+ * A variable-length parameter, or a parmeter that is larger than
+ * 32 bits is passed as <length, data> pair, where length is a
+ * 32-bit quantity and data is padded to 32 bits.
+ */
+#pragma pack(1)
+struct uath_cmd_hdr {
+	uint32_t	len;		/* msg length including header */
+	uint32_t	code;		/* operation code */
+/* NB: these are defined for rev 1.5 firmware; rev 1.6 is different */
+/* messages from Host -> Target */
+#define	WDCMSG_HOST_AVAILABLE		0x01
+#define	WDCMSG_BIND			0x02
+#define	WDCMSG_TARGET_RESET		0x03
+#define	WDCMSG_TARGET_GET_CAPABILITY	0x04
+#define	WDCMSG_TARGET_SET_CONFIG	0x05
+#define	WDCMSG_TARGET_GET_STATUS	0x06
+#define	WDCMSG_TARGET_GET_STATS		0x07
+#define	WDCMSG_TARGET_START		0x08
+#define	WDCMSG_TARGET_STOP		0x09
+#define	WDCMSG_TARGET_ENABLE		0x0a
+#define	WDCMSG_TARGET_DISABLE		0x0b
+#define	WDCMSG_CREATE_CONNECTION	0x0c
+#define	WDCMSG_UPDATE_CONNECT_ATTR	0x0d
+#define	WDCMSG_DELETE_CONNECT		0x0e
+#define	WDCMSG_SEND			0x0f
+#define	WDCMSG_FLUSH			0x10
+/* messages from Target -> Host */
+#define	WDCMSG_STATS_UPDATE		0x11
+#define	WDCMSG_BMISS			0x12
+#define	WDCMSG_DEVICE_AVAIL		0x13
+#define	WDCMSG_SEND_COMPLETE		0x14
+#define	WDCMSG_DATA_AVAIL		0x15
+#define	WDCMSG_SET_PWR_MODE		0x16
+#define	WDCMSG_BMISS_ACK		0x17
+#define	WDCMSG_SET_LED_STEADY		0x18
+#define	WDCMSG_SET_LED_BLINK		0x19
+/* more messages */
+#define	WDCMSG_SETUP_BEACON_DESC	0x1a
+#define	WDCMSG_BEACON_INIT		0x1b
+#define	WDCMSG_RESET_KEY_CACHE		0x1c
+#define	WDCMSG_RESET_KEY_CACHE_ENTRY	0x1d
+#define	WDCMSG_SET_KEY_CACHE_ENTRY	0x1e
+#define	WDCMSG_SET_DECOMP_MASK		0x1f
+#define	WDCMSG_SET_REGULATORY_DOMAIN	0x20
+#define	WDCMSG_SET_LED_STATE		0x21
+#define	WDCMSG_WRITE_ASSOCID		0x22
+#define	WDCMSG_SET_STA_BEACON_TIMERS	0x23
+#define	WDCMSG_GET_TSF			0x24
+#define	WDCMSG_RESET_TSF		0x25
+#define	WDCMSG_SET_ADHOC_MODE		0x26
+#define	WDCMSG_SET_BASIC_RATE		0x27
+#define	WDCMSG_MIB_CONTROL		0x28
+#define	WDCMSG_GET_CHANNEL_DATA		0x29
+#define	WDCMSG_GET_CUR_RSSI		0x2a
+#define	WDCMSG_SET_ANTENNA_SWITCH	0x2b
+#define	WDCMSG_USE_SHORT_SLOT_TIME	0x2f
+#define	WDCMSG_SET_POWER_MODE		0x30
+#define	WDCMSG_SETUP_PSPOLL_DESC	0x31
+#define	WDCMSG_SET_RX_MULTICAST_FILTER	0x32
+#define	WDCMSG_RX_FILTER		0x33
+#define	WDCMSG_PER_CALIBRATION		0x34
+#define	WDCMSG_RESET			0x35
+#define	WDCMSG_DISABLE			0x36
+#define	WDCMSG_PHY_DISABLE		0x37
+#define	WDCMSG_SET_TX_POWER_LIMIT	0x38
+#define	WDCMSG_SET_TX_QUEUE_PARAMS	0x39
+#define	WDCMSG_SETUP_TX_QUEUE		0x3a
+#define	WDCMSG_RELEASE_TX_QUEUE		0x3b
+#define	WDCMSG_SET_DEFAULT_KEY		0x43
+	uint32_t	msgid;		/* msg id (supplied by host) */
+	uint32_t	magic;		/* response desired/target status */
+	uint32_t	debug[4];	/* debug data area */
+	/* msg data follows */
+};
+#pragma pack()
+
+#define	UATH_RX_DUMMYSIZE		4
+
+#pragma pack(1)
+struct uath_chunk {
+	uint8_t		seqnum;		/* sequence number for ordering */
+	uint8_t		flags;
+#define	UATH_CFLAGS_FINAL	0x01	/* final chunk of a msg */
+#define	UATH_CFLAGS_RXMSG	0x02	/* chunk contains rx completion */
+#define	UATH_CFLAGS_DEBUG	0x04	/* for debugging */
+	uint16_t	length;		/* chunk size in bytes */
+	/* chunk data follows */
+};
+#pragma pack()
+
+/*
+ * Message format for a WDCMSG_DATA_AVAIL message from Target to Host.
+ */
+#pragma pack(1)
+struct uath_rx_desc {
+	uint32_t	len;		/* msg length including header */
+	uint32_t	code;		/* WDCMSG_DATA_AVAIL */
+	uint32_t	gennum;		/* generation number */
+	uint32_t	status;		/* start of RECEIVE_INFO */
+#define	UATH_STATUS_OK			0
+#define	UATH_STATUS_STOP_IN_PROGRESS	1
+#define	UATH_STATUS_CRC_ERR		2
+#define	UATH_STATUS_PHY_ERR		3
+#define	UATH_STATUS_DECRYPT_CRC_ERR	4
+#define	UATH_STATUS_DECRYPT_MIC_ERR	5
+#define	UATH_STATUS_DECOMP_ERR		6
+#define	UATH_STATUS_KEY_ERR		7
+#define	UATH_STATUS_ERR			8
+	uint32_t	tstamp_low;	/* low-order 32-bits of rx timestamp */
+	uint32_t	tstamp_high;	/* high-order 32-bits of rx timestamp */
+	uint32_t	framelen;	/* frame length */
+	uint32_t	rate;		/* rx rate code */
+	uint32_t	antenna;
+	int32_t		rssi;
+	uint32_t	channel;
+	uint32_t	phyerror;
+	uint32_t	connix;		/* key table ix for bss traffic */
+	uint32_t	decrypterror;
+	uint32_t	keycachemiss;
+	uint32_t	pad;		/* XXX? */
+};
+#pragma pack()
+
+#pragma pack(1)
+struct uath_tx_desc {
+	uint32_t	msglen;
+	uint32_t	msgid;		/* msg id (supplied by host) */
+	uint32_t	type;		/* opcode: WDMSG_SEND or WDCMSG_FLUSH */
+	uint32_t	txqid;		/* tx queue id and flags */
+#define	UATH_TXQID_MASK		0x0f
+#define	UATH_TXQID_MINRATE	0x10	/* use min tx rate */
+#define	UATH_TXQID_FF		0x20	/* content is fast frame */
+	uint32_t	connid;		/* tx connection id */
+#define	UATH_ID_INVALID	0xffffffff	/* for sending prior to connection */
+	uint32_t	flags;		/* non-zero if response desired */
+#define	UATH_TX_NOTIFY	(1 << 24)	/* f/w will send a UATH_NOTIF_TX */
+	uint32_t	buflen;		/* payload length */
+};
+#pragma pack()
+
+#pragma pack(1)
+struct uath_cmd_host_available {
+	uint32_t	sw_ver_major;
+	uint32_t	sw_ver_minor;
+	uint32_t	sw_ver_patch;
+	uint32_t	sw_ver_build;
+};
+#pragma pack()
+
+#define	ATH_SW_VER_MAJOR	1
+#define	ATH_SW_VER_MINOR	5
+#define	ATH_SW_VER_PATCH	0
+#define	ATH_SW_VER_BUILD	9999
+
+
+/* structure for command UATH_CMD_WRITE_MAC */
+#pragma pack(1)
+struct uath_write_mac {
+	uint32_t	reg;
+	uint32_t	len;
+	uint8_t		data[32];
+};
+#pragma pack()
+
+#pragma pack(1)
+struct uath_cmd_ledsteady {		/* WDCMSG_SET_LED_STEADY */
+	uint32_t	lednum;
+#define	UATH_LED_LINK		0
+#define	UATH_LED_ACTIVITY	1
+	uint32_t	ledmode;
+#define	UATH_LED_OFF	0
+#define	UATH_LED_ON	1
+};
+#pragma pack()
+
+#pragma pack(1)
+struct uath_cmd_ledblink {		/* WDCMSG_SET_LED_BLINK */
+	uint32_t	lednum;
+	uint32_t	ledmode;
+	uint32_t	blinkrate;
+	uint32_t	slowmode;
+};
+#pragma pack()
+
+/* structure for command WDCMSG_RESET */
+#pragma pack(1)
+struct uath_cmd_reset {
+	uint32_t	flags;		/* channel flags */
+#define	UATH_CHAN_TURBO	0x0100
+#define	UATH_CHAN_CCK	0x0200
+#define	UATH_CHAN_OFDM	0x0400
+#define	UATH_CHAN_2GHZ	0x1000
+#define	UATH_CHAN_5GHZ	0x2000
+	uint32_t	freq;		/* channel frequency */
+	uint32_t	maxrdpower;
+	uint32_t	cfgctl;
+	uint32_t	twiceantennareduction;
+	uint32_t	channelchange;
+	uint32_t	keeprccontent;
+};
+#pragma pack()
+
+#pragma pack(1)
+struct uath_cmd_rateset {
+	uint8_t		length;
+#define	UATH_MAX_NRATES	32
+	uint8_t		set[UATH_MAX_NRATES];
+};
+#pragma pack()
+
+#pragma pack(1)
+/* structure for command WDCMSG_SET_BASIC_RATE */
+struct uath_cmd_rates {
+	uint32_t	connid;
+	uint32_t	keeprccontent;
+	uint32_t	size;
+	struct uath_cmd_rateset rateset;
+};
+#pragma pack()
+
+enum {
+	WLAN_MODE_NONE = 0,
+	WLAN_MODE_11b,
+	WLAN_MODE_11a,
+	WLAN_MODE_11g,
+	WLAN_MODE_11a_TURBO,
+	WLAN_MODE_11g_TURBO,
+	WLAN_MODE_11a_TURBO_PRIME,
+	WLAN_MODE_11g_TURBO_PRIME,
+	WLAN_MODE_11a_XR,
+	WLAN_MODE_11g_XR,
+};
+
+#pragma pack(1)
+struct uath_cmd_connection_attr {
+	uint32_t	longpreambleonly;
+	struct uath_cmd_rateset	rateset;
+	uint32_t	wlanmode;
+};
+#pragma pack()
+
+#pragma pack(1)
+/* structure for command WDCMSG_CREATE_CONNECTION */
+struct uath_cmd_create_connection {
+	uint32_t	connid;
+	uint32_t	bssid;
+	uint32_t	size;
+	struct uath_cmd_connection_attr	connattr;
+};
+#pragma pack()
+
+#pragma pack(1)
+struct uath_cmd_txq_attr {
+	uint32_t	priority;
+	uint32_t	aifs;
+	uint32_t	logcwmin;
+	uint32_t	logcwmax;
+	uint32_t	bursttime;
+	uint32_t	mode;
+	uint32_t	qflags;
+};
+#pragma pack()
+
+#pragma pack(1)
+struct uath_cmd_txq_setup {		/* WDCMSG_SETUP_TX_QUEUE */
+	uint32_t	qid;
+	uint32_t	len;
+	struct uath_cmd_txq_attr attr;
+};
+#pragma pack()
+
+#pragma pack(1)
+struct uath_cmd_rx_filter {		/* WDCMSG_RX_FILTER */
+	uint32_t	bits;
+#define	UATH_FILTER_RX_UCAST		0x00000001
+#define	UATH_FILTER_RX_MCAST		0x00000002
+#define	UATH_FILTER_RX_BCAST		0x00000004
+#define	UATH_FILTER_RX_CONTROL		0x00000008
+#define	UATH_FILTER_RX_BEACON		0x00000010	/* beacon frames */
+#define	UATH_FILTER_RX_PROM		0x00000020	/* promiscuous mode */
+#define	UATH_FILTER_RX_PHY_ERR		0x00000040	/* phy errors */
+#define	UATH_FILTER_RX_PHY_RADAR	0x00000080	/* radar phy errors */
+#define	UATH_FILTER_RX_XR_POOL		0x00000400	/* XR group polls */
+#define	UATH_FILTER_RX_PROBE_REQ	0x00000800
+	uint32_t	op;
+#define	UATH_FILTER_OP_INIT		0x0
+#define	UATH_FILTER_OP_SET		0x1
+#define	UATH_FILTER_OP_CLEAR		0x2
+#define	UATH_FILTER_OP_TEMP		0x3
+#define	UATH_FILTER_OP_RESTORE		0x4
+};
+#pragma pack()
+
+#pragma pack(1)
+struct uath_cmd_set_associd {		/* WDCMSG_WRITE_ASSOCID */
+	uint32_t	defaultrateix;
+	uint32_t	associd;
+	uint32_t	timoffset;
+	uint32_t	turboprime;
+	uint32_t	bssid[2];
+};
+#pragma pack()
+
+enum {
+	CFG_NONE,			/* Sentinal to indicate "no config" */
+	CFG_REG_DOMAIN,			/* Regulatory Domain */
+	CFG_RATE_CONTROL_ENABLE,
+	CFG_DEF_XMIT_DATA_RATE,		/* NB: if rate control is not enabled */
+	CFG_HW_TX_RETRIES,
+	CFG_SW_TX_RETRIES,
+	CFG_SLOW_CLOCK_ENABLE,
+	CFG_COMP_PROC,
+	CFG_USER_RTS_THRESHOLD,
+	CFG_XR2NORM_RATE_THRESHOLD,
+	CFG_XRMODE_SWITCH_COUNT,
+	CFG_PROTECTION_TYPE,
+	CFG_BURST_SEQ_THRESHOLD,
+	CFG_ABOLT,
+	CFG_IQ_LOG_COUNT_MAX,
+	CFG_MODE_CTS,
+	CFG_WME_ENABLED,
+	CFG_GPRS_CBR_PERIOD,
+	CFG_SERVICE_TYPE,
+	/* MAC Address to use.  Overrides EEPROM */
+	CFG_MAC_ADDR,
+	CFG_DEBUG_EAR,
+	CFG_INIT_REGS,
+	/* An ID for use in error & debug messages */
+	CFG_DEBUG_ID,
+	CFG_COMP_WIN_SZ,
+	CFG_DIVERSITY_CTL,
+	CFG_TP_SCALE,
+	CFG_TPC_HALF_DBM5,
+	CFG_TPC_HALF_DBM2,
+	CFG_OVERRD_TX_POWER,
+	CFG_USE_32KHZ_CLOCK,
+	CFG_GMODE_PROTECTION,
+	CFG_GMODE_PROTECT_RATE_INDEX,
+	CFG_GMODE_NON_ERP_PREAMBLE,
+	CFG_WDC_TRANSPORT_CHUNK_SIZE,
+};
+
+enum {
+	/* Sentinal to indicate "no capability" */
+	CAP_NONE,
+	CAP_ALL,			/* ALL capabilities */
+	CAP_TARGET_VERSION,
+	CAP_TARGET_REVISION,
+	CAP_MAC_VERSION,
+	CAP_MAC_REVISION,
+	CAP_PHY_REVISION,
+	CAP_ANALOG_5GHz_REVISION,
+	CAP_ANALOG_2GHz_REVISION,
+	/* Target supports WDC message debug features */
+	CAP_DEBUG_WDCMSG_SUPPORT,
+
+	CAP_REG_DOMAIN,
+	CAP_COUNTRY_CODE,
+	CAP_REG_CAP_BITS,
+
+	CAP_WIRELESS_MODES,
+	CAP_CHAN_SPREAD_SUPPORT,
+	CAP_SLEEP_AFTER_BEACON_BROKEN,
+	CAP_COMPRESS_SUPPORT,
+	CAP_BURST_SUPPORT,
+	CAP_FAST_FRAMES_SUPPORT,
+	CAP_CHAP_TUNING_SUPPORT,
+	CAP_TURBOG_SUPPORT,
+	CAP_TURBO_PRIME_SUPPORT,
+	CAP_DEVICE_TYPE,
+	CAP_XR_SUPPORT,
+	CAP_WME_SUPPORT,
+	CAP_TOTAL_QUEUES,
+	CAP_CONNECTION_ID_MAX,		/* Should absorb CAP_KEY_CACHE_SIZE */
+
+	CAP_LOW_5GHZ_CHAN,
+	CAP_HIGH_5GHZ_CHAN,
+	CAP_LOW_2GHZ_CHAN,
+	CAP_HIGH_2GHZ_CHAN,
+
+	CAP_MIC_AES_CCM,
+	CAP_MIC_CKIP,
+	CAP_MIC_TKIP,
+	CAP_MIC_TKIP_WME,
+	CAP_CIPHER_AES_CCM,
+	CAP_CIPHER_CKIP,
+	CAP_CIPHER_TKIP,
+
+	CAP_TWICE_ANTENNAGAIN_5G,
+	CAP_TWICE_ANTENNAGAIN_2G,
+};
+
+enum {
+	ST_NONE,			/* Sentinal to indicate "no status" */
+	ST_ALL,
+	ST_SERVICE_TYPE,
+	ST_WLAN_MODE,
+	ST_FREQ,
+	ST_BAND,
+	ST_LAST_RSSI,
+	ST_PS_FRAMES_DROPPED,
+	ST_CACHED_DEF_ANT,
+	ST_COUNT_OTHER_RX_ANT,
+	ST_USE_FAST_DIVERSITY,
+	ST_MAC_ADDR,
+	ST_RX_GENERATION_NUM,
+	ST_TX_QUEUE_DEPTH,
+	ST_SERIAL_NUMBER,
+	ST_WDC_TRANSPORT_CHUNK_SIZE,
+};
+
+enum {
+	TARGET_DEVICE_AWAKE,
+	TARGET_DEVICE_SLEEP,
+	TARGET_DEVICE_PWRDN,
+	TARGET_DEVICE_PWRSAVE,
+	TARGET_DEVICE_SUSPEND,
+	TARGET_DEVICE_RESUME,
+};
+
+#define	UATH_MAX_TXBUFSZ						\
+	(sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc) +	\
+	IEEE80211_MAX_LEN)
+
+/*
+ * it's not easy to measure how the chunk is passed into the host if the target
+ * passed the multi-chunks so just we check a minimal size we can imagine.
+ */
+#define	UATH_MIN_RXBUFSZ	(sizeof (struct uath_chunk))
+
+#define	USB_VENDOR_ACCTON		0x083a	/* Accton Technology */
+#define	USB_VENDOR_ATHEROS		0x168c	/* Atheros Communications */
+#define	USB_VENDOR_ATHEROS2		0x0cf3	/* Atheros Communications */
+#define	USB_VENDOR_CONCEPTRONIC		0x0d8e	/* Conceptronic */
+#define	USB_VENDOR_DLINK		0x2001	/* D-Link */
+#define	USB_VENDOR_GIGASET		0x1690	/* Gigaset */
+#define	USB_VENDOR_GLOBALSUN		0x16ab	/* Global Sun Technology */
+#define	USB_VENDOR_IODATA		0x04bb	/* I/O Data */
+#define	USB_VENDOR_MELCO		0x0411	/* Melco */
+#define	USB_VENDOR_NETGEAR		0x0846	/* BayNETGEAR */
+#define	USB_VENDOR_NETGEAR3		0x1385	/* Netgear */
+#define	USB_VENDOR_PHILIPS		0x0471	/* Philips */
+#define	USB_VENDOR_UMEDIA		0x157e	/* U-MEDIA Communications */
+#define	USB_VENDOR_WISTRONNEWEB		0x1435	/* Wistron NeWeb */
+#define	USB_VENDOR_ZCOM			0x0cde	/* Z-Com */
+
+#define	USB_PRODUCT_ACCTON_SMCWUSBTG2		0x4506	/* SMCWUSBT-G2 */
+#define	USB_PRODUCT_ACCTON_SMCWUSBTG2_NF	0x4507	/* SMCWUSBT-G2 */
+#define	USB_PRODUCT_ATHEROS_AR5523		0x0001	/* AR5523 */
+#define	USB_PRODUCT_ATHEROS_AR5523_NF		0x0002	/* AR5523 */
+#define	USB_PRODUCT_ATHEROS2_AR5523_1		0x0003	/* AR5523 */
+#define	USB_PRODUCT_ATHEROS2_AR5523_1_NF	0x0002	/* AR5523 */
+#define	USB_PRODUCT_ATHEROS2_AR5523_2		0x0005	/* AR5523 */
+#define	USB_PRODUCT_ATHEROS2_AR5523_2_NF	0x0004	/* AR5523 */
+#define	USB_PRODUCT_ATHEROS2_AR5523_3		0x0007	/* AR5523 */
+#define	USB_PRODUCT_ATHEROS2_AR5523_3_NF	0x0006	/* AR5523 */
+#define	USB_PRODUCT_CONCEPTRONIC_AR5523_1	0x7801	/* AR5523 */
+#define	USB_PRODUCT_CONCEPTRONIC_AR5523_1_NF	0x7802	/* AR5523 */
+#define	USB_PRODUCT_CONCEPTRONIC_AR5523_2	0x7811	/* AR5523 */
+#define	USB_PRODUCT_CONCEPTRONIC_AR5523_2_NF	0x7812	/* AR5523 */
+#define	USB_PRODUCT_DLINK_DWLAG122		0x3a04	/* DWL-AG122 */
+#define	USB_PRODUCT_DLINK_DWLAG122_NF		0x3a05	/* DWL-AG122 */
+#define	USB_PRODUCT_DLINK_DWLAG132		0x3a00	/* DWL-AG132 */
+#define	USB_PRODUCT_DLINK_DWLAG132_NF		0x3a01	/* DWL-AG132 */
+#define	USB_PRODUCT_DLINK_DWLG132		0x3a02	/* DWL-G132 */
+#define	USB_PRODUCT_DLINK_DWLG132_NF		0x3a03	/* DWL-G132 */
+#define	USB_PRODUCT_GIGASET_AR5523		0x0712	/* AR5523 */
+#define	USB_PRODUCT_GIGASET_AR5523_NF		0x0713	/* AR5523 */
+#define	USB_PRODUCT_GIGASET_SMCWUSBTG		0x0710	/* SMCWUSBT-G */
+#define	USB_PRODUCT_GIGASET_SMCWUSBTG_NF	0x0711	/* SMCWUSBT-G */
+#define	USB_PRODUCT_GLOBALSUN_AR5523_1		0x7801	/* AR5523 */
+#define	USB_PRODUCT_GLOBALSUN_AR5523_1_NF	0x7802	/* AR5523 */
+#define	USB_PRODUCT_GLOBALSUN_AR5523_2		0x7811	/* AR5523 */
+#define	USB_PRODUCT_GLOBALSUN_AR5523_2_NF	0x7812	/* AR5523 */
+#define	USB_PRODUCT_IODATA_USBWNG54US		0x0928	/* USB WN-G54/US */
+#define	USB_PRODUCT_IODATA_USBWNG54US_NF	0x0929	/* USB WN-G54/US */
+#define	USB_PRODUCT_MELCO_WLIU2KAMG54		0x0091	/* WLI-U2-KAMG54 */
+#define	USB_PRODUCT_MELCO_WLIU2KAMG54_NF	0x0092	/* WLI-U2-KAMG54 */
+#define	USB_PRODUCT_NETGEAR_WG111U		0x4300	/* WG111U */
+#define	USB_PRODUCT_NETGEAR_WG111U_NF		0x4301	/* WG111U */
+#define	USB_PRODUCT_NETGEAR3_WG111T		0x4252	/* WG111T */
+#define	USB_PRODUCT_NETGEAR3_WG111T_NF		0x4251	/* WG111T */
+#define	USB_PRODUCT_NETGEAR3_WPN111		0x5f00	/* WPN111 */
+#define	USB_PRODUCT_NETGEAR3_WPN111_NF		0x5f01	/* WPN111 */
+#define	USB_PRODUCT_PHILIPS_SNU6500		0x1232	/* SNU6500 */
+#define	USB_PRODUCT_PHILIPS_SNU6500_NF		0x1233	/* SNU6500 */
+#define	USB_PRODUCT_UMEDIA_AR5523_2		0x3205	/* AR5523 */
+#define	USB_PRODUCT_UMEDIA_AR5523_2_NF		0x3206	/* AR5523 */
+#define	USB_PRODUCT_UMEDIA_TEW444UBEU		0x3006	/* TEW-444UB EU */
+#define	USB_PRODUCT_UMEDIA_TEW444UBEU_NF	0x3007	/* TEW-444UB EU */
+#define	USB_PRODUCT_WISTRONNEWEB_AR5523_1	0x0826	/* AR5523 */
+#define	USB_PRODUCT_WISTRONNEWEB_AR5523_1_NF	0x0827	/* AR5523 */
+#define	USB_PRODUCT_WISTRONNEWEB_AR5523_2	0x082a	/* AR5523 */
+#define	USB_PRODUCT_WISTRONNEWEB_AR5523_2_NF	0x0829	/* AR5523 */
+#define	USB_PRODUCT_ZCOM_AR5523			0x0012	/* AR5523 */
+#define	USB_PRODUCT_ZCOM_AR5523_NF		0x0013	/* AR5523 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UATH_REG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/uath/uath_var.h	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,264 @@
+/*
+ *
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2006
+ *	Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2006 Sam Leffler, Errno Consulting
+ * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef	_UATH_VAR_H
+#define	_UATH_VAR_H
+
+#include <sys/queue.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define	UATH_ID_BSS		2	/* Connection ID  */
+
+#define	UATH_RX_DATA_LIST_COUNT	1	/* 128 */
+#define	UATH_TX_DATA_LIST_COUNT	8	/* 16 */
+#define	UATH_CMD_LIST_COUNT	8	/* 60 */
+
+#define	UATH_DATA_TIMEOUT	10000
+#define	UATH_CMD_TIMEOUT	1000
+
+/*
+ * Useful combinations of channel characteristics from net80211.
+ */
+#define	UATH_CHAN_A	\
+	(IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
+#define	UATH_CHAN_B	\
+	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
+#define	UATH_CHAN_PUREG	\
+	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM)
+#define	UATH_CHAN_G	\
+	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
+
+#define	UATH_IS_CHAN_A(_c)		\
+	(((_c)->ich_flags & UATH_CHAN_A) == UATH_CHAN_A)
+#define	UATH_IS_CHAN_B(_c)		\
+	(((_c)->ich_flags & UATH_CHAN_B) == UATH_CHAN_B)
+#define	UATH_IS_CHAN_PUREG(_c)	\
+	(((_c)->ich_flags & UATH_CHAN_PUREG) == UATH_CHAN_PUREG)
+#define	UATH_IS_CHAN_G(_c)		\
+	(((_c)->ich_flags & UATH_CHAN_G) == UATH_CHAN_G)
+#define	UATH_IS_CHAN_ANYG(_c)	\
+	(UATH_IS_CHAN_PUREG(_c) || UATH_IS_CHAN_G(_c))
+
+#define	UATH_IS_CHAN_OFDM(_c)	\
+	((_c)->ich_flags & IEEE80211_CHAN_OFDM)
+#define	UATH_IS_CHAN_CCK(_c)	\
+	((_c)->ich_flags & IEEE80211_CHAN_CCK)
+
+#define	UATH_NODE_QOS	0x0002		/* QoS enabled */
+
+
+/* flags for sending firmware commands */
+#define	UATH_CMD_FLAG_ASYNC	(1 << 0)
+#define	UATH_CMD_FLAG_READ	(1 << 1)
+#define	UATH_CMD_FLAG_MAGIC	(1 << 2)
+
+struct uath_cmd {
+	struct uath_softc	*sc;
+	uint32_t		flags;
+	uint32_t		msgid;
+	uint8_t			*buf;
+	uint16_t		buflen;
+	void			*odata;		/* NB: tx only */
+	int			olen;		/* space in odata */
+	STAILQ_ENTRY(uath_cmd)	next;
+};
+typedef STAILQ_HEAD(, uath_cmd) uath_cmdhead;
+
+struct uath_data {
+	struct uath_softc	*sc;
+	uint8_t			*buf;
+	uint16_t		buflen;
+	struct ieee80211_node	*ni;		/* NB: tx only */
+	STAILQ_ENTRY(uath_data)	next;
+};
+typedef STAILQ_HEAD(, uath_data) uath_datahead;
+
+struct uath_cmd_lock {
+	boolean_t	done;
+	kmutex_t	mutex;
+	kcondvar_t	cv;
+};
+
+struct uath_wme_settings {
+	uint8_t				aifsn;
+	uint8_t				logcwmin;
+	uint8_t				logcwmax;
+	uint16_t			txop;
+#define	UATH_TXOP_TO_US(txop)		((txop) << 5)
+	uint8_t				acm;
+};
+
+struct uath_devcap {
+	uint32_t			targetVersion;
+	uint32_t			targetRevision;
+	uint32_t			macVersion;
+	uint32_t			macRevision;
+	uint32_t			phyRevision;
+	uint32_t			analog5GhzRevision;
+	uint32_t			analog2GhzRevision;
+	uint32_t			regDomain;
+	uint32_t			regCapBits;
+	uint32_t			countryCode;
+	uint32_t			keyCacheSize;
+	uint32_t			numTxQueues;
+	uint32_t			connectionIdMax;
+	uint32_t			wirelessModes;
+#define	UATH_WIRELESS_MODE_11A		0x01
+#define	UATH_WIRELESS_MODE_TURBO	0x02
+#define	UATH_WIRELESS_MODE_11B		0x04
+#define	UATH_WIRELESS_MODE_11G		0x08
+#define	UATH_WIRELESS_MODE_108G		0x10
+	uint32_t			chanSpreadSupport;
+	uint32_t			compressSupport;
+	uint32_t			burstSupport;
+	uint32_t			fastFramesSupport;
+	uint32_t			chapTuningSupport;
+	uint32_t			turboGSupport;
+	uint32_t			turboPrimeSupport;
+	uint32_t			deviceType;
+	uint32_t			wmeSupport;
+	uint32_t			low2GhzChan;
+	uint32_t			high2GhzChan;
+	uint32_t			low5GhzChan;
+	uint32_t			high5GhzChan;
+	uint32_t			supportCipherWEP;
+	uint32_t			supportCipherAES_CCM;
+	uint32_t			supportCipherTKIP;
+	uint32_t			supportCipherMicAES_CCM;
+	uint32_t			supportMicTKIP;
+	uint32_t			twiceAntennaGain5G;
+	uint32_t			twiceAntennaGain2G;
+};
+
+struct uath_stat {
+	uint32_t			st_badchunkseqnum;
+	uint32_t			st_invalidlen;
+	uint32_t			st_multichunk;
+	uint32_t			st_toobigrxpkt;
+	uint32_t			st_stopinprogress;
+	uint32_t			st_crcerr;
+	uint32_t			st_phyerr;
+	uint32_t			st_decrypt_crcerr;
+	uint32_t			st_decrypt_micerr;
+	uint32_t			st_decomperr;
+	uint32_t			st_keyerr;
+	uint32_t			st_err;
+	/* not use CMD/RX/TX queues, so ignore some structure */
+};
+#define	UATH_STAT_INC(sc, var)		(sc)->sc_stat.var++
+#define	UATH_STAT_DEC(sc, var)		(sc)->sc_stat.var--
+
+struct uath_softc {
+	struct ieee80211com	sc_ic;
+	dev_info_t		*sc_dev;
+
+	usb_client_dev_data_t	*sc_udev;	/* usb dev */
+	int			dev_flags;
+	uint32_t		sc_flags;
+
+	usb_pipe_handle_t	rx_cmd_pipe;
+	usb_pipe_handle_t	rx_data_pipe;
+	usb_pipe_handle_t	tx_cmd_pipe;
+	usb_pipe_handle_t	tx_data_pipe;
+
+	kmutex_t		sc_genlock;
+	kmutex_t		sc_rxlock_cmd;
+	kmutex_t		sc_rxlock_data;
+	kmutex_t		sc_txlock_cmd;
+	kmutex_t		sc_txlock_data;
+
+	struct uath_cmd		sc_cmd[UATH_CMD_LIST_COUNT];
+	struct uath_data	sc_rx[UATH_RX_DATA_LIST_COUNT];
+	struct uath_data	sc_tx[UATH_TX_DATA_LIST_COUNT];
+
+	int			tx_cmd_queued;
+	int			rx_cmd_queued;
+	int			tx_data_queued;
+	int			rx_data_queued;
+
+	int			sc_cmdid;
+
+	struct uath_stat	sc_stat;
+
+	struct uath_cmd_lock 	rlock;
+	struct uath_cmd_lock 	wlock;
+
+	struct uath_devcap	sc_devcap;
+	uint8_t			sc_serial[16];
+
+	uint32_t		sc_msgid;
+	uint32_t		sc_seqnum;
+
+	uint8_t			sc_intrx_nextnum;
+	uint32_t		sc_intrx_len;
+#define	UATH_MAX_INTRX_SIZE		3616
+
+	timeout_id_t		sc_scan_id;
+	timeout_id_t		sc_stat_id;
+
+	uint32_t		sc_need_sched;
+
+	/* kstats */
+	uint32_t		sc_tx_nobuf;
+	uint32_t		sc_rx_nobuf;
+	uint32_t		sc_tx_err;
+	uint32_t		sc_rx_err;
+	uint32_t		sc_tx_retries;
+
+	int			(*sc_newstate)(struct ieee80211com *,
+				    enum ieee80211_state, int);
+};
+
+#define	UATH_SUCCESS		0
+#define	UATH_FAILURE		-1
+
+#define	UATH_FLAG_RUNNING	(1 << 0)
+#define	UATH_FLAG_SUSPEND	(1 << 1)
+#define	UATH_FLAG_RECONNECT	(1 << 2)
+#define	UATH_FLAG_DISCONNECT	(1 << 3)
+
+#define	UATH_LOCK(sc)		mutex_enter(&(sc)->sc_genlock)
+#define	UATH_UNLOCK(sc)		mutex_exit(&(sc)->sc_genlock)
+#define	UATH_IS_RUNNING(_sc)	((_sc)->sc_flags & UATH_FLAG_RUNNING)
+#define	UATH_IS_SUSPEND(_sc)	((_sc)->sc_flags & UATH_FLAG_SUSPEND)
+#define	UATH_IS_DISCONNECT(_sc)	((_sc)->sc_flags & UATH_FLAG_DISCONNECT)
+#define	UATH_IS_RECONNECT(_sc)	((_sc)->sc_flags & UATH_FLAG_RECONNECT)
+
+#define	UATH_RESET_INTRX(sc) do {		\
+	(sc)->sc_intrx_nextnum = 0;		\
+	(sc)->sc_intrx_len = 0;			\
+	_NOTE(CONSTCOND)						\
+} while (0)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UATH_VAR_H */
--- a/usr/src/uts/common/io/vuidmice/vuidps2.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/io/vuidmice/vuidps2.c	Mon Jul 20 13:07:46 2009 -0400
@@ -59,18 +59,18 @@
 #define	PS2_DELTA_Y			3	/* Got delta X		*/
 #define	PS2_WHEEL_DELTA_Z		4
 #define	PS2_WHEEL5_DELTA_Z		5
-#define	PS2_WAIT_RESET_ACK		6
-#define	PS2_WAIT_RESET_AA		7
-#define	PS2_WAIT_RESET_00		8
+#define	PS2_WAIT_RESET_COMPLETE		6
+#define	PS2_WAIT_FOR_AA			7
+#define	PS2_WAIT_FOR_00			8
 #define	PS2_WAIT_SETRES0_ACK1		9
 #define	PS2_WAIT_SETRES0_ACK2		10	/* -+ must be consecutive */
 #define	PS2_WAIT_SCALE1_1_ACK		11	/*  | */
 #define	PS2_WAIT_SCALE1_2_ACK		12	/*  | */
 #define	PS2_WAIT_SCALE1_3_ACK		13	/* -+ */
-#define	PS2_WAIT_STATREQ_ACK		14
-#define	PS2_WAIT_STATUS_1		15
-#define	PS2_WAIT_STATUS_BUTTONS		16
-#define	PS2_WAIT_STATUS_REV		17
+#define	PS2_WAIT_STATREQ_ACK		14	/* -+ */
+#define	PS2_WAIT_STATUS_1		15	/*  | */
+#define	PS2_WAIT_STATUS_BUTTONS		16	/*  | must stay in this order */
+#define	PS2_WAIT_STATUS_REV		17	/* -+ */
 #define	PS2_WAIT_STATUS_3		18
 #define	PS2_WAIT_WHEEL_SMPL1_CMD_ACK	19	/* Set the sample rate to 200 */
 #define	PS2_WAIT_WHEEL_SMPL1_RATE_ACK	20
@@ -94,9 +94,6 @@
 #define	PS2_WAIT_STREAM_ACK		38
 #define	PS2_WAIT_ON_ACK			39
 
-#define	MSE_AA		0xaa
-#define	MSE_00		0x00
-
 #define	MOUSE_MODE_PLAIN	0	/* Normal PS/2 mouse - 3 byte msgs */
 #define	MOUSE_MODE_WHEEL	1	/* Wheel mouse - 4 byte msgs */
 #define	MOUSE_MODE_WHEEL5	2	/* Wheel + 5 btn mouse - 4 byte msgs */
@@ -115,7 +112,6 @@
 
 #define	PS2_MAX_INIT_COUNT	5
 
-
 static void vuidmice_send_wheel_event(queue_t *const, uchar_t,
 		uchar_t, uchar_t, int);
 extern void VUID_PUTNEXT(queue_t *const, uchar_t, uchar_t, uchar_t, int);
@@ -126,7 +122,6 @@
  * We apply timeout to nearly each command-response
  * during initialization:
  *
- * Set timeout for RESET
  * Set timeout for SET RESOLUTION
  * Set timeout for SET SCALE
  * Set timeout for SET SAMPLE RATE
@@ -141,7 +136,8 @@
 static void
 vuid_set_timeout(queue_t *const qp, clock_t time)
 {
-	ASSERT(STATEP->init_tid == 0);
+	if (STATEP->init_tid != 0)
+		(void) quntimeout(qp, STATEP->init_tid);
 	STATEP->init_tid = qtimeout(qp, VUID_INIT_TIMEOUT,
 	    qp, drv_usectohz(time));
 }
@@ -149,7 +145,6 @@
 static void
 vuid_cancel_timeout(queue_t *const qp)
 {
-	ASSERT(STATEP->init_tid != 0);
 	(void) quntimeout(qp, STATEP->init_tid);
 	STATEP->init_tid = 0;
 }
@@ -214,6 +209,30 @@
 	}
 }
 
+static void
+vuidmice_start_wdc_or_setres(queue_t *qp)
+{
+	/* Set timeout for set res or sample rate */
+	vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP);
+
+	/*
+	 * Start the wheel-mouse detection code.  First, we look
+	 * for standard wheel mice.  If we set the sample rate
+	 * to 200, 100, and then 80 and finally request the
+	 * device ID, a wheel mouse will return an ID of 0x03.
+	 * After that, we'll try for the wheel+5 variety.  The
+	 * incantation in this case is 200, 200, and 80.  We'll
+	 * get 0x04 back in that case.
+	 */
+	if (STATEP->inited & PS2_FLAG_NO_EXTN) {
+		STATEP->state = PS2_WAIT_SETRES3_ACK1;
+		put1(WR(qp), MSESETRES);
+	} else {
+		STATEP->state = PS2_WAIT_WHEEL_SMPL1_CMD_ACK;
+		put1(WR(qp), MSECHGMOD);
+	}
+}
+
 int
 VUID_OPEN(queue_t *const qp)
 {
@@ -222,10 +241,7 @@
 	STATEP->inited = 0;
 	STATEP->nbuttons = 3;
 
-	STATEP->state = PS2_WAIT_RESET_ACK;
-
-	/* Set timeout for reset */
-	vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET);
+	STATEP->state = PS2_WAIT_RESET_COMPLETE;
 
 	put1(WR(qp), MSERESET);
 
@@ -277,24 +293,49 @@
 		STATEP->inited |= PS2_FLAG_NO_EXTN;
 	}
 
-	if (++STATEP->init_count >= PS2_MAX_INIT_COUNT) {
-		STATEP->inited |= PS2_FLAG_INIT_TIMEOUT;
+
+	/*
+	 * If the Logitech button detection sequence timed out at some point
+	 * in the sequence, ignore it and skip to the next step in
+	 * initialization.  Do NOT count this as a timeout, so do NOT
+	 * increment init_count.
+	 */
+	if (STATEP->state >= PS2_WAIT_STATREQ_ACK &&
+	    STATEP->state <= PS2_WAIT_STATUS_REV) {
+
+		/* See the comment under the PS2_WAIT_STATUS_BUTTONS case */
+#if	defined(VUID3PS2)
+		STATEP->nbuttons = 3;
+#else
+		STATEP->nbuttons = 2;
+#endif
+		vuidmice_start_wdc_or_setres(qp);
 		return;
 	}
 
-
-	STATEP->state = PS2_WAIT_RESET_ACK;
+	/*
+	 * If the initialization process has timed out too many times, even if
+	 * a subset of the process was successful, stop trying and put the
+	 * mouse in the only state from which it can recover -- waiting for an
+	 * 0xAA 0x00 response (i.e. like one we get on resume from mouse8042
+	 * or from a replug).
+	 */
+	if (++STATEP->init_count >= PS2_MAX_INIT_COUNT) {
+		STATEP->inited |= PS2_FLAG_INIT_TIMEOUT;
+		STATEP->state = PS2_WAIT_FOR_AA;
+	} else {
 
-	vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET);
+		STATEP->state = PS2_WAIT_RESET_COMPLETE;
 
-	/* try again */
-	put1(WR(qp), MSERESET);
+		/* Try to reset the mouse again */
+		put1(WR(qp), MSERESET);
+	}
 }
 
 void
 VUID_QUEUE(queue_t *const qp, mblk_t *mp)
 {
-	int code;
+	int code, length;
 	clock_t now;
 	clock_t elapsed;
 	clock_t mouse_timeout;
@@ -305,6 +346,7 @@
 	STATEP->last_event_lbolt = now;
 
 	while (mp->b_rptr < mp->b_wptr) {
+		length = MBLKL(mp);
 		code = *mp->b_rptr++;
 
 		switch (STATEP->state) {
@@ -391,10 +433,39 @@
 
 			break;
 
+		case PS2_WAIT_FOR_AA:
+			/*
+			 * On Dell latitude D800, the initial MSE_ACK is
+			 * received after the initialization sequence
+			 * times out, so restart it here.
+			 */
+			if (code == MSE_ACK) {
+				STATEP->inited &= ~PS2_FLAG_INIT_TIMEOUT;
+				STATEP->init_count = 0;
+				STATEP->state = PS2_WAIT_RESET_COMPLETE;
+				put1(WR(qp), MSERESET);
+				break;
+			}
+
+			if (code != MSE_AA)
+				break;
+
+			STATEP->state = PS2_WAIT_FOR_00;
+			break;
+
+		case PS2_WAIT_FOR_00:
+			if (code != MSE_00)
+				break;
+
+			STATEP->inited &= ~PS2_FLAG_INIT_TIMEOUT;
+			STATEP->init_count = 0;
+			STATEP->state = PS2_WAIT_RESET_COMPLETE;
+			put1(WR(qp), MSERESET);
+			break;
+
 		case PS2_MAYBE_REATTACH:
 			if (code == MSE_00) {
-				STATEP->state = PS2_WAIT_RESET_ACK;
-				vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET);
+				STATEP->state = PS2_WAIT_RESET_COMPLETE;
 				put1(WR(qp), MSERESET);
 				break;
 			}
@@ -542,48 +613,45 @@
 			STATEP->deltax = STATEP->deltay = 0;
 			break;
 
-		case PS2_WAIT_RESET_ACK:
-			if (code != MSE_ACK) {
+		case PS2_WAIT_RESET_COMPLETE:
+
+			/*
+			 * If length is 1, code holds the data from the message.
+			 * for lengths > 1, we look at *(mp->b_rptr + offset)
+			 * for the rest of the data.
+			 */
+			if (length == 1) {
+				/*
+				 * Technically, a length of 1 from the mouse
+				 * driver should only contain a MSEERROR or
+				 * MSERESEND value, but we don't test
+				 * that here because we'd be issuing a reset
+				 * anyway.  For mice that are not connected,
+				 * we will receive a MSERESEND quickly.
+				 */
+				if (++STATEP->init_count >=
+				    PS2_MAX_INIT_COUNT) {
+					STATEP->inited |= PS2_FLAG_INIT_TIMEOUT;
+					STATEP->state = PS2_WAIT_FOR_AA;
+				} else {
+					put1(WR(qp), MSERESET);
+				}
+				break;
+
+			} else if (length != 3) {
 				break;
 			}
 
-			/*
-			 * On Dell latitude D800, we find that the MSE_ACK is
-			 * coming up even after timeout in VUID_OPEN during
-			 * early boot. So here (PS2_WAIT_RESET_ACK) we check
-			 * if timeout happened before, if true, we reset the
-			 * timeout to restart the initialization.
-			 */
-			if (STATEP->inited & PS2_FLAG_INIT_TIMEOUT) {
-				STATEP->inited &= ~PS2_FLAG_INIT_TIMEOUT;
-				STATEP->init_count = 0;
-				vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET);
-				break;
-			}
+			mp->b_rptr += 2;	/* Skip past the 0xAA 0x00 */
 
-			STATEP->state = PS2_WAIT_RESET_AA;
-			break;
-
-		case PS2_WAIT_RESET_AA:
-			if (code != MSE_AA) {
-				break;
-			}
-			STATEP->state = PS2_WAIT_RESET_00;
-			break;
-
-		case PS2_WAIT_RESET_00:
-			if (code != MSE_00) {
-				break;
-			}
-
-			/* Reset has been ok */
-			vuid_cancel_timeout(qp);
+			/* Reset completed successfully */
 
 			STATEP->state = PS2_WAIT_SETRES0_ACK1;
 
 			/* Set timeout for set res */
 			vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP);
 
+			/* Begin Logitech autodetect sequence */
 			put1(WR(qp), MSESETRES);
 			break;
 
@@ -673,30 +741,12 @@
 
 		case PS2_WAIT_STATUS_3:
 
-			/* Status request has been ok */
+			/* Status request completed successfully */
 			vuid_cancel_timeout(qp);
 
-			/* Set timeout for set res or sample rate */
-			vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP);
+			vuidmice_start_wdc_or_setres(qp);
+			break;
 
-			/*
-			 * Start the wheel-mouse detection code.  First, we look
-			 * for standard wheel mice.  If we set the sample rate
-			 * to 200, 100, and then 80 and finally request the
-			 * device ID, a wheel mouse will return an ID of 0x03.
-			 * After that, we'll try for the wheel+5 variety.  The
-			 * incantation in this case is 200, 200, and 80.  We'll
-			 * get 0x04 back in that case.
-			 */
-			if (STATEP->inited & PS2_FLAG_NO_EXTN) {
-				STATEP->state = PS2_WAIT_SETRES3_ACK1;
-				put1(WR(qp), MSESETRES);
-			} else {
-				STATEP->state = PS2_WAIT_WHEEL_SMPL1_CMD_ACK;
-				put1(WR(qp), MSECHGMOD);
-			}
-
-			break;
 		case PS2_WAIT_WHEEL_SMPL1_CMD_ACK:
 			if (code != MSE_ACK) {
 				break;
@@ -741,7 +791,7 @@
 				break;
 			}
 
-			/* Set sample rate has been ok */
+			/* Set sample rate completed successfully */
 			vuid_cancel_timeout(qp);
 
 			STATEP->state = PS2_WAIT_WHEEL_DEV_CMD;
@@ -761,7 +811,7 @@
 
 		case PS2_WAIT_WHEEL_DEV_ACK:
 
-			/* Get dev has been ok */
+			/* Get dev completed successfully */
 			vuid_cancel_timeout(qp);
 
 			if (code != 0x03) {
@@ -837,7 +887,7 @@
 				break;
 			}
 
-			/* Set sample rate has been ok */
+			/* Set sample rate completed successfully */
 			vuid_cancel_timeout(qp);
 
 			STATEP->state = PS2_WAIT_WHEEL5_DEV_CMD;
@@ -869,7 +919,7 @@
 				    MOUSE_MODE_WHEEL;
 			}
 
-			/* Wheel5 get dev has been ok */
+			/* Wheel5 get dev completed successfully */
 			vuid_cancel_timeout(qp);
 
 			/* FALLTHROUGH */
@@ -897,7 +947,7 @@
 				break;
 			}
 
-			/* Set res has been ok */
+			/* Set res completed successfully */
 			vuid_cancel_timeout(qp);
 
 			STATEP->state = PS2_WAIT_STREAM_ACK;
@@ -922,9 +972,17 @@
 				break;
 			}
 
-			/* Enable has been ok */
+			/* Enable completed successfully */
+
+			/*
+			 * The entire initialization sequence
+			 * is complete.  Now, we can clear the
+			 * init_count retry counter.
+			 */
+			STATEP->init_count = 0;
 			vuid_cancel_timeout(qp);
 
+
 			STATEP->state = PS2_START;
 			break;
 		}
--- a/usr/src/uts/common/nfs/nfs4.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/nfs/nfs4.h	Mon Jul 20 13:07:46 2009 -0400
@@ -546,6 +546,7 @@
  * finfo - reference to the open file for this state
  * share_access - how did the openowner OPEN the file (access)
  * share_deny - how did the openowner OPEN the file (deny)
+ * opened - has VOP_OPEN been done
  * closed - has this file been closed?
  * lostatelist - root of list of lo_state associated with this state/file
  * node - node for state struct list of states
@@ -557,6 +558,7 @@
 	struct rfs4_file	*rs_finfo;
 	uint32_t		rs_share_access;
 	uint32_t		rs_share_deny;
+	unsigned		rs_opened:1;
 	unsigned		rs_closed:1;
 	list_t			rs_lostatelist;
 	list_node_t		rs_node;
--- a/usr/src/uts/common/os/devcfg.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/os/devcfg.c	Mon Jul 20 13:07:46 2009 -0400
@@ -52,6 +52,7 @@
 #include <sys/reboot.h>
 #include <sys/sysmacros.h>
 #include <sys/systm.h>
+#include <sys/fs/sdev_impl.h>
 #include <sys/sunldi.h>
 #include <sys/sunldi_impl.h>
 
--- a/usr/src/uts/common/os/main.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/os/main.c	Mon Jul 20 13:07:46 2009 -0400
@@ -485,7 +485,6 @@
 	 * and swap have been set up.
 	 */
 	consconfig();
-	release_bootstrap();
 
 	/*
 	 * attach drivers with ddi-forceattach prop
@@ -544,6 +543,12 @@
 	start_other_cpus(0);
 
 	/*
+	 * Release bootstrap here since PROM interfaces are
+	 * used to start other CPUs above.
+	 */
+	release_bootstrap();
+
+	/*
 	 * Finish lgrp initialization after all CPUS are brought online.
 	 */
 	lgrp_main_mp_init();
--- a/usr/src/uts/common/os/mem_config.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/os/mem_config.c	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -72,20 +72,42 @@
 static int delspan_reserve(pfn_t, pgcnt_t);
 static void delspan_unreserve(pfn_t, pgcnt_t);
 
-static kmutex_t memseg_lists_lock;
-static struct memseg *memseg_va_avail;
+kmutex_t memseg_lists_lock;
+struct memseg *memseg_va_avail;
+struct memseg *memseg_alloc(void);
 static struct memseg *memseg_delete_junk;
 static struct memseg *memseg_edit_junk;
 void memseg_remap_init(void);
-static void memseg_remap_to_dummy(caddr_t, pgcnt_t);
+static void memseg_remap_to_dummy(struct memseg *);
 static void kphysm_addmem_error_undospan(pfn_t, pgcnt_t);
 static struct memseg *memseg_reuse(pgcnt_t);
 
 static struct kmem_cache *memseg_cache;
 
 /*
- * Add a chunk of memory to the system.  page_t's for this memory
- * are allocated in the first few pages of the chunk.
+ * Interfaces to manage externally allocated
+ * page_t memory (metadata) for a memseg.
+ */
+#pragma weak	memseg_alloc_meta
+#pragma weak	memseg_free_meta
+#pragma weak	memseg_get_metapfn
+#pragma weak	memseg_remap_meta
+
+extern int ppvm_enable;
+extern page_t *ppvm_base;
+extern int memseg_alloc_meta(pfn_t, pgcnt_t, void **, pgcnt_t *);
+extern void memseg_free_meta(void *, pgcnt_t);
+extern pfn_t memseg_get_metapfn(void *, pgcnt_t);
+extern void memseg_remap_meta(struct memseg *);
+static int memseg_is_dynamic(struct memseg *);
+static int memseg_includes_meta(struct memseg *);
+static pfn_t memseg_get_start(struct memseg *);
+static void memseg_cpu_vm_flush(void);
+
+int meta_alloc_enable;
+
+/*
+ * Add a chunk of memory to the system.
  * base: starting PAGESIZE page of new memory.
  * npgs: length in PAGESIZE pages.
  *
@@ -94,24 +116,35 @@
  * dynamically most likely means more hash misses, since the tables will
  * be smaller than they otherwise would be.
  */
+#ifdef	DEBUG
+static int memseg_debug;
+#define	MEMSEG_DEBUG(args...) if (memseg_debug) printf(args)
+#else
+#define	MEMSEG_DEBUG(...)
+#endif
+
 int
 kphysm_add_memory_dynamic(pfn_t base, pgcnt_t npgs)
 {
-	page_t		*pp;
-	page_t		*opp, *oepp;
+	page_t *pp;
+	page_t		*opp, *oepp, *segpp;
 	struct memseg	*seg;
 	uint64_t	avmem;
 	pfn_t		pfn;
 	pfn_t		pt_base = base;
 	pgcnt_t		tpgs = npgs;
-	pgcnt_t		metapgs;
+	pgcnt_t		metapgs = 0;
 	int		exhausted;
 	pfn_t		pnum;
 	int		mnode;
 	caddr_t		vaddr;
 	int		reuse;
 	int		mlret;
+	int		rv;
+	int		flags;
+	int		meta_alloc = 0;
 	void		*mapva;
+	void		*metabase = (void *)base;
 	pgcnt_t		nkpmpgs = 0;
 	offset_t	kpm_pages_off;
 
@@ -145,8 +178,7 @@
 		if (mlret == MEML_SPANOP_EALLOC) {
 			delspan_unreserve(pt_base, tpgs);
 			return (KPHYSM_ERESOURCE);
-		} else
-		if (mlret == MEML_SPANOP_ESPAN) {
+		} else if (mlret == MEML_SPANOP_ESPAN) {
 			delspan_unreserve(pt_base, tpgs);
 			return (KPHYSM_ESPAN);
 		} else {
@@ -155,6 +187,20 @@
 		}
 	}
 
+	if (meta_alloc_enable) {
+		/*
+		 * Allocate the page_t's from existing memory;
+		 * if that fails, allocate from the incoming memory.
+		 */
+		rv = memseg_alloc_meta(base, npgs, &metabase, &metapgs);
+		if (rv == KPHYSM_OK) {
+			ASSERT(metapgs);
+			ASSERT(btopr(npgs * sizeof (page_t)) <= metapgs);
+			meta_alloc = 1;
+			goto mapalloc;
+		}
+	}
+
 	/*
 	 * We store the page_t's for this new memory in the first
 	 * few pages of the chunk. Here, we go and get'em ...
@@ -220,13 +266,13 @@
 	 */
 	if (exhausted) {
 		kphysm_addmem_error_undospan(pt_base, tpgs);
-
 		/*
 		 * There is no specific error code for 'too small'.
 		 */
 		return (KPHYSM_ERESOURCE);
 	}
 
+mapalloc:
 	/*
 	 * We may re-use a previously allocated VA space for the page_ts
 	 * eventually, but we need to initialize and lock the pages first.
@@ -242,6 +288,8 @@
 		cmn_err(CE_WARN, "kphysm_add_memory_dynamic:"
 		    " Can't allocate VA for page_ts");
 
+		if (meta_alloc)
+			memseg_free_meta(metabase, metapgs);
 		kphysm_addmem_error_undospan(pt_base, tpgs);
 
 		return (KPHYSM_ERESOURCE);
@@ -258,6 +306,8 @@
 	pfn = pt_base;
 	vaddr = (caddr_t)pp;
 	for (pnum = 0; pnum < metapgs; pnum++) {
+		if (meta_alloc)
+			pfn = memseg_get_metapfn(metabase, (pgcnt_t)pnum);
 		hat_devload(kas.a_hat, vaddr, ptob(1), pfn,
 		    PROT_READ | PROT_WRITE,
 		    HAT_LOAD | HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST);
@@ -276,7 +326,8 @@
 		    HAT_UNLOAD_UNMAP|HAT_UNLOAD_UNLOCK);
 
 		vmem_free(heap_arena, mapva, ptob(metapgs));
-
+		if (meta_alloc)
+			memseg_free_meta(metabase, metapgs);
 		kphysm_addmem_error_undospan(pt_base, tpgs);
 
 		return (KPHYSM_EFAULT);
@@ -289,31 +340,26 @@
 	 * this may change with COD or in larger SSM systems with
 	 * nested latency groups, so we must not assume that the
 	 * node does not yet exist.
-	 *
-	 * Also, using pt_base (page table base address)
-	 * and tpgs (total number of pages) to mimic the case when a
-	 * memory board is already installed in a system at boot
-	 * time.  This will ensure the entire address range is
-	 * specified in order to have proper deletion.
 	 */
 	pnum = pt_base + tpgs - 1;
-	mem_node_add_slice(pt_base, pnum);
+	mem_node_add_range(pt_base, pnum);
 
 	/*
 	 * Allocate or resize page counters as necessary to accommodate
 	 * the increase in memory pages.
 	 */
 	mnode = PFN_2_MEM_NODE(pnum);
-	if (page_ctrs_adjust(mnode) != 0) {
-
-		mem_node_pre_del_slice(pt_base, pnum);
-		mem_node_post_del_slice(pt_base, pnum, 0);
+	PAGE_CTRS_ADJUST(base, npgs, rv);
+	if (rv) {
+
+		mem_node_del_range(pt_base, pnum);
 
 		hat_unload(kas.a_hat, (caddr_t)pp, ptob(metapgs),
 		    HAT_UNLOAD_UNMAP|HAT_UNLOAD_UNLOCK);
 
 		vmem_free(heap_arena, mapva, ptob(metapgs));
-
+		if (meta_alloc)
+			memseg_free_meta(metabase, metapgs);
 		kphysm_addmem_error_undospan(pt_base, tpgs);
 
 		return (KPHYSM_ERESOURCE);
@@ -333,9 +379,23 @@
 	memlist_write_unlock();
 
 	/* See if we can find a memseg to re-use. */
-	seg = memseg_reuse(metapgs);
-
-	reuse = (seg != NULL);
+	if (meta_alloc) {
+		seg = memseg_reuse(0);
+		reuse = 1;	/* force unmapping of temp mapva */
+		flags = MEMSEG_DYNAMIC | MEMSEG_META_ALLOC;
+		/*
+		 * There is a 1:1 fixed relationship between a pfn
+		 * and a page_t VA.  The pfn is used as an index into
+		 * the ppvm_base page_t table in order to calculate
+		 * the page_t base address for a given pfn range.
+		 */
+		segpp = ppvm_base + base;
+	} else {
+		seg = memseg_reuse(metapgs);
+		reuse = (seg != NULL);
+		flags = MEMSEG_DYNAMIC | MEMSEG_META_INCL;
+		segpp = pp;
+	}
 
 	/*
 	 * Initialize the memseg structure representing this memory
@@ -343,15 +403,31 @@
 	 * initialization and add the memory to the system.
 	 * In order to prevent lock deadlocks, the add_physmem()
 	 * code is repeated here, but split into several stages.
+	 *
+	 * If a memseg is reused, invalidate memseg pointers in
+	 * all cpu vm caches.  We need to do this this since the check
+	 * 	pp >= seg->pages && pp < seg->epages
+	 * used in various places is not atomic and so the first compare
+	 * can happen before reuse and the second compare after reuse.
+	 * The invalidation ensures that a memseg is not deferenced while
+	 * it's page/pfn pointers are changing.
 	 */
 	if (seg == NULL) {
-		seg = kmem_cache_alloc(memseg_cache, KM_SLEEP);
-		bzero(seg, sizeof (struct memseg));
-		seg->msegflags = MEMSEG_DYNAMIC;
-		seg->pages = pp;
+		seg = memseg_alloc();
+		ASSERT(seg != NULL);
+		seg->msegflags = flags;
+		MEMSEG_DEBUG("memseg_get: alloc seg=0x%p, pages=0x%p",
+		    (void *)seg, (void *)(seg->pages));
+		seg->pages = segpp;
 	} else {
-		/*EMPTY*/
-		ASSERT(seg->msegflags & MEMSEG_DYNAMIC);
+		ASSERT(seg->msegflags == flags);
+		ASSERT(seg->pages_base == seg->pages_end);
+		MEMSEG_DEBUG("memseg_get: reuse seg=0x%p, pages=0x%p",
+		    (void *)seg, (void *)(seg->pages));
+		if (meta_alloc) {
+			memseg_cpu_vm_flush();
+			seg->pages = segpp;
+		}
 	}
 
 	seg->epages = seg->pages + npgs;
@@ -382,6 +458,9 @@
 		pfn = pt_base;
 		vaddr = (caddr_t)seg->pages;
 		for (pnum = 0; pnum < metapgs; pnum++) {
+			if (meta_alloc)
+				pfn = memseg_get_metapfn(metabase,
+				    (pgcnt_t)pnum);
 			hat_devload(kas.a_hat, vaddr, ptob(1), pfn,
 			    PROT_READ | PROT_WRITE,
 			    HAT_LOAD_REMAP | HAT_LOAD | HAT_LOAD_NOCONSIST);
@@ -509,14 +588,16 @@
 }
 
 /*
- * Only return an available memseg of exactly the right size.
+ * Only return an available memseg of exactly the right size
+ * if size is required.
  * When the meta data area has it's own virtual address space
  * we will need to manage this more carefully and do best fit
  * allocations, possibly splitting an available area.
  */
-static struct memseg *
+struct memseg *
 memseg_reuse(pgcnt_t metapgs)
 {
+	int type;
 	struct memseg **segpp, *seg;
 
 	mutex_enter(&memseg_lists_lock);
@@ -525,12 +606,24 @@
 	for (; (seg = *segpp) != NULL; segpp = &seg->lnext) {
 		caddr_t end;
 
+		/*
+		 * Make sure we are reusing the right segment type.
+		 */
+		type = metapgs ? MEMSEG_META_INCL : MEMSEG_META_ALLOC;
+
+		if ((seg->msegflags & (MEMSEG_META_INCL | MEMSEG_META_ALLOC))
+		    != type)
+			continue;
+
 		if (kpm_enable)
 			end = hat_kpm_mseg_reuse(seg);
 		else
 			end = (caddr_t)seg->epages;
 
-		if (btopr(end - (caddr_t)seg->pages) == metapgs) {
+		/*
+		 * Check for the right size if it is provided.
+		 */
+		if (!metapgs || btopr(end - (caddr_t)seg->pages) == metapgs) {
 			*segpp = seg->lnext;
 			seg->lnext = NULL;
 			break;
@@ -968,25 +1061,11 @@
 
 /*
  * Return whether memseg was created by kphysm_add_memory_dynamic().
- * If this is the case and startp non zero, return also the start pfn
- * of the meta data via startp.
  */
 static int
-memseg_is_dynamic(struct memseg *seg, pfn_t *startp)
+memseg_is_dynamic(struct memseg *seg)
 {
-	pfn_t		pt_start;
-
-	if ((seg->msegflags & MEMSEG_DYNAMIC) == 0)
-		return (0);
-
-	/* Meta data is required to be at the beginning */
-	ASSERT(hat_getpfnum(kas.a_hat, (caddr_t)seg->epages) < seg->pages_base);
-
-	pt_start = hat_getpfnum(kas.a_hat, (caddr_t)seg->pages);
-	if (startp != NULL)
-		*startp = pt_start;
-
-	return (1);
+	return (seg->msegflags & MEMSEG_DYNAMIC);
 }
 
 int
@@ -1090,13 +1169,12 @@
 				/* Span and memseg don't overlap. */
 				continue;
 			}
+			mseg_start = memseg_get_start(seg);
 			/* Check that segment is suitable for delete. */
-			if (memseg_is_dynamic(seg, &mseg_start)) {
+			if (memseg_includes_meta(seg)) {
 				/*
-				 * Can only delete whole added segments
-				 * for the moment.
-				 * Check that this is completely within the
-				 * span.
+				 * Check that this segment is completely
+				 * within the span.
 				 */
 				if (mseg_start < mdsp->mds_base ||
 				    seg->pages_end > p_end) {
@@ -1106,10 +1184,6 @@
 				pages_checked += seg->pages_end - mseg_start;
 			} else {
 				/*
-				 * Set mseg_start for accounting below.
-				 */
-				mseg_start = seg->pages_base;
-				/*
 				 * If this segment is larger than the span,
 				 * try to split it. After the split, it
 				 * is necessary to restart.
@@ -1231,9 +1305,7 @@
 				}
 			}
 			if (seg != NULL) {
-				if (!memseg_is_dynamic(seg, &mseg_start)) {
-					mseg_start = seg->pages_base;
-				}
+				mseg_start = memseg_get_start(seg);
 				/*
 				 * Now have the full extent of the memseg so
 				 * do the range check.
@@ -1722,11 +1794,6 @@
 		    (mhp->mh_cancel == 0); mdsp = mdsp->mds_next) {
 			pfn_t pfn, p_end;
 
-			if (first_scan) {
-				mem_node_pre_del_slice(mdsp->mds_base,
-				    mdsp->mds_base + mdsp->mds_npgs - 1);
-			}
-
 			p_end = mdsp->mds_base + mdsp->mds_npgs;
 			for (pfn = mdsp->mds_base; (pfn < p_end) &&
 			    (mhp->mh_cancel == 0); pfn++) {
@@ -2309,13 +2376,13 @@
 	kphysm_del_cleanup(mhp);
 
 	/*
-	 * mem_node_post_del_slice needs to be after kphysm_del_cleanup so
+	 * mem_node_del_range needs to be after kphysm_del_cleanup so
 	 * that the mem_node_config[] will remain intact for the cleanup.
 	 */
 	for (mdsp = mhp->mh_transit.trl_spans; mdsp != NULL;
 	    mdsp = mdsp->mds_next) {
-		mem_node_post_del_slice(mdsp->mds_base,
-		    mdsp->mds_base + mdsp->mds_npgs - 1, 0);
+		mem_node_del_range(mdsp->mds_base,
+		    mdsp->mds_base + mdsp->mds_npgs - 1);
 	}
 
 	comp_code = KPHYSM_OK;
@@ -2477,29 +2544,68 @@
 	mutex_exit(&pp_dummy_lock);
 }
 
-static void
-memseg_remap_to_dummy(caddr_t pp, pgcnt_t metapgs)
+/*
+ * Remap a page-aglined range of page_t's to dummy pages.
+ */
+void
+remap_to_dummy(caddr_t va, pgcnt_t metapgs)
 {
-	ASSERT(pp_dummy != NULL);
+	int phase;
+
+	ASSERT(IS_P2ALIGNED((uint64_t)va, PAGESIZE));
+
+	/*
+	 * We may start remapping at a non-zero page offset
+	 * within the dummy pages since the low/high ends
+	 * of the outgoing pp's could be shared by other
+	 * memsegs (see memseg_remap_meta).
+	 */
+	phase = btop((uint64_t)va) % pp_dummy_npages;
+	ASSERT(PAGESIZE % sizeof (page_t) || phase == 0);
 
 	while (metapgs != 0) {
 		pgcnt_t n;
-		int i;
+		int i, j;
 
 		n = pp_dummy_npages;
 		if (n > metapgs)
 			n = metapgs;
 		for (i = 0; i < n; i++) {
-			hat_devload(kas.a_hat, pp, ptob(1), pp_dummy_pfn[i],
+			j = (i + phase) % pp_dummy_npages;
+			hat_devload(kas.a_hat, va, ptob(1), pp_dummy_pfn[j],
 			    PROT_READ,
 			    HAT_LOAD | HAT_LOAD_NOCONSIST |
 			    HAT_LOAD_REMAP);
-			pp += ptob(1);
+			va += ptob(1);
 		}
 		metapgs -= n;
 	}
 }
 
+static void
+memseg_remap_to_dummy(struct memseg *seg)
+{
+	caddr_t pp;
+	pgcnt_t metapgs;
+
+	ASSERT(memseg_is_dynamic(seg));
+	ASSERT(pp_dummy != NULL);
+
+
+	if (!memseg_includes_meta(seg)) {
+		memseg_remap_meta(seg);
+		return;
+	}
+
+	pp = (caddr_t)seg->pages;
+	metapgs = seg->pages_base - memseg_get_start(seg);
+	ASSERT(metapgs != 0);
+
+	seg->pages_end = seg->pages_base;
+
+	remap_to_dummy(pp, metapgs);
+}
+
 /*
  * Transition all the deleted pages to the deleted state so that
  * page_lock will not wait. The page_lock_delete call will
@@ -2588,9 +2694,6 @@
 		pfn_t mseg_start;
 		pfn_t mseg_base, mseg_end;
 		pgcnt_t mseg_npgs;
-		page_t *pp;
-		pgcnt_t metapgs;
-		int dynamic;
 		int mlret;
 
 		seglist = seg->lnext;
@@ -2609,17 +2712,11 @@
 		mseg_base = seg->pages_base;
 		mseg_end = seg->pages_end;
 		mseg_npgs = MSEG_NPAGES(seg);
-		dynamic = memseg_is_dynamic(seg, &mseg_start);
-
-		seg->pages_end = seg->pages_base;
-
-		if (dynamic) {
-			pp = seg->pages;
-			metapgs = mseg_base - mseg_start;
-			ASSERT(metapgs != 0);
-
+		mseg_start = memseg_get_start(seg);
+
+		if (memseg_is_dynamic(seg)) {
 			/* Remap the meta data to our special dummy area. */
-			memseg_remap_to_dummy((caddr_t)pp, metapgs);
+			memseg_remap_to_dummy(seg);
 
 			mutex_enter(&memseg_lists_lock);
 			seg->lnext = memseg_va_avail;
@@ -2627,16 +2724,13 @@
 			mutex_exit(&memseg_lists_lock);
 		} else {
 			/*
-			 * Set for clean-up below.
-			 */
-			mseg_start = seg->pages_base;
-			/*
 			 * For memory whose page_ts were allocated
 			 * at boot, we need to find a new use for
 			 * the page_t memory.
 			 * For the moment, just leak it.
 			 * (It is held in the memseg_delete_junk list.)
 			 */
+			seg->pages_end = seg->pages_base;
 
 			mutex_enter(&memseg_lists_lock);
 			seg->lnext = memseg_delete_junk;
@@ -3019,7 +3113,7 @@
 		memsegs_unlock(1);
 		return (0);
 	}
-	if (memseg_is_dynamic(seg, (pfn_t *)NULL)) {
+	if (memseg_includes_meta(seg)) {
 		memsegs_unlock(1);
 		return (0);
 	}
@@ -3053,18 +3147,13 @@
 	seg_low = NULL;
 	seg_high = NULL;
 
-	if (size_low != 0) {
-		seg_low = kmem_cache_alloc(memseg_cache, KM_SLEEP);
-		bzero(seg_low, sizeof (struct memseg));
-	}
-
-	seg_mid = kmem_cache_alloc(memseg_cache, KM_SLEEP);
-	bzero(seg_mid, sizeof (struct memseg));
-
-	if (size_high != 0) {
-		seg_high = kmem_cache_alloc(memseg_cache, KM_SLEEP);
-		bzero(seg_high, sizeof (struct memseg));
-	}
+	if (size_low != 0)
+		seg_low = memseg_alloc();
+
+	seg_mid = memseg_alloc();
+
+	if (size_high != 0)
+		seg_high = memseg_alloc();
 
 	/*
 	 * All allocation done now.
@@ -3075,6 +3164,7 @@
 		seg_low->pages_base = seg->pages_base;
 		seg_low->pages_end = seg_low->pages_base + size_low;
 		seg_low->next = seg_mid;
+		seg_low->msegflags = seg->msegflags;
 	}
 	if (size_high != 0) {
 		seg_high->pages = seg->epages - size_high;
@@ -3082,6 +3172,7 @@
 		seg_high->pages_base = seg->pages_end - size_high;
 		seg_high->pages_end = seg_high->pages_base + size_high;
 		seg_high->next = seg->next;
+		seg_high->msegflags = seg->msegflags;
 	}
 
 	seg_mid->pages = seg->pages + size_low;
@@ -3089,6 +3180,7 @@
 	seg_mid->epages = seg->epages - size_high;
 	seg_mid->pages_end = seg->pages_end - size_high;
 	seg_mid->next = (seg_high != NULL) ? seg_high : seg->next;
+	seg_mid->msegflags = seg->msegflags;
 
 	/*
 	 * Update hat_kpm specific info of all involved memsegs and
@@ -3147,3 +3239,64 @@
 	memseg_cache = kmem_cache_create("memseg_cache", sizeof (struct memseg),
 	    0, NULL, NULL, NULL, NULL, static_arena, KMC_NOHASH);
 }
+
+struct memseg *
+memseg_alloc()
+{
+	struct memseg *seg;
+
+	seg = kmem_cache_alloc(memseg_cache, KM_SLEEP);
+	bzero(seg, sizeof (struct memseg));
+
+	return (seg);
+}
+
+/*
+ * Return whether the page_t memory for this memseg
+ * is included in the memseg itself.
+ */
+static int
+memseg_includes_meta(struct memseg *seg)
+{
+	return (seg->msegflags & MEMSEG_META_INCL);
+}
+
+pfn_t
+memseg_get_start(struct memseg *seg)
+{
+	pfn_t		pt_start;
+
+	if (memseg_includes_meta(seg)) {
+		pt_start = hat_getpfnum(kas.a_hat, (caddr_t)seg->pages);
+
+		/* Meta data is required to be at the beginning */
+		ASSERT(pt_start < seg->pages_base);
+	} else
+		pt_start = seg->pages_base;
+
+	return (pt_start);
+}
+
+/*
+ * Invalidate memseg pointers in cpu private vm data caches.
+ */
+static void
+memseg_cpu_vm_flush()
+{
+	cpu_t *cp;
+	vm_cpu_data_t *vc;
+
+	mutex_enter(&cpu_lock);
+	pause_cpus(NULL);
+
+	cp = cpu_list;
+	do {
+		vc = cp->cpu_vm_data;
+		vc->vc_pnum_memseg = NULL;
+		vc->vc_pnext_memseg = NULL;
+
+	} while ((cp = cp->cpu_next) != cpu_list);
+
+	start_cpus();
+	mutex_exit(&cpu_lock);
+}
--- a/usr/src/uts/common/os/modconf.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/os/modconf.c	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -56,7 +56,6 @@
 #include <sys/brand.h>
 #include <sys/cpc_pcbe.h>
 #include <sys/kstat.h>
-#include <sys/fs/sdev_node.h>
 #include <sys/socketvar.h>
 #include <sys/kiconv.h>
 
@@ -229,17 +228,6 @@
 };
 
 /*
- * /dev fs modules
- */
-static int mod_infodev(struct modldev *, struct modlinkage *, int *);
-static int mod_installdev(struct modldev *, struct modlinkage *);
-static int mod_removedev(struct modldev *, struct modlinkage *);
-
-struct mod_ops mod_devfsops = {
-	mod_installdev, mod_removedev, mod_infodev
-};
-
-/*
  * PCBE (Performance Counter BackEnd) modules.
  */
 static int mod_installpcbe(struct modlpcbe *, struct modlinkage *);
@@ -545,42 +533,6 @@
 }
 
 /*
- * manage /dev fs modules
- */
-/*ARGSUSED*/
-static int
-mod_infodev(struct modldev *modl, struct modlinkage *modlp, int *p0)
-{
-	if (mod_getctl(modlp) == NULL) {
-		*p0 = -1;
-		return (0);	/* module is not yet installed */
-	}
-
-	*p0 = 0;
-	return (0);
-}
-
-static int
-mod_installdev(struct modldev *modl, struct modlinkage *modlp)
-{
-	struct modctl	*mcp;
-
-	if ((mcp = mod_getctl(modlp)) == NULL)
-		return (EINVAL);
-	return (sdev_module_register(mcp->mod_modname, modl->dev_ops));
-}
-
-/*
- * /dev modules are not unloadable.
- */
-/*ARGSUSED*/
-static int
-mod_removedev(struct modldev *modl, struct modlinkage *modlp)
-{
-	return (EBUSY);
-}
-
-/*
  * Install a new driver
  */
 static int
--- a/usr/src/uts/common/os/modctl.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/os/modctl.c	Mon Jul 20 13:07:46 2009 -0400
@@ -76,7 +76,7 @@
 #include <ipp/ipp_impl.h>
 #include <sys/fs/dv_node.h>
 #include <sys/strsubr.h>
-#include <sys/fs/sdev_node.h>
+#include <sys/fs/sdev_impl.h>
 
 static int		mod_circdep(struct modctl *);
 static int		modinfo(modid_t, struct modinfo *);
@@ -2247,11 +2247,7 @@
 
 	switch (subcmd) {
 	case MODDEVNAME_LOOKUPDOOR:
-	case MODDEVNAME_DEVFSADMNODE:
-		error = devname_filename_register(subcmd, (char *)a1);
-		break;
-	case MODDEVNAME_NSMAPS:
-		error = devname_nsmaps_register((char *)a1, (size_t)a2);
+		error = devname_filename_register((char *)a1);
 		break;
 	case MODDEVNAME_PROFILE:
 		error = devname_profile_update((char *)a1, (size_t)a2);
--- a/usr/src/uts/common/os/sunpm.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/os/sunpm.c	Mon Jul 20 13:07:46 2009 -0400
@@ -6604,6 +6604,7 @@
 	char *ptr;
 	int lower_bound_cycles, upper_bound_cycles, cycles_allowed;
 	int cycles_diff, cycles_over;
+	struct pm_smart_count *smart_p;
 
 	if (datap == NULL) {
 		PMD(PMD_TCHECK, ("%s: NULL data pointer!\n", pmf))
@@ -6785,6 +6786,18 @@
 		PMD(PMD_TCHECK, ("%s: no cycle is allowed in %ld secs\n", pmf,
 		    *intervalp))
 		return (0);
+	} else if (datap->format == DC_SMART_FORMAT) {
+		/*
+		 * power cycles of SATA disks are reported from SMART
+		 * attributes.
+		 */
+		smart_p = &datap->un.smart_count;
+		if (smart_p->consumed >= smart_p->allowed) {
+			*intervalp = (LONG_MAX / hz);
+			PMD(PMD_TCHECK, ("%s: exceeded lifemax cycles.\n", pmf))
+			return (0);
+		} else
+			return (1);
 	}
 
 	PMD(PMD_TCHECK, ("%s: unknown format!\n", pmf))
--- a/usr/src/uts/common/rpc/xdr.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/rpc/xdr.c	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -307,6 +307,29 @@
 }
 
 /*
+ * XDR an unsigned char
+ */
+bool_t
+xdr_u_char(XDR *xdrs, uchar_t *cp)
+{
+	int i;
+
+	switch (xdrs->x_op) {
+	case XDR_ENCODE:
+		i = (*cp);
+		return (XDR_PUTINT32(xdrs, &i));
+	case XDR_DECODE:
+		if (!XDR_GETINT32(xdrs, &i))
+			return (FALSE);
+		*cp = (uchar_t)i;
+		return (TRUE);
+	case XDR_FREE:
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+/*
  * XDR booleans
  *
  * PSARC 2003/523 Contract Private Interface
@@ -608,6 +631,32 @@
 }
 
 /*
+ * xdr_vector():
+ *
+ * XDR a fixed length array. Unlike variable-length arrays, the storage
+ * of fixed length arrays is static and unfreeable.
+ * > basep: base of the array
+ * > size: size of the array
+ * > elemsize: size of each element
+ * > xdr_elem: routine to XDR each element
+ */
+bool_t
+xdr_vector(XDR *xdrs, char *basep, const uint_t nelem,
+	const uint_t elemsize, const xdrproc_t xdr_elem)
+{
+	uint_t i;
+	char *elptr;
+
+	elptr = basep;
+	for (i = 0; i < nelem; i++) {
+		if (!(*xdr_elem)(xdrs, elptr, LASTUNSIGNED))
+			return (FALSE);
+		elptr += elemsize;
+	}
+	return (TRUE);
+}
+
+/*
  * Wrapper for xdr_string that can be called directly from
  * routines like clnt_call
  */
--- a/usr/src/uts/common/rpc/xdr.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/rpc/xdr.h	Mon Jul 20 13:07:46 2009 -0400
@@ -18,7 +18,7 @@
  *
  * CDDL HEADER END
  *
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
@@ -420,6 +420,8 @@
 extern bool_t	xdr_string(XDR *, char **, const uint_t);
 extern bool_t	xdr_union(XDR *, enum_t *, char *,
 		    const struct xdr_discrim *, const xdrproc_t);
+extern bool_t	xdr_vector(XDR *, char *, const uint_t, const uint_t,
+    const xdrproc_t);
 extern unsigned int  xdr_sizeof(xdrproc_t, void *);
 
 extern bool_t   xdr_hyper(XDR *, longlong_t *);
@@ -428,6 +430,7 @@
 extern bool_t   xdr_u_longlong_t(XDR *, u_longlong_t *);
 
 extern bool_t	xdr_char(XDR *, char *);
+extern bool_t	xdr_u_char(XDR *, uchar_t *);
 extern bool_t	xdr_wrapstring(XDR *, char **);
 extern bool_t	xdr_reference(XDR *, caddr_t *, uint_t, const xdrproc_t);
 extern bool_t	xdr_pointer(XDR *, char **, uint_t, const xdrproc_t);
@@ -446,9 +449,6 @@
 #endif
 
 #ifndef _KERNEL
-extern bool_t	xdr_u_char(XDR *, uchar_t *);
-extern bool_t	xdr_vector(XDR *, char *, const uint_t, const uint_t, const
-xdrproc_t);
 extern bool_t	xdr_float(XDR *, float *);
 extern bool_t	xdr_double(XDR *, double *);
 extern bool_t	xdr_quadruple(XDR *, long double *);
@@ -468,12 +468,14 @@
 extern bool_t	xdr_opaque();
 extern bool_t	xdr_string();
 extern bool_t	xdr_union();
+extern bool_t	xdr_vector();
 
 extern bool_t   xdr_hyper();
 extern bool_t   xdr_longlong_t();
 extern bool_t   xdr_u_hyper();
 extern bool_t   xdr_u_longlong_t();
 extern bool_t	xdr_char();
+extern bool_t	xdr_u_char();
 extern bool_t	xdr_reference();
 extern bool_t	xdr_pointer();
 extern void	xdr_free();
@@ -492,8 +494,6 @@
 #endif
 
 #ifndef _KERNEL
-extern bool_t	xdr_u_char();
-extern bool_t	xdr_vector();
 extern bool_t	xdr_float();
 extern bool_t	xdr_double();
 extern bool_t   xdr_quadruple();
--- a/usr/src/uts/common/rpcsvc/idmap_prot.x	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/rpcsvc/idmap_prot.x	Mon Jul 20 13:07:46 2009 -0400
@@ -19,13 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-
 /* opaque type to support non-ASCII strings */
 typedef	string	idmap_utf8str<>;
+typedef	idmap_utf8str	idmap_utf8str_list<>;
 
 /* Return status */
 typedef int idmap_retcode;
@@ -270,6 +270,76 @@
 };
 #endif
 
+/*
+ * Represents an error from the directory lookup service.
+ *
+ * code is an ASCII string that is a key for the error.  It is not
+ * localized.
+ *
+ * fmt is a format string with %n markers for where to include
+ * params[n-1].  It should be, but NEEDSWORK is not localized to
+ * the caller's locale.
+ *
+ * params is a list of parameters for the error - e.g. the name that
+ * encountered a failure, the server that reported the failure, et cetera.
+ * The values are to be used both as marked in fmt and for machine
+ * interpretation of the error.
+ */
+struct directory_error_rpc {
+	idmap_utf8str	code;
+	idmap_utf8str	fmt;
+	idmap_utf8str	params<>;
+};
+
+/*
+ * One value of a multivalued attribute.
+ */
+typedef opaque			directory_value_rpc<>;
+
+/*
+ * The value of an attribute, if found.  Note that this is a list
+ * of directory_value_rpc objects, to support multivalued attributes.
+ */
+union directory_values_rpc switch (bool found) {
+	case TRUE:
+		directory_value_rpc values<>;
+	case FALSE:
+		void;
+};
+
+/*
+ * The status of the lookup for any particular identifier.
+ */
+enum directory_lookup_status_rpc {
+	DIRECTORY_NOT_FOUND = 0,
+	DIRECTORY_FOUND = 1,
+	DIRECTORY_ERROR = 2
+};
+
+/*
+ * This is the data returned for a particular identifier, either a
+ * list of attribute values or an error.
+ */
+union directory_entry_rpc switch (directory_lookup_status_rpc status) {
+	case DIRECTORY_NOT_FOUND:
+		void;
+	case DIRECTORY_FOUND:
+		directory_values_rpc attrs<>;
+	case DIRECTORY_ERROR:
+		directory_error_rpc err;
+};
+
+/*
+ * This is the result from a request, either a list of the entries for
+ * the identifiers specified, or an error.
+ */
+union directory_results_rpc switch (bool failed) {
+	case TRUE:
+		directory_error_rpc	err;
+	case FALSE:
+		directory_entry_rpc	entries<>;
+};
+
 program IDMAP_PROG {
 	version IDMAP_V1 {
 		void
@@ -302,6 +372,27 @@
 		idmap_prop_res
 		IDMAP_GET_PROP(idmap_prop_type) = 6;
 #endif
+		/*
+		 * Retrieve directory information about a list of users
+		 * or groups by name or SID.
+		 *
+		 * ids is a list of user names, group names, or SIDs.
+		 *
+		 * types is a list of types of the ids in the id list.
+		 * If the type list is shorter than the id list, the last
+		 * type listed applies to all of the ids from that point.
+		 * The defined types are:
+		 *     'n' - name (could be user or group)
+		 *     'u' - user
+		 *     'g' - group
+		 *     's' - SID
+		 *
+		 * attrs is a list of attribute names to retrieve.
+		 */
+		directory_results_rpc DIRECTORY_GET_COMMON(
+			idmap_utf8str_list ids,
+			idmap_utf8str types,
+			idmap_utf8str_list attrs) = 7;
 
 	} = 1;
 } = 100172;
--- a/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl	Mon Jul 20 13:07:46 2009 -0400
@@ -403,6 +403,7 @@
   SWITCH(switch_value)
 	union mslm_NetConnectInfoResUnion ru;
 };
+typedef struct mslm_NetConnectInfo srvsvc_NetConnectInfo_t;
 
 OPERATION(SRVSVC_OPNUM_NetConnectEnum)
 struct mslm_NetConnectEnum {
@@ -993,22 +994,19 @@
  * 
  * servername
  * [in] Pointer to a string that specifies the DNS or NetBIOS name
- * of the remote server on which the function is to execute. If this
- * parameter is NULL, the local computer is used.
- * Windows NT 4.0 and earlier: This string must begin with \\.
+ * of the server.  Servers should not validate this parameter.
+ * This parameter may be NULL and on Windows NT 4.0 and earlier it
+ * should begin with \\.
  *
  * UncClientName
- * [in] Pointer to a string that specifies the computer name of the
- * client to disconnect. If UncClientName is NULL, then all the sessions
- * of the user identified by the username parameter will be deleted on
- * the server specified by servername. For more information, see
- * NetSessionEnum.
+ * [in] Pointer to a string that specifies the name of the client
+ * to disconnect. If UncClientName is NULL, all sessions associated
+ * with the specified user will be disconnected.
  *
  * username
  * [in] Pointer to a string that specifies the name of the user whose
- * session is to be terminated. If this parameter is NULL, all users'
- * sessions from the client specified by the UncClientName parameter
- * are to be terminated.
+ * session is to be terminated. If username is NULL, all sessions
+ * from the specified client will be disconnected.
  *
  * Remarks
  * Windows 95/98/Me: You must specify the session key in the sReserved
@@ -1041,8 +1039,11 @@
  */
 
 /* for svX_platform */
-#define SV_PLATFORM_ID_OS2 400
-#define SV_PLATFORM_ID_NT  500
+#define	SV_PLATFORM_ID_DOS		300
+#define	SV_PLATFORM_ID_OS2		400
+#define	SV_PLATFORM_ID_NT		500
+#define	SV_PLATFORM_ID_OSF		600
+#define	SV_PLATFORM_ID_VMS		700
 
 /* Bit-mapped values for svX_type fields */
 #define SV_TYPE_WORKSTATION         0x00000001
--- a/usr/src/uts/common/smbsrv/smb_ioctl.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/smbsrv/smb_ioctl.h	Mon Jul 20 13:07:46 2009 -0400
@@ -47,8 +47,10 @@
 #define	SMB_IOC_GMTOFF		_IOW(SMB_IOC_BASE, 7, int)
 #define	SMB_IOC_SHARE		_IOW(SMB_IOC_BASE, 8, int)
 #define	SMB_IOC_UNSHARE		_IOW(SMB_IOC_BASE, 9, int)
-#define	SMB_IOC_USER_NUMBER	_IOW(SMB_IOC_BASE, 10, int)
-#define	SMB_IOC_USER_LIST	_IOW(SMB_IOC_BASE, 11, int)
+#define	SMB_IOC_NUMOPEN		_IOW(SMB_IOC_BASE, 10, int)
+#define	SMB_IOC_SVCENUM		_IOW(SMB_IOC_BASE, 11, int)
+#define	SMB_IOC_FILE_CLOSE	_IOW(SMB_IOC_BASE, 12, int)
+#define	SMB_IOC_SESSION_CLOSE	_IOW(SMB_IOC_BASE, 13, int)
 
 typedef struct smb_ioc_header {
 	uint32_t	version;
@@ -80,18 +82,55 @@
 	int		udoor;
 } smb_ioc_start_t;
 
-typedef	struct smb_ioc_usernum {
+typedef	struct smb_ioc_opennum {
 	smb_ioc_header_t hdr;
-	uint32_t	num;
-} smb_ioc_usernum_t;
+	uint32_t	open_users;
+	uint32_t	open_trees;
+	uint32_t	open_files;
+	uint32_t	qualtype;
+	char		qualifier[MAXNAMELEN];
+} smb_ioc_opennum_t;
+
+/*
+ * For enumeration, user and session are synonymous, as are
+ * connection and tree.
+ */
+#define	SMB_SVCENUM_TYPE_USER	0x55534552	/* 'USER' */
+#define	SMB_SVCENUM_TYPE_TREE	0x54524545	/* 'TREE' */
+#define	SMB_SVCENUM_TYPE_FILE	0x46494C45	/* 'FILE' */
+#define	SMB_SVCENUM_TYPE_SHARE	0x53484152	/* 'SHAR' */
 
-typedef	struct smb_ioc_ulist {
+typedef struct smb_svcenum {
+	uint32_t	se_type;	/* object type to enumerate */
+	uint32_t	se_level;	/* level of detail being requested */
+	uint32_t	se_prefmaxlen;	/* client max size buffer preference */
+	uint32_t	se_resume;	/* client resume handle */
+	uint32_t	se_bavail;	/* remaining buffer space in bytes */
+	uint32_t	se_bused;	/* consumed buffer space in bytes */
+	uint32_t	se_ntotal;	/* total number of objects */
+	uint32_t	se_nlimit;	/* max number of objects to return */
+	uint32_t	se_nitems;	/* number of objects in buf */
+	uint32_t	se_nskip;	/* number of objects to skip */
+	uint32_t	se_status;	/* enumeration status */
+	uint32_t	se_buflen;	/* length of the buffer in bytes */
+	uint8_t		se_buf[1];	/* buffer to hold enumeration data */
+} smb_svcenum_t;
+
+typedef	struct smb_ioc_svcenum {
 	smb_ioc_header_t hdr;
-	uint32_t	cookie;
-	uint32_t	num;
-	uint32_t	data_len;
-	uint8_t		data[1];
-} smb_ioc_ulist_t;
+	smb_svcenum_t	svcenum;
+} smb_ioc_svcenum_t;
+
+typedef struct smb_ioc_session {
+	smb_ioc_header_t hdr;
+	char		client[MAXNAMELEN];
+	char		username[MAXNAMELEN];
+} smb_ioc_session_t;
+
+typedef	struct smb_ioc_fileid {
+	smb_ioc_header_t hdr;
+	uint32_t	uniqid;
+} smb_ioc_fileid_t;
 
 typedef struct smb_ioc_cfg {
 	smb_ioc_header_t hdr;
@@ -117,8 +156,10 @@
 	smb_ioc_cfg_t		ioc_cfg;
 	smb_ioc_start_t		ioc_start;
 	smb_ioc_listen_t	ioc_listen;
-	smb_ioc_usernum_t	ioc_unum;
-	smb_ioc_ulist_t		ioc_ulist;
+	smb_ioc_opennum_t	ioc_opennum;
+	smb_ioc_svcenum_t	ioc_svcenum;
+	smb_ioc_session_t	ioc_session;
+	smb_ioc_fileid_t	ioc_fileid;
 	smb_ioc_share_t		ioc_share;
 } smb_ioc_t;
 
--- a/usr/src/uts/common/smbsrv/smb_kproto.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h	Mon Jul 20 13:07:46 2009 -0400
@@ -198,6 +198,7 @@
 	((op)->create_disposition != FILE_SUPERSEDE) &&		\
 	((op)->create_disposition != FILE_OVERWRITE))		\
 
+uint32_t smb_lock_get_lock_count(smb_node_t *);
 uint32_t smb_unlock_range(smb_request_t *, smb_node_t *,
     uint64_t, uint64_t);
 uint32_t smb_lock_range(smb_request_t *, uint64_t, uint64_t, uint32_t,
@@ -313,8 +314,6 @@
 void smb_opipe_door_fini(void);
 int smb_opipe_door_open(int);
 void smb_opipe_door_close(void);
-void smb_user_context_init(smb_user_t *, smb_opipe_context_t *);
-void smb_user_context_fini(smb_opipe_context_t *);
 
 /*
  * SMB server functions (file smb_server.c)
@@ -329,13 +328,14 @@
 int smb_server_tcp_listen(smb_ioc_listen_t *);
 int smb_server_nbt_receive(void);
 int smb_server_tcp_receive(void);
-uint32_t smb_server_get_user_count(void);
 uint32_t smb_server_get_session_count(void);
 int smb_server_share_export(smb_ioc_share_t *);
 int smb_server_share_unexport(smb_ioc_share_t *);
 int smb_server_set_gmtoff(smb_ioc_gmt_t *);
-int smb_server_user_number(smb_ioc_usernum_t *);
-int smb_server_user_list(smb_ioc_ulist_t *);
+int smb_server_numopen(smb_ioc_opennum_t *);
+int smb_server_enum(smb_ioc_svcenum_t *);
+int smb_server_session_close(smb_ioc_session_t *);
+int smb_server_file_close(smb_ioc_fileid_t *);
 
 void smb_server_reconnection_check(smb_server_t *, smb_session_t *);
 void smb_server_get_cfg(smb_server_t *, smb_kmod_cfg_t *);
@@ -474,6 +474,8 @@
 void smb_session_list_terminate(smb_session_list_t *, smb_session_t *);
 void smb_session_list_signal(smb_session_list_t *);
 smb_user_t *smb_session_dup_user(smb_session_t *, char *, char *);
+void smb_session_getclient(smb_session_t *, char *, size_t);
+boolean_t smb_session_isclient(smb_session_t *, const char *);
 void smb_session_correct_keep_alive_values(smb_session_list_t *, uint32_t);
 void smb_session_oplock_break(smb_session_t *, smb_ofile_t *);
 int smb_session_send(smb_session_t *, uint8_t type, mbuf_chain_t *);
@@ -489,16 +491,20 @@
  * ofile functions (file smb_ofile.c)
  */
 smb_ofile_t *smb_ofile_lookup_by_fid(smb_tree_t *, uint16_t);
+smb_ofile_t *smb_ofile_lookup_by_uniqid(smb_tree_t *, uint32_t);
+boolean_t smb_ofile_disallow_fclose(smb_ofile_t *);
 smb_ofile_t *smb_ofile_open(smb_tree_t *, smb_node_t *, uint16_t,
     open_param_t *, uint16_t, uint32_t, smb_error_t *);
 void smb_ofile_close(smb_ofile_t *, uint32_t);
 uint32_t smb_ofile_access(smb_ofile_t *, cred_t *, uint32_t);
 int smb_ofile_seek(smb_ofile_t *, ushort_t, int32_t, uint32_t *);
+boolean_t smb_ofile_hold(smb_ofile_t *);
 void smb_ofile_release(smb_ofile_t *);
 void smb_ofile_close_all(smb_tree_t *);
 void smb_ofile_close_all_by_pid(smb_tree_t *, uint16_t);
 void smb_ofile_set_flags(smb_ofile_t *, uint32_t);
 boolean_t smb_ofile_is_open(smb_ofile_t *);
+int smb_ofile_enum(smb_ofile_t *, smb_svcenum_t *);
 uint32_t smb_ofile_open_check(smb_ofile_t *, cred_t *, uint32_t, uint32_t);
 uint32_t smb_ofile_rename_check(smb_ofile_t *);
 uint32_t smb_ofile_delete_check(smb_ofile_t *);
@@ -554,12 +560,19 @@
 smb_tree_t *smb_user_lookup_share(smb_user_t *, const char *, smb_tree_t *);
 smb_tree_t *smb_user_lookup_volume(smb_user_t *, const char *, smb_tree_t *);
 boolean_t smb_user_is_admin(smb_user_t *);
+boolean_t smb_user_namecmp(smb_user_t *, const char *);
+int smb_user_enum(smb_user_t *, smb_svcenum_t *);
 void smb_user_close_pid(smb_user_t *, uint16_t);
 void smb_user_disconnect_trees(smb_user_t *user);
 void smb_user_disconnect_share(smb_user_t *, const char *);
+int smb_user_fclose(smb_user_t *, uint32_t);
+boolean_t smb_user_hold(smb_user_t *);
 void smb_user_release(smb_user_t *);
 cred_t *smb_user_getcred(smb_user_t *);
 cred_t *smb_user_getprivcred(smb_user_t *);
+void smb_user_netinfo_init(smb_user_t *, smb_netuserinfo_t *);
+void smb_user_netinfo_fini(smb_netuserinfo_t *);
+int smb_user_netinfo_encode(smb_user_t *, uint8_t *, size_t, uint32_t *);
 
 /*
  * SMB tree functions (file smb_tree.c)
@@ -568,6 +581,8 @@
 void smb_tree_disconnect(smb_tree_t *, boolean_t);
 void smb_tree_close_pid(smb_tree_t *, uint16_t);
 boolean_t smb_tree_has_feature(smb_tree_t *, uint_t);
+int smb_tree_enum(smb_tree_t *, smb_svcenum_t *);
+int smb_tree_fclose(smb_tree_t *, uint32_t);
 boolean_t smb_tree_hold(smb_tree_t *);
 void smb_tree_release(smb_tree_t *);
 smb_odir_t *smb_tree_lookup_odir(smb_tree_t *, uint16_t);
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h	Mon Jul 20 13:07:46 2009 -0400
@@ -507,10 +507,9 @@
 	volatile int		flags;	/* FILE_NOTIFY_CHANGE_* */
 	volatile int		waiting_event; /* # of clients requesting FCN */
 	smb_times_t		n_timestamps; /* cached timestamps */
-	unsigned int		what;
 	smb_oplock_t		n_oplock;
-	struct smb_node		*dir_snode; /* Directory of node */
-	struct smb_node		*unnamed_stream_node; /* set in stream nodes */
+	struct smb_node		*n_dnode; /* directory node */
+	struct smb_node		*n_unode; /* unnamed stream node */
 	/* Credentials for delayed delete */
 	cred_t			*delete_on_close_cred;
 	uint32_t		n_delete_on_close_flags;
@@ -873,6 +872,8 @@
 	acl_type_t		t_acltype;
 	uint32_t		t_access;
 	uint32_t		t_shr_flags;
+	time_t			t_connect_time;
+	volatile uint32_t	t_open_files;
 } smb_tree_t;
 
 #define	SMB_TREE_VFS(tree)	((tree)->t_snode->vp->v_vfsp)
@@ -942,7 +943,7 @@
 	char *p_name;
 	uint32_t p_busy;
 	smb_opipe_hdr_t p_hdr;
-	smb_opipe_context_t p_context;
+	smb_netuserinfo_t p_user;
 	uint8_t *p_doorbuf;
 	uint8_t *p_data;
 } smb_opipe_t;
@@ -1656,7 +1657,7 @@
 	char name[MAXNAMELEN];
 } smb_trans2_setinfo_t;
 
-#define	SMB_IS_STREAM(node) ((node)->unnamed_stream_node)
+#define	SMB_IS_STREAM(node) ((node)->n_unode)
 
 typedef struct smb_tsd {
 	void (*proc)();
--- a/usr/src/uts/common/smbsrv/smb_xdr.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/smbsrv/smb_xdr.h	Mon Jul 20 13:07:46 2009 -0400
@@ -33,6 +33,7 @@
 #include <rpc/xdr.h>
 #include <sys/param.h>
 #include <smbsrv/smbinfo.h>
+#include <smbsrv/smb_ioctl.h>
 
 typedef struct smb_dr_kshare {
 	int32_t k_op;
@@ -46,10 +47,6 @@
 #define	xdr_int16_t	xdr_short
 #define	xdr_uint16_t	xdr_u_short
 
-extern bool_t xdr_u_char(XDR *xdrs, uchar_t *cp);
-extern bool_t xdr_vector(XDR *xdrs, char *basep, uint_t nelem,
-    uint_t elemsize, xdrproc_t xdr_elem);
-
 smb_dr_kshare_t *smb_share_mkabsolute(uint8_t *buf, uint32_t len);
 #else
 uint8_t *smb_kshare_mkselfrel(smb_dr_kshare_t *kshare, uint32_t *len);
@@ -91,25 +88,68 @@
 	uint32_t oh_status;
 } smb_opipe_hdr_t;
 
-typedef struct smb_opipe_context {
-	uint64_t oc_session_id;
-	uint16_t oc_uid;
-	uint16_t oc_domain_len;
-	char *oc_domain;
-	uint16_t oc_account_len;
-	char *oc_account;
-	uint16_t oc_workstation_len;
-	char *oc_workstation;
-	smb_inaddr_t oc_ipaddr;
-	int32_t oc_native_os;
-	int64_t oc_logon_time;
-	uint32_t oc_flags;
-} smb_opipe_context_t;
+typedef struct smb_netuserinfo {
+	uint64_t	ui_session_id;
+	uint16_t	ui_uid;
+	uint16_t	ui_domain_len;
+	char		*ui_domain;
+	uint16_t	ui_account_len;
+	char		*ui_account;
+	uint16_t	ui_workstation_len;
+	char		*ui_workstation;
+	smb_inaddr_t	ui_ipaddr;
+	int32_t		ui_native_os;
+	int64_t		ui_logon_time;
+	uint32_t	ui_numopens;
+	uint32_t	ui_flags;
+} smb_netuserinfo_t;
+
+typedef struct smb_opennum {
+	uint32_t	open_users;
+	uint32_t	open_trees;
+	uint32_t	open_files;
+	uint32_t	qualtype;
+	char		qualifier[MAXNAMELEN];
+} smb_opennum_t;
 
-typedef struct smb_ulist {
-	uint32_t ul_cnt;
-	smb_opipe_context_t *ul_users;
-} smb_ulist_t;
+typedef struct smb_netconnectinfo {
+	uint32_t	ci_id;
+	uint32_t	ci_type;
+	uint32_t	ci_numopens;
+	uint32_t	ci_numusers;
+	uint32_t	ci_time;
+	uint32_t	ci_namelen;
+	uint32_t	ci_sharelen;
+	char		*ci_username;
+	char		*ci_share;
+} smb_netconnectinfo_t;
+
+typedef struct smb_netfileinfo {
+	uint16_t	fi_fid;
+	uint32_t	fi_uniqid;
+	uint32_t	fi_permissions;
+	uint32_t	fi_numlocks;
+	uint32_t	fi_pathlen;
+	uint32_t	fi_namelen;
+	char		*fi_path;
+	char		*fi_username;
+} smb_netfileinfo_t;
+
+typedef struct smb_netsvcitem {
+	list_node_t	nsi_lnd;
+	union {
+		smb_netuserinfo_t	nsi_user;
+		smb_netconnectinfo_t	nsi_tree;
+		smb_netfileinfo_t	nsi_ofile;
+	} nsi_un;
+} smb_netsvcitem_t;
+
+typedef struct smb_netsvc {
+	list_t			ns_list;
+	smb_netsvcitem_t	*ns_items;
+	smb_ioc_svcenum_t	*ns_ioc;
+	uint32_t		ns_ioclen;
+} smb_netsvc_t;
 
 /* xdr routines for common door arguments/results */
 extern bool_t xdr_smb_dr_string_t(XDR *, smb_dr_string_t *);
@@ -120,11 +160,18 @@
 int smb_opipe_hdr_encode(smb_opipe_hdr_t *, uint8_t *, uint32_t);
 int smb_opipe_hdr_decode(smb_opipe_hdr_t *, uint8_t *, uint32_t);
 bool_t smb_opipe_hdr_xdr(XDR *xdrs, smb_opipe_hdr_t *objp);
-int smb_opipe_context_encode(smb_opipe_context_t *, uint8_t *, uint32_t,
+int smb_netuserinfo_encode(smb_netuserinfo_t *, uint8_t *, uint32_t, uint_t *);
+int smb_netuserinfo_decode(smb_netuserinfo_t *, uint8_t *, uint32_t, uint_t *);
+bool_t smb_netuserinfo_xdr(XDR *, smb_netuserinfo_t *);
+int smb_netconnectinfo_encode(smb_netconnectinfo_t *, uint8_t *, uint32_t,
     uint_t *);
-int smb_opipe_context_decode(smb_opipe_context_t *, uint8_t *, uint32_t,
+int smb_netconnectinfo_decode(smb_netconnectinfo_t *, uint8_t *, uint32_t,
     uint_t *);
-bool_t smb_opipe_context_xdr(XDR *, smb_opipe_context_t *);
+bool_t smb_netconnectinfo_xdr(XDR *, smb_netconnectinfo_t *);
+int smb_netfileinfo_encode(smb_netfileinfo_t *, uint8_t *, uint32_t, uint_t *);
+int smb_netfileinfo_decode(smb_netfileinfo_t *, uint8_t *, uint32_t, uint_t *);
+bool_t smb_netfileinfo_xdr(XDR *, smb_netfileinfo_t *);
+
 /*
  * VSS Door Structures
  */
--- a/usr/src/uts/common/sys/Makefile	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -807,7 +807,6 @@
 	decomp.h		\
 	dv_node.h		\
 	sdev_impl.h		\
-	sdev_node.h		\
 	fifonode.h		\
 	hsfs_isospec.h		\
 	hsfs_node.h		\
--- a/usr/src/uts/common/sys/fct.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/fct.h	Mon Jul 20 13:07:46 2009 -0400
@@ -158,6 +158,9 @@
 #define	FCHBA_DRIVER_NAME_LEN		256
 #define	FCHBA_SYMB_NAME_LEN		255
 
+#define	FC_TGT_PORT_INFO_CMD		(((uint32_t)'I') << 24)
+#define	FC_TGT_PORT_RLS			FC_TGT_PORT_INFO_CMD + 0x1
+
 typedef struct fct_port_attrs {
 	char		manufacturer[FCHBA_MANUFACTURER_LEN];
 	char		serial_number[FCHBA_SERIAL_NUMBER_LEN];
@@ -174,6 +177,15 @@
 	uint32_t	max_frame_size;
 } fct_port_attrs_t;
 
+typedef struct fct_port_link_status {
+	uint32_t	LinkFailureCount;
+	uint32_t	LossOfSyncCount;
+	uint32_t	LossOfSignalsCount;
+	uint32_t	PrimitiveSeqProtocolErrorCount;
+	uint32_t	InvalidTransmissionWordCount;
+	uint32_t	InvalidCRCCount;
+} fct_port_link_status_t;
+
 typedef struct fct_dbuf_store {
 	void			*fds_fct_private;
 	void			*fds_fca_private;
@@ -232,6 +244,9 @@
 			struct fct_flogi_xchg *fx);
 	void			(*port_populate_hba_details)(
 		struct fct_local_port *port, struct fct_port_attrs *port_attrs);
+	fct_status_t		(*port_info)(uint32_t cmd,
+		struct fct_local_port *port, void *arg, uint8_t *buf,
+		uint32_t *bufsizep);
 } fct_local_port_t;
 
 /*
@@ -277,6 +292,15 @@
 	uint8_t			port_rpwwn[8];
 } fct_link_info_t;
 
+typedef struct fct_port_stat {
+	kstat_named_t	link_failure_cnt;
+	kstat_named_t	loss_of_sync_cnt;
+	kstat_named_t	loss_of_signals_cnt;
+	kstat_named_t	prim_seq_protocol_err_cnt;
+	kstat_named_t	invalid_tx_word_cnt;
+	kstat_named_t	invalid_crc_cnt;
+} fct_port_stat_t;
+
 /*
  * port topology
  */
--- a/usr/src/uts/common/sys/fct_defines.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/fct_defines.h	Mon Jul 20 13:07:46 2009 -0400
@@ -71,6 +71,7 @@
 #define	ELS_OP_FLOGI		0x04
 #define	ELS_OP_LOGO		0x05
 #define	ELS_OP_ABTX		0x06
+#define	ELS_OP_RLS		0x0f
 #define	ELS_OP_ECHO		0x10
 #define	ELS_OP_REC		0x13
 #define	ELS_OP_SRR		0x14
--- a/usr/src/uts/common/sys/fctio.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/fctio.h	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #ifndef	_FCTIO_H
@@ -38,6 +38,7 @@
 #define	FCTIO_GET_DISCOVERED_PORT_ATTRIBUTES	(FCTIO_SUB_CMD + 0x04)
 #define	FCTIO_GET_PORT_ATTRIBUTES		(FCTIO_SUB_CMD + 0x05)
 #define	FCTIO_GET_ADAPTER_PORT_STATS		(FCTIO_SUB_CMD + 0x06)
+#define	FCTIO_GET_LINK_STATUS			(FCTIO_SUB_CMD + 0x07)
 
 /*
  * fcio_xfer definitions
--- a/usr/src/uts/common/sys/fm/io/ddi.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/fm/io/ddi.h	Mon Jul 20 13:07:46 2009 -0400
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_SYS_FM_IO_DDI_H
 #define	_SYS_FM_IO_DDI_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -45,6 +43,8 @@
 #define	DDI_FM_DEVICE_BADINT_LIMIT	"badint_limit"
 #define	DDI_FM_DEVICE_INTERN_CORR	"intern_corr"
 #define	DDI_FM_DEVICE_INTERN_UNCORR	"intern_uncorr"
+#define	DDI_FM_DEVICE_FW_CORRUPT	"fw_corrupt"
+#define	DDI_FM_DEVICE_FW_MISMATCH	"fw_mismatch"
 
 /* service impact ereport definitions */
 #define	DDI_FM_SERVICE_IMPACT		"service"
--- a/usr/src/uts/common/sys/fs/dv_node.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/fs/dv_node.h	Mon Jul 20 13:07:46 2009 -0400
@@ -40,7 +40,7 @@
 #include <sys/sunddi.h>
 #include <sys/devops.h>
 #include <sys/ddi_impldefs.h>
-#include <sys/fs/sdev_node.h>
+#include <sys/fs/sdev_impl.h>
 #include <sys/devpolicy.h>
 #include <sys/avl.h>
 #include <sys/vfs_opreg.h>
--- a/usr/src/uts/common/sys/fs/sdev_impl.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/fs/sdev_impl.h	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -69,17 +69,6 @@
  * supported devfsadm_cmd
  */
 #define	DEVFSADMD_RUN_ALL	1
-#define	DEVFSADMD_NS_LOOKUP	2
-#define	DEVFSADMD_NS_READDIR	3
-
-/*
- * supported protocols
- */
-typedef enum devname_spec {
-	DEVNAME_NS_NONE = 0,
-	DEVNAME_NS_PATH,	/* physical /devices path */
-	DEVNAME_NS_DEV		/* /dev path */
-} devname_spec_t;
 
 /*
  * devfsadm_error codes
@@ -87,35 +76,16 @@
 #define	DEVFSADM_RUN_INVALID		1
 #define	DEVFSADM_RUN_EPERM		2
 #define	DEVFSADM_RUN_NOTSUP		3
-#define	DEVFSADM_NS_FAILED		4
-
-typedef struct sdev_ns_handle {
-	char	ns_name[MAXPATHLEN];	/* device to be looked up */
-	char	ns_map[MAXPATHLEN];
-} sdev_ns_handle_t;
-
-typedef struct sdev_lkp_handle {
-	devname_spec_t	devfsadm_spec;	/* returned path property */
-	char	devfsadm_link[MAXPATHLEN]; /* symlink destination */
-} sdev_lkp_handle_t;
-
-typedef struct sdev_rdr_handle {
-	uint32_t ns_mapcount;	/* number of entries in the map */
-	uint32_t maplist_size;
-} sdev_rdr_handle_t;
 
 /*
  * devfsadm/devname door data structures
  */
 typedef struct sdev_door_arg {
 	uint8_t devfsadm_cmd;	/* what to do for devfsadm[d] */
-	sdev_ns_handle_t ns_hdl;
 } sdev_door_arg_t;
 
 typedef struct sdev_door_res {
 	int32_t devfsadm_error;
-	sdev_lkp_handle_t ns_lkp_hdl;
-	sdev_rdr_handle_t ns_rdr_hdl;
 } sdev_door_res_t;
 
 #ifdef _KERNEL
@@ -134,7 +104,6 @@
  */
 struct devname_handle {
 	struct sdev_node *dh_data;	/* the sdev_node */
-	devname_spec_t dh_spec;
 	void    *dh_args;
 };
 typedef struct devname_handle devname_handle_t;
@@ -145,7 +114,6 @@
  */
 typedef struct sdev_global_data {
 	struct devname_handle sdev_ghandle;
-	struct devname_nsmap *sdev_gmapinfo;	/* VDIR name service info */
 	ulong_t		sdev_dir_ggen;		/* name space generation # */
 } sdev_global_data_t;
 
@@ -200,7 +168,6 @@
 #define	sdev_gdata sdev_instance_data.sdev_globaldata
 
 #define	sdev_handle		sdev_gdata.sdev_ghandle
-#define	sdev_mapinfo		sdev_gdata.sdev_gmapinfo
 #define	sdev_gdir_gen		sdev_gdata.sdev_dir_ggen
 
 #define	sdev_ldir_gen		sdev_ldata.sdev_dir_lgen
@@ -353,7 +320,7 @@
 /*
  * devname_inactive_func()
  */
-extern void devname_inactive_func(struct vnode *, struct cred *,
+extern void devname_inactive_func(struct vnode *, struct cred *cred,
     void (*)(struct vnode *));
 
 /*
@@ -418,7 +385,7 @@
 }
 
 extern int sdev_wait4lookup(struct sdev_node *, int);
-extern int devname_filename_register(int, char *);
+extern int devname_filename_register(char *);
 extern int devname_nsmaps_register(char *, size_t);
 extern void sdev_devfsadm_lockinit(void);
 extern void sdev_devfsadm_lockdestroy(void);
@@ -432,13 +399,6 @@
 extern struct vnodeops *devvt_getvnodeops(void);
 
 /*
- * Directory Based Device Naming (DBNR) defines
- */
-
-#define	ETC_DEV_DIR		"/etc/dev"
-#define	DEVNAME_NSCONFIG	"sdev_nsconfig_mod"
-
-/*
  * directory name rule
  */
 struct devname_nsmap {
@@ -447,7 +407,6 @@
 	char	*dir_name;	/* /dev subdir name, e.g. /dev/disk */
 	char	*dir_module;	/* devname module impl the operations */
 	char	*dir_map;	/* dev naming rules, e.g. /etc/dev/disks */
-	struct devname_ops *dir_ops;	/* directory specific vnode ops */
 	char    *dir_newmodule; /* to be reloaded  */
 	char    *dir_newmap;    /* to be reloaded */
 	int	dir_invalid;    /* map entry obsolete */
@@ -466,15 +425,6 @@
 } devname_lkp_arg_t;
 
 /*
- * name-value-property restured
- */
-typedef struct devname_lkp_result {
-	devname_spec_t	devname_spec;	/* link to /devices or /dev */
-	char	*devname_link;		/* the source path */
-	int	reserved;
-} devname_lkp_result_t;
-
-/*
  * directory name-value populating results
  */
 typedef struct devname_rdr_result {
@@ -559,25 +509,6 @@
  * name service globals and prototypes
  */
 
-extern struct devname_ops *devname_ns_ops;
-extern int devname_nsmaps_loaded;
-extern kmutex_t devname_nsmaps_lock;
-
-extern void sdev_invalidate_nsmaps(void);
-extern void sdev_validate_nsmaps(void);
-extern int sdev_module_register(char *, struct devname_ops *);
-extern struct devname_nsmap *sdev_get_nsmap_by_dir(char *, int);
-extern struct devname_nsmap *sdev_get_nsmap_by_module(char *);
-extern void sdev_dispatch_to_nsrdr_thread(struct sdev_node *, char *,
-    devname_rdr_result_t *);
-extern void sdev_insert_nsmap(char *, char *, char *);
-extern int devname_nsmap_lookup(devname_lkp_arg_t *, devname_lkp_result_t **);
-extern struct devname_nsmap *sdev_get_map(struct sdev_node *, int);
-extern int sdev_nsmaps_loaded(void);
-extern void sdev_replace_nsmap(struct devname_nsmap *, char *, char *);
-extern int sdev_nsmaps_reloaded(void);
-extern int devname_get_dir_nsmap(devname_handle_t *, struct devname_nsmap **);
-
 /*
  * vnodeops and vfsops helpers
  */
@@ -632,13 +563,6 @@
 extern void *sdev_get_vtor(struct sdev_node *dv);
 
 /*
- * devinfo helpers
- */
-extern int sdev_modctl_readdir(const char *, char ***, int *, int *, int);
-extern void sdev_modctl_readdir_free(char **, int, int);
-extern int sdev_modctl_devexists(const char *);
-
-/*
  * ncache handlers
  */
 
@@ -651,6 +575,13 @@
 extern void sdev_modctl_dump_files(void);
 
 /*
+ * devinfo helpers
+ */
+extern int sdev_modctl_readdir(const char *, char ***, int *, int *, int);
+extern void sdev_modctl_readdir_free(char **, int, int);
+extern int sdev_modctl_devexists(const char *);
+
+/*
  * globals
  */
 extern kmutex_t sdev_lock;
--- a/usr/src/uts/common/sys/fs/sdev_node.h	Tue Jul 14 11:18:27 2009 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +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 2006 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _SYS_SDEV_NODE_H
-#define	_SYS_SDEV_NODE_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-
-#include <sys/fs/sdev_impl.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef _KERNEL
-
-#define	DEVNOPS_REV	1
-
-/*
- * directory vnode ops implemented in a loadable module
- */
-struct devname_ops {
-	int	devnops_rev;	/* module build version */
-	int	(*devnops_lookup)(char *, devname_handle_t *, struct cred *);
-	int	(*devnops_remove)(devname_handle_t *);
-	int	(*devnops_rename)(devname_handle_t *, char *);
-	int 	(*devnops_getattr)(devname_handle_t *, struct vattr *,
-		    struct cred *);
-	int	(*devnops_readdir)(devname_handle_t *, struct cred *);
-	void	(*devnops_inactive)(devname_handle_t *, struct cred *);
-};
-
-/*
- * supported protocols
- */
-#define	DEVNAME_NS_PATH	1
-#define	DEVNAME_NS_DEV	2
-
-/*
- * default devname_ops for a /dev directory
- * that has a device name binding rule map
- */
-extern void devname_set_nodetype(devname_handle_t *, void *, int);
-extern void devname_get_vnode(devname_handle_t *, vnode_t **);
-extern int devname_get_path(devname_handle_t *, char **);
-extern int devname_get_name(devname_handle_t *, char **);
-extern int devname_get_dir_handle(devname_handle_t *, devname_handle_t **);
-extern void devname_get_dir_vnode(devname_handle_t *, vnode_t **);
-extern int devname_get_dir_path(devname_handle_t *, char **);
-extern int devname_get_dir_name(devname_handle_t *, char **);
-
-#endif	/* _KERNEL */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif	/* _SYS_SDEV_NODE_H */
--- a/usr/src/uts/common/sys/fs/zfs.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/fs/zfs.h	Mon Jul 20 13:07:46 2009 -0400
@@ -18,6 +18,7 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
@@ -280,14 +281,15 @@
 #define	SPA_VERSION_14			14ULL
 #define	SPA_VERSION_15			15ULL
 #define	SPA_VERSION_16			16ULL
+#define	SPA_VERSION_17			17ULL
 /*
  * When bumping up SPA_VERSION, make sure GRUB ZFS understands the on-disk
  * format change. Go to usr/src/grub/grub-0.97/stage2/{zfs-include/, fsys_zfs*},
  * and do the appropriate changes.  Also bump the version number in
  * usr/src/grub/capability.
  */
-#define	SPA_VERSION			SPA_VERSION_16
-#define	SPA_VERSION_STRING		"16"
+#define	SPA_VERSION			SPA_VERSION_17
+#define	SPA_VERSION_STRING		"17"
 
 /*
  * Symbolic names for the changes that caused a SPA_VERSION switch.
@@ -303,7 +305,7 @@
 #define	SPA_VERSION_INITIAL		SPA_VERSION_1
 #define	SPA_VERSION_DITTO_BLOCKS	SPA_VERSION_2
 #define	SPA_VERSION_SPARES		SPA_VERSION_3
-#define	SPA_VERSION_RAID6		SPA_VERSION_3
+#define	SPA_VERSION_RAIDZ2		SPA_VERSION_3
 #define	SPA_VERSION_BPLIST_ACCOUNT	SPA_VERSION_3
 #define	SPA_VERSION_RAIDZ_DEFLATE	SPA_VERSION_3
 #define	SPA_VERSION_DNODE_BYTES		SPA_VERSION_3
@@ -325,6 +327,7 @@
 #define	SPA_VERSION_PASSTHROUGH_X	SPA_VERSION_14
 #define	SPA_VERSION_USERSPACE		SPA_VERSION_15
 #define	SPA_VERSION_STMF_PROP		SPA_VERSION_16
+#define	SPA_VERSION_RAIDZ3		SPA_VERSION_17
 
 /*
  * ZPL version - rev'd whenever an incompatible on-disk format change
--- a/usr/src/uts/common/sys/i8042.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/i8042.h	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -56,21 +56,18 @@
 #define	I8042_INT_INPUT_AVAIL		0x00
 #define	I8042_INT_INPUT_DATA		0x01
 #define	I8042_INT_OUTPUT_DATA		0x03
-#define	I8042_INT_CMD_PLUS_PARAM	0x05	/* See comment below */
+#define	I8042_LOCK			0x05	/* See comment below */
 #define	I8042_POLL_INPUT_AVAIL		0x10
 #define	I8042_POLL_INPUT_DATA		0x11
 #define	I8042_POLL_OUTPUT_DATA		0x13
-#define	I8042_POLL_CMD_PLUS_PARAM	0x15	/* See comment below */
+#define	I8042_UNLOCK			0x15	/* See comment below */
 
 /*
- * The I8042_INT_CMD_PLUS_PARAM and I8042_POLL_CMD_PLUS_PARAM virtual
- * registers are meant to be used with i8042_rep_put8() [via
- * ddi_rep_put8 in child drivers], which is designed to allow commands
- * that have responses (or that have responses plus an option byte) to
- * execute atomically with respect to commands from other children
- * (some 8042 implementations get confused when other child devices
- * intersperse their own commands while a command to a different
- * 8042-connected device is in flight).
+ * The I8042_LOCK and I8042_UNLOCK virtual
+ * registers are meant to be used by child drivers that require exclusive
+ * access to the 8042 registers for an atomic transaction (e.g. keyboard
+ * enable, mouse reset) that consists of multiple single-byte commands
+ * and (possibly) their arguments.
  */
 
 /* Softint priority used */
--- a/usr/src/uts/common/sys/ib/adapters/hermon/hermon.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/ib/adapters/hermon/hermon.h	Mon Jul 20 13:07:46 2009 -0400
@@ -722,6 +722,7 @@
 	ddi_acc_handle_t	hs_fm_uarhdl;	/* fm-protected UAR hdl */
 	ddi_device_acc_attr_t	hs_fm_accattr;	/* fm-protected acc attr */
 	ddi_periodic_t		hs_fm_poll_thread; /* fma poll thread */
+	int32_t			hs_fm_degraded_reason;	/* degradation cause */
 #ifdef FMA_TEST
 	mod_hash_t		*hs_fm_test_hash; /* testset */
 	mod_hash_t		*hs_fm_id_hash;	/* testid */
--- a/usr/src/uts/common/sys/ib/adapters/hermon/hermon_fm.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/ib/adapters/hermon/hermon_fm.h	Mon Jul 20 13:07:46 2009 -0400
@@ -202,6 +202,11 @@
 #define	HCA_PIO_PERSISTENT	(2)	/* persistent error */
 #define	HCA_PIO_RETRY_CNT	(3)
 
+/* HCA firmware faults */
+#define	HCA_FW_MISC		0x1	/* firmware misc faults */
+#define	HCA_FW_CORRUPT		0x2	/* firmware corruption */
+#define	HCA_FW_MISMATCH		0x3	/* firmware version mismatch */
+
 /*
  * Hermon FM macros
  */
--- a/usr/src/uts/common/sys/ib/ibnex/ibnex_devctl.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/ib/ibnex/ibnex_devctl.h	Mon Jul 20 13:07:46 2009 -0400
@@ -184,8 +184,17 @@
  *
  * Caller sets hca_guid field of this structure.
  *
+ * Caller allocates memory for hca device path. Sets hca_device_path to point
+ * to the allocated memory and hca_device_path_alloc_sz to the number of bytes
+ * allocated.
+ *
  * Upon successful return from the IOCTL, hca_info will contain HCA attributes
- * for the specified GUID.
+ * for the specified GUID. hca_info.hca_device_path_len will contain the actual
+ * string length of the hca device path plus the terminating null character.
+ * hca_info.hca_device_path will point to null terminated hca device path
+ * string if the caller allocated memory for the hca device path is large
+ * enough to hold the hca device path and the terminating null character.
+ * Otherwise hca_info.hca_device_path will be set to NULL.
  *
  *
  * IBNEX_CTL_QUERY_HCA_PORT
@@ -281,6 +290,14 @@
 	char		hca_driver_name[MAX_HCA_DRVNAME_LEN];
 	int		hca_driver_instance;
 
+	/*
+	 * hca device path and the length.
+	 * hca_device_path_len is string length of the actual hca device path
+	 * plus the terminating null character.
+	 */
+	char		*hca_device_path;
+	uint_t		hca_device_path_len;
+
 	ibt_hca_flags_t		hca_flags;	/* HCA capabilities etc */
 	ibt_hca_flags2_t	hca_flags2;	/* HCA capabilities etc */
 
@@ -359,14 +376,130 @@
 	int32_t		hca_pad;
 } ibnex_ctl_hca_info_t;
 
+typedef struct ibnex_ctl_hca_info_32_s {
+	ib_guid_t	hca_node_guid;		/* Node GUID */
+	ib_guid_t	hca_si_guid;		/* Optional System Image GUID */
+	uint_t		hca_nports;		/* Number of physical ports */
+
+	/* HCA driver name and instance number */
+	char		hca_driver_name[MAX_HCA_DRVNAME_LEN];
+	int		hca_driver_instance;
+
+	/*
+	 * hca device path and the length.
+	 * hca_device_path_len is string length of the actual hca device path
+	 * plus the terminating null character.
+	 */
+	caddr32_t	hca_device_path;
+	uint_t		hca_device_path_len;
+
+	ibt_hca_flags_t		hca_flags;	/* HCA capabilities etc */
+	ibt_hca_flags2_t	hca_flags2;	/* HCA capabilities etc */
+
+	uint32_t	hca_vendor_id;		/* Vendor ID */
+	uint16_t	hca_device_id;		/* Device ID */
+	uint32_t	hca_version_id;		/* Version ID */
+
+	uint_t		hca_max_chans;		/* Max channels supported */
+	uint_t		hca_max_chan_sz;	/* Max outstanding WRs on any */
+						/* channel */
+
+	uint_t		hca_max_sgl;		/* Max SGL entries per WR */
+
+	uint_t		hca_max_cq;		/* Max num of CQs supported  */
+	uint_t		hca_max_cq_sz;		/* Max capacity of each CQ */
+
+	ibt_page_sizes_t	hca_page_sz;	/* Bit mask of page sizes */
+
+	uint_t		hca_max_memr;		/* Max num of HCA mem regions */
+	ib_memlen_t	hca_max_memr_len;	/* Largest block, in bytes of */
+						/* mem that can be registered */
+	uint_t		hca_max_mem_win;	/* Max Memory windows in HCA */
+
+	uint_t		hca_max_rsc; 		/* Max Responder Resources of */
+						/* this HCA for RDMAR/Atomics */
+						/* with this HCA as target. */
+	uint8_t		hca_max_rdma_in_chan;	/* Max RDMAR/Atomics in per */
+						/* chan this HCA as target. */
+	uint8_t		hca_max_rdma_out_chan;	/* Max RDMA Reads/Atomics out */
+						/* per channel by this HCA */
+	uint_t		hca_max_ipv6_chan;	/* Max IPV6 channels in HCA */
+	uint_t		hca_max_ether_chan;	/* Max Ether channels in HCA */
+
+	uint_t		hca_max_mcg_chans;	/* Max number of channels */
+						/* that can join multicast */
+						/* groups */
+	uint_t		hca_max_mcg;		/* Max multicast groups */
+	uint_t		hca_max_chan_per_mcg;	/* Max number of channels per */
+						/* Multicast group in HCA */
+	uint16_t	hca_max_partitions;	/* Max partitions in HCA */
+
+	ib_time_t	hca_local_ack_delay;
+
+	uint_t		hca_max_port_sgid_tbl_sz;
+	uint16_t	hca_max_port_pkey_tbl_sz;
+	uint_t		hca_max_pd;		/* Max# of Protection Domains */
+
+	uint_t		hca_max_ud_dest;
+	uint_t		hca_max_srqs;		/* Max SRQs supported */
+	uint_t		hca_max_srqs_sz;	/* Max outstanding WRs on any */
+						/* SRQ */
+	uint_t		hca_max_srq_sgl;	/* Max SGL entries per SRQ WR */
+	uint_t		hca_max_cq_handlers;
+	ibt_lkey_t	hca_reserved_lkey;	/* Reserved L_Key value */
+	uint_t		hca_max_fmrs;		/* Max FMR Supported */
+
+	uint_t		hca_max_lso_size;
+	uint_t		hca_max_lso_hdr_size;
+	uint_t		hca_max_inline_size;
+
+	uint_t		hca_max_cq_mod_count;	/* CQ notify moderation */
+	uint_t		hca_max_cq_mod_usec;
+
+	uint32_t	hca_fw_major_version;	/* firmware version */
+	uint16_t	hca_fw_minor_version;
+	uint16_t	hca_fw_micro_version;
+
+	/* detailed WQE size info */
+	uint_t		hca_ud_send_inline_sz;	/* inline size in bytes */
+	uint_t		hca_conn_send_inline_sz;
+	uint_t		hca_conn_rdmaw_inline_overhead;
+	uint_t		hca_recv_sgl_sz;	/* detailed SGL sizes */
+	uint_t		hca_ud_send_sgl_sz;
+	uint_t		hca_conn_send_sgl_sz;
+	uint_t		hca_conn_rdma_sgl_overhead;
+	int32_t		hca_pad;
+} ibnex_ctl_hca_info_32_t;
+
 /*
  * Data structure for IBNEX_CTL_QUERY_HCA
  */
 typedef struct ibnex_ctl_query_hca_s {
-	ib_guid_t		hca_guid;	/* in: HCA GUID */
+	ib_guid_t	hca_guid;	/* in: HCA GUID */
+
+	/*
+	 * in: user allocated memory pointer for hca device path and number of
+	 * bytes allocated for the hca device path.
+	 */
+	char		*hca_device_path;
+	uint_t		hca_device_path_alloc_sz;
+
 	ibnex_ctl_hca_info_t	hca_info;	/* out: HCA information */
 } ibnex_ctl_query_hca_t;
 
+typedef struct ibnex_ctl_query_hca_32_s {
+	ib_guid_t	hca_guid;	/* in: HCA GUID */
+
+	/*
+	 * in: user allocated memory pointer for hca device path and number of
+	 * bytes allocated for the hca device path.
+	 */
+	caddr32_t	hca_device_path;
+	uint_t		hca_device_path_alloc_sz;
+
+	ibnex_ctl_hca_info_32_t	hca_info;	/* out: HCA information */
+} ibnex_ctl_query_hca_32_t;
+
 /*
  * HCA port information structure
  */
--- a/usr/src/uts/common/sys/ib/ibtl/impl/ibtl_ibnex.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/ib/ibtl/impl/ibtl_ibnex.h	Mon Jul 20 13:07:46 2009 -0400
@@ -238,6 +238,8 @@
  *	driver_name	- caller allocated buffer which will contain
  *			  HCA driver name upon success
  *	driver_instance - HCA driver instance
+ *	hca_device_path	- caller allocated buffer of size MAXPATHLEN which
+ *			  will contain hca device path upon success.
  * Returns:
  *	IBT_SUCCESS/IBT_FAILURE
  * Description:
@@ -245,7 +247,8 @@
  *	specified HCA.
  */
 ibt_status_t
-ibtl_ibnex_query_hca_byguid(ib_guid_t, ibt_hca_attr_t *, char *, size_t, int *);
+ibtl_ibnex_query_hca_byguid(ib_guid_t, ibt_hca_attr_t *, char *, size_t, int *,
+    char *);
 
 #ifdef __cplusplus
 }
--- a/usr/src/uts/common/sys/ib/mgt/ibdm/ibdm_ibnex.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/ib/mgt/ibdm/ibdm_ibnex.h	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -52,7 +52,9 @@
 typedef enum ibdm_events_e {
 	IBDM_EVENT_HCA_ADDED,
 	IBDM_EVENT_HCA_REMOVED,
-	IBDM_EVENT_IOC_PROP_UPDATE
+	IBDM_EVENT_IOC_PROP_UPDATE,
+	IBDM_EVENT_PORT_UP,
+	IBDM_EVENT_PORT_PKEY_CHANGE
 } ibdm_events_t;
 
 /*
--- a/usr/src/uts/common/sys/lvm/meta_basic.x	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/lvm/meta_basic.x	Mon Jul 20 13:07:46 2009 -0400
@@ -20,7 +20,7 @@
 % */
 %
 %/*
-% * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+% * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 % * Use is subject to license terms.
 % */
 %
@@ -177,42 +177,6 @@
 %		return (FALSE);
 %	return (TRUE);
 %}
-%
-#ifdef	_KERNEL
-%
-%#define	LASTUNSIGNED	((u_int)0-1)
-%
-%/*
-% * xdr_vector():
-% *
-% * XDR a fixed length array. Unlike variable-length arrays,
-% * the storage of fixed length arrays is static and unfreeable.
-% * > basep: base of the array
-% * > size: size of the array
-% * > elemsize: size of each element
-% * > xdr_elem: routine to XDR each element
-% */
-%bool_t
-%xdr_vector(xdrs, basep, nelem, elemsize, xdr_elem)
-%	XDR *xdrs;
-%	char *basep;
-%	u_int nelem;
-%	u_int elemsize;
-%	xdrproc_t xdr_elem;
-%{
-%	u_int i;
-%	char *elptr;
-%
-%	elptr = basep;
-%	for (i = 0; i < nelem; i++) {
-%		if (! (*xdr_elem)(xdrs, elptr, LASTUNSIGNED)) {
-%			return (FALSE);
-%		}
-%		elptr += elemsize;
-%	}
-%	return (TRUE);
-%}
-#endif /* _KERNEL */
 #endif	/* RPC_XDR */
 
 #ifdef RPC_HDR
@@ -351,11 +315,6 @@
 %extern	bool_t	xdr_minor_t(XDR *xdrs, minor_t *objp);
 %extern	bool_t	xdr_timeval(XDR *xdrs, struct timeval *objp);
 %extern	bool_t	xdr_clnt_stat(XDR *xdrs, enum clnt_stat *objp);
-#ifdef _KERNEL
-%extern bool_t	xdr_vector(XDR *xdrs, char *basep,
-%			u_int nelem, u_int elemsize,
-%			xdrproc_t xdr_elem);
-#endif	/* _KERNEL */
 %#else /* K&R C */
 #ifndef _KERNEL
 %extern	bool_t	xdr_uint_t();
@@ -374,9 +333,5 @@
 %extern	bool_t	xdr_minor_t();
 %extern	bool_t	xdr_timeval();
 %extern	bool_t	xdr_clnt_stat();
-%
-#ifdef _KERNEL
-%extern bool_t	xdr_vector();
-#endif	/* _KERNEL */
 %#endif /* K&R C */
 #endif	/* RPC_HDR */
--- a/usr/src/uts/common/sys/modctl.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/modctl.h	Mon Jul 20 13:07:46 2009 -0400
@@ -78,7 +78,6 @@
 extern struct mod_ops mod_dacfops;
 extern struct mod_ops mod_ippops;
 extern struct mod_ops mod_pcbeops;
-extern struct mod_ops mod_devfsops;
 extern struct mod_ops mod_kiconvops;
 
 #endif /* _KERNEL */
@@ -183,13 +182,6 @@
 	struct brand		*brand_branddef;
 };
 
-/* for devname fs */
-struct modldev {
-	struct mod_ops		*dev_modops;
-	char			*dev_linkinfo;
-	struct devname_ops	*dev_ops;
-};
-
 /* For socket Modules. */
 struct modlsockmod {
 	struct mod_ops		*sockmod_modops;
@@ -293,8 +285,6 @@
  * devname subcmds for MODDEVNAME
  */
 #define	MODDEVNAME_LOOKUPDOOR	0
-#define	MODDEVNAME_DEVFSADMNODE	1
-#define	MODDEVNAME_NSMAPS	2
 #define	MODDEVNAME_PROFILE	3
 #define	MODDEVNAME_RECONFIG	4
 #define	MODDEVNAME_SYSAVAIL	5
--- a/usr/src/uts/common/sys/mouse.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/mouse.h	Mon Jul 20 13:07:46 2009 -0400
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,8 +19,8 @@
  * CDDL HEADER END
  */
 /*
- * Copyright (c) 1999 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 
 /*	Copyright (c) 1990, 1991 UNIX System Laboratories, Inc.	*/
@@ -31,77 +30,16 @@
 #ifndef	_SYS_MOUSE_H
 #define	_SYS_MOUSE_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
-#define	BUTCHNGMASK	0x38
-#define	MOVEMENT	0x40
-
-#define	BUTSTATMASK	7
-#define	BUT3STAT	1
-#define	BUT2STAT	2
-#define	BUT1STAT	4
-#define	BUT3CHNG	8
-#define	BUT2CHNG	0x10
-#define	BUT1CHNG	0x20
-
-struct mse_event {
-	uchar_t	type;		/* event type (see below) */
-	uchar_t	code;		/* when type is XQ_MOTION or XQ_BUTTON, => */
-				/*	bit 0 clear if right button pushed; */
-				/*	bit 1 clear if middle button pushed; */
-				/*	bit 2 clear if left button pushed; */
-	char	x;		/* delta x movement (mouse motion only) */
-	char	y;		/* delta y movement (mouse motion only) */
-};
-
-#define	MSE_BUTTON	0
-#define	MSE_MOTION	1
-
-struct mouseinfo {
-	unsigned char	status;
-	char	xmotion, ymotion;
-};
-
-/* Ioctl Command definitions */
-
-#define	MOUSEIOC	('M'<<8)
-#define	MOUSEIOCREAD    (MOUSEIOC|60)
-#define	MOUSEISOPEN	(MOUSEIOC|66)
-#define	MOUSE320    	(MOUSEIOC|67)
-#define	MSEBUTTONS	(MOUSEIOC|68)
-#define	TS_CALIB	(MOUSEIOC|70)	/* Touch screen: set the calibration */
-#define	TS_RECALIB	(MOUSEIOC|71)	/* Touch screen: disable calibration */
-#define	TS_CURPOS	(MOUSEIOC|72)	/* Touch screen: set cursor position */
-#define	MOUSEIOCDELAY	(MOUSEIOC|80)
-#define	MOUSEIOCNDELAY	(MOUSEIOC|81)
-#define	MOUSEIOCCONFIG	(MOUSEIOC|100)
-#define	MOUSEIOCMON	(MOUSEIOC|101)
-
-#define	VPC_MOUSE_READ  MOUSEIOCREAD
-
-#define	UPPERLIM	127
-#define	LOWERLIM	-128
-#define	ONEBYTE(x)	((x) > UPPERLIM ? UPPERLIM : \
-				(x) < LOWERLIM ? LOWERLIM : (x))
-
-/* 320 mouse command/query structure */
-
-struct cmd_320 {
-	int	cmd;
-	int	arg1;
-	int	arg2;
-	int	arg3;
-};
-
 /*
  * AT&T 320 (PS/2 style) Mouse Commands
  */
 #define	MSERESET	0xff	/* reset mouse */
 #define	MSERESEND	0xfe	/* resend last data stream */
+#define	MSEERROR	0xfc	/* error */
 #define	MSESETDEF	0xf6	/* set default status */
 #define	MSEOFF		0xf5	/* disable mouse */
 #define	MSEON		0xf4	/* enable mouse */
@@ -117,53 +55,12 @@
 #define	MSESCALE2	0xe7	/* set 2:1 scaling */
 #define	MSESCALE1	0xe6	/* set 1:1 scaling */
 
-/*
- * 320 mouse 8042 controller commands and flags
- */
-#define	MSE_ROP		0xD0	/* read output port command */
-#define	MSE_RIP		0xC0	/* read input port command */
-#define	MSE_WOP		0xD3	/* write to loopback command */
-#define	MSE_WAD		0xD4	/* write to device command */
-#define	MSE_RCB		0x20	/* read command byte command */
-#define	MSE_WCB		0x60	/* write command byte command */
-#define	MSE_INBF	0x03	/* input/output buffer full flag */
-#define	MSE_OUTBF	0x21	/* output buffer full flag */
-#define	MSE_ENAB	0xA8	/* enable 8042 interface */
-#define	MSE_DISAB	0xA7	/* disable 8042 interface */
 #define	MSE_ACK		0xFA	/* Acknowledgement byte from 8042 */
 
-typedef struct mouseinfo MOUSEINFO;
-
-/*
- * Begin Carrol touch screen-specific definitions.
- */
-
-/*
- * Calibration data structure.	Used with TS_CALIB ioctl to register the upper
- * left opto-coordinate that corresponds to the upper left corner of the active
- * video area, and the lower right opto-coordinate that corresponds to the
- * lower right corner of the active video area.
- */
+/* Post-reset return values */
+#define	MSE_AA		0xaa
+#define	MSE_00		0x00
 
-struct ts_calib {
-	int	c_ulx,	/* upper left X opto-coordinate of active video area */
-		c_uly,	/* upper left Y opto-coordinate of active video area */
-		c_lrx,	/* lower right X opto-coordinate of active video area */
-		c_lry;	/* lower right Y opto-coordinate of active video area */
-};
-
-/*
- * Position cursor at the given "pixel" coordinate.
- */
-
-struct ts_curpos {
-	int	p_xpos, /* X cursor coordinate */
-		p_ypos;	/* Y cursor coordinate */
-};
-
-/*
- * End Carrol touch screen-specific definitions.
- */
 
 #ifdef	__cplusplus
 }
--- a/usr/src/uts/common/sys/pset.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/pset.h	Mon Jul 20 13:07:46 2009 -0400
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_SYS_PSET_H
 #define	_SYS_PSET_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -60,6 +58,7 @@
 extern int	pset_assign(psetid_t, processorid_t, psetid_t *);
 extern int	pset_info(psetid_t, int *, uint_t *, processorid_t *);
 extern int	pset_bind(psetid_t, idtype_t, id_t, psetid_t *);
+extern int	pset_bind_lwp(psetid_t, id_t, pid_t, psetid_t *);
 extern int	pset_getloadavg(psetid_t, double [], int);
 extern int	pset_list(psetid_t *, uint_t *);
 extern int	pset_setattr(psetid_t, uint_t);
@@ -72,6 +71,7 @@
 extern int	pset_assign();
 extern int	pset_info();
 extern int	pset_bind();
+extern int	pset_bind_lwp();
 extern int	pset_getloadavg();
 extern int	pset_list();
 extern int	pset_setattr();
@@ -93,6 +93,7 @@
 #define	PSET_SETATTR		7
 #define	PSET_GETATTR		8
 #define	PSET_ASSIGN_FORCED	9
+#define	PSET_BIND_LWP		10
 
 /* attribute bits */
 #define	PSET_NOESCAPE	0x0001
--- a/usr/src/uts/common/sys/sata/adapters/ahci/ahcivar.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/sata/adapters/ahci/ahcivar.h	Mon Jul 20 13:07:46 2009 -0400
@@ -352,6 +352,8 @@
 
 #define	AHCI_DEBUG		1
 
+#endif
+
 #define	AHCIDBG_INIT		0x0001
 #define	AHCIDBG_ENTRY		0x0002
 #define	AHCIDBG_PRDT		0x0004
@@ -373,44 +375,28 @@
 
 extern uint32_t ahci_debug_flags;
 
-#define	AHCIDBG0(flag, ahci_ctlp, format)			\
-	if (ahci_debug_flags & (flag)) {			\
-		ahci_log(ahci_ctlp, CE_WARN, format);		\
-	}
+#if DEBUG
 
-#define	AHCIDBG1(flag, ahci_ctlp, format, arg1)			\
+#define	AHCIDBG(flag, ahci_ctlp, fmt, args ...)			\
 	if (ahci_debug_flags & (flag)) {			\
-		ahci_log(ahci_ctlp, CE_WARN, format, arg1);	\
-	}
-
-#define	AHCIDBG2(flag, ahci_ctlp, format, arg1, arg2)			\
-	if (ahci_debug_flags & (flag)) {				\
-		ahci_log(ahci_ctlp, CE_WARN, format, arg1, arg2);	\
+		ahci_log(ahci_ctlp, CE_WARN, fmt, ## args);	\
+		if (ahci_ctlp == NULL)				\
+			sata_trace_debug(NULL, fmt, ## args);	\
+		else						\
+			sata_trace_debug(ahci_ctlp->ahcictl_dip,\
+			    fmt, ## args);			\
 	}
 
-#define	AHCIDBG3(flag, ahci_ctlp, format, arg1, arg2, arg3)		\
-	if (ahci_debug_flags & (flag)) {				\
-		ahci_log(ahci_ctlp, CE_WARN, format, arg1, arg2, arg3); \
-	}
-
-#define	AHCIDBG4(flag, ahci_ctlp, format, arg1, arg2, arg3, arg4)	\
-	if (ahci_debug_flags & (flag)) {				\
-		ahci_log(ahci_ctlp, CE_WARN, format, arg1, arg2, arg3, arg4); \
-	}
-
-#define	AHCIDBG5(flag, ahci_ctlp, format, arg1, arg2, arg3, arg4, arg5)	\
-	if (ahci_debug_flags & (flag)) {				\
-		ahci_log(ahci_ctlp, CE_WARN, format, arg1, arg2,	\
-		    arg3, arg4, arg5); 					\
-	}
 #else
 
-#define	AHCIDBG0(flag, dip, frmt)
-#define	AHCIDBG1(flag, dip, frmt, arg1)
-#define	AHCIDBG2(flag, dip, frmt, arg1, arg2)
-#define	AHCIDBG3(flag, dip, frmt, arg1, arg2, arg3)
-#define	AHCIDBG4(flag, dip, frmt, arg1, arg2, arg3, arg4)
-#define	AHCIDBG5(flag, dip, frmt, arg1, arg2, arg3, arg4, arg5)
+#define	AHCIDBG(flag, ahci_ctlp, fmt, args ...)			\
+	if (ahci_debug_flags & (flag)) {			\
+		if (ahci_ctlp == NULL)				\
+			sata_trace_debug(NULL, fmt, ## args);	\
+		else						\
+			sata_trace_debug(ahci_ctlp->ahcictl_dip,\
+			    fmt, ## args);			\
+	}
 
 #endif /* DEBUG */
 
--- a/usr/src/uts/common/sys/sata/impl/sata.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/sata/impl/sata.h	Mon Jul 20 13:07:46 2009 -0400
@@ -227,6 +227,13 @@
 	uint64_t	satadrv_max_queue_depth; /* maximum queue depth */
 	sata_id_t	satadrv_id;		/* Device Identify Data */
 	struct sata_drive_stats satadrv_stats;	/* drive statistics */
+
+	/*
+	 * saved standby timer
+	 * [0] - [3] = high - low
+	 */
+	uint8_t		satadrv_standby_timer[4];
+	uint8_t		satadrv_power_level; /* saved power level */
 };
 
 typedef struct sata_drive_info sata_drive_info_t;
@@ -313,6 +320,22 @@
 typedef	struct sata_pmport_info sata_pmport_info_t;
 
 /*
+ * sata drive's power level
+ * default value is active
+ */
+#define	SATA_POWER_ACTIVE	0x00
+#define	SATA_POWER_IDLE		0x01
+#define	SATA_POWER_STANDBY	0x02
+#define	SATA_POWER_STOPPED	0x03
+
+/*
+ * pm-capable value definition according to PSARC 2009/310
+ */
+#define	SATA_CAP_POWER_CONDITON	PM_CAPABLE_SPC4
+#define	SATA_CAP_SMART_PAGE	PM_CAPABLE_SMART_LOG
+#define	SATA_CAP_LOG_SENSE	PM_CAPABLE_LOG_SUPPORTED
+
+/*
  * Port SSTATUS register (sata_port_scr sport_sstatus field).
  * Link bits are valid only in port active state.
  */
@@ -470,9 +493,12 @@
 #define	SD_SCSI_ASC_INVALID_COMMAND_CODE		0x20
 #define	SD_SCSI_ASC_LBA_OUT_OF_RANGE			0x21
 #define	SD_SCSI_ASC_INVALID_FIELD_IN_CDB		0x24
-#define	SD_SCSI_ASC_INVALID_FIELD_IN_PARAMS_LIST 	0x26
+#define	SD_SCSI_ASC_INVALID_FIELD_IN_PARAMS_LIST	0x26
 #define	SD_SCSI_ASC_RESET				0x29
 #define	SD_SCSI_ASC_SAVING_PARAMS_NOT_SUPPORTED		0x39
+#define	SD_SCSI_ASC_CMD_SEQUENCE_ERR			0x2c
+#define	SD_SCSI_ASC_LOW_POWER_CONDITION_ON		0x5e
+#define	SD_SCSI_ASC_LU_NOT_RESPONSE			0x05
 
 
 /* SCSI defs missing from scsi headers */
@@ -485,6 +511,28 @@
 #define	MODEPAGE_RW_ERRRECOV			0x01 /* read/write recovery */
 
 /*
+ * medium access command
+ */
+#define	SATA_IS_MEDIUM_ACCESS_CMD(cmd) \
+	(((cmd) == SCMD_READ) || ((cmd) == SCMD_WRITE) || \
+	((cmd) == SCMD_READ_G1) || ((cmd) == SCMD_WRITE_G1) || \
+	((cmd) == SCMD_READ_G4) || ((cmd) == SCMD_WRITE_G4) || \
+	((cmd) == SCMD_READ_G5) || ((cmd) == SCMD_WRITE_G5) || \
+	((cmd) == SCMD_VERIFY) || ((cmd) == SCMD_VERIFY_G4) || \
+	((cmd) == SCMD_VERIFY_G5) || ((cmd) == 0x7f) /* VERIFY(32) */|| \
+	((cmd) == SCMD_SYNCHRONIZE_CACHE) || ((cmd) == SCMD_SPACE_G4) || \
+	((cmd) == SCMD_READ_POSITION) || \
+	((cmd) == 0x90) /* PRE-FETCH(16) */ || \
+	((cmd) == SCMD_READ_DEFECT_LIST) || \
+	((cmd) == 0xb7) /* READ DEFECT DATA */ || \
+	((cmd) == SCMD_READ_LONG) || ((cmd) == SCMD_SVC_ACTION_IN_G4) || \
+	((cmd) == SCMD_WRITE_LONG) || ((cmd) == SCMD_SVC_ACTION_OUT_G4) || \
+	((cmd) == 0x41) || ((cmd) == 0x93) || /* WRITE SAME */ \
+	((cmd) == 0x52) || ((cmd) == 0x50) || /* XDREAD & XDWRITE */ \
+	((cmd) == 0x53) || ((cmd) == 0x51) || /* XDWRITEREAD & XPWRITE */ \
+	((cmd) == 0x7f))
+
+/*
  * Macros for accessing various structure fields
  */
 
--- a/usr/src/uts/common/sys/sata/sata_defs.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/sata/sata_defs.h	Mon Jul 20 13:07:46 2009 -0400
@@ -45,6 +45,7 @@
 #define	SATAC_DOOR_LOCK		0xde	/* door lock */
 #define	SATAC_DOOR_UNLOCK	0xdf	/* door unlock */
 #define	SATAC_IDLE		0xe3	/* idle	*/
+#define	SATAC_STANDBY		0xe2	/* standby */
 
 /*
  * ATA/ATAPI disk commands (subset)
@@ -94,9 +95,11 @@
  */
 #define	SATAC_CHECK_POWER_MODE	0xe5	/* check power mode */
 
-#define	SATA_PWRMODE_STANDBY	0	/* standby mode */
-#define	SATA_PWRMODE_IDLE	0x80	/* idle mode */
-#define	SATA_PWRMODE_ACTIVE	0xFF	/* active or idle mode, rev7 spec */
+#define	SATA_PWRMODE_STANDBY		0	/* standby mode */
+#define	SATA_PWRMODE_IDLE		0x80	/* idle mode */
+#define	SATA_PWRMODE_ACTIVE_SPINDOWN	0x40	/* PM0 and spinning down */
+#define	SATA_PWRMODE_ACTIVE_SPINUP	0x41	/* PM0 and spinning up */
+#define	SATA_PWRMODE_ACTIVE		0xFF	/* active or idle mode */
 
 
 /*
@@ -152,8 +155,8 @@
  * Following is the ATA Device Identify data layout
  */
 typedef struct sata_id {
-/*  					WORD				  */
-/* 					OFFSET COMMENT			  */
+/*					WORD				  */
+/*					OFFSET COMMENT			  */
 	ushort_t  ai_config;	   /*   0  general configuration bits	  */
 	ushort_t  ai_fixcyls;	   /*   1  # of cylinders (obsolete)	  */
 	ushort_t  ai_resv0;	   /*   2  # reserved			  */
@@ -245,7 +248,7 @@
 
 #define	SATA_ATA_TYPE_MASK	0x8001	/* ATA Device type mask */
 #define	SATA_ATA_TYPE		0x0000	/* ATA device */
-#define	SATA_REM_MEDIA  	0x0080 	/* Removable media */
+#define	SATA_REM_MEDIA		0x0080	/* Removable media */
 #define	SATA_INCOMPLETE_DATA	0x0004	/* Incomplete Identify Device data */
 #define	SATA_CFA_TYPE		0x848a	/* CFA feature set device */
 
@@ -297,6 +300,8 @@
 
 /* Identify Device: command set supported/enabled bits - words 84 & 87 */
 #define	SATA_SMART_SELF_TEST_SUPPORTED	0x0002	/* SMART self-test supported */
+/* IDLE IMMEDIATE with UNLOAD FEATURE supported */
+#define	SATA_IDLE_UNLOAD_SUPPORTED	0x2000
 
 /* Identify (Packet) Device word 63,  ATA/ATAPI-6 & 7 */
 #define	SATA_MDMA_SEL_MASK	0x0700	/* Multiword DMA selected */
@@ -329,11 +334,11 @@
 /* Identify Packet Device: general config bits  - word 0 */
 
 #define	SATA_ATAPI_TYPE_MASK	0xc000
-#define	SATA_ATAPI_TYPE		0x8000 	/* ATAPI device */
-#define	SATA_ATAPI_ID_PKT_SZ	0x0003 	/* Packet size mask */
+#define	SATA_ATAPI_TYPE		0x8000	/* ATAPI device */
+#define	SATA_ATAPI_ID_PKT_SZ	0x0003	/* Packet size mask */
 #define	SATA_ATAPI_ID_PKT_12B	0x0000  /* Packet size 12 bytes */
 #define	SATA_ATAPI_ID_PKT_16B	0x0001  /* Packet size 16 bytes */
-#define	SATA_ATAPI_ID_DRQ_TYPE	0x0060 	/* DRQ asserted in 3ms after pkt */
+#define	SATA_ATAPI_ID_DRQ_TYPE	0x0060	/* DRQ asserted in 3ms after pkt */
 #define	SATA_ATAPI_ID_DRQ_INTR	0x0020  /* Obsolete in ATA/ATAPI 7 */
 
 #define	SATA_ATAPI_ID_DEV_TYPE	0x0f00	/* device type/command set mask */
@@ -413,9 +418,9 @@
  * Status bits from AT_STATUS register
  */
 #define	SATA_STATUS_BSY		0x80    /* controller busy */
-#define	SATA_STATUS_DRDY	0x40    /* drive ready 	*/
+#define	SATA_STATUS_DRDY	0x40    /* drive ready	*/
 #define	SATA_STATUS_DF		0x20    /* device fault	*/
-#define	SATA_STATUS_DSC    	0x10    /* seek operation complete */
+#define	SATA_STATUS_DSC		0x10    /* seek operation complete */
 #define	SATA_STATUS_DRQ		0x08	/* data request */
 #define	SATA_STATUS_CORR	0x04    /* obsolete */
 #define	SATA_STATUS_IDX		0x02    /* obsolete */
@@ -508,6 +513,9 @@
 	uint8_t ncq_checksum;
 };
 
+/* SMART attribute of Start/Stop Count */
+#define	SMART_START_STOP_COUNT_ID	0x4
+
 /*
  * SMART data structures
  */
@@ -574,6 +582,24 @@
 };
 
 /*
+ * The definition of CONTROL byte field in SCSI command
+ * according to SAM 5
+ */
+#define	CTL_BYTE_VENDOR_MASK		0xc0
+#define	CTL_BYTE_NACA_MASK		0x04
+
+/*
+ * The definition of mask in START STOP UNIT command
+ */
+#define	START_STOP_IMMED_MASK		0x01
+#define	START_STOP_POWER_COND_MASK	0xF0
+#define	START_STOP_START_MASK		0x01
+#define	START_STOP_LOEJ_MASK		0x02
+#define	START_STOP_NOFLUSH_MASK		0x04
+#define	START_STOP_MODIFIER_MASK	0x0f
+#define	START_STOP_POWER_COND_SHIFT	4
+
+/*
  * SMART specific data
  * These eventually need to go to a generic scsi hearder file
  * for now they will reside here
@@ -583,6 +609,7 @@
 #define	PAGE_CODE_SELF_TEST_RESULTS		0x10
 #define	PAGE_CODE_INFORMATION_EXCEPTIONS	0x2f
 #define	PAGE_CODE_SMART_READ_DATA		0x30
+#define	PAGE_CODE_START_STOP_CYCLE_COUNTER	0x0e
 
 
 struct log_parameter {
--- a/usr/src/uts/common/sys/sata/sata_hba.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/sata/sata_hba.h	Mon Jul 20 13:07:46 2009 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -714,6 +714,40 @@
 void	sata_free_error_retrieval_pkt(sata_pkt_t *);
 void	sata_free_dma_resources(sata_pkt_t *);
 
+/*
+ * SATA trace ring buffer constants
+ */
+#define	DMSG_RING_SIZE		0x100000	/* 1MB */
+#define	DMSG_BUF_SIZE		256
+
+/*
+ * SATA trace ring buffer content
+ */
+typedef struct sata_trace_dmsg {
+	dev_info_t		*dip;
+	timespec_t		timestamp;
+	char			buf[DMSG_BUF_SIZE];
+	struct sata_trace_dmsg	*next;
+} sata_trace_dmsg_t;
+
+/*
+ * SATA trace ring buffer header
+ */
+typedef struct sata_trace_rbuf {
+	kmutex_t		lock;		/* lock to avoid clutter */
+	int			looped;		/* completed ring */
+	int			allocfailed;	/* dmsg mem alloc failed */
+	size_t			size;		/* current size */
+	size_t			maxsize;	/* max size */
+	sata_trace_dmsg_t	*dmsgh;		/* messages head */
+	sata_trace_dmsg_t	*dmsgp;		/* ptr to last message */
+} sata_trace_rbuf_t;
+
+/*
+ * SATA trace ring buffer interfaces
+ */
+void sata_trace_debug(dev_info_t *, const char *fmt, ...);
+void sata_vtrace_debug(dev_info_t *, const char *fmt, va_list);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/uts/common/sys/scsi/generic/inquiry.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/scsi/generic/inquiry.h	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -425,6 +425,24 @@
 	/* ---- data follows ---- */
 };
 
+/*
+ * "pm-capable" integer property bit mask definitions
+ */
+#define	PM_CAPABLE_PM_MASK	0x0000ffff	/* use lower 16 bits to */
+						/* indicate PM mode */
+#define	PM_CAPABLE_CCS		RDF_CCS
+#define	PM_CAPABLE_SCSI2	RDF_SCSI2
+#define	PM_CAPABLE_SPC		RDF_SCSI_SPC
+#define	PM_CAPABLE_SPC2		RDF_SCSI_SPC2
+#define	PM_CAPABLE_SPC3		RDF_SCSI_SPC3
+#define	PM_CAPABLE_SPC4		RDF_SCSI_SPC4
+#define	PM_CAPABLE_LOG_MASK	0xffff0000	/* use upper 16 bit to */
+						/* indicate log specifics */
+#define	PM_CAPABLE_LOG_SUPPORTED	0x10000	/* Log page 0xE might be */
+						/* supported */
+#define	PM_CAPABLE_SMART_LOG		0x20000 /* Log page 0xE reports SMART */
+						/* attributes instead of the */
+						/* default SCSI Log pages */
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/uts/common/sys/scsi/generic/mode.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/scsi/generic/mode.h	Mon Jul 20 13:07:46 2009 -0400
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_SYS_SCSI_GENERIC_MODE_H
 #define	_SYS_SCSI_GENERIC_MODE_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -391,6 +389,89 @@
 #define	MRIE_NO_SENSE		0x5
 #define	MRIE_ONLY_ON_REQUEST	0x6
 
+struct mode_info_power_cond {
+	struct mode_page mode_page;	/* common mode page header */
+	uchar_t reserved;
+#if defined(_BIT_FIELDS_LTOH)
+	uchar_t standby	:1,	/* standby bit */
+		idle	:1,	/* idle bit */
+			:6;	/* reserved */
+#elif defined(_BIT_FIELDS_HTOL)
+	uchar_t		:6,	/* reserved */
+		idle	:1,	/* idle bit */
+		standby	:1;	/* standby bit */
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+	uchar_t	idle_cond_timer_high;
+	uchar_t idle_cond_timer_low;
+	uchar_t standby_cond_timer[4];
+};
+
+struct parameter_control {
+#if defined(_BIT_FIELDS_LTOH)
+	uchar_t fmt_link:2,	/* format and link bit */
+		tmc	:2,	/* tmc bit */
+		etc	:1,	/* etc bit */
+		tsd	:1,	/* tsd bit */
+		reserv	:1,	/* obsolete */
+		du	:1;	/* du bit */
+#elif defined(_BIT_FIELDS_HTOL)
+	uchar_t	du	:1,	/* du bit */
+		reserv	:1,	/* obsolete */
+		tsd	:1,	/* tsd bit */
+		etc	:1,	/* etc bit */
+		tmc	:2,	/* tmc bit */
+		fmt_link:2;	/* format and link bit */
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+};
+
+struct start_stop_cycle_counter_log {
+#if defined(_BIT_FIELDS_LTOH)
+	uchar_t code	:6,	/* page code bit */
+		spf	:1,	/* spf bit */
+		ds	:1;	/* ds bit */
+#elif defined(_BIT_FIELDS_HTOL)
+	uchar_t	ds	:1,	/* ds bit */
+		spf	:1,	/* spf bit */
+		code	:6;	/* page code bit */
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+	uchar_t			sub_page_code;
+	uchar_t			page_len_high;
+	uchar_t			page_len_low;
+
+	uchar_t			manufactor_date_high;
+	uchar_t			manufactor_date_low;
+	struct parameter_control param_1;
+	uchar_t			param_len_1;
+	uchar_t			year_manu[4];
+	uchar_t			week_manu[2];
+
+	uchar_t			account_date_high;
+	uchar_t			account_date_low;
+	struct parameter_control param_2;
+	uchar_t			param_len_2;
+	uchar_t			year_account[4];
+	uchar_t			week_account[2];
+
+	uchar_t			lifetime_code_high;
+	uchar_t			lifetime_code_low;
+	struct parameter_control param_3;
+	uchar_t			param_len_3;
+	uchar_t			cycle_lifetime[4];
+
+	uchar_t			cycle_code_high;
+	uchar_t			cycle_code_low;
+	struct parameter_control param_4;
+	uchar_t			param_len_4;
+	uchar_t			cycle_accumulated[4];
+};
+
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/uts/common/sys/scsi/impl/uscsi.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/scsi/impl/uscsi.h	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -152,8 +152,14 @@
 #define	USCSI_NOPARITY	0x00000010	/* run command without parity */
 #define	USCSI_NODISCON	0x00000020	/* run command without disconnects */
 
+/*
+ * suitable for FMA module for PM purpose
+ */
+#define	USCSI_PMFAILFAST	0x00100000	/* fail command if device is */
+						/* in low power */
 
-#define	USCSI_RESERVED	0xfff00000	/* Reserved Bits, must be zero */
+
+#define	USCSI_RESERVED	0xffe00000	/* Reserved Bits, must be zero */
 
 struct uscsi_rqs {
 	int		rqs_flags;	/* see below */
--- a/usr/src/uts/common/sys/scsi/targets/sddef.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/scsi/targets/sddef.h	Mon Jul 20 13:07:46 2009 -0400
@@ -125,7 +125,7 @@
  * Macro to retrieve the DDI instance number from the given buf struct.
  * The instance number is encoded in the minor device number.
  */
-#define	SD_GET_INSTANCE_FROM_BUF(bp)					\
+#define	SD_GET_INSTANCE_FROM_BUF(bp)				\
 	(getminor((bp)->b_edev) >> SDUNIT_SHIFT)
 
 
@@ -447,7 +447,13 @@
 						/* sent in sdclose */
 	    un_f_devid_transport_defined :1,	/* devid defined by transport */
 	    un_f_rmw_type		 :2,	/* RMW type */
-	    un_f_reserved		:10;
+	    un_f_power_condition_disabled :1,	/* power condition disabled */
+						/* through sd configuration */
+	    un_f_power_condition_supported :1,	/* support power condition */
+						/* field by hardware */
+	    un_f_pm_log_sense_smart	:1,	/* log sense support SMART */
+						/* feature attribute */
+	    un_f_reserved		:7;
 
 	/* Ptr to table of strings for ASC/ASCQ error message printing */
 	struct scsi_asq_key_strings	*un_additional_codes;
@@ -1783,11 +1789,28 @@
 #define	SD_CONF_NOT_USED		32
 
 /*
- * Return values from "pm-capable" property
+ * "pm-capable" property values and macros
  */
 #define	SD_PM_CAPABLE_UNDEFINED		-1
-#define	SD_PM_CAPABLE_FALSE		0
-#define	SD_PM_CAPABLE_TRUE		1
+
+#define	SD_PM_CAPABLE_IS_UNDEFINED(pm_cap)	\
+	(pm_cap == SD_PM_CAPABLE_UNDEFINED)
+
+#define	SD_PM_CAPABLE_IS_FALSE(pm_cap)	\
+	((pm_cap & PM_CAPABLE_PM_MASK) == 0)
+
+#define	SD_PM_CAPABLE_IS_TRUE(pm_cap)	\
+	(!SD_PM_CAPABLE_IS_UNDEFINED(pm_cap) && \
+	    ((pm_cap & PM_CAPABLE_PM_MASK) > 0))
+
+#define	SD_PM_CAPABLE_IS_SPC_4(pm_cap)	\
+	((pm_cap & PM_CAPABLE_PM_MASK) == PM_CAPABLE_SPC4)
+
+#define	SD_PM_CAP_LOG_SUPPORTED(pm_cap)	\
+	((pm_cap & PM_CAPABLE_LOG_SUPPORTED) ? TRUE : FALSE)
+
+#define	SD_PM_CAP_SMART_LOG(pm_cap)	\
+	((pm_cap & PM_CAPABLE_SMART_LOG) ? TRUE : FALSE)
 
 /*
  * Property data values used in static configuration table
@@ -2022,6 +2045,13 @@
 #define	SD_CONF_BSET_CACHE_IS_NV	(1 << SD_CONF_SET_CACHE_IS_NV)
 
 /*
+ * Bit in flags telling driver that the power condition flag from [s]sd.conf
+ * [s]sd-config-list and driver table.
+ */
+#define	SD_CONF_SET_PC_DISABLED	19
+#define	SD_CONF_BSET_PC_DISABLED	(1 << SD_CONF_SET_PC_DISABLED)
+
+/*
  * This is the number of items currently settable in the sd.conf
  * sd-config-list.  The mask value is defined for parameter checking. The
  * item count and mask should be updated when new properties are added.
@@ -2040,6 +2070,7 @@
 	int sdt_disk_sort_dis;
 	int sdt_lun_reset_enable;
 	int sdt_suppress_cache_flush;
+	int sdt_power_condition_dis;
 } sd_tunables;
 
 /* Type definition for static configuration table entries */
@@ -2050,13 +2081,21 @@
 } sd_disk_config_t;
 
 /*
- * byte 4 options for 1bh command
+ * first 2 bits of byte 4 options for 1bh command
  */
 #define	SD_TARGET_STOP			0x00
 #define	SD_TARGET_START			0x01
 #define	SD_TARGET_EJECT			0x02
 #define	SD_TARGET_CLOSE			0x03
 
+/*
+ * power condition of byte 4 for 1bh command
+ */
+#define	SD_TARGET_START_VALID		0x00
+#define	SD_TARGET_ACTIVE		0x01
+#define	SD_TARGET_IDLE			0x02
+#define	SD_TARGET_STANDBY		0x03
+
 
 #define	SD_MODE_SENSE_PAGE3_CODE	0x03
 #define	SD_MODE_SENSE_PAGE4_CODE	0x04
@@ -2143,7 +2182,47 @@
 #define	SD_SPINDLE_UNINIT	(-1)
 #define	SD_SPINDLE_OFF		0
 #define	SD_SPINDLE_ON		1
-#define	SD_PM_NOT_SUPPORTED	2
+#define	SD_SPINDLE_STOPPED	0
+#define	SD_SPINDLE_STANDBY	1
+#define	SD_SPINDLE_IDLE		2
+#define	SD_SPINDLE_ACTIVE	3
+#define	SD_PM_NOT_SUPPORTED	4
+
+/*
+ * Power method flag
+ */
+#define	SD_START_STOP		0
+#define	SD_POWER_CONDITION	1
+
+
+/*
+ * Number of power level for start stop or power condition
+ */
+#define	SD_PM_NUM_LEVEL_SSU_SS	2
+#define	SD_PM_NUM_LEVEL_SSU_PC	4
+
+/*
+ * SD internal power state change flag
+ */
+#define	SD_PM_STATE_CHANGE	0
+#define	SD_PM_STATE_ROLLBACK	1
+
+/*
+ * Power attribute table
+ */
+typedef struct disk_power_attr_ss {
+	char *pm_comp[SD_PM_NUM_LEVEL_SSU_SS + 2];	/* pm component */
+	int ran_perf[SD_PM_NUM_LEVEL_SSU_SS];		/* random performance */
+	int pwr_saving[SD_PM_NUM_LEVEL_SSU_SS];		/* power saving */
+	int latency[SD_PM_NUM_LEVEL_SSU_SS];		/* latency */
+}sd_power_attr_ss;
+
+typedef struct disk_power_attr_pc {
+	char *pm_comp[SD_PM_NUM_LEVEL_SSU_PC + 2];	/* pm component */
+	int ran_perf[SD_PM_NUM_LEVEL_SSU_PC];		/* random performance */
+	int pwr_saving[SD_PM_NUM_LEVEL_SSU_PC];		/* power saving */
+	int latency[SD_PM_NUM_LEVEL_SSU_PC];		/* latency */
+}sd_power_attr_pc;
 
 
 /*
@@ -2166,6 +2245,30 @@
 #define	SD_OK_TO_SUSPEND_SCSI_WATCHER(un)	(un->un_swr_token != NULL)
 #define	SD_DEVICE_IS_IN_LOW_POWER(un)		((un->un_f_pm_is_enabled) && \
 						    (un->un_pm_count < 0))
+#define	SD_PM_STATE_ACTIVE(un)				\
+		(un->un_f_power_condition_supported ?	\
+		SD_SPINDLE_ACTIVE : SD_SPINDLE_ON)
+#define	SD_PM_STATE_STOPPED(un)				\
+		(un->un_f_power_condition_supported ?	\
+		SD_SPINDLE_STOPPED : SD_SPINDLE_OFF)
+#define	SD_PM_IS_LEVEL_VALID(un, level)			\
+		((un->un_f_power_condition_supported &&	\
+		level >= SD_SPINDLE_STOPPED &&		\
+		level <= SD_SPINDLE_ACTIVE) ||		\
+		(!un->un_f_power_condition_supported &&	\
+		level >= SD_SPINDLE_OFF &&		\
+		level <= SD_SPINDLE_ON))
+#define	SD_PM_IS_IO_CAPABLE(un, level)			\
+		((un->un_f_power_condition_supported &&	\
+		sd_pwr_pc.ran_perf[level] > 0) ||	\
+		(!un->un_f_power_condition_supported &&	\
+		sd_pwr_ss.ran_perf[level] > 0))
+#define	SD_PM_STOP_MOTOR_NEEDED(un, level)		\
+		((un->un_f_power_condition_supported &&	\
+		level <= SD_SPINDLE_STANDBY) ||		\
+		(!un->un_f_power_condition_supported &&	\
+		level == SD_SPINDLE_OFF))
+
 /*
  * Could move this define to some thing like log sense.h in SCSA headers
  * But for now let it live here.
--- a/usr/src/uts/common/sys/socket_proto.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/socket_proto.h	Mon Jul 20 13:07:46 2009 -0400
@@ -60,6 +60,7 @@
 	uint_t sopp_rcvtimer;		/* delayed recv notification (time) */
 	uint32_t sopp_rcvthresh;	/* delayed recv notification (bytes) */
 	socklen_t sopp_maxaddrlen;	/* maximum size of protocol address */
+	boolean_t sopp_loopback;	/* loopback connection */
 };
 
 /* flags to determine which socket options are set */
@@ -75,6 +76,7 @@
 #define	SOCKOPT_RCVTHRESH	0x0200
 #define	SOCKOPT_MAXADDRLEN	0x0400	/* set max address length */
 #define	SOCKOPT_MINPSZ		0x0800	/* set minpsz for protocols */
+#define	SOCKOPT_LOOPBACK	0x1000	/* set loopback */
 
 #define	IS_SO_OOB_INLINE(so)	((so)->so_proto_props.sopp_oobinline)
 
--- a/usr/src/uts/common/sys/stmf_sbd_ioctl.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/stmf_sbd_ioctl.h	Mon Jul 20 13:07:46 2009 -0400
@@ -83,6 +83,7 @@
 			slu_rev_valid:1,
 			slu_serial_valid:1,
 			slu_alias_valid:1,
+			slu_mgmt_url_valid:1,
 			slu_guid_valid:1,
 			slu_company_id_valid:1,
 			slu_writeback_cache_disable_valid:1,
@@ -98,8 +99,7 @@
 	uint16_t	slu_blksize;
 	uint32_t	slu_company_id;
 	uint16_t	slu_alias_off;
-	uint8_t		slu_rsvd2;
-	uint8_t		slu_rsvd;
+	uint16_t	slu_mgmt_url_off;
 	uint32_t	slu_rsvd1;
 	char		slu_rev[4];
 	char		slu_vid[8];
@@ -120,6 +120,7 @@
 	uint32_t	mlu_lu_size_valid:1,
 			mlu_serial_valid:1,
 			mlu_alias_valid:1,
+			mlu_mgmt_url_valid:1,
 			mlu_writeback_cache_disable_valid:1,
 			mlu_writeback_cache_disable:1,
 			mlu_write_protected_valid:1,
@@ -128,9 +129,12 @@
 			mlu_by_fname:1;
 	uint64_t	mlu_lu_size;
 	uint16_t	mlu_alias_off;
+	uint16_t	mlu_mgmt_url_off;
 	uint16_t	mlu_serial_off;
 	uint16_t	mlu_serial_size;
 	uint16_t	mlu_fname_off;
+	uint16_t	mlu_rsvd1;
+	uint32_t	mlu_rsvd2;
 	uint8_t		mlu_input_guid[16];
 	char		mlu_buf[8]; /* can be more than 8 */
 } sbd_modify_lu_t;
@@ -151,6 +155,7 @@
 			slp_data_fname_valid:1,
 			slp_zfs_meta:1,
 			slp_alias_valid:1,
+			slp_mgmt_url_valid:1,
 			slp_lu_vid:1,
 			slp_lu_pid:1,
 			slp_lu_rev:1,
@@ -165,6 +170,7 @@
 	uint16_t	slp_serial_off;
 	uint16_t	slp_blksize;
 	uint16_t	slp_alias_off;
+	uint16_t	slp_mgmt_url_off;
 	uint32_t	slp_buf_size_needed;	/* Upon return */
 	uint16_t	slp_serial_size;
 	uint16_t	slp_rsvd;
--- a/usr/src/uts/common/sys/sunpm.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/sys/sunpm.h	Mon Jul 20 13:07:46 2009 -0400
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_SYS_SUNPM_H
 #define	_SYS_SUNPM_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Sun Specific Power Management definitions
  */
@@ -51,9 +49,10 @@
 #ifdef	_KERNEL
 
 /*
- * Power cycle transition check is supported for these devices.
+ * Power cycle transition check is supported for SCSI and SATA devices.
  */
 #define	DC_SCSI_FORMAT		0x1		/* SCSI */
+#define	DC_SMART_FORMAT		0x2		/* SMART */
 
 #define	DC_SCSI_MFR_LEN		6		/* YYYYWW */
 
@@ -64,10 +63,17 @@
 	int	flag;				/* reserved for future */
 };
 
+struct pm_smart_count {
+	int	allowed;	/* normalized max cycles allowed */
+	int	consumed;	/* normalized consumed cycles */
+	int	flag;		/* type of cycles */
+};
+
 struct pm_trans_data {
 	int	format;				/* data format */
 	union {
 		struct pm_scsi_cycles scsi_cycles;
+		struct pm_smart_count smart_count;
 	} un;
 };
 
--- a/usr/src/uts/common/syscall/pset.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/syscall/pset.c	Mon Jul 20 13:07:46 2009 -0400
@@ -470,6 +470,66 @@
 	return (error);
 }
 
+/*
+ * Bind the lwp:id of process:pid to processor set: pset
+ */
+static int
+pset_bind_lwp(psetid_t pset, id_t id, pid_t pid, psetid_t *opset)
+{
+	kthread_t	*tp;
+	proc_t		*pp;
+	psetid_t	oldpset;
+	void		*projbuf, *zonebuf;
+	int		error = 0;
+
+	pool_lock();
+	mutex_enter(&cpu_lock);
+	projbuf = fss_allocbuf(FSS_NPROJ_BUF, FSS_ALLOC_PROJ);
+	zonebuf = fss_allocbuf(FSS_NPROJ_BUF, FSS_ALLOC_ZONE);
+
+	mutex_enter(&pidlock);
+	if ((pid == P_MYID && id == P_MYID) ||
+	    (pid == curproc->p_pid && id == P_MYID)) {
+		pp = curproc;
+		tp = curthread;
+		mutex_enter(&pp->p_lock);
+	} else {
+		if (pid == P_MYID) {
+			pp = curproc;
+		} else if ((pp = prfind(pid)) == NULL) {
+			error = ESRCH;
+			goto err;
+		}
+		if (pp != curproc && id == P_MYID) {
+			error = EINVAL;
+			goto err;
+		}
+		mutex_enter(&pp->p_lock);
+		if ((tp = idtot(pp, id)) == NULL) {
+			mutex_exit(&pp->p_lock);
+			error = ESRCH;
+			goto err;
+		}
+	}
+
+	error = pset_bind_thread(tp, pset, &oldpset, projbuf, zonebuf);
+	mutex_exit(&pp->p_lock);
+err:
+	mutex_exit(&pidlock);
+
+	fss_freebuf(projbuf, FSS_ALLOC_PROJ);
+	fss_freebuf(zonebuf, FSS_ALLOC_ZONE);
+	mutex_exit(&cpu_lock);
+	pool_unlock();
+	if (opset != NULL) {
+		if (copyout(&oldpset, opset, sizeof (psetid_t)) != 0)
+			return (set_errno(EFAULT));
+	}
+	if (error != 0)
+		return (set_errno(error));
+	return (0);
+}
+
 static int
 pset_bind(psetid_t pset, idtype_t idtype, id_t id, psetid_t *opset)
 {
@@ -797,6 +857,9 @@
 	case PSET_BIND:
 		return (pset_bind((psetid_t)arg1, (idtype_t)arg2,
 		    (id_t)arg3, (psetid_t *)arg4));
+	case PSET_BIND_LWP:
+		return (pset_bind_lwp((psetid_t)arg1, (id_t)arg2,
+		    (pid_t)arg3, (psetid_t *)arg4));
 	case PSET_GETLOADAVG:
 		return (pset_getloadavg((psetid_t)arg1, (int *)arg2,
 		    (int)arg3));
--- a/usr/src/uts/common/vm/page.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/vm/page.h	Mon Jul 20 13:07:46 2009 -0400
@@ -1126,6 +1126,8 @@
 
 /* msegflags */
 #define	MEMSEG_DYNAMIC		0x1	/* DR: memory was added dynamically */
+#define	MEMSEG_META_INCL	0x2	/* DR: memseg includes it's metadata */
+#define	MEMSEG_META_ALLOC	0x4	/* DR: memseg allocated it's metadata */
 
 /* memseg support macros */
 #define	MSEG_NPAGES(SEG)	((SEG)->pages_end - (SEG)->pages_base)
--- a/usr/src/uts/common/vm/vm_page.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/vm/vm_page.c	Mon Jul 20 13:07:46 2009 -0400
@@ -1116,8 +1116,11 @@
 			VM_STAT_ADD(page_exphcontg[4]);
 			return (1);
 		}
+		/*
+		 * Also check whether p_pagenum was modified by DR.
+		 */
 		if (pp->p_szc != pszc || pp->p_vnode != vp ||
-		    pp->p_offset != off) {
+		    pp->p_offset != off || pp->p_pagenum != pfn) {
 			VM_STAT_ADD(page_exphcontg[5]);
 			page_unlock(pp);
 			off = save_off;
@@ -1204,11 +1207,17 @@
 	 */
 
 	for (i = 0; i < pages; i++, pp++, off += PAGESIZE, pfn++) {
-		ASSERT(pp->p_pagenum == pfn);
 		if (!page_trylock(pp, SE_EXCL)) {
 			VM_STAT_ADD(page_exphcontg[12]);
 			break;
 		}
+		/*
+		 * Check whether p_pagenum was modified by DR.
+		 */
+		if (pp->p_pagenum != pfn) {
+			page_unlock(pp);
+			break;
+		}
 		if (pp->p_vnode != vp ||
 		    pp->p_offset != off) {
 			VM_STAT_ADD(page_exphcontg[13]);
@@ -5835,6 +5844,10 @@
 	 * another cpu and trying to reference it after it has been freed.
 	 * This will keep us on cpu and prevent it from being removed while
 	 * we are still on it.
+	 *
+	 * We may be caching a memseg in vc_pnum_memseg/vc_pnext_memseg
+	 * which is being resued by DR who will flush those references
+	 * before modifying the reused memseg.  See memseg_cpu_vm_flush().
 	 */
 	kpreempt_disable();
 	vc = CPU->cpu_vm_data;
@@ -5870,8 +5883,10 @@
 		if (pfnum >= seg->pages_base && pfnum < seg->pages_end) {
 			vc->vc_pnum_memseg = seg;
 			pp = seg->pages + (pfnum - seg->pages_base);
-			kpreempt_enable();
-			return ((page_t *)pp);
+			if (pp->p_pagenum == pfnum) {
+				kpreempt_enable();
+				return ((page_t *)pp);
+			}
 		}
 	}
 	vc->vc_pnum_memseg = NULL;
@@ -5887,20 +5902,33 @@
 	struct memseg *seg;
 	page_t *pp;
 
+	/*
+	 * We may be caching a memseg in vc_pnum_memseg/vc_pnext_memseg
+	 * which is being resued by DR who will flush those references
+	 * before modifying the reused memseg.  See memseg_cpu_vm_flush().
+	 */
+	kpreempt_disable();
 	/* Try hash */
 	if (((seg = memseg_hash[MEMSEG_PFN_HASH(pfnum)]) != NULL) &&
 	    (pfnum >= seg->pages_base) && (pfnum < seg->pages_end)) {
 		pp = seg->pages + (pfnum - seg->pages_base);
-		if (pp->p_pagenum == pfnum)
+		if (pp->p_pagenum == pfnum) {
+			kpreempt_enable();
 			return (seg);
+		}
 	}
 
 	/* Else Brute force */
 	for (seg = memsegs; seg != NULL; seg = seg->next) {
 		if (pfnum >= seg->pages_base && pfnum < seg->pages_end) {
-			return (seg);
-		}
-	}
+			pp = seg->pages + (pfnum - seg->pages_base);
+			if (pp->p_pagenum == pfnum) {
+				kpreempt_enable();
+				return (seg);
+			}
+		}
+	}
+	kpreempt_enable();
 	return ((struct memseg *)NULL);
 }
 
@@ -5925,6 +5953,10 @@
 	 * another cpu and trying to reference it after it has been freed.
 	 * This will keep us on cpu and prevent it from being removed while
 	 * we are still on it.
+	 *
+	 * We may be caching a memseg in vc_pnum_memseg/vc_pnext_memseg
+	 * which is being resued by DR who will flush those references
+	 * before modifying the reused memseg.  See memseg_cpu_vm_flush().
 	 */
 	kpreempt_disable();
 	vc = (vm_cpu_data_t *)CPU->cpu_vm_data;
@@ -6008,12 +6040,12 @@
 	 * Catch if we went past the end of the current memory segment. If so,
 	 * just move to the next segment with pages.
 	 */
-	if (new_pp >= seg->epages) {
+	if (new_pp >= seg->epages || seg->pages_base == seg->pages_end) {
 		do {
 			seg = seg->next;
 			if (seg == NULL)
 				seg = memsegs;
-		} while (seg->pages == seg->epages);
+		} while (seg->pages_base == seg->pages_end);
 		new_pp = seg->pages;
 		*cookie = (void *)seg;
 	}
--- a/usr/src/uts/common/vm/vm_pagelist.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/vm/vm_pagelist.c	Mon Jul 20 13:07:46 2009 -0400
@@ -954,6 +954,7 @@
 	int cands_cache_nranges;
 	int old_maxmrange, new_maxmrange;
 	int rc = 0;
+	int oldmnode;
 
 	cands_cache = kmem_zalloc(sizeof (pcc_info_t *) * NPC_MUTEX *
 	    MMU_PAGE_SIZES, KM_NOSLEEP);
@@ -1048,6 +1049,21 @@
 	 */
 	PAGE_CTRS_WRITE_LOCK(mnode);
 
+	/*
+	 * For interleaved mnodes, find the first mnode
+	 * with valid page counters since the current
+	 * mnode may have just been added and not have
+	 * valid page counters.
+	 */
+	if (interleaved_mnodes) {
+		for (i = 0; i < max_mem_nodes; i++)
+			if (PAGE_COUNTERS_COUNTERS(i, 1) != NULL)
+				break;
+		ASSERT(i < max_mem_nodes);
+		oldmnode = i;
+	} else
+		oldmnode = mnode;
+
 	old_nranges = mnode_nranges[mnode];
 	cands_cache_nranges = old_nranges;
 	mnode_nranges[mnode] = nranges;
@@ -1057,10 +1073,10 @@
 
 	for (r = 1; r < mmu_page_sizes; r++) {
 		PAGE_COUNTERS_SHIFT(mnode, r) = PAGE_BSZS_SHIFT(r);
-		old_ctr = PAGE_COUNTERS_COUNTERS(mnode, r);
-		old_csz = PAGE_COUNTERS_ENTRIES(mnode, r);
-		oldbase = PAGE_COUNTERS_BASE(mnode, r);
-		old_npgs = old_csz << PAGE_COUNTERS_SHIFT(mnode, r);
+		old_ctr = PAGE_COUNTERS_COUNTERS(oldmnode, r);
+		old_csz = PAGE_COUNTERS_ENTRIES(oldmnode, r);
+		oldbase = PAGE_COUNTERS_BASE(oldmnode, r);
+		old_npgs = old_csz << PAGE_COUNTERS_SHIFT(oldmnode, r);
 		for (mrange = 0; mrange < MAX_MNODE_MRANGES; mrange++) {
 			old_color_array[mrange] =
 			    PAGE_COUNTERS_CURRENT_COLOR_ARRAY(mnode,
@@ -1102,9 +1118,11 @@
 			for (i = 0; i < max_mem_nodes; i++) {
 				if (i == mnode)
 					continue;
+				ASSERT(
+				    PAGE_COUNTERS_COUNTERS(i, r) == old_ctr ||
+				    PAGE_COUNTERS_COUNTERS(i, r) == NULL);
 				if (mem_node_config[i].exists == 0)
 					continue;
-				ASSERT(PAGE_COUNTERS_COUNTERS(i, r) == old_ctr);
 				PAGE_COUNTERS_COUNTERS(i, r) = new_ctr;
 				PAGE_COUNTERS_ENTRIES(i, r) = pcsz;
 				PAGE_COUNTERS_BASE(i, r) = newbase;
@@ -1126,13 +1144,14 @@
 			int mhi = interleaved_mnodes ? max_mem_nodes :
 			    (mnode + 1);
 			int m;
-			pfn_t  pfnum = newbase;
+			pfn_t  pfnum;
 			size_t idx;
 			MEM_NODE_ITERATOR_DECL(it);
 
 			for (m = mlo; m < mhi; m++) {
 				if (mem_node_config[m].exists == 0)
 					continue;
+				pfnum = newbase;
 				MEM_NODE_ITERATOR_INIT(pfnum, m, r, &it);
 				if (pfnum == (pfn_t)-1) {
 					idx = 0;
@@ -1143,8 +1162,10 @@
 					idx = (idx < pcsz) ? idx : 0;
 				}
 				for (mrange = 0; mrange < nranges; mrange++) {
-					PAGE_COUNTERS_CURRENT_COLOR(m,
-					    r, i, mrange) = idx;
+					if (PAGE_COUNTERS_CURRENT_COLOR_ARRAY(m,
+					    r, mrange) != NULL)
+						PAGE_COUNTERS_CURRENT_COLOR(m,
+						    r, i, mrange) = idx;
 				}
 			}
 		}
@@ -2251,13 +2272,8 @@
 
 	/* get pfn range for mtype */
 	len = PAGE_COUNTERS_ENTRIES(mnode, r);
-#if defined(__sparc)
-	lo = PAGE_COUNTERS_BASE(mnode, r);
-	hi = IDX_TO_PNUM(mnode, r, len);
-#else
 	MNODETYPE_2_PFN(mnode, mtype, lo, hi);
 	hi++;
-#endif
 
 	/* use lower limit if given */
 	if (pfnhi != PFNNULL && pfnhi < hi)
--- a/usr/src/uts/common/vm/vm_usage.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/common/vm/vm_usage.c	Mon Jul 20 13:07:46 2009 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -111,11 +111,11 @@
  *    - visited page ranges for each collective.
  *	   - per vnode (entity->vme_vnode_hash)
  *	   - per shared amp (entity->vme_amp_hash)
- *	For accurate counting of map-shared and cow-shared pages.
+ *	For accurate counting of map-shared and COW-shared pages.
  *
  *    - visited private anons (refcnt > 1) for each collective.
  *	(entity->vme_anon_hash)
- *	For accurate counting of cow-shared pages.
+ *	For accurate counting of COW-shared pages.
  *
  * The common accounting structure is the vmu_entity_t, which represents
  * collectives:
@@ -152,6 +152,7 @@
 #include <sys/vm_usage.h>
 #include <sys/zone.h>
 #include <sys/sunddi.h>
+#include <sys/avl.h>
 #include <vm/anon.h>
 #include <vm/as.h>
 #include <vm/seg_vn.h>
@@ -167,13 +168,19 @@
 #define	VMUSAGE_BOUND_INCORE		1
 #define	VMUSAGE_BOUND_NOT_INCORE	2
 
+#define	ISWITHIN(node, addr)	((node)->vmb_start <= addr && \
+				    (node)->vmb_end >= addr ? 1 : 0)
+
 /*
  * bounds for vnodes and shared amps
  * Each bound is either entirely incore, entirely not in core, or
- * entirely unknown.  bounds are stored in order by offset.
+ * entirely unknown.  bounds are stored in an avl tree sorted by start member
+ * when in use, otherwise (free or temporary lists) they're strung
+ * together off of vmb_next.
  */
 typedef struct vmu_bound {
-	struct  vmu_bound *vmb_next;
+	avl_node_t vmb_node;
+	struct vmu_bound *vmb_next; /* NULL in tree else on free or temp list */
 	pgcnt_t vmb_start;  /* page offset in vnode/amp on which bound starts */
 	pgcnt_t	vmb_end;    /* page offset in vnode/amp on which bound ends */
 	char	vmb_type;   /* One of VMUSAGE_BOUND_* */
@@ -188,7 +195,7 @@
 	struct vmu_object	*vmo_next;	/* free list */
 	caddr_t		vmo_key;
 	short		vmo_type;
-	vmu_bound_t	*vmo_bounds;
+	avl_tree_t	vmo_bounds;
 } vmu_object_t;
 
 /*
@@ -214,7 +221,7 @@
 	struct vmu_entity *vme_next_calc;
 	mod_hash_t	*vme_vnode_hash; /* vnodes visited for entity */
 	mod_hash_t	*vme_amp_hash;	 /* shared amps visited for entity */
-	mod_hash_t	*vme_anon_hash;	 /* cow anons visited for entity */
+	mod_hash_t	*vme_anon_hash;	 /* COW anons visited for entity */
 	vmusage_t	vme_result;	 /* identifies entity and results */
 } vmu_entity_t;
 
@@ -298,12 +305,34 @@
 static kmem_cache_t *vmu_object_cache;
 
 /*
- * Save a bound on the free list
+ * Comparison routine for AVL tree. We base our comparison on vmb_start.
+ */
+static int
+bounds_cmp(const void *bnd1, const void *bnd2)
+{
+	const vmu_bound_t *bound1 = bnd1;
+	const vmu_bound_t *bound2 = bnd2;
+
+	if (bound1->vmb_start == bound2->vmb_start) {
+		return (0);
+	}
+	if (bound1->vmb_start < bound2->vmb_start) {
+		return (-1);
+	}
+
+	return (1);
+}
+
+/*
+ * Save a bound on the free list.
  */
 static void
 vmu_free_bound(vmu_bound_t *bound)
 {
 	bound->vmb_next = vmu_data.vmu_free_bounds;
+	bound->vmb_start = 0;
+	bound->vmb_end = 0;
+	bound->vmb_type = 0;
 	vmu_data.vmu_free_bounds = bound;
 }
 
@@ -314,14 +343,15 @@
 vmu_free_object(mod_hash_val_t val)
 {
 	vmu_object_t *obj = (vmu_object_t *)val;
-	vmu_bound_t *bound = obj->vmo_bounds;
-	vmu_bound_t *tmp;
+	avl_tree_t *tree = &(obj->vmo_bounds);
+	vmu_bound_t *bound;
+	void *cookie = NULL;
 
-	while (bound != NULL) {
-		tmp = bound;
-		bound = bound->vmb_next;
-		vmu_free_bound(tmp);
-	}
+	while ((bound = avl_destroy_nodes(tree, &cookie)) != NULL)
+		vmu_free_bound(bound);
+	avl_destroy(tree);
+
+	obj->vmo_type = 0;
 	obj->vmo_next = vmu_data.vmu_free_objects;
 	vmu_data.vmu_free_objects = obj;
 }
@@ -530,9 +560,10 @@
 		object = kmem_cache_alloc(vmu_object_cache, KM_SLEEP);
 	}
 
+	object->vmo_next = NULL;
 	object->vmo_key = key;
 	object->vmo_type = type;
-	object->vmo_bounds = NULL;
+	avl_create(&(object->vmo_bounds), bounds_cmp, sizeof (vmu_bound_t), 0);
 
 	return (object);
 }
@@ -549,11 +580,14 @@
 		bound = vmu_data.vmu_free_bounds;
 		vmu_data.vmu_free_bounds =
 		    vmu_data.vmu_free_bounds->vmb_next;
-		bzero(bound, sizeof (vmu_bound_t));
 	} else {
 		bound = kmem_cache_alloc(vmu_bound_cache, KM_SLEEP);
-		bzero(bound, sizeof (vmu_bound_t));
 	}
+
+	bound->vmb_next = NULL;
+	bound->vmb_start = 0;
+	bound->vmb_end = 0;
+	bound->vmb_type = 0;
 	return (bound);
 }
 
@@ -630,120 +664,117 @@
 vmu_insert_lookup_object_bounds(vmu_object_t *ro, pgcnt_t start, pgcnt_t
     end, char type, vmu_bound_t **first, vmu_bound_t **last)
 {
-	vmu_bound_t *next;
-	vmu_bound_t *prev = NULL;
-	vmu_bound_t *tmp = NULL;
-	pgcnt_t ret = 0;
+	avl_tree_t	*tree = &(ro->vmo_bounds);
+	avl_index_t	where;
+	vmu_bound_t	*walker, *tmp;
+	pgcnt_t		ret = 0;
+
+	ASSERT(start <= end);
 
 	*first = *last = NULL;
 
-	for (next = ro->vmo_bounds; next != NULL; next = next->vmb_next) {
-		/*
-		 * Find bounds overlapping or overlapped by range [start,end].
-		 */
-		if (start > next->vmb_end) {
-			/* bound is before new bound */
-			prev = next;
-			continue;
+	tmp = vmu_alloc_bound();
+	tmp->vmb_start = start;
+	tmp->vmb_type = type;
+
+	/* Hopelessly optimistic case. */
+	if (walker = avl_find(tree, tmp, &where)) {
+		/* We got lucky. */
+		vmu_free_bound(tmp);
+		*first = walker;
+	}
+
+	if (walker == NULL) {
+		/* Is start in the previous node? */
+		walker = avl_nearest(tree, where, AVL_BEFORE);
+		if (walker != NULL) {
+			if (ISWITHIN(walker, start)) {
+				/* We found start. */
+				vmu_free_bound(tmp);
+				*first = walker;
+			}
 		}
-		if (next->vmb_start > end) {
-			/* bound is after new bound */
-			break;
-		}
-		if (*first == NULL)
-			*first = next;
-		*last = next;
 	}
 
+	/*
+	 * At this point, if *first is still NULL, then we
+	 * didn't get a direct hit and start isn't covered
+	 * by the previous node. We know that the next node
+	 * must have a greater start value than we require
+	 * because avl_find tells us where the AVL routines would
+	 * insert our new node. We have some gap between the
+	 * start we want and the next node.
+	 */
 	if (*first == NULL) {
-		ASSERT(*last == NULL);
-		/*
-		 * No bounds overlapping range [start,end], so create new
-		 * bound
-		 */
-		tmp = vmu_alloc_bound();
-		tmp->vmb_start = start;
-		tmp->vmb_end = end;
-		tmp->vmb_type = type;
-		if (prev == NULL) {
-			tmp->vmb_next = ro->vmo_bounds;
-			ro->vmo_bounds = tmp;
+		walker = avl_nearest(tree, where, AVL_AFTER);
+		if (walker != NULL && walker->vmb_start <= end) {
+			/* Fill the gap. */
+			tmp->vmb_end = walker->vmb_start - 1;
+			*first = tmp;
 		} else {
-			tmp->vmb_next = prev->vmb_next;
-			prev->vmb_next = tmp;
+			/* We have a gap over [start, end]. */
+			tmp->vmb_end = end;
+			*first = *last = tmp;
 		}
-		*first = tmp;
-		*last = tmp;
-		ASSERT(tmp->vmb_end >= tmp->vmb_start);
-		ret = tmp->vmb_end - tmp->vmb_start + 1;
+		ret += tmp->vmb_end - tmp->vmb_start + 1;
+		avl_insert(tree, tmp, where);
+	}
+
+	ASSERT(*first != NULL);
+
+	if (*last != NULL) {
+		/* We're done. */
 		return (ret);
 	}
 
-	/* Check to see if start is before first known bound */
-	ASSERT(first != NULL && last != NULL);
-	next = (*first);
-	if (start < (*first)->vmb_start) {
-		/* Create new bound before first bound */
-		tmp = vmu_alloc_bound();
-		tmp->vmb_start = start;
-		tmp->vmb_end = (*first)->vmb_start - 1;
-		tmp->vmb_type = type;
-		tmp->vmb_next = *first;
-		if (*first == ro->vmo_bounds)
-			ro->vmo_bounds = tmp;
-		if (prev != NULL)
-			prev->vmb_next = tmp;
-		ASSERT(tmp->vmb_end >= tmp->vmb_start);
-		ret += tmp->vmb_end - tmp->vmb_start + 1;
-		*first = tmp;
-	}
 	/*
-	 * Between start and end, search for gaps between and after existing
-	 * bounds.  Create new bounds to fill gaps if they exist.
+	 * If we are here we still need to set *last and
+	 * that may involve filling in some gaps.
 	 */
-	while (end > next->vmb_end) {
-		/*
-		 * Check for gap between bound and next bound. if no gap,
-		 * continue.
-		 */
-		if ((next != *last) &&
-		    ((next->vmb_end + 1) == next->vmb_next->vmb_start)) {
-			next = next->vmb_next;
-			continue;
+	*last = *first;
+	for (;;) {
+		if (ISWITHIN(*last, end)) {
+			/* We're done. */
+			break;
 		}
-		/*
-		 * Insert new bound in gap after bound, and before next
-		 * bound if next bound exists.
-		 */
-		tmp = vmu_alloc_bound();
-		tmp->vmb_type = type;
-		tmp->vmb_next = next->vmb_next;
-		tmp->vmb_start = next->vmb_end + 1;
-
-		if (next != *last) {
-			tmp->vmb_end = next->vmb_next->vmb_start - 1;
-			ASSERT(tmp->vmb_end >= tmp->vmb_start);
+		walker = AVL_NEXT(tree, *last);
+		if (walker == NULL || walker->vmb_start > end) {
+			/* Bottom or mid tree with gap. */
+			tmp = vmu_alloc_bound();
+			tmp->vmb_start = (*last)->vmb_end + 1;
+			tmp->vmb_end = end;
 			ret += tmp->vmb_end - tmp->vmb_start + 1;
-			next->vmb_next = tmp;
-			next = tmp->vmb_next;
-		} else {
-			tmp->vmb_end = end;
-			ASSERT(tmp->vmb_end >= tmp->vmb_start);
-			ret += tmp->vmb_end - tmp->vmb_start + 1;
-			next->vmb_next = tmp;
+			avl_insert_here(tree, tmp, *last, AVL_AFTER);
 			*last = tmp;
 			break;
+		} else {
+			if ((*last)->vmb_end + 1 != walker->vmb_start) {
+				/* Non-contiguous. */
+				tmp = vmu_alloc_bound();
+				tmp->vmb_start = (*last)->vmb_end + 1;
+				tmp->vmb_end = walker->vmb_start - 1;
+				ret += tmp->vmb_end - tmp->vmb_start + 1;
+				avl_insert_here(tree, tmp, *last, AVL_AFTER);
+				*last = tmp;
+			} else {
+				*last = walker;
+			}
 		}
 	}
+
 	return (ret);
 }
 
 /*
  * vmu_update_bounds()
  *
+ * tree: avl_tree in which first and last hang.
+ *
  * first, last:	list of continuous bounds, of which zero or more are of
  * 		type VMUSAGE_BOUND_UNKNOWN.
  *
+ * new_tree: avl_tree in which new_first and new_last hang.
+ *
  * new_first, new_last:	list of continuous bounds, of which none are of
  *			type VMUSAGE_BOUND_UNKNOWN.  These bounds are used to
  *			update the types of bounds in (first,last) with
@@ -763,8 +794,8 @@
  *
  */
 static pgcnt_t
-vmu_update_bounds(vmu_bound_t **first, vmu_bound_t **last,
-    vmu_bound_t *new_first, vmu_bound_t *new_last)
+vmu_update_bounds(avl_tree_t *tree, vmu_bound_t **first, vmu_bound_t **last,
+    avl_tree_t *new_tree, vmu_bound_t *new_first, vmu_bound_t *new_last)
 {
 	vmu_bound_t *next, *new_next, *tmp;
 	pgcnt_t rss = 0;
@@ -777,19 +808,19 @@
 	 * have unknown type.
 	 */
 	ASSERT((*first)->vmb_type != VMUSAGE_BOUND_UNKNOWN ||
-	    (*first)->vmb_start >= new_next->vmb_start);
+	    (*first)->vmb_start >= new_first->vmb_start);
 	ASSERT((*last)->vmb_type != VMUSAGE_BOUND_UNKNOWN ||
 	    (*last)->vmb_end <= new_last->vmb_end);
 	for (;;) {
-		/* If bound already has type, proceed to next bound */
+		/* If bound already has type, proceed to next bound. */
 		if (next->vmb_type != VMUSAGE_BOUND_UNKNOWN) {
 			if (next == *last)
 				break;
-			next = next->vmb_next;
+			next = AVL_NEXT(tree, next);
 			continue;
 		}
 		while (new_next->vmb_end < next->vmb_start)
-			new_next = new_next->vmb_next;
+			new_next = AVL_NEXT(new_tree, new_next);
 		ASSERT(new_next->vmb_type != VMUSAGE_BOUND_UNKNOWN);
 		next->vmb_type = new_next->vmb_type;
 		if (new_next->vmb_end < next->vmb_end) {
@@ -798,9 +829,8 @@
 			tmp->vmb_type = VMUSAGE_BOUND_UNKNOWN;
 			tmp->vmb_start = new_next->vmb_end + 1;
 			tmp->vmb_end = next->vmb_end;
-			tmp->vmb_next = next->vmb_next;
+			avl_insert_here(tree, tmp, next, AVL_AFTER);
 			next->vmb_end = new_next->vmb_end;
-			next->vmb_next = tmp;
 			if (*last == next)
 				*last = tmp;
 			if (next->vmb_type == VMUSAGE_BOUND_INCORE)
@@ -811,41 +841,40 @@
 				rss += next->vmb_end - next->vmb_start + 1;
 			if (next == *last)
 				break;
-			next = next->vmb_next;
+			next = AVL_NEXT(tree, next);
 		}
 	}
 	return (rss);
 }
 
 /*
- * merges adjacent bounds with same type between first and last bound.
+ * Merges adjacent bounds with same type between first and last bound.
  * After merge, last pointer is no longer valid, as last bound may be
  * merged away.
  */
 static void
-vmu_merge_bounds(vmu_bound_t **first, vmu_bound_t **last)
+vmu_merge_bounds(avl_tree_t *tree, vmu_bound_t **first, vmu_bound_t **last)
 {
+	vmu_bound_t *current;
 	vmu_bound_t *next;
-	vmu_bound_t *tmp;
 
+	ASSERT(tree != NULL);
 	ASSERT(*first != NULL);
 	ASSERT(*last != NULL);
 
-	next = *first;
-	while (next != *last) {
-
-		/* If bounds are adjacent and have same type, merge them */
-		if (((next->vmb_end + 1) == next->vmb_next->vmb_start) &&
-		    (next->vmb_type == next->vmb_next->vmb_type)) {
-			tmp = next->vmb_next;
-			next->vmb_end = tmp->vmb_end;
-			next->vmb_next = tmp->vmb_next;
-			vmu_free_bound(tmp);
-			if (tmp == *last)
-				*last = next;
-		} else {
-			next = next->vmb_next;
+	current = *first;
+	while (current != *last) {
+		next = AVL_NEXT(tree, current);
+		if ((current->vmb_end + 1) == next->vmb_start &&
+		    current->vmb_type == next->vmb_type) {
+			current->vmb_end = next->vmb_end;
+			avl_remove(tree, next);
+			vmu_free_bound(next);
+			if (next == *last) {
+				break;
+			}
 		}
+		current = AVL_NEXT(tree, current);
 	}
 }
 
@@ -855,14 +884,14 @@
  *
  * If a bound is partially incore, it will be split into two bounds.
  * first and last may be modified, as bounds may be split into multiple
- * bounds if the are partially incore/not-incore.
+ * bounds if they are partially incore/not-incore.
  *
- * Set incore to non-zero if bounds are already known to be incore
+ * Set incore to non-zero if bounds are already known to be incore.
  *
  */
 static void
-vmu_amp_update_incore_bounds(struct anon_map *amp, vmu_bound_t **first,
-    vmu_bound_t **last, boolean_t incore)
+vmu_amp_update_incore_bounds(avl_tree_t *tree, struct anon_map *amp,
+    vmu_bound_t **first, vmu_bound_t **last, boolean_t incore)
 {
 	vmu_bound_t *next;
 	vmu_bound_t *tmp;
@@ -874,7 +903,7 @@
 	struct anon *ap;
 
 	next = *first;
-	/* Shared anon slots don't change once set */
+	/* Shared anon slots don't change once set. */
 	ANON_LOCK_ENTER(&amp->a_rwlock, RW_READER);
 	for (;;) {
 		if (incore == B_TRUE)
@@ -883,7 +912,7 @@
 		if (next->vmb_type != VMUSAGE_BOUND_UNKNOWN) {
 			if (next == *last)
 				break;
-			next = next->vmb_next;
+			next = AVL_NEXT(tree, next);
 			continue;
 		}
 		bound_type = next->vmb_type;
@@ -919,16 +948,15 @@
 				next->vmb_type = page_type;
 			} else if (next->vmb_type != page_type) {
 				/*
-				 * if current bound type does not match page
+				 * If current bound type does not match page
 				 * type, need to split off new bound.
 				 */
 				tmp = vmu_alloc_bound();
 				tmp->vmb_type = page_type;
 				tmp->vmb_start = index;
 				tmp->vmb_end = next->vmb_end;
-				tmp->vmb_next = next->vmb_next;
+				avl_insert_here(tree, tmp, next, AVL_AFTER);
 				next->vmb_end = index - 1;
-				next->vmb_next = tmp;
 				if (*last == next)
 					*last = tmp;
 				next = tmp;
@@ -947,7 +975,7 @@
 			ASSERT(next->vmb_type != VMUSAGE_BOUND_UNKNOWN);
 			break;
 		} else
-			next = next->vmb_next;
+			next = AVL_NEXT(tree, next);
 	}
 	ANON_LOCK_EXIT(&amp->a_rwlock);
 }
@@ -957,8 +985,8 @@
  * incore-/not-incore for vnodes.
  */
 static void
-vmu_vnode_update_incore_bounds(vnode_t *vnode, vmu_bound_t **first,
-    vmu_bound_t **last)
+vmu_vnode_update_incore_bounds(avl_tree_t *tree, vnode_t *vnode,
+    vmu_bound_t **first, vmu_bound_t **last)
 {
 	vmu_bound_t *next;
 	vmu_bound_t *tmp;
@@ -974,7 +1002,7 @@
 		if (next->vmb_type != VMUSAGE_BOUND_UNKNOWN) {
 			if (next == *last)
 				break;
-			next = next->vmb_next;
+			next = AVL_NEXT(tree, next);
 			continue;
 		}
 
@@ -1007,16 +1035,15 @@
 				next->vmb_type = page_type;
 			} else if (next->vmb_type != page_type) {
 				/*
-				 * if current bound type does not match page
+				 * If current bound type does not match page
 				 * type, need to split off new bound.
 				 */
 				tmp = vmu_alloc_bound();
 				tmp->vmb_type = page_type;
 				tmp->vmb_start = index;
 				tmp->vmb_end = next->vmb_end;
-				tmp->vmb_next = next->vmb_next;
+				avl_insert_here(tree, tmp, next, AVL_AFTER);
 				next->vmb_end = index - 1;
-				next->vmb_next = tmp;
 				if (*last == next)
 					*last = tmp;
 				next = tmp;
@@ -1035,15 +1062,15 @@
 			ASSERT(next->vmb_type != VMUSAGE_BOUND_UNKNOWN);
 			break;
 		} else
-			next = next->vmb_next;
+			next = AVL_NEXT(tree, next);
 	}
 }
 
 /*
  * Calculate the rss and swap consumed by a segment.  vmu_entities is the
  * list of entities to visit.  For shared segments, the vnode or amp
- * is looked up in each entity to see if has been already counted.  Private
- * anon pages are checked per entity to ensure that cow pages are not
+ * is looked up in each entity to see if it has been already counted.  Private
+ * anon pages are checked per entity to ensure that COW pages are not
  * double counted.
  *
  * For private mapped files, first the amp is checked for private pages.
@@ -1060,6 +1087,7 @@
 	vmu_object_t *entity_object = NULL;
 	vmu_entity_t *entity;
 	vmusage_t *result;
+	avl_tree_t *tree;
 	vmu_bound_t *first = NULL;
 	vmu_bound_t *last = NULL;
 	vmu_bound_t *cur = NULL;
@@ -1074,7 +1102,7 @@
 	pgcnt_t swresv = 0;
 	pgcnt_t panon = 0;
 
-	/* Can zero-length segments exist?  Not sure, so parenoia */
+	/* Can zero-length segments exist?  Not sure, so paranoia. */
 	if (seg->s_size <= 0)
 		return;
 
@@ -1085,11 +1113,31 @@
 	 */
 	if (seg->s_ops == &segvn_ops) {
 		svd = (struct segvn_data *)seg->s_data;
-		if (svd->type == MAP_SHARED)
+		if (svd->type == MAP_SHARED) {
 			shared = B_TRUE;
-		else
+		} else {
 			swresv = svd->swresv;
 
+			if (SEGVN_LOCK_TRYENTER(seg->s_as, &svd->lock,
+			    RW_READER) != 0) {
+				/*
+				 * Text replication anon maps can be shared
+				 * across all zones. Space used for text
+				 * replication is typically capped as a small %
+				 * of memory.  To keep it simple for now we
+				 * don't account for swap and memory space used
+				 * for text replication.
+				 */
+				if (svd->tr_state == SEGVN_TR_OFF &&
+				    svd->amp != NULL) {
+					private_amp = svd->amp;
+					p_start = svd->anon_index;
+					p_end = svd->anon_index +
+					    btop(seg->s_size) - 1;
+				}
+				SEGVN_LOCK_EXIT(seg->s_as, &svd->lock);
+			}
+		}
 		if (svd->vp != NULL) {
 			file = 1;
 			shared_object = vmu_find_insert_object(
@@ -1109,20 +1157,6 @@
 			if (svd->amp->swresv == 0)
 				incore = B_TRUE;
 		}
-		SEGVN_LOCK_ENTER(seg->s_as, &svd->lock, RW_READER);
-		/*
-		 * Text replication anon maps can be shared across all zones.
-		 * Space used for text replication is typically capped as
-		 * small % of memory.  To keep it simple for now we don't
-		 * account for swap and memory space used for text replication.
-		 */
-		if (svd->tr_state == SEGVN_TR_OFF && svd->amp != NULL &&
-		    svd->type == MAP_PRIVATE) {
-			private_amp = svd->amp;
-			p_start = svd->anon_index;
-			p_end = svd->anon_index + btop(seg->s_size) - 1;
-		}
-		SEGVN_LOCK_EXIT(seg->s_as, &svd->lock);
 	} else if (seg->s_ops == &segspt_shmops) {
 		shared = B_TRUE;
 		shmd = (struct shm_data *)seg->s_data;
@@ -1143,15 +1177,15 @@
 
 	/*
 	 * If there is a private amp, count anon pages that exist.  If an
-	 * anon has a refcnt > 1 (cow sharing), then save the anon in a
+	 * anon has a refcnt > 1 (COW sharing), then save the anon in a
 	 * hash so that it is not double counted.
 	 *
-	 * If there is also a shared object, they figure out the bounds
+	 * If there is also a shared object, then figure out the bounds
 	 * which are not mapped by the private amp.
 	 */
 	if (private_amp != NULL) {
 
-		/* Enter as writer to prevent cow anons from being freed */
+		/* Enter as writer to prevent COW anons from being freed */
 		ANON_LOCK_ENTER(&private_amp->a_rwlock, RW_WRITER);
 
 		p_index = p_start;
@@ -1185,7 +1219,7 @@
 				ap = NULL;
 			}
 			/*
-			 * For cow segments, keep track of bounds not
+			 * For COW segments, keep track of bounds not
 			 * backed by private amp so they can be looked
 			 * up in the backing vnode
 			 */
@@ -1199,7 +1233,6 @@
 
 				if (shared_object != NULL) {
 					cur = vmu_alloc_bound();
-					cur->vmb_next = NULL;
 					cur->vmb_start = s_index;
 					cur->vmb_end = s_index + p_bound_size;
 					cur->vmb_type = VMUSAGE_BOUND_UNKNOWN;
@@ -1270,7 +1303,7 @@
 
 			/*
 			 * Assume anon structs with a refcnt
-			 * of 1 are not cow shared, so there
+			 * of 1 are not COW shared, so there
 			 * is no reason to track them per entity.
 			 */
 			if (cnt == 1) {
@@ -1282,7 +1315,7 @@
 
 				result = &entity->vme_result;
 				/*
-				 * Track cow anons per entity so
+				 * Track COW anons per entity so
 				 * they are not double counted.
 				 */
 				if (vmu_find_insert_anon(entity->vme_anon_hash,
@@ -1318,7 +1351,6 @@
 			 * the shared object.
 			 */
 			first = vmu_alloc_bound();
-			first->vmb_next = NULL;
 			first->vmb_start = s_start;
 			first->vmb_end = s_end;
 			first->vmb_type = VMUSAGE_BOUND_UNKNOWN;
@@ -1334,21 +1366,26 @@
 			    cur->vmb_start, cur->vmb_end, VMUSAGE_BOUND_UNKNOWN,
 			    &first, &last) > 0) {
 				/* new bounds, find incore/not-incore */
+				tree = &(shared_object->vmo_bounds);
 				if (shared_object->vmo_type ==
-				    VMUSAGE_TYPE_VNODE)
+				    VMUSAGE_TYPE_VNODE) {
 					vmu_vnode_update_incore_bounds(
+					    tree,
 					    (vnode_t *)
 					    shared_object->vmo_key, &first,
 					    &last);
-				else
+				} else {
 					vmu_amp_update_incore_bounds(
+					    tree,
 					    (struct anon_map *)
 					    shared_object->vmo_key, &first,
 					    &last, incore);
-				vmu_merge_bounds(&first, &last);
+				}
+				vmu_merge_bounds(tree, &first, &last);
 			}
 			for (entity = vmu_entities; entity != NULL;
 			    entity = entity->vme_next_calc) {
+				avl_tree_t *e_tree;
 
 				result = &entity->vme_result;
 
@@ -1368,8 +1405,9 @@
 				/*
 				 * Range visited for this entity
 				 */
-				rss = vmu_update_bounds(&e_first,
-				    &e_last, first, last);
+				e_tree = &(entity_object->vmo_bounds);
+				rss = vmu_update_bounds(e_tree, &e_first,
+				    &e_last, tree, first, last);
 				result->vmu_rss_all += (rss << PAGESHIFT);
 				if (shared == B_TRUE && file == B_FALSE) {
 					/* shared anon mapping */
@@ -1389,7 +1427,7 @@
 					result->vmu_rss_private +=
 					    (rss << PAGESHIFT);
 				}
-				vmu_merge_bounds(&e_first, &e_last);
+				vmu_merge_bounds(e_tree, &e_first, &e_last);
 			}
 			tmp = cur;
 			cur = cur->vmb_next;
--- a/usr/src/uts/i86pc/boot/boot_console.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/i86pc/boot/boot_console.c	Mon Jul 20 13:07:46 2009 -0400
@@ -234,6 +234,7 @@
 find_boot_line_prop(const char *name)
 {
 	char *ptr;
+	char *ret = NULL;
 	char end_char;
 	size_t len;
 
@@ -256,14 +257,14 @@
 			    !ISSPACE(*ptr))
 				ptr++;
 			if (*ptr == '\0')
-				return (NULL);
+				goto out;
 			else if (*ptr != 'B')
 				continue;
 		} else {
 			while ((*ptr != '\0') && !ISSPACE(*ptr))
 				ptr++;
 			if (*ptr == '\0')
-				return (NULL);
+				goto out;
 			continue;
 		}
 
@@ -274,10 +275,15 @@
 			if ((strncmp(ptr, name, len) == 0) &&
 			    (ptr[len] == '=')) {
 				ptr += len + 1;
-				if ((*ptr == '\'') || (*ptr == '"'))
-					return (ptr + 1);
-				else
-					return (ptr);
+				if ((*ptr == '\'') || (*ptr == '"')) {
+					ret = ptr + 1;
+					end_char = *ptr;
+					ptr++;
+				} else {
+					ret = ptr;
+					end_char = ',';
+				}
+				goto consume_property;
 			}
 
 			/*
@@ -295,7 +301,7 @@
 			 * name without a value, either continue or break.
 			 */
 			if (*ptr == '\0')
-				return (NULL);
+				goto out;
 			else if (*ptr == ',')
 				continue;
 			else if (ISSPACE(*ptr))
@@ -307,6 +313,7 @@
 			 */
 			if ((*ptr == '\'') || (*ptr == '"')) {
 				end_char = *ptr;
+				ptr++;
 			} else {
 				/*
 				 * Not quoted, so the string ends at a comma
@@ -320,15 +327,17 @@
 			 * Now, we can ignore any characters until we find
 			 * end_char.
 			 */
+consume_property:
 			for (; (*ptr != '\0') && (*ptr != end_char); ptr++) {
 				if ((end_char == ',') && ISSPACE(*ptr))
 					break;
 			}
-			if (*ptr && (*ptr != ','))
+			if (*ptr && (*ptr != ',') && !ISSPACE(*ptr))
 				ptr++;
 		} while (*ptr == ',');
 	}
-	return (NULL);
+out:
+	return (ret);
 }
 
 
@@ -657,7 +666,7 @@
 	console_value_t *consolep;
 	int i;
 
-	if (console != CONS_USBSER) {
+	if (console != CONS_USBSER && console != CONS_SCREEN_GRAPHICS) {
 		if (console_set) {
 			/*
 			 * If the console was set on the command line,
@@ -705,13 +714,11 @@
 			serial_init();
 			return;
 		}
-	}
-
-
-	/*
-	 * USB serial -- we just collect data into a buffer
-	 */
-	if (console == CONS_USBSER || console == CONS_SCREEN_GRAPHICS) {
+	} else {
+		/*
+		 * USB serial and GRAPHICS console
+		 * we just collect data into a buffer
+		 */
 		extern void *defcons_init(size_t);
 		defcons_buf = defcons_cur = defcons_init(MMU_PAGESIZE);
 	}
@@ -748,7 +755,8 @@
 static void
 defcons_putchar(int c)
 {
-	if (defcons_cur + 1 - defcons_buf < MMU_PAGESIZE) {
+	if (defcons_buf != NULL &&
+	    defcons_cur + 1 - defcons_buf < MMU_PAGESIZE) {
 		*defcons_cur++ = c;
 		*defcons_cur = 0;
 	}
--- a/usr/src/uts/i86pc/i86hvm/io/hvm_bootstrap.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/i86pc/i86hvm/io/hvm_bootstrap.c	Mon Jul 20 13:07:46 2009 -0400
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/modctl.h>
 #include <sys/sunddi.h>
 #include <sys/sunndi.h>
@@ -42,21 +40,29 @@
  * these nodes (which usually happens when mounting the root disk device
  * in an hvm environment).  See the block comments at the top of pv_cmdk.c
  * for more information about why this is necessary.
+ *
+ * hvmboot_rootconf() also force attaches xnf network driver nodes so
+ * that boot interface can be plumbed when booted via the network.
  */
 int
 hvmboot_rootconf()
 {
 	dev_info_t	*xpvd_dip;
-	major_t		xdf_major;
+	major_t		dev_major;
 
-	xdf_major = ddi_name_to_major("xdf");
-	if (xdf_major == (major_t)-1)
+	dev_major = ddi_name_to_major("xdf");
+	if (dev_major == (major_t)-1)
 		cmn_err(CE_PANIC, "unable to load xdf disk driver");
 
 	if (resolve_pathname("/xpvd", &xpvd_dip, NULL, NULL) != 0)
 		cmn_err(CE_PANIC, "unable to configure /xpvd nexus");
 
-	(void) ndi_devi_config_driver(xpvd_dip, 0, xdf_major);
+	(void) ndi_devi_config_driver(xpvd_dip, 0, dev_major);
+
+	dev_major = ddi_name_to_major("xnf");
+	if (dev_major == (major_t)-1)
+		cmn_err(CE_PANIC, "unable to load xnf network driver");
+	(void) ndi_devi_config_driver(xpvd_dip, 0, dev_major);
 
 	ndi_rele_devi(xpvd_dip);
 	return (0);
--- a/usr/src/uts/i86pc/io/isa.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/i86pc/io/isa.c	Mon Jul 20 13:07:46 2009 -0400
@@ -38,6 +38,7 @@
 #include <sys/psm.h>
 #include <sys/ddidmareq.h>
 #include <sys/ddi_impldefs.h>
+#include <sys/ddi_subrdefs.h>
 #include <sys/dma_engine.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
@@ -57,10 +58,10 @@
     psm_intr_op_t, int *);
 extern void pci_register_isa_resources(int, uint32_t, uint32_t);
 static char USED_RESOURCES[] = "used-resources";
-static void isa_alloc_nodes(dev_info_t *);
+static void isa_enumerate(int);
 static void enumerate_BIOS_serial(dev_info_t *);
 static void adjust_prtsz(dev_info_t *isa_dip);
-static void isa_postattach(dev_info_t *);
+static void isa_create_ranges_prop(dev_info_t *);
 
 /*
  * The following typedef is used to represent an entry in the "ranges"
@@ -228,13 +229,26 @@
 int
 _init(void)
 {
-	return (mod_install(&modlinkage));
+	int	err;
+
+	if ((err = mod_install(&modlinkage)) != 0)
+		return (err);
+
+	impl_bus_add_probe(isa_enumerate);
+	return (0);
 }
 
 int
 _fini(void)
 {
-	return (mod_remove(&modlinkage));
+	int	err;
+
+	impl_bus_delete_probe(isa_enumerate);
+
+	if ((err = mod_remove(&modlinkage)) != 0)
+		return (err);
+
+	return (0);
 }
 
 int
@@ -268,19 +282,8 @@
 		return (DDI_FAILURE);
 	}
 
-	bzero(isa_extra_resource, MAX_EXTRA_RESOURCE * sizeof (struct regspec));
-
-	if ((rval = i_dmae_init(devi)) == DDI_SUCCESS) {
+	if ((rval = i_dmae_init(devi)) == DDI_SUCCESS)
 		ddi_report_dev(devi);
-		/*
-		 * Enumerate children -- invoking ACPICA
-		 * This is normally in bus_config(), but we need this
-		 * to happen earlier to boot.
-		 */
-		isa_alloc_nodes(devi);
-	}
-
-	isa_postattach(devi);
 
 	return (rval);
 }
@@ -329,7 +332,7 @@
 }
 
 static void
-isa_postattach(dev_info_t *dip)
+isa_create_ranges_prop(dev_info_t *dip)
 {
 	dev_info_t *used;
 	int *ioarray, *memarray, status;
@@ -1036,11 +1039,11 @@
 }
 
 static void
-isa_alloc_nodes(dev_info_t *isa_dip)
+isa_enumerate(int reprogram)
 {
-	static int alloced = 0;
 	int circ, i;
 	dev_info_t *xdip;
+	dev_info_t *isa_dip = ddi_find_devinfo("isa", -1, 0);
 
 	/* hard coded isa stuff */
 	struct regspec asy_regs[] = {
@@ -1057,15 +1060,12 @@
 	char *acpi_prop;
 	int acpi_enum = 1; /* ACPI is default to be on */
 
-	if (alloced)
+	if (reprogram || !isa_dip)
 		return;
 
+	bzero(isa_extra_resource, MAX_EXTRA_RESOURCE * sizeof (struct regspec));
+
 	ndi_devi_enter(isa_dip, &circ);
-	if (alloced) {	/* just in case we are multi-threaded */
-		ndi_devi_exit(isa_dip, circ);
-		return;
-	}
-	alloced = 1;
 
 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
 	    DDI_PROP_DONTPASS, "acpi-enum", &acpi_prop) == DDI_PROP_SUCCESS) {
@@ -1086,6 +1086,8 @@
 
 			/* adjust parallel port size  */
 			adjust_prtsz(isa_dip);
+
+			isa_create_ranges_prop(isa_dip);
 			return;
 		}
 		cmn_err(CE_NOTE, "!Solaris did not detect ACPI BIOS");
@@ -1127,6 +1129,7 @@
 
 	ndi_devi_exit(isa_dip, circ);
 
+	isa_create_ranges_prop(isa_dip);
 }
 
 /*
--- a/usr/src/uts/i86pc/io/pcplusmp/apic.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/i86pc/io/pcplusmp/apic.c	Mon Jul 20 13:07:46 2009 -0400
@@ -118,6 +118,7 @@
 /* Now the ones for Dynamic Interrupt distribution */
 int	apic_enable_dynamic_migration = 0;
 
+int apic_have_32bit_cr8 = 0;
 
 /*
  * These variables are frequently accessed in apic_intr_enter(),
@@ -436,6 +437,9 @@
 	for (i = 0; i <= MAXIPL; i++)
 		apic_cr8pri[i] = apic_ipltopri[i] >> APIC_IPL_SHIFT;
 	CPU->cpu_pri_data = apic_cr8pri;
+#else
+	if (cpuid_have_cr8access(CPU))
+		apic_have_32bit_cr8 = 1;
 #endif	/* __amd64 */
 }
 
@@ -953,8 +957,12 @@
 			setcr8((ulong_t)(apic_ipltopri[nipl] >>
 			    APIC_IPL_SHIFT));
 #else
-			LOCAL_APIC_WRITE_REG(APIC_TASK_REG,
-			    (uint32_t)apic_ipltopri[nipl]);
+			if (apic_have_32bit_cr8)
+				setcr8((ulong_t)(apic_ipltopri[nipl] >>
+				    APIC_IPL_SHIFT));
+			else
+				LOCAL_APIC_WRITE_REG(APIC_TASK_REG,
+				    (uint32_t)apic_ipltopri[nipl]);
 #endif
 			LOCAL_APIC_WRITE_REG(APIC_EOI_REG, 0);
 		} else {
@@ -995,8 +1003,12 @@
 #if defined(__amd64)
 		setcr8((ulong_t)(apic_ipltopri[nipl] >> APIC_IPL_SHIFT));
 #else
-		LOCAL_APIC_WRITE_REG(APIC_TASK_REG,
-		    (uint32_t)apic_ipltopri[nipl]);
+		if (apic_have_32bit_cr8)
+			setcr8((ulong_t)(apic_ipltopri[nipl] >>
+			    APIC_IPL_SHIFT));
+		else
+			LOCAL_APIC_WRITE_REG(APIC_TASK_REG,
+			    (uint32_t)apic_ipltopri[nipl]);
 #endif
 	} else {
 		X2APIC_WRITE(APIC_TASK_REG, apic_ipltopri[nipl]);
@@ -1059,7 +1071,10 @@
 #if defined(__amd64)
 	setcr8((ulong_t)apic_cr8pri[prev_ipl]);
 #else
-	apicadr[APIC_TASK_REG] = apic_ipltopri[prev_ipl];
+	if (apic_have_32bit_cr8)
+		setcr8((ulong_t)(apic_ipltopri[prev_ipl] >> APIC_IPL_SHIFT));
+	else
+		apicadr[APIC_TASK_REG] = apic_ipltopri[prev_ipl];
 #endif
 
 	APIC_INTR_EXIT();
@@ -1098,7 +1113,10 @@
 #if defined(__amd64)
 	setcr8((ulong_t)apic_cr8pri[ipl]);
 #else
-	apicadr[APIC_TASK_REG] = apic_ipltopri[ipl];
+	if (apic_have_32bit_cr8)
+		setcr8((ulong_t)(apic_ipltopri[ipl] >> APIC_IPL_SHIFT));
+	else
+		apicadr[APIC_TASK_REG] = apic_ipltopri[ipl];
 #endif
 
 	/* interrupts at ipl above this cannot be in progress */
--- a/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c	Mon Jul 20 13:07:46 2009 -0400
@@ -83,6 +83,7 @@
 	apic_send_EOI,
 };
 
+extern int apic_have_32bit_cr8;
 
 /* The default ops is local APIC (Memory Mapped IO) */
 apic_reg_ops_t *apic_reg_ops = &local_apic_regs_ops;
@@ -119,6 +120,8 @@
 #if defined(__amd64)
 	return ((int)getcr8());
 #else
+	if (apic_have_32bit_cr8)
+		return ((int)getcr8());
 	return (apicadr[APIC_TASK_REG]);
 #endif
 }
@@ -129,7 +132,10 @@
 #if defined(__amd64)
 	setcr8((ulong_t)(value >> APIC_IPL_SHIFT));
 #else
-	apicadr[APIC_TASK_REG] = (uint32_t)value;
+	if (apic_have_32bit_cr8)
+		setcr8((ulong_t)(value >> APIC_IPL_SHIFT));
+	else
+		apicadr[APIC_TASK_REG] = (uint32_t)value;
 #endif
 }
 
--- a/usr/src/uts/i86pc/io/ppm.conf	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/i86pc/io/ppm.conf	Mon Jul 20 13:07:46 2009 -0400
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -105,6 +105,7 @@
     "Dell Inc.", "Latitude D630                   ",
     "Dell Inc.", "Precision M4300                 ",
     "Sun Microsystems", "Ultra 24",
+    "Sun Microsystems", "Ultra 27",
     "Sun Microsystems", "Sun Ultra 40 Workstation",
     "Sun Microsystems", "Sun Ultra 20 Workstation";
 
@@ -127,6 +128,7 @@
     "Dell Inc.", "Latitude D630                   ",
     "Dell Inc.", "Precision M4300                 ",
     "Sun Microsystems", "Ultra 24",
+    "Sun Microsystems", "Ultra 27",
     "Sun Microsystems", "Sun Ultra 40 Workstation",
     "Sun Microsystems", "Sun Ultra 20 Workstation";
 
@@ -149,6 +151,7 @@
     "Dell Inc.", "Latitude D630                   ",
     "Dell Inc.", "Precision M4300                 ",
     "Sun Microsystems", "Ultra 24",
+    "Sun Microsystems", "Ultra 27",
     "Sun Microsystems", "Sun Ultra 40 Workstation",
     "Sun Microsystems", "Sun Ultra 20 Workstation";
 
--- a/usr/src/uts/i86pc/os/cpuid.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/i86pc/os/cpuid.c	Mon Jul 20 13:07:46 2009 -0400
@@ -364,6 +364,11 @@
 		break;
 	case X86_VENDOR_AMD:
 		switch (eax) {
+
+		case 0x80000001:
+			cp->cp_ecx &= ~CPUID_AMD_ECX_CR8D;
+			break;
+
 		case 0x80000008:
 			/*
 			 * Zero out the (ncores-per-chip - 1) field
@@ -2535,6 +2540,24 @@
 	return (cpu->cpu_m.mcpu_cpi->cpi_clogid);
 }
 
+/*ARGSUSED*/
+int
+cpuid_have_cr8access(cpu_t *cpu)
+{
+#if defined(__amd64)
+	return (1);
+#else
+	struct cpuid_info *cpi;
+
+	ASSERT(cpu != NULL);
+	cpi = cpu->cpu_m.mcpu_cpi;
+	if (cpi->cpi_vendor == X86_VENDOR_AMD && cpi->cpi_maxeax >= 1 &&
+	    (CPI_FEATURES_XTD_ECX(cpi) & CPUID_AMD_ECX_CR8D) != 0)
+		return (1);
+	return (0);
+#endif
+}
+
 uint32_t
 cpuid_get_apicid(cpu_t *cpu)
 {
--- a/usr/src/uts/i86pc/os/ddi_impl.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/i86pc/os/ddi_impl.c	Mon Jul 20 13:07:46 2009 -0400
@@ -200,6 +200,9 @@
 	check_driver_disable();
 	i_ddi_init_root();
 
+	/* reprogram devices not set up by firmware (BIOS) */
+	impl_bus_reprobe();
+
 	/*
 	 * attach the isa nexus to get ACPI resource usage
 	 * isa is "kind of" a pseudo node
@@ -218,8 +221,6 @@
 		(void) i_ddi_attach_hw_nodes("isa");
 #endif
 
-	/* reprogram devices not set up by firmware (BIOS) */
-	impl_bus_reprobe();
 #endif	/* !SAS && !MPSAS */
 }
 
@@ -2588,11 +2589,21 @@
 impl_bus_add_probe(void (*func)(int))
 {
 	struct bus_probe *probe;
+	struct bus_probe *lastprobe = NULL;
 
 	probe = kmem_alloc(sizeof (*probe), KM_SLEEP);
-	probe->next = bus_probes;
 	probe->probe = func;
-	bus_probes = probe;
+	probe->next = NULL;
+
+	if (!bus_probes) {
+		bus_probes = probe;
+		return;
+	}
+
+	lastprobe = bus_probes;
+	while (lastprobe->next)
+		lastprobe = lastprobe->next;
+	lastprobe->next = probe;
 }
 
 /*ARGSUSED*/
@@ -2636,12 +2647,19 @@
 		if (modload("misc", "pci_autoconfig") < 0) {
 			panic("failed to load misc/pci_autoconfig");
 		}
+
+		if (modload("drv", "isa") < 0)
+			panic("failed to load drv/isa");
 	}
+
 	(void) modload("misc", "xpv_autoconfig");
 #else
 	if (modload("misc", "pci_autoconfig") < 0) {
 		panic("failed to load misc/pci_autoconfig");
 	}
+
+	if (modload("drv", "isa") < 0)
+		panic("failed to load drv/isa");
 #endif
 
 	probe = bus_probes;
--- a/usr/src/uts/i86pc/os/memnode.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/i86pc/os/memnode.c	Mon Jul 20 13:07:46 2009 -0400
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/systm.h>
 #include <sys/sysmacros.h>
 #include <sys/bootconf.h>
@@ -85,9 +83,6 @@
 		end = roundup(end, btop(mem_node_physalign)) - 1;
 	}
 
-	if (&plat_slice_add)
-		plat_slice_add(start, end);
-
 	mnode = PFN_2_MEM_NODE(start);
 	ASSERT(mnode < max_mem_nodes);
 
@@ -115,16 +110,6 @@
 	lgrp_config(LGRP_CONFIG_MEM_ADD, mnode, MEM_NODE_2_LGRPHAND(mnode));
 }
 
-/* ARGSUSED */
-void
-mem_node_pre_del_slice(pfn_t start, pfn_t end)
-{
-	int mnode = PFN_2_MEM_NODE(start);
-
-	ASSERT(mnode < max_mem_nodes);
-	ASSERT(mem_node_config[mnode].exists == 1);
-}
-
 /*
  * Remove a PFN range from a memnode.  On some platforms,
  * the memnode will be created with physbase at the first
@@ -133,7 +118,7 @@
  * to assume physbase and up.
  */
 void
-mem_node_post_del_slice(pfn_t start, pfn_t end, int cancelled)
+mem_node_del_slice(pfn_t start, pfn_t end)
 {
 	int mnode;
 	pgcnt_t delta_pgcnt, node_size;
@@ -148,43 +133,56 @@
 	ASSERT(mnode < max_mem_nodes);
 	ASSERT(mem_node_config[mnode].exists == 1);
 
-	if (!cancelled) {
-		delta_pgcnt = end - start;
-		node_size = mem_node_config[mnode].physmax -
-		    mem_node_config[mnode].physbase;
+	delta_pgcnt = end - start;
+	node_size = mem_node_config[mnode].physmax -
+	    mem_node_config[mnode].physbase;
+
+	if (node_size > delta_pgcnt) {
+		/*
+		 * Subtract the slice from the memnode.
+		 */
+		if (start <= mem_node_config[mnode].physbase)
+			mem_node_config[mnode].physbase = end + 1;
+		ASSERT(end <= mem_node_config[mnode].physmax);
+		if (end == mem_node_config[mnode].physmax)
+			mem_node_config[mnode].physmax = start - 1;
+	} else {
+		/*
+		 * Let the common lgrp framework know this mnode is
+		 * leaving
+		 */
+		lgrp_config(LGRP_CONFIG_MEM_DEL,
+		    mnode, MEM_NODE_2_LGRPHAND(mnode));
 
-		if (node_size > delta_pgcnt) {
-			/*
-			 * Subtract the slice from the memnode.
-			 */
-			if (start <= mem_node_config[mnode].physbase)
-				mem_node_config[mnode].physbase = end + 1;
-			ASSERT(end <= mem_node_config[mnode].physmax);
-			if (end == mem_node_config[mnode].physmax)
-				mem_node_config[mnode].physmax = start - 1;
-		} else {
-			/*
-			 * Let the common lgrp framework know this mnode is
-			 * leaving
-			 */
-			lgrp_config(LGRP_CONFIG_MEM_DEL,
-			    mnode, MEM_NODE_2_LGRPHAND(mnode));
+		/*
+		 * Delete the whole node.
+		 */
+		ASSERT(MNODE_PGCNT(mnode) == 0);
+		do {
+			omask = memnodes_mask;
+			nmask = omask & ~(1ull << mnode);
+		} while (cas64(&memnodes_mask, omask, nmask) != omask);
+		atomic_add_16(&num_memnodes, -1);
+		mem_node_config[mnode].exists = 0;
+	}
+}
 
-			/*
-			 * Delete the whole node.
-			 */
-			ASSERT(MNODE_PGCNT(mnode) == 0);
-			do {
-				omask = memnodes_mask;
-				nmask = omask & ~(1ull << mnode);
-			} while (cas64(&memnodes_mask, omask, nmask) != omask);
-			atomic_add_16(&num_memnodes, -1);
-			mem_node_config[mnode].exists = 0;
-		}
+void
+mem_node_add_range(pfn_t start, pfn_t end)
+{
+	if (&plat_slice_add)
+		plat_slice_add(start, end);
+	else
+		mem_node_add_slice(start, end);
+}
 
-		if (&plat_slice_del)
-			plat_slice_del(start, end);
-	}
+void
+mem_node_del_range(pfn_t start, pfn_t end)
+{
+	if (&plat_slice_del)
+		plat_slice_del(start, end);
+	else
+		mem_node_del_slice(start, end);
 }
 
 void
@@ -208,7 +206,7 @@
 			end = (list->address + list->size - 1) >> PAGESHIFT;
 			if (end > physmax)
 				end = physmax;
-			mem_node_add_slice(start, end);
+			mem_node_add_range(start, end);
 			list = list->next;
 		}
 		mem_node_physalign = 0;
--- a/usr/src/uts/i86pc/sys/memnode.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/i86pc/sys/memnode.h	Mon Jul 20 13:07:46 2009 -0400
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _SYS_MEMNODE_H
 #define	_SYS_MEMNODE_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -81,10 +79,11 @@
 
 extern void startup_build_mem_nodes(struct memlist *);
 extern void mem_node_add_slice(pfn_t, pfn_t);
-extern void mem_node_pre_del_slice(pfn_t, pfn_t);
-extern void mem_node_post_del_slice(pfn_t, pfn_t, int);
+extern void mem_node_del_slice(pfn_t, pfn_t);
 extern int mem_node_alloc(void);
 extern pgcnt_t mem_node_memlist_pages(int, struct memlist *);
+extern void mem_node_add_range(pfn_t, pfn_t);
+extern void mem_node_del_range(pfn_t, pfn_t);
 
 extern int plat_mnode_xcheck(pfn_t);
 
--- a/usr/src/uts/intel/Makefile.intel.shared	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/intel/Makefile.intel.shared	Mon Jul 20 13:07:46 2009 -0400
@@ -334,6 +334,7 @@
 DRV_KMODS	+= udp6
 DRV_KMODS	+= ucode
 DRV_KMODS	+= ural
+DRV_KMODS	+= uath
 DRV_KMODS	+= urtw
 DRV_KMODS	+= vgatext
 DRV_KMODS	+= heci
@@ -631,6 +632,7 @@
 MISC_KMODS	+= qlc_fw_6322
 MISC_KMODS	+= qlc_fw_8100
 MISC_KMODS	+= hwa1480_fw
+MISC_KMODS	+= uathfw
 MISC_KMODS	+= uwba
 
 $(CLOSED_BUILD)CLOSED_MISC_KMODS	+= klmmod klmops
@@ -710,11 +712,6 @@
 MAC_KMODS	+= mac_ib
 
 #
-# 'Devname' Modules (kernel/devname)
-#
-DEVNAME_KMODS	+= sdev_nsconfig_mod
-
-#
 # socketmod (kernel/socketmod)
 #
 SOCKET_KMODS	+= socksctp
--- a/usr/src/uts/intel/ia32/ml/i86_subr.s	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/intel/ia32/ml/i86_subr.s	Mon Jul 20 13:07:46 2009 -0400
@@ -580,6 +580,24 @@
         ret
 	SET_SIZE(setcr0)
 
+	/*
+	 * "lock mov %cr0" is used on processors which indicate it is
+	 * supported via CPUID. Normally the 32 bit TPR is accessed via
+	 * the local APIC.
+	 */
+	ENTRY(getcr8)
+	lock
+	movl	%cr0, %eax
+	ret
+	SET_SIZE(getcr8)
+
+	ENTRY(setcr8)
+        movl    4(%esp), %eax
+	lock
+        movl    %eax, %cr0
+	ret
+	SET_SIZE(setcr8)
+
         ENTRY(getcr2)
 #if defined(__xpv)
 	movl	%gs:CPU_VCPU_INFO, %eax
--- a/usr/src/uts/intel/ia32/ml/modstubs.s	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/intel/ia32/ml/modstubs.s	Mon Jul 20 13:07:46 2009 -0400
@@ -424,9 +424,7 @@
 	NO_UNLOAD_STUB(dev, sdev_modctl_readdir_free,	nomod_minus_one);
 	NO_UNLOAD_STUB(dev, devname_filename_register,	nomod_minus_one);
 	NO_UNLOAD_STUB(dev, sdev_modctl_devexists,	nomod_minus_one);
-	NO_UNLOAD_STUB(dev, devname_nsmaps_register,	nomod_minus_one);
 	NO_UNLOAD_STUB(dev, devname_profile_update,	nomod_minus_one);
-	NO_UNLOAD_STUB(dev, sdev_module_register,	nomod_minus_one);
 	NO_UNLOAD_STUB(dev, sdev_devstate_change,	nomod_minus_one);
 	NO_UNLOAD_STUB(dev, devvt_getvnodeops,		nomod_minus_one);
 	NO_UNLOAD_STUB(dev, devpts_getvnodeops,		nomod_zero);
--- a/usr/src/uts/intel/os/minor_perm	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/intel/os/minor_perm	Mon Jul 20 13:07:46 2009 -0400
@@ -144,6 +144,7 @@
 clone:rwd 0666 root sys
 clone:rwn 0666 root sys
 clone:simnet 0666 root sys
+clone:uath 0666 root sys
 clone:ural 0666 root sys
 clone:urtw 0666 root sys
 clone:wpi 0666 root sys
@@ -177,6 +178,7 @@
 rwd:* 0666 root sys
 rwn:* 0666 root sys
 simnet:* 0666 root sys
+uath:* 0666 root sys
 ural:* 0666 root sys
 urtw:* 0666 root sys
 wpi:* 0666 root sys
--- a/usr/src/uts/intel/sdev_nsconfig_mod/Makefile	Tue Jul 14 11:18:27 2009 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +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 2006 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# uts/intel/sdev_nsconfig_mod/Makefile
-#
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#
-#	Path to the base of the uts directory tree (usually /usr/src/uts).
-#
-UTSBASE	= ../..
-
-#
-#	Define the module and object file sets.
-#
-MODULE		= sdev_nsconfig_mod
-OBJECTS		= $(NSCONFIG_DEVNAME_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(NSCONFIG_DEVNAME_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_DEVNAME_DIR)/$(MODULE)
-
-#
-#	Include common rules.
-#
-include $(UTSBASE)/intel/Makefile.intel
-
-#
-#	Define targets
-#
-ALL_TARGET	= $(BINARY)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
-
-#
-#	Override defaults to build a unique, local modstubs.o.
-#
-MODSTUBS_DIR	 = $(OBJS_DIR)
-CLEANFILES	+= $(MODSTUBS_O)
-
-#
-# depends on fs/dev module
-#
-LDFLAGS += -dy -Nfs/dev
-
-#
-#	Default build targets.
-#
-.KEEP_STATE:
-
-def:		$(DEF_DEPS)
-
-all:		$(ALL_DEPS)
-
-clean:		$(CLEAN_DEPS)
-
-clobber:	$(CLOBBER_DEPS)
-
-lint:		$(LINT_DEPS)
-
-modlintlib:	$(MODLINTLIB_DEPS)
-
-clean.lint:	$(CLEAN_LINT_DEPS)
-
-install:	$(INSTALL_DEPS)
-
-#
-#	Include common targets.
-#
-include $(UTSBASE)/intel/Makefile.targ
-
--- a/usr/src/uts/intel/sys/archsystm.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/intel/sys/archsystm.h	Mon Jul 20 13:07:46 2009 -0400
@@ -45,6 +45,8 @@
 
 extern ulong_t getcr0(void);
 extern void setcr0(ulong_t);
+extern ulong_t getcr8(void);
+extern void setcr8(ulong_t);
 extern ulong_t getcr2(void);
 extern void iommu_cpu_nop(void);
 extern void clflush_insn(caddr_t addr);
--- a/usr/src/uts/intel/sys/x86_archext.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/intel/sys/x86_archext.h	Mon Jul 20 13:07:46 2009 -0400
@@ -629,6 +629,8 @@
 extern uint32_t cpuid_getsockettype(struct cpu *);
 extern const char *cpuid_getsocketstr(struct cpu *);
 
+extern int cpuid_have_cr8access(struct cpu *);
+
 extern int cpuid_opteron_erratum(struct cpu *, uint_t);
 
 struct cpuid_info;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/uath/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,97 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# This makefile drives the production of the uath driver kernel module.
+#
+# i86pc architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= uath
+OBJECTS		= $(UATH_OBJS:%=$(OBJS_DIR)/%)
+LINTS           = $(UATH_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+#	Driver depends on GLDv3 & wifi kernel support module.
+#
+LDFLAGS		+= -dy -Nmisc/mac -Nmisc/net80211 -Nmisc/usba
+
+#
+#	Overrides
+#
+LINTTAGS	+= -erroff=E_BAD_PTR_CAST_ALIGN
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
+
+#
+#	If you have any special case that general
+#	Makefile rules don't serve for you, just do
+#	it yourself.
+#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/uathfw/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,112 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+#	This makefile drives the production of the hwa1480_fw kernel module.
+#
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= uathfw
+OBJECTS		= $(UATHFW_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(UATHFW_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_MISC_DIR)/$(MODULE)
+
+FWOBJ		= $(OBJS_DIR)/$(MODULE).o
+
+OBJECTS		+= $(FWOBJ)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+LDFLAGS	= 
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+# For now, disable these lint checks; maintainers should endeavor
+# to investigate and remove these for maximum lint coverage.
+# Please do not carry these forward to new Makefiles.
+#
+LINTTAGS	+= -erroff=E_BAD_PTR_CAST_ALIGN
+LINTTAGS	+= -erroff=E_PTRDIFF_OVERFLOW
+LINTTAGS	+= -erroff=E_ASSIGN_NARROW_CONV
+LINTTAGS	+= -erroff=E_STATIC_UNUSED
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS) $(FWOBJ)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+		$(RM) $(BINDEST)/$(BINCOPY)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+
+# customized section for transforming firmware binary
+ELFWRAP		= elfwrap
+BINSRC		= $(UTSBASE)/common/io/uath/uath_fw
+BINDEST		= $(UTSBASE)/intel/uathfw
+BINCOPY		= uathbin
+ORIGIN_SRC	= uathfw.bin
+
+#get build type, 32/64
+WRAPTYPE	= $(CLASS:%=-%)
+
+#set elfwrap option
+WRAPOPT		= $(WRAPTYPE:-32=)
+
+$(FWOBJ):
+	cp $(BINSRC)/$(ORIGIN_SRC) $(BINDEST)/$(BINCOPY)
+	$(ELFWRAP) $(WRAPOPT) -o $@ $(BINDEST)/$(BINCOPY)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
+
--- a/usr/src/uts/sparc/Makefile.sparc.shared	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sparc/Makefile.sparc.shared	Mon Jul 20 13:07:46 2009 -0400
@@ -493,11 +493,6 @@
 MAC_KMODS	+= mac_ib
 
 #
-# 'Devname' Modules (kernel/devname)
-#
-DEVNAME_KMODS	+= sdev_nsconfig_mod
-
-#
 # socketmod (kernel/socketmod)
 #
 SOCKET_KMODS	+= socksctp
--- a/usr/src/uts/sparc/ml/modstubs.s	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sparc/ml/modstubs.s	Mon Jul 20 13:07:46 2009 -0400
@@ -312,9 +312,7 @@
 	NO_UNLOAD_STUB(dev, sdev_modctl_readdir_free,	nomod_minus_one);
 	NO_UNLOAD_STUB(dev, devname_filename_register,	nomod_minus_one);
 	NO_UNLOAD_STUB(dev, sdev_modctl_devexists,	nomod_minus_one);
-	NO_UNLOAD_STUB(dev, devname_nsmaps_register,	nomod_minus_one);
 	NO_UNLOAD_STUB(dev, devname_profile_update,	nomod_minus_one);
-	NO_UNLOAD_STUB(dev, sdev_module_register,	nomod_minus_one);
 	NO_UNLOAD_STUB(dev, sdev_devstate_change,	nomod_minus_one);
 	NO_UNLOAD_STUB(dev, devvt_getvnodeops,		nomod_minus_one);
 	NO_UNLOAD_STUB(dev, devpts_getvnodeops,		nomod_zero);
--- a/usr/src/uts/sparc/sdev_nsconfig_mod/Makefile	Tue Jul 14 11:18:27 2009 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +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
-#
-# uts/sparc/sdev_nsconfig_mod/Makefile
-#
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-#
-#	This makefile drives production of devname/sdev_nsconfig_mod module.
-#
-#
-#	Path to the base of the uts directory tree (usually /usr/src/uts).
-#
-UTSBASE	= ../..
-
-#
-#	Define the module and object file sets.
-#
-MODULE		= sdev_nsconfig_mod
-OBJECTS		= $(NSCONFIG_DEVNAME_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(NSCONFIG_DEVNAME_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_DEVNAME_DIR)/$(MODULE)
-
-#
-#	Include common rules.
-#
-include $(UTSBASE)/sparc/Makefile.sparc
-
-# 
-# lint pass one enforcement 
-# 
-CFLAGS += $(CCVERBOSE)
-
-# 
-# Dependencies
-#
-LDFLAGS += -dy -Nfs/dev
-
-#
-#       Define targets
-#
-ALL_TARGET      = $(BINARY)
-LINT_TARGET     = $(MODULE).lint
-INSTALL_TARGET  = $(BINARY) $(ROOTMODULE)
-
-
-.KEEP_STATE:
-
-def:            $(DEF_DEPS)
-
-all:            $(ALL_DEPS)
-
-clean:          $(CLEAN_DEPS)
-
-clobber:        $(CLOBBER_DEPS)
-
-lint:           $(LINT_DEPS)
-
-modlintlib:     $(MODLINTLIB_DEPS)
-
-clean.lint:     $(CLEAN_LINT_DEPS)
-
-install:        $(INSTALL_DEPS)
-
-#
-#       Include common targets.
-#
-include $(UTSBASE)/sparc/Makefile.targ
--- a/usr/src/uts/sun4/cpu/cpu_module.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4/cpu/cpu_module.c	Mon Jul 20 13:07:46 2009 -0400
@@ -82,6 +82,11 @@
 
 /*ARGSUSED*/
 void
+vtag_unmap_perm_tl1(uint64_t addr, uint64_t ctx)
+{}
+
+/*ARGSUSED*/
+void
 vac_flushpage(pfn_t pf, int color)
 {}
 
--- a/usr/src/uts/sun4/io/px/px_intr.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4/io/px/px_intr.c	Mon Jul 20 13:07:46 2009 -0400
@@ -715,27 +715,27 @@
 		break;
 	case DDI_INTROP_ENABLE:
 		/*
-		 * curr_nenables will be greater than 0 if rdip is using
-		 * MSI-X and also, if it is using DUP interface. If this
-		 * curr_enables is > 1, return after clearing the mask bit.
+		 * For MSI, just clear the mask bit and return if curr_nenables
+		 * is > 1. For MSI-X, program MSI address and data for every
+		 * MSI-X vector including dup vectors irrespective of current
+		 * curr_nenables value.
 		 */
-		if ((pci_is_msi_enabled(rdip, hdlp->ih_type) == DDI_SUCCESS) &&
-		    (i_ddi_intr_get_current_nenables(rdip) > 0)) {
-			return (pci_msi_clr_mask(rdip, hdlp->ih_type,
-			    hdlp->ih_inum));
-		}
+		if ((pci_is_msi_enabled(rdip, hdlp->ih_type) != DDI_SUCCESS) ||
+		    (hdlp->ih_type == DDI_INTR_TYPE_MSIX)) {
+			nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip);
 
-		nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip);
+			if ((ret = pci_msi_configure(rdip, hdlp->ih_type,
+			    nintrs, hdlp->ih_inum, msi_addr,
+			    hdlp->ih_type == DDI_INTR_TYPE_MSIX ?
+			    msi_num : msi_num & ~(nintrs - 1))) != DDI_SUCCESS)
+				return (ret);
 
-		if ((ret = pci_msi_configure(rdip, hdlp->ih_type,
-		    nintrs, hdlp->ih_inum, msi_addr,
-		    hdlp->ih_type == DDI_INTR_TYPE_MSIX ? msi_num :
-		    msi_num & ~(nintrs - 1))) != DDI_SUCCESS)
-			return (ret);
-
-		if ((ret = pci_msi_enable_mode(rdip,
-		    hdlp->ih_type)) != DDI_SUCCESS)
-			return (ret);
+			if (i_ddi_intr_get_current_nenables(rdip) < 1) {
+				if ((ret = pci_msi_enable_mode(rdip,
+				    hdlp->ih_type)) != DDI_SUCCESS)
+					return (ret);
+			}
+		}
 
 		if ((ret = pci_msi_clr_mask(rdip, hdlp->ih_type,
 		    hdlp->ih_inum)) != DDI_SUCCESS)
--- a/usr/src/uts/sun4/os/memnode.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4/os/memnode.c	Mon Jul 20 13:07:46 2009 -0400
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/systm.h>
 #include <sys/platform_module.h>
 #include <sys/sysmacros.h>
@@ -82,9 +80,6 @@
 		end = roundup(end, btop(mem_node_physalign)) - 1;
 	}
 
-	if (&plat_slice_add != NULL)
-		plat_slice_add(start, end);
-
 	mnode = PFN_2_MEM_NODE(start);
 	ASSERT(mnode < max_mem_nodes);
 
@@ -111,16 +106,6 @@
 	lgrp_config(LGRP_CONFIG_MEM_ADD, mnode, MEM_NODE_2_LGRPHAND(mnode));
 }
 
-/* ARGSUSED */
-void
-mem_node_pre_del_slice(pfn_t start, pfn_t end)
-{
-	int mnode = PFN_2_MEM_NODE(start);
-
-	ASSERT(mnode < max_mem_nodes);
-	ASSERT(mem_node_config[mnode].exists == 1);
-}
-
 /*
  * Remove a PFN range from a memnode.  On some platforms,
  * the memnode will be created with physbase at the first
@@ -129,7 +114,7 @@
  * to assume physbase and up.
  */
 void
-mem_node_post_del_slice(pfn_t start, pfn_t end, int cancelled)
+mem_node_del_slice(pfn_t start, pfn_t end)
 {
 	int mnode;
 	pgcnt_t delta_pgcnt, node_size;
@@ -144,44 +129,57 @@
 	ASSERT(mnode < max_mem_nodes);
 	ASSERT(mem_node_config[mnode].exists == 1);
 
-	if (!cancelled) {
-		delta_pgcnt = end - start;
-		node_size = mem_node_config[mnode].physmax -
-		    mem_node_config[mnode].physbase;
+	delta_pgcnt = end - start;
+	node_size = mem_node_config[mnode].physmax -
+	    mem_node_config[mnode].physbase;
 
-		if (node_size > delta_pgcnt) {
-			/*
-			 * Subtract the slice from the memnode.
-			 */
-			if (start <= mem_node_config[mnode].physbase)
-				mem_node_config[mnode].physbase = end + 1;
-			ASSERT(end <= mem_node_config[mnode].physmax);
-			if (end == mem_node_config[mnode].physmax)
-				mem_node_config[mnode].physmax = start - 1;
-		} else {
+	if (node_size > delta_pgcnt) {
+		/*
+		 * Subtract the slice from the memnode.
+		 */
+		if (start <= mem_node_config[mnode].physbase)
+			mem_node_config[mnode].physbase = end + 1;
+		ASSERT(end <= mem_node_config[mnode].physmax);
+		if (end == mem_node_config[mnode].physmax)
+			mem_node_config[mnode].physmax = start - 1;
+	} else {
+
+		/*
+		 * Let the common lgrp framework know the mnode is
+		 * leaving
+		 */
+		lgrp_config(LGRP_CONFIG_MEM_DEL, mnode,
+		    MEM_NODE_2_LGRPHAND(mnode));
 
-			/*
-			 * Let the common lgrp framework know the mnode is
-			 * leaving
-			 */
-			lgrp_config(LGRP_CONFIG_MEM_DEL, mnode,
-			    MEM_NODE_2_LGRPHAND(mnode));
+		/*
+		 * Delete the whole node.
+		 */
+		ASSERT(MNODE_PGCNT(mnode) == 0);
+		do {
+			omask = memnodes_mask;
+			nmask = omask & ~(1ull << mnode);
+		} while (cas64(&memnodes_mask, omask, nmask) != omask);
+		atomic_add_16(&num_memnodes, -1);
+		mem_node_config[mnode].exists = 0;
+	}
+}
 
-			/*
-			 * Delete the whole node.
-			 */
-			ASSERT(MNODE_PGCNT(mnode) == 0);
-			do {
-				omask = memnodes_mask;
-				nmask = omask & ~(1ull << mnode);
-			} while (cas64(&memnodes_mask, omask, nmask) != omask);
-			atomic_add_16(&num_memnodes, -1);
-			mem_node_config[mnode].exists = 0;
-		}
+void
+mem_node_add_range(pfn_t start, pfn_t end)
+{
+	if (&plat_slice_add != NULL)
+		plat_slice_add(start, end);
+	else
+		mem_node_add_slice(start, end);
+}
 
-		if (&plat_slice_del != NULL)
-			plat_slice_del(start, end);
-	}
+void
+mem_node_del_range(pfn_t start, pfn_t end)
+{
+	if (&plat_slice_del != NULL)
+		plat_slice_del(start, end);
+	else
+		mem_node_del_slice(start, end);
 }
 
 void
@@ -203,7 +201,7 @@
 		for (elem = 0; elem < nelems; list++, elem++) {
 			basepfn = btop(list->addr);
 			npgs = btop(list->size);
-			mem_node_add_slice(basepfn, basepfn + npgs - 1);
+			mem_node_add_range(basepfn, basepfn + npgs - 1);
 		}
 	}
 }
--- a/usr/src/uts/sun4/os/startup.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4/os/startup.c	Mon Jul 20 13:07:46 2009 -0400
@@ -202,6 +202,16 @@
 pgcnt_t segziosize = 0;		/* size of zio segment in pages */
 
 /*
+ * A static DR page_t VA map is reserved that can map the page structures
+ * for a domain's entire RA space. The pages that backs this space are
+ * dynamically allocated and need not be physically contiguous.  The DR
+ * map size is derived from KPM size.
+ */
+int ppvm_enable = 0;		/* Static virtual map for page structs */
+page_t *ppvm_base;		/* Base of page struct map */
+pgcnt_t ppvm_size = 0;		/* Size of page struct map */
+
+/*
  * debugger pages (if allocated)
  */
 struct vnode kdebugvp;
@@ -1987,6 +1997,8 @@
 		mach_kpm_init();
 	}
 
+	va = kpm_vbase + (kpm_size * vac_colors);
+
 	if (!segzio_fromheap) {
 		size_t size;
 		size_t physmem_b = mmu_ptob(physmem);
@@ -2019,7 +2031,8 @@
 		}
 		segziosize = mmu_btop(roundup(size, MMU_PAGESIZE));
 		/* put the base of the ZIO segment after the kpm segment */
-		segzio_base = kpm_vbase + (kpm_size * vac_colors);
+		segzio_base = va;
+		va += mmu_ptob(segziosize);
 		PRM_DEBUG(segziosize);
 		PRM_DEBUG(segzio_base);
 
@@ -2042,6 +2055,41 @@
 		rw_exit(&kas.a_lock);
 	}
 
+	if (ppvm_enable) {
+		caddr_t ppvm_max;
+
+		/*
+		 * ppvm refers to the static VA space used to map
+		 * the page_t's for dynamically added memory.
+		 *
+		 * ppvm_base should not cross a potential VA hole.
+		 *
+		 * ppvm_size should be large enough to map the
+		 * page_t's needed to manage all of KPM range.
+		 */
+		ppvm_size =
+		    roundup(mmu_btop(kpm_size * vac_colors) * sizeof (page_t),
+		    MMU_PAGESIZE);
+		ppvm_max = (caddr_t)(0ull - ppvm_size);
+		ppvm_base = (page_t *)va;
+
+		if ((caddr_t)ppvm_base <= hole_end) {
+			cmn_err(CE_WARN,
+			    "Memory DR disabled: invalid DR map base: 0x%p\n",
+			    (void *)ppvm_base);
+			ppvm_enable = 0;
+		} else if ((caddr_t)ppvm_base > ppvm_max) {
+			uint64_t diff = (caddr_t)ppvm_base - ppvm_max;
+
+			cmn_err(CE_WARN,
+			    "Memory DR disabled: insufficient DR map size:"
+			    " 0x%lx (needed 0x%lx)\n",
+			    ppvm_size - diff, ppvm_size);
+			ppvm_enable = 0;
+		}
+		PRM_DEBUG(ppvm_size);
+		PRM_DEBUG(ppvm_base);
+	}
 
 	/*
 	 * Now create generic mapping segment.  This mapping
@@ -2541,10 +2589,15 @@
 			/*
 			 * init it, lock it, and hashin on prom_pages vp.
 			 *
+			 * Mark it as NONRELOC to let DR know the page
+			 * is locked long term, otherwise DR hangs when
+			 * trying to remove those pages.
+			 *
 			 * XXX	vnode offsets on the prom_ppages vnode
 			 *	are page numbers (gack) for >32 bit
 			 *	physical memory machines.
 			 */
+			PP_SETNORELOC(pp);
 			add_physmem_cb(pp, base);
 			if (page_trylock(pp, SE_EXCL) == 0)
 				cmn_err(CE_PANIC, "prom page locked");
@@ -2614,7 +2667,7 @@
 			ASSERT(memseg_find(
 			    roundup(base + num, kpmpnpgs) - 1, NULL) == NULL);
 		}
-		kpm_ppleft -= num;
+		kpm_ppleft -= kpnum;
 	}
 
 	memseg_list_add(seg);
@@ -2645,6 +2698,8 @@
 		 */
 		while (rpp < lpp) {
 			ASSERT(PAGE_EXCL(rpp) && rpp->p_vnode == &prom_ppages);
+			ASSERT(PP_ISNORELOC(rpp));
+			PP_CLRNORELOC(rpp);
 			page_pp_unlock(rpp, 0, 1);
 			page_hashout(rpp, NULL);
 			page_unlock(rpp);
--- a/usr/src/uts/sun4/sys/memnode.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4/sys/memnode.h	Mon Jul 20 13:07:46 2009 -0400
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _SYS_MEMNODE_H
 #define	_SYS_MEMNODE_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -104,14 +102,19 @@
 
 struct memlist;
 
+/*
+ * Common layer calls the mem_node_*_range interfaces
+ * which in turn call the platmod hooks if they exist.
+ * The platmod layer then calls the mem_node_*slice interfaces.
+ */
 extern void startup_build_mem_nodes(prom_memlist_t *, size_t);
 extern void mem_node_add_slice(pfn_t, pfn_t);
-extern void mem_node_pre_del_slice(pfn_t, pfn_t);
-extern void mem_node_post_del_slice(pfn_t, pfn_t, int);
+extern void mem_node_del_slice(pfn_t, pfn_t);
 extern int mem_node_alloc(void);
 extern pgcnt_t mem_node_memlist_pages(int, struct memlist *);
-extern void mem_node_add_slice(pfn_t start, pfn_t end);
 extern void mem_node_max_range(pfn_t *, pfn_t *);
+extern void mem_node_add_range(pfn_t, pfn_t);
+extern void mem_node_del_range(pfn_t, pfn_t);
 
 extern struct mem_node_conf	mem_node_config[];
 extern uint64_t			mem_node_physalign;
--- a/usr/src/uts/sun4/vm/vm_dep.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4/vm/vm_dep.h	Mon Jul 20 13:07:46 2009 -0400
@@ -60,7 +60,6 @@
 	mtype = (flags & PG_NORELOC) ? MTYPE_NORELOC : MTYPE_RELOC;
 
 #define	MNODETYPE_2_PFN(mnode, mtype, pfnlo, pfnhi)			\
-	ASSERT(mtype != MTYPE_NORELOC);					\
 	pfnlo = mem_node_config[mnode].physbase;			\
 	pfnhi = mem_node_config[mnode].physmax;
 
@@ -115,12 +114,18 @@
  * translations requiring initializer call if color or ceq_mask changes,
  * even if pfn doesn't. MEM_NODE_ITERATOR_INIT() must also be called before
  * PFN_2_COLOR() that uses a valid iterator argument.
+ *
+ * plat_mem_node_iterator_init() starts from last mblock in continuation
+ * case which may be invalid because memory DR.  To detect this situation
+ * mi_genid is checked against mpo_genid which is incremented after a
+ * memory DR operation.  See also plat_slice_add()/plat_slice_del().
  */
 #ifdef	sun4v
 
 typedef struct mem_node_iterator {
 	uint_t mi_mnode;		/* mnode in which to iterate */
 	int mi_init;			/* set to 1 when first init */
+	int mi_genid;			/* set/checked against mpo_genid */
 	int mi_last_mblock;		/* last mblock visited */
 	uint_t mi_hash_ceq_mask;	/* cached copy of ceq_mask */
 	uint_t mi_hash_color;		/* cached copy of color */
@@ -460,6 +465,36 @@
 	}								       \
 }
 
+/*
+ * macro to call page_ctrs_adjust() when memory is added
+ * during a DR operation.
+ */
+#define	PAGE_CTRS_ADJUST(pfn, cnt, rv) {				       \
+	spgcnt_t _cnt = (spgcnt_t)(cnt);				       \
+	int _mn;							       \
+	pgcnt_t _np;							       \
+	if (&plat_mem_node_intersect_range != NULL) {			       \
+		for (_mn = 0; _mn < max_mem_nodes; _mn++) {		       \
+			plat_mem_node_intersect_range((pfn), _cnt, _mn, &_np); \
+			if (_np == 0)					       \
+				continue;				       \
+			if ((rv = page_ctrs_adjust(_mn)) != 0)		       \
+				break;					       \
+		}							       \
+	} else {							       \
+		pfn_t _pfn = (pfn);					       \
+		pfn_t _endpfn = _pfn + _cnt;				       \
+		while (_pfn < _endpfn) {				       \
+			_mn = PFN_2_MEM_NODE(_pfn);			       \
+			_np = MIN(_endpfn, mem_node_config[_mn].physmax + 1) - \
+			    _pfn;					       \
+			_pfn += _np;					       \
+			if ((rv = page_ctrs_adjust(_mn)) != 0)		       \
+				break;					       \
+		}							       \
+	}								       \
+}
+
 extern plcnt_t	plcnt;
 
 #define	MNODE_PGCNT(mn)							\
--- a/usr/src/uts/sun4u/opl/os/opl.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4u/opl/os/opl.c	Mon Jul 20 13:07:46 2009 -0400
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/cpuvar.h>
 #include <sys/systm.h>
 #include <sys/sysmacros.h>
@@ -657,8 +655,7 @@
 			if (mem_node_config[mnode].exists) {
 				start = mem_node_config[mnode].physbase;
 				end = mem_node_config[mnode].physmax;
-				mem_node_pre_del_slice(start, end);
-				mem_node_post_del_slice(start, end, 0);
+				mem_node_del_slice(start, end);
 			}
 		}
 
@@ -703,8 +700,7 @@
 		if (tnode != -1 && mem_node_config[tnode].exists) {
 			start = mem_node_config[tnode].physbase;
 			end = mem_node_config[tnode].physmax;
-			mem_node_pre_del_slice(start, end);
-			mem_node_post_del_slice(start, end, 0);
+			mem_node_del_slice(start, end);
 		}
 
 		plat_assign_lgrphand_to_mem_node(thand, snode);
--- a/usr/src/uts/sun4v/Makefile.files	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4v/Makefile.files	Mon Jul 20 13:07:46 2009 -0400
@@ -24,7 +24,7 @@
 # Use is subject to license terms.
 #
 #	This Makefile defines all file modules for the directory uts/sun4v
-#	and it's children. These are the source files which are sun4u
+#	and it's children. These are the source files which are sun4v
 #	"implementation architecture" dependent.
 #
 
@@ -60,6 +60,7 @@
 CORE_OBJS +=	mem_cage.o
 CORE_OBJS +=	mem_config.o
 CORE_OBJS +=	memlist_new.o
+CORE_OBJS +=	memseg.o
 CORE_OBJS +=	mpo.o
 CORE_OBJS +=	ppage.o
 CORE_OBJS +=	promif_asr.o
@@ -161,6 +162,7 @@
 BOOTDEV_OBJS	+= bootdev.o
 DR_CPU_OBJS	+= dr_cpu.o
 DR_IO_OBJS	+= dr_io.o
+DR_MEM_OBJS	+= dr_mem.o
 DRCTL_OBJS	= drctl.o drctl_impl.o dr_util.o
 DS_OBJS		= ds_common.o ds_drv.o
 FAULT_ISO_OBJS	= fault_iso.o
--- a/usr/src/uts/sun4v/Makefile.sun4v.shared	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4v/Makefile.sun4v.shared	Mon Jul 20 13:07:46 2009 -0400
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #	This makefile contains the common definitions for the sun4v unix
@@ -390,6 +390,7 @@
 MISC_KMODS	+= bootdev
 MISC_KMODS	+= dr_cpu
 MISC_KMODS	+= dr_io
+MISC_KMODS	+= dr_mem
 MISC_KMODS	+= ds
 MISC_KMODS	+= fault_iso
 MISC_KMODS	+= ldc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4v/dr_mem/Makefile	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,91 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE		= dr_mem
+OBJECTS		= $(DR_MEM_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(DR_MEM_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_PSM_MISC_DIR)/$(MODULE)
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/sun4v/Makefile.sun4v
+
+#
+# Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+# lint pass one enforcement
+#
+CFLAGS		+= $(CCVERBOSE)
+
+#
+# Turn on doubleword alignment for 64 bit registers
+#
+CFLAGS		+= -dalign
+
+#
+# Module Dependencies
+#
+LDFLAGS		+= -dy -Nmisc/ds -Nmisc/platsvc -Ndrv/drctl
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/$(PLATFORM)/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4v/io/dr_mem.c	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,1252 @@
+/*
+ * 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.
+ */
+
+/*
+ * sun4v Memory DR Module
+ */
+
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/vmem.h>
+#include <sys/kmem.h>
+#include <sys/systm.h>
+#include <sys/machsystm.h>	/* for page_freelist_coalesce() */
+#include <sys/errno.h>
+#include <sys/memnode.h>
+#include <sys/memlist.h>
+#include <sys/memlist_impl.h>
+#include <sys/tuneable.h>
+#include <sys/proc.h>
+#include <sys/disp.h>
+#include <sys/debug.h>
+#include <sys/vm.h>
+#include <sys/callb.h>
+#include <sys/memlist_plat.h>	/* for installed_top_size() */
+#include <sys/condvar_impl.h>	/* for CV_HAS_WAITERS() */
+#include <sys/dumphdr.h>	/* for dump_resize() */
+#include <sys/atomic.h>		/* for use in stats collection */
+#include <sys/rwlock.h>
+#include <vm/seg_kmem.h>
+#include <vm/seg_kpm.h>
+#include <vm/page.h>
+#include <vm/vm_dep.h>
+#define	SUNDDI_IMPL		/* so sunddi.h will not redefine splx() et al */
+#include <sys/sunddi.h>
+#include <sys/mem_config.h>
+#include <sys/mem_cage.h>
+#include <sys/lgrp.h>
+#include <sys/ddi.h>
+
+#include <sys/modctl.h>
+#include <sys/sysevent/dr.h>
+#include <sys/mach_descrip.h>
+#include <sys/mdesc.h>
+#include <sys/ds.h>
+#include <sys/drctl.h>
+#include <sys/dr_util.h>
+#include <sys/dr_mem.h>
+
+
+/*
+ * DR operations are subject to Memory Alignment restrictions
+ * for both address and the size of the request.
+ */
+#define	MA_ADDR	0x10000000	/* addr alignment 256M */
+#define	MA_SIZE	0x10000000	/* size alignment 256M */
+
+#define	MBLK_IS_VALID(m) \
+	(IS_P2ALIGNED((m)->addr, MA_ADDR) && IS_P2ALIGNED((m)->size, MA_SIZE))
+
+static memhandle_t dr_mh;	/* memory handle for delete */
+
+static struct modlmisc modlmisc = {
+	&mod_miscops,
+	"sun4v memory DR"
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1,
+	(void *)&modlmisc,
+	NULL
+};
+
+static int dr_mem_allow_unload = 0;
+
+typedef int (*fn_t)(dr_mem_blk_t *, int *);
+
+/*
+ * Global Domain Services (DS) Handle
+ */
+static ds_svc_hdl_t ds_handle;
+
+/*
+ * Supported DS Capability Versions
+ */
+static ds_ver_t		dr_mem_vers[] = { { 1, 0 } };
+#define	DR_MEM_NVERS	(sizeof (dr_mem_vers) / sizeof (dr_mem_vers[0]))
+
+/*
+ * DS Capability Description
+ */
+static ds_capability_t dr_mem_cap = {
+	DR_MEM_DS_ID,		/* svc_id */
+	dr_mem_vers,		/* vers */
+	DR_MEM_NVERS		/* nvers */
+};
+
+/*
+ * DS Callbacks
+ */
+static void dr_mem_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
+static void dr_mem_unreg_handler(ds_cb_arg_t arg);
+static void dr_mem_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
+
+/*
+ * DS Client Ops Vector
+ */
+static ds_clnt_ops_t dr_mem_ops = {
+	dr_mem_reg_handler,	/* ds_reg_cb */
+	dr_mem_unreg_handler,	/* ds_unreg_cb */
+	dr_mem_data_handler,	/* ds_data_cb */
+	NULL			/* cb_arg */
+};
+
+/*
+ * Operation Results
+ *
+ * Used internally to gather results while an operation on a
+ * list of mblks is in progress. In particular, it is used to
+ * keep track of which mblks have already failed so that they are
+ * not processed further, and the manner in which they failed.
+ */
+typedef struct {
+	uint64_t	addr;
+	uint64_t	size;
+	uint32_t	result;
+	uint32_t	status;
+	char		*string;
+} dr_mem_res_t;
+
+static char *
+dr_mem_estr[] = {
+	"operation succeeded",		/* DR_MEM_RES_OK */
+	"operation failed",		/* DR_MEM_RES_FAILURE */
+	"operation was blocked",	/* DR_MEM_RES_BLOCKED */
+	"memory not defined in MD",	/* DR_MEM_RES_NOT_IN_MD */
+	"memory already in use",	/* DR_MEM_RES_ESPAN */
+	"memory access test failed",	/* DR_MEM_RES_EFAULT */
+	"resource not available",	/* DR_MEM_RES_ERESOURCE */
+	"permanent pages in span",	/* DR_MEM_RES_PERM */
+	"memory span busy",		/* DR_MEM_RES_EBUSY */
+	"VM viability test failed",	/* DR_MEM_RES_ENOTVIABLE */
+	"no pages to unconfigure",	/* DR_MEM_RES_ENOWORK */
+	"operation cancelled",		/* DR_MEM_RES_ECANCELLED */
+	"operation refused",		/* DR_MEM_RES_EREFUSED */
+	"memory span duplicate",	/* DR_MEM_RES_EDUP */
+	"invalid argument"		/* DR_MEM_RES_EINVAL */
+};
+
+typedef struct {
+	kcondvar_t cond;
+	kmutex_t lock;
+	int error;
+	int done;
+} mem_sync_t;
+
+/*
+ * Internal Functions
+ */
+static int dr_mem_init(void);
+static int dr_mem_fini(void);
+
+static int dr_mem_list_wrk(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
+static int dr_mem_list_query(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
+static int dr_mem_del_stat(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
+static int dr_mem_del_cancel(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
+
+static int dr_mem_unconfigure(dr_mem_blk_t *, int *);
+static int dr_mem_configure(dr_mem_blk_t *, int *);
+static void dr_mem_query(dr_mem_blk_t *, dr_mem_query_t *);
+
+static dr_mem_res_t *dr_mem_res_array_init(dr_mem_hdr_t *, drctl_rsrc_t *, int);
+static void dr_mem_res_array_fini(dr_mem_res_t *res, int nres);
+static size_t dr_mem_pack_response(dr_mem_hdr_t *req, dr_mem_res_t *res,
+    dr_mem_hdr_t **respp);
+
+static int dr_mem_find(dr_mem_blk_t *mbp);
+static mde_cookie_t dr_mem_find_node_md(dr_mem_blk_t *, md_t *, mde_cookie_t *);
+
+static int mem_add(pfn_t, pgcnt_t);
+static int mem_del(pfn_t, pgcnt_t);
+
+static size_t rsvaddsz;
+extern void i_dr_mem_init(uint64_t *);
+extern void i_dr_mem_fini();
+extern void i_dr_mem_update();
+extern int kphysm_add_memory_dynamic(pfn_t, pgcnt_t);
+
+int
+_init(void)
+{
+	int	status;
+
+	/* check that Memory DR is enabled */
+	if (dr_is_disabled(DR_TYPE_MEM))
+		return (ENOTSUP);
+
+	if ((status = dr_mem_init()) != 0) {
+		cmn_err(CE_NOTE, "Memory DR initialization failed");
+		return (status);
+	}
+
+	if ((status = mod_install(&modlinkage)) != 0) {
+		(void) dr_mem_fini();
+	}
+
+	return (status);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+int
+_fini(void)
+{
+	int	status;
+
+	if (dr_mem_allow_unload == 0)
+		return (EBUSY);
+
+	if ((status = mod_remove(&modlinkage)) == 0) {
+		(void) dr_mem_fini();
+	}
+
+	return (status);
+}
+
+static int
+dr_mem_init(void)
+{
+	int rv;
+
+	if ((rv = ds_cap_init(&dr_mem_cap, &dr_mem_ops)) != 0) {
+		cmn_err(CE_NOTE, "dr_mem: ds_cap_init failed: %d", rv);
+		return (rv);
+	}
+
+	i_dr_mem_init(&rsvaddsz);
+
+	return (0);
+}
+
+static int
+dr_mem_fini(void)
+{
+	int rv;
+
+	i_dr_mem_fini();
+
+	if ((rv = ds_cap_fini(&dr_mem_cap)) != 0) {
+		cmn_err(CE_NOTE, "dr_mem: ds_cap_fini failed: %d", rv);
+	}
+
+	return (rv);
+}
+
+static void
+dr_mem_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
+{
+	DR_DBG_MEM("reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", arg,
+	    ver->major, ver->minor, hdl);
+
+	ds_handle = hdl;
+}
+
+static void
+dr_mem_unreg_handler(ds_cb_arg_t arg)
+{
+	DR_DBG_MEM("unreg_handler: arg=0x%p\n", arg);
+
+	ds_handle = DS_INVALID_HDL;
+}
+
+/*ARGSUSED*/
+static void
+dr_mem_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
+{
+	dr_mem_hdr_t	*req = buf;
+	dr_mem_hdr_t	err_resp;
+	dr_mem_hdr_t	*resp = &err_resp;
+	int		resp_len = 0;
+	int		rv = EINVAL;
+
+	/*
+	 * Sanity check the message
+	 */
+	if (buflen < sizeof (dr_mem_hdr_t)) {
+		DR_DBG_MEM("incoming message short: expected at least %ld "
+		    "bytes, received %ld\n", sizeof (dr_mem_hdr_t), buflen);
+		goto done;
+	}
+
+	if (req == NULL) {
+		DR_DBG_MEM("empty message: expected at least %ld bytes\n",
+		    sizeof (dr_mem_hdr_t));
+		goto done;
+	}
+
+	DR_DBG_MEM("incoming request:\n");
+	DR_DBG_DUMP_MSG(buf, buflen);
+
+	/*
+	 * Process the command
+	 */
+	switch (req->msg_type) {
+	case DR_MEM_CONFIGURE:
+	case DR_MEM_UNCONFIGURE:
+		if (req->msg_arg == 0) {
+			DR_DBG_MEM("No mblks specified for operation\n");
+			goto done;
+		}
+		if ((rv = dr_mem_list_wrk(req, &resp, &resp_len)) != 0) {
+			DR_DBG_MEM("%s failed (%d)\n",
+			    (req->msg_type == DR_MEM_CONFIGURE) ?
+			    "Memory configure" : "Memory unconfigure", rv);
+		}
+		break;
+
+	case DR_MEM_UNCONF_STATUS:
+		if ((rv = dr_mem_del_stat(req, &resp, &resp_len)) != 0)
+			DR_DBG_MEM("Memory delete status failed (%d)\n", rv);
+		break;
+
+	case DR_MEM_UNCONF_CANCEL:
+		if ((rv = dr_mem_del_cancel(req, &resp, &resp_len)) != 0)
+			DR_DBG_MEM("Memory delete cancel failed (%d)\n", rv);
+		break;
+
+	case DR_MEM_QUERY:
+		if (req->msg_arg == 0) {
+			DR_DBG_MEM("No mblks specified for operation\n");
+			goto done;
+		}
+		if ((rv = dr_mem_list_query(req, &resp, &resp_len)) != 0)
+			DR_DBG_MEM("Memory query failed (%d)\n", rv);
+		break;
+
+	default:
+		cmn_err(CE_NOTE, "unsupported memory DR operation (%d)",
+		    req->msg_type);
+		break;
+	}
+
+done:
+	/* check if an error occurred */
+	if (resp == &err_resp) {
+		resp->req_num = (req) ? req->req_num : 0;
+		resp->msg_type = DR_MEM_ERROR;
+		resp->msg_arg = rv;
+		resp_len = sizeof (dr_mem_hdr_t);
+	}
+
+	DR_DBG_MEM("outgoing response:\n");
+	DR_DBG_DUMP_MSG(resp, resp_len);
+
+	/* send back the response */
+	if (ds_cap_send(ds_handle, resp, resp_len) != 0) {
+		DR_DBG_MEM("ds_send failed\n");
+	}
+
+	/* free any allocated memory */
+	if (resp != &err_resp) {
+		kmem_free(resp, resp_len);
+	}
+}
+
+/*
+ * Common routine to config or unconfig multiple mblks.
+ *
+ * Note: Do not modify result buffer or length on error.
+ */
+static int
+dr_mem_list_wrk(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
+{
+	int		rv;
+	int		idx;
+	int		count;
+	int		result;
+	int		status;
+	fn_t		dr_fn;
+	int		se_hint;
+	dr_mem_blk_t	*req_mblks;
+	dr_mem_res_t	*res;
+	int		drctl_cmd;
+	int		drctl_flags = 0;
+	drctl_rsrc_t	*drctl_req;
+	size_t		drctl_req_len;
+	drctl_resp_t	*drctl_resp;
+	drctl_rsrc_t	*drctl_rsrc;
+	size_t		drctl_resp_len = 0;
+	drctl_cookie_t	drctl_res_ck;
+
+	ASSERT((req != NULL) && (req->msg_arg != 0));
+
+	count = req->msg_arg;
+
+	/*
+	 * Extract all information that is specific
+	 * to the various types of operations.
+	 */
+	switch (req->msg_type) {
+	case DR_MEM_CONFIGURE:
+		dr_fn = dr_mem_configure;
+		drctl_cmd = DRCTL_MEM_CONFIG_REQUEST;
+		se_hint = SE_HINT_INSERT;
+		break;
+	case DR_MEM_UNCONFIGURE:
+		dr_fn = dr_mem_unconfigure;
+		drctl_cmd = DRCTL_MEM_UNCONFIG_REQUEST;
+		se_hint = SE_HINT_REMOVE;
+		break;
+	default:
+		/* Programming error if we reach this. */
+		cmn_err(CE_NOTE, "%s: bad msg_type %d\n",
+		    __func__, req->msg_type);
+		ASSERT(0);
+		return (-1);
+	}
+
+	/* the incoming array of mblks to operate on */
+	req_mblks = DR_MEM_CMD_MBLKS(req);
+
+	/* allocate drctl request msg based on incoming resource count */
+	drctl_req_len = sizeof (drctl_rsrc_t) * count;
+	drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP);
+
+	/* copy the size for the drctl call from the incoming request msg */
+	for (idx = 0; idx < count; idx++) {
+		drctl_req[idx].res_mem_addr = req_mblks[idx].addr;
+		drctl_req[idx].res_mem_size = req_mblks[idx].size;
+	}
+
+	rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req,
+	    count, &drctl_resp, &drctl_resp_len, &drctl_res_ck);
+
+	ASSERT((drctl_resp != NULL) && (drctl_resp_len != 0));
+
+	if (rv != 0) {
+		DR_DBG_MEM("%s: drctl_config_init returned: %d\n",
+		    __func__, rv);
+		kmem_free(drctl_resp, drctl_resp_len);
+		kmem_free(drctl_req, drctl_req_len);
+		return (rv);
+	}
+
+	ASSERT(drctl_resp->resp_type == DRCTL_RESP_OK);
+
+	drctl_rsrc = drctl_resp->resp_resources;
+
+	/* create the result scratch array */
+	res = dr_mem_res_array_init(req, drctl_rsrc, count);
+
+	/* perform the specified operation on each of the mblks */
+	for (idx = 0; idx < count; idx++) {
+		/*
+		 * If no action will be taken against the current
+		 * mblk, update the drctl resource information to
+		 * ensure that it gets recovered properly during
+		 * the drctl fini() call.
+		 */
+		if (res[idx].result != DR_MEM_RES_OK) {
+			drctl_req[idx].status = DRCTL_STATUS_CONFIG_FAILURE;
+			continue;
+		}
+
+		/* call the function to perform the actual operation */
+		result = (*dr_fn)(&req_mblks[idx], &status);
+
+		/* save off results of the operation */
+		res[idx].result = result;
+		res[idx].status = status;
+		res[idx].addr = req_mblks[idx].addr;	/* for partial case */
+		res[idx].size = req_mblks[idx].size;	/* for partial case */
+		res[idx].string = i_ddi_strdup(dr_mem_estr[result], KM_SLEEP);
+
+		/* save result for drctl fini() reusing init() msg memory */
+		drctl_req[idx].status = (result != DR_MEM_RES_OK) ?
+		    DRCTL_STATUS_CONFIG_FAILURE : DRCTL_STATUS_CONFIG_SUCCESS;
+
+		DR_DBG_MEM("%s: mblk 0x%lx.0x%lx stat %d result %d off '%s'\n",
+		    __func__, req_mblks[idx].addr, req_mblks[idx].size,
+		    drctl_req[idx].status, result,
+		    (res[idx].string) ? res[idx].string : "");
+	}
+
+	if ((rv = drctl_config_fini(&drctl_res_ck, drctl_req, count)) != 0)
+		DR_DBG_MEM("%s: drctl_config_fini returned: %d\n",
+		    __func__, rv);
+
+	/*
+	 * Operation completed without any fatal errors.
+	 * Pack the response for transmission.
+	 */
+	*resp_len = dr_mem_pack_response(req, res, resp);
+
+	/* notify interested parties about the operation */
+	dr_generate_event(DR_TYPE_MEM, se_hint);
+
+	/*
+	 * Deallocate any scratch memory.
+	 */
+	kmem_free(drctl_resp, drctl_resp_len);
+	kmem_free(drctl_req, drctl_req_len);
+
+	dr_mem_res_array_fini(res, count);
+
+	return (0);
+}
+
+/*
+ * Allocate and initialize a result array based on the initial
+ * drctl operation. A valid result array is always returned.
+ */
+static dr_mem_res_t *
+dr_mem_res_array_init(dr_mem_hdr_t *req, drctl_rsrc_t *rsrc, int nrsrc)
+{
+	int		idx;
+	dr_mem_res_t	*res;
+	char		*err_str;
+	size_t		err_len;
+
+	/* allocate zero filled buffer to initialize fields */
+	res = kmem_zalloc(nrsrc * sizeof (dr_mem_res_t), KM_SLEEP);
+
+	/*
+	 * Fill in the result information for each resource.
+	 */
+	for (idx = 0; idx < nrsrc; idx++) {
+		res[idx].addr = rsrc[idx].res_mem_addr;
+		res[idx].size = rsrc[idx].res_mem_size;
+		res[idx].result = DR_MEM_RES_OK;
+
+		if (rsrc[idx].status == DRCTL_STATUS_ALLOW)
+			continue;
+
+		/*
+		 * Update the state information for this mblk.
+		 */
+		res[idx].result = DR_MEM_RES_BLOCKED;
+		res[idx].status = (req->msg_type == DR_MEM_CONFIGURE) ?
+		    DR_MEM_STAT_UNCONFIGURED : DR_MEM_STAT_CONFIGURED;
+
+		/*
+		 * If an error string exists, copy it out of the
+		 * message buffer. This eliminates any dependency
+		 * on the memory allocated for the message buffer
+		 * itself.
+		 */
+		if (rsrc[idx].offset != NULL) {
+			err_str = (char *)rsrc + rsrc[idx].offset;
+			err_len = strlen(err_str) + 1;
+
+			res[idx].string = kmem_alloc(err_len, KM_SLEEP);
+			bcopy(err_str, res[idx].string, err_len);
+		}
+	}
+
+	return (res);
+}
+
+static void
+dr_mem_res_array_fini(dr_mem_res_t *res, int nres)
+{
+	int	idx;
+	size_t	str_len;
+
+	for (idx = 0; idx < nres; idx++) {
+		/* deallocate the error string if present */
+		if (res[idx].string) {
+			str_len = strlen(res[idx].string) + 1;
+			kmem_free(res[idx].string, str_len);
+		}
+	}
+
+	/* deallocate the result array itself */
+	kmem_free(res, sizeof (dr_mem_res_t) * nres);
+}
+
+/*
+ * Allocate and pack a response message for transmission based
+ * on the specified result array. A valid response message and
+ * valid size information is always returned.
+ */
+static size_t
+dr_mem_pack_response(dr_mem_hdr_t *req, dr_mem_res_t *res, dr_mem_hdr_t **respp)
+{
+	int		idx;
+	dr_mem_hdr_t	*resp;
+	dr_mem_stat_t	*resp_stat;
+	size_t		resp_len;
+	uint32_t	curr_off;
+	caddr_t		curr_str;
+	size_t		str_len;
+	size_t		stat_len;
+	int		nstat = req->msg_arg;
+
+	/*
+	 * Calculate the size of the response message
+	 * and allocate an appropriately sized buffer.
+	 */
+	resp_len = sizeof (dr_mem_hdr_t);
+
+	/* add the stat array size */
+	stat_len = sizeof (dr_mem_stat_t) * nstat;
+	resp_len += stat_len;
+
+	/* add the size of any error strings */
+	for (idx = 0; idx < nstat; idx++) {
+		if (res[idx].string != NULL) {
+			resp_len += strlen(res[idx].string) + 1;
+		}
+	}
+
+	/* allocate the message buffer */
+	resp = kmem_zalloc(resp_len, KM_SLEEP);
+
+	/*
+	 * Fill in the header information.
+	 */
+	resp->req_num = req->req_num;
+	resp->msg_type = DR_MEM_OK;
+	resp->msg_arg = nstat;
+
+	/*
+	 * Fill in the stat information.
+	 */
+	resp_stat = DR_MEM_RESP_STATS(resp);
+
+	/* string offsets start immediately after stat array */
+	curr_off = sizeof (dr_mem_hdr_t) + stat_len;
+	curr_str = (char *)resp_stat + stat_len;
+
+	for (idx = 0; idx < nstat; idx++) {
+		resp_stat[idx].addr = res[idx].addr;
+		resp_stat[idx].size = res[idx].size;
+		resp_stat[idx].result = res[idx].result;
+		resp_stat[idx].status = res[idx].status;
+
+		if (res[idx].string != NULL) {
+			/* copy over the error string */
+			str_len = strlen(res[idx].string) + 1;
+			bcopy(res[idx].string, curr_str, str_len);
+			resp_stat[idx].string_off = curr_off;
+
+			curr_off += str_len;
+			curr_str += str_len;
+		}
+	}
+
+	/* buffer should be exactly filled */
+	ASSERT(curr_off == resp_len);
+
+	*respp = resp;
+	return (resp_len);
+}
+
+static void
+dr_mem_query(dr_mem_blk_t *mbp, dr_mem_query_t *mqp)
+{
+	memquery_t mq;
+
+	DR_DBG_MEM("dr_mem_query...\n");
+
+
+	(void) kphysm_del_span_query(btop(mbp->addr), btop(mbp->size), &mq);
+
+	if (!mq.phys_pages)
+		return;
+
+	mqp->addr = mbp->addr;
+	mqp->mq.phys_pages = ptob(mq.phys_pages);
+	mqp->mq.managed = ptob(mq.managed);
+	mqp->mq.nonrelocatable = ptob(mq.nonrelocatable);
+	mqp->mq.first_nonrelocatable = ptob(mq.first_nonrelocatable);
+	mqp->mq.last_nonrelocatable = ptob(mq.last_nonrelocatable);
+	/*
+	 * Set to the max byte offset within the page.
+	 */
+	if (mqp->mq.nonrelocatable)
+		mqp->mq.last_nonrelocatable += PAGESIZE - 1;
+}
+
+/*
+ * Do not modify result buffer or length on error.
+ */
+static int
+dr_mem_list_query(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
+{
+	int		idx;
+	int		rlen;
+	int		nml;
+	struct memlist	*ml;
+	dr_mem_blk_t	*req_mblks, mb;
+	dr_mem_hdr_t	*rp;
+	dr_mem_query_t	*stat;
+
+	/* the incoming array of req_mblks to configure */
+	req_mblks = DR_MEM_CMD_MBLKS(req);
+
+	/* allocate a response message, should be freed by caller */
+	nml = 0;
+	rlen = sizeof (dr_mem_hdr_t);
+	if (req_mblks->addr == NULL && req_mblks->size == 0) {
+		/*
+		 * Request is for domain's full view of it's memory.
+		 */
+		memlist_read_lock();
+		for (ml = phys_install; ml; ml = ml->next)
+			nml++;
+
+		rlen += nml * sizeof (dr_mem_query_t);
+	} else {
+		rlen += req->msg_arg * sizeof (dr_mem_query_t);
+	}
+	rp = kmem_zalloc(rlen, KM_SLEEP);
+
+	/* fill in the known data */
+	rp->req_num = req->req_num;
+	rp->msg_type = DR_MEM_OK;
+	rp->msg_arg = nml ? nml : req->msg_arg;
+
+	/* stat array for the response */
+	stat = DR_MEM_RESP_QUERY(rp);
+
+	/* get the status for each of the mblocks */
+	if (nml) {
+		for (idx = 0, ml = phys_install; ml; ml = ml->next, idx++) {
+			mb.addr = ml->address;
+			mb.size = ml->size;
+			dr_mem_query(&mb, &stat[idx]);
+		}
+		memlist_read_unlock();
+	} else {
+		for (idx = 0; idx < req->msg_arg; idx++)
+			dr_mem_query(&req_mblks[idx], &stat[idx]);
+	}
+
+	*resp = rp;
+	*resp_len = rlen;
+
+	return (0);
+}
+
+static int
+cvt_err(int err)
+{
+	int rv;
+
+	switch (err) {
+	case KPHYSM_OK:
+		rv = DR_MEM_RES_OK;
+		break;
+	case KPHYSM_ESPAN:
+		rv = DR_MEM_RES_ESPAN;
+		break;
+	case KPHYSM_EFAULT:
+		rv = DR_MEM_RES_EFAULT;
+		break;
+	case KPHYSM_ERESOURCE:
+		rv = DR_MEM_RES_ERESOURCE;
+		break;
+	case KPHYSM_ENOTSUP:
+	case KPHYSM_ENOHANDLES:
+		rv = DR_MEM_RES_FAILURE;
+		break;
+	case KPHYSM_ENONRELOC:
+		rv = DR_MEM_RES_PERM;
+		break;
+	case KPHYSM_EHANDLE:
+		rv = DR_MEM_RES_FAILURE;
+		break;
+	case KPHYSM_EBUSY:
+		rv = DR_MEM_RES_EBUSY;
+		break;
+	case KPHYSM_ENOTVIABLE:
+		rv = DR_MEM_RES_ENOTVIABLE;
+		break;
+	case KPHYSM_ESEQUENCE:
+		rv = DR_MEM_RES_FAILURE;
+		break;
+	case KPHYSM_ENOWORK:
+		rv = DR_MEM_RES_ENOWORK;
+		break;
+	case KPHYSM_ECANCELLED:
+		rv = DR_MEM_RES_ECANCELLED;
+		break;
+	case KPHYSM_EREFUSED:
+		rv = DR_MEM_RES_EREFUSED;
+		break;
+	case KPHYSM_ENOTFINISHED:
+	case KPHYSM_ENOTRUNNING:
+		rv = DR_MEM_RES_FAILURE;
+		break;
+	case KPHYSM_EDUP:
+		rv = DR_MEM_RES_EDUP;
+		break;
+	default:
+		rv = DR_MEM_RES_FAILURE;
+		break;
+	}
+
+	return (rv);
+}
+
+static int
+dr_mem_configure(dr_mem_blk_t *mbp, int *status)
+{
+	int rv;
+	uint64_t addr, size, addsz;
+
+	rv = 0;
+	addr = mbp->addr;
+	size = mbp->size;
+
+	DR_DBG_MEM("dr_mem_configure...\n");
+
+	if (!MBLK_IS_VALID(mbp)) {
+		DR_DBG_MEM("invalid mblk 0x%lx.0x%lx\n", addr, size);
+		*status = DR_MEM_STAT_UNCONFIGURED;
+		rv = DR_MEM_RES_EINVAL;
+	} else if (rv = dr_mem_find(mbp)) {
+		DR_DBG_MEM("failed to find mblk 0x%lx.0x%lx (%d)\n",
+		    addr, size, rv);
+		if (rv == EINVAL) {
+			*status = DR_MEM_STAT_NOT_PRESENT;
+			rv = DR_MEM_RES_NOT_IN_MD;
+		} else {
+			*status = DR_MEM_STAT_UNCONFIGURED;
+			rv = DR_MEM_RES_FAILURE;
+		}
+	} else if (rsvaddsz) {
+		addr += size;
+
+		/*
+		 * Add up to the first <rsvaddsz> portion of mblock
+		 * first since that portion has reserved meta pages.
+		 * This will likely guarantee an additional amount of
+		 * free pages from which we may have to allocate the
+		 * rest of the meta pages.
+		 *
+		 * Break up the request in descending order (if needed)
+		 * in order to ensure that cage grows from the high end
+		 * of the original request.
+		 */
+		for (addsz = MIN(size, rsvaddsz); addsz > 0; addsz = size) {
+			ASSERT(addr >= mbp->addr);
+			DR_DBG_MEM("addsz=0x%lx  size=0x%lx\n", addsz, size);
+			if (rv = mem_add(btop(addr - addsz), btop(addsz))) {
+				DR_DBG_MEM("failed to configure span"
+				    " 0x%lx.0x%lx (%d)\n", addr, addsz, rv);
+				break;
+			} else {
+				size -= addsz;
+				addr -= addsz;
+			}
+		}
+
+		/*
+		 * Mark the mblock configured if any span
+		 * in that mblock was successfully added.
+		 *
+		 * In case of partial success:
+		 *
+		 *	rv != DR_MEM_RES_OK
+		 *	status == DR_MEM_STAT_CONFIGURED
+		 *
+		 * mark span actually configured.
+		 */
+		if (size == mbp->size && rv != KPHYSM_ESPAN) {
+			*status = DR_MEM_STAT_UNCONFIGURED;
+		} else {
+			DR_DBG_MEM("failed (partial) to configure span"
+			    " 0x%lx.0x%lx (%d)\n", addr, addsz, rv);
+			*status = DR_MEM_STAT_CONFIGURED;
+			mbp->addr = addr;
+			mbp->size -= size;
+		}
+
+		rv = cvt_err(rv);
+		i_dr_mem_update();
+	} else {
+		/*
+		 * The reserved feature is disabled, add whole mblock.
+		 */
+		rv = mem_add(btop(addr), btop(size));
+		DR_DBG_MEM("addr=0x%lx size=0x%lx rv=%d\n", addr, size, rv);
+		if (rv) {
+			rv = cvt_err(rv);
+			*status = DR_MEM_STAT_UNCONFIGURED;
+		} else {
+			*status = DR_MEM_STAT_CONFIGURED;
+		}
+	}
+
+	return (rv);
+}
+
+static int
+dr_mem_unconfigure(dr_mem_blk_t *mbp, int *status)
+{
+	int rv;
+
+	DR_DBG_MEM("dr_mem_unconfigure...\n");
+
+	if (!MBLK_IS_VALID(mbp)) {
+		DR_DBG_MEM("invalid mblk 0x%lx.0x%lx\n",
+		    mbp->addr, mbp->size);
+			*status = DR_MEM_STAT_CONFIGURED;
+			rv = DR_MEM_RES_EINVAL;
+	} else if (rv = mem_del(btop(mbp->addr), btop(mbp->size))) {
+		rv = cvt_err(rv);
+		*status = DR_MEM_STAT_CONFIGURED;
+	} else {
+		*status = DR_MEM_STAT_UNCONFIGURED;
+		rv = DR_MEM_RES_OK;
+		DR_DBG_MEM("mblk 0x%lx.0x%lx unconfigured\n",
+		    mbp->addr, mbp->size);
+	}
+	return (rv);
+}
+
+static int
+dr_mem_del_stat(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
+{
+	int			status;
+	int			rlen;
+	memdelstat_t		del_stat, *stat;
+	dr_mem_hdr_t		*rp;
+
+	/*
+	 * If a mem delete is in progress, get its status.
+	 */
+	status = (dr_mh && (kphysm_del_status(dr_mh, &del_stat) == KPHYSM_OK));
+
+	/* allocate a response message, should be freed by caller */
+	rlen = sizeof (dr_mem_hdr_t);
+	rlen += status * sizeof (memdelstat_t);
+	rp = kmem_zalloc(rlen, KM_SLEEP);
+
+	/* fill in the known data */
+	rp->req_num = req->req_num;
+	rp->msg_type = DR_MEM_OK;
+	rp->msg_arg = status;
+
+	if (status) {
+		/* stat struct for the response */
+		stat = DR_MEM_RESP_DEL_STAT(rp);
+		stat->phys_pages = ptob(del_stat.phys_pages);
+		stat->managed = ptob(del_stat.managed);
+		stat->collected = ptob(del_stat.collected);
+	}
+
+	*resp = rp;
+	*resp_len = rlen;
+
+	return (0);
+}
+
+static int
+dr_mem_del_cancel(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
+{
+	int		rlen;
+	dr_mem_hdr_t	*rp;
+
+	/* allocate a response message, should be freed by caller */
+	rlen = sizeof (dr_mem_hdr_t);
+	rp = kmem_zalloc(rlen, KM_SLEEP);
+
+	/* fill in the known data */
+	rp->req_num = req->req_num;
+	rp->msg_type = DR_MEM_OK;
+	rp->msg_arg = (dr_mh && kphysm_del_cancel(dr_mh) != KPHYSM_OK) ?
+	    DR_MEM_RES_EINVAL : DR_MEM_RES_OK;
+
+	*resp = rp;
+	*resp_len = rlen;
+
+	return (0);
+}
+
+static int
+dr_mem_find(dr_mem_blk_t *mbp)
+{
+	md_t		*mdp = NULL;
+	int		num_nodes;
+	int		rv = 0;
+	int		listsz;
+	mde_cookie_t	*listp = NULL;
+	mde_cookie_t	memnode;
+	char		*found = "found";
+
+	if ((mdp = md_get_handle()) == NULL) {
+		DR_DBG_MEM("unable to initialize machine description\n");
+		return (-1);
+	}
+
+	num_nodes = md_node_count(mdp);
+	ASSERT(num_nodes > 0);
+
+	listsz = num_nodes * sizeof (mde_cookie_t);
+	listp = kmem_zalloc(listsz, KM_SLEEP);
+
+	memnode = dr_mem_find_node_md(mbp, mdp, listp);
+
+	if (memnode == MDE_INVAL_ELEM_COOKIE) {
+		rv = EINVAL;
+		found = "not found";
+	}
+
+	DR_DBG_MEM("mblk 0x%lx.0x%lx %s\n", mbp->addr, mbp->size, found);
+
+	kmem_free(listp, listsz);
+	(void) md_fini_handle(mdp);
+
+	return (rv);
+}
+
+/*
+ * Look up a particular mblk in the MD. Returns the mde_cookie_t
+ * representing that mblk if present, and MDE_INVAL_ELEM_COOKIE
+ * otherwise. It is assumed the scratch array has already been
+ * allocated so that it can accommodate the worst case scenario,
+ * every node in the MD.
+ */
+static mde_cookie_t
+dr_mem_find_node_md(dr_mem_blk_t *mbp, md_t *mdp, mde_cookie_t *listp)
+{
+	int		idx;
+	int		nnodes;
+	mde_cookie_t	rootnode;
+	uint64_t	base_prop;
+	uint64_t	size_prop;
+	mde_cookie_t	result = MDE_INVAL_ELEM_COOKIE;
+
+	rootnode = md_root_node(mdp);
+	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
+
+	/*
+	 * Scan the DAG for all the mem nodes
+	 */
+	nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "mblock"),
+	    md_find_name(mdp, "fwd"), listp);
+
+	if (nnodes < 0) {
+		DR_DBG_MEM("Scan for mblks failed\n");
+		return (result);
+	}
+
+	DR_DBG_MEM("dr_mem_find_node_md: found %d mblks in the MD\n", nnodes);
+
+	/*
+	 * Find the mblk of interest
+	 */
+	for (idx = 0; idx < nnodes; idx++) {
+
+		if (md_get_prop_val(mdp, listp[idx], "base", &base_prop)) {
+			DR_DBG_MEM("Missing 'base' property for mblk node %d\n",
+			    idx);
+			break;
+		}
+
+		if (md_get_prop_val(mdp, listp[idx], "size", &size_prop)) {
+			DR_DBG_MEM("Missing 'size' property for mblk node %d\n",
+			    idx);
+			break;
+		}
+
+		if (base_prop <= mbp->addr &&
+		    (base_prop + size_prop) >= (mbp->addr + mbp->size)) {
+			/* found a match */
+			DR_DBG_MEM("dr_mem_find_node_md: found mblk "
+			    "0x%lx.0x%lx in MD\n", mbp->addr, mbp->size);
+			result = listp[idx];
+			break;
+		}
+	}
+
+	if (result == MDE_INVAL_ELEM_COOKIE) {
+		DR_DBG_MEM("mblk 0x%lx.0x%lx not in MD\n",
+		    mbp->addr, mbp->size);
+	}
+
+	return (result);
+}
+
+static int
+mem_add(pfn_t base, pgcnt_t npgs)
+{
+	int rv, rc;
+
+	DR_DBG_MEM("%s: begin base=0x%lx npgs=0x%lx\n", __func__, base, npgs);
+
+	if (npgs == 0)
+		return (0);
+
+	rv = kphysm_add_memory_dynamic(base, npgs);
+	DR_DBG_MEM("%s: kphysm_add(0x%lx, 0x%lx) = %d", __func__, base, npgs,
+	    rv);
+	if (!rv) {
+		if (rc = kcage_range_add(base, npgs, KCAGE_DOWN))
+			cmn_err(CE_WARN, "kcage_range_add() = %d", rc);
+	}
+	return (rv);
+}
+
+static void
+del_done(void *arg, int error)
+{
+	mem_sync_t *ms = arg;
+
+	mutex_enter(&ms->lock);
+	ms->error = error;
+	ms->done = 1;
+	cv_signal(&ms->cond);
+	mutex_exit(&ms->lock);
+}
+
+static int
+mem_del(pfn_t base, pgcnt_t npgs)
+{
+	int rv, err, del_range = 0;
+	mem_sync_t ms;
+	memquery_t mq;
+	memhandle_t mh;
+	struct memlist *ml;
+	struct memlist *d_ml = NULL;
+
+	DR_DBG_MEM("%s: begin base=0x%lx npgs=0x%lx\n", __func__, base, npgs);
+
+	if (npgs == 0)
+		return (0);
+
+	if ((rv = kphysm_del_gethandle(&mh)) != KPHYSM_OK) {
+		cmn_err(CE_WARN, "%s: del_gethandle() = %d", __func__, rv);
+		return (rv);
+	}
+	if ((rv = kphysm_del_span_query(base, npgs, &mq))
+	    != KPHYSM_OK) {
+		cmn_err(CE_WARN, "%s: del_span_query() = %d", __func__, rv);
+		goto done;
+	}
+	if (mq.nonrelocatable) {
+		DR_DBG_MEM("%s: non-reloc pages = %ld",
+		    __func__, mq.nonrelocatable);
+		rv = KPHYSM_ENONRELOC;
+		goto done;
+	}
+	if (rv = kcage_range_delete(base, npgs)) {
+		cmn_err(CE_WARN, "%s: del_range() = %d", __func__, rv);
+		goto done;
+	} else {
+		del_range++;
+	}
+	if ((rv = kphysm_del_span(mh, base, npgs)) != KPHYSM_OK) {
+		cmn_err(CE_WARN, "%s: del_span() = %d", __func__, rv);
+		goto done;
+	}
+	if ((rv = memlist_add_span(ptob(base), ptob(npgs), &d_ml))
+	    != MEML_SPANOP_OK) {
+		cmn_err(CE_WARN, "%s: add_span() = %d", __func__, rv);
+		goto done;
+	}
+
+	DR_DBG_MEM("%s: reserved=0x%lx", __func__, npgs);
+
+	bzero((void *) &ms, sizeof (ms));
+
+	mutex_init(&ms.lock, NULL, MUTEX_DRIVER, NULL);
+	cv_init(&ms.cond, NULL, CV_DRIVER, NULL);
+	mutex_enter(&ms.lock);
+
+	if ((rv = kphysm_del_start(mh, del_done, (void *) &ms)) == KPHYSM_OK) {
+		/*
+		 * Since we've called drctl_config_init, we are the only
+		 * DR ctl operation in progress.  Set dr_mh to the
+		 * delete memhandle for use by stat and cancel.
+		 */
+		ASSERT(dr_mh == NULL);
+		dr_mh = mh;
+
+		/*
+		 * Wait for completion or interrupt.
+		 */
+		while (!ms.done) {
+			if (cv_wait_sig(&ms.cond, &ms.lock) == 0) {
+				/*
+				 * There is a pending signal.
+				 */
+				(void) kphysm_del_cancel(mh);
+				DR_DBG_MEM("%s: cancel", __func__);
+				/*
+				 * Wait for completion.
+				 */
+				while (!ms.done)
+					cv_wait(&ms.cond, &ms.lock);
+			}
+		}
+		dr_mh = NULL;
+		rv = ms.error;
+	} else {
+		DR_DBG_MEM("%s: del_start() = %d", __func__, rv);
+	}
+
+	mutex_exit(&ms.lock);
+	cv_destroy(&ms.cond);
+	mutex_destroy(&ms.lock);
+
+done:
+	if (rv && del_range) {
+		/*
+		 * Add back the spans to the kcage growth list.
+		 */
+		for (ml = d_ml; ml; ml = ml->next)
+			if (err = kcage_range_add(btop(ml->address),
+			    btop(ml->size), KCAGE_DOWN))
+				cmn_err(CE_WARN, "kcage_range_add() = %d", err);
+	}
+	memlist_free_list(d_ml);
+
+	if ((err = kphysm_del_release(mh)) != KPHYSM_OK)
+		cmn_err(CE_WARN, "%s: del_release() = %d", __func__, err);
+
+	DR_DBG_MEM("%s: rv=%d", __func__, rv);
+
+	return (rv);
+}
--- a/usr/src/uts/sun4v/io/dr_util.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4v/io/dr_util.c	Mon Jul 20 13:07:46 2009 -0400
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * sun4v DR Utility functions
  */
@@ -41,6 +39,8 @@
 
 #include <sys/dr_util.h>
 
+extern int ppvm_enable;
+
 boolean_t
 dr_is_disabled(dr_type_t type)
 {
@@ -64,6 +64,11 @@
 		return (B_TRUE);
 	}
 
+	if (type == DR_TYPE_MEM && ppvm_enable == 0) {
+		cmn_err(CE_NOTE, "!Memory DR is disabled\n");
+		return (B_TRUE);
+	}
+
 	return (B_FALSE);
 }
 
--- a/usr/src/uts/sun4v/io/drctl.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4v/io/drctl.c	Mon Jul 20 13:07:46 2009 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -354,6 +354,9 @@
 		if (count != 1)
 			return (EIO);
 		break;
+	case DRCTL_MEM_CONFIG_REQUEST:
+	case DRCTL_MEM_UNCONFIG_REQUEST:
+		break;
 	default:
 		return (EIO);
 	}
@@ -391,12 +394,13 @@
 	case DRCTL_IO_UNCONFIG_NOTIFY:
 	case DRCTL_IO_CONFIG_REQUEST:
 	case DRCTL_IO_CONFIG_NOTIFY:
-		rv = 0;
-		break;
 	case DRCTL_MEM_CONFIG_REQUEST:
 	case DRCTL_MEM_CONFIG_NOTIFY:
 	case DRCTL_MEM_UNCONFIG_REQUEST:
 	case DRCTL_MEM_UNCONFIG_NOTIFY:
+		rv = 0;
+		break;
+	default:
 		rv = ENOTSUP;
 		break;
 	}
@@ -555,9 +559,13 @@
 		break;
 
 	case DRCTL_MEM_CONFIG_REQUEST:
-	case DRCTL_MEM_CONFIG_NOTIFY:
+		notify_cmd = DRCTL_MEM_CONFIG_NOTIFY;
+		break;
+
 	case DRCTL_MEM_UNCONFIG_REQUEST:
-	case DRCTL_MEM_UNCONFIG_NOTIFY:
+		notify_cmd = DRCTL_MEM_UNCONFIG_NOTIFY;
+		break;
+
 	default:
 		/* none of the above should have been accepted in _init */
 		ASSERT(0);
@@ -657,6 +665,12 @@
 	case DRCTL_CPU_UNCONFIG_NOTIFY:
 		*data_size = count * sizeof (drctl_rsrc_t);
 		break;
+	case DRCTL_MEM_CONFIG_REQUEST:
+	case DRCTL_MEM_CONFIG_NOTIFY:
+	case DRCTL_MEM_UNCONFIG_REQUEST:
+	case DRCTL_MEM_UNCONFIG_NOTIFY:
+		*data_size = count * sizeof (drctl_rsrc_t);
+		break;
 	case DRCTL_IO_CONFIG_REQUEST:
 	case DRCTL_IO_CONFIG_NOTIFY:
 	case DRCTL_IO_UNCONFIG_REQUEST:
--- a/usr/src/uts/sun4v/io/mdeg.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4v/io/mdeg.c	Mon Jul 20 13:07:46 2009 -0400
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * MD Event Generator (MDEG) Module
  */
@@ -885,18 +883,22 @@
 static void
 mdeg_dump_clnt(mdeg_clnt_t *clnt)
 {
-	char	str[MAX_FIELD_STR];
+	char	str[MAX_FIELD_STR] = "";
 
 	if (!clnt->valid) {
 		MDEG_DBG("  valid=B_FALSE\n");
 		return;
 	}
 
-	mdeg_spec_str(clnt->pspec, str, MAX_FIELD_STR);
-	MDEG_DBG("  pspecp=%s\n", str);
+	if (clnt->pspec) {
+		mdeg_spec_str(clnt->pspec, str, MAX_FIELD_STR);
+		MDEG_DBG("  pspecp=%s\n", str);
+	}
 
-	mdeg_match_str(clnt->nmatch, str, MAX_FIELD_STR);
-	MDEG_DBG("  nmatch=%s\n", str);
+	if (clnt->nmatch) {
+		mdeg_match_str(clnt->nmatch, str, MAX_FIELD_STR);
+		MDEG_DBG("  nmatch=%s\n", str);
+	}
 }
 
 static void
--- a/usr/src/uts/sun4v/os/fillsysinfo.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4v/os/fillsysinfo.c	Mon Jul 20 13:07:46 2009 -0400
@@ -75,7 +75,7 @@
 static void get_weakest_mem_model(md_t *, mde_cookie_t);
 static void get_q_sizes(md_t *, mde_cookie_t);
 static void get_va_bits(md_t *, mde_cookie_t);
-static size_t get_ra_limit(md_t *);
+static size_t get_ra_limit(md_t *, mde_cookie_t);
 static int get_l2_cache_node_count(md_t *);
 static unsigned long names2bits(char *tokens, size_t tokenslen,
     char *bit_formatter, char *warning);
@@ -495,7 +495,7 @@
 	/*
 	 * ra_limit is the highest real address in the machine.
 	 */
-	ra_limit = get_ra_limit(mdp);
+	ra_limit = get_ra_limit(mdp, cpulist[0]);
 
 	md_free_scan_dag(mdp, &cpulist);
 
@@ -808,19 +808,38 @@
 	return (ul);
 }
 
-
 uint64_t
-get_ra_limit(md_t *mdp)
+get_ra_limit(md_t *mdp, mde_cookie_t cpu_node_cookie)
 {
+	extern int ppvm_enable;
+	extern int meta_alloc_enable;
 	mde_cookie_t *mem_list;
 	mde_cookie_t *mblock_list;
 	int i;
 	int memnodes;
 	int nmblock;
+	uint64_t r;
 	uint64_t base;
 	uint64_t size;
 	uint64_t ra_limit = 0, new_limit = 0;
 
+	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#ra-bits", &r) == 0) {
+		if (r == 0 || r > RA_ADDRESS_SPACE_BITS)
+			cmn_err(CE_PANIC, "Incorrect number of ra bits in MD");
+		else {
+			/*
+			 * Enable memory DR and metadata (page_t)
+			 * allocation from existing memory.
+			 */
+			ppvm_enable = 1;
+			meta_alloc_enable = 1;
+			return (1ULL << r);
+		}
+	}
+
+	cmn_err(CE_WARN, "mmu-#ra-bits property not found in MD");
+	cmn_err(CE_WARN, "Memory DR disabled");
+
 	memnodes = md_alloc_scan_dag(mdp,
 	    md_root_node(mdp), "memory", "fwd", &mem_list);
 
--- a/usr/src/uts/sun4v/os/mach_startup.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4v/os/mach_startup.c	Mon Jul 20 13:07:46 2009 -0400
@@ -506,6 +506,9 @@
 	if (modload("misc", "dr_io") == -1)
 		cmn_err(CE_NOTE, "!'dr_io' module failed to load");
 
+	if (modload("misc", "dr_mem") == -1)
+		cmn_err(CE_NOTE, "!'dr_mem' module failed to load");
+
 	/*
 	 * Attempt to attach any virtual device servers. These
 	 * drivers must be loaded at start of day so that they
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4v/os/memseg.c	Mon Jul 20 13:07:46 2009 -0400
@@ -0,0 +1,410 @@
+/*
+ *
+ * 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 <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/vm.h>
+#include <sys/mman.h>
+#include <vm/vm_dep.h>
+#include <vm/seg_kmem.h>
+#include <vm/seg_kpm.h>
+#include <sys/mem_config.h>
+#include <sys/sysmacros.h>
+
+extern pgcnt_t pp_dummy_npages;
+extern pfn_t *pp_dummy_pfn;	/* Array of dummy pfns. */
+
+extern kmutex_t memseg_lists_lock;
+extern struct memseg *memseg_va_avail;
+extern struct memseg *memseg_alloc();
+
+extern page_t *ppvm_base;
+extern pgcnt_t ppvm_size;
+
+static vnode_t pp_vn, rsv_vn;
+static pgcnt_t rsv_metapgs;
+static int meta_rsv_enable;
+static int sun4v_memseg_debug;
+
+extern struct memseg *memseg_reuse(pgcnt_t);
+extern void remap_to_dummy(caddr_t, pgcnt_t);
+
+/*
+ * The page_t memory for incoming pages is allocated from existing memory
+ * which can create a potential situation where memory addition fails
+ * because of shortage of existing memory.  To mitigate this situation
+ * some memory is always reserved ahead of time for page_t allocation.
+ * Each 4MB of reserved page_t's guarantees a 256MB (x64) addition without
+ * page_t allocation.  The added 256MB added memory could theoretically
+ * allow an addition of 16GB.
+ */
+#define	RSV_SIZE	0x40000000	/* add size with rsrvd page_t's 1G */
+
+#ifdef	DEBUG
+#define	MEMSEG_DEBUG(args...) if (sun4v_memseg_debug) printf(args)
+#else
+#define	MEMSEG_DEBUG(...)
+#endif
+
+/*
+ * The page_t's for the incoming memory are allocated from
+ * existing pages.
+ */
+/*ARGSUSED*/
+int
+memseg_alloc_meta(pfn_t base, pgcnt_t npgs, void **ptp, pgcnt_t *metap)
+{
+	page_t		*pp, *opp, *epp, *pgpp;
+	pgcnt_t		metapgs;
+	int		i, rsv;
+	struct seg	kseg;
+	caddr_t		vaddr;
+	u_offset_t	off;
+
+	/*
+	 * Verify incoming memory is within supported DR range.
+	 */
+	if ((base + npgs) * sizeof (page_t) > ppvm_size)
+		return (KPHYSM_ENOTSUP);
+
+	opp = pp = ppvm_base + base;
+	epp = pp + npgs;
+	metapgs = btopr(npgs * sizeof (page_t));
+
+	if (!IS_P2ALIGNED((uint64_t)pp, PAGESIZE) &&
+	    page_find(&pp_vn, (u_offset_t)pp)) {
+		/*
+		 * Another memseg has page_t's in the same
+		 * page which 'pp' resides.  This would happen
+		 * if PAGESIZE is not an integral multiple of
+		 * sizeof (page_t) and therefore 'pp'
+		 * does not start on a page boundry.
+		 *
+		 * Since the other memseg's pages_t's still
+		 * map valid pages, skip allocation of this page.
+		 * Advance 'pp' to the next page which should
+		 * belong only to the incoming memseg.
+		 *
+		 * If the last page_t in the current page
+		 * crosses a page boundary, this should still
+		 * work.  The first part of the page_t is
+		 * already allocated.  The second part of
+		 * the page_t will be allocated below.
+		 */
+		ASSERT(PAGESIZE % sizeof (page_t));
+		pp = (page_t *)P2ROUNDUP((uint64_t)pp, PAGESIZE);
+		metapgs--;
+	}
+
+	if (!IS_P2ALIGNED((uint64_t)epp, PAGESIZE) &&
+	    page_find(&pp_vn, (u_offset_t)epp)) {
+		/*
+		 * Another memseg has page_t's in the same
+		 * page which 'epp' resides.  This would happen
+		 * if PAGESIZE is not an integral multiple of
+		 * sizeof (page_t) and therefore 'epp'
+		 * does not start on a page boundry.
+		 *
+		 * Since the other memseg's pages_t's still
+		 * map valid pages, skip allocation of this page.
+		 */
+		ASSERT(PAGESIZE % sizeof (page_t));
+		metapgs--;
+	}
+
+	ASSERT(IS_P2ALIGNED((uint64_t)pp, PAGESIZE));
+
+	/*
+	 * Back metadata space with physical pages.
+	 */
+	kseg.s_as = &kas;
+	vaddr = (caddr_t)pp;
+
+	for (i = 0; i < metapgs; i++)
+		if (page_find(&pp_vn, (u_offset_t)(vaddr + i * PAGESIZE)))
+			panic("page_find(0x%p, %p)\n",
+			    (void *)&pp_vn, (void *)(vaddr + i * PAGESIZE));
+
+	/*
+	 * Allocate the metadata pages; these are the pages that will
+	 * contain the page_t's for the incoming memory.
+	 *
+	 * If a normal allocation fails, use the reserved metapgs for
+	 * a small allocation; otherwise retry with PG_WAIT.
+	 */
+	rsv = off = 0;
+	if (metapgs <= rsv_metapgs) {
+		MEMSEG_DEBUG("memseg_get: use rsv 0x%lx metapgs", metapgs);
+		ASSERT(meta_rsv_enable);
+		rsv = 1;
+	} else if ((pgpp = page_create_va(&pp_vn, (u_offset_t)pp, ptob(metapgs),
+	    PG_NORELOC | PG_EXCL, &kseg, vaddr)) == NULL) {
+		cmn_err(CE_WARN, "memseg_get: can't get 0x%ld metapgs",
+		    metapgs);
+		return (KPHYSM_ERESOURCE);
+	}
+	if (rsv) {
+		/*
+		 * The reseve pages must be hashed out of the reserve vnode
+		 * and rehashed by <pp_vn,vaddr>.  The resreved pages also
+		 * must be replenished immedidately at the end of the add
+		 * processing.
+		 */
+		for (i = 0; i < metapgs; i++) {
+			pgpp = page_find(&rsv_vn, off);
+			ASSERT(pgpp);
+			page_hashout(pgpp, 0);
+			hat_devload(kas.a_hat, vaddr, PAGESIZE,
+			    page_pptonum(pgpp), PROT_READ | PROT_WRITE,
+			    HAT_LOAD | HAT_LOAD_REMAP | HAT_LOAD_NOCONSIST);
+			ASSERT(!page_find(&pp_vn, (u_offset_t)vaddr));
+			if (!page_hashin(pgpp, &pp_vn, (u_offset_t)vaddr, 0))
+				panic("memseg_get: page_hashin(0x%p, 0x%p)",
+				    (void *)pgpp, (void *)vaddr);
+			off += PAGESIZE;
+			vaddr += PAGESIZE;
+			rsv_metapgs--;
+		}
+	} else {
+		for (i = 0; i < metapgs; i++) {
+			hat_devload(kas.a_hat, vaddr, PAGESIZE,
+			    page_pptonum(pgpp), PROT_READ | PROT_WRITE,
+			    HAT_LOAD | HAT_LOAD_REMAP | HAT_LOAD_NOCONSIST);
+			pgpp = pgpp->p_next;
+			vaddr += PAGESIZE;
+		}
+	}
+
+	ASSERT(ptp);
+	ASSERT(metap);
+
+	*ptp = (void *)opp;
+	*metap = metapgs;
+
+	return (KPHYSM_OK);
+}
+
+void
+memseg_free_meta(void *ptp, pgcnt_t metapgs)
+{
+	int i;
+	page_t *pp;
+	u_offset_t off;
+
+	if (!metapgs)
+		return;
+
+	off = (u_offset_t)ptp;
+
+	ASSERT(off);
+	ASSERT(IS_P2ALIGNED((uint64_t)off, PAGESIZE));
+
+	MEMSEG_DEBUG("memseg_free_meta: off=0x%lx metapgs=0x%lx\n",
+	    (uint64_t)off, metapgs);
+	/*
+	 * Free pages allocated during add.
+	 */
+	for (i = 0; i < metapgs; i++) {
+		pp = page_find(&pp_vn, off);
+		ASSERT(pp);
+		ASSERT(pp->p_szc == 0);
+		page_io_unlock(pp);
+		page_destroy(pp, 0);
+		off += PAGESIZE;
+	}
+}
+
+pfn_t
+memseg_get_metapfn(void *ptp, pgcnt_t metapg)
+{
+	page_t *pp;
+	u_offset_t off;
+
+	off = (u_offset_t)ptp + ptob(metapg);
+
+	ASSERT(off);
+	ASSERT(IS_P2ALIGNED((uint64_t)off, PAGESIZE));
+
+	pp = page_find(&pp_vn, off);
+	ASSERT(pp);
+	ASSERT(pp->p_szc == 0);
+	ASSERT(pp->p_pagenum != PFN_INVALID);
+
+	return (pp->p_pagenum);
+}
+
+/*
+ * Remap a memseg's page_t's to dummy pages.  Skip the low/high
+ * ends of the range if they are already in use.
+ */
+void
+memseg_remap_meta(struct memseg *seg)
+{
+	int i;
+	u_offset_t off;
+	page_t *pp;
+#if 0
+	page_t *epp;
+#endif
+	pgcnt_t metapgs;
+
+	metapgs = btopr(MSEG_NPAGES(seg) * sizeof (page_t));
+	ASSERT(metapgs);
+	pp = seg->pages;
+	seg->pages_end = seg->pages_base;
+#if 0
+	epp = seg->epages;
+
+	/*
+	 * This code cannot be tested as the kernel does not compile
+	 * when page_t size is changed.  It is left here as a starting
+	 * point if the unaligned page_t size needs to be supported.
+	 */
+
+	if (!IS_P2ALIGNED((uint64_t)pp, PAGESIZE) &&
+	    page_find(&pp_vn, (u_offset_t)(pp - 1)) && !page_deleted(pp - 1)) {
+		/*
+		 * Another memseg has page_t's in the same
+		 * page which 'pp' resides.  This would happen
+		 * if PAGESIZE is not an integral multiple of
+		 * sizeof (page_t) and therefore 'seg->pages'
+		 * does not start on a page boundry.
+		 *
+		 * Since the other memseg's pages_t's still
+		 * map valid pages, skip remap of this page.
+		 * Advance 'pp' to the next page which should
+		 * belong only to the outgoing memseg.
+		 *
+		 * If the last page_t in the current page
+		 * crosses a page boundary, this should still
+		 * work.  The first part of the page_t is
+		 * valid since memseg_lock_delete_all() has
+		 * been called.  The second part of the page_t
+		 * will be remapped to the corresponding
+		 * dummy page below.
+		 */
+		ASSERT(PAGESIZE % sizeof (page_t));
+		pp = (page_t *)P2ROUNDUP((uint64_t)pp, PAGESIZE);
+		metapgs--;
+	}
+
+	if (!IS_P2ALIGNED((uint64_t)epp, PAGESIZE) &&
+	    page_find(&pp_vn, (u_offset_t)epp) && !page_deleted(epp)) {
+		/*
+		 * Another memseg has page_t's in the same
+		 * page which 'epp' resides.  This would happen
+		 * if PAGESIZE is not an integral multiple of
+		 * sizeof (page_t) and therefore 'seg->epages'
+		 * does not start on a page boundry.
+		 *
+		 * Since the other memseg's pages_t's still
+		 * map valid pages, skip remap of this page.
+		 */
+		ASSERT(PAGESIZE % sizeof (page_t));
+		metapgs--;
+	}
+#endif
+	ASSERT(IS_P2ALIGNED((uint64_t)pp, PAGESIZE));
+
+	remap_to_dummy((caddr_t)pp, metapgs);
+
+	off = (u_offset_t)pp;
+
+	MEMSEG_DEBUG("memseg_remap: off=0x%lx metapgs=0x%lx\n", (uint64_t)off,
+	    metapgs);
+	/*
+	 * Free pages allocated during add.
+	 */
+	for (i = 0; i < metapgs; i++) {
+		pp = page_find(&pp_vn, off);
+		ASSERT(pp);
+		ASSERT(pp->p_szc == 0);
+		page_io_unlock(pp);
+		page_destroy(pp, 0);
+		off += PAGESIZE;
+	}
+}
+
+static void
+rsv_alloc()
+{
+	int i;
+	page_t *pp;
+	pgcnt_t metapgs;
+	u_offset_t off;
+	struct seg kseg;
+
+	kseg.s_as = &kas;
+
+	/*
+	 * Reserve enough page_t pages for an add request of
+	 * RSV_SIZE bytes.
+	 */
+	metapgs = btopr(btop(RSV_SIZE) * sizeof (page_t)) - rsv_metapgs;
+
+	for (i = off = 0; i < metapgs; i++, off += PAGESIZE) {
+		(void) page_create_va(&rsv_vn, off, PAGESIZE,
+		    PG_NORELOC | PG_WAIT, &kseg, 0);
+		pp = page_find(&rsv_vn, off);
+		ASSERT(pp);
+		ASSERT(PAGE_EXCL(pp));
+		page_iolock_init(pp);
+		rsv_metapgs++;
+	}
+}
+
+void
+i_dr_mem_init(size_t *hint)
+{
+	if (meta_rsv_enable) {
+		rsv_alloc();
+		if (hint)
+			*hint = RSV_SIZE;
+	}
+}
+
+void
+i_dr_mem_fini()
+{
+	int i;
+	page_t *pp;
+	u_offset_t off;
+
+	for (i = off = 0; i < rsv_metapgs; i++, off += PAGESIZE) {
+		if (pp = page_find(&rsv_vn, off)) {
+			ASSERT(PAGE_EXCL(pp));
+			page_destroy(pp, 0);
+		}
+		ASSERT(!page_find(&rsv_vn, off));
+	}
+	rsv_metapgs = 0;
+}
+
+void
+i_dr_mem_update()
+{
+	rsv_alloc();
+}
--- a/usr/src/uts/sun4v/os/mpo.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4v/os/mpo.c	Mon Jul 20 13:07:46 2009 -0400
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/sysmacros.h>
 #include <sys/machsystm.h>
@@ -36,6 +34,7 @@
 #include <sys/memnode.h>
 #include <sys/mdesc.h>
 #include <sys/mpo.h>
+#include <vm/page.h>
 #include <vm/vm_dep.h>
 #include <vm/hat_sfmmu.h>
 #include <sys/promif.h>
@@ -91,6 +90,45 @@
  *
  * plat_mem_node_intersect_range()
  *	Find the intersection with a mem_node.
+ *
+ * plat_slice_add()
+ * plat_slice_del()
+ *	Platform hooks to add/delete a pfn range.
+ *
+ * Internal Organization
+ * ---------------------
+ *
+ * A number of routines are used both boot/DR code which (re)build
+ * appropriate MPO structures.
+ *
+ * mblock_alloc()
+ *	Allocate memory for mblocks and stripes as
+ *	appropriate for boot or memory DR.
+ *
+ * mblock_free()
+ *	Free memory allocated by mblock_alloc.
+ *
+ * mblock_update()
+ *	Build mblocks based on mblock nodes read from the MD.
+ *
+ * mblock_update_add()
+ *	Rebuild mblocks after a memory DR add operation.
+ *
+ * mblock_update_del()
+ *	Rebuild mblocks after a memory DR delete operation.
+ *
+ * mblock_install()
+ *	Install mblocks as the new configuration.
+ *
+ * mstripe_update()
+ *	Build stripes based on mblocks.
+ *
+ * mnode_update()
+ *	Call memnode layer to add/del a pfn range, based on stripes.
+ *
+ * The platform interfaces allocate all memory required for the
+ * particualar update first, block access to the MPO structures
+ * while they are updated, and free old structures after the update.
  */
 
 int	sun4v_mpo_enable = 1;
@@ -106,6 +144,7 @@
 static	int	n_lgrpnodes = 0;
 static	int	n_locality_groups = 0;
 static	int	max_locality_groups = 0;
+static	int	szc_mask0 = 0;
 
 /* Save mblocks from the MD */
 #define	SMALL_MBLOCKS_COUNT	8
@@ -116,7 +155,6 @@
 /* Save mem_node stripes calculate from mblocks and lgroups. */
 static mem_stripe_t *mem_stripes;
 static	mem_stripe_t small_mem_stripes[SMALL_MBLOCKS_COUNT * MAX_MEM_NODES];
-static	int 	mstripesz = 0;
 static	int	n_mem_stripes = 0;
 static	pfn_t	mnode_stride;	/* distance between stripes, start to start */
 static	int	stripe_shift;	/* stride/stripes expressed as a shift */
@@ -133,15 +171,33 @@
 static	int	higher_latency = 0;
 
 static	pfn_t	base_ra_to_pa_pfn = 0;	/* ra_to_pa for single mblock memory */
+static	int	mpo_genid;		/* config gen; updated by mem DR */
+static	mpo_config_t mpo_config;	/* current mblocks and stripes */
+
+typedef enum { U_ADD, U_ADD_ALL, U_DEL } update_t;
 
 static	int	valid_pages(md_t *md, mde_cookie_t cpu0);
 static	int	unique_home_mem_lg_count(uint64_t mem_lg_homeset);
 static	int	fix_interleave(void);
 
+static int  mblock_alloc(mpo_config_t *, update_t, int nmblocks);
+static void mblock_install(mpo_config_t *);
+static void mblock_free(mpo_config_t *);
+static void mblock_update(mpo_config_t *, md_t, mde_cookie_t *mblocknodes);
+static void mblock_update_add(mpo_config_t *);
+static void mblock_update_del(mpo_config_t *, mpo_config_t *, pfn_t, pfn_t);
+static void mstripe_update(mpo_config_t *);
+static void mnode_update(mpo_config_t *, pfn_t, pfn_t, update_t);
+
 /* Debug support */
 #if defined(DEBUG) && !defined(lint)
+#define	VALIDATE_SLICE(base, end) { 					\
+	ASSERT(IS_P2ALIGNED(ptob(base), TTEBYTES(TTE256M)));		\
+	ASSERT(IS_P2ALIGNED(ptob(end - base + 1), TTEBYTES(TTE256M)));	\
+}
 #define	MPO_DEBUG(args...) if (sun4v_mpo_debug) printf(args)
 #else
+#define	VALIDATE_SLICE(base, end)
 #define	MPO_DEBUG(...)
 #endif	/* DEBUG */
 
@@ -152,6 +208,31 @@
 }
 
 /*
+ * The MPO locks are to protect the MPO metadata while that
+ * information is updated as a result of a memory DR operation.
+ * The read lock must be acquired to read the metadata and the
+ * write locks must be acquired to update it.
+ */
+#define	mpo_rd_lock	kpreempt_disable
+#define	mpo_rd_unlock	kpreempt_enable
+
+static void
+mpo_wr_lock()
+{
+	mutex_enter(&cpu_lock);
+	pause_cpus(NULL);
+	mutex_exit(&cpu_lock);
+}
+
+static void
+mpo_wr_unlock()
+{
+	mutex_enter(&cpu_lock);
+	start_cpus();
+	mutex_exit(&cpu_lock);
+}
+
+/*
  * Routine to read a uint64_t from a given md
  */
 static	int64_t
@@ -350,204 +431,51 @@
 	mpo_update_tunables();
 }
 
-/*
- *
- * Traverse the MD to determine:
- *
- *  Number of CPU nodes, lgrp_nodes, and mblocks
- *  Then for each lgrp_node, obtain the appropriate data.
- *  For each CPU, determine its home locality and store it.
- *  For each mblock, retrieve its data and store it.
- */
-static	int
-lgrp_traverse(md_t *md)
+static mde_cookie_t
+md_get_root(md_t *md)
 {
-	mde_cookie_t root, *cpunodes, *lgrpnodes, *nodes, *mblocknodes;
-	uint64_t i, j, k, o, n_nodes;
-	uint64_t mem_lg_homeset = 0;
-	int ret_val = 0;
-	int result = 0;
-	int n_cpunodes = 0;
-	int sub_page_fix;
-	int mblocksz = 0;
-	size_t allocsz;
+	mde_cookie_t root = MDE_INVAL_ELEM_COOKIE;
+	int n_nodes;
 
 	n_nodes = md_node_count(md);
 
 	if (n_nodes <= 0) {
-		MPO_STATUS("lgrp_traverse: No nodes in node count\n");
-		ret_val = -1;
-		goto fail;
+		MPO_STATUS("md_get_root: No nodes in node count\n");
+		return (root);
 	}
 
 	root = md_root_node(md);
 
 	if (root == MDE_INVAL_ELEM_COOKIE) {
-		MPO_STATUS("lgrp_traverse: Root node is missing\n");
-		ret_val = -1;
-		goto fail;
+		MPO_STATUS("md_get_root: Root node is missing\n");
+		return (root);
 	}
 
-	/*
-	 * Build the Memory Nodes.  Do this before any possibility of
-	 * bailing from this routine so we obtain ra_to_pa (needed for page
-	 * coloring) even when there are no lgroups defined.
-	 */
-
-	n_mblocks = md_alloc_scan_dag(md, root, PROP_LG_MBLOCK,
-	    "fwd", &mblocknodes);
-
-	if (n_mblocks <= 0) {
-		MPO_STATUS("lgrp_traverse: No mblock "
-		    "nodes detected in Machine Descriptor\n");
-		n_mblocks = 0;
-		ret_val = -1;
-		goto fail;
-	}
-	/*
-	 * If we have a small number of mblocks we will use the space
-	 * that we preallocated. Otherwise, we will dynamically
-	 * allocate the space
-	 */
-	mblocksz = n_mblocks * sizeof (struct mblock_md);
-	mstripesz = MAX_MEM_NODES * n_mblocks * sizeof (mem_stripe_t);
-
-	if (n_mblocks <= SMALL_MBLOCKS_COUNT) {
-		mpo_mblock = &small_mpo_mblocks[0];
-		mem_stripes = &small_mem_stripes[0];
-	} else {
-		allocsz = mmu_ptob(mmu_btopr(mblocksz + mstripesz));
-	/* Ensure that we dont request more space than reserved */
-		if (allocsz > MPOBUF_SIZE) {
-			MPO_STATUS("lgrp_traverse: Insufficient space "
-			    "for mblock structures \n");
-			ret_val = -1;
-			n_mblocks = 0;
-			goto fail;
-		}
-		mpo_mblock = (struct mblock_md *)
-		    prom_alloc((caddr_t)MPOBUF_BASE, allocsz, PAGESIZE);
-		if (mpo_mblock != (struct mblock_md *)MPOBUF_BASE) {
-			MPO_STATUS("lgrp_traverse: Cannot allocate space "
-			    "for mblocks \n");
-			ret_val = -1;
-			n_mblocks = 0;
-			goto fail;
-		}
-		mpo_heap32_buf = (caddr_t)MPOBUF_BASE;
-		mpo_heap32_bufsz = MPOBUF_SIZE;
-
-		mem_stripes = (mem_stripe_t *)(mpo_mblock + n_mblocks);
-	}
-	for (i = 0, j = 0; j < n_mblocks; j++) {
-		mpo_mblock[i].node = mblocknodes[j];
-
-		/* Without a base or size value we will fail */
-		result = get_int(md, mblocknodes[j], PROP_LG_BASE,
-		    &mpo_mblock[i].base);
-		if (result < 0) {
-			MPO_STATUS("lgrp_traverse: "
-			    "PROP_LG_BASE is missing\n");
-			n_mblocks = 0;
-			ret_val = -1;
-			goto fail;
-		}
+	MPO_DEBUG("md_get_root: Node Count: %d\n", n_nodes);
+	MPO_DEBUG("md_get_root: md: %p\n", md);
+	MPO_DEBUG("md_get_root: root: %lx\n", root);
+done:
+	return (root);
+}
 
-		result = get_int(md, mblocknodes[j], PROP_LG_SIZE,
-		    &mpo_mblock[i].size);
-		if (result < 0) {
-			MPO_STATUS("lgrp_traverse: "
-			    "PROP_LG_SIZE is missing\n");
-			n_mblocks = 0;
-			ret_val = -1;
-			goto fail;
-		}
-
-		result = get_int(md, mblocknodes[j],
-		    PROP_LG_RA_PA_OFFSET, &mpo_mblock[i].ra_to_pa);
-
-		/* If we don't have an ra_pa_offset, just set it to 0 */
-		if (result < 0)
-			mpo_mblock[i].ra_to_pa = 0;
-
-		MPO_DEBUG("mblock[%ld]: base = %lx, size = %lx, "
-		    "ra_to_pa = %lx\n", i,
-		    mpo_mblock[i].base,
-		    mpo_mblock[i].size,
-		    mpo_mblock[i].ra_to_pa);
-
-		/* check for unsupportable values of base and size */
-		if (mpo_mblock[i].base >
-		    mpo_mblock[i].base + mpo_mblock[i].size) {
-			MPO_STATUS("lgrp_traverse: "
-			    "PROP_LG_BASE+PROP_LG_SIZE is invalid: "
-			    "base = %lx, size = %lx",
-			    mpo_mblock[i].base, mpo_mblock[i].size);
-			n_mblocks = 0;
-			ret_val = -1;
-			goto fail;
-		}
-
-		/* eliminate size==0 blocks */
-		if (mpo_mblock[i].size != 0) {
-			i++;
-		}
-	}
-
-	if (i == 0) {
-		MPO_STATUS("lgrp_traverse: "
-		    "No non-empty mblock nodes were found "
-		    "in the Machine Descriptor\n");
-		n_mblocks = 0;
-		ret_val = -1;
-		goto fail;
-	}
-	ASSERT(i <= n_mblocks);
-	n_mblocks = i;
-
-	/* Must sort mblocks by address for mem_node_iterator_init() */
-	mblock_sort(mpo_mblock, n_mblocks);
-
-	base_ra_to_pa_pfn = btop(mpo_mblock[0].ra_to_pa);
-
-	/* Page coloring hook is required so we can iterate through mnodes */
-	if (&page_next_pfn_for_color_cpu == NULL) {
-		MPO_STATUS("lgrp_traverse: No page coloring support\n");
-		ret_val = -1;
-		goto fail;
-	}
-
-	/* Global enable for mpo */
-	if (sun4v_mpo_enable == 0) {
-		MPO_STATUS("lgrp_traverse: MPO feature is not enabled\n");
-		ret_val = -1;
-		goto fail;
-	}
+static int
+lgrp_update(md_t *md, mde_cookie_t root)
+{
+	int i, j, result;
+	int ret_val = 0;
+	int sub_page_fix;
+	mde_cookie_t *nodes, *lgrpnodes;
 
 	n_lgrpnodes = md_alloc_scan_dag(md, root, PROP_LG_MEM_LG,
 	    "fwd", &lgrpnodes);
 
 	if (n_lgrpnodes <= 0 || n_lgrpnodes >= MAX_MD_LGROUPS) {
-		MPO_STATUS("lgrp_traverse: No Lgroups\n");
+		MPO_STATUS("lgrp_update: No Lgroups\n");
 		ret_val = -1;
 		goto fail;
 	}
 
-	n_cpunodes = md_alloc_scan_dag(md, root, PROP_LG_CPU, "fwd", &cpunodes);
-
-	if (n_cpunodes <= 0 || n_cpunodes > NCPU) {
-		MPO_STATUS("lgrp_traverse: No CPU nodes detected "
-		    "in MD\n");
-		ret_val = -1;
-		goto fail;
-	}
-
-	MPO_DEBUG("lgrp_traverse: Node Count: %ld\n", n_nodes);
-	MPO_DEBUG("lgrp_traverse: md: %p\n", md);
-	MPO_DEBUG("lgrp_traverse: root: %lx\n", root);
-	MPO_DEBUG("lgrp_traverse: mem_lgs: %d\n", n_lgrpnodes);
-	MPO_DEBUG("lgrp_traverse: cpus: %d\n", n_cpunodes);
-	MPO_DEBUG("lgrp_traverse: mblocks: %d\n", n_mblocks);
+	MPO_DEBUG("lgrp_update: mem_lgs: %d\n", n_lgrpnodes);
 
 	for (i = 0; i < n_lgrpnodes; i++) {
 		mpo_lgroup[i].node = lgrpnodes[i];
@@ -590,7 +518,7 @@
 
 	for (i = 0; i < n_lgrpnodes; i++) {
 		if (mpo_lgroup[0].addr_mask != mpo_lgroup[i].addr_mask) {
-			MPO_STATUS("lgrp_traverse: "
+			MPO_STATUS("lgrp_update: "
 			    "addr_mask values are not the same\n");
 			ret_val = -1;
 			goto fail;
@@ -609,13 +537,98 @@
 			    PROP_LG_MBLOCK, "fwd", &nodes);
 			md_free_scan_dag(md, &nodes);
 			if (j != n_mblocks) {
-				MPO_STATUS("lgrp_traverse: "
+				MPO_STATUS("lgrp_update: "
 				    "sub-page interleave is being fixed\n");
 				ret_val = -1;
 				goto fail;
 			}
 		}
 	}
+fail:
+	if (n_lgrpnodes > 0) {
+		md_free_scan_dag(md, &lgrpnodes);
+		for (i = 0; i < n_lgrpnodes; i++)
+			mpo_lgroup[i].node = MDE_INVAL_ELEM_COOKIE;
+	}
+
+	return (ret_val);
+}
+
+/*
+ *
+ * Traverse the MD to determine:
+ *
+ *  Number of CPU nodes, lgrp_nodes, and mblocks
+ *  Then for each lgrp_node, obtain the appropriate data.
+ *  For each CPU, determine its home locality and store it.
+ *  For each mblock, retrieve its data and store it.
+ */
+static	int
+lgrp_traverse(md_t *md)
+{
+	mde_cookie_t root, *cpunodes, *mblocknodes;
+	int o;
+	uint64_t i, k, stripe, stride;
+	uint64_t mem_lg_homeset = 0;
+	int ret_val = 0;
+	int result = 0;
+	int n_cpunodes = 0;
+	mpo_config_t new_config;
+
+	if ((root = md_get_root(md)) == MDE_INVAL_ELEM_COOKIE) {
+		ret_val = -1;
+		goto fail;
+	}
+
+	n_mblocks = md_alloc_scan_dag(md, root, PROP_LG_MBLOCK, "fwd",
+	    &mblocknodes);
+	if (n_mblocks <= 0) {
+		MPO_STATUS("lgrp_traverse: No mblock nodes detected in Machine "
+		    "Descriptor\n");
+		ret_val = -1;
+		goto fail;
+	}
+
+	/*
+	 * Build the Memory Nodes.  Do this before any possibility of
+	 * bailing from this routine so we obtain ra_to_pa (needed for page
+	 * coloring) even when there are no lgroups defined.
+	 */
+	if (mblock_alloc(&new_config, U_ADD_ALL, n_mblocks) < 0) {
+		ret_val = -1;
+		goto fail;
+	}
+
+	mblock_update(&new_config, md, mblocknodes);
+	mblock_install(&new_config);
+
+	/* Page coloring hook is required so we can iterate through mnodes */
+	if (&page_next_pfn_for_color_cpu == NULL) {
+		MPO_STATUS("lgrp_traverse: No page coloring support\n");
+		ret_val = -1;
+		goto fail;
+	}
+
+	/* Global enable for mpo */
+	if (sun4v_mpo_enable == 0) {
+		MPO_STATUS("lgrp_traverse: MPO feature is not enabled\n");
+		ret_val = -1;
+		goto fail;
+	}
+
+	n_cpunodes = md_alloc_scan_dag(md, root, PROP_LG_CPU, "fwd", &cpunodes);
+
+	if (n_cpunodes <= 0 || n_cpunodes > NCPU) {
+		MPO_STATUS("lgrp_traverse: No CPU nodes detected "
+		    "in MD\n");
+		ret_val = -1;
+		goto fail;
+	}
+
+	MPO_DEBUG("lgrp_traverse: cpus: %d\n", n_cpunodes);
+
+	if ((ret_val = lgrp_update(md, root)) == -1)
+		goto fail;
 
 	/*
 	 * Use the address mask from the first lgroup node
@@ -634,6 +647,11 @@
 	max_locality_groups =
 	    1 << highbit(home_mask_pfn >> home_mask_pfn_shift);
 
+	stripe_shift = highbit(max_locality_groups) - 1;
+	stripe = ptob(mnode_pages);
+	stride = max_locality_groups * stripe;
+	mnode_stride = btop(stride);
+
 	/* Now verify the home mask bits are contiguous */
 
 	if (max_locality_groups - 1 != home_mask_pfn >> home_mask_pfn_shift) {
@@ -721,23 +739,17 @@
 	}
 
 fail:
-	/* MD cookies are no longer valid; ensure they are not used again. */
-	for (i = 0; i < n_mblocks; i++)
-		mpo_mblock[i].node = MDE_INVAL_ELEM_COOKIE;
-	for (i = 0; i < n_lgrpnodes; i++)
-		mpo_lgroup[i].node = MDE_INVAL_ELEM_COOKIE;
-
 	if (n_cpunodes > 0)
 		md_free_scan_dag(md, &cpunodes);
-	if (n_lgrpnodes > 0)
-		md_free_scan_dag(md, &lgrpnodes);
 	if (n_mblocks > 0)
 		md_free_scan_dag(md, &mblocknodes);
 	else
 		panic("lgrp_traverse: No memory blocks found");
 
-	if (ret_val == 0)
+	if (ret_val == 0) {
 		MPO_STATUS("MPO feature is enabled.\n");
+	} else
+		sun4v_mpo_enable = 0;	/* set this for DR */
 
 	return (ret_val);
 }
@@ -843,13 +855,26 @@
 	mem_node_add_slice(basepfn, endpfn);
 }
 
+static	void
+mpo_mem_node_del_slice(pfn_t basepfn, pfn_t endpfn)
+{
+#if defined(DEBUG) && !defined(lint)
+	static int slice_count = 0;
+
+	slice_count++;
+	MPO_DEBUG("mem_del_slice(%d): basepfn: %lx  endpfn: %lx\n",
+	    slice_count, basepfn, endpfn);
+#endif
+	mem_node_del_slice(basepfn, endpfn);
+}
+
 /*
  *  Helper routine for debugging calls to plat_assign_lgrphand_to_mem_node()
  */
 static	void
 mpo_plat_assign_lgrphand_to_mem_node(lgrp_handle_t plathand, int mnode)
 {
-	MPO_DEBUG("plat_assign_to_mem_nodes: lgroup home %ld,"
+	MPO_DEBUG("plat_assign_to_mem_nodes: lgroup home %ld, "
 	    "mnode index: %d\n", plathand, mnode);
 	plat_assign_lgrphand_to_mem_node(plathand, mnode);
 }
@@ -901,22 +926,20 @@
  *	  mblock 0		  mblock 1
  */
 
+/*ARGSUSED*/
 void
 plat_build_mem_nodes(prom_memlist_t *list, size_t nelems)
 {
-	lgrp_handle_t lgrphand, lgrp_start;
-	int i, mnode, elem;
-	uint64_t offset, stripe_end, base, len, end, ra_to_pa, stride;
-	uint64_t stripe, frag, remove;
-	mem_stripe_t *ms;
+	int elem;
+	uint64_t base, len;
 
 	/* Pre-reserve space for plat_assign_lgrphand_to_mem_node */
 	max_mem_nodes = max_locality_groups;
 
+	mstripe_update(&mpo_config);
+
 	/* Check for non-MPO sun4v platforms */
 	if (n_locality_groups <= 1) {
-		ASSERT(n_locality_groups == 1);
-		ASSERT(max_locality_groups == 1 && max_mem_nodes == 1);
 		mpo_plat_assign_lgrphand_to_mem_node(LGRP_DEFAULT_HANDLE, 0);
 		for (elem = 0; elem < nelems; list++, elem++) {
 			base = list->addr;
@@ -927,105 +950,8 @@
 		}
 		mem_node_pfn_shift = 0;
 		mem_node_physalign = 0;
-
-		if (n_mblocks == 1) {
-			n_mem_stripes = 0;
-		} else {
-			n_mem_stripes = n_mblocks;
-			bzero(mem_stripes, mstripesz);
-			for (i = 0; i < n_mblocks; i++) {
-				base = mpo_mblock[i].base;
-				end = base + mpo_mblock[i].size;
-				ASSERT(end > base);
-				mem_stripes[i].exists = 1;
-				mpo_mblock[i].base_pfn = btop(base);
-				mpo_mblock[i].end_pfn = btop(end - 1);
-				mem_stripes[i].physbase =
-				    mpo_mblock[i].base_pfn;
-				mem_stripes[i].physmax = mpo_mblock[i].end_pfn;
-			}
-		}
-		return;
-	}
-
-	bzero(mem_stripes, mstripesz);
-	stripe = ptob(mnode_pages);
-	stride = max_locality_groups * stripe;
-
-	/* Save commonly used values in globals */
-	mnode_stride = btop(stride);
-	n_mem_stripes = max_locality_groups * n_mblocks;
-	stripe_shift = highbit(max_locality_groups) - 1;
-
-	for (i = 0; i < n_mblocks; i++) {
-		base = mpo_mblock[i].base;
-		end = mpo_mblock[i].base + mpo_mblock[i].size;
-		ra_to_pa = mpo_mblock[i].ra_to_pa;
-		mpo_mblock[i].base_pfn = btop(base);
-		mpo_mblock[i].end_pfn = btop(end - 1);
-
-		/* Find the offset from the prev stripe boundary in PA space. */
-		offset = (base + ra_to_pa) & (stripe - 1);
-
-		/* Set the next stripe boundary. */
-		stripe_end = base - offset + stripe;
-
-		lgrp_start = (((base + ra_to_pa) & home_mask) >>
-		    home_mask_shift);
-		lgrphand = lgrp_start;
-
-		/*
-		 * Loop over all lgroups covered by the mblock, creating a
-		 * stripe for each.  Stop when lgrp_start is visited again.
-		 */
-		do {
-			/* mblock may not span all lgroups */
-			if (base >= end)
-				break;
-
-			mnode = lgrphand;
-			ASSERT(mnode < max_mem_nodes);
-
-			/*
-			 * Calculate the size of the fragment that does not
-			 * belong to the mnode in the last partial stride.
-			 */
-			frag = (end - (base - offset)) & (stride - 1);
-			if (frag == 0) {
-				/* remove the gap */
-				remove = stride - stripe;
-			} else if (frag < stripe) {
-				/* fragment fits in stripe; keep it all */
-				remove = 0;
-			} else {
-				/* fragment is large; trim after whole stripe */
-				remove = frag - stripe;
-			}
-
-			ms = &mem_stripes[i * max_locality_groups + mnode];
-			ms->physbase = btop(base);
-			ms->physmax = btop(end - 1 - remove);
-			ms->offset = btop(offset);
-			ms->exists = 1;
-
-			/*
-			 * If we have only 1 lgroup and multiple mblocks,
-			 * then we have already established our lgrp handle
-			 * to mem_node and mem_node_config values above.
-			 */
-			if (n_locality_groups > 1) {
-				mpo_plat_assign_lgrphand_to_mem_node(lgrphand,
-				    mnode);
-				mpo_mem_node_add_slice(ms->physbase,
-				    ms->physmax);
-			}
-			base = stripe_end;
-			stripe_end += stripe;
-			offset = 0;
-			lgrphand = (((base + ra_to_pa) & home_mask) >>
-			    home_mask_shift);
-		} while (lgrphand != lgrp_start);
-	}
+	} else
+		mnode_update(&mpo_config, 0, 0, U_ADD_ALL);
 
 	/*
 	 * Indicate to vm_pagelist that the hpm_counters array
@@ -1042,11 +968,17 @@
 lgrp_handle_t
 plat_lgrp_cpu_to_hand(processorid_t id)
 {
+	lgrp_handle_t lgrphand;
+
+	mpo_rd_lock();
 	if (n_locality_groups > 1) {
-		return ((lgrp_handle_t)mpo_cpu[(int)id].home);
+		lgrphand = (lgrp_handle_t)mpo_cpu[(int)id].home;
 	} else {
-		return ((lgrp_handle_t)LGRP_DEFAULT_HANDLE); /* Default */
+		lgrphand = (lgrp_handle_t)LGRP_DEFAULT_HANDLE; /* Default */
 	}
+	mpo_rd_unlock();
+
+	return (lgrphand);
 }
 
 int
@@ -1081,6 +1013,7 @@
 	 * the pfn falls to get the ra_to_pa adjustment, and extract
 	 * the home bits.
 	 */
+	mpo_rd_lock();
 	mb = &mpo_mblock[0];
 	for (i = 0; i < n_mblocks; i++) {
 		if (pfn >= mb->base_pfn && pfn <= mb->end_pfn) {
@@ -1088,6 +1021,7 @@
 			mnode = (((pfn + ra_to_pa_pfn) & home_mask_pfn) >>
 			    home_mask_pfn_shift);
 			ASSERT(mnode < max_mem_nodes);
+			mpo_rd_unlock();
 			return (mnode);
 		}
 		mb++;
@@ -1119,9 +1053,11 @@
 	 * Find the mblock in which the pfn falls
 	 * in order to get the ra_to_pa adjustment.
 	 */
+	mpo_rd_lock();
 	for (mb = &mpo_mblock[0], i = 0; i < n_mblocks; i++, mb++) {
 		if (pfn <= mb->end_pfn && pfn >= mb->base_pfn) {
 			ra_to_pa_pfn = btop(mb->ra_to_pa);
+			mpo_rd_unlock();
 			return (pfn + ra_to_pa_pfn);
 		}
 	}
@@ -1160,6 +1096,11 @@
  *          When the caller calculates a pfn that is greater than the
  *          returned value it->mi_mblock_end, the caller should again
  *          call plat_mem_node_iterator_init, passing init=0.
+ *
+ *          The last mblock in continuation case may be invalid because
+ *          of memory DR.  To detect this situation mi_genid is checked
+ *          against mpo_genid which is incremented after a memory DR
+ *          operation.  See also plat_slice_add()/plat_slice_del().
  */
 pfn_t
 plat_mem_node_iterator_init(pfn_t pfn, int mnode, uchar_t szc,
@@ -1177,15 +1118,20 @@
 	ASSERT(n_mblocks > 0);
 	ASSERT(P2PHASE(pfn, szcpgcnt) == 0);
 
-	if (init) {
+	mpo_rd_lock();
+
+	if (init || (it->mi_genid != mpo_genid)) {
+		it->mi_genid = mpo_genid;
 		it->mi_last_mblock = 0;
 		it->mi_init = 1;
 	}
 
 	/* Check if mpo is not enabled and we only have one mblock */
 	if (n_locality_groups == 1 && n_mblocks == 1) {
-		if (P2PHASE(base_ra_to_pa_pfn, szcpgcnt))
-			return ((pfn_t)-1);
+		if (P2PHASE(base_ra_to_pa_pfn, szcpgcnt)) {
+			pfn = (pfn_t)-1;
+			goto done;
+		}
 		it->mi_mnode = mnode;
 		it->mi_ra_to_pa = base_ra_to_pa_pfn;
 		it->mi_mnode_pfn_mask = 0;
@@ -1197,7 +1143,7 @@
 			pfn = P2ROUNDUP(it->mi_mblock_base, szcpgcnt);
 		if ((pfn + szcpgcnt - 1) > it->mi_mblock_end)
 			pfn = (pfn_t)-1;
-		return (pfn);
+		goto done;
 	}
 
 	/* init=1 means begin iterator, init=0 means continue */
@@ -1208,8 +1154,10 @@
 		i = it->mi_last_mblock;
 		ASSERT(pfn >
 		    mem_stripes[i * max_locality_groups + mnode].physmax);
-		if (++i == n_mblocks)
-			return ((pfn_t)-1);
+		if (++i == n_mblocks) {
+			pfn = (pfn_t)-1;
+			goto done;
+		}
 	}
 
 	/*
@@ -1229,7 +1177,8 @@
 	}
 	if (i == n_mblocks) {
 		it->mi_last_mblock = i - 1;
-		return ((pfn_t)-1);
+		pfn = (pfn_t)-1;
+		goto done;
 	}
 
 	it->mi_last_mblock = i;
@@ -1250,6 +1199,8 @@
 		ASSERT(pfn + szcpgcnt - 1 <= end);
 	}
 	ASSERT((pfn + szcpgcnt - 1) <= mpo_mblock[i].end_pfn);
+done:
+	mpo_rd_unlock();
 	return (pfn);
 }
 
@@ -1300,6 +1251,7 @@
 	 * multiply by stripe width, and add the start and end fragments.
 	 */
 
+	mpo_rd_lock();
 	for (i = mnode; i < n_mem_stripes; i += max_locality_groups) {
 		ms = &mem_stripes[i];
 		if (ms->exists &&
@@ -1357,6 +1309,7 @@
 	}
 
 	*npages_out = npages;
+	mpo_rd_unlock();
 }
 
 /*
@@ -1384,9 +1337,15 @@
 	 * to get a sane mask.
 	 */
 
-	if (md_get_prop_val(md, cpu0, "mmu-page-size-list", &szc_mask))
-		szc_mask = 0;
-	szc_mask |=  (1 << TTE4M);	/* largest in sun4v default support */
+	if (cpu0 == NULL)
+		szc_mask = szc_mask0;
+	else {
+		if (md_get_prop_val(md, cpu0, "mmu-page-size-list", &szc_mask))
+			szc_mask = 0;
+		/* largest in sun4v default support */
+		szc_mask |=  (1 << TTE4M);
+		szc_mask0 = szc_mask;
+	}
 	max_szc = highbit(szc_mask) - 1;
 	if (max_szc > TTE256M)
 		max_szc = TTE256M;
@@ -1494,3 +1453,592 @@
 
 	return (mask != 0);
 }
+
+/*
+ * mblock_alloc
+ *
+ * Allocate memory for mblock an stripe arrays from either static or
+ * dynamic space depending on utype, and return the result in mc.
+ * Returns 0 on success and -1 on error.
+ */
+
+static int
+mblock_alloc(mpo_config_t *mc, update_t utype, int nmblocks)
+{
+	mblock_md_t *mb = NULL;
+	mem_stripe_t *ms = NULL;
+	int nstripes = MAX_MEM_NODES * nmblocks;
+	size_t mblocksz = nmblocks * sizeof (struct mblock_md);
+	size_t mstripesz = nstripes * sizeof (mem_stripe_t);
+	size_t allocsz = mmu_ptob(mmu_btopr(mblocksz + mstripesz));
+
+	/*
+	 * Allocate space for mblocks and mstripes.
+	 *
+	 * For DR allocations, just use kmem_alloc(), and set
+	 * mc_alloc_sz to indicate it was used.
+	 *
+	 * For boot allocation:
+	 * If we have a small number of mblocks we will use the space
+	 * that we preallocated. Otherwise, we will dynamically
+	 * allocate the space from the prom and map it to the
+	 * reserved VA at MPOBUF_BASE.
+	 */
+
+	if (utype == U_ADD || utype == U_DEL) {
+		mb = (struct mblock_md *)kmem_zalloc(allocsz, KM_SLEEP);
+		ms = (mem_stripe_t *)(mb + nmblocks);
+		mc->mc_alloc_sz = allocsz;
+	} else if (nmblocks <= SMALL_MBLOCKS_COUNT) {
+		mb = &small_mpo_mblocks[0];
+		ms = &small_mem_stripes[0];
+		mc->mc_alloc_sz = 0;
+	} else {
+		/* Ensure that we dont request more space than reserved */
+		if (allocsz > MPOBUF_SIZE) {
+			MPO_STATUS("mblock_alloc: Insufficient space "
+			    "for mblock structures \n");
+			return (-1);
+		}
+		mb = (struct mblock_md *)
+		    prom_alloc((caddr_t)MPOBUF_BASE, allocsz, PAGESIZE);
+		if (mb != (struct mblock_md *)MPOBUF_BASE) {
+			MPO_STATUS("mblock_alloc: Cannot allocate space "
+			    "for mblocks \n");
+			return (-1);
+		}
+		mpo_heap32_buf = (caddr_t)MPOBUF_BASE;
+		mpo_heap32_bufsz = MPOBUF_SIZE;
+		ms = (mem_stripe_t *)(mb + nmblocks);
+		mc->mc_alloc_sz = 0;
+	}
+	mc->mc_mblocks = mb;
+	mc->mc_stripes = ms;
+	mc->mc_nmblocks = nmblocks;
+	mc->mc_nstripes = nstripes;
+	MPO_DEBUG("mblock_alloc: mblocks: %d\n", nmblocks);
+	return (0);
+}
+
+/*
+ * mblock_free
+ *
+ * Free memory in mc that was allocated by mblock_alloc.
+ */
+
+static void
+mblock_free(mpo_config_t *mc)
+{
+	if (mc->mc_alloc_sz > 0) {
+		ASSERT(mc->mc_mblocks != mpo_mblock);
+		kmem_free((caddr_t)mc->mc_mblocks, mc->mc_alloc_sz);
+	}
+	bzero(mc, sizeof (*mc));
+}
+
+/*
+ * mblock_install
+ *
+ * Install mblock config passed in mc as the global configuration.
+ * May only be called at boot or while holding mpo_wr_lock.
+ */
+
+static void
+mblock_install(mpo_config_t *mc)
+{
+	mpo_mblock = mc->mc_mblocks;
+	n_mblocks = mc->mc_nmblocks;
+	mem_stripes = mc->mc_stripes;
+	n_mem_stripes = mc->mc_nstripes;
+	base_ra_to_pa_pfn = btop(mc->mc_mblocks[0].ra_to_pa);
+	mpo_config = *mc;
+}
+
+/*
+ * mblock_update
+ *
+ * Traverse mblocknodes, read the mblock properties from the MD, and
+ * save the mblocks in mc.
+ */
+
+static void
+mblock_update(mpo_config_t *mc, md_t md, mde_cookie_t *mblocknodes)
+{
+	uint64_t i, j;
+	int result = 0;
+	mblock_md_t *mblock = mc->mc_mblocks;
+
+	for (i = 0, j = 0; j < mc->mc_nmblocks; j++) {
+
+		/* Without a base or size value we will fail */
+		result = get_int(md, mblocknodes[j], PROP_LG_BASE,
+		    &mblock[i].base);
+		if (result < 0) {
+			MPO_STATUS("mblock_update: "
+			    "PROP_LG_BASE is missing\n");
+			mc->mc_nmblocks = 0;
+			return;
+		}
+
+		result = get_int(md, mblocknodes[j], PROP_LG_SIZE,
+		    &mblock[i].size);
+		if (result < 0) {
+			MPO_STATUS("mblock_update: "
+			    "PROP_LG_SIZE is missing\n");
+			mc->mc_nmblocks = 0;
+			return;
+		}
+
+		result = get_int(md, mblocknodes[j],
+		    PROP_LG_RA_PA_OFFSET, &mblock[i].ra_to_pa);
+
+		/* If we don't have an ra_pa_offset, just set it to 0 */
+		if (result < 0)
+			mblock[i].ra_to_pa = 0;
+
+		MPO_DEBUG("mblock[%ld]: base = %lx, size = %lx, "
+		    "ra_to_pa = %lx\n", i,
+		    mblock[i].base,
+		    mblock[i].size,
+		    mblock[i].ra_to_pa);
+
+		/* check for unsupportable values of base and size */
+		if (mblock[i].base > mblock[i].base + mblock[i].size) {
+			MPO_STATUS("mblock_update: "
+			    "PROP_LG_BASE+PROP_LG_SIZE is invalid: "
+			    "base = %lx, size = %lx\n",
+			    mblock[i].base, mblock[i].size);
+			mc->mc_nmblocks = 0;
+			return;
+		}
+
+		/* eliminate size==0 blocks */
+		if (mblock[i].size != 0) {
+			uint64_t base = mblock[i].base;
+			uint64_t end = base + mblock[i].size;
+			ASSERT(end > base);
+			mblock[i].base_pfn = btop(base);
+			mblock[i].end_pfn = btop(end - 1);
+			i++;
+		}
+	}
+
+	if (i == 0) {
+		MPO_STATUS("mblock_update: "
+		    "No non-empty mblock nodes were found "
+		    "in the Machine Descriptor\n");
+		mc->mc_nmblocks = 0;
+		return;
+	}
+	ASSERT(i <= mc->mc_nmblocks);
+	mc->mc_nmblocks = i;
+
+	/* Must sort mblocks by address for mem_node_iterator_init() */
+	mblock_sort(mblock, mc->mc_nmblocks);
+}
+
+/*
+ * mblock_update_add
+ *
+ * Update mblock config after a memory DR add.  The added range is not
+ * needed, as we read *all* mblock nodes from the MD.  Save the mblocks
+ * in mc.
+ */
+
+static void
+mblock_update_add(mpo_config_t *mc)
+{
+	md_t *md;
+	mde_cookie_t root, *mblocknodes;
+	int nmblocks = 0;
+
+	if ((md = md_get_handle()) == NULL) {
+		MPO_STATUS("Cannot access Machine Descriptor\n");
+		goto error;
+	}
+
+	if ((root = md_get_root(md)) == MDE_INVAL_ELEM_COOKIE)
+		goto error;
+
+	nmblocks = md_alloc_scan_dag(md, root, PROP_LG_MBLOCK, "fwd",
+	    &mblocknodes);
+	if (nmblocks <= 0) {
+		MPO_STATUS("No mblock nodes detected in Machine Descriptor\n");
+		goto error;
+	}
+
+	if (mblock_alloc(mc, U_ADD, nmblocks) < 0)
+		goto error;
+
+	mblock_update(mc, md, mblocknodes);
+	md_free_scan_dag(md, &mblocknodes);
+	(void) md_fini_handle(md);
+	return;
+error:
+	panic("mblock_update_add: cannot process mblocks from MD.\n");
+}
+
+/*
+ * mblock_update_del
+ *
+ * Update mblocks after a memory DR deletion of the range (ubase, uend).
+ * Allocate a new mblock config, copy old config to the new, modify the new
+ * mblocks to reflect the deletion.   The new mblocks are returned in
+ * mc_new and are not yet installed as the active config.
+ */
+
+static void
+mblock_update_del(mpo_config_t *mc_new, mpo_config_t *mc_old, pfn_t ubase,
+    pfn_t uend)
+{
+	int i, j;
+	pfn_t base, end;
+	mblock_md_t *mblock;
+	int nmblocks = mc_old->mc_nmblocks;
+
+	MPO_DEBUG("mblock_update_del(0x%lx, 0x%lx)\n", ubase, uend);
+
+	/*
+	 * Allocate mblocks in mc_new and copy the old to the new.
+	 * Allocate one extra in case the deletion splits an mblock.
+	 */
+	if (mblock_alloc(mc_new, U_DEL, nmblocks + 1) < 0)
+		return;
+	mblock = mc_new->mc_mblocks;
+	bcopy(mc_old->mc_mblocks, mblock, nmblocks * sizeof (mblock_md_t));
+
+	/*
+	 * Find the mblock containing the deleted range and adjust it in
+	 * the new config.
+	 */
+	for (i = 0; i < nmblocks; i++) {
+
+		base = btop(mblock[i].base);
+		end = base + btop(mblock[i].size) - 1;
+
+		/*
+		 * Adjust the mblock based on the subset that was deleted.
+		 *
+		 * If the entire mblk was deleted, compact the table.
+		 *
+		 * If the middle of the mblk was deleted, extend
+		 * the table.  Space for the new slot was already
+		 * allocated.
+		 *
+		 * The memory to be deleted is a mblock or a subset of
+		 * and does not span multiple mblocks.
+		 */
+		if (base == ubase && end == uend) {
+			for (j = i; j < nmblocks - 1; j++)
+				mblock[j] = mblock[j + 1];
+			nmblocks--;
+			bzero(&mblock[nmblocks], sizeof (*mblock));
+			break;
+		} else if (base < ubase && end > uend) {
+			for (j = nmblocks - 1; j >= i; j--)
+				mblock[j + 1] = mblock[j];
+			mblock[i].size = ptob(ubase - base);
+			mblock[i].end_pfn = ubase - 1;
+			mblock[i + 1].base = ptob(uend + 1);
+			mblock[i + 1].size = ptob(end - uend);
+			mblock[i + 1].base_pfn = uend + 1;
+			nmblocks++;
+			break;
+		} else if (base == ubase) {
+			MPO_DEBUG("mblock_update_del: shrink>"
+			    " i=%d base=0x%lx end=0x%lx", i, base, end);
+			mblock[i].base = ptob(uend + 1);
+			mblock[i].size -= ptob(uend - ubase + 1);
+			base = uend + 1;
+			mblock[i].base_pfn = base;
+			mblock[i].end_pfn = end;
+			MPO_DEBUG(" nbase=0x%lx nend=0x%lx\n", base, end);
+			break;
+		} else if (end == uend) {
+			MPO_DEBUG("mblock_update_del: shrink<"
+			    " i=%d base=0x%lx end=0x%lx", i, base, end);
+			mblock[i].size -= ptob(uend - ubase + 1);
+			end = ubase - 1;
+			mblock[i].base_pfn = base;
+			mblock[i].end_pfn = end;
+			MPO_DEBUG(" nbase=0x%lx nend=0x%lx\n", base, end);
+			break;
+		}
+	}
+	mc_new->mc_nmblocks = nmblocks;
+	ASSERT(end > base);
+}
+
+/*
+ * mstripe_update
+ *
+ * Read mblocks from mc and update mstripes in mc
+ */
+
+static void
+mstripe_update(mpo_config_t *mc)
+{
+	lgrp_handle_t lgrphand, lgrp_start;
+	int i, mnode;
+	uint64_t offset, stripe_end, base, end, ra_to_pa, stride;
+	uint64_t stripe, frag, remove;
+	mem_stripe_t *ms;
+	mblock_md_t *mblock = mc->mc_mblocks;
+	int nmblocks = mc->mc_nmblocks;
+	int mstripesz = MAX_MEM_NODES * nmblocks * sizeof (mem_stripe_t);
+
+	/* Check for non-MPO sun4v platforms or memory DR removal */
+	if (n_locality_groups <= 1) {
+		ASSERT(n_locality_groups == 1);
+		ASSERT(max_locality_groups == 1 && max_mem_nodes == 1);
+
+		if (nmblocks == 1) {
+			mc->mc_nstripes = 0;
+		} else {
+			mc->mc_nstripes = nmblocks;
+			bzero(mc->mc_stripes, mstripesz);
+			for (i = 0; i < nmblocks; i++) {
+				mc->mc_stripes[i].exists = 1;
+				mc->mc_stripes[i].physbase = mblock[i].base_pfn;
+				mc->mc_stripes[i].physmax = mblock[i].end_pfn;
+			}
+		}
+		return;
+	}
+
+	bzero(mc->mc_stripes, mstripesz);
+	mc->mc_nstripes = max_locality_groups * nmblocks;
+	stripe = ptob(mnode_pages);
+	stride = max_locality_groups * stripe;
+
+	for (i = 0; i < nmblocks; i++) {
+		base = mblock[i].base;
+		end = base + mblock[i].size;
+		ra_to_pa = mblock[i].ra_to_pa;
+
+		/* Find the offset from the prev stripe boundary in PA space. */
+		offset = (base + ra_to_pa) & (stripe - 1);
+
+		/* Set the next stripe boundary. */
+		stripe_end = base - offset + stripe;
+
+		lgrp_start = (((base + ra_to_pa) & home_mask) >>
+		    home_mask_shift);
+		lgrphand = lgrp_start;
+
+		/*
+		 * Loop over all lgroups covered by the mblock, creating a
+		 * stripe for each.  Stop when lgrp_start is visited again.
+		 */
+		do {
+			/* mblock may not span all lgroups */
+			if (base >= end)
+				break;
+
+			mnode = lgrphand;
+			ASSERT(mnode < max_mem_nodes);
+
+			/*
+			 * Calculate the size of the fragment that does not
+			 * belong to the mnode in the last partial stride.
+			 */
+			frag = (end - (base - offset)) & (stride - 1);
+			if (frag == 0) {
+				/* remove the gap */
+				remove = stride - stripe;
+			} else if (frag < stripe) {
+				/* fragment fits in stripe; keep it all */
+				remove = 0;
+			} else {
+				/* fragment is large; trim after whole stripe */
+				remove = frag - stripe;
+			}
+
+			ms = &mc->mc_stripes[i * max_locality_groups + mnode];
+			ms->physbase = btop(base);
+			ms->physmax = btop(end - 1 - remove);
+			ms->offset = btop(offset);
+			ms->exists = 1;
+
+			base = stripe_end;
+			stripe_end += stripe;
+			offset = 0;
+			lgrphand = (((base + ra_to_pa) & home_mask) >>
+			    home_mask_shift);
+		} while (lgrphand != lgrp_start);
+	}
+}
+
+#define	INTERSECT(a, b, c, d)				\
+	if (((a) >= (c) && (a) <= (d)) ||		\
+	    ((c) >= (a) && (c) <= (b))) {		\
+		(c) = MAX((a), (c));			\
+		(d) = MIN((b), (d));			\
+	} else {					\
+		ASSERT((a) >= (d) || (b) <= (c));	\
+		continue;				\
+	}						\
+
+/*
+ * mnode_update
+ *
+ * Read stripes from mc and update mnode extents.  The mnode extents are
+ * part of the live configuration, so this can only be done at boot time
+ * or while holding the mpo_wr_lock.
+ */
+
+static void
+mnode_update(mpo_config_t *mc, pfn_t ubase, pfn_t uend, update_t utype)
+{
+	int i, j, mnode, found;
+	pfn_t base, end;
+	mem_stripe_t *ms;
+
+	MPO_DEBUG("mnode_udpate: basepfn: %lx  endpfn: %lx\n", ubase, uend);
+
+	if (n_locality_groups <= 1 && mc->mc_nmblocks == 1) {
+		if (utype == U_ADD)
+			mpo_mem_node_add_slice(ubase, uend);
+		else if (utype == U_DEL)
+			mpo_mem_node_del_slice(ubase, uend);
+		else
+			panic("mnode update: %d: invalid\n", utype);
+		return;
+	}
+
+	found = 0;
+	for (i = 0; i < mc->mc_nmblocks; i++) {
+		for (mnode = 0; mnode < max_locality_groups; mnode++) {
+
+			j = i * max_locality_groups + mnode;
+			ms = &mc->mc_stripes[j];
+			if (!ms->exists)
+				continue;
+
+			base = ms->physbase;
+			end = ms->physmax;
+
+			/*
+			 * Look for the mstripes intersecting this slice.
+			 *
+			 * The mstripe and slice pairs may not be equal
+			 * if a subset of a mblock is added/deleted.
+			 */
+			switch (utype) {
+			case U_ADD:
+				INTERSECT(ubase, uend, base, end);
+				/*FALLTHROUGH*/
+			case U_ADD_ALL:
+				if (n_locality_groups > 1)
+					mpo_plat_assign_lgrphand_to_mem_node(
+					    mnode, mnode);
+				mpo_mem_node_add_slice(base, end);
+				break;
+			case U_DEL:
+				INTERSECT(ubase, uend, base, end);
+				mpo_mem_node_del_slice(base, end);
+				break;
+			default:
+				panic("mnode_update: %d: invalid\n", utype);
+				break;
+			}
+
+			found++;
+		}
+	}
+
+	if (!found)
+		panic("mnode_update: mstripe not found");
+
+#ifdef	DEBUG
+	if (utype == U_ADD_ALL || utype == U_DEL)
+		return;
+	found = 0;
+	for (i = 0; i < max_mem_nodes; i++) {
+		if (!mem_node_config[i].exists)
+			continue;
+		if (ubase >= mem_node_config[i].physbase &&
+		    ubase <= mem_node_config[i].physmax)
+			found |= 1;
+		if (uend >= mem_node_config[i].physbase &&
+		    uend <= mem_node_config[i].physmax)
+			found |= 2;
+	}
+	ASSERT(found == 3);
+	{
+		pfn_t minpfn, maxpfn;
+
+		mem_node_max_range(&minpfn, &maxpfn);
+		ASSERT(minpfn <= ubase);
+		ASSERT(maxpfn >= uend);
+	}
+#endif
+}
+
+/*
+ * Plat_slice_add()/plat_slice_del() are the platform hooks
+ * for adding/deleting a pfn range to/from the system.
+ *
+ * Platform_slice_add() is used for both boot/DR cases.
+ *
+ * - Zeus has already added the mblocks to the MD, so read the updated
+ *   MD and allocate all data structures required to manage the new memory
+ *   configuration.
+ *
+ * - Recompute the stripes which are derived from the mblocks.
+ *
+ * - Update (expand) the mnode extents and install the modified mblocks as
+ *   the new mpo config.  This must be done while holding the mpo_wr_lock
+ *   to guarantee that no other threads access the mpo meta-data.
+ *
+ * - Unlock MPO data structures; the new config is live.  Free the old config.
+ *
+ * Plat_slice_del() is used for DR only.
+ *
+ * - Zeus has not yet modified the MD to reflect the deletion, so copy
+ *   the old mpo mblocks and delete the range from the copy.
+ *
+ * - Recompute the stripes which are derived from the mblocks.
+ *
+ * - Update (shrink) the mnode extents and install the modified mblocks as
+ *   the new mpo config.  This must be done while holding the mpo_wr_lock
+ *   to guarantee that no other threads access the mpo meta-data.
+ *
+ * - Unlock MPO data structures; the new config is live.  Free the old config.
+ */
+
+void
+plat_slice_add(pfn_t base, pfn_t end)
+{
+	mpo_config_t old_config = mpo_config;
+	mpo_config_t new_config;
+
+	VALIDATE_SLICE(base, end);
+	mblock_update_add(&new_config);
+	mstripe_update(&new_config);
+	mpo_wr_lock();
+	mblock_install(&new_config);
+	/* Use new config to add all ranges for mnode_update */
+	mnode_update(&new_config, base, end, U_ADD);
+	mpo_genid++;
+	mpo_wr_unlock();
+	mblock_free(&old_config);
+}
+
+void
+plat_slice_del(pfn_t base, pfn_t end)
+{
+	mpo_config_t old_config = mpo_config;
+	mpo_config_t new_config;
+
+	VALIDATE_SLICE(base, end);
+	mblock_update_del(&new_config, &old_config, base, end);
+	mstripe_update(&new_config);
+	mpo_wr_lock();
+	/* Use old config to find deleted range for mnode_update */
+	mnode_update(&old_config, base, end, U_DEL);
+	mblock_install(&new_config);
+	mpo_genid++;
+	mpo_wr_unlock();
+	mblock_free(&old_config);
+}
--- a/usr/src/uts/sun4v/promif/promif_emul.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4v/promif/promif_emul.c	Mon Jul 20 13:07:46 2009 -0400
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/promif_impl.h>
 #include <sys/machsystm.h>
 #include <sys/lpad.h>
@@ -37,19 +35,39 @@
 #include <sys/hypervisor_api.h>
 #include <sys/mdesc.h>
 #include <sys/mach_descrip.h>
+#include <sys/cpu_module.h>
 
 #ifndef _KMDB
+#include <sys/pte.h>
+#include <vm/hat_sfmmu.h>
+#include <sys/memlist_impl.h>
+
 static processorid_t cif_cpu;
 static struct translation *cif_prom_trans;
 static size_t cif_prom_ntrans;
 
 int cif_cpu_mp_ready;
 int (*prom_cif_handler)(void *) = NULL;
+
+extern struct memlist *phys_avail;
+extern struct vnode prom_ppages;
+extern void kdi_tlb_page_unlock(caddr_t, int);
+
+#define	COMBINE(hi, lo) (((uint64_t)(uint32_t)(hi) << 32) | (uint32_t)(lo))
+#define	OFW_PT_START_ADDR	0xfffffffc00000000	/* OBP PT start */
+#define	OFW_PT_END_ADDR		0xffffffffffffffff	/* OBP PT end */
+
+#define	PROM_ADDR(a)	(((a) >= OFW_START_ADDR && (a) <= OFW_END_ADDR) || \
+			((a) >= OFW_PT_START_ADDR && (a) <= OFW_PT_END_ADDR))
 #endif
 
 #ifdef DEBUG
 uint_t cif_debug;
-#endif /* DEBUG */
+int prom_free_debug;
+#define	PMFREE_DEBUG(args...) if (prom_free_debug) printf(args)
+#else
+#define	PMFREE_DEBUG(args...)
+#endif
 
 extern int (*cif_handler)(void *);
 
@@ -171,6 +189,161 @@
 
 #else
 
+static struct translation *
+read_prom_mappings(size_t *ntransp)
+{
+	char *prop = "translations";
+	pnode_t node;
+	size_t translen;
+	ihandle_t immu;
+	struct translation *transroot;
+
+	*ntransp = 0;
+
+	/*
+	 * the "translations" property is associated with the mmu node
+	 */
+	if ((immu = prom_mmu_ihandle()) == (ihandle_t)-1) {
+		PMFREE_DEBUG("no mmu ihandle");
+		return (NULL);
+	}
+	node = (pnode_t)prom_getphandle(immu);
+	if (node == OBP_NONODE || node == OBP_BADNODE) {
+		PMFREE_DEBUG("no mmu node");
+		return (NULL);
+	}
+
+	if ((translen = prom_getproplen(node, prop)) == -1) {
+		PMFREE_DEBUG("no translations property");
+		return (NULL);
+	}
+	transroot = (struct translation *)kmem_zalloc(translen, KM_SLEEP);
+
+	if (prom_getprop(node, prop, (caddr_t)transroot) == -1) {
+		PMFREE_DEBUG("translations getprop failed");
+		kmem_free(transroot, translen);
+		return (NULL);
+	}
+	*ntransp = translen / sizeof (*transroot);
+
+	return (transroot);
+}
+
+static void
+unmap_prom_mappings(struct translation *transroot, size_t ntransroot)
+{
+	int i, j, rv;
+	int npgs, nunmapped, nfreed, nskipped;
+	char *p;
+	tte_t tte;
+	pfn_t pfn;
+	page_t *pp;
+	uint64_t vaddr;
+	struct translation *promt;
+	cpuset_t other_cpus;
+
+	/*
+	 * During startup isa_list is allocated in OBP address space
+	 * so it needs to be re-allocated in kernel address space
+	 * before OBP memory is unmapped.
+	 *
+	 * see cpu_setup_common().
+	 */
+	p = kmem_zalloc(strlen(isa_list) + 1, KM_SLEEP);
+	(void) strcpy(p, isa_list);
+	isa_list = p;
+
+	nfreed = 0;
+	nunmapped = 0;
+	nskipped = 0;
+
+	for (i = 0, promt = transroot; i < ntransroot; i++, promt++) {
+		ASSERT(promt->tte_hi != 0);
+		ASSERT32(promt->virt_hi == 0 && promt->size_hi == 0);
+
+		vaddr = COMBINE(promt->virt_hi, promt->virt_lo);
+
+		if (!PROM_ADDR(vaddr)) {
+			nskipped++;
+			continue;
+		}
+
+		npgs = mmu_btopr(COMBINE(promt->size_hi, promt->size_lo));
+
+		if (npgs > 1) {
+			PMFREE_DEBUG("large trans vaddr=0x%lx, npgs=%d\n",
+			    vaddr, npgs);
+		}
+		for (j = 0; j < npgs; j++) {
+
+			pfn = sfmmu_vatopfn((caddr_t)vaddr, KHATID, &tte);
+
+			if (pfn == PFN_INVALID) {
+				tte.tte_inthi = promt->tte_hi;
+				tte.tte_intlo = promt->tte_lo;
+				pfn = TTE_TO_PFN((caddr_t)COMBINE(
+				    promt->virt_hi, promt->virt_lo), &tte);
+				PMFREE_DEBUG(
+				    "no mapping for vaddr=0x%lx (opfn=0x%lx)\n",
+				    vaddr, pfn);
+				break;
+			}
+			ASSERT(!TTE_IS_LOCKED(&tte));
+			ASSERT(TTE_IS_8K(&tte));
+
+			/*
+			 * Unload the current mapping for the page and
+			 * if it is the last mapping, free the page.
+			 */
+			pp = page_numtopp_nolock(pfn);
+			PMFREE_DEBUG("unmap vaddr=0x%lx pfn=0x%lx pp=0x%p",
+			    vaddr, pfn, (void *)pp);
+			ASSERT(pp);
+			ASSERT(PAGE_EXCL(pp));
+			ASSERT(PP_ISNORELOC(pp));
+			ASSERT(!PP_ISFREE(pp));
+			ASSERT(page_find(&prom_ppages, pfn));
+			ASSERT(page_get_pagecnt(pp->p_szc) == 1);
+
+			hat_unload(kas.a_hat, (caddr_t)vaddr, PAGESIZE,
+			    HAT_UNLOAD_UNLOCK);
+
+			if (pp->p_mapping) {
+				PMFREE_DEBUG(" skip\n");
+			} else {
+				PP_CLRNORELOC(pp);
+				page_destroy(pp, 0);
+				memlist_write_lock();
+				rv = memlist_add_span(pfn << PAGESHIFT,
+				    PAGESIZE, &phys_avail);
+				ASSERT(rv == MEML_SPANOP_OK);
+				memlist_write_unlock();
+				PMFREE_DEBUG(" free\n");
+				nfreed++;
+			}
+			nunmapped++;
+			vaddr += PAGESIZE;
+		}
+	}
+
+	if (transroot) {
+		PMFREE_DEBUG("nunmapped=%d nfreed=%d nskipped=%d\n",
+		    nunmapped, nfreed, nskipped);
+		kmem_free(transroot, ntransroot * sizeof (*transroot));
+	}
+
+	/*
+	 * Unload OBP permanent mappings.
+	 */
+	kdi_tlb_page_unlock((caddr_t)OFW_START_ADDR, 1);
+	kpreempt_disable();
+	other_cpus = cpu_ready_set;
+	CPUSET_DEL(other_cpus, CPU->cpu_id);
+	xt_some(other_cpus, vtag_unmap_perm_tl1, (uint64_t)OFW_START_ADDR,
+	    KCONTEXT);
+	kpreempt_enable();
+}
+
 static void cache_prom_data(void);
 
 /*
@@ -252,6 +425,8 @@
 	void (*kmdb_cb)(void);
 	uint64_t rtba;
 	uint64_t rv;
+	size_t ntransroot;
+	struct translation *transroot;
 
 	/*
 	 * Check if domaining is enabled. If not, do not
@@ -260,6 +435,8 @@
 	if (!domaining_enabled())
 		return;
 
+	transroot = read_prom_mappings(&ntransroot);
+
 	/*
 	 * Cache PROM data that is needed later, e.g. a shadow
 	 * copy of the device tree, IO mappings, etc.
@@ -301,6 +478,9 @@
 	}
 
 	cif_check_cpus();
+
+	if (transroot != NULL)
+		unmap_prom_mappings(transroot, ntransroot);
 }
 
 static void
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4v/sys/dr_mem.h	Mon Jul 20 13:07:46 2009 -0400
@@ -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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DR_MEM_H
+#define	_DR_MEM_H
+
+/*
+ * Memory DR Control Protocol
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Memory DR Message Header
+ */
+typedef struct {
+	uint32_t	msg_type;	/* message type */
+	uint32_t	msg_arg;	/* messages argument */
+	uint64_t	req_num;	/* request number */
+} dr_mem_hdr_t;
+
+/*
+ * Memory command and response messages
+ */
+
+#define	DR_MEM_DS_ID		"dr-mem"
+
+#define	DR_MEM_CONFIGURE	(0x4d43)	/* 'MC' configure mem */
+#define	DR_MEM_UNCONFIGURE	(0x4d55)	/* 'MU' unconfigure  mem */
+#define	DR_MEM_UNCONF_STATUS	(0x4d53)	/* 'MS' get mem unconf status */
+#define	DR_MEM_UNCONF_CANCEL	(0x4d4e)	/* 'MN' cancel mem unconf */
+#define	DR_MEM_QUERY		(0x4d51)	/* 'MQ' query mem info */
+
+#define	DR_MEM_OK		('o')
+#define	DR_MEM_ERROR		('e')
+
+typedef struct {
+	uint64_t	addr;		/* mblk base address */
+	uint64_t	size;		/* mblk size */
+} dr_mem_blk_t;
+
+/*
+ * Response Message
+ */
+typedef struct {
+	uint64_t	addr;		/* mblk base address */
+	uint64_t	size;		/* mblk size */
+	uint32_t	result;		/* result of the operation */
+	uint32_t	status;		/* status of the mblk */
+	uint32_t	string_off;	/* informational string offset */
+	uint32_t	reserved;	/* padding */
+} dr_mem_stat_t;
+
+typedef struct {
+	uint64_t	addr;		/* query address */
+	memquery_t	mq;		/* query results */
+} dr_mem_query_t;
+
+/*
+ * Result Codes
+ */
+#define	DR_MEM_RES_OK			0x0	/* operation succeeded */
+#define	DR_MEM_RES_FAILURE		0x1	/* operation failed */
+#define	DR_MEM_RES_BLOCKED		0x2	/* operation was blocked */
+#define	DR_MEM_RES_NOT_IN_MD		0x3	/* memory not defined in MD */
+#define	DR_MEM_RES_ESPAN		0x4	/* memory already in use */
+#define	DR_MEM_RES_EFAULT		0x5	/* memory access test failed */
+#define	DR_MEM_RES_ERESOURCE		0x6	/* resource not available */
+#define	DR_MEM_RES_PERM			0x7	/* permanent pages in span */
+#define	DR_MEM_RES_EBUSY		0x8	/* memory span busy */
+#define	DR_MEM_RES_ENOTVIABLE		0x9	/* VM viability test failed */
+#define	DR_MEM_RES_ENOWORK		0xA	/* no pages to unconfigure */
+#define	DR_MEM_RES_ECANCELLED		0xB	/* operation cancelled */
+#define	DR_MEM_RES_EREFUSED		0xC	/* operation refused */
+#define	DR_MEM_RES_EDUP			0xD	/* memory span duplicate */
+#define	DR_MEM_RES_EINVAL		0xE	/* invalid argument */
+
+/*
+ * Status Codes
+ */
+#define	DR_MEM_STAT_NOT_PRESENT		0x0	/* mblk ID not in MD */
+#define	DR_MEM_STAT_UNCONFIGURED	0x1	/* mblk unconfigured */
+#define	DR_MEM_STAT_CONFIGURED		0x2	/* mblk configured */
+
+/*
+ * Macros to access arrays that follow message header
+ */
+#define	DR_MEM_HDR(h)		((dr_mem_hdr_t *)(h))
+#define	DR_MEM_CMD_MBLKS(h)	((dr_mem_blk_t *)((DR_MEM_HDR(h)) + 1))
+#define	DR_MEM_RESP_STATS(h)	((dr_mem_stat_t *)((DR_MEM_HDR(h)) + 1))
+#define	DR_MEM_RESP_DEL_STAT(h)	((memdelstat_t *)(DR_MEM_HDR(h) + 1))
+#define	DR_MEM_RESP_QUERY(h)	((dr_mem_query_t *)(DR_MEM_HDR(h) + 1))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DR_MEM_H */
--- a/usr/src/uts/sun4v/sys/mpo.h	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4v/sys/mpo.h	Mon Jul 20 13:07:46 2009 -0400
@@ -1,4 +1,3 @@
-
 /*
  * CDDL HEADER START
  *
@@ -21,15 +20,13 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _SYS_MPO_H
 #define	_SYS_MPO_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -80,14 +77,13 @@
 
 /* Structure to store mblock information retrieved from the MD */
 
-struct mblock_md {
+typedef struct mblock_md {
 	uint64_t	base;
 	uint64_t	size;
 	uint64_t	ra_to_pa;
-	mde_cookie_t	node;
 	pfn_t		base_pfn;
 	pfn_t		end_pfn;
-};
+} mblock_md_t;
 
 /* Structure for memnode information for use by plat_pfn_to_mem_node */
 
@@ -104,6 +100,17 @@
 	int exists;	/* set to 1 if mblock has memory in this mnode stripe */
 } mem_stripe_t;
 
+/* Configuration including allocation state of mblocks and stripes */
+
+typedef struct {
+	mblock_md_t	*mc_mblocks;	/* mblock array */
+	int 		mc_nmblocks;	/* number in array */
+	mem_stripe_t 	*mc_stripes;	/* stripe array */
+	int 		mc_nstripes;	/* number in array */
+	int 		mc_alloc_sz;	/* size in bytes of mc_mblocks if */
+					/* it was kmem_alloc'd, else 0 */
+} mpo_config_t;
+
 /* These are used when MPO requires preallocated kvseg32 space */
 extern	caddr_t	mpo_heap32_buf;
 extern	size_t	mpo_heap32_bufsz;
--- a/usr/src/uts/sun4v/vm/mach_kpm.c	Tue Jul 14 11:18:27 2009 -0400
+++ b/usr/src/uts/sun4v/vm/mach_kpm.c	Mon Jul 20 13:07:46 2009 -0400
@@ -216,7 +216,32 @@
 void
 hat_kpm_addmem_mseg_update(struct memseg *msp, pgcnt_t nkpmpgs,
 	offset_t kpm_pages_off)
-{}
+{
+	pfn_t base, end;
+
+	/*
+	 * kphysm_add_memory_dynamic() does not set nkpmpgs
+	 * when page_t memory is externally allocated.  That
+	 * code must properly calculate nkpmpgs in all cases
+	 * if nkpmpgs needs to be used at some point.
+	 */
+
+	base = msp->pages_base;
+	end = msp->pages_end;
+
+	hat_devload(kas.a_hat, kpm_vbase + mmu_ptob(base),
+	    mmu_ptob(end - base), base, PROT_READ | PROT_WRITE,
+	    HAT_LOAD | HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST);
+}
+
+/*
+ * Return end of metadata for an already setup memseg.
+ */
+caddr_t
+hat_kpm_mseg_reuse(struct memseg *msp)
+{
+	return ((caddr_t)msp->epages);
+}
 
 /*ARGSUSED*/
 void
@@ -229,16 +254,17 @@
 {}
 
 /*ARGSUSED*/
-caddr_t
-hat_kpm_mseg_reuse(struct memseg *msp)
-{
-	return (0);
-}
-
-/*ARGSUSED*/
 void
 hat_kpm_delmem_mseg_update(struct memseg *msp, struct memseg **mspp)
-{}
+{
+	pfn_t base, end;
+
+	base = msp->pages_base;
+	end = msp->pages_end;
+
+	hat_unload(kas.a_hat, kpm_vbase +  mmu_ptob(base), mmu_ptob(end - base),
+	    HAT_UNLOAD | HAT_UNLOAD_UNLOCK | HAT_UNLOAD_UNMAP);
+}
 
 /*ARGSUSED*/
 void