changeset 10923:df470fd79c3c

PSARC/2008/181 Solaris Hotplug Framework 6837240 Solaris Hotplug Framework 6783012 Add support for PCIe Alternate Routing-ID Interpretation 6638136 remove obsolete ndi_ra_xxx logic from px_msi code 6695081 Race condition between pciehpc_intr() and pciehpc_init()
author Evan Yan <Evan.Yan@Sun.COM>
date Mon, 02 Nov 2009 15:58:28 +0800
parents e2081f502306
children 6b60693201e3
files usr/src/Makefile.lint usr/src/cmd/Makefile usr/src/cmd/cfgadm/cfgadm.c usr/src/cmd/hotplug/Makefile usr/src/cmd/hotplug/hotplug.c usr/src/cmd/hotplugd/Makefile usr/src/cmd/hotplugd/hotplug.xml usr/src/cmd/hotplugd/hotplugd.c usr/src/cmd/hotplugd/hotplugd_door.c usr/src/cmd/hotplugd/hotplugd_impl.c usr/src/cmd/hotplugd/hotplugd_impl.h usr/src/cmd/hotplugd/hotplugd_info.c usr/src/cmd/hotplugd/hotplugd_rcm.c usr/src/cmd/hotplugd/svc-hotplug usr/src/cmd/mdb/common/modules/genunix/Makefile.files usr/src/cmd/mdb/common/modules/genunix/devinfo.c usr/src/cmd/mdb/common/modules/genunix/devinfo.h usr/src/cmd/mdb/common/modules/genunix/genunix.c usr/src/cmd/mdb/common/modules/genunix/hotplug.c usr/src/cmd/mdb/common/modules/genunix/hotplug.h usr/src/cmd/pcitool/pcitool.c usr/src/cmd/truss/print.c usr/src/head/auth_list.h usr/src/lib/Makefile usr/src/lib/cfgadm_plugins/Makefile usr/src/lib/cfgadm_plugins/shp/Makefile usr/src/lib/cfgadm_plugins/shp/Makefile.com usr/src/lib/cfgadm_plugins/shp/amd64/Makefile usr/src/lib/cfgadm_plugins/shp/common/mapfile-vers usr/src/lib/cfgadm_plugins/shp/common/shp.c usr/src/lib/cfgadm_plugins/shp/i386/Makefile usr/src/lib/cfgadm_plugins/shp/shp.xcl usr/src/lib/cfgadm_plugins/shp/sparc/Makefile usr/src/lib/cfgadm_plugins/shp/sparcv9/Makefile usr/src/lib/libbsm/audit_event.txt usr/src/lib/libbsm/common/adt.xml usr/src/lib/libcfgadm/common/config_admin.c usr/src/lib/libdevinfo/devinfo.c usr/src/lib/libdevinfo/libdevinfo.h usr/src/lib/libdevinfo/mapfile-vers usr/src/lib/libhotplug/Makefile usr/src/lib/libhotplug/Makefile.com usr/src/lib/libhotplug/amd64/Makefile usr/src/lib/libhotplug/common/libhotplug.c usr/src/lib/libhotplug/common/libhotplug.h usr/src/lib/libhotplug/common/libhotplug_impl.h usr/src/lib/libhotplug/common/llib-lhotplug usr/src/lib/libhotplug/common/mapfile-vers usr/src/lib/libhotplug/i386/Makefile usr/src/lib/libhotplug/sparc/Makefile usr/src/lib/libhotplug/sparcv9/Makefile usr/src/lib/libsecdb/auth_attr.txt usr/src/lib/libsecdb/help/auths/HotplugHeader.html usr/src/lib/libsecdb/help/auths/HotplugModify.html usr/src/lib/libsecdb/help/auths/Makefile usr/src/lib/libsecdb/help/auths/SmfManageHotplug.html usr/src/lib/libsecdb/help/profiles/Makefile usr/src/lib/libsecdb/help/profiles/RtHotplugMngmnt.html usr/src/lib/libsecdb/prof_attr.txt usr/src/pkgdefs/SUNW0on/prototype_com usr/src/pkgdefs/SUNWarc/prototype_com usr/src/pkgdefs/SUNWarc/prototype_i386 usr/src/pkgdefs/SUNWarc/prototype_sparc usr/src/pkgdefs/SUNWckr/prototype_i386 usr/src/pkgdefs/SUNWckr/prototype_sparc usr/src/pkgdefs/SUNWcsl/prototype_com usr/src/pkgdefs/SUNWcsl/prototype_i386 usr/src/pkgdefs/SUNWcsl/prototype_sparc usr/src/pkgdefs/SUNWcsr/prototype_com usr/src/pkgdefs/SUNWcsu/prototype_com usr/src/pkgdefs/SUNWefck/prototype_com usr/src/pkgdefs/SUNWhea/prototype_com usr/src/tools/scripts/bfu.sh usr/src/uts/common/Makefile.files usr/src/uts/common/Makefile.rules usr/src/uts/common/io/busra.c usr/src/uts/common/io/devinfo.c usr/src/uts/common/io/hotplug/pciehpc/pciehpc.c usr/src/uts/common/io/hotplug/pcihp/pcihp.c usr/src/uts/common/io/hotplug/pcishpc/pcishpc.c usr/src/uts/common/io/pciex/hotplug/pcie_hp.c usr/src/uts/common/io/pciex/hotplug/pciehpc.c usr/src/uts/common/io/pciex/hotplug/pcishpc.c usr/src/uts/common/io/pciex/pcie.c usr/src/uts/common/io/pciex/pcieb.c usr/src/uts/common/io/pciex/pcieb.h usr/src/uts/common/os/ddi_hp_impl.c usr/src/uts/common/os/ddi_hp_ndi.c usr/src/uts/common/os/devcfg.c usr/src/uts/common/os/modctl.c usr/src/uts/common/sys/Makefile usr/src/uts/common/sys/autoconf.h usr/src/uts/common/sys/ddi_hp.h usr/src/uts/common/sys/ddi_hp_impl.h usr/src/uts/common/sys/ddi_impldefs.h usr/src/uts/common/sys/devinfo_impl.h usr/src/uts/common/sys/devops.h usr/src/uts/common/sys/hotplug/pci/pcicfg.h usr/src/uts/common/sys/hotplug/pci/pcie_hp.h usr/src/uts/common/sys/hotplug/pci/pciehpc.h usr/src/uts/common/sys/hotplug/pci/pciehpc_impl.h usr/src/uts/common/sys/hotplug/pci/pcihp.h usr/src/uts/common/sys/hotplug/pci/pcishpc.h usr/src/uts/common/sys/hotplug/pci/pcishpc_regs.h usr/src/uts/common/sys/modctl.h usr/src/uts/common/sys/pci.h usr/src/uts/common/sys/pci_impl.h usr/src/uts/common/sys/pcie.h usr/src/uts/common/sys/pcie_impl.h usr/src/uts/common/sys/sunndi.h usr/src/uts/i86pc/Makefile.files usr/src/uts/i86pc/Makefile.rules usr/src/uts/i86pc/io/pci/pci.c usr/src/uts/i86pc/io/pci/pci_common.c usr/src/uts/i86pc/io/pci/pci_common.h usr/src/uts/i86pc/io/pci/pci_tools.c usr/src/uts/i86pc/io/pci/pci_tools_ext.h usr/src/uts/i86pc/io/pciex/inc.flg usr/src/uts/i86pc/io/pciex/npe.c usr/src/uts/i86pc/npe/Makefile usr/src/uts/i86pc/pcie/Makefile usr/src/uts/i86xpv/Makefile.files usr/src/uts/i86xpv/Makefile.rules usr/src/uts/i86xpv/npe/Makefile usr/src/uts/i86xpv/pcie/Makefile usr/src/uts/intel/Makefile.files usr/src/uts/intel/Makefile.intel.shared usr/src/uts/intel/Makefile.rules usr/src/uts/intel/ia32/ml/modstubs.s usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c usr/src/uts/intel/io/hotplug/pciehpc/pciehpc_acpi.c usr/src/uts/intel/io/hotplug/pciehpc/pciehpc_acpi.h usr/src/uts/intel/io/pci/pci_boot.c usr/src/uts/intel/io/pci/pci_pci.c usr/src/uts/intel/io/pciex/hotplug/pciehpc_acpi.c usr/src/uts/intel/io/pciex/pcieb_x86.c usr/src/uts/intel/pci_autoconfig/Makefile usr/src/uts/intel/pci_pci/Makefile usr/src/uts/intel/pcicfg/Makefile usr/src/uts/intel/pcieb/Makefile usr/src/uts/intel/pciehpc/Makefile usr/src/uts/intel/sys/hotplug/pci/pciehpc_acpi.h usr/src/uts/sparc/Makefile.files usr/src/uts/sparc/Makefile.sparc.shared usr/src/uts/sparc/io/pciex/pcieb_sparc.c usr/src/uts/sparc/ml/modstubs.s usr/src/uts/sparc/pci_pci/Makefile usr/src/uts/sparc/pcicfg.e/Makefile usr/src/uts/sparc/pcicfg/Makefile usr/src/uts/sparc/pcie/Makefile usr/src/uts/sparc/pcieb/Makefile usr/src/uts/sparc/pcieb_bcm/Makefile usr/src/uts/sparc/pciehpc/Makefile usr/src/uts/sparc/pcihp/Makefile usr/src/uts/sparc/pcishpc/Makefile usr/src/uts/sun4/io/pcicfg.c usr/src/uts/sun4/io/pcicfg.e.c usr/src/uts/sun4/io/px/px.c usr/src/uts/sun4/io/px/px_devctl.c usr/src/uts/sun4/io/px/px_fm.c usr/src/uts/sun4/io/px/px_msi.c usr/src/uts/sun4/io/px/px_msi.h usr/src/uts/sun4/io/px/px_msiq.c usr/src/uts/sun4/io/px/px_msiq.h usr/src/uts/sun4/io/px/px_obj.h usr/src/uts/sun4/io/px/px_pec.c usr/src/uts/sun4/io/px/px_space.c usr/src/uts/sun4/io/px/px_tools.c usr/src/uts/sun4/io/px/px_tools_ext.h usr/src/uts/sun4/io/px/px_util.c usr/src/uts/sun4/io/px/px_util.h usr/src/uts/sun4/io/px/px_var.h usr/src/uts/sun4u/io/pci/pci.c usr/src/uts/sun4u/io/pci/pci_devctl.c usr/src/uts/sun4u/io/pci/pci_pci.c usr/src/uts/sun4u/io/px/oberon_regs.h usr/src/uts/sun4u/io/px/px_hlib.c usr/src/uts/sun4u/io/px/px_lib4u.c usr/src/uts/sun4u/io/px/px_lib4u.h usr/src/uts/sun4u/px/Makefile usr/src/uts/sun4u/sys/pci/pci_obj.h usr/src/uts/sun4u/sys/pci/pci_tools_ext.h usr/src/uts/sun4u/sys/pci/pci_var.h usr/src/uts/sun4v/io/px/px_lib4v.c usr/src/uts/sun4v/niumx/Makefile usr/src/uts/sun4v/px/Makefile
diffstat 186 files changed, 30058 insertions(+), 14866 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/Makefile.lint	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/Makefile.lint	Mon Nov 02 15:58:28 2009 +0800
@@ -156,6 +156,8 @@
 	cmd/head \
 	cmd/hostid \
 	cmd/hostname \
+	cmd/hotplug \
+	cmd/hotplugd \
 	cmd/idmap \
 	cmd/init \
 	cmd/intrstat \
@@ -361,6 +363,7 @@
 	lib/libgen \
 	lib/libgrubmgmt \
 	lib/libgss \
+	lib/libhotplug \
 	lib/libidmap \
 	lib/libinetcfg \
 	lib/libinetsvc \
--- a/usr/src/cmd/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/cmd/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -192,6 +192,8 @@
 	head		\
 	hostid		\
 	hostname	\
+	hotplug		\
+	hotplugd	\
 	hwdata		\
 	id		\
 	idmap		\
@@ -593,6 +595,7 @@
 	halt		\
 	head		\
 	hostname	\
+	hotplug		\
 	id		\
 	idmap		\
 	isaexec		\
--- a/usr/src/cmd/cfgadm/cfgadm.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/cmd/cfgadm/cfgadm.c	Mon Nov 02 15:58:28 2009 +0800
@@ -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.
  */
 
@@ -405,86 +405,86 @@
 
 	switch (action) {
 	case CFGA_OP_CHANGE_STATE:
-	    /* Sanity check - requires an argument */
-	    if ((argc - optind) <= 0) {
-		usage();
+		/* Sanity check - requires an argument */
+		if ((argc - optind) <= 0) {
+			usage();
+			break;
+		}
+		/* Sanity check - args cannot be ap_types */
+		for (i = 0; i < (argc - optind); i++) {
+			if (find_arg_type(ap_args[i]) == AP_TYPE) {
+				usage();
+				exit(EXIT_ARGERROR);
+				/*NOTREACHED*/
+			}
+		}
+		ret = config_change_state(sc_opt, argc - optind, ap_args,
+		    plat_opts, &confirm, &message, &estrp, flags);
+		if (ret != CFGA_OK)
+			cfgadm_error(ret, estrp);
 		break;
-	    }
-	    /* Sanity check - args cannot be ap_types */
-	    for (i = 0; i < (argc - optind); i++) {
-		    if (find_arg_type(ap_args[i]) == AP_TYPE) {
+	case CFGA_OP_PRIVATE:
+		/* Sanity check - requires an argument */
+		if ((argc - optind) <= 0) {
 			usage();
-			exit(EXIT_ARGERROR);
-			/*NOTREACHED*/
-		    }
-	    }
-	    ret = config_change_state(sc_opt, argc - optind, ap_args, plat_opts,
-		&confirm, &message, &estrp, flags);
-	    if (ret != CFGA_OK)
-		    cfgadm_error(ret, estrp);
-	    break;
-	case CFGA_OP_PRIVATE:
-	    /* Sanity check - requires an argument */
-	    if ((argc - optind) <= 0) {
-		usage();
+			break;
+		}
+		/* Sanity check - args cannot be ap_types */
+		for (i = 0; i < (argc - optind); i++) {
+			if (find_arg_type(ap_args[i]) == AP_TYPE) {
+				usage();
+				exit(EXIT_ARGERROR);
+				/*NOTREACHED*/
+			}
+		}
+
+		ret = config_private_func(act_arg, argc - optind, ap_args,
+		    plat_opts, &confirm, &message, &estrp, flags);
+
+		if (ret != CFGA_OK)
+			cfgadm_error(ret, estrp);
 		break;
-	    }
-	    /* Sanity check - args cannot be ap_types */
-	    for (i = 0; i < (argc - optind); i++) {
-		    if (find_arg_type(ap_args[i]) == AP_TYPE) {
+	case CFGA_OP_TEST:
+		/* Sanity check - requires an argument */
+		if ((argc - optind) <= 0) {
+			usage();
+			break;
+		}
+
+		if ((flags & ~CFGA_FLAG_VERBOSE) != 0) {
 			usage();
 			exit(EXIT_ARGERROR);
 			/*NOTREACHED*/
-		    }
-	    }
-
-	    ret = config_private_func(act_arg, argc - optind, ap_args,
-		plat_opts, &confirm, &message, &estrp, flags);
+		}
 
-	    if (ret != CFGA_OK)
-		    cfgadm_error(ret, estrp);
-	    break;
-	case CFGA_OP_TEST:
-	    /* Sanity check - requires an argument */
-	    if ((argc - optind) <= 0) {
-		usage();
+		/* Sanity check - args cannot be ap_types */
+		for (i = 0; i < (argc - optind); i++) {
+			if (find_arg_type(ap_args[i]) == AP_TYPE) {
+				usage();
+				exit(EXIT_ARGERROR);
+				/*NOTREACHED*/
+			}
+		}
+		ret = config_test(argc - optind, ap_args, plat_opts, &message,
+		    &estrp, flags);
+		if (ret != CFGA_OK)
+			cfgadm_error(ret, estrp);
 		break;
-	    }
+	case CFGA_OP_HELP:
 
-	    if ((flags & ~CFGA_FLAG_VERBOSE) != 0) {
-		usage();
-		exit(EXIT_ARGERROR);
-		/*NOTREACHED*/
-	    }
-
-	    /* Sanity check - args cannot be ap_types */
-	    for (i = 0; i < (argc - optind); i++) {
-		    if (find_arg_type(ap_args[i]) == AP_TYPE) {
+		if ((flags & ~CFGA_FLAG_VERBOSE) != 0) {
 			usage();
 			exit(EXIT_ARGERROR);
 			/*NOTREACHED*/
-		    }
-	    }
-	    ret = config_test(argc - optind, ap_args, plat_opts, &message,
-		&estrp, flags);
-	    if (ret != CFGA_OK)
-		    cfgadm_error(ret, estrp);
-	    break;
-	case CFGA_OP_HELP:
+		}
 
-	    if ((flags & ~CFGA_FLAG_VERBOSE) != 0) {
+		/* always do usage? */
 		usage();
-		exit(EXIT_ARGERROR);
-		/*NOTREACHED*/
-	    }
-
-	    /* always do usage? */
-	    usage();
-	    ret = config_help(argc - optind, ap_args, &message, plat_opts,
-		flags);
-	    if (ret != CFGA_OK)
-		    cfgadm_error(ret, estrp);
-	    break;
+		ret = config_help(argc - optind, ap_args, &message, plat_opts,
+		    flags);
+		if (ret != CFGA_OK)
+			cfgadm_error(ret, estrp);
+		break;
 
 	case CFGA_OP_LIST: {
 		/*
@@ -604,6 +604,8 @@
 			S_FREE(list_array);
 			S_FREE(post_filtp);
 
+			if (estrp != NULL && *estrp != '\0')
+				cfgadm_error(CFGA_NOTSUPP, estrp);
 			if (exitcode != EXIT_OK) {
 				exit(exitcode);
 				/*NOTREACHED*/
@@ -634,8 +636,7 @@
  * usage - outputs the usage help message.
  */
 static void
-usage(
-	void)
+usage(void)
 {
 	int i;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/hotplug/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -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.
+#
+# cmd/hotplug/Makefile
+#
+
+PROG=	hotplug
+
+include	../Makefile.cmd
+
+OBJS=	hotplug.o
+SRCS=	$(OBJS:.o=.c)
+
+CPPFLAGS +=	-I$(SRC)/lib/libhotplug/common
+LDLIBS +=	-lhotplug
+
+XGETFLAGS += -s
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+	$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+	$(POST_PROCESS)
+
+install: all $(ROOTUSRSBINPROG)
+
+check:	$(PROG).c
+	$(CSTYLE) -pP $(SRCS:%=%)
+
+clean:
+
+lint: lint_SRCS
+
+include	../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/hotplug/hotplug.c	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,1286 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <libintl.h>
+#include <alloca.h>
+#include <getopt.h>
+#include <libhotplug.h>
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#include <sys/ddi_hp.h>
+
+#if !defined(TEXT_DOMAIN)		/* should be defined by cc -D */
+#define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it wasn't */
+#endif
+
+/*
+ * Function prototypes.
+ */
+static int	cmd_list(int, char **, const char *);
+static int	cmd_online(int, char **, const char *);
+static int	cmd_offline(int, char **, const char *);
+static int	cmd_enable(int, char **, const char *);
+static int	cmd_disable(int, char **, const char *);
+static int	cmd_poweron(int, char **, const char *);
+static int	cmd_poweroff(int, char **, const char *);
+static int	cmd_getpriv(int, char **, const char *);
+static int	cmd_setpriv(int, char **, const char *);
+static int	cmd_changestate(int, char **, const char *);
+static void	parse_common(int, char **, const char *);
+static void	parse_flags(int, char **, int *, const char *);
+static void	parse_target(int, char **, char **, char **, const char *);
+static void	parse_options(int, char **, char **, const char *);
+static void	bad_option(int, int, const char *);
+static void	usage(const char *);
+static int	list_cb(hp_node_t, void *);
+static int	list_long_cb(hp_node_t, void *);
+static int	error_cb(hp_node_t, void *);
+static void	print_options(const char *);
+static void	print_error(int);
+static int	state_atoi(char *);
+static char	*state_itoa(int);
+static short	valid_target(int);
+
+/*
+ * Define a conversion table for hotplug states.
+ */
+typedef struct {
+	int	state;
+	char	*state_str;
+	short	valid_target;
+} hpstate_t;
+
+static hpstate_t hpstates[] = {
+	{ DDI_HP_CN_STATE_EMPTY,	"EMPTY",	0 },
+	{ DDI_HP_CN_STATE_PRESENT,	"PRESENT",	1 },
+	{ DDI_HP_CN_STATE_POWERED,	"POWERED",	1 },
+	{ DDI_HP_CN_STATE_ENABLED,	"ENABLED",	1 },
+	{ DDI_HP_CN_STATE_PORT_EMPTY,	"PORT-EMPTY",	0 },
+	{ DDI_HP_CN_STATE_PORT_PRESENT,	"PORT-PRESENT",	1 },
+	{ DDI_HP_CN_STATE_OFFLINE,	"OFFLINE",	1 },
+	{ DDI_HP_CN_STATE_ATTACHED,	"ATTACHED",	0 },
+	{ DDI_HP_CN_STATE_MAINTENANCE,	"MAINTENANCE",	0 },
+	{ DDI_HP_CN_STATE_ONLINE,	"ONLINE",	1 },
+	{ 0, 0, 0 }
+};
+
+/*
+ * Define tables of supported subcommands.
+ */
+typedef struct {
+	char		*usage_str;
+	char		*cmd_str;
+	int		(*func)(int argc, char *argv[], const char *usage_str);
+} subcmd_t;
+
+static subcmd_t	subcmds[] = {
+	{ "list       [-l] [-v] [<path> [<connection>]]", "list", cmd_list },
+	{ "online     <path> <port>", "online", cmd_online },
+	{ "offline    [-f] [-q] <path> <port>", "offline", cmd_offline },
+	{ "enable     <path> <connector>", "enable", cmd_enable },
+	{ "disable    [-f] [-q] <path> <connector>", "disable", cmd_disable },
+	{ "poweron    <path> <connector>", "poweron", cmd_poweron },
+	{ "poweroff   [-f] [-q] <path> <connector>", "poweroff", cmd_poweroff },
+	{ "get        -o <options> <path> <connector>", "get", cmd_getpriv },
+	{ "set        -o <options> <path> <connector>", "set", cmd_setpriv }
+};
+
+static subcmd_t hidden_subcmds[] = {
+	{ "changestate  [-f] [-q] -s <state> <path> <connection>",
+	    "changestate", cmd_changestate }
+};
+
+/*
+ * Define tables of command line options.
+ */
+static const struct option common_opts[] = {
+	{ "help",	no_argument,		0, '?' },
+	{ "version",	no_argument,		0, 'V' },
+	{ 0, 0, 0, 0 }
+};
+
+static const struct option list_opts[] = {
+	{ "list-path",	no_argument,		0, 'l' },
+	{ "verbose",	no_argument,		0, 'v' },
+	{ 0, 0,	0, 0 }
+};
+
+static const struct option flag_opts[] = {
+	{ "force",	no_argument,		0, 'f' },
+	{ "query",	no_argument,		0, 'q' },
+	{ 0, 0,	0, 0 }
+};
+
+static const struct option private_opts[] = {
+	{ "options",	required_argument,	0, 'o' },
+	{ 0, 0,	0, 0 }
+};
+
+static const struct option changestate_opts[] = {
+	{ "force",	no_argument,		0, 'f' },
+	{ "query",	no_argument,		0, 'q' },
+	{ "state",	required_argument,	0, 's' },
+	{ 0, 0,	0, 0 }
+};
+
+/*
+ * Define exit codes.
+ */
+#define	EXIT_OK		0
+#define	EXIT_EINVAL	1	/* invalid arguments */
+#define	EXIT_ENOENT	2	/* path or connection doesn't exist */
+#define	EXIT_FAILED	3	/* operation failed */
+#define	EXIT_UNAVAIL	4	/* service not available */
+
+/*
+ * Global variables.
+ */
+static char 	*prog;
+static char	version[] = "1.0";
+extern int	errno;
+
+/*
+ * main()
+ *
+ *	The main routine determines which subcommand is used,
+ *	and dispatches control to the corresponding function.
+ */
+int
+main(int argc, char *argv[])
+{
+	int 		i, rv;
+
+	(void) setlocale(LC_ALL, "");
+	(void) textdomain(TEXT_DOMAIN);
+
+	if ((prog = strrchr(argv[0], '/')) == NULL)
+		prog = argv[0];
+	else
+		prog++;
+
+	if (argc < 2) {
+		usage(NULL);
+		return (EXIT_EINVAL);
+	}
+
+	parse_common(argc, argv, NULL);
+
+	/* Check the list of defined subcommands. */
+	for (i = 0; i < (sizeof (subcmds) / sizeof (subcmd_t)); i++) {
+		if (strcmp(argv[1], subcmds[i].cmd_str) == 0) {
+			rv = subcmds[i].func(argc - 1, &argv[1],
+			    subcmds[i].usage_str);
+			goto finished;
+		}
+	}
+
+	/* Check the list of hidden subcommands. */
+	for (i = 0; i < (sizeof (hidden_subcmds) / sizeof (subcmd_t)); i++) {
+		if (strcmp(argv[1], hidden_subcmds[i].cmd_str) == 0) {
+			rv = hidden_subcmds[i].func(argc - 1, &argv[1],
+			    hidden_subcmds[i].usage_str);
+			goto finished;
+		}
+	}
+
+	/* No matching subcommand found. */
+	(void) fprintf(stderr, gettext("ERROR: %s: unknown subcommand '%s'\n"),
+	    prog, argv[1]);
+	usage(NULL);
+	exit(EXIT_EINVAL);
+
+finished:
+	/* Determine exit code */
+	switch (rv) {
+	case 0:
+		break;
+	case EINVAL:
+		return (EXIT_EINVAL);
+	case ENXIO:
+	case ENOENT:
+		return (EXIT_ENOENT);
+	case EBADF:
+		return (EXIT_UNAVAIL);
+	default:
+		return (EXIT_FAILED);
+	}
+
+	return (EXIT_OK);
+}
+
+/*
+ * cmd_list()
+ *
+ *	Subcommand to list hotplug information.
+ */
+static int
+cmd_list(int argc, char *argv[], const char *usage_str)
+{
+	hp_node_t	root;
+	char		*path = NULL;
+	char		*connection = NULL;
+	boolean_t	long_flag = B_FALSE;
+	int		flags = 0;
+	int		opt;
+
+	/* Parse command line options */
+	parse_common(argc, argv, usage_str);
+	while ((opt = getopt_clip(argc, argv, "lv", list_opts, NULL)) != -1) {
+		switch (opt) {
+		case 'l':
+			long_flag = B_TRUE;
+			break;
+		case 'v':
+			flags |= HPINFOUSAGE;
+			break;
+		default:
+			bad_option(opt, optopt, usage_str);
+			break;
+		}
+	}
+	parse_target(argc, argv, &path, &connection, usage_str);
+
+	/* Default path is "/" */
+	if (path == NULL)
+		path = "/";
+
+	/* Get hotplug information snapshot */
+	if ((root = hp_init(path, connection, flags)) == NULL) {
+		print_error(errno);
+		return (errno);
+	}
+
+	/* Display hotplug information */
+	(void) hp_traverse(root, NULL, long_flag ? list_long_cb : list_cb);
+
+	/* Discard hotplug information snapshot */
+	hp_fini(root);
+
+	return (0);
+}
+
+/*
+ * cmd_online()
+ *
+ *	Subcommand to online a hotplug port.
+ */
+static int
+cmd_online(int argc, char *argv[], const char *usage_str)
+{
+	hp_node_t	root;
+	hp_node_t	results = NULL;
+	char		*path = NULL;
+	char		*connection = NULL;
+	int		rv;
+
+	/* Parse command line options */
+	parse_common(argc, argv, usage_str);
+	parse_target(argc, argv, &path, &connection, usage_str);
+
+	/* Path and connection are required */
+	if ((path == NULL) || (connection == NULL)) {
+		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
+		usage(usage_str);
+		return (EINVAL);
+	}
+
+	/* Get hotplug information snapshot */
+	if ((root = hp_init(path, connection, 0)) == NULL) {
+		print_error(errno);
+		return (errno);
+	}
+
+	/* Verify target is a port */
+	if (hp_type(root) != HP_NODE_PORT) {
+		(void) fprintf(stderr,
+		    gettext("ERROR: invalid target (must be a port).\n"));
+		hp_fini(root);
+		return (EINVAL);
+	}
+
+	/* Do state change */
+	rv = hp_set_state(root, 0, DDI_HP_CN_STATE_ONLINE, &results);
+
+	/* Display results */
+	if (rv == EIO) {
+		(void) fprintf(stderr, gettext("ERROR: failed to attach device "
+		    "drivers or other internal errors.\n"));
+	} else if (rv != 0) {
+		print_error(rv);
+	}
+	if (results != NULL) {
+		(void) hp_traverse(results, NULL, error_cb);
+		hp_fini(results);
+	}
+
+	/* Discard hotplug information snapshot */
+	hp_fini(root);
+
+	return (rv);
+}
+
+/*
+ * cmd_offline()
+ *
+ *	Subcommand to offline a hotplug port.
+ */
+static int
+cmd_offline(int argc, char *argv[], const char *usage_str)
+{
+	hp_node_t	root;
+	hp_node_t	results = NULL;
+	char		*path = NULL;
+	char		*connection = NULL;
+	int		flags = 0;
+	int		rv;
+
+	/* Parse command line options */
+	parse_common(argc, argv, usage_str);
+	parse_flags(argc, argv, &flags, usage_str);
+	parse_target(argc, argv, &path, &connection, usage_str);
+
+	/* Path and connection are required */
+	if ((path == NULL) || (connection == NULL)) {
+		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
+		usage(usage_str);
+		return (EINVAL);
+	}
+
+	/* Get hotplug information snapshot */
+	if ((root = hp_init(path, connection, 0)) == NULL) {
+		print_error(errno);
+		return (errno);
+	}
+
+	/* Verify target is a port */
+	if (hp_type(root) != HP_NODE_PORT) {
+		(void) fprintf(stderr,
+		    gettext("ERROR: invalid target (must be a port).\n"));
+		hp_fini(root);
+		return (EINVAL);
+	}
+
+	/* Do state change */
+	rv = hp_set_state(root, flags, DDI_HP_CN_STATE_OFFLINE, &results);
+
+	/* Display results */
+	print_error(rv);
+	if (results != NULL) {
+		(void) hp_traverse(results, NULL, error_cb);
+		hp_fini(results);
+	}
+
+	/* Discard hotplug information snapshot */
+	hp_fini(root);
+
+	return (rv);
+}
+
+/*
+ * cmd_enable()
+ *
+ *	Subcommand to enable a hotplug connector.
+ */
+static int
+cmd_enable(int argc, char *argv[], const char *usage_str)
+{
+	hp_node_t	root;
+	hp_node_t	results = NULL;
+	char		*path = NULL;
+	char		*connection = NULL;
+	int		rv;
+
+	/* Parse command line options */
+	parse_common(argc, argv, usage_str);
+	parse_target(argc, argv, &path, &connection, usage_str);
+
+	/* Path and connection are required */
+	if ((path == NULL) || (connection == NULL)) {
+		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
+		usage(usage_str);
+		return (EINVAL);
+	}
+
+	/* Get hotplug information snapshot */
+	if ((root = hp_init(path, connection, 0)) == NULL) {
+		print_error(errno);
+		return (errno);
+	}
+
+	/* Verify target is a connector */
+	if (hp_type(root) != HP_NODE_CONNECTOR) {
+		(void) fprintf(stderr,
+		    gettext("ERROR: invalid target (must be a connector).\n"));
+		hp_fini(root);
+		return (EINVAL);
+	}
+
+	/* Do state change */
+	rv = hp_set_state(root, 0, DDI_HP_CN_STATE_ENABLED, &results);
+
+	/* Display results */
+	print_error(rv);
+	if (results != NULL) {
+		(void) hp_traverse(results, NULL, error_cb);
+		hp_fini(results);
+	}
+
+	/* Discard hotplug information snapshot */
+	hp_fini(root);
+
+	return (rv);
+}
+
+/*
+ * cmd_disable()
+ *
+ *	Subcommand to disable a hotplug connector.
+ */
+static int
+cmd_disable(int argc, char *argv[], const char *usage_str)
+{
+	hp_node_t	root;
+	hp_node_t	results = NULL;
+	char		*path = NULL;
+	char		*connection = NULL;
+	int		flags = 0;
+	int		rv;
+
+	/* Parse command line options */
+	parse_common(argc, argv, usage_str);
+	parse_flags(argc, argv, &flags, usage_str);
+	parse_target(argc, argv, &path, &connection, usage_str);
+
+	/* Path and connection are required */
+	if ((path == NULL) || (connection == NULL)) {
+		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
+		usage(usage_str);
+		return (EINVAL);
+	}
+
+	/* Get hotplug information snapshot */
+	if ((root = hp_init(path, connection, 0)) == NULL) {
+		print_error(errno);
+		return (errno);
+	}
+
+	/* Verify target is a connector */
+	if (hp_type(root) != HP_NODE_CONNECTOR) {
+		(void) fprintf(stderr,
+		    gettext("ERROR: invalid target (must be a connector).\n"));
+		hp_fini(root);
+		return (EINVAL);
+	}
+
+	/*
+	 * Do nothing unless the connector is in the ENABLED state.
+	 * Otherwise this subcommand becomes an alias for 'poweron.'
+	 */
+	if (hp_state(root) != DDI_HP_CN_STATE_ENABLED) {
+		hp_fini(root);
+		return (0);
+	}
+
+	/* Do state change */
+	rv = hp_set_state(root, flags, DDI_HP_CN_STATE_POWERED, &results);
+
+	/* Display results */
+	print_error(rv);
+	if (results != NULL) {
+		(void) hp_traverse(results, NULL, error_cb);
+		hp_fini(results);
+	}
+
+	/* Discard hotplug information snapshot */
+	hp_fini(root);
+
+	return (rv);
+}
+
+/*
+ * cmd_poweron()
+ *
+ *	Subcommand to power on a hotplug connector.
+ */
+static int
+cmd_poweron(int argc, char *argv[], const char *usage_str)
+{
+	hp_node_t	root;
+	hp_node_t	results = NULL;
+	char		*path = NULL;
+	char		*connection = NULL;
+	int		rv;
+
+	/* Parse command line options */
+	parse_common(argc, argv, usage_str);
+	parse_target(argc, argv, &path, &connection, usage_str);
+
+	/* Path and connection are required */
+	if ((path == NULL) || (connection == NULL)) {
+		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
+		usage(usage_str);
+		return (EINVAL);
+	}
+
+	/* Get hotplug information snapshot */
+	if ((root = hp_init(path, connection, 0)) == NULL) {
+		print_error(errno);
+		return (errno);
+	}
+
+	/* Verify target is a connector */
+	if (hp_type(root) != HP_NODE_CONNECTOR) {
+		(void) fprintf(stderr,
+		    gettext("ERROR: invalid target (must be a connector).\n"));
+		hp_fini(root);
+		return (EINVAL);
+	}
+
+	/*
+	 * Do nothing if the connector is already powered.
+	 * Otherwise this subcommand becomes an alias for 'disable.'
+	 */
+	if (hp_state(root) >= DDI_HP_CN_STATE_POWERED) {
+		hp_fini(root);
+		return (0);
+	}
+
+	/* Do state change */
+	rv = hp_set_state(root, 0, DDI_HP_CN_STATE_POWERED, &results);
+
+	/* Display results */
+	print_error(rv);
+	if (results != NULL) {
+		(void) hp_traverse(results, NULL, error_cb);
+		hp_fini(results);
+	}
+
+	/* Discard hotplug information snapshot */
+	hp_fini(root);
+
+	return (rv);
+}
+
+/*
+ * cmd_poweroff()
+ *
+ *	Subcommand to power off a hotplug connector.
+ */
+static int
+cmd_poweroff(int argc, char *argv[], const char *usage_str)
+{
+	hp_node_t	root;
+	hp_node_t	results = NULL;
+	char		*path = NULL;
+	char		*connection = NULL;
+	int		flags = 0;
+	int		rv;
+
+	/* Parse command line options */
+	parse_common(argc, argv, usage_str);
+	parse_flags(argc, argv, &flags, usage_str);
+	parse_target(argc, argv, &path, &connection, usage_str);
+
+	/* Path and connection are required */
+	if ((path == NULL) || (connection == NULL)) {
+		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
+		usage(usage_str);
+		return (EINVAL);
+	}
+
+	/* Get hotplug information snapshot */
+	if ((root = hp_init(path, connection, 0)) == NULL) {
+		print_error(errno);
+		return (errno);
+	}
+
+	/* Verify target is a connector */
+	if (hp_type(root) != HP_NODE_CONNECTOR) {
+		(void) fprintf(stderr,
+		    gettext("ERROR: invalid target (must be a connector).\n"));
+		hp_fini(root);
+		return (EINVAL);
+	}
+
+	/* Do state change */
+	rv = hp_set_state(root, flags, DDI_HP_CN_STATE_PRESENT, &results);
+
+	/* Display results */
+	print_error(rv);
+	if (results != NULL) {
+		(void) hp_traverse(results, NULL, error_cb);
+		hp_fini(results);
+	}
+
+	/* Discard hotplug information snapshot */
+	hp_fini(root);
+
+	return (rv);
+}
+
+/*
+ * cmd_getpriv()
+ *
+ *	Subcommand to get and display bus private options.
+ */
+static int
+cmd_getpriv(int argc, char *argv[], const char *usage_str)
+{
+	hp_node_t	root;
+	char		*path = NULL;
+	char		*connection = NULL;
+	char		*options = NULL;
+	char		*results = NULL;
+	int		rv;
+
+	/* Parse command line options */
+	parse_common(argc, argv, usage_str);
+	parse_options(argc, argv, &options, usage_str);
+	parse_target(argc, argv, &path, &connection, usage_str);
+
+	/* Options, path, and connection are all required */
+	if ((options == NULL) || (path == NULL) || (connection == NULL)) {
+		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
+		usage(usage_str);
+		return (EINVAL);
+	}
+
+	/* Get hotplug information snapshot */
+	if ((root = hp_init(path, connection, 0)) == NULL) {
+		print_error(errno);
+		return (errno);
+	}
+
+	/* Verify target is a connector */
+	if (hp_type(root) != HP_NODE_CONNECTOR) {
+		(void) fprintf(stderr,
+		    gettext("ERROR: invalid target (must be a connector).\n"));
+		hp_fini(root);
+		return (EINVAL);
+	}
+
+	/* Do the operation */
+	rv = hp_get_private(root, options, &results);
+
+	/* Display results */
+	if (rv == ENOTSUP) {
+		(void) fprintf(stderr,
+		    gettext("ERROR: unsupported property name or value.\n"));
+		(void) fprintf(stderr,
+		    gettext("(Properties may depend upon connector state.)\n"));
+	} else if (rv != 0) {
+		print_error(rv);
+	}
+	if (results != NULL) {
+		print_options(results);
+		free(results);
+	}
+
+	/* Discard hotplug information snapshot */
+	hp_fini(root);
+
+	return (rv);
+}
+
+/*
+ * cmd_setpriv()
+ *
+ *	Subcommand to set bus private options.
+ */
+static int
+cmd_setpriv(int argc, char *argv[], const char *usage_str)
+{
+	hp_node_t	root;
+	char		*path = NULL;
+	char		*connection = NULL;
+	char		*options = NULL;
+	char		*results = NULL;
+	int		rv;
+
+	/* Parse command line options */
+	parse_common(argc, argv, usage_str);
+	parse_options(argc, argv, &options, usage_str);
+	parse_target(argc, argv, &path, &connection, usage_str);
+
+	/* Options, path, and connection are all required */
+	if ((options == NULL) || (path == NULL) || (connection == NULL)) {
+		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
+		usage(usage_str);
+		return (EINVAL);
+	}
+
+	/* Get hotplug information snapshot */
+	if ((root = hp_init(path, connection, 0)) == NULL) {
+		print_error(errno);
+		return (errno);
+	}
+
+	/* Verify target is a connector */
+	if (hp_type(root) != HP_NODE_CONNECTOR) {
+		(void) fprintf(stderr,
+		    gettext("ERROR: invalid target (must be a connector).\n"));
+		hp_fini(root);
+		return (EINVAL);
+	}
+
+	/* Do the operation */
+	rv = hp_set_private(root, options, &results);
+
+	/* Display results */
+	if (rv == ENOTSUP) {
+		(void) fprintf(stderr,
+		    gettext("ERROR: unsupported property name or value.\n"));
+		(void) fprintf(stderr,
+		    gettext("(Properties may depend upon connector state.)\n"));
+	} else if (rv != 0) {
+		print_error(rv);
+	}
+	if (results != NULL) {
+		print_options(results);
+		free(results);
+	}
+
+	/* Discard hotplug information snapshot */
+	hp_fini(root);
+
+	return (rv);
+}
+
+/*
+ * cmd_changestate()
+ *
+ *	Subcommand to initiate a state change operation.  This is
+ *	a hidden subcommand to directly set a connector or port to
+ *	a specific target state.
+ */
+static int
+cmd_changestate(int argc, char *argv[], const char *usage_str)
+{
+	hp_node_t	root;
+	hp_node_t	results = NULL;
+	char		*path = NULL;
+	char		*connection = NULL;
+	int		state = -1;
+	int		flags = 0;
+	int		opt, rv;
+
+	/* Parse command line options */
+	parse_common(argc, argv, usage_str);
+	while ((opt = getopt_clip(argc, argv, "fqs:", changestate_opts,
+	    NULL)) != -1) {
+		switch (opt) {
+		case 'f':
+			flags |= HPFORCE;
+			break;
+		case 'q':
+			flags |= HPQUERY;
+			break;
+		case 's':
+			if ((state = state_atoi(optarg)) == -1) {
+				(void) printf("ERROR: invalid target state\n");
+				return (EINVAL);
+			}
+			break;
+		default:
+			bad_option(opt, optopt, usage_str);
+			break;
+		}
+	}
+	parse_target(argc, argv, &path, &connection, usage_str);
+
+	/* State, path, and connection are all required */
+	if ((state == -1) || (path == NULL) || (connection == NULL)) {
+		(void) fprintf(stderr, gettext("ERROR: too few arguments.\n"));
+		usage(usage_str);
+		return (EINVAL);
+	}
+
+	/* Check that target state is valid */
+	if (valid_target(state) == 0) {
+		(void) fprintf(stderr,
+		    gettext("ERROR: invalid target state\n"));
+		return (EINVAL);
+	}
+
+	/* Get hotplug information snapshot */
+	if ((root = hp_init(path, connection, 0)) == NULL) {
+		print_error(errno);
+		return (errno);
+	}
+
+	/* Initiate state change operation on root of snapshot */
+	rv = hp_set_state(root, flags, state, &results);
+
+	/* Display results */
+	print_error(rv);
+	if (results) {
+		(void) hp_traverse(results, NULL, error_cb);
+		hp_fini(results);
+	}
+
+	/* Discard hotplug information snapshot */
+	hp_fini(root);
+
+	return (rv);
+}
+
+/*
+ * parse_common()
+ *
+ *	Parse command line options that are common to the
+ *	entire program, and to each of its subcommands.
+ */
+static void
+parse_common(int argc, char *argv[], const char *usage_str)
+{
+	int		opt;
+	extern int	opterr;
+	extern int	optind;
+
+	/* Turn off error reporting */
+	opterr = 0;
+
+	while ((opt = getopt_clip(argc, argv, "?V", common_opts, NULL)) != -1) {
+		switch (opt) {
+		case '?':
+			if (optopt == '?') {
+				usage(usage_str);
+				exit(0);
+			}
+			break;
+		case 'V':
+			(void) printf(gettext("%s: Version %s\n"),
+			    prog, version);
+			exit(0);
+		default:
+			break;
+		}
+	}
+
+	/* Reset option index */
+	optind = 1;
+}
+
+/*
+ * parse_flags()
+ *
+ *	Parse command line flags common to all downward state
+ *	change operations (offline, disable, poweoff).
+ */
+static void
+parse_flags(int argc, char *argv[], int *flagsp, const char *usage_str)
+{
+	int	opt;
+	int	flags = 0;
+
+	while ((opt = getopt_clip(argc, argv, "fq", flag_opts, NULL)) != -1) {
+		switch (opt) {
+		case 'f':
+			flags |= HPFORCE;
+			break;
+		case 'q':
+			flags |= HPQUERY;
+			break;
+		default:
+			bad_option(opt, optopt, usage_str);
+			break;
+		}
+	}
+
+	*flagsp = flags;
+}
+
+/*
+ * parse_options()
+ *
+ *	Parse command line options common to the bus private set and
+ *	get subcommands.
+ */
+static void
+parse_options(int argc, char *argv[], char **optionsp, const char *usage_str)
+{
+	int	opt;
+
+	while ((opt = getopt_clip(argc, argv, "o:", private_opts,
+	    NULL)) != -1) {
+		switch (opt) {
+		case 'o':
+			*optionsp = optarg;
+			break;
+		default:
+			bad_option(opt, optopt, usage_str);
+			break;
+		}
+	}
+}
+
+/*
+ * parse_target()
+ *
+ *	Parse the target path and connection name from the command line.
+ */
+static void
+parse_target(int argc, char *argv[], char **pathp, char **connectionp,
+    const char *usage_str)
+{
+	extern int	optind;
+
+	if (optind < argc)
+		*pathp = argv[optind++];
+
+	if (optind < argc)
+		*connectionp = argv[optind++];
+
+	if (optind < argc) {
+		(void) fprintf(stderr, gettext("ERROR: too many arguments.\n"));
+		usage(usage_str);
+		exit(EINVAL);
+	}
+}
+
+/*
+ * bad_option()
+ *
+ *	Routine to handle bad command line options.
+ */
+static void
+bad_option(int opt, int optopt, const char *usage_str)
+{
+	switch (opt) {
+	case ':':
+		(void) fprintf(stderr,
+		    gettext("ERROR: option '%c' requires an argument.\n"),
+		    optopt);
+		break;
+	default:
+		if (optopt == '?') {
+			usage(usage_str);
+			exit(EXIT_OK);
+		}
+		(void) fprintf(stderr,
+		    gettext("ERROR: unrecognized option '%c'.\n"), optopt);
+		break;
+	}
+
+	usage(usage_str);
+
+	exit(EXIT_EINVAL);
+}
+
+/*
+ * usage()
+ *
+ *	Display general usage of the command.  Including
+ *	the usage synopsis of each defined subcommand.
+ */
+static void
+usage(const char *usage_str)
+{
+	int	i;
+
+	if (usage_str != NULL) {
+		(void) fprintf(stderr, gettext("Usage:   %s  %s\n\n"),
+		    prog, usage_str);
+		return;
+	}
+
+	(void) fprintf(stderr, gettext("Usage:  %s  <subcommand> [<args>]\n\n"),
+	    prog);
+
+	(void) fprintf(stderr, gettext("Subcommands:\n\n"));
+
+	for (i = 0; i < (sizeof (subcmds) / sizeof (subcmd_t)); i++)
+		(void) fprintf(stderr, "   %s\n\n", subcmds[i].usage_str);
+}
+
+/*
+ * list_cb()
+ *
+ *	Callback function for hp_traverse(), to display nodes
+ *	of a hotplug information snapshot.  (Short version.)
+ */
+/*ARGSUSED*/
+static int
+list_cb(hp_node_t node, void *arg)
+{
+	hp_node_t	parent;
+
+	/* Indent */
+	for (parent = hp_parent(node); parent; parent = hp_parent(parent))
+		if (hp_type(parent) == HP_NODE_DEVICE)
+			(void) printf("     ");
+
+	switch (hp_type(node)) {
+	case HP_NODE_DEVICE:
+		(void) printf("%s\n", hp_name(node));
+		break;
+
+	case HP_NODE_CONNECTOR:
+		(void) printf("[%s]", hp_name(node));
+		(void) printf("  (%s)", state_itoa(hp_state(node)));
+		(void) printf("\n");
+		break;
+
+	case HP_NODE_PORT:
+		(void) printf("<%s>", hp_name(node));
+		(void) printf("  (%s)", state_itoa(hp_state(node)));
+		(void) printf("\n");
+		break;
+
+	case HP_NODE_USAGE:
+		(void) printf("{ %s }\n", hp_usage(node));
+		break;
+	}
+
+	return (HP_WALK_CONTINUE);
+}
+
+/*
+ * list_long_cb()
+ *
+ *	Callback function for hp_traverse(), to display nodes
+ *	of a hotplug information snapshot.  (Long version.)
+ */
+/*ARGSUSED*/
+static int
+list_long_cb(hp_node_t node, void *arg)
+{
+	char	path[MAXPATHLEN];
+	char	connection[MAXPATHLEN];
+
+	if (hp_type(node) != HP_NODE_USAGE) {
+		if (hp_path(node, path, connection) != 0)
+			return (HP_WALK_CONTINUE);
+		(void) printf("%s", path);
+	}
+
+	switch (hp_type(node)) {
+	case HP_NODE_CONNECTOR:
+		(void) printf(" [%s]", connection);
+		(void) printf(" (%s)", state_itoa(hp_state(node)));
+		break;
+
+	case HP_NODE_PORT:
+		(void) printf(" <%s>", connection);
+		(void) printf(" (%s)", state_itoa(hp_state(node)));
+		break;
+
+	case HP_NODE_USAGE:
+		(void) printf("    { %s }", hp_usage(node));
+		break;
+	}
+
+	(void) printf("\n");
+
+	return (HP_WALK_CONTINUE);
+}
+
+/*
+ * error_cb()
+ *
+ *	Callback function for hp_traverse(), to display
+ *	error results from a state change operation.
+ */
+/*ARGSUSED*/
+static int
+error_cb(hp_node_t node, void *arg)
+{
+	hp_node_t	child;
+	char		*usage_str;
+	static char	path[MAXPATHLEN];
+	static char	connection[MAXPATHLEN];
+
+	if (((child = hp_child(node)) != NULL) &&
+	    (hp_type(child) == HP_NODE_USAGE)) {
+		if (hp_path(node, path, connection) == 0)
+			(void) printf("%s:\n", path);
+		return (HP_WALK_CONTINUE);
+	}
+
+	if ((hp_type(node) == HP_NODE_USAGE) &&
+	    ((usage_str = hp_usage(node)) != NULL))
+		(void) printf("   { %s }\n", usage_str);
+
+	return (HP_WALK_CONTINUE);
+}
+
+/*
+ * print_options()
+ *
+ *	Parse and display bus private options.  The options are
+ *	formatted as a string which conforms to the getsubopt(3C)
+ *	format.  This routine only splits the string elements as
+ *	separated by commas, and displays each portion on its own
+ *	separate line of output.
+ */
+static void
+print_options(const char *options)
+{
+	char	*buf, *curr, *next;
+	size_t	len;
+
+	/* Do nothing if options string is empty */
+	if ((len = strlen(options)) == 0)
+		return;
+
+	/* To avoid modifying the input string, make a copy on the stack */
+	if ((buf = (char *)alloca(len + 1)) == NULL) {
+		(void) printf("%s\n", options);
+		return;
+	}
+	(void) strlcpy(buf, options, len + 1);
+
+	/* Iterate through each comma-separated name/value pair */
+	curr = buf;
+	do {
+		if ((next = strchr(curr, ',')) != NULL) {
+			*next = '\0';
+			next++;
+		}
+		(void) printf("%s\n", curr);
+	} while ((curr = next) != NULL);
+}
+
+/*
+ * print_error()
+ *
+ *	Common routine to print error numbers in an appropriate way.
+ *	Prints nothing if error code is 0.
+ */
+static void
+print_error(int error)
+{
+	switch (error) {
+	case 0:
+		/* No error */
+		return;
+	case EACCES:
+		(void) fprintf(stderr,
+		    gettext("ERROR: operation not authorized.\n"));
+		break;
+	case EBADF:
+		(void) fprintf(stderr,
+		    gettext("ERROR: hotplug service is not available.\n"));
+		break;
+	case EBUSY:
+		(void) fprintf(stderr,
+		    gettext("ERROR: devices or resources are busy.\n"));
+		break;
+	case EEXIST:
+		(void) fprintf(stderr,
+		    gettext("ERROR: resource already exists.\n"));
+		break;
+	case EFAULT:
+		(void) fprintf(stderr,
+		    gettext("ERROR: internal failure in hotplug service.\n"));
+		break;
+	case EINVAL:
+		(void) fprintf(stderr,
+		    gettext("ERROR: invalid arguments.\n"));
+		break;
+	case ENOENT:
+		(void) fprintf(stderr,
+		    gettext("ERROR: there are no connections to display.\n"));
+		(void) fprintf(stderr,
+		    gettext("(See hotplug(1m) for more information.)\n"));
+		break;
+	case ENXIO:
+		(void) fprintf(stderr,
+		    gettext("ERROR: no such path or connection.\n"));
+		break;
+	case ENOMEM:
+		(void) fprintf(stderr,
+		    gettext("ERROR: not enough memory.\n"));
+		break;
+	case ENOTSUP:
+		(void) fprintf(stderr,
+		    gettext("ERROR: operation not supported.\n"));
+		break;
+	case EIO:
+		(void) fprintf(stderr,
+		    gettext("ERROR: hardware or driver specific failure.\n"));
+		break;
+	default:
+		(void) fprintf(stderr, gettext("ERROR: operation failed: %s\n"),
+		    strerror(error));
+		break;
+	}
+}
+
+/*
+ * state_atoi()
+ *
+ *	Convert a hotplug state from a string to an integer.
+ */
+static int
+state_atoi(char *state)
+{
+	int	i;
+
+	for (i = 0; hpstates[i].state_str != NULL; i++)
+		if (strcasecmp(state, hpstates[i].state_str) == 0)
+			return (hpstates[i].state);
+
+	return (-1);
+}
+
+/*
+ * state_itoa()
+ *
+ *	Convert a hotplug state from an integer to a string.
+ */
+static char *
+state_itoa(int state)
+{
+	static char	unknown[] = "UNKNOWN";
+	int		i;
+
+	for (i = 0; hpstates[i].state_str != NULL; i++)
+		if (state == hpstates[i].state)
+			return (hpstates[i].state_str);
+
+	return (unknown);
+}
+
+/*
+ * valid_target()
+ *
+ *	Check if a state is a valid target for a changestate command.
+ */
+static short
+valid_target(int state)
+{
+	int	i;
+
+	for (i = 0; hpstates[i].state_str != NULL; i++)
+		if (state == hpstates[i].state)
+			return (hpstates[i].valid_target);
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/hotplugd/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,68 @@
+#
+# 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.
+#
+#
+# cmd/hotplugd/Makefile
+#
+
+PROG= 		hotplugd
+OBJS=		hotplugd.o \
+		hotplugd_impl.o \
+		hotplugd_door.o \
+		hotplugd_info.o \
+		hotplugd_rcm.o
+SRCS=		$(OBJS:.o=.c)
+SVCMETHOD=	svc-hotplug
+MANIFEST=	hotplug.xml
+
+include ../Makefile.cmd
+
+ROOTCMDDIR=		$(ROOTLIB)
+ROOTMANIFESTDIR=	$(ROOTSVCSYSTEM)
+$(ROOTMANIFEST)		:= FILEMODE= 444
+
+CPPFLAGS += -I$(SRC)/lib/libhotplug/common
+LDLIBS += -ldevinfo -lhotplug -lnvpair -lsecdb -lrcm -lbsm
+
+.KEEP_STATE:
+
+all:	$(PROG)
+
+$(PROG): $(OBJS)
+	$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+	$(POST_PROCESS)
+
+.PARALLEL: $(OBJS)
+
+install: all $(ROOTCMD) $(ROOTMANIFEST) $(ROOTSVCMETHOD)
+
+clean:
+	$(RM) $(PROG) $(OBJS) $(LLOBJS)
+
+check: $(CHKMANIFEST)
+	$(CSTYLE) -pP $(SRCS:%=%)
+
+lint:	lint_SRCS
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/hotplugd/hotplug.xml	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,96 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ 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.
+
+	NOTE:  This service manifest is not editable; its contents will
+	be overwritten by package or patch operations, including
+	operating system upgrade.  Make customizations in a different
+	file.
+-->
+
+<service_bundle type='manifest' name='SUNWcsr:hotplug'>
+
+<service
+	name='system/hotplug'
+	type='service'
+	version='1'>
+
+	<create_default_instance enabled='false' />
+
+	<single_instance/>
+
+	<dependency name='device'
+		type='service'
+		grouping='require_all'
+		restart_on='none'>
+		<service_fmri value='svc:/system/device/local' />
+	</dependency>
+
+	<dependency name='usr'
+		type='service'
+		grouping='require_all'
+		restart_on='none'>
+		<service_fmri value='svc:/system/filesystem/local' />
+	</dependency>
+
+	<exec_method
+		type='method'
+		name='start'
+		exec='/lib/svc/method/svc-hotplug'
+		timeout_seconds='30'>
+		<method_context>
+			<method_credential user='root' group='root' />
+		</method_context>
+	</exec_method>
+
+	<exec_method
+		type='method'
+		name='stop'
+		exec=':kill'
+		timeout_seconds='30'>
+	</exec_method>
+
+	<property_group name='general' type='framework'>
+		<propval name='action_authorization' type='astring'
+			value='solaris.smf.manage.hotplug' />
+		<propval name='value_authorization' type='astring'
+			value='solaris.smf.manage.hotplug' />
+	</property_group>
+
+	<stability value='Unstable' />
+
+	<template>
+		<common_name>
+			<loctext xml:lang='C'>
+			hotplug daemon
+			</loctext>
+		</common_name>
+		<documentation>
+			<manpage title='hotplugd' section='1M'
+				manpath='/usr/share/man' />
+		</documentation>
+	</template>
+</service>
+
+</service_bundle>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/hotplugd/hotplugd.c	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,405 @@
+/*
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <strings.h>
+#include <syslog.h>
+#include <priv.h>
+#include <wait.h>
+#include <getopt.h>
+#include <synch.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <libhotplug.h>
+#include <libhotplug_impl.h>
+#include "hotplugd_impl.h"
+
+/*
+ * Define long options for command line.
+ */
+static const struct option lopts[] = {
+	{ "help",	no_argument,	0, '?' },
+	{ "version",	no_argument,	0, 'V' },
+	{ "debug",	no_argument,	0, 'd' },
+	{ 0, 0, 0, 0 }
+};
+
+/*
+ * Local functions.
+ */
+static void		usage(void);
+static boolean_t	check_privileges(void);
+static int		daemonize(void);
+static void		init_signals(void);
+static void		signal_handler(int signum);
+static void		shutdown_daemon(void);
+
+/*
+ * Global variables.
+ */
+static char		*prog;
+static char		version[] = "1.0";
+static boolean_t	log_flag = B_FALSE;
+static boolean_t	debug_flag = B_FALSE;
+static boolean_t	exit_flag = B_FALSE;
+static sema_t		signal_sem;
+
+/*
+ * main()
+ *
+ *	The hotplug daemon is designed to be a background daemon
+ *	controlled by SMF.  So by default it will daemonize and
+ *	do some coordination with its parent process in order to
+ *	indicate proper success or failure back to SMF.  And all
+ *	output will be sent to syslog.
+ *
+ *	But if given the '-d' command line option, it will instead
+ *	run in the foreground in a standalone, debug mode.  Errors
+ *	and additional debug messages will be printed to the controlling
+ *	terminal instead of to syslog.
+ */
+int
+main(int argc, char *argv[])
+{
+	int	opt;
+	int	pfd;
+	int	status;
+
+	if ((prog = strrchr(argv[0], '/')) == NULL)
+		prog = argv[0];
+	else
+		prog++;
+
+	/* Check privileges */
+	if (!check_privileges()) {
+		(void) fprintf(stderr, "Insufficient privileges.  "
+		    "(All privileges are required.)\n");
+		return (-1);
+	}
+
+	/* Process options  */
+	while ((opt = getopt_clip(argc, argv, "dV?", lopts, NULL)) != -1) {
+		switch (opt) {
+		case 'd':
+			debug_flag = B_TRUE;
+			break;
+		case 'V':
+			(void) printf("%s: Version %s\n", prog, version);
+			return (0);
+		default:
+			if (optopt == '?') {
+				usage();
+				return (0);
+			}
+			(void) fprintf(stderr, "Unrecognized option '%c'.\n",
+			    optopt);
+			usage();
+			return (-1);
+		}
+	}
+
+	/* Initialize semaphore for daemon shutdown */
+	if (sema_init(&signal_sem, 1, USYNC_THREAD, NULL) != 0)
+		exit(EXIT_FAILURE);
+
+	/* Initialize signal handling */
+	init_signals();
+
+	/* Daemonize, if not in DEBUG mode */
+	if (!debug_flag)
+		pfd = daemonize();
+
+	/* Initialize door service */
+	if (!door_server_init()) {
+		if (!debug_flag) {
+			status = EXIT_FAILURE;
+			(void) write(pfd, &status, sizeof (status));
+			(void) close(pfd);
+		}
+		exit(EXIT_FAILURE);
+	}
+
+	/* Daemon initialized */
+	if (!debug_flag) {
+		status = 0;
+		(void) write(pfd, &status, sizeof (status));
+		(void) close(pfd);
+	}
+
+	/* Note that daemon is running */
+	log_info("hotplug daemon started.\n");
+
+	/* Wait for shutdown signal */
+	while (!exit_flag)
+		(void) sema_wait(&signal_sem);
+
+	shutdown_daemon();
+	return (0);
+}
+
+/*
+ * usage()
+ *
+ *	Print a brief usage synopsis for the command line options.
+ */
+static void
+usage(void)
+{
+	(void) printf("Usage: %s [-d]\n", prog);
+}
+
+/*
+ * check_privileges()
+ *
+ *	Check if the current process has enough privileges
+ *	to run the daemon.  Note that all privileges are
+ *	required in order for RCM interactions to work.
+ */
+static boolean_t
+check_privileges(void)
+{
+	priv_set_t	*privset;
+	boolean_t	rv = B_FALSE;
+
+	if ((privset = priv_allocset()) != NULL) {
+		if (getppriv(PRIV_EFFECTIVE, privset) == 0) {
+			rv = priv_isfullset(privset);
+		}
+		priv_freeset(privset);
+	}
+
+	return (rv);
+}
+
+/*
+ * daemonize()
+ *
+ *	Fork the daemon process into the background, and detach from
+ *	the controlling terminal.  Setup a shared pipe that will later
+ *	be used to report startup status to the parent process.
+ */
+static int
+daemonize(void)
+{
+	int		status;
+	int		pfds[2];
+	pid_t		pid;
+	sigset_t	set;
+	sigset_t	oset;
+
+	/*
+	 * Temporarily block all signals.  They will remain blocked in
+	 * the parent, but will be unblocked in the child once it has
+	 * notified the parent of its startup status.
+	 */
+	(void) sigfillset(&set);
+	(void) sigdelset(&set, SIGABRT);
+	(void) sigprocmask(SIG_BLOCK, &set, &oset);
+
+	/* Create the shared pipe */
+	if (pipe(pfds) == -1) {
+		log_err("Cannot create pipe (%s)\n", strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	/* Fork the daemon process */
+	if ((pid = fork()) == -1) {
+		log_err("Cannot fork daemon process (%s)\n", strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	/* Parent:  waits for exit status from child. */
+	if (pid > 0) {
+		(void) close(pfds[1]);
+		if (read(pfds[0], &status, sizeof (status)) == sizeof (status))
+			_exit(status);
+		if ((waitpid(pid, &status, 0) == pid) && WIFEXITED(status))
+			_exit(WEXITSTATUS(status));
+		log_err("Failed to spawn daemon process.\n");
+		_exit(EXIT_FAILURE);
+	}
+
+	/* Child continues... */
+
+	(void) setsid();
+	(void) chdir("/");
+	(void) umask(CMASK);
+	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
+	(void) close(pfds[0]);
+
+	/* Detach from controlling terminal */
+	(void) close(0);
+	(void) close(1);
+	(void) close(2);
+	(void) open("/dev/null", O_RDONLY);
+	(void) open("/dev/null", O_WRONLY);
+	(void) open("/dev/null", O_WRONLY);
+
+	/* Use syslog for future messages */
+	log_flag = B_TRUE;
+	openlog(prog, LOG_PID, LOG_DAEMON);
+
+	return (pfds[1]);
+}
+
+/*
+ * init_signals()
+ *
+ *	Initialize signal handling.
+ */
+static void
+init_signals(void)
+{
+	struct sigaction	act;
+	sigset_t		set;
+
+	(void) sigfillset(&set);
+	(void) sigdelset(&set, SIGABRT);
+
+	(void) sigfillset(&act.sa_mask);
+	act.sa_handler = signal_handler;
+	act.sa_flags = 0;
+
+	(void) sigaction(SIGTERM, &act, NULL);
+	(void) sigaction(SIGHUP, &act, NULL);
+	(void) sigaction(SIGINT, &act, NULL);
+	(void) sigaction(SIGPIPE, &act, NULL);
+
+	(void) sigdelset(&set, SIGTERM);
+	(void) sigdelset(&set, SIGHUP);
+	(void) sigdelset(&set, SIGINT);
+	(void) sigdelset(&set, SIGPIPE);
+}
+
+/*
+ * signal_handler()
+ *
+ *	Most signals cause the hotplug daemon to shut down.
+ *	Shutdown is triggered using a semaphore to wake up
+ *	the main thread for a clean exit.
+ *
+ *	Except SIGPIPE is used to coordinate between the parent
+ *	and child processes when the daemon first starts.
+ */
+static void
+signal_handler(int signum)
+{
+	log_info("Received signal %d.\n", signum);
+
+	switch (signum) {
+	case 0:
+	case SIGPIPE:
+		break;
+	default:
+		exit_flag = B_TRUE;
+		(void) sema_post(&signal_sem);
+		break;
+	}
+}
+
+/*
+ * shutdown_daemon()
+ *
+ *	Perform a clean shutdown of the daemon.
+ */
+static void
+shutdown_daemon(void)
+{
+	log_info("Hotplug daemon shutting down.\n");
+
+	door_server_fini();
+
+	if (log_flag)
+		closelog();
+
+	(void) sema_destroy(&signal_sem);
+}
+
+/*
+ * log_err()
+ *
+ *	Display an error message.  Use syslog if in daemon
+ *	mode, otherwise print to stderr when in debug mode.
+ */
+/*PRINTFLIKE1*/
+void
+log_err(char *fmt, ...)
+{
+	va_list	ap;
+
+	va_start(ap, fmt);
+	if (debug_flag || !log_flag)
+		(void) vfprintf(stderr, fmt, ap);
+	else
+		vsyslog(LOG_ERR, fmt, ap);
+	va_end(ap);
+}
+
+/*
+ * log_info()
+ *
+ *	Display an information message.  Use syslog if in daemon
+ *	mode, otherwise print to stdout when in debug mode.
+ */
+/*PRINTFLIKE1*/
+void
+log_info(char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	if (debug_flag || !log_flag)
+		(void) vfprintf(stdout, fmt, ap);
+	else
+		vsyslog(LOG_INFO, fmt, ap);
+	va_end(ap);
+}
+
+/*
+ * dprintf()
+ *
+ *	Print a debug tracing statement.  Only works in debug
+ *	mode, and always prints to stdout.
+ */
+/*PRINTFLIKE1*/
+void
+dprintf(char *fmt, ...)
+{
+	va_list	ap;
+
+	if (debug_flag) {
+		va_start(ap, fmt);
+		(void) vprintf(fmt, ap);
+		va_end(ap);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/hotplugd/hotplugd_door.c	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,760 @@
+/*
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <alloca.h>
+#include <door.h>
+#include <pthread.h>
+#include <synch.h>
+#include <pwd.h>
+#include <auth_list.h>
+#include <auth_attr.h>
+#include <bsm/adt.h>
+#include <bsm/adt_event.h>
+#include <sys/sunddi.h>
+#include <sys/ddi_hp.h>
+#include <libnvpair.h>
+#include <libhotplug.h>
+#include <libhotplug_impl.h>
+#include "hotplugd_impl.h"
+
+/*
+ * Buffer management for results.
+ */
+typedef struct i_buffer {
+	uint64_t	seqnum;
+	char		*buffer;
+	struct i_buffer	*next;
+} i_buffer_t;
+
+static uint64_t		buffer_seqnum = 1;
+static i_buffer_t	*buffer_list = NULL;
+static pthread_mutex_t	buffer_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * Door file descriptor.
+ */
+static int	door_fd = -1;
+
+/*
+ * Function prototypes.
+ */
+static void	door_server(void *, char *, size_t, door_desc_t *, uint_t);
+static int	check_auth(ucred_t *, const char *);
+static int	cmd_getinfo(nvlist_t *, nvlist_t **);
+static int	cmd_changestate(nvlist_t *, nvlist_t **);
+static int	cmd_private(hp_cmd_t, nvlist_t *, nvlist_t **);
+static void	add_buffer(uint64_t, char *);
+static void	free_buffer(uint64_t);
+static uint64_t	get_seqnum(void);
+static char	*state_str(int);
+static int	audit_session(ucred_t *, adt_session_data_t **);
+static void	audit_changestate(ucred_t *, char *, char *, char *, int, int,
+		    int);
+static void	audit_setprivate(ucred_t *, char *, char *, char *, char *,
+		    int);
+
+/*
+ * door_server_init()
+ *
+ *	Create the door file, and initialize the door server.
+ */
+boolean_t
+door_server_init(void)
+{
+	int	fd;
+
+	/* Create the door file */
+	if ((fd = open(HOTPLUGD_DOOR, O_CREAT|O_EXCL|O_RDONLY, 0644)) == -1) {
+		if (errno == EEXIST) {
+			log_err("Door service is already running.\n");
+		} else {
+			log_err("Cannot open door file '%s': %s\n",
+			    HOTPLUGD_DOOR, strerror(errno));
+		}
+		return (B_FALSE);
+	}
+	(void) close(fd);
+
+	/* Initialize the door service */
+	if ((door_fd = door_create(door_server, NULL,
+	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
+		log_err("Cannot create door service: %s\n", strerror(errno));
+		return (B_FALSE);
+	}
+
+	/* Cleanup stale door associations */
+	(void) fdetach(HOTPLUGD_DOOR);
+
+	/* Associate door service with door file */
+	if (fattach(door_fd, HOTPLUGD_DOOR) != 0) {
+		log_err("Cannot attach to door file '%s': %s\n", HOTPLUGD_DOOR,
+		    strerror(errno));
+		(void) door_revoke(door_fd);
+		(void) fdetach(HOTPLUGD_DOOR);
+		door_fd = -1;
+		return (B_FALSE);
+	}
+
+	return (B_TRUE);
+}
+
+/*
+ * door_server_fini()
+ *
+ *	Terminate and cleanup the door server.
+ */
+void
+door_server_fini(void)
+{
+	if (door_fd != -1) {
+		(void) door_revoke(door_fd);
+		(void) fdetach(HOTPLUGD_DOOR);
+	}
+
+	(void) unlink(HOTPLUGD_DOOR);
+}
+
+/*
+ * door_server()
+ *
+ *	This routine is the handler which responds to each door call.
+ *	Each incoming door call is expected to send a packed nvlist
+ *	of arguments which describe the requested action.  And each
+ *	response is sent back as a packed nvlist of results.
+ *
+ *	Results are always allocated on the heap.  A global list of
+ *	allocated result buffers is managed, and each one is tracked
+ *	by a unique sequence number.  The final step in the protocol
+ *	is for the caller to send a short response using the sequence
+ *	number when the buffer can be released.
+ */
+/*ARGSUSED*/
+static void
+door_server(void *cookie, char *argp, size_t sz, door_desc_t *dp, uint_t ndesc)
+{
+	nvlist_t	*args = NULL;
+	nvlist_t	*results = NULL;
+	hp_cmd_t	cmd;
+	int		rv;
+
+	dprintf("Door call: cookie=%p, argp=%p, sz=%d\n", cookie, (void *)argp,
+	    sz);
+
+	/* Special case to free a results buffer */
+	if (sz == sizeof (uint64_t)) {
+		free_buffer(*(uint64_t *)(uintptr_t)argp);
+		(void) door_return(NULL, 0, NULL, 0);
+		return;
+	}
+
+	/* Unpack the arguments nvlist */
+	if (nvlist_unpack(argp, sz, &args, 0) != 0) {
+		log_err("Cannot unpack door arguments.\n");
+		rv = EINVAL;
+		goto fail;
+	}
+
+	/* Extract the requested command */
+	if (nvlist_lookup_int32(args, HPD_CMD, (int32_t *)&cmd) != 0) {
+		log_err("Cannot decode door command.\n");
+		rv = EINVAL;
+		goto fail;
+	}
+
+	/* Implement the command */
+	switch (cmd) {
+	case HP_CMD_GETINFO:
+		rv = cmd_getinfo(args, &results);
+		break;
+	case HP_CMD_CHANGESTATE:
+		rv = cmd_changestate(args, &results);
+		break;
+	case HP_CMD_SETPRIVATE:
+	case HP_CMD_GETPRIVATE:
+		rv = cmd_private(cmd, args, &results);
+		break;
+	default:
+		rv = EINVAL;
+		break;
+	}
+
+	/* The arguments nvlist is no longer needed */
+	nvlist_free(args);
+	args = NULL;
+
+	/*
+	 * If an nvlist was constructed for the results,
+	 * then pack the results nvlist and return it.
+	 */
+	if (results != NULL) {
+		uint64_t	seqnum;
+		char		*buf = NULL;
+		size_t		len = 0;
+
+		/* Add a sequence number to the results */
+		seqnum = get_seqnum();
+		if (nvlist_add_uint64(results, HPD_SEQNUM, seqnum) != 0) {
+			log_err("Cannot add sequence number.\n");
+			rv = EFAULT;
+			goto fail;
+		}
+
+		/* Pack the results nvlist */
+		if (nvlist_pack(results, &buf, &len,
+		    NV_ENCODE_NATIVE, 0) != 0) {
+			log_err("Cannot pack door results.\n");
+			rv = EFAULT;
+			goto fail;
+		}
+
+		/* Link results buffer into list */
+		add_buffer(seqnum, buf);
+
+		/* The results nvlist is no longer needed */
+		nvlist_free(results);
+
+		/* Return the results */
+		(void) door_return(buf, len, NULL, 0);
+		return;
+	}
+
+	/* Return result code (when no nvlist) */
+	(void) door_return((char *)&rv, sizeof (int), NULL, 0);
+	return;
+
+fail:
+	log_err("Door call failed (%s)\n", strerror(rv));
+	if (args != NULL)
+		nvlist_free(args);
+	if (results != NULL)
+		nvlist_free(results);
+	(void) door_return((char *)&rv, sizeof (int), NULL, 0);
+}
+
+/*
+ * check_auth()
+ *
+ *	Perform an RBAC authorization check.
+ */
+static int
+check_auth(ucred_t *ucred, const char *auth)
+{
+	struct passwd	pwd;
+	uid_t		euid;
+	char		buf[MAXPATHLEN];
+
+	euid = ucred_geteuid(ucred);
+
+	if ((getpwuid_r(euid, &pwd, buf, sizeof (buf)) == NULL) ||
+	    (chkauthattr(auth, pwd.pw_name) == 0)) {
+		log_info("Unauthorized door call.\n");
+		return (-1);
+	}
+
+	return (0);
+}
+
+/*
+ * cmd_getinfo()
+ *
+ *	Implements the door command to get a hotplug information snapshot.
+ */
+static int
+cmd_getinfo(nvlist_t *args, nvlist_t **resultsp)
+{
+	hp_node_t	root;
+	nvlist_t	*results;
+	char		*path;
+	char		*connection;
+	char		*buf = NULL;
+	size_t		len = 0;
+	uint_t		flags;
+	int		rv;
+
+	dprintf("cmd_getinfo:\n");
+
+	/* Get arguments */
+	if (nvlist_lookup_string(args, HPD_PATH, &path) != 0) {
+		dprintf("cmd_getinfo: invalid arguments.\n");
+		return (EINVAL);
+	}
+	if (nvlist_lookup_string(args, HPD_CONNECTION, &connection) != 0)
+		connection = NULL;
+	if (nvlist_lookup_uint32(args, HPD_FLAGS, (uint32_t *)&flags) != 0)
+		flags = 0;
+
+	/* Get and pack the requested snapshot */
+	if ((rv = getinfo(path, connection, flags, &root)) == 0) {
+		rv = hp_pack(root, &buf, &len);
+		hp_fini(root);
+	}
+	dprintf("cmd_getinfo: getinfo(): rv = %d, buf = %p.\n", rv,
+	    (void *)buf);
+
+	/*
+	 * If the above failed or there is no snapshot,
+	 * then only return a status code.
+	 */
+	if (rv != 0)
+		return (rv);
+	if (buf == NULL)
+		return (EFAULT);
+
+	/* Allocate nvlist for results */
+	if (nvlist_alloc(&results, NV_UNIQUE_NAME_TYPE, 0) != 0) {
+		dprintf("cmd_getinfo: nvlist_alloc() failed.\n");
+		free(buf);
+		return (ENOMEM);
+	}
+
+	/* Add snapshot and successful status to results */
+	if ((nvlist_add_int32(results, HPD_STATUS, 0) != 0) ||
+	    (nvlist_add_byte_array(results, HPD_INFO,
+	    (uchar_t *)buf, len) != 0)) {
+		dprintf("cmd_getinfo: nvlist add failure.\n");
+		nvlist_free(results);
+		free(buf);
+		return (ENOMEM);
+	}
+
+	/* Packed snapshot no longer needed */
+	free(buf);
+
+	/* Success */
+	*resultsp = results;
+	return (0);
+}
+
+/*
+ * cmd_changestate()
+ *
+ *	Implements the door command to initate a state change operation.
+ *
+ *	NOTE: requires 'modify' authorization.
+ */
+static int
+cmd_changestate(nvlist_t *args, nvlist_t **resultsp)
+{
+	hp_node_t	root = NULL;
+	nvlist_t	*results = NULL;
+	char		*path, *connection;
+	ucred_t		*uc = NULL;
+	uint_t		flags;
+	int		rv, state, old_state, status;
+
+	dprintf("cmd_changestate:\n");
+
+	/* Get arguments */
+	if ((nvlist_lookup_string(args, HPD_PATH, &path) != 0) ||
+	    (nvlist_lookup_string(args, HPD_CONNECTION, &connection) != 0) ||
+	    (nvlist_lookup_int32(args, HPD_STATE, &state) != 0)) {
+		dprintf("cmd_changestate: invalid arguments.\n");
+		return (EINVAL);
+	}
+	if (nvlist_lookup_uint32(args, HPD_FLAGS, (uint32_t *)&flags) != 0)
+		flags = 0;
+
+	/* Get caller's credentials */
+	if (door_ucred(&uc) != 0) {
+		log_err("Cannot get door credentials (%s)\n", strerror(errno));
+		return (EACCES);
+	}
+
+	/* Check authorization */
+	if (check_auth(uc, HP_MODIFY_AUTH) != 0) {
+		dprintf("cmd_changestate: access denied.\n");
+		audit_changestate(uc, HP_MODIFY_AUTH, path, connection,
+		    state, -1, ADT_FAIL_VALUE_AUTH);
+		ucred_free(uc);
+		return (EACCES);
+	}
+
+	/* Perform the state change operation */
+	status = changestate(path, connection, state, flags, &old_state, &root);
+	dprintf("cmd_changestate: changestate() == %d\n", status);
+
+	/* Audit the operation */
+	audit_changestate(uc, HP_MODIFY_AUTH, path, connection, state,
+	    old_state, status);
+
+	/* Caller's credentials no longer needed */
+	ucred_free(uc);
+
+	/*
+	 * Pack the results into an nvlist if there is an error snapshot.
+	 *
+	 * If any error occurs while packing the results, the original
+	 * error code from changestate() above is still returned.
+	 */
+	if (root != NULL) {
+		char	*buf = NULL;
+		size_t	len = 0;
+
+		dprintf("cmd_changestate: results nvlist required.\n");
+
+		/* Pack and discard the error snapshot */
+		rv = hp_pack(root, &buf, &len);
+		hp_fini(root);
+		if (rv != 0) {
+			dprintf("cmd_changestate: hp_pack() failed (%s).\n",
+			    strerror(rv));
+			return (status);
+		}
+
+		/* Allocate nvlist for results */
+		if (nvlist_alloc(&results, NV_UNIQUE_NAME_TYPE, 0) != 0) {
+			dprintf("cmd_changestate: nvlist_alloc() failed.\n");
+			free(buf);
+			return (status);
+		}
+
+		/* Add the results into the nvlist */
+		if ((nvlist_add_int32(results, HPD_STATUS, status) != 0) ||
+		    (nvlist_add_byte_array(results, HPD_INFO, (uchar_t *)buf,
+		    len) != 0)) {
+			dprintf("cmd_changestate: nvlist add failed.\n");
+			nvlist_free(results);
+			free(buf);
+			return (status);
+		}
+
+		*resultsp = results;
+	}
+
+	return (status);
+}
+
+/*
+ * cmd_private()
+ *
+ *	Implementation of the door command to set or get bus private options.
+ *
+ *	NOTE: requires 'modify' authorization for the 'set' command.
+ */
+static int
+cmd_private(hp_cmd_t cmd, nvlist_t *args, nvlist_t **resultsp)
+{
+	nvlist_t	*results = NULL;
+	ucred_t		*uc = NULL;
+	char		*path, *connection, *options;
+	char		*values = NULL;
+	int		status;
+
+	dprintf("cmd_private:\n");
+
+	/* Get caller's credentials */
+	if ((cmd == HP_CMD_SETPRIVATE) && (door_ucred(&uc) != 0)) {
+		log_err("Cannot get door credentials (%s)\n", strerror(errno));
+		return (EACCES);
+	}
+
+	/* Get arguments */
+	if ((nvlist_lookup_string(args, HPD_PATH, &path) != 0) ||
+	    (nvlist_lookup_string(args, HPD_CONNECTION, &connection) != 0) ||
+	    (nvlist_lookup_string(args, HPD_OPTIONS, &options) != 0)) {
+		dprintf("cmd_private: invalid arguments.\n");
+		return (EINVAL);
+	}
+
+	/* Check authorization */
+	if ((cmd == HP_CMD_SETPRIVATE) &&
+	    (check_auth(uc, HP_MODIFY_AUTH) != 0)) {
+		dprintf("cmd_private: access denied.\n");
+		audit_setprivate(uc, HP_MODIFY_AUTH, path, connection, options,
+		    ADT_FAIL_VALUE_AUTH);
+		ucred_free(uc);
+		return (EACCES);
+	}
+
+	/* Perform the operation */
+	status = private_options(path, connection, cmd, options, &values);
+	dprintf("cmd_private: private_options() == %d\n", status);
+
+	/* Audit the operation */
+	if (cmd == HP_CMD_SETPRIVATE) {
+		audit_setprivate(uc, HP_MODIFY_AUTH, path, connection, options,
+		    status);
+		ucred_free(uc);
+	}
+
+	/* Construct an nvlist if values were returned */
+	if (values != NULL) {
+
+		/* Allocate nvlist for results */
+		if (nvlist_alloc(&results, NV_UNIQUE_NAME_TYPE, 0) != 0) {
+			dprintf("cmd_private: nvlist_alloc() failed.\n");
+			free(values);
+			return (ENOMEM);
+		}
+
+		/* Add values and status to the results */
+		if ((nvlist_add_int32(results, HPD_STATUS, status) != 0) ||
+		    (nvlist_add_string(results, HPD_OPTIONS, values) != 0)) {
+			dprintf("cmd_private: nvlist add failed.\n");
+			nvlist_free(results);
+			free(values);
+			return (ENOMEM);
+		}
+
+		/* The values string is no longer needed */
+		free(values);
+
+		*resultsp = results;
+	}
+
+	return (status);
+}
+
+/*
+ * get_seqnum()
+ *
+ *	Allocate the next unique sequence number for a results buffer.
+ */
+static uint64_t
+get_seqnum(void)
+{
+	uint64_t seqnum;
+
+	(void) pthread_mutex_lock(&buffer_lock);
+
+	seqnum = buffer_seqnum++;
+
+	(void) pthread_mutex_unlock(&buffer_lock);
+
+	return (seqnum);
+}
+
+/*
+ * add_buffer()
+ *
+ *	Link a results buffer into the list containing all buffers.
+ */
+static void
+add_buffer(uint64_t seqnum, char *buf)
+{
+	i_buffer_t	*node;
+
+	if ((node = (i_buffer_t *)malloc(sizeof (i_buffer_t))) == NULL) {
+		/* The consequence is a memory leak. */
+		log_err("Cannot allocate results buffer: %s\n",
+		    strerror(errno));
+		return;
+	}
+
+	node->seqnum = seqnum;
+	node->buffer = buf;
+
+	(void) pthread_mutex_lock(&buffer_lock);
+
+	node->next = buffer_list;
+	buffer_list = node;
+
+	(void) pthread_mutex_unlock(&buffer_lock);
+}
+
+/*
+ * free_buffer()
+ *
+ *	Remove a results buffer from the list containing all buffers.
+ */
+static void
+free_buffer(uint64_t seqnum)
+{
+	i_buffer_t	*node, *prev;
+
+	(void) pthread_mutex_lock(&buffer_lock);
+
+	prev = NULL;
+	node = buffer_list;
+
+	while (node) {
+		if (node->seqnum == seqnum) {
+			dprintf("Free buffer %lld\n", seqnum);
+			if (prev) {
+				prev->next = node->next;
+			} else {
+				buffer_list = node->next;
+			}
+			free(node->buffer);
+			free(node);
+			break;
+		}
+		prev = node;
+		node = node->next;
+	}
+
+	(void) pthread_mutex_unlock(&buffer_lock);
+}
+
+/*
+ * audit_session()
+ *
+ *	Initialize an audit session.
+ */
+static int
+audit_session(ucred_t *ucred, adt_session_data_t **sessionp)
+{
+	adt_session_data_t	*session;
+
+	if (adt_start_session(&session, NULL, 0) != 0) {
+		log_err("Cannot start audit session.\n");
+		return (-1);
+	}
+
+	if (adt_set_from_ucred(session, ucred, ADT_NEW) != 0) {
+		log_err("Cannot set audit session from ucred.\n");
+		(void) adt_end_session(session);
+		return (-1);
+	}
+
+	*sessionp = session;
+	return (0);
+}
+
+/*
+ * audit_changestate()
+ *
+ *	Audit a 'changestate' door command.
+ */
+static void
+audit_changestate(ucred_t *ucred, char *auth, char *path, char *connection,
+    int new_state, int old_state, int result)
+{
+	adt_session_data_t	*session;
+	adt_event_data_t	*event;
+	int			pass_fail, fail_reason;
+
+	if (audit_session(ucred, &session) != 0)
+		return;
+
+	if ((event = adt_alloc_event(session, ADT_hotplug_state)) == NULL) {
+		(void) adt_end_session(session);
+		return;
+	}
+
+	if (result == 0) {
+		pass_fail = ADT_SUCCESS;
+		fail_reason = ADT_SUCCESS;
+	} else {
+		pass_fail = ADT_FAILURE;
+		fail_reason = result;
+	}
+
+	event->adt_hotplug_state.auth_used = auth;
+	event->adt_hotplug_state.device_path = path;
+	event->adt_hotplug_state.connection = connection;
+	event->adt_hotplug_state.new_state = state_str(new_state);
+	event->adt_hotplug_state.old_state = state_str(old_state);
+
+	/* Put the event */
+	if (adt_put_event(event, pass_fail, fail_reason) != 0)
+		log_err("Cannot put audit event.\n");
+
+	adt_free_event(event);
+	(void) adt_end_session(session);
+}
+
+/*
+ * audit_setprivate()
+ *
+ *	Audit a 'set private' door command.
+ */
+static void
+audit_setprivate(ucred_t *ucred, char *auth, char *path, char *connection,
+    char *options, int result)
+{
+	adt_session_data_t	*session;
+	adt_event_data_t	*event;
+	int			pass_fail, fail_reason;
+
+	if (audit_session(ucred, &session) != 0)
+		return;
+
+	if ((event = adt_alloc_event(session, ADT_hotplug_set)) == NULL) {
+		(void) adt_end_session(session);
+		return;
+	}
+
+	if (result == 0) {
+		pass_fail = ADT_SUCCESS;
+		fail_reason = ADT_SUCCESS;
+	} else {
+		pass_fail = ADT_FAILURE;
+		fail_reason = result;
+	}
+
+	event->adt_hotplug_set.auth_used = auth;
+	event->adt_hotplug_set.device_path = path;
+	event->adt_hotplug_set.connection = connection;
+	event->adt_hotplug_set.options = options;
+
+	/* Put the event */
+	if (adt_put_event(event, pass_fail, fail_reason) != 0)
+		log_err("Cannot put audit event.\n");
+
+	adt_free_event(event);
+	(void) adt_end_session(session);
+}
+
+/*
+ * state_str()
+ *
+ *	Convert a state from integer to string.
+ */
+static char *
+state_str(int state)
+{
+	switch (state) {
+	case DDI_HP_CN_STATE_EMPTY:
+		return ("EMPTY");
+	case DDI_HP_CN_STATE_PRESENT:
+		return ("PRESENT");
+	case DDI_HP_CN_STATE_POWERED:
+		return ("POWERED");
+	case DDI_HP_CN_STATE_ENABLED:
+		return ("ENABLED");
+	case DDI_HP_CN_STATE_PORT_EMPTY:
+		return ("PORT-EMPTY");
+	case DDI_HP_CN_STATE_PORT_PRESENT:
+		return ("PORT-PRESENT");
+	case DDI_HP_CN_STATE_OFFLINE:
+		return ("OFFLINE");
+	case DDI_HP_CN_STATE_ATTACHED:
+		return ("ATTACHED");
+	case DDI_HP_CN_STATE_MAINTENANCE:
+		return ("MAINTENANCE");
+	case DDI_HP_CN_STATE_ONLINE:
+		return ("ONLINE");
+	default:
+		return ("UNKNOWN");
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/hotplugd/hotplugd_impl.c	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,435 @@
+/*
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <alloca.h>
+#include <libnvpair.h>
+#include <libhotplug.h>
+#include <libhotplug_impl.h>
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#include <sys/ddi_hp.h>
+#include <sys/modctl.h>
+#include "hotplugd_impl.h"
+
+/*
+ * All operations affecting kernel state are serialized.
+ */
+static pthread_mutex_t	hotplug_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * Local functions.
+ */
+static boolean_t	check_rcm_required(hp_node_t, int);
+static int		pack_properties(const char *, ddi_hp_property_t *);
+static void		unpack_properties(ddi_hp_property_t *, char **);
+static void		free_properties(ddi_hp_property_t *);
+
+/*
+ * changestate()
+ *
+ *	Perform a state change operation.
+ *
+ *	NOTE: all operations are serialized, using a global lock.
+ */
+int
+changestate(const char *path, const char *connection, int state, uint_t flags,
+    int *old_statep, hp_node_t *resultsp)
+{
+	hp_node_t	root = NULL;
+	char		**rsrcs = NULL;
+	boolean_t	use_rcm = B_FALSE;
+	int		rv;
+
+	dprintf("changestate(path=%s, connection=%s, state=0x%x, flags=0x%x)\n",
+	    path, connection, state, flags);
+
+	/* Initialize results */
+	*resultsp = NULL;
+	*old_statep = -1;
+
+	(void) pthread_mutex_lock(&hotplug_lock);
+
+	/* Get an information snapshot, without usage details */
+	if ((rv = getinfo(path, connection, 0, &root)) != 0) {
+		(void) pthread_mutex_unlock(&hotplug_lock);
+		dprintf("changestate: getinfo() failed (%s)\n", strerror(rv));
+		return (rv);
+	}
+
+	/* Record current state (used in hotplugd_door.c for auditing) */
+	*old_statep = hp_state(root);
+
+	/* Check if RCM interactions are required */
+	use_rcm = check_rcm_required(root, state);
+
+	/* If RCM is required, perform RCM offline */
+	if (use_rcm) {
+
+		dprintf("changestate: RCM offline is required.\n");
+
+		/* Get RCM resources */
+		if ((rv = rcm_resources(root, &rsrcs)) != 0) {
+			dprintf("changestate: rcm_resources() failed.\n");
+			(void) pthread_mutex_unlock(&hotplug_lock);
+			hp_fini(root);
+			return (rv);
+		}
+
+		/* Request RCM offline */
+		if ((rsrcs != NULL) &&
+		    ((rv = rcm_offline(rsrcs, flags, root)) != 0)) {
+			dprintf("changestate: rcm_offline() failed.\n");
+			rcm_online(rsrcs);
+			(void) pthread_mutex_unlock(&hotplug_lock);
+			free_rcm_resources(rsrcs);
+			*resultsp = root;
+			return (rv);
+		}
+	}
+
+	/* The information snapshot is no longer needed */
+	hp_fini(root);
+
+	/* Stop now if QUERY flag was specified */
+	if (flags & HPQUERY) {
+		dprintf("changestate: operation was QUERY only.\n");
+		rcm_online(rsrcs);
+		(void) pthread_mutex_unlock(&hotplug_lock);
+		free_rcm_resources(rsrcs);
+		return (0);
+	}
+
+	/* Do state change in kernel */
+	rv = 0;
+	if (modctl(MODHPOPS, MODHPOPS_CHANGE_STATE, path, connection, state))
+		rv = errno;
+	dprintf("changestate: modctl(MODHPOPS_CHANGE_STATE) = %d.\n", rv);
+
+	/*
+	 * If RCM is required, then perform an RCM online or RCM remove
+	 * operation.  Which depends upon if modctl succeeded or failed.
+	 */
+	if (use_rcm && (rsrcs != NULL)) {
+
+		/* RCM online if failure, or RCM remove if successful */
+		if (rv == 0)
+			rcm_remove(rsrcs);
+		else
+			rcm_online(rsrcs);
+
+		/* RCM resources no longer required */
+		free_rcm_resources(rsrcs);
+	}
+
+	(void) pthread_mutex_unlock(&hotplug_lock);
+
+	*resultsp = NULL;
+	return (rv);
+}
+
+/*
+ * private_options()
+ *
+ *	Implement set/get of bus private options.
+ */
+int
+private_options(const char *path, const char *connection, hp_cmd_t cmd,
+    const char *options, char **resultsp)
+{
+	ddi_hp_property_t	prop;
+	ddi_hp_property_t	results;
+	char			*values = NULL;
+	int			rv;
+
+	dprintf("private_options(path=%s, connection=%s, options='%s')\n",
+	    path, connection, options);
+
+	/* Initialize property arguments */
+	if ((rv = pack_properties(options, &prop)) != 0) {
+		dprintf("private_options: failed to pack properties.\n");
+		return (rv);
+	}
+
+	/* Initialize results */
+	(void) memset(&results, 0, sizeof (ddi_hp_property_t));
+	results.buf_size = HP_PRIVATE_BUF_SZ;
+	results.nvlist_buf = (char *)calloc(1, HP_PRIVATE_BUF_SZ);
+	if (results.nvlist_buf == NULL) {
+		dprintf("private_options: failed to allocate buffer.\n");
+		free_properties(&prop);
+		return (ENOMEM);
+	}
+
+	/* Lock hotplug */
+	(void) pthread_mutex_lock(&hotplug_lock);
+
+	/* Perform the command */
+	rv = 0;
+	if (cmd == HP_CMD_GETPRIVATE) {
+		if (modctl(MODHPOPS, MODHPOPS_BUS_GET, path, connection,
+		    &prop, &results))
+			rv = errno;
+		dprintf("private_options: modctl(MODHPOPS_BUS_GET) = %d\n", rv);
+	} else {
+		if (modctl(MODHPOPS, MODHPOPS_BUS_SET, path, connection,
+		    &prop, &results))
+			rv = errno;
+		dprintf("private_options: modctl(MODHPOPS_BUS_SET) = %d\n", rv);
+	}
+
+	/* Unlock hotplug */
+	(void) pthread_mutex_unlock(&hotplug_lock);
+
+	/* Parse results */
+	if (rv == 0) {
+		unpack_properties(&results, &values);
+		*resultsp = values;
+	}
+
+	/* Cleanup */
+	free_properties(&prop);
+	free_properties(&results);
+
+	return (rv);
+}
+
+/*
+ * check_rcm_required()
+ *
+ *	Given the root of a changestate operation and the target
+ *	state, determine if RCM interactions will be required.
+ */
+static boolean_t
+check_rcm_required(hp_node_t root, int target_state)
+{
+	/*
+	 * RCM is required when transitioning an ENABLED
+	 * connector to a non-ENABLED state.
+	 */
+	if ((root->hp_type == HP_NODE_CONNECTOR) &&
+	    HP_IS_ENABLED(root->hp_state) && !HP_IS_ENABLED(target_state))
+		return (B_TRUE);
+
+	/*
+	 * RCM is required when transitioning an OPERATIONAL
+	 * port to a non-OPERATIONAL state.
+	 */
+	if ((root->hp_type == HP_NODE_PORT) &&
+	    HP_IS_ONLINE(root->hp_state) && HP_IS_OFFLINE(target_state))
+		return (B_TRUE);
+
+	/* RCM is not required in other cases */
+	return (B_FALSE);
+}
+
+/*
+ * pack_properties()
+ *
+ *	Given a specified set/get command and an options string,
+ *	construct the structure containing a packed nvlist that
+ *	contains the specified options.
+ */
+static int
+pack_properties(const char *options, ddi_hp_property_t *prop)
+{
+	nvlist_t	*nvl;
+	char		*buf, *tmp, *name, *value, *next;
+	size_t		len;
+
+	/* Initialize results */
+	(void) memset(prop, 0, sizeof (ddi_hp_property_t));
+
+	/* Do nothing if options string is empty */
+	if ((len = strlen(options)) == 0) {
+		dprintf("pack_properties: options string is empty.\n");
+		return (ENOENT);
+	}
+
+	/* Avoid modifying the input string by using a copy on the stack */
+	if ((tmp = (char *)alloca(len + 1)) == NULL) {
+		log_err("Failed to allocate buffer for private options.\n");
+		return (ENOMEM);
+	}
+	(void) strlcpy(tmp, options, len + 1);
+
+	/* Allocate the nvlist */
+	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
+		log_err("Failed to allocate private options nvlist.\n");
+		return (ENOMEM);
+	}
+
+	/* Add each option from the string */
+	for (name = tmp; name != NULL; name = next) {
+
+		/* Isolate current name/value, and locate the next */
+		if ((next = strchr(name, ',')) != NULL) {
+			*next = '\0';
+			next++;
+		}
+
+		/* Split current name/value pair */
+		if ((value = strchr(name, '=')) != NULL) {
+			*value = '\0';
+			value++;
+		} else {
+			value = "";
+		}
+
+		/* Add the option to the nvlist */
+		if (nvlist_add_string(nvl, name, value) != 0) {
+			log_err("Failed to add private option to nvlist.\n");
+			nvlist_free(nvl);
+			return (EFAULT);
+		}
+	}
+
+	/* Pack the nvlist */
+	len = 0;
+	buf = NULL;
+	if (nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0) != 0) {
+		log_err("Failed to pack private options nvlist.\n");
+		nvlist_free(nvl);
+		return (EFAULT);
+	}
+
+	/* Save results */
+	prop->nvlist_buf = buf;
+	prop->buf_size = len;
+
+	/* The nvlist is no longer needed */
+	nvlist_free(nvl);
+
+	return (0);
+}
+
+/*
+ * unpack_properties()
+ *
+ *	Given a structure possibly containing a packed nvlist of
+ *	bus private options, unpack the nvlist and expand its
+ *	contents into an options string.
+ */
+static void
+unpack_properties(ddi_hp_property_t *prop, char **optionsp)
+{
+	nvlist_t	*nvl = NULL;
+	nvpair_t	*nvp;
+	boolean_t	first_flag;
+	char		*name, *value, *options;
+	size_t		len;
+
+	/* Initialize results */
+	*optionsp = NULL;
+
+	/* Do nothing if properties do not exist */
+	if ((prop->nvlist_buf == NULL) || (prop->buf_size == 0)) {
+		dprintf("unpack_properties: no properties exist.\n");
+		return;
+	}
+
+	/* Unpack the nvlist */
+	if (nvlist_unpack(prop->nvlist_buf, prop->buf_size, &nvl, 0) != 0) {
+		log_err("Failed to unpack private options nvlist.\n");
+		return;
+	}
+
+	/* Compute the size of the options string */
+	for (len = 0, nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
+
+		name = nvpair_name(nvp);
+
+		/* Skip the command, and anything not a string */
+		if ((strcmp(name, "cmd") == 0) ||
+		    (nvpair_type(nvp) != DATA_TYPE_STRING))
+			continue;
+
+		(void) nvpair_value_string(nvp, &value);
+
+		/* Account for '=' signs, commas, and terminating NULL */
+		len += (strlen(name) + strlen(value) + 2);
+	}
+
+	/* Allocate the resulting options string */
+	if ((options = (char *)calloc(len, sizeof (char))) == NULL) {
+		log_err("Failed to allocate private options string.\n");
+		nvlist_free(nvl);
+		return;
+	}
+
+	/* Copy name/value pairs into the options string */
+	first_flag = B_TRUE;
+	for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
+
+		name = nvpair_name(nvp);
+
+		/* Skip the command, and anything not a string */
+		if ((strcmp(name, "cmd") == 0) ||
+		    (nvpair_type(nvp) != DATA_TYPE_STRING))
+			continue;
+
+		if (!first_flag)
+			(void) strlcat(options, ",", len);
+
+		(void) strlcat(options, name, len);
+
+		(void) nvpair_value_string(nvp, &value);
+
+		if (strlen(value) > 0) {
+			(void) strlcat(options, "=", len);
+			(void) strlcat(options, value, len);
+		}
+
+		first_flag = B_FALSE;
+	}
+
+	/* The unpacked nvlist is no longer needed */
+	nvlist_free(nvl);
+
+	/* Save results */
+	*optionsp = options;
+}
+
+/*
+ * free_properties()
+ *
+ *	Destroy a structure containing a packed nvlist of bus
+ *	private properties.
+ */
+static void
+free_properties(ddi_hp_property_t *prop)
+{
+	if (prop) {
+		if (prop->nvlist_buf)
+			free(prop->nvlist_buf);
+		(void) memset(prop, 0, sizeof (ddi_hp_property_t));
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/hotplugd/hotplugd_impl.h	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,81 @@
+/*
+ * 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	_HOTPLUGD_IMPL_H
+#define	_HOTPLUGD_IMPL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Define macros to test connection states.
+ */
+#define	HP_IS_ENABLED(s)	(s == DDI_HP_CN_STATE_ENABLED)
+
+#define	HP_IS_ONLINE(s)		((s == DDI_HP_CN_STATE_ONLINE) || \
+				(s == DDI_HP_CN_STATE_MAINTENANCE))
+
+#define	HP_IS_OFFLINE(s)	((s == DDI_HP_CN_STATE_PORT_EMPTY) || \
+				(s == DDI_HP_CN_STATE_PORT_PRESENT) || \
+				(s == DDI_HP_CN_STATE_OFFLINE))
+
+/*
+ * Define size of nvlist buffer for set/get commands.
+ */
+#define	HP_PRIVATE_BUF_SZ	4096
+
+/*
+ * Define a string for parsing /devices paths.
+ */
+#define	S_DEVICES		"/devices"
+
+/*
+ * Global functions.
+ */
+void		log_err(char *fmt, ...);
+void		log_info(char *fmt, ...);
+void		dprintf(char *fmt, ...);
+boolean_t	door_server_init(void);
+void		door_server_fini(void);
+int		getinfo(const char *path, const char *connection, uint_t flags,
+		    hp_node_t *rootp);
+int		changestate(const char *path, const char *connection, int state,
+		    uint_t flags, int *old_statep, hp_node_t *resultsp);
+int		private_options(const char *path, const char *connection,
+		    hp_cmd_t cmd, const char *options, char **resultsp);
+int		copy_usage(hp_node_t root);
+int		rcm_resources(hp_node_t root, char ***rsrcsp);
+void		free_rcm_resources(char **rsrcs);
+int		rcm_offline(char **rsrcs, uint_t flags, hp_node_t root);
+void		rcm_online(char **rsrcs);
+void		rcm_remove(char **rsrcs);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif	/* _HOTPLUGD_IMPL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/hotplugd/hotplugd_info.c	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,513 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libdevinfo.h>
+#include <libhotplug.h>
+#include <libhotplug_impl.h>
+#include <sys/sunddi.h>
+#include <sys/ddi_hp.h>
+#include "hotplugd_impl.h"
+
+/*
+ * Define a list of hotplug nodes.
+ * (Only used within this module.)
+ */
+typedef struct {
+	hp_node_t	head;
+	hp_node_t	prev;
+} hp_node_list_t;
+
+/*
+ * Local functions.
+ */
+static int		copy_devinfo(const char *, const char *, uint_t,
+			    hp_node_t *);
+static int		copy_devices(hp_node_t, di_node_t, uint_t, hp_node_t *);
+static int		copy_hotplug(hp_node_t, di_node_t, const char *, uint_t,
+			    hp_node_t *);
+static char		*base_path(const char *);
+static int		search_cb(di_node_t, void *);
+static int		check_search(di_node_t, uint_t);
+static hp_node_t	new_device_node(hp_node_t, di_node_t);
+static hp_node_t	new_hotplug_node(hp_node_t, di_hp_t);
+static void		node_list_add(hp_node_list_t *, hp_node_t);
+
+/*
+ * getinfo()
+ *
+ *	Build a hotplug information snapshot.  The path, connection,
+ *	and flags indicate what information should be included.
+ */
+int
+getinfo(const char *path, const char *connection, uint_t flags, hp_node_t *retp)
+{
+	hp_node_t	root = NULL;
+	hp_node_t	child;
+	char		*basepath;
+	int		rv;
+
+	if ((path == NULL) || (retp == NULL))
+		return (EINVAL);
+
+	dprintf("getinfo: path=%s, connection=%s, flags=0x%x\n", path,
+	    (connection == NULL) ? "NULL" : connection, flags);
+
+	/* Allocate the base path */
+	if ((basepath = base_path(path)) == NULL)
+		return (ENOMEM);
+
+	/* Copy in device and hotplug nodes from libdevinfo */
+	if ((rv = copy_devinfo(basepath, connection, flags, &root)) != 0) {
+		hp_fini(root);
+		free(basepath);
+		return (rv);
+	}
+
+	/* Check if there were no connections */
+	if (root == NULL) {
+		dprintf("getinfo: no hotplug connections.\n");
+		free(basepath);
+		return (ENOENT);
+	}
+
+	/* Special case: exclude root nexus from snapshot */
+	if (strcmp(basepath, "/") == 0) {
+		child = root->hp_child;
+		if (root->hp_name != NULL)
+			free(root->hp_name);
+		free(root);
+		root = child;
+		for (child = root; child; child = child->hp_sibling)
+			child->hp_parent = NULL;
+	}
+
+	/* Store a pointer to the base path in each root node */
+	for (child = root; child != NULL; child = child->hp_sibling)
+		child->hp_basepath = basepath;
+
+	/* Copy in usage information from RCM */
+	if (flags & HPINFOUSAGE) {
+		if ((rv = copy_usage(root)) != 0) {
+			(void) hp_fini(root);
+			return (rv);
+		}
+	}
+
+	*retp = root;
+	return (0);
+}
+
+/*
+ * copy_devinfo()
+ *
+ *	Copy information about device and hotplug nodes from libdevinfo.
+ *
+ *	When path is set to "/", the results need to be limited only to
+ *	branches that contain hotplug information.  An initial search
+ * 	is performed to mark which branches contain hotplug nodes.
+ */
+static int
+copy_devinfo(const char *path, const char *connection, uint_t flags,
+    hp_node_t *rootp)
+{
+	hp_node_t	hp_root = NULL;
+	di_node_t	di_root;
+	int		rv;
+
+	/* Get libdevinfo snapshot */
+	if ((di_root = di_init(path, DINFOSUBTREE | DINFOHP)) == DI_NODE_NIL)
+		return (errno);
+
+	/* Do initial search pass, if required */
+	if (strcmp(path, "/") == 0) {
+		flags |= HPINFOSEARCH;
+		(void) di_walk_node(di_root, DI_WALK_CLDFIRST, NULL, search_cb);
+	}
+
+	/*
+	 * If a connection is specified, just copy immediate hotplug info.
+	 * Else, copy the device tree normally.
+	 */
+	if (connection != NULL)
+		rv = copy_hotplug(NULL, di_root, connection, flags, &hp_root);
+	else
+		rv = copy_devices(NULL, di_root, flags, &hp_root);
+
+	/* Destroy devinfo snapshot */
+	di_fini(di_root);
+
+	*rootp = (rv == 0) ? hp_root : NULL;
+	return (rv);
+}
+
+/*
+ * copy_devices()
+ *
+ *	Copy a full branch of device nodes.  Used by copy_devinfo() and
+ *	copy_hotplug().
+ */
+static int
+copy_devices(hp_node_t parent, di_node_t dev, uint_t flags, hp_node_t *rootp)
+{
+	hp_node_list_t	children;
+	hp_node_t	self, branch;
+	di_node_t	child;
+	int		rv = 0;
+
+	/* Initialize results */
+	*rootp = NULL;
+
+	/* Enforce search semantics */
+	if (check_search(dev, flags) == 0)
+		return (0);
+
+	/* Allocate new node for current device */
+	if ((self = new_device_node(parent, dev)) == NULL)
+		return (ENOMEM);
+
+	/*
+	 * If the device has hotplug nodes, then use copy_hotplug()
+	 * instead to build the branch associated with current device.
+	 */
+	if (di_hp_next(dev, DI_HP_NIL) != DI_HP_NIL) {
+		if ((rv = copy_hotplug(self, dev, NULL, flags,
+		    &self->hp_child)) != 0) {
+			free(self);
+			return (rv);
+		}
+		*rootp = self;
+		return (0);
+	}
+
+	/*
+	 * The device does not have hotplug nodes.  Use normal
+	 * approach of iterating through its child device nodes.
+	 */
+	(void) memset(&children, 0, sizeof (hp_node_list_t));
+	for (child = di_child_node(dev); child != DI_NODE_NIL;
+	    child = di_sibling_node(child)) {
+		branch = NULL;
+		if ((rv = copy_devices(self, child, flags, &branch)) != 0) {
+			(void) hp_fini(children.head);
+			free(self);
+			return (rv);
+		}
+		if (branch != NULL)
+			node_list_add(&children, branch);
+	}
+	self->hp_child = children.head;
+
+	/* Done */
+	*rootp = self;
+	return (0);
+}
+
+/*
+ * copy_hotplug()
+ *
+ *	Copy a full branch of hotplug nodes.  Used by copy_devinfo()
+ *	and copy_devices().
+ *
+ *	If a connection is specified, the results are limited only
+ *	to the branch associated with that specific connection.
+ */
+static int
+copy_hotplug(hp_node_t parent, di_node_t dev, const char *connection,
+    uint_t flags, hp_node_t *retp)
+{
+	hp_node_list_t	connections, ports;
+	hp_node_t	node, port_node;
+	di_node_t	child_dev;
+	di_hp_t		hp, port_hp;
+	uint_t		child_flags;
+	int		rv, physnum;
+
+	/* Stop implementing the HPINFOSEARCH flag */
+	child_flags = flags & ~(HPINFOSEARCH);
+
+	/* Clear lists of discovered ports and connections */
+	(void) memset(&ports, 0, sizeof (hp_node_list_t));
+	(void) memset(&connections, 0, sizeof (hp_node_list_t));
+
+	/*
+	 * Scan virtual ports.
+	 *
+	 * If a connection is specified and it matches a virtual port,
+	 * this will build the branch associated with that connection.
+	 * Else, this will only build branches for virtual ports that
+	 * are not associated with a physical connector.
+	 */
+	for (hp = DI_HP_NIL; (hp = di_hp_next(dev, hp)) != DI_HP_NIL; ) {
+
+		/* Ignore connectors */
+		if (di_hp_type(hp) != DDI_HP_CN_TYPE_VIRTUAL_PORT)
+			continue;
+
+		/*
+		 * Ignore ports associated with connectors, unless
+		 * a specific connection is being sought.
+		 */
+		if ((connection == NULL) && (di_hp_depends_on(hp) != -1))
+			continue;
+
+		/* If a connection is specified, ignore non-matching ports */
+		if ((connection != NULL) &&
+		    (strcmp(di_hp_name(hp), connection) != 0))
+			continue;
+
+		/* Create a new port node */
+		if ((node = new_hotplug_node(parent, hp)) == NULL) {
+			rv = ENOMEM;
+			goto fail;
+		}
+
+		/* Add port node to connection list */
+		node_list_add(&connections, node);
+
+		/* Add branch of child devices to port node */
+		if ((child_dev = di_hp_child(hp)) != DI_NODE_NIL)
+			if ((rv = copy_devices(node, child_dev, child_flags,
+			    &node->hp_child)) != 0)
+				goto fail;
+	}
+
+	/*
+	 * Scan physical connectors.
+	 *
+	 * If a connection is specified, the results will be limited
+	 * only to the branch associated with that connection.
+	 */
+	for (hp = DI_HP_NIL; (hp = di_hp_next(dev, hp)) != DI_HP_NIL; ) {
+
+		/* Ignore ports */
+		if (di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT)
+			continue;
+
+		/* If a connection is specified, ignore non-matching ports */
+		if ((connection != NULL) &&
+		    (strcmp(di_hp_name(hp), connection) != 0))
+			continue;
+
+		/* Create a new connector node */
+		if ((node = new_hotplug_node(parent, hp)) == NULL) {
+			rv = ENOMEM;
+			goto fail;
+		}
+
+		/* Add connector node to connection list */
+		node_list_add(&connections, node);
+
+		/* Add branches of associated port nodes */
+		physnum = di_hp_connection(hp);
+		port_hp = DI_HP_NIL;
+		while ((port_hp = di_hp_next(dev, port_hp)) != DI_HP_NIL) {
+
+			/* Ignore irrelevant connections */
+			if (di_hp_depends_on(port_hp) != physnum)
+				continue;
+
+			/* Add new port node to port list */
+			if ((port_node = new_hotplug_node(node,
+			    port_hp)) == NULL) {
+				rv = ENOMEM;
+				goto fail;
+			}
+			node_list_add(&ports, port_node);
+
+			/* Add branch of child devices */
+			if ((child_dev = di_hp_child(port_hp)) != DI_NODE_NIL) {
+				if ((rv = copy_devices(port_node, child_dev,
+				    child_flags, &port_node->hp_child)) != 0)
+					goto fail;
+			}
+		}
+		node->hp_child = ports.head;
+		(void) memset(&ports, 0, sizeof (hp_node_list_t));
+	}
+
+	if (connections.head == NULL)
+		return (ENXIO);
+	*retp = connections.head;
+	return (0);
+
+fail:
+	(void) hp_fini(ports.head);
+	(void) hp_fini(connections.head);
+	return (rv);
+}
+
+/*
+ * base_path()
+ *
+ *	Normalize the base path of a hotplug information snapshot.
+ *	The caller must free the string that is allocated.
+ */
+static char *
+base_path(const char *path)
+{
+	char	*base_path;
+	size_t	devices_len;
+
+	devices_len = strlen(S_DEVICES);
+
+	if (strncmp(path, S_DEVICES, devices_len) == 0)
+		base_path = strdup(&path[devices_len]);
+	else
+		base_path = strdup(path);
+
+	return (base_path);
+}
+
+/*
+ * search_cb()
+ *
+ *	Callback function used by di_walk_node() to search for branches
+ *	of the libdevinfo snapshot that contain hotplug nodes.
+ */
+/*ARGSUSED*/
+static int
+search_cb(di_node_t node, void *arg)
+{
+	di_node_t	parent;
+	uint_t		flags;
+
+	(void) di_node_private_set(node, (void *)(uintptr_t)0);
+
+	if (di_hp_next(node, DI_HP_NIL) == DI_HP_NIL)
+		return (DI_WALK_CONTINUE);
+
+	for (parent = node; parent != DI_NODE_NIL;
+	    parent = di_parent_node(parent)) {
+		flags = (uint_t)(uintptr_t)di_node_private_get(parent);
+		flags |= HPINFOSEARCH;
+		(void) di_node_private_set(parent, (void *)(uintptr_t)flags);
+	}
+
+	return (DI_WALK_CONTINUE);
+}
+
+/*
+ * check_search()
+ *
+ *	Check if a device node was marked by an initial search pass.
+ */
+static int
+check_search(di_node_t dev, uint_t flags)
+{
+	uint_t	dev_flags;
+
+	if (flags & HPINFOSEARCH) {
+		dev_flags = (uint_t)(uintptr_t)di_node_private_get(dev);
+		if ((dev_flags & HPINFOSEARCH) == 0)
+			return (0);
+	}
+
+	return (1);
+}
+
+/*
+ * node_list_add()
+ *
+ *	Utility function to append one node to a list of hotplug nodes.
+ */
+static void
+node_list_add(hp_node_list_t *listp, hp_node_t node)
+{
+	if (listp->prev != NULL)
+		listp->prev->hp_sibling = node;
+	else
+		listp->head = node;
+
+	listp->prev = node;
+}
+
+/*
+ * new_device_node()
+ *
+ *	Build a new hotplug node based on a specified devinfo node.
+ */
+static hp_node_t
+new_device_node(hp_node_t parent, di_node_t dev)
+{
+	hp_node_t	node;
+	char		*node_name, *bus_addr;
+	char		name[MAXPATHLEN];
+
+	node = (hp_node_t)calloc(1, sizeof (struct hp_node));
+
+	if (node != NULL) {
+		node->hp_parent = parent;
+		node->hp_type = HP_NODE_DEVICE;
+
+		node_name = di_node_name(dev);
+		bus_addr = di_bus_addr(dev);
+		if (bus_addr && (strlen(bus_addr) > 0)) {
+			if (snprintf(name, sizeof (name), "%s@%s", node_name,
+			    bus_addr) >= sizeof (name)) {
+				log_err("Path too long for device node.\n");
+				free(node);
+				return (NULL);
+			}
+			node->hp_name = strdup(name);
+		} else
+			node->hp_name = strdup(node_name);
+	}
+
+	return (node);
+}
+
+/*
+ * new_hotplug_node()
+ *
+ *	Build a new hotplug node based on a specified devinfo hotplug node.
+ */
+static hp_node_t
+new_hotplug_node(hp_node_t parent, di_hp_t hp)
+{
+	hp_node_t	node;
+	char		*s;
+
+	node = (hp_node_t)calloc(1, sizeof (struct hp_node));
+
+	if (node != NULL) {
+		node->hp_parent = parent;
+		node->hp_state = di_hp_state(hp);
+		node->hp_last_change = di_hp_last_change(hp);
+		if ((s = di_hp_name(hp)) != NULL)
+			node->hp_name = strdup(s);
+		if ((s = di_hp_description(hp)) != NULL)
+			node->hp_description = strdup(s);
+		if (di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT)
+			node->hp_type = HP_NODE_PORT;
+		else
+			node->hp_type = HP_NODE_CONNECTOR;
+	}
+
+	return (node);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/hotplugd/hotplugd_rcm.c	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,703 @@
+/*
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <librcm.h>
+#include <libhotplug.h>
+#include <libhotplug_impl.h>
+#include <sys/sunddi.h>
+#include <sys/ddi_hp.h>
+#include "hotplugd_impl.h"
+
+/*
+ * Define structures for a path-to-usage lookup table.
+ */
+typedef struct info_entry {
+	char			*rsrc;
+	char			*usage;
+	struct info_entry	*next;
+} info_entry_t;
+
+typedef struct {
+	char		*path;
+	info_entry_t	*entries;
+} info_table_t;
+
+/*
+ * Define callback argument used when getting resources.
+ */
+typedef struct {
+	int	error;
+	int	n_rsrcs;
+	char	**rsrcs;
+	char	path[MAXPATHLEN];
+	char	connection[MAXPATHLEN];
+	char	dev_path[MAXPATHLEN];
+} resource_cb_arg_t;
+
+/*
+ * Define callback argument used when merging info.
+ */
+typedef struct {
+	int		error;
+	info_table_t	*table;
+	size_t		table_len;
+	char		path[MAXPATHLEN];
+	char		connection[MAXPATHLEN];
+} merge_cb_arg_t;
+
+/*
+ * Local functions.
+ */
+static int	merge_rcm_info(hp_node_t root, rcm_info_t *info);
+static int	get_rcm_usage(char **rsrcs, rcm_info_t **info_p);
+static int	build_table(rcm_info_t *info, info_table_t **tablep,
+		    size_t *table_lenp);
+static void	free_table(info_table_t *table, size_t table_len);
+static int	resource_callback(hp_node_t node, void *argp);
+static int	merge_callback(hp_node_t node, void *argp);
+static int	rsrc2path(const char *rsrc, char *path);
+static int	compare_info(const void *a, const void *b);
+
+/*
+ * copy_usage()
+ *
+ *	Given an information snapshot, get the corresponding
+ *	RCM usage information and merge it into the snapshot.
+ */
+int
+copy_usage(hp_node_t root)
+{
+	rcm_info_t	*info = NULL;
+	char		**rsrcs = NULL;
+	int		rv;
+
+	/* Get resource names */
+	if ((rv = rcm_resources(root, &rsrcs)) != 0) {
+		log_err("Cannot get RCM resources (%s)\n", strerror(rv));
+		return (rv);
+	}
+
+	/* Do nothing if no resources */
+	if (rsrcs == NULL)
+		return (0);
+
+	/* Get RCM usage information */
+	if ((rv = get_rcm_usage(rsrcs, &info)) != 0) {
+		log_err("Cannot get RCM information (%s)\n", strerror(rv));
+		free_rcm_resources(rsrcs);
+		return (rv);
+	}
+
+	/* Done with resource names */
+	free_rcm_resources(rsrcs);
+
+	/* If there is RCM usage information, merge it in */
+	if (info != NULL) {
+		rv = merge_rcm_info(root, info);
+		rcm_free_info(info);
+		return (rv);
+	}
+
+	return (0);
+}
+
+/*
+ * rcm_resources()
+ *
+ *	Given the root of a hotplug information snapshot,
+ *	construct a list of RCM compatible resource names.
+ */
+int
+rcm_resources(hp_node_t root, char ***rsrcsp)
+{
+	resource_cb_arg_t	arg;
+
+	/* Initialize results */
+	*rsrcsp = NULL;
+
+	/* Traverse snapshot to get resources */
+	(void) memset(&arg, 0, sizeof (resource_cb_arg_t));
+	(void) hp_traverse(root, &arg, resource_callback);
+
+	/* Check for errors */
+	if (arg.error != 0) {
+		free_rcm_resources(arg.rsrcs);
+		return (arg.error);
+	}
+
+	/* Success */
+	*rsrcsp = arg.rsrcs;
+	return (0);
+}
+
+/*
+ * free_rcm_resources()
+ *
+ *	Free a table of RCM resource names.
+ */
+void
+free_rcm_resources(char **rsrcs)
+{
+	int	i;
+
+	if (rsrcs != NULL) {
+		for (i = 0; rsrcs[i] != NULL; i++)
+			free(rsrcs[i]);
+		free(rsrcs);
+	}
+}
+
+/*
+ * rcm_offline()
+ *
+ *	Implement an RCM offline request.
+ *
+ *	NOTE: errors from RCM will be merged into the snapshot.
+ */
+int
+rcm_offline(char **rsrcs, uint_t flags, hp_node_t root)
+{
+	rcm_handle_t	*handle;
+	rcm_info_t	*info = NULL;
+	uint_t		rcm_flags = 0;
+	int		rv = 0;
+
+	dprintf("rcm_offline()\n");
+
+	/* Set flags */
+	if (flags & HPFORCE)
+		rcm_flags |= RCM_FORCE;
+	if (flags & HPQUERY)
+		rcm_flags |= RCM_QUERY;
+
+	/* Allocate RCM handle */
+	if (rcm_alloc_handle(NULL, 0, NULL, &handle) != RCM_SUCCESS) {
+		log_err("Cannot allocate RCM handle (%s)\n", strerror(errno));
+		return (EFAULT);
+	}
+
+	/* Request RCM offline */
+	if (rcm_request_offline_list(handle, rsrcs, rcm_flags,
+	    &info) != RCM_SUCCESS)
+		rv = EBUSY;
+
+	/* RCM handle is no longer needed */
+	(void) rcm_free_handle(handle);
+
+	/*
+	 * Check if RCM returned any information tuples.  If so,
+	 * then also check if the RCM operation failed, and possibly
+	 * merge the RCM info into the caller's hotplug snapshot.
+	 */
+	if (info != NULL) {
+		if (rv != 0)
+			(void) merge_rcm_info(root, info);
+		rcm_free_info(info);
+	}
+
+	return (rv);
+}
+
+/*
+ * rcm_online()
+ *
+ *	Implement an RCM online notification.
+ */
+void
+rcm_online(char **rsrcs)
+{
+	rcm_handle_t	*handle;
+	rcm_info_t	*info = NULL;
+
+	dprintf("rcm_online()\n");
+
+	if (rcm_alloc_handle(NULL, 0, NULL, &handle) != RCM_SUCCESS) {
+		log_err("Cannot allocate RCM handle (%s)\n", strerror(errno));
+		return;
+	}
+
+	(void) rcm_notify_online_list(handle, rsrcs, 0, &info);
+
+	(void) rcm_free_handle(handle);
+
+	if (info != NULL)
+		rcm_free_info(info);
+}
+
+/*
+ * rcm_remove()
+ *
+ *	Implement an RCM remove notification.
+ */
+void
+rcm_remove(char **rsrcs)
+{
+	rcm_handle_t	*handle;
+	rcm_info_t	*info = NULL;
+
+	dprintf("rcm_remove()\n");
+
+	if (rcm_alloc_handle(NULL, 0, NULL, &handle) != RCM_SUCCESS) {
+		log_err("Cannot allocate RCM handle (%s)\n", strerror(errno));
+		return;
+	}
+
+	(void) rcm_notify_remove_list(handle, rsrcs, 0, &info);
+
+	(void) rcm_free_handle(handle);
+
+	if (info != NULL)
+		rcm_free_info(info);
+}
+
+/*
+ * get_rcm_usage()
+ *
+ *	Lookup usage information for a set of resources from RCM.
+ */
+static int
+get_rcm_usage(char **rsrcs, rcm_info_t **info_p)
+{
+	rcm_handle_t	*handle;
+	rcm_info_t	*info = NULL;
+	int		rv = 0;
+
+	/* No-op if no RCM resources */
+	if (rsrcs == NULL)
+		return (0);
+
+	/* Allocate RCM handle */
+	if (rcm_alloc_handle(NULL, RCM_NOPID, NULL, &handle) != RCM_SUCCESS) {
+		log_err("Cannot allocate RCM handle (%s)\n", strerror(errno));
+		return (EFAULT);
+	}
+
+	/* Get usage information from RCM */
+	if (rcm_get_info_list(handle, rsrcs,
+	    RCM_INCLUDE_DEPENDENT | RCM_INCLUDE_SUBTREE,
+	    &info) != RCM_SUCCESS) {
+		log_err("Failed to get RCM information (%s)\n",
+		    strerror(errno));
+		rv = EFAULT;
+	}
+
+	/* RCM handle is no longer needed */
+	(void) rcm_free_handle(handle);
+
+	*info_p = info;
+	return (rv);
+}
+
+/*
+ * merge_rcm_info()
+ *
+ *	Merge RCM information into a hotplug information snapshot.
+ *	First a lookup table is built to map lists of RCM usage to
+ *	pathnames.  Then during a full traversal of the snapshot,
+ *	the lookup table is used for each node to find matching
+ *	RCM info tuples for each path in the snapshot.
+ */
+static int
+merge_rcm_info(hp_node_t root, rcm_info_t *info)
+{
+	merge_cb_arg_t		arg;
+	info_table_t		*table;
+	size_t			table_len;
+	int			rv;
+
+	/* Build a lookup table, mapping paths to usage information */
+	if ((rv = build_table(info, &table, &table_len)) != 0) {
+		log_err("Cannot build RCM lookup table (%s)\n", strerror(rv));
+		return (rv);
+	}
+
+	/* Stop if no valid entries were inserted in table */
+	if ((table == NULL) || (table_len == 0)) {
+		log_err("Unable to gather RCM usage.\n");
+		return (0);
+	}
+
+	/* Initialize callback argument */
+	(void) memset(&arg, 0, sizeof (merge_cb_arg_t));
+	arg.table = table;
+	arg.table_len = table_len;
+
+	/* Perform a merge traversal */
+	(void) hp_traverse(root, (void *)&arg, merge_callback);
+
+	/* Done with the table */
+	free_table(table, table_len);
+
+	/* Check for errors */
+	if (arg.error != 0) {
+		log_err("Cannot merge RCM information (%s)\n", strerror(rv));
+		return (rv);
+	}
+
+	return (0);
+}
+
+/*
+ * resource_callback()
+ *
+ *	A callback function for hp_traverse() that builds an RCM
+ *	compatible list of resource path names.  The array has
+ *	been pre-allocated based on results from the related
+ *	callback resource_count_callback().
+ */
+static int
+resource_callback(hp_node_t node, void *argp)
+{
+	resource_cb_arg_t	*arg = (resource_cb_arg_t *)argp;
+	char			**new_rsrcs;
+	size_t			new_size;
+	int			type;
+
+	/* Get node type */
+	type = hp_type(node);
+
+	/* Prune OFFLINE ports */
+	if ((type == HP_NODE_PORT) && HP_IS_OFFLINE(hp_state(node)))
+		return (HP_WALK_PRUNECHILD);
+
+	/* Skip past non-devices */
+	if (type != HP_NODE_DEVICE)
+		return (HP_WALK_CONTINUE);
+
+	/* Lookup resource path */
+	if (hp_path(node, arg->path, arg->connection) != 0) {
+		log_err("Cannot get RCM resource path.\n");
+		arg->error = EFAULT;
+		return (HP_WALK_TERMINATE);
+	}
+
+	/* Insert "/devices" to path name */
+	(void) snprintf(arg->dev_path, MAXPATHLEN, "/devices%s", arg->path);
+
+	/*
+	 * Grow resource array to accomodate new /devices path.
+	 * NOTE: include an extra NULL pointer at end of array.
+	 */
+	new_size = (arg->n_rsrcs + 2) * sizeof (char *);
+	if (arg->rsrcs == NULL)
+		new_rsrcs = (char **)malloc(new_size);
+	else
+		new_rsrcs = (char **)realloc(arg->rsrcs, new_size);
+	if (new_rsrcs != NULL) {
+		arg->rsrcs = new_rsrcs;
+	} else {
+		log_err("Cannot allocate RCM resource array.\n");
+		arg->error = ENOMEM;
+		return (HP_WALK_TERMINATE);
+	}
+
+	/* Initialize new entries */
+	arg->rsrcs[arg->n_rsrcs] = strdup(arg->dev_path);
+	arg->rsrcs[arg->n_rsrcs + 1] = NULL;
+
+	/* Check for errors */
+	if (arg->rsrcs[arg->n_rsrcs] == NULL) {
+		log_err("Cannot allocate RCM resource path.\n");
+		arg->error = ENOMEM;
+		return (HP_WALK_TERMINATE);
+	}
+
+	/* Increment resource count */
+	arg->n_rsrcs += 1;
+
+	/* Do not visit children */
+	return (HP_WALK_PRUNECHILD);
+}
+
+/*
+ * merge_callback()
+ *
+ *	A callback function for hp_traverse() that merges RCM information
+ *	tuples into an existing hotplug information snapshot.  The RCM
+ *	information will be turned into HP_NODE_USAGE nodes.
+ */
+static int
+merge_callback(hp_node_t node, void *argp)
+{
+	merge_cb_arg_t	*arg = (merge_cb_arg_t *)argp;
+	hp_node_t	usage;
+	info_table_t	lookup;
+	info_table_t	*slot;
+	info_entry_t	*entry;
+	int		rv;
+
+	/* Only process device nodes (other nodes cannot have usage) */
+	if (hp_type(node) != HP_NODE_DEVICE)
+		return (HP_WALK_CONTINUE);
+
+	/* Get path of current node, using buffer provided in 'arg' */
+	if ((rv = hp_path(node, arg->path, arg->connection)) != 0) {
+		log_err("Cannot lookup hotplug path (%s)\n", strerror(rv));
+		arg->error = rv;
+		return (HP_WALK_TERMINATE);
+	}
+
+	/* Check the lookup table for associated usage */
+	lookup.path = arg->path;
+	if ((slot = bsearch(&lookup, arg->table, arg->table_len,
+	    sizeof (info_table_t), compare_info)) == NULL)
+		return (HP_WALK_CONTINUE);
+
+	/* Usage information was found.  Append HP_NODE_USAGE nodes. */
+	for (entry = slot->entries; entry != NULL; entry = entry->next) {
+
+		/* Allocate a new usage node */
+		usage = (hp_node_t)calloc(1, sizeof (struct hp_node));
+		if (usage == NULL) {
+			log_err("Cannot allocate hotplug usage node.\n");
+			arg->error = ENOMEM;
+			return (HP_WALK_TERMINATE);
+		}
+
+		/* Initialize the usage node's contents */
+		usage->hp_type = HP_NODE_USAGE;
+		if ((usage->hp_name = strdup(entry->rsrc)) == NULL) {
+			log_err("Cannot allocate hotplug usage node name.\n");
+			free(usage);
+			arg->error = ENOMEM;
+			return (HP_WALK_TERMINATE);
+		}
+		if ((usage->hp_usage = strdup(entry->usage)) == NULL) {
+			log_err("Cannot allocate hotplug usage node info.\n");
+			free(usage->hp_name);
+			free(usage);
+			arg->error = ENOMEM;
+			return (HP_WALK_TERMINATE);
+		}
+
+		/* Link the usage node as a child of the device node */
+		usage->hp_parent = node;
+		usage->hp_sibling = node->hp_child;
+		node->hp_child = usage;
+	}
+
+	return (HP_WALK_CONTINUE);
+}
+
+/*
+ * build_table()
+ *
+ *	Build a lookup table that will be used to map paths to their
+ *	corresponding RCM information tuples.
+ */
+static int
+build_table(rcm_info_t *info, info_table_t **tablep, size_t *table_lenp)
+{
+	rcm_info_tuple_t	*tuple;
+	info_entry_t		*entry;
+	info_table_t		*slot;
+	info_table_t		*table;
+	size_t			table_len;
+	const char		*rsrc;
+	const char		*usage;
+	char			path[MAXPATHLEN];
+
+	/* Initialize results */
+	*tablep = NULL;
+	*table_lenp = 0;
+
+	/* Count the RCM info tuples to determine the table's size */
+	table_len = 0;
+	for (tuple = NULL; (tuple = rcm_info_next(info, tuple)) != NULL; )
+		table_len++;
+
+	/* If the table would be empty, then do nothing */
+	if (table_len == 0)
+		return (ENOENT);
+
+	/* Allocate the lookup table */
+	table = (info_table_t *)calloc(table_len, sizeof (info_table_t));
+	if (table == NULL)
+		return (ENOMEM);
+
+	/*
+	 * Fill in the lookup table.  Fill one slot in the table
+	 * for each device path that has a set of associated RCM
+	 * information tuples.  In some cases multiple tuples will
+	 * be joined together within the same slot.
+	 */
+	slot = NULL;
+	table_len = 0;
+	for (tuple = NULL; (tuple = rcm_info_next(info, tuple)) != NULL; ) {
+
+		/*
+		 * Extract RCM resource name and usage description.
+		 *
+		 * NOTE: skip invalid tuples to return as much as possible.
+		 */
+		if (((rsrc = rcm_info_rsrc(tuple)) == NULL) ||
+		    ((usage = rcm_info_info(tuple)) == NULL)) {
+			log_err("RCM returned invalid resource or usage.\n");
+			continue;
+		}
+
+		/*
+		 * Try to convert the RCM resource name to a hotplug path.
+		 * If conversion succeeds and this path differs from the
+		 * current slot in the table, then initialize the next
+		 * slot in the table.
+		 */
+		if ((rsrc2path(rsrc, path) == 0) &&
+		    ((slot == NULL) || (strcmp(slot->path, path) != 0))) {
+			slot = &table[table_len];
+			if ((slot->path = strdup(path)) == NULL) {
+				log_err("Cannot build info table slot.\n");
+				free_table(table, table_len);
+				return (ENOMEM);
+			}
+			table_len++;
+		}
+
+		/* Append current usage to entry list in the current slot */
+		if (slot != NULL) {
+
+			/* Allocate new entry */
+			entry = (info_entry_t *)malloc(sizeof (info_entry_t));
+			if (entry == NULL) {
+				log_err("Cannot allocate info table entry.\n");
+				free_table(table, table_len);
+				return (ENOMEM);
+			}
+
+			/* Link entry into current slot list */
+			entry->next = slot->entries;
+			slot->entries = entry;
+
+			/* Initialize entry values */
+			if (((entry->rsrc = strdup(rsrc)) == NULL) ||
+			    ((entry->usage = strdup(usage)) == NULL)) {
+				log_err("Cannot build info table entry.\n");
+				free_table(table, table_len);
+				return (ENOMEM);
+			}
+		}
+	}
+
+	/* Check if valid entries were inserted in table */
+	if (table_len == 0) {
+		free(table);
+		return (0);
+	}
+
+	/* Sort the lookup table by hotplug path */
+	qsort(table, table_len, sizeof (info_table_t), compare_info);
+
+	/* Done */
+	*tablep = table;
+	*table_lenp = table_len;
+	return (0);
+}
+
+/*
+ * free_table()
+ *
+ *	Destroy a lookup table.
+ */
+static void
+free_table(info_table_t *table, size_t table_len)
+{
+	info_entry_t	*entry;
+	int		index;
+
+	if (table != NULL) {
+		for (index = 0; index < table_len; index++) {
+			if (table[index].path != NULL)
+				free(table[index].path);
+			while (table[index].entries != NULL) {
+				entry = table[index].entries;
+				table[index].entries = entry->next;
+				if (entry->rsrc != NULL)
+					free(entry->rsrc);
+				if (entry->usage != NULL)
+					free(entry->usage);
+				free(entry);
+			}
+		}
+		free(table);
+	}
+}
+
+/*
+ * rsrc2path()
+ *
+ *	Convert from an RCM resource name to a hotplug device path.
+ */
+static int
+rsrc2path(const char *rsrc, char *path)
+{
+	char	*s;
+	char	tmp[MAXPATHLEN];
+
+	/* Only convert /dev and /devices paths */
+	if (strncmp(rsrc, "/dev", 4) == 0) {
+
+		/* Follow symbolic links for /dev paths */
+		if (realpath(rsrc, tmp) == NULL) {
+			log_err("Cannot resolve RCM resource (%s)\n",
+			    strerror(errno));
+			return (-1);
+		}
+
+		/* Remove the leading "/devices" part */
+		(void) strlcpy(path, &tmp[strlen(S_DEVICES)], MAXPATHLEN);
+
+		/* Remove any trailing minor node part */
+		if ((s = strrchr(path, ':')) != NULL)
+			*s = '\0';
+
+		/* Successfully converted */
+		return (0);
+	}
+
+	/* Not converted */
+	return (-1);
+}
+
+/*
+ * compare_info()
+ *
+ *	Compare two slots in the lookup table that maps paths to usage.
+ *
+ *	NOTE: for use with qsort() and bsearch().
+ */
+static int
+compare_info(const void *a, const void *b)
+{
+	info_table_t	*slot_a = (info_table_t *)a;
+	info_table_t	*slot_b = (info_table_t *)b;
+
+	return (strcmp(slot_a->path, slot_b->path));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/hotplugd/svc-hotplug	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,54 @@
+#!/sbin/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.
+#
+
+#
+# Startup script for the hotplugd(1M) daemon.
+#
+
+. /lib/svc/share/smf_include.sh
+
+HOTPLUGD_DOOR=/var/run/hotplugd_door
+
+# The hotplug service is only supported in the global zone.
+if smf_is_nonglobalzone; then
+	/usr/sbin/svcadm disable $SMF_FMRI
+	echo "$SMF_FMRI is not supported in a local zone"
+	sleep 5 &
+	exit $SMF_EXIT_OK
+fi
+
+# If a hotplug door exists, check for a hotplugd process and exit
+# if the daemon is already running.
+if [ -f $HOTPLUGD_DOOR ]; then
+	if /usr/bin/pgrep -x -u 0 hotplugd >/dev/null 2>&1; then
+		echo "$0: hotplugd is already running"
+		exit 1
+	fi
+fi
+
+rm -f $HOTPLUGD_DOOR
+exec /usr/lib/hotplugd
--- a/usr/src/cmd/mdb/common/modules/genunix/Makefile.files	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/cmd/mdb/common/modules/genunix/Makefile.files	Mon Nov 02 15:58:28 2009 +0800
@@ -44,6 +44,7 @@
 	fm.c		\
 	genunix.c	\
 	group.c		\
+	hotplug.c	\
 	irm.c		\
 	kgrep.c		\
 	kmem.c		\
--- a/usr/src/cmd/mdb/common/modules/genunix/devinfo.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/cmd/mdb/common/modules/genunix/devinfo.c	Mon Nov 02 15:58:28 2009 +0800
@@ -41,21 +41,12 @@
 #include <mdb/mdb_ks.h>
 
 #include "nvpair.h"
+#include "devinfo.h"
 
 #define	DEVINFO_TREE_INDENT	4	/* Indent for devs one down in tree */
 #define	DEVINFO_PROP_INDENT	4	/* Indent for properties */
 #define	DEVINFO_PROPLIST_INDENT	8	/* Indent for properties lists */
 
-
-/*
- * Options for prtconf/devinfo dcmd.
- */
-#define	DEVINFO_VERBOSE	0x1
-#define	DEVINFO_PARENT	0x2
-#define	DEVINFO_CHILD	0x4
-#define	DEVINFO_ALLBOLD	0x8
-#define	DEVINFO_SUMMARY	0x10
-
 /*
  * devinfo node state map. Used by devinfo() and devinfo_audit().
  * Long words are deliberately truncated so that output
@@ -954,11 +945,6 @@
 	mdb_dec_indent(DEVINFO_PROP_INDENT);
 }
 
-typedef struct devinfo_cb_data {
-	uintptr_t	di_base;
-	uint_t		di_flags;
-} devinfo_cb_data_t;
-
 static int
 devinfo_print(uintptr_t addr, struct dev_info *dev, devinfo_cb_data_t *data)
 {
--- a/usr/src/cmd/mdb/common/modules/genunix/devinfo.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/cmd/mdb/common/modules/genunix/devinfo.h	Mon Nov 02 15:58:28 2009 +0800
@@ -20,21 +20,34 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_DEVINFO_H
 #define	_DEVINFO_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
 #include <mdb/mdb_modapi.h>
 
+/*
+ * Options for prtconf/devinfo/hotplug dcmd.
+ */
+#define	DEVINFO_VERBOSE		0x1
+#define	DEVINFO_PARENT		0x2
+#define	DEVINFO_CHILD		0x4
+#define	DEVINFO_ALLBOLD		0x8
+#define	DEVINFO_SUMMARY		0x10
+#define	DEVINFO_HP_PHYSICAL	0x20
+
+typedef struct devinfo_cb_data {
+	uintptr_t	di_base;
+	uint_t		di_flags;
+} devinfo_cb_data_t;
+
 extern int devinfo_walk_init(mdb_walk_state_t *);
 extern int devinfo_walk_step(mdb_walk_state_t *);
 extern void devinfo_walk_fini(mdb_walk_state_t *);
--- a/usr/src/cmd/mdb/common/modules/genunix/genunix.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/cmd/mdb/common/modules/genunix/genunix.c	Mon Nov 02 15:58:28 2009 +0800
@@ -106,6 +106,7 @@
 #include "typegraph.h"
 #include "vfs.h"
 #include "zone.h"
+#include "hotplug.h"
 
 /*
  * Surely this is defined somewhere...
@@ -4503,6 +4504,10 @@
 	{ "zsd", ":[-v] [zsd_key]", "display zone-specific-data entries for "
 	    "selected zones", zsd },
 
+	/* from hotplug.c */
+	{ "hotplug", "?[-p]", "display a registered hotplug attachment",
+	    hotplug, hotplug_help },
+
 	{ NULL }
 };
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/common/modules/genunix/hotplug.c	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,164 @@
+/*
+ * 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 <sys/proc.h>
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#include <sys/ddi_hp.h>
+#include "devinfo.h"
+
+static char *
+ddihp_get_cn_state(ddi_hp_cn_state_t state)
+{
+	switch (state) {
+	case DDI_HP_CN_STATE_EMPTY:
+		return ("Empty");
+	case DDI_HP_CN_STATE_PRESENT:
+		return ("Present");
+	case DDI_HP_CN_STATE_POWERED:
+		return ("Powered");
+	case DDI_HP_CN_STATE_ENABLED:
+		return ("Enabled");
+	case DDI_HP_CN_STATE_PORT_EMPTY:
+		return ("Port_Empty");
+	case DDI_HP_CN_STATE_PORT_PRESENT:
+		return ("Port_Present");
+	case DDI_HP_CN_STATE_OFFLINE:
+		return ("Offline");
+	case DDI_HP_CN_STATE_ATTACHED:
+		return ("Attached");
+	case DDI_HP_CN_STATE_MAINTENANCE:
+		return ("Maintenance");
+	case DDI_HP_CN_STATE_ONLINE:
+		return ("Online");
+	default:
+		return ("Unknown");
+	}
+}
+
+/*ARGSUSED*/
+static int
+hotplug_print(uintptr_t addr, struct dev_info *dev, devinfo_cb_data_t *data)
+{
+	ddi_hp_cn_handle_t	hdl;
+	uintptr_t		hdlp = (uintptr_t)dev->devi_hp_hdlp;
+	char			cn_type[15];
+	char			cn_name[15];
+
+	while (hdlp) {
+		if (mdb_vread(&hdl, sizeof (ddi_hp_cn_handle_t), hdlp) == -1) {
+			mdb_warn("Failed to read hdlp!\n");
+			return (DCMD_ERR);
+		}
+
+		if (!(data->di_flags & DEVINFO_HP_PHYSICAL) ||
+		    hdl.cn_info.cn_type != DDI_HP_CN_TYPE_VIRTUAL_PORT) {
+			if (mdb_readstr(cn_type, sizeof (cn_type),
+			    (uintptr_t)hdl.cn_info.cn_type_str) == -1) {
+				mdb_warn("Failed to read cn_type!\n");
+				return (DCMD_ERR);
+			}
+			if (mdb_readstr(cn_name, sizeof (cn_name),
+			    (uintptr_t)hdl.cn_info.cn_name) == -1) {
+				mdb_warn("Failed to read cn_name!\n");
+				return (DCMD_ERR);
+			}
+			mdb_printf("%?p %?p %-12s %-15s %-15s\n", hdl.cn_dip,
+			    hdlp, ddihp_get_cn_state(hdl.cn_info.cn_state),
+			    cn_type, cn_name);
+		}
+		hdlp = (uintptr_t)hdl.next;
+	};
+
+	return (WALK_NEXT);
+}
+
+void
+hotplug_help(void)
+{
+	mdb_printf("Switches:\n"
+	    "  -p   only print the physical hotplug connectors\n");
+}
+
+int
+hotplug(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+	devinfo_cb_data_t data;
+	uintptr_t devinfo_root;		/* Address of root of devinfo tree */
+	ddi_hp_cn_handle_t	hdl;
+	char			cn_type[15];
+	char			cn_name[15];
+	int status;
+
+	data.di_flags = 0;
+	if (mdb_getopts(argc, argv,
+	    'p', MDB_OPT_SETBITS, DEVINFO_HP_PHYSICAL, &data.di_flags, NULL)
+	    != argc)
+		return (DCMD_USAGE);
+
+	if (DCMD_HDRSPEC(flags)) {
+		mdb_printf("%<u>%?s %?s %-12s %-15s %-15s%</u>\n",
+		    "PARENT_DEVINFO", "HANDLE", "STATE", "TYPE", "CN_NAME");
+	}
+
+	if ((flags & DCMD_ADDRSPEC) == 0) {
+		data.di_flags |= DEVINFO_PARENT | DEVINFO_CHILD;
+
+		if (mdb_readvar(&devinfo_root, "top_devinfo") == -1) {
+			mdb_warn("failed to read 'top_devinfo'");
+			return (NULL);
+		}
+
+		data.di_base = devinfo_root;
+		status = mdb_pwalk("devinfo", (mdb_walk_cb_t)hotplug_print,
+		    &data, devinfo_root);
+		if (status == -1) {
+			mdb_warn("couldn't walk devinfo tree");
+			return (DCMD_ERR);
+		}
+		return (DCMD_OK);
+	}
+
+	if (mdb_vread(&hdl, sizeof (ddi_hp_cn_handle_t), (uintptr_t)addr)
+	    == -1) {
+		mdb_warn("Failed to read hdlp!\n");
+		return (DCMD_ERR);
+	}
+	if (mdb_readstr(cn_type, sizeof (cn_type),
+	    (uintptr_t)hdl.cn_info.cn_type_str) == -1) {
+		mdb_warn("Failed to read cn_type!\n");
+		return (DCMD_ERR);
+	}
+	if (mdb_readstr(cn_name, sizeof (cn_name),
+	    (uintptr_t)hdl.cn_info.cn_name) == -1) {
+		mdb_warn("Failed to read cn_name!\n");
+		return (DCMD_ERR);
+	}
+	mdb_printf("%?p %?p %-12s %-15s %-15s\n", hdl.cn_dip, addr,
+	    ddihp_get_cn_state(hdl.cn_info.cn_state), cn_type, cn_name);
+
+	return (DCMD_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/common/modules/genunix/hotplug.h	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,41 @@
+/*
+ * 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	_HOTPLUG_H
+#define	_HOTPLUG_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+extern int hotplug(uintptr_t addr, uint_t flags, int argc,
+    const mdb_arg_t *argv);
+extern void hotplug_help(void);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _HOTPLUG_H */
--- a/usr/src/cmd/pcitool/pcitool.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/cmd/pcitool/pcitool.c	Mon Nov 02 15:58:28 2009 +0800
@@ -136,6 +136,7 @@
     pcitool_reg_t *info_p, boolean_t verbose);
 static int get_config_header(int fd, uint8_t bus_no, uint8_t dev_no,
     uint8_t func_no, pci_conf_hdr_t *config_hdr_p);
+static int supports_ari(int fd, uint8_t bus_no);
 static int probe_dev(int fd, pcitool_reg_t *prg_p,
     pcitool_uiargs_t *input_args_p);
 static int do_probe(int fd, di_node_t di_node, di_prom_handle_t di_phdl,
@@ -457,8 +458,102 @@
 		}
 		config_hdr_p->dwords[i] = (uint32_t)cfg_prg.data;
 	}
+	return (rval);
+}
 
-	return (rval);
+static int
+supports_ari(int fd, uint8_t bus_no)
+{
+	pcitool_reg_t cfg_prg;
+	int deadcount = 0;
+	uint32_t data, hdr_next_ptr, hdr_cap_id;
+	uint8_t dev_no = 0;
+	uint8_t func_no = 0;
+
+	/* Prepare a local pcitool_reg_t so as to not disturb the caller's. */
+	cfg_prg.bus_no = bus_no;
+	cfg_prg.dev_no = dev_no;
+	cfg_prg.func_no = func_no;
+	cfg_prg.barnum = 0;
+	cfg_prg.user_version = PCITOOL_VERSION;
+	cfg_prg.offset = PCI_CONF_COMM;
+	cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + PCITOOL_ACC_ATTR_ENDN_LTL;
+
+	if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) {
+		return (FAILURE);
+	}
+
+	data = (uint32_t)cfg_prg.data;
+
+	if (!((data >> 16) & PCI_STAT_CAP))
+		return (FAILURE);
+
+	cfg_prg.offset = PCI_CONF_CAP_PTR;
+	if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) {
+		return (FAILURE);
+	}
+	data = (uint32_t)cfg_prg.data;
+	hdr_next_ptr = data & 0xff;
+	hdr_cap_id = 0;
+
+	/*
+	 * Find the PCIe capability.
+	 */
+	while ((hdr_next_ptr != PCI_CAP_NEXT_PTR_NULL) &&
+	    (hdr_cap_id != PCI_CAP_ID_PCI_E)) {
+
+		if (hdr_next_ptr < 0x40)
+			break;
+
+		cfg_prg.offset = hdr_next_ptr;
+
+		if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS)
+			return (FAILURE);
+
+		data = (uint32_t)cfg_prg.data;
+
+		hdr_next_ptr = (data >> 8) & 0xFF;
+		hdr_cap_id = data & 0xFF;
+
+		if (deadcount++ > 100)
+			return (FAILURE);
+	}
+
+	if (hdr_cap_id != PCI_CAP_ID_PCI_E)
+		return (FAILURE);
+
+	/* Found a PCIe Capability */
+
+	hdr_next_ptr = 0x100;
+	hdr_cap_id = 0;
+
+	/*
+	 * Now find the ARI Capability.
+	 */
+	while ((hdr_next_ptr != PCI_CAP_NEXT_PTR_NULL) &&
+	    (hdr_cap_id != 0xe)) {
+
+		if (hdr_next_ptr < 0x40)
+			break;
+
+		cfg_prg.offset = hdr_next_ptr;
+
+		if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) {
+			return (FAILURE);
+		}
+		data = (uint32_t)cfg_prg.data;
+
+		hdr_next_ptr = (data >> 20) & 0xFFF;
+		hdr_cap_id = data & 0xFFFF;
+
+		if (deadcount++ > 100)
+			return (FAILURE);
+	}
+
+	if (hdr_cap_id != 0xe)
+		return (FAILURE);
+
+	return (SUCCESS);
 }
 
 /*
@@ -488,7 +583,7 @@
 probe_dev(int fd, pcitool_reg_t *prg_p, pcitool_uiargs_t *input_args_p)
 {
 	pci_conf_hdr_t	config_hdr;
-	boolean_t	multi_function_device;
+	boolean_t	multi_function_device = B_FALSE;
 	int		func;
 	int		first_func = 0;
 	int		last_func = PCI_REG_FUNC_M >> PCI_REG_FUNC_SHIFT;
@@ -496,6 +591,10 @@
 
 	if (input_args_p->flags & FUNC_SPEC_FLAG) {
 		first_func = last_func = input_args_p->function;
+	} else if (supports_ari(fd, prg_p->bus_no) == SUCCESS) {
+		multi_function_device = B_TRUE;
+		if (!(input_args_p->flags & DEV_SPEC_FLAG))
+			last_func = 255;
 	}
 
 	/*
@@ -508,11 +607,14 @@
 	 * will force the loop as the user wants a specific function to be
 	 * checked.
 	 */
-	for (func = first_func, multi_function_device = B_FALSE;
-	    ((func <= last_func) &&
+	for (func = first_func;  ((func <= last_func) &&
 	    ((func == first_func) || (multi_function_device)));
 	    func++) {
-		prg_p->func_no = func;
+		if (last_func > 7) {
+			prg_p->func_no = func & 0x7;
+			prg_p->dev_no = (func >> 3) & 0x1f;
+		} else
+			prg_p->func_no = func;
 
 		/*
 		 * Four things can happen here:
@@ -587,8 +689,6 @@
 		 */
 		} else if (prg_p->data == 0) {
 			rval = SUCCESS;
-			break;	/* Func loop. */
-
 		/* Found something. */
 		} else {
 			config_hdr.dwords[0] = (uint32_t)prg_p->data;
@@ -718,6 +818,17 @@
 	 */
 	for (bus = first_bus; ((bus <= last_bus) && (rval == SUCCESS)); bus++) {
 		prg.bus_no = bus;
+
+		/* Device number explicitly specified. */
+		if (input_args_p->flags & DEV_SPEC_FLAG) {
+			first_dev = last_dev = input_args_p->device;
+		} else if (supports_ari(fd, bus) == SUCCESS) {
+			last_dev = 0;
+			first_dev = 0;
+		} else {
+			last_dev = PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT;
+		}
+
 		for (dev = first_dev;
 		    ((dev <= last_dev) && (rval == SUCCESS)); dev++) {
 			prg.dev_no = dev;
--- a/usr/src/cmd/truss/print.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/cmd/truss/print.c	Mon Nov 02 15:58:28 2009 +0800
@@ -1140,6 +1140,7 @@
 		case MODGETDEVFSPATH_MI:
 					s = "MODGETDEVFSPATH_MI"; break;
 		case MODREMDRVALIAS:	s = "MODREMDRVALIAS"; break;
+		case MODHPOPS:	s = "MODHPOPS"; break;
 		}
 	}
 
--- a/usr/src/head/auth_list.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/head/auth_list.h	Mon Nov 02 15:58:28 2009 +0800
@@ -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 is an internal header file. Not to be shipped.
@@ -48,6 +48,7 @@
 #define	SET_DATE_AUTH		"solaris.system.date"
 #define	WIFI_CONFIG_AUTH	"solaris.network.wifi.config"
 #define	WIFI_WEP_AUTH		"solaris.network.wifi.wep"
+#define	HP_MODIFY_AUTH		"solaris.hotplug.modify"
 
 /*
  * Authorizations used by Trusted Solaris.
--- a/usr/src/lib/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/lib/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -262,6 +262,7 @@
 	mpapi		\
 	librstp		\
 	libreparse	\
+	libhotplug	\
 	$($(MACH)_SUBDIRS)
 
 i386_SUBDIRS=		\
@@ -641,6 +642,8 @@
 libgrubmgmt:	libdevinfo libzfs libfstyp
 pyzfs:		libnvpair libsec libidmap libzfs
 libreparse:	libnvpair
+libhotplug:	libnvpair
+cfgadm_plugins:	libhotplug
 
 #
 # The reason this rule checks for the existence of the
--- a/usr/src/lib/cfgadm_plugins/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/lib/cfgadm_plugins/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -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.
 #
 # lib/cfgadm_plugins/Makefile
@@ -27,7 +27,7 @@
 
 include $(SRC)/Makefile.master
 
-COMMON_SUBDIRS= scsi sdcard pci usb ib fp
+COMMON_SUBDIRS= scsi sdcard pci usb ib fp shp
 sparc_SUBDIRS=	sbd ac sysctrl
 
 i386_SUBDIRS= sata
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/shp/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,70 @@
+#
+# 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.master
+
+SUBDIRS =	$(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all :=		TARGET= all
+clean :=	TARGET= clean
+clobber :=	TARGET= clobber
+delete :=	TARGET= delete
+install :=	TARGET= install
+lint :=		TARGET= lint
+_msg :=		TARGET= _msg
+package :=	TARGET= package
+
+TEXT_DOMAIN=	SUNW_OST_OSLIB
+XGETFLAGS=	-a -x shp.xcl
+POFILE=		shp.po
+POFILES=	generic.po
+
+SED=	sed
+GREP=	grep
+
+.KEEP_STATE:
+
+all clean clobber delete install lint package: $(SUBDIRS)
+
+$(SUBDIRS):	FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+_msg:	$(MSGDOMAIN) $(POFILE)
+	$(RM) $(MSGDOMAIN)/$(POFILE)
+	$(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE):	$(POFILES)
+	$(RM) $@
+	$(CAT) $(POFILES) > $@
+
+$(POFILES):
+	$(RM) messages.po
+	$(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext *.[ch]* */*.[ch]*`
+	$(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+	$(RM) messages.po
+
+FRC:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/shp/Makefile.com	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,86 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY= shp.a
+VERS= .1
+OBJECTS= shp.o pci_strings.o
+
+# include library definitions
+include ../../../Makefile.lib
+
+SRCDIR =	../common
+INS.dir.root.sys=       $(INS) -s -d -m $(DIRMODE) $@
+$(CH)INS.dir.root.sys=  $(INS) -s -d -m $(DIRMODE) -u root -g sys $@
+INS.dir.bin.bin=        $(INS) -s -d -m $(DIRMODE) $@
+$(CH)INS.dir.bin.bin=   $(INS) -s -d -m $(DIRMODE) -u bin -g bin $@
+
+USR_LIB_DIR		= $(ROOT)/usr/lib
+USR_LIB_DIR_CFGADM	= $(USR_LIB_DIR)/cfgadm
+USR_LIB_DIR_CFGADM_64	= $(USR_LIB_DIR_CFGADM)/$(MACH64)
+
+ROOTLIBDIR= $(USR_LIB_DIR_CFGADM)
+ROOTLIBDIR64= $(USR_LIB_DIR_CFGADM_64)
+
+SRCS=		../common/shp.c $(SRC)/common/pci/pci_strings.c
+
+LIBS = $(DYNLIB)
+
+CPPFLAGS +=     -I$(SRC)/lib/libhotplug/common
+CPPFLAGS +=	-D_POSIX_PTHREAD_SEMANTICS
+CFLAGS +=	$(CCVERBOSE)
+LDLIBS +=	-lc -ldevinfo -lhotplug
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint:   lintcheck
+
+# Create target directories
+$(USR_LIB_DIR):
+	-$(INS.dir.root.sys)
+
+$(USR_LIB_DIR_CFGADM): $(USR_LIB_DIR)
+	-$(INS.dir.bin.bin)
+
+$(USR_LIB_DIR_CFGADM_64): $(USR_LIB_DIR_CFGADM)
+	-$(INS.dir.bin.bin)
+
+$(USR_LIB_DIR_CFGADM)/%: % $(USR_LIB_DIR_CFGADM)
+	-$(INS.file)
+
+$(USR_LIB_DIR_CFGADM_64)/%: % $(USR_LIB_DIR_CFGADM_64)
+	-$(INS.file)
+
+# include library targets
+include ../../../Makefile.targ
+
+pics/shp.o: ../common/shp.c
+	$(COMPILE.c) -o $@ ../common/shp.c
+	$(POST_PROCESS_O)
+
+pics/pci_strings.o: $(SRC)/common/pci/pci_strings.c
+	$(COMPILE.c) -o $@ $(SRC)/common/pci/pci_strings.c
+	$(POST_PROCESS_O)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/shp/amd64/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+.KEEP_STATE:
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/shp/common/mapfile-vers	Mon Nov 02 15:58:28 2009 +0800
@@ -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.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING:  STOP NOW.  DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+#	usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+SUNWprivate_1.1 {
+    global:
+	cfga_change_state;
+	cfga_help;
+	cfga_list_ext;
+	cfga_private_func;
+	cfga_test;
+	cfga_version;
+    local:
+	*;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/shp/common/shp.c	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,1698 @@
+/*
+ * 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.
+ */
+
+/*
+ *	Plugin library for PCI Express and PCI (SHPC) hotplug controller
+ */
+
+#include <stddef.h>
+#include <locale.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <locale.h>
+#include <langinfo.h>
+#include <time.h>
+#include <sys/param.h>
+#include <stdarg.h>
+#include <libdevinfo.h>
+#include <libdevice.h>
+
+#define	CFGA_PLUGIN_LIB
+
+#include <config_admin.h>
+
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/dditypes.h>
+#include <sys/pci.h>
+#include <libintl.h>
+
+#include <dirent.h>
+#include <limits.h>
+#include <sys/mkdev.h>
+#include "../../../../uts/common/sys/hotplug/pci/pcie_hp.h"
+#include "../../../../common/pci/pci_strings.h"
+#include <libhotplug.h>
+
+extern const struct pci_class_strings_s class_pci[];
+extern int class_pci_items;
+
+#define	MSG_HOTPLUG_DISABLED \
+	"Error: hotplug service is probably not running, " \
+	"please use 'svcadm enable hotplug' to enable the service. " \
+	"See cfgadm_shp(1M) for more details."
+
+#define	DEVICES_DIR		"/devices"
+#define	SLASH			"/"
+#define	GET_DYN(a)	(strstr((a), CFGA_DYN_SEP))
+
+/*
+ * Set the version number
+ */
+int cfga_version = CFGA_HSL_V2;
+
+#ifdef	DEBUG
+#define	SHP_DBG	1
+#endif
+
+#if !defined(TEXT_DOMAIN)
+#define	TEXT_DOMAIN	"SYS_TEST"
+#endif
+
+/*
+ *	DEBUGING LEVEL
+ *
+ * 	External routines:  1 - 2
+ *	Internal routines:  3 - 4
+ */
+#ifdef	SHP_DBG
+int	shp_debug = 1;
+#define	DBG(level, args) \
+	{ if (shp_debug >= (level)) printf args; }
+#define	DBG_F(level, args) \
+	{ if (shp_debug >= (level)) fprintf args; }
+#else
+#define	DBG(level, args)	/* nothing */
+#define	DBG_F(level, args)	/* nothing */
+#endif
+
+#define	CMD_ACQUIRE		0
+#define	CMD_GETSTAT		1
+#define	CMD_LIST		2
+#define	CMD_SLOT_CONNECT	3
+#define	CMD_SLOT_DISCONNECT	4
+#define	CMD_SLOT_CONFIGURE	5
+#define	CMD_SLOT_UNCONFIGURE	6
+#define	CMD_SLOT_INSERT		7
+#define	CMD_SLOT_REMOVE		8
+#define	CMD_OPEN		9
+#define	CMD_FSTAT		10
+#define	ERR_CMD_INVAL		11
+#define	ERR_AP_INVAL		12
+#define	ERR_AP_ERR		13
+#define	ERR_OPT_INVAL		14
+
+static char *
+cfga_errstrs[] = {
+	/* n */ "acquire ",
+	/* n */ "get-status ",
+	/* n */ "list ",
+	/* n */ "connect ",
+	/* n */ "disconnect ",
+	/* n */ "configure ",
+	/* n */ "unconfigure ",
+	/* n */ "insert ",
+	/* n */ "remove ",
+	/* n */ "open ",
+	/* n */ "fstat ",
+	/* y */ "invalid command ",
+	/* y */ "invalid attachment point ",
+	/* y */ "invalid transition ",
+	/* y */ "invalid option ",
+		NULL
+};
+
+#define	HELP_HEADER		1
+#define	HELP_CONFIG		2
+#define	HELP_ENABLE_SLOT	3
+#define	HELP_DISABLE_SLOT	4
+#define	HELP_ENABLE_AUTOCONF	5
+#define	HELP_DISABLE_AUTOCONF	6
+#define	HELP_LED_CNTRL		7
+#define	HELP_UNKNOWN		8
+#define	SUCCESS			9
+#define	FAILED			10
+#define	UNKNOWN			11
+
+#define	MAXLINE			256
+
+extern int errno;
+
+static void cfga_err(char **errstring, ...);
+static cfga_err_t fix_ap_name(char *ap_log_id, const char *ap_id,
+    char *slot_name, char **errstring);
+static cfga_err_t check_options(const char *options);
+static void cfga_msg(struct cfga_msg *msgp, const char *str);
+static char *findlink(char *ap_phys_id);
+
+static char *
+cfga_strs[] = {
+NULL,
+"\nPCI hotplug specific commands:",
+"\t-c [connect|disconnect|configure|unconfigure|insert|remove] "
+"ap_id [ap_id...]",
+"\t-x enable_slot  ap_id [ap_id...]",
+"\t-x disable_slot ap_id [ap_id...]",
+"\t-x enable_autoconfig  ap_id [ap_id...]",
+"\t-x disable_autoconfig ap_id [ap_id...]",
+"\t-x led[=[fault|power|active|attn],mode=[on|off|blink]] ap_id [ap_id...]",
+"\tunknown command or option: ",
+"success   ",
+"failed   ",
+"unknown",
+NULL
+};
+
+#define	MAX_FORMAT 80
+
+#define	ENABLE_SLOT	0
+#define	DISABLE_SLOT	1
+#define	ENABLE_AUTOCNF	2
+#define	DISABLE_AUTOCNF	3
+#define	LED		4
+#define	MODE		5
+
+typedef	enum { PCIEHPC_FAULT_LED, PCIEHPC_POWER_LED, PCIEHPC_ATTN_LED,
+	PCIEHPC_ACTIVE_LED} pciehpc_led_t;
+
+typedef	enum { PCIEHPC_BOARD_UNKNOWN, PCIEHPC_BOARD_PCI_HOTPLUG }
+	pciehpc_board_type_t;
+
+/*
+ * Board Type
+ */
+static char *
+board_strs[] = {
+	/* n */ "???",	/* PCIEHPC_BOARD_UNKNOWN */
+	/* n */ "hp",	/* PCIEHPC_BOARD_PCI_HOTPLUG */
+	/* n */ NULL
+};
+
+/*
+ * HW functions
+ */
+static char *
+func_strs[] = {
+	/* n */ "enable_slot",
+	/* n */ "disable_slot",
+	/* n */ "enable_autoconfig",
+	/* n */ "disable_autoconfig",
+	/* n */ "led",
+	/* n */ "mode",
+	/* n */ NULL
+};
+
+/*
+ * LED strings
+ */
+static char *
+led_strs[] = {
+	/* n */ "fault",	/* PCIEHPC_FAULT_LED */
+	/* n */ "power",	/* PCIEHPC_POWER_LED */
+	/* n */ "attn",		/* PCIEHPC_ATTN_LED */
+	/* n */ "active",	/* PCIEHPC_ACTIVE_LED */
+	/* n */ NULL
+};
+
+static char *
+led_strs2[] = {
+	/* n */ PCIEHPC_PROP_LED_FAULT,		/* PCIEHPC_FAULT_LED */
+	/* n */ PCIEHPC_PROP_LED_POWER,		/* PCIEHPC_POWER_LED */
+	/* n */ PCIEHPC_PROP_LED_ATTN,		/* PCIEHPC_ATTN_LED */
+	/* n */ PCIEHPC_PROP_LED_ACTIVE,	/* PCIEHPC_ACTIVE_LED */
+	/* n */ NULL
+};
+
+#define	FAULT	0
+#define	POWER	1
+#define	ATTN	2
+#define	ACTIVE	3
+
+static char *
+mode_strs[] = {
+	/* n */ "off",		/* OFF */
+	/* n */ "on",		/* ON */
+	/* n */ "blink",	/* BLINK */
+	/* n */	NULL
+};
+
+#define	OFF	0
+#define	ON	1
+#define	BLINK	2
+
+#define	cfga_errstrs(i)		cfga_errstrs[(i)]
+
+#define	cfga_eid(a, b)		(((a) << 8) + (b))
+#define	MAXDEVS			32
+
+typedef enum {
+	SOLARIS_SLT_NAME,
+	PROM_SLT_NAME
+} slt_name_src_t;
+
+struct searcharg {
+	char	*devpath;
+	char	slotnames[MAXDEVS][MAXNAMELEN];
+	int	minor;
+	di_prom_handle_t	promp;
+	slt_name_src_t	slt_name_src;
+};
+
+static void *private_check;
+
+/*
+ * Return the corresponding hp node for a given ap_id, it is the caller's
+ * responsibility to call hp_fini() to free the snapshot.
+ */
+static cfga_err_t
+physpath2node(const char *physpath, char **errstring, hp_node_t *nodep)
+{
+	char *rpath;
+	char *cp;
+	hp_node_t node;
+	size_t len;
+	char *errmsg;
+
+	if (getuid() != 0 && geteuid() != 0)
+		return (CFGA_ERROR);
+
+	if ((rpath = malloc(strlen(physpath) + 1)) == NULL)
+		return (CFGA_ERROR);
+
+	(void) strcpy(rpath, physpath);
+
+	/* Remove devices prefix (if any) */
+	len = strlen(DEVICES_DIR);
+	if (strncmp(rpath, DEVICES_DIR SLASH, len + strlen(SLASH)) == 0) {
+		(void) memmove(rpath, rpath + len,
+		    strlen(rpath + len) + 1);
+	}
+
+	/* Remove dynamic component if any */
+	if ((cp = GET_DYN(rpath)) != NULL) {
+		*cp = '\0';
+	}
+
+	/* Remove minor name (if any) */
+	if ((cp = strrchr(rpath, ':')) == NULL) {
+		free(rpath);
+		return (CFGA_INVAL);
+	}
+
+	*cp = '\0';
+	cp++;
+
+	DBG(1, ("rpath=%s,cp=%s\n", rpath, cp));
+	if ((node = hp_init(rpath, cp, 0)) == NULL) {
+		if (errno == EBADF) {
+			/* No reponse to operations on the door file. */
+			assert(errstring != NULL);
+			*errstring = strdup(MSG_HOTPLUG_DISABLED);
+			free(rpath);
+			return (CFGA_NOTSUPP);
+		}
+		free(rpath);
+		return (CFGA_ERROR);
+	}
+
+	free(rpath);
+
+	*nodep = node;
+	return (CFGA_OK);
+}
+
+typedef struct error_size_cb_arg {
+	size_t	rsrc_width;
+	size_t	info_width;
+	int	cnt;
+} error_size_cb_arg_t;
+
+/*
+ * Callback function for hp_traverse(), to sum up the
+ * maximum length for error message display.
+ */
+static int
+error_sizeup_cb(hp_node_t node, void *arg)
+{
+	error_size_cb_arg_t	*sizearg = (error_size_cb_arg_t *)arg;
+	size_t 			len;
+
+	/* Only process USAGE nodes */
+	if (hp_type(node) != HP_NODE_USAGE)
+		return (HP_WALK_CONTINUE);
+
+	sizearg->cnt++;
+
+	/* size up resource name */
+	len = strlen(hp_name(node));
+	if (sizearg->rsrc_width < len)
+		sizearg->rsrc_width = len;
+
+	/* size up usage description */
+	len = strlen(hp_usage(node));
+	if (sizearg->info_width < len)
+		sizearg->info_width = len;
+
+	return (HP_WALK_CONTINUE);
+}
+
+typedef struct error_sum_cb_arg {
+	char **table;
+	char *format;
+} error_sum_cb_arg_t;
+
+/*
+ * Callback function for hp_traverse(), to add the error
+ * message to he table.
+ */
+static int
+error_sumup_cb(hp_node_t node, void *arg)
+{
+	error_sum_cb_arg_t *sumarg = (error_sum_cb_arg_t *)arg;
+	char **table = sumarg->table;
+	char *format = sumarg->format;
+
+	/* Only process USAGE nodes */
+	if (hp_type(node) != HP_NODE_USAGE)
+		return (HP_WALK_CONTINUE);
+
+	(void) strcat(*table, "\n");
+	(void) sprintf(&((*table)[strlen(*table)]),
+	    format, hp_name(node), hp_usage(node));
+
+	return (HP_WALK_CONTINUE);
+}
+
+/*
+ * Takes an opaque rcm_info_t pointer and a character pointer, and appends
+ * the rcm_info_t data in the form of a table to the given character pointer.
+ */
+static void
+pci_rcm_info_table(hp_node_t node, char **table)
+{
+	int i;
+	size_t w;
+	size_t width = 0;
+	size_t w_rsrc = 0;
+	size_t w_info = 0;
+	size_t table_size = 0;
+	uint_t tuples = 0;
+	char *rsrc;
+	char *info;
+	char *newtable;
+	static char format[MAX_FORMAT];
+	const char *infostr;
+	error_size_cb_arg_t sizearg;
+	error_sum_cb_arg_t sumarg;
+
+	/* Protect against invalid arguments */
+	if (table == NULL)
+		return;
+
+	/* Set localized table header strings */
+	rsrc = dgettext(TEXT_DOMAIN, "Resource");
+	info = dgettext(TEXT_DOMAIN, "Information");
+
+	/* A first pass, to size up the RCM information */
+	sizearg.rsrc_width = strlen(rsrc);
+	sizearg.info_width = strlen(info);
+	sizearg.cnt = 0;
+	(void) hp_traverse(node, &sizearg, error_sizeup_cb);
+
+	/* If nothing was sized up above, stop early */
+	if (sizearg.cnt == 0)
+		return;
+
+	w_rsrc = sizearg.rsrc_width;
+	w_info = sizearg.info_width;
+	tuples = sizearg.cnt;
+
+	/* Adjust column widths for column headings */
+	if ((w = strlen(rsrc)) > w_rsrc)
+		w_rsrc = w;
+	else if ((w_rsrc - w) % 2)
+		w_rsrc++;
+	if ((w = strlen(info)) > w_info)
+		w_info = w;
+	else if ((w_info - w) % 2)
+		w_info++;
+
+	/*
+	 * Compute the total line width of each line,
+	 * accounting for intercolumn spacing.
+	 */
+	width = w_info + w_rsrc + 4;
+
+	/* Allocate space for the table */
+	table_size = (2 + tuples) * (width + 1) + 2;
+	if (*table == NULL) {
+		/* zero fill for the strcat() call below */
+		*table = calloc(table_size, sizeof (char));
+		if (*table == NULL)
+			return;
+	} else {
+		newtable = realloc(*table, strlen(*table) + table_size);
+		if (newtable == NULL)
+			return;
+		else
+			*table = newtable;
+	}
+
+	/* Place a table header into the string */
+
+	/* The resource header */
+	(void) strcat(*table, "\n");
+	w = strlen(rsrc);
+	for (i = 0; i < ((w_rsrc - w) / 2); i++)
+		(void) strcat(*table, " ");
+	(void) strcat(*table, rsrc);
+	for (i = 0; i < ((w_rsrc - w) / 2); i++)
+		(void) strcat(*table, " ");
+
+	/* The information header */
+	(void) strcat(*table, "  ");
+	w = strlen(info);
+	for (i = 0; i < ((w_info - w) / 2); i++)
+		(void) strcat(*table, " ");
+	(void) strcat(*table, info);
+	for (i = 0; i < ((w_info - w) / 2); i++)
+		(void) strcat(*table, " ");
+	/* Underline the headers */
+	(void) strcat(*table, "\n");
+	for (i = 0; i < w_rsrc; i++)
+		(void) strcat(*table, "-");
+	(void) strcat(*table, "  ");
+	for (i = 0; i < w_info; i++)
+		(void) strcat(*table, "-");
+
+	/* Construct the format string */
+	(void) snprintf(format, MAX_FORMAT, "%%-%ds  %%-%ds",
+	    (int)w_rsrc, (int)w_info);
+
+	/* Add the tuples to the table string */
+	sumarg.table = table;
+	sumarg.format = format;
+	(void) hp_traverse(node, &sumarg, error_sumup_cb);
+}
+
+/*
+ * Figure out the target kernel state for a given cfgadm
+ * change-state operation.
+ */
+static cfga_err_t
+cfga_target_state(cfga_cmd_t state_change_cmd, int *state)
+{
+	switch (state_change_cmd) {
+	case CFGA_CMD_CONNECT:
+		*state = DDI_HP_CN_STATE_POWERED;
+		break;
+	case CFGA_CMD_DISCONNECT:
+		*state = DDI_HP_CN_STATE_PRESENT;
+		break;
+	case CFGA_CMD_CONFIGURE:
+		*state = DDI_HP_CN_STATE_ENABLED;
+		break;
+	case CFGA_CMD_UNCONFIGURE:
+		*state = DDI_HP_CN_STATE_POWERED;
+		break;
+	default:
+		return (CFGA_ERROR);
+	}
+
+	return (CFGA_OK);
+}
+
+/*
+ * Translate kernel state to cfgadm receptacle state and occupant state.
+ */
+static cfga_err_t
+cfga_get_state(hp_node_t connector, ap_rstate_t *rs, ap_ostate_t *os)
+{
+	int state;
+	hp_node_t port;
+
+	state = hp_state(connector);
+
+	/* Receptacle state */
+	switch (state) {
+	case DDI_HP_CN_STATE_EMPTY:
+		*rs = AP_RSTATE_EMPTY;
+		break;
+	case DDI_HP_CN_STATE_PRESENT:
+		*rs = AP_RSTATE_DISCONNECTED;
+		break;
+	case DDI_HP_CN_STATE_POWERED:
+	case DDI_HP_CN_STATE_ENABLED:
+		*rs = AP_RSTATE_CONNECTED;
+		break;
+		/*
+		 * Connector state can only be one of
+		 * Empty, Present, Powered, Enabled.
+		 */
+	default:
+		return (CFGA_ERROR);
+	}
+
+	/*
+	 * Occupant state
+	 */
+	port = hp_child(connector);
+	while (port != NULL) {
+		DBG(1, ("cfga_get_state:(%x)\n", hp_state(port)));
+
+		/*
+		 * Mark occupant state as "configured" if at least one of the
+		 * associated ports is at state "offline" or above. Driver
+		 * attach ("online" state) is not necessary here.
+		 */
+		if (hp_state(port) >= DDI_HP_CN_STATE_OFFLINE)
+			break;
+
+		port = hp_sibling(port);
+	}
+
+	if (port != NULL)
+		*os = AP_OSTATE_CONFIGURED;
+	else
+		*os = AP_OSTATE_UNCONFIGURED;
+
+	return (CFGA_OK);
+}
+
+/*
+ * Transitional Diagram:
+ *
+ *  empty		unconfigure
+ * (remove)	^|  (physically insert card)
+ *			|V
+ * disconnect	configure
+ * "-c DISCONNECT"	^|	"-c CONNECT"
+ *				|V	"-c CONFIGURE"
+ * connect	unconfigure	->	connect    configure
+ *						<-
+ *					"-c UNCONFIGURE"
+ *
+ */
+/*ARGSUSED*/
+cfga_err_t
+cfga_change_state(cfga_cmd_t state_change_cmd, const char *ap_id,
+    const char *options, struct cfga_confirm *confp,
+    struct cfga_msg *msgp, char **errstring, cfga_flags_t flags)
+{
+	int		rv, state, new_state;
+	hp_node_t	node;
+	hp_node_t	results = NULL;
+
+	if ((rv = check_options(options)) != CFGA_OK) {
+		return (rv);
+	}
+
+	if (errstring != NULL)
+		*errstring = NULL;
+
+	rv = CFGA_OK;
+	DBG(1, ("cfga_change_state:(%s)\n", ap_id));
+
+	rv = physpath2node(ap_id, errstring, &node);
+	if (rv != CFGA_OK)
+		return (rv);
+
+	state = hp_state(node);
+
+	/*
+	 * Which state should we drive to ?
+	 */
+	if ((state_change_cmd != CFGA_CMD_LOAD) &&
+	    (state_change_cmd != CFGA_CMD_UNLOAD)) {
+		if (cfga_target_state(state_change_cmd,
+		    &new_state) != CFGA_OK) {
+			hp_fini(node);
+			return (CFGA_ERROR);
+		}
+	}
+
+	DBG(1, ("cfga_change_state: state is %d\n", state));
+	switch (state_change_cmd) {
+	case CFGA_CMD_CONNECT:
+		if ((state == DDI_HP_CN_STATE_EMPTY) ||
+		    (state >= DDI_HP_CN_STATE_POWERED)) {
+			cfga_err(errstring, ERR_AP_ERR, 0);
+			rv = CFGA_INVAL;
+		} else {
+			/* Lets connect the slot */
+			if (hp_set_state(node, 0, new_state, &results) != 0) {
+				rv = CFGA_ERROR;
+				cfga_err(errstring, CMD_SLOT_CONNECT, 0);
+			}
+		}
+
+		break;
+
+	case CFGA_CMD_DISCONNECT:
+		DBG(1, ("disconnect\n"));
+
+		if (state < DDI_HP_CN_STATE_POWERED) {
+			cfga_err(errstring, ERR_AP_ERR, 0);
+			rv = CFGA_INVAL;
+		} else {
+			if ((rv = hp_set_state(node, 0, new_state, &results))
+			    != 0) {
+				if (rv == EBUSY)
+					rv = CFGA_BUSY;
+				else
+					rv = CFGA_ERROR;
+
+				if (results) {
+					pci_rcm_info_table(results, errstring);
+					hp_fini(results);
+				} else {
+					cfga_err(errstring,
+					    CMD_SLOT_DISCONNECT, 0);
+				}
+			}
+		}
+
+		break;
+
+	case CFGA_CMD_CONFIGURE:
+		/*
+		 * for multi-func device we allow multiple
+		 * configure on the same slot because one
+		 * func can be configured and other one won't
+		 */
+		if (hp_set_state(node, 0, new_state, &results) != 0) {
+			rv = CFGA_ERROR;
+			cfga_err(errstring, CMD_SLOT_CONFIGURE, 0);
+		}
+
+		break;
+
+	case CFGA_CMD_UNCONFIGURE:
+		DBG(1, ("unconfigure\n"));
+
+		if (state >= DDI_HP_CN_STATE_ENABLED) {
+			if ((rv = hp_set_state(node, 0, new_state, &results))
+			    != 0) {
+				if (rv == EBUSY)
+					rv = CFGA_BUSY;
+				else
+					rv = CFGA_ERROR;
+
+				if (results) {
+					pci_rcm_info_table(results, errstring);
+					hp_fini(results);
+				} else {
+					cfga_err(errstring,
+					    CMD_SLOT_UNCONFIGURE, 0);
+				}
+			}
+		} else {
+			cfga_err(errstring, ERR_AP_ERR, 0);
+			rv = CFGA_INVAL;
+		}
+
+		DBG(1, ("unconfigure rv:(%i)\n", rv));
+		break;
+
+	case CFGA_CMD_LOAD:
+		/* do nothing, just produce error msg as is */
+		if (state < DDI_HP_CN_STATE_POWERED) {
+			rv = CFGA_ERROR;
+			cfga_err(errstring, CMD_SLOT_INSERT, 0);
+		} else {
+			cfga_err(errstring, ERR_AP_ERR, 0);
+			rv = CFGA_INVAL;
+		}
+		break;
+
+	case CFGA_CMD_UNLOAD:
+		/* do nothing, just produce error msg as is */
+		if (state < DDI_HP_CN_STATE_POWERED) {
+			rv = CFGA_ERROR;
+			cfga_err(errstring, CMD_SLOT_REMOVE, 0);
+		} else {
+			cfga_err(errstring, ERR_AP_ERR, 0);
+			rv = CFGA_INVAL;
+		}
+		break;
+
+	default:
+		rv = CFGA_OPNOTSUPP;
+		break;
+	}
+
+	hp_fini(node);
+	return (rv);
+}
+
+char *
+get_val_from_result(char *result)
+{
+	char *tmp;
+
+	tmp = strchr(result, '=');
+	if (tmp == NULL)
+		return (NULL);
+
+	tmp++;
+	return (tmp);
+}
+
+static cfga_err_t
+prt_led_mode(const char *ap_id, int repeat, char **errstring,
+    struct cfga_msg *msgp)
+{
+	pciehpc_led_t led;
+	hp_node_t node;
+	char *buff;
+	char *buf;
+	char *cp, line[MAXLINE];
+	char *tmp;
+	char *format;
+	char *result;
+	int i, n, rv;
+	int len = MAXLINE;
+
+	pciehpc_led_t states[] = {
+		PCIEHPC_POWER_LED,
+		PCIEHPC_FAULT_LED,
+		PCIEHPC_ATTN_LED,
+		PCIEHPC_ACTIVE_LED
+	};
+
+	DBG(1, ("prt_led_mod function\n"));
+	if (!repeat)
+		cfga_msg(msgp, "Ap_Id\t\t\tLed");
+
+	rv = physpath2node(ap_id, errstring, &node);
+	if (rv != CFGA_OK)
+		return (rv);
+
+	if ((buff = malloc(MAXPATHLEN)) == NULL) {
+		hp_fini(node);
+		cfga_err(errstring, "malloc ", 0);
+		return (CFGA_ERROR);
+	}
+
+	(void) memset(buff, 0, MAXPATHLEN);
+
+	if (fix_ap_name(buff, ap_id, hp_name(node),
+	    errstring) != CFGA_OK) {
+		hp_fini(node);
+		free(buff);
+		return (CFGA_ERROR);
+	}
+
+	cp = line;
+	(void) snprintf(cp, len, "%s\t\t", buff);
+	len -= strlen(cp);
+	cp += strlen(cp);
+
+	free(buff);
+
+	n = sizeof (states)/sizeof (pciehpc_led_t);
+	for (i = 0; i < n; i++) {
+		led = states[i];
+
+		format = (i == n - 1) ? "%s=%s" : "%s=%s,";
+		if (hp_get_private(node, led_strs2[led], &result) != 0) {
+			(void) snprintf(cp, len, format,
+			    led_strs[led], cfga_strs[UNKNOWN]);
+			len -= strlen(cp);
+			cp += strlen(cp);
+			DBG(1, ("%s:%s\n", led_strs[led], cfga_strs[UNKNOWN]));
+		} else {
+			/*
+			 * hp_get_private() will return back things like
+			 * "led_fault=off", transform it to cfgadm desired
+			 * format.
+			 */
+			tmp = get_val_from_result(result);
+			if (tmp == NULL) {
+				free(result);
+				hp_fini(node);
+				return (CFGA_ERROR);
+			}
+
+			(void) snprintf(cp, len, format,
+			    led_strs[led], tmp);
+			len -= strlen(cp);
+			cp += strlen(cp);
+			DBG(1, ("%s:%s\n", led_strs[led], tmp));
+			free(result);
+		}
+	}
+
+	cfga_msg(msgp, line);	/* print the message */
+
+	hp_fini(node);
+
+	return (CFGA_OK);
+}
+
+/*ARGSUSED*/
+cfga_err_t
+cfga_private_func(const char *function, const char *ap_id,
+    const char *options, struct cfga_confirm *confp,
+    struct cfga_msg *msgp, char **errstring, cfga_flags_t flags)
+{
+	char *str;
+	int   len, fd, i = 0, repeat = 0;
+	char buf[MAXNAMELEN];
+	char ptr;
+	cfga_err_t rv;
+	char *led, *mode;
+	hp_node_t node;
+	char *result;
+
+	DBG(1, ("cfgadm_private_func: ap_id:%s\n", ap_id));
+	DBG(2, ("  options: %s\n", (options == NULL)?"null":options));
+	DBG(2, ("  confp: %x\n", confp));
+	DBG(2, ("  cfga_msg: %x\n", cfga_msg));
+	DBG(2, ("  flag: %d\n", flags));
+
+	if ((rv = check_options(options)) != CFGA_OK) {
+		return (rv);
+	}
+
+	if (private_check == confp)
+		repeat = 1;
+	else
+		private_check = (void*)confp;
+
+	for (i = 0, str = func_strs[i], len = strlen(str);
+	    func_strs[i] != NULL; i++) {
+		str = func_strs[i];
+		len = strlen(str);
+		if (strncmp(function, str, len) == 0)
+			break;
+	}
+
+	switch (i) {
+		case ENABLE_SLOT:
+		case DISABLE_SLOT:
+			/* pass through */
+		case ENABLE_AUTOCNF:
+		case DISABLE_AUTOCNF:
+			/* no action needed */
+			return (CFGA_OK);
+			break;
+		case LED:
+			/* set mode */
+			ptr = function[len++];
+			if (ptr == '=') {
+				str = (char *)function;
+				for (str = (str+len++), i = 0; *str != ',';
+				    i++, str++) {
+					if (i == (MAXNAMELEN - 1))
+						break;
+
+					buf[i] = *str;
+					DBG_F(2, (stdout, "%c\n", buf[i]));
+				}
+				buf[i] = '\0'; str++;
+				DBG(2, ("buf = %s\n", buf));
+
+				/* ACTIVE=3,ATTN=2,POWER=1,FAULT=0 */
+				if (strcmp(buf, led_strs[POWER]) == 0)
+					led = PCIEHPC_PROP_LED_POWER;
+				else if (strcmp(buf, led_strs[FAULT]) == 0)
+					led = PCIEHPC_PROP_LED_FAULT;
+				else if (strcmp(buf, led_strs[ATTN]) == 0)
+					led = PCIEHPC_PROP_LED_ATTN;
+				else if (strcmp(buf, led_strs[ACTIVE]) == 0)
+					led = PCIEHPC_PROP_LED_ACTIVE;
+				else return (CFGA_INVAL);
+
+				len = strlen(func_strs[MODE]);
+				if ((strncmp(str, func_strs[MODE], len) == 0) &&
+				    (*(str+(len)) == '=')) {
+					for (str = (str+(++len)), i = 0;
+					    *str != NULL; i++, str++) {
+						buf[i] = *str;
+					}
+				}
+				buf[i] = '\0';
+				DBG(2, ("buf_mode= %s\n", buf));
+
+				/* ON = 1, OFF = 0 */
+				if (strcmp(buf, mode_strs[ON]) == 0)
+					mode = PCIEHPC_PROP_VALUE_ON;
+				else if (strcmp(buf, mode_strs[OFF]) == 0)
+					mode = PCIEHPC_PROP_VALUE_OFF;
+				else if (strcmp(buf, mode_strs[BLINK]) == 0)
+					mode = PCIEHPC_PROP_VALUE_BLINK;
+				else return (CFGA_INVAL);
+
+				/* sendin  */
+				memset(buf, 0, sizeof (buf));
+				snprintf(buf, sizeof (buf), "%s=%s",
+				    led, mode);
+				buf[MAXNAMELEN - 1] = '\0';
+
+				break;
+			} else if (ptr == '\0') {
+				/* print mode */
+				DBG(1, ("Print mode\n"));
+				return (prt_led_mode(ap_id, repeat, errstring,
+				    msgp));
+			}
+		default:
+			DBG(1, ("default\n"));
+			errno = EINVAL;
+			return (CFGA_INVAL);
+	}
+
+	rv = physpath2node(ap_id, errstring, &node);
+	if (rv != CFGA_OK)
+		return (rv);
+
+	if (hp_set_private(node, buf, &result) != 0) {
+		hp_fini(node);
+		return (CFGA_ERROR);
+	}
+
+	hp_fini(node);
+	return (CFGA_OK);
+}
+
+/*ARGSUSED*/
+cfga_err_t cfga_test(const char *ap_id, const char *options,
+    struct cfga_msg *msgp, char **errstring, cfga_flags_t flags)
+{
+	cfga_err_t rv;
+	if (errstring != NULL)
+		*errstring = NULL;
+
+	if ((rv = check_options(options)) != CFGA_OK) {
+		return (rv);
+	}
+
+	DBG(1, ("cfga_test:(%s)\n", ap_id));
+	/* will need to implement pci CTRL command */
+	return (CFGA_NOTSUPP);
+}
+
+/*
+ * The slot-names property describes the external labeling of add-in slots.
+ * This property is an encoded array, an integer followed by a list of
+ * strings. The return value from di_prop_lookup_ints for slot-names is -1.
+ * The expected return value should be the number of elements.
+ * Di_prop_decode_common does not decode encoded data from software,
+ * such as the solaris device tree, unlike from the prom.
+ * Di_prop_decode_common takes the size of the encoded data and mods
+ * it with the size of int. The size of the encoded data for slot-names is 9
+ * and the size of int is 4, yielding a non zero result. A value of -1 is used
+ * to indicate that the number of elements can not be determined.
+ * Di_prop_decode_common can be modified to decode encoded data from the solaris
+ * device tree.
+ */
+static int
+fixup_slotname(int rval, int *intp, struct searcharg *slotarg)
+{
+	if ((slotarg->slt_name_src == PROM_SLT_NAME) && (rval == -1)) {
+		return (DI_WALK_TERMINATE);
+	} else {
+		int i;
+		char *tmptr = (char *)(intp+1);
+		DBG(1, ("slot-bitmask: %x \n", *intp));
+
+		rval = (rval -1) * 4;
+
+		for (i = 0; i <= slotarg->minor; i++) {
+			DBG(2, ("curr slot-name: %s \n", tmptr));
+
+			if (i >= MAXDEVS)
+				return (DI_WALK_TERMINATE);
+
+			if ((*intp >> i) & 1) {
+				/* assign tmptr */
+				DBG(2, ("slot-name: %s \n", tmptr));
+				if (i == slotarg->minor)
+					(void) strcpy(slotarg->slotnames[i],
+					    tmptr);
+				/* wind tmptr to next \0 */
+				while (*tmptr != '\0') {
+					tmptr++;
+				}
+				tmptr++;
+			} else {
+				/* point at unknown string */
+				if (i == slotarg->minor)
+					(void) strcpy(slotarg->slotnames[i],
+					    "unknown");
+			}
+		}
+	}
+	return (DI_WALK_TERMINATE);
+}
+
+static int
+find_slotname(di_node_t din, di_minor_t dim, void *arg)
+{
+	struct searcharg *slotarg = (struct searcharg *)arg;
+	di_prom_handle_t ph = (di_prom_handle_t)slotarg->promp;
+	di_prom_prop_t	prom_prop;
+	di_prop_t	solaris_prop;
+	int *intp, rval;
+	char *devname;
+	char fulldevname[MAXNAMELEN];
+
+	slotarg->minor = dim->dev_minor % 256;
+
+	DBG(2, ("minor number:(%i)\n", slotarg->minor));
+	DBG(2, ("hot plug slots found so far:(%i)\n", 0));
+
+	if ((devname = di_devfs_path(din)) != NULL) {
+		(void) snprintf(fulldevname, MAXNAMELEN,
+		    "/devices%s:%s", devname, di_minor_name(dim));
+		di_devfs_path_free(devname);
+	}
+
+	if (strcmp(fulldevname, slotarg->devpath) == 0) {
+
+		/*
+		 * Check the Solaris device tree first
+		 * in the case of a DR operation
+		 */
+		solaris_prop = di_prop_hw_next(din, DI_PROP_NIL);
+		while (solaris_prop != DI_PROP_NIL) {
+			if (strcmp("slot-names", di_prop_name(solaris_prop))
+			    == 0) {
+				rval = di_prop_lookup_ints(DDI_DEV_T_ANY,
+				    din, di_prop_name(solaris_prop), &intp);
+				slotarg->slt_name_src = SOLARIS_SLT_NAME;
+
+				return (fixup_slotname(rval, intp, slotarg));
+			}
+			solaris_prop = di_prop_hw_next(din, solaris_prop);
+		}
+
+		/*
+		 * Check the prom device tree which is populated at boot.
+		 * If this fails, give up and set the slot name to null.
+		 */
+		prom_prop = di_prom_prop_next(ph, din, DI_PROM_PROP_NIL);
+		while (prom_prop != DI_PROM_PROP_NIL) {
+			if (strcmp("slot-names", di_prom_prop_name(prom_prop))
+			    == 0) {
+				rval = di_prom_prop_lookup_ints(ph,
+				    din, di_prom_prop_name(prom_prop), &intp);
+				slotarg->slt_name_src = PROM_SLT_NAME;
+
+				return (fixup_slotname(rval, intp, slotarg));
+			}
+			prom_prop = di_prom_prop_next(ph, din, prom_prop);
+		}
+		*slotarg->slotnames[slotarg->minor] = '\0';
+		return (DI_WALK_TERMINATE);
+	} else
+		return (DI_WALK_CONTINUE);
+}
+
+static int
+find_physical_slot_names(const char *devcomp, struct searcharg *slotarg)
+{
+	di_node_t root_node;
+
+	DBG(1, ("find_physical_slot_names\n"));
+
+	if ((root_node = di_init("/", DINFOCPYALL|DINFOPATH))
+	    == DI_NODE_NIL) {
+		DBG(1, ("di_init() failed\n"));
+		return (-1);
+	}
+
+	slotarg->devpath = (char *)devcomp;
+
+	if ((slotarg->promp = di_prom_init()) == DI_PROM_HANDLE_NIL) {
+		DBG(1, ("di_prom_init() failed\n"));
+		di_fini(root_node);
+		return (-1);
+	}
+
+	(void) di_walk_minor(root_node, "ddi_ctl:attachment_point:pci",
+	    0, (void *)slotarg, find_slotname);
+
+	di_prom_fini(slotarg->promp);
+	di_fini(root_node);
+	if (slotarg->slotnames[0] != NULL)
+		return (0);
+	else
+		return (-1);
+}
+
+static void
+get_type(const char *boardtype, const char *cardtype, char *buf)
+{
+/* for type string assembly in get_type() */
+#define	TPCT(s)	(void) strlcat(buf, (s), CFGA_TYPE_LEN)
+
+	int i;
+
+	if (strcmp(cardtype, "unknown") == 0) {
+		TPCT("unknown");
+		return;
+	}
+
+	TPCT(cardtype);
+	TPCT("/");
+
+	if (strcmp(boardtype, PCIEHPC_PROP_VALUE_PCIHOTPLUG) == 0)
+		TPCT(board_strs[PCIEHPC_BOARD_PCI_HOTPLUG]);
+	else
+		TPCT(board_strs[PCIEHPC_BOARD_UNKNOWN]);
+}
+
+/*
+ * call-back function for di_devlink_walk
+ * if the link lives in /dev/cfg copy its name
+ */
+static int
+found_devlink(di_devlink_t link, void *ap_log_id)
+{
+	if (strncmp("/dev/cfg/", di_devlink_path(link), 9) == 0) {
+		/* copy everything but /dev/cfg/ */
+		(void) strcpy((char *)ap_log_id, di_devlink_path(link) + 9);
+		DBG(1, ("found_devlink: %s\n", (char *)ap_log_id));
+		return (DI_WALK_TERMINATE);
+	}
+	return (DI_WALK_CONTINUE);
+}
+
+/*
+ * Walk throught the cached /dev link tree looking for links to the ap
+ * if none are found return an error
+ */
+static cfga_err_t
+check_devlinks(char *ap_log_id, const char *ap_id)
+{
+	di_devlink_handle_t hdl;
+
+	DBG(1, ("check_devlinks: %s\n", ap_id));
+
+	hdl = di_devlink_init(NULL, 0);
+
+	if (strncmp("/devices/", ap_id, 9) == 0) {
+		/* ap_id is a valid minor_path with /devices prepended */
+		(void) di_devlink_walk(hdl, NULL, ap_id + 8, DI_PRIMARY_LINK,
+		    (void *)ap_log_id, found_devlink);
+	} else {
+		DBG(1, ("check_devlinks: invalid ap_id: %s\n", ap_id));
+		return (CFGA_ERROR);
+	}
+
+	(void) di_devlink_fini(&hdl);
+
+	if (ap_log_id[0] != '\0')
+		return (CFGA_OK);
+	else
+		return (CFGA_ERROR);
+}
+
+/*
+ * most of this is needed to compensate for
+ * differences between various platforms
+ */
+static cfga_err_t
+fix_ap_name(char *ap_log_id, const char *ap_id, char *slot_name,
+    char **errstring)
+{
+	char *buf;
+	char *tmp;
+	char *ptr;
+
+	di_node_t ap_node;
+
+	ap_log_id[0] = '\0';
+
+	if (check_devlinks(ap_log_id, ap_id) == CFGA_OK)
+		return (CFGA_OK);
+
+	DBG(1, ("fix_ap_name: %s\n", ap_id));
+
+	if ((buf = malloc(strlen(ap_id) + 1)) == NULL) {
+		DBG(1, ("malloc failed\n"));
+		return (CFGA_ERROR);
+	}
+	(void) strcpy(buf, ap_id);
+	tmp = buf + sizeof ("/devices") - 1;
+
+	ptr = strchr(tmp, ':');
+	ptr[0] = '\0';
+
+	DBG(1, ("fix_ap_name: %s\n", tmp));
+
+	ap_node = di_init(tmp, DINFOMINOR);
+	if (ap_node == DI_NODE_NIL) {
+		cfga_err(errstring, "di_init ", 0);
+		DBG(1, ("fix_ap_name: failed to snapshot node\n"));
+		return (CFGA_ERROR);
+	}
+
+	(void) snprintf(ap_log_id, strlen(ap_id) + 1, "%s%i:%s",
+	    di_driver_name(ap_node), di_instance(ap_node), slot_name);
+
+	DBG(1, ("fix_ap_name: %s\n", ap_log_id));
+
+	di_fini(ap_node);
+
+	free(buf);
+	return (CFGA_OK);
+}
+
+
+static int
+findlink_cb(di_devlink_t devlink, void *arg)
+{
+	(*(char **)arg) = strdup(di_devlink_path(devlink));
+
+	return (DI_WALK_TERMINATE);
+}
+
+/*
+ * returns an allocated string containing the full path to the devlink for
+ * <ap_phys_id> in the devlink database; we expect only one devlink per
+ * <ap_phys_id> so we return the first encountered
+ */
+static char *
+findlink(char *ap_phys_id)
+{
+	di_devlink_handle_t hdl;
+	char *path = NULL;
+
+	hdl = di_devlink_init(NULL, 0);
+
+	if (strncmp("/devices/", ap_phys_id, 9) == 0)
+		ap_phys_id += 8;
+
+	(void) di_devlink_walk(hdl, "^cfg/.+$", ap_phys_id, DI_PRIMARY_LINK,
+	    (void *)&path, findlink_cb);
+
+	(void) di_devlink_fini(&hdl);
+	return (path);
+}
+
+
+/*
+ * returns CFGA_OK if it can succesfully retrieve the devlink info associated
+ * with devlink for <ap_phys_id> which will be returned through <ap_info>
+ */
+cfga_err_t
+get_dli(char *dlpath, char *ap_info, int ap_info_sz)
+{
+	int fd;
+
+	fd = di_dli_openr(dlpath);
+	if (fd < 0)
+		return (CFGA_ERROR);
+
+	(void) read(fd, ap_info, ap_info_sz);
+	ap_info[ap_info_sz - 1] = '\0';
+
+	di_dli_close(fd);
+	return (CFGA_OK);
+}
+
+static cfga_err_t
+cfga_get_condition(hp_node_t node, ap_condition_t *cond)
+{
+	char *condition;
+
+	/* "condition" bus specific commands */
+	if (hp_get_private(node, PCIEHPC_PROP_SLOT_CONDITION,
+	    &condition) != 0) {
+		*cond = AP_COND_UNKNOWN;
+		return (CFGA_ERROR);
+	}
+
+	condition = get_val_from_result(condition);
+
+	if (strcmp(condition, PCIEHPC_PROP_COND_OK) == 0)
+		*cond = AP_COND_OK;
+	else if (strcmp(condition, PCIEHPC_PROP_COND_FAILING) == 0)
+		*cond = AP_COND_FAILING;
+	else if (strcmp(condition, PCIEHPC_PROP_COND_FAILED) == 0)
+		*cond = AP_COND_FAILED;
+	else if (strcmp(condition, PCIEHPC_PROP_COND_UNUSABLE) == 0)
+		*cond = AP_COND_UNUSABLE;
+	else if (strcmp(condition, PCIEHPC_PROP_COND_UNKNOWN) == 0)
+		*cond = AP_COND_UNKNOWN;
+	else
+		return (CFGA_ERROR);
+
+	return (CFGA_OK);
+}
+
+/*ARGSUSED*/
+cfga_err_t
+cfga_list_ext(const char *ap_id, cfga_list_data_t **cs,
+    int *nlist, const char *options, const char *listopts, char **errstring,
+    cfga_flags_t flags)
+{
+	char			*boardtype;
+	char			*cardtype;
+	struct	searcharg	slotname_arg;
+	int			fd;
+	int			rv = CFGA_OK;
+	char			*dlpath = NULL;
+	hp_node_t		node;
+	ap_rstate_t		rs;
+	ap_ostate_t		os;
+	ap_condition_t		cond;
+
+	if ((rv = check_options(options)) != CFGA_OK) {
+		return (rv);
+	}
+
+	if (errstring != NULL)
+		*errstring = NULL;
+
+	DBG(1, ("cfga_list_ext:(%s)\n", ap_id));
+
+	if (cs == NULL || nlist == NULL) {
+		rv = CFGA_ERROR;
+		return (rv);
+	}
+
+	*nlist = 1;
+
+	if ((*cs = malloc(sizeof (cfga_list_data_t))) == NULL) {
+		cfga_err(errstring, "malloc ", 0);
+		DBG(1, ("malloc failed\n"));
+		rv = CFGA_ERROR;
+		return (rv);
+	}
+	(void) memset(*cs, 0, sizeof (cfga_list_data_t));
+
+	rv = physpath2node(ap_id, errstring, &node);
+	if (rv != CFGA_OK) {
+		DBG(1, ("physpath2node failed\n"));
+		return (rv);
+	}
+
+	if (cfga_get_state(node, &rs, &os) != CFGA_OK) {
+		DBG(1, ("cfga_get_state failed\n"));
+		hp_fini(node);
+		return (CFGA_ERROR);
+	}
+
+	switch (rs) {
+		case AP_RSTATE_EMPTY:
+			(*cs)->ap_r_state = CFGA_STAT_EMPTY;
+			DBG(2, ("ap_rstate = CFGA_STAT_EMPTY\n"));
+			break;
+		case AP_RSTATE_DISCONNECTED:
+			(*cs)->ap_r_state = CFGA_STAT_DISCONNECTED;
+			DBG(2, ("ap_rstate = CFGA_STAT_DISCONNECTED\n"));
+			break;
+		case AP_RSTATE_CONNECTED:
+			(*cs)->ap_r_state = CFGA_STAT_CONNECTED;
+			DBG(2, ("ap_rstate = CFGA_STAT_CONNECTED\n"));
+			break;
+	default:
+		cfga_err(errstring, CMD_GETSTAT, ap_id, 0);
+		rv = CFGA_ERROR;
+		hp_fini(node);
+		return (rv);
+	}
+
+	switch (os) {
+		case AP_OSTATE_CONFIGURED:
+			(*cs)->ap_o_state = CFGA_STAT_CONFIGURED;
+			DBG(2, ("ap_ostate = CFGA_STAT_CONFIGURED\n"));
+			break;
+		case AP_OSTATE_UNCONFIGURED:
+			(*cs)->ap_o_state = CFGA_STAT_UNCONFIGURED;
+			DBG(2, ("ap_ostate = CFGA_STAT_UNCONFIGURED\n"));
+			break;
+	default:
+		cfga_err(errstring, CMD_GETSTAT, ap_id, 0);
+		rv = CFGA_ERROR;
+		hp_fini(node);
+		return (rv);
+	}
+
+	(void) cfga_get_condition(node, &cond);
+
+	switch (cond) {
+		case AP_COND_OK:
+			(*cs)->ap_cond = CFGA_COND_OK;
+			DBG(2, ("ap_cond = CFGA_COND_OK\n"));
+			break;
+		case AP_COND_FAILING:
+			(*cs)->ap_cond = CFGA_COND_FAILING;
+			DBG(2, ("ap_cond = CFGA_COND_FAILING\n"));
+			break;
+		case AP_COND_FAILED:
+			(*cs)->ap_cond = CFGA_COND_FAILED;
+			DBG(2, ("ap_cond = CFGA_COND_FAILED\n"));
+			break;
+		case AP_COND_UNUSABLE:
+			(*cs)->ap_cond = CFGA_COND_UNUSABLE;
+			DBG(2, ("ap_cond = CFGA_COND_UNUSABLE\n"));
+			break;
+		case AP_COND_UNKNOWN:
+			(*cs)->ap_cond = CFGA_COND_UNKNOWN;
+			DBG(2, ("ap_cond = CFGA_COND_UNKNOW\n"));
+			break;
+	default:
+		cfga_err(errstring, CMD_GETSTAT, ap_id, 0);
+		rv = CFGA_ERROR;
+		hp_fini(node);
+		return (rv);
+	}
+	/*
+	 * We're not busy since the entrance into the kernel has been
+	 * sync'ed via libhotplug.
+	 */
+	(*cs)->ap_busy = 0;
+
+	/* last change */
+	(*cs)->ap_status_time = hp_last_change(node);
+
+	/* board type */
+	if (hp_get_private(node, PCIEHPC_PROP_BOARD_TYPE, &boardtype) != 0)
+		boardtype = PCIEHPC_PROP_VALUE_UNKNOWN;
+	else
+		boardtype = get_val_from_result(boardtype);
+
+	/* card type */
+	if (hp_get_private(node, PCIEHPC_PROP_CARD_TYPE, &cardtype) != 0)
+		cardtype = PCIEHPC_PROP_VALUE_UNKNOWN;
+	else
+		cardtype = get_val_from_result(cardtype);
+
+	/* logical ap_id */
+	rv = fix_ap_name((*cs)->ap_log_id, ap_id,
+	    hp_name(node), errstring);
+	DBG(1, ("logical id: %s\n", (*cs)->ap_log_id));
+	/* physical ap_id */
+	(void) strcpy((*cs)->ap_phys_id, ap_id);    /* physical path of AP */
+
+	/* information */
+	dlpath = findlink((*cs)->ap_phys_id);
+	if (dlpath != NULL) {
+		if (get_dli(dlpath, (*cs)->ap_info,
+		    sizeof ((*cs)->ap_info)) != CFGA_OK)
+			(*cs)->ap_info[0] = '\0';
+		free(dlpath);
+	}
+
+	if ((*cs)->ap_log_id[0] == '\0')
+		(void) strcpy((*cs)->ap_log_id, hp_name(node));
+
+	if ((*cs)->ap_info[0] == '\0') {
+		/* slot_names of bus node  */
+		if (find_physical_slot_names(ap_id, &slotname_arg) != -1)
+			(void) strcpy((*cs)->ap_info,
+			    slotname_arg.slotnames[slotname_arg.minor]);
+	}
+
+	/* class_code/subclass/boardtype */
+	get_type(boardtype, cardtype, (*cs)->ap_type);
+
+	DBG(1, ("cfga_list_ext return success\n"));
+	rv = CFGA_OK;
+
+	hp_fini(node);
+	return (rv);
+}
+
+/*
+ * This routine prints a single line of help message
+ */
+static void
+cfga_msg(struct cfga_msg *msgp, const char *str)
+{
+	DBG(2, ("<%s>", str));
+
+	if (msgp == NULL || msgp->message_routine == NULL)
+		return;
+
+	(*msgp->message_routine)(msgp->appdata_ptr, str);
+	(*msgp->message_routine)(msgp->appdata_ptr, "\n");
+}
+
+static cfga_err_t
+check_options(const char *options)
+{
+	struct cfga_msg *msgp = NULL;
+
+	if (options) {
+		cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_UNKNOWN]));
+		cfga_msg(msgp, options);
+		return (CFGA_INVAL);
+	}
+	return (CFGA_OK);
+}
+
+/*ARGSUSED*/
+cfga_err_t
+cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
+{
+	if (options) {
+		cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_UNKNOWN]));
+		cfga_msg(msgp, options);
+	}
+	DBG(1, ("cfga_help\n"));
+
+	cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_HEADER]));
+	cfga_msg(msgp, cfga_strs[HELP_CONFIG]);
+	cfga_msg(msgp, cfga_strs[HELP_ENABLE_SLOT]);
+	cfga_msg(msgp, cfga_strs[HELP_DISABLE_SLOT]);
+	cfga_msg(msgp, cfga_strs[HELP_ENABLE_AUTOCONF]);
+	cfga_msg(msgp, cfga_strs[HELP_DISABLE_AUTOCONF]);
+	cfga_msg(msgp, cfga_strs[HELP_LED_CNTRL]);
+	return (CFGA_OK);
+}
+
+/*
+ * cfga_err() accepts a variable number of message IDs and constructs
+ * a corresponding error string which is returned via the errstring argument.
+ * cfga_err() calls gettext() to internationalize proper messages.
+ */
+static void
+cfga_err(char **errstring, ...)
+{
+	int a;
+	int i;
+	int n;
+	int len;
+	int flen;
+	char *p;
+	char *q;
+	char *s[32];
+	char *failed;
+	va_list ap;
+
+	/*
+	 * If errstring is null it means user is not interested in getting
+	 * error status. So we don't do all the work
+	 */
+	if (errstring == NULL) {
+		return;
+	}
+	va_start(ap, errstring);
+
+	failed = dgettext(TEXT_DOMAIN, cfga_strs[FAILED]);
+	flen = strlen(failed);
+
+	for (n = len = 0; (a = va_arg(ap, int)) != 0; n++) {
+		switch (a) {
+		case CMD_GETSTAT:
+		case CMD_LIST:
+		case CMD_SLOT_CONNECT:
+		case CMD_SLOT_DISCONNECT:
+		case CMD_SLOT_CONFIGURE:
+		case CMD_SLOT_UNCONFIGURE:
+			p =  cfga_errstrs(a);
+			len += (strlen(p) + flen);
+			s[n] = p;
+			s[++n] = cfga_strs[FAILED];
+
+			DBG(2, ("<%s>", p));
+			DBG(2, (cfga_strs[FAILED]));
+			break;
+
+		case ERR_CMD_INVAL:
+		case ERR_AP_INVAL:
+		case ERR_OPT_INVAL:
+		case ERR_AP_ERR:
+			switch (a) {
+			case ERR_CMD_INVAL:
+				p = dgettext(TEXT_DOMAIN,
+				    cfga_errstrs[ERR_CMD_INVAL]);
+				break;
+			case ERR_AP_INVAL:
+				p = dgettext(TEXT_DOMAIN,
+				    cfga_errstrs[ERR_AP_INVAL]);
+				break;
+			case ERR_OPT_INVAL:
+				p = dgettext(TEXT_DOMAIN,
+				    cfga_errstrs[ERR_OPT_INVAL]);
+				break;
+			case ERR_AP_ERR:
+				p = dgettext(TEXT_DOMAIN,
+				    cfga_errstrs[ERR_AP_ERR]);
+				break;
+			}
+
+			if ((q = va_arg(ap, char *)) != NULL) {
+				len += (strlen(p) + strlen(q));
+				s[n] = p;
+				s[++n] = q;
+				DBG(2, ("<%s>", p));
+				DBG(2, ("<%s>", q));
+				break;
+			} else {
+				len += strlen(p);
+				s[n] = p;
+
+			}
+			DBG(2, ("<%s>", p));
+			break;
+
+		default:
+			n--;
+			break;
+		}
+	}
+
+	DBG(2, ("\n"));
+	va_end(ap);
+
+	if ((p = calloc(len + 1, 1)) == NULL)
+		return;
+
+	for (i = 0; i < n; i++) {
+		(void) strlcat(p, s[i], len + 1);
+		DBG(2, ("i:%d, %s\n", i, s[i]));
+	}
+
+	*errstring = p;
+	DBG(2, ("%s\n", *errstring));
+}
+
+/*
+ * cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/shp/i386/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -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 ../Makefile.com
+
+.KEEP_STATE:
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/shp/shp.xcl	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,154 @@
+#
+# 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/cfgadm_plugins/pci/pci.xcl
+#
+msgid  "acquire "
+msgid  "get-status "
+msgid  "list "
+msgid  "connect "
+msgid  "disconnect "
+msgid  "configure "
+msgid  "unconfigure "
+msgid  "insert "
+msgid  "remove "
+msgid  "open "
+msgid  "fstat "
+msgid  "\t-c [connect|disconnect|configure|unconfigure|insert|remove] "
+       "ap_id [ap_id...]"
+msgid  "\t-x enable_slot  ap_id [ap_id...]"
+msgid  "\t-x disable_slot ap_id [ap_id...]"
+msgid  "\t-x enable_autoconfig  ap_id [ap_id...]"
+msgid  "\t-x disable_autoconfig ap_id [ap_id...]"
+msgid  "\t-x led[=[fault|power|active|attn],mode=[on|off|blink]] ap_id [ap_id...]"
+msgid  "unknown"
+msgid  "SCSI"
+msgid  "IDE"
+msgid  "FlpyDisk"
+msgid  "IPI"
+msgid  "RAID"
+msgid  "MassStrg"
+msgid  "Ethernet"
+msgid  "TokenRg"
+msgid  "FDDI"
+msgid  "ATM"
+msgid  "Network"
+msgid  "VGA8514"
+msgid  "xGA"
+msgid  "Display"
+msgid  "Vedio"
+msgid  "Audio"
+msgid  "MultiMda"
+msgid  "Ram"
+msgid  "Flash"
+msgid  "Memory"
+msgid  "Host-PCI"
+msgid  "PCI-ISA"
+msgid  "PCI-EISA"
+msgid  "PCI-MC"
+msgid  "PCI-PCI"
+msgid  "PCI-MCIA"
+msgid  "PCI-NuBs"
+msgid  "PCI-Card"
+msgid  "Bridge"
+msgid  "???"
+msgid  "HP"
+msgid  "NHS"
+msgid  "BHS"
+msgid  "FHS"
+msgid  "HS"
+msgid  "enable_slot"
+msgid  "disable_slot"
+msgid  "enable_autoconfig"
+msgid  "disable_autoconfig"
+msgid  "led"
+msgid  "mode"
+msgid  "fault"
+msgid  "power"
+msgid  "attn"
+msgid  "active"
+msgid  "off"
+msgid  "on"
+msgid  "blink"
+msgid  "slot"
+msgid  "ap_idx(%s)\n"
+msgid  "<%d>"
+msgid  "%s"
+msgid  "cfga_change_state:(%s)\n"
+msgid  "cfga_change_state: state is %d\n"
+msgid  "cfga_get_condition failed\n"
+msgid  "cfga_get_state failed\n"
+msgid  "cfga_get_state:(%x)\n"
+msgid  "malloc failed\n"
+msgid  "prt_led_mod function\n"
+msgid  "Ap_Id\t\t\tLed\n"
+msgid  "physpath2node failed\n"
+msgid  "malloc "
+msgid  "%s\t\t"
+msgid  "%s=%s,"
+msgid  "%s:%s\n"
+msgid  "%s=%s\n"
+msgid  "cfgadm_private_func: ap_id:%s\n"
+msgid  "  options: %s\n"
+msgid  "null"
+msgid  "  confp: %x\n"
+msgid  "  cfga_msg: %x\n"
+msgid  "  flag: %d\n"
+msgid  "%c\n"
+msgid  "buf = %s\n"
+msgid  "buf_mode= %s\n"
+msgid  "Print mode\n"
+msgid  "default\n"
+msgid  "open"
+msgid  "cfga_test:(%s)\n"
+msgid  "/devices%s:%s"
+msgid  "slot-names"
+msgid  "di_prom_prop_lookup_ints"
+msgid  "slot-names:"
+       " %s \n"
+msgid  "/"
+msgid  "di_init() failed\n"
+msgid  "di_prom_init() failed\n"
+msgid  "ddi_ctl:attachment_point:pci"
+msgid  "MULT"
+msgid  "cfga_stat:(%d)\n"
+msgid  "ap_rstate = CFGA_STAT_EMPTY\n"
+msgid  "ap_rstate = CFGA_STAT_DISCONNECTED\n"
+msgid  "ap_rstate = CFGA_STAT_CONNECTED\n"
+msgid  "ap_ostate = CFGA_STAT_CONFIGURED\n"
+msgid  "ap_ostate = CFGA_STAT_UNCONFIGURED\n"
+msgid  "ap_cond = CFGA_COND_OK\n"
+msgid  "ap_cond = CFGA_COND_FAILING\n"
+msgid  "ap_cond = CFGA_COND_FAILED\n"
+msgid  "ap_cond = CFGA_COND_UNUSABLE\n"
+msgid  "ap_cond = CFGA_COND_UNKNOW\n"
+msgid  "cfga_stat return success\n"
+msgid  "cfga_list:(%s)\n"
+msgid  "cfga_help\n"
+msgid  "<%s>"
+msgid  "\n"
+msgid  "i:%d, %s\n"
+msgid  "%s\n"
+msgid  "rpath=%s,cp=%s\n"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/shp/sparc/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -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 ../Makefile.com
+
+.KEEP_STATE:
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/shp/sparcv9/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+.KEEP_STATE:
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- a/usr/src/lib/libbsm/audit_event.txt	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/lib/libbsm/audit_event.txt	Mon Nov 02 15:58:28 2009 +0800
@@ -533,6 +533,11 @@
 6417:AUE_tpm_physicalpresence:set the TPM physical presence flag:as
 6418:AUE_tpm_fieldupgrade:update TPM protected capabilities:as
 6419:AUE_tpm_resetlockvalue:reset TPM failed authorization attempt lock:as
+#
+# hotplugd(1m) events
+#
+6500:AUE_hotplug_state:change hotplug connection state:ss
+6501:AUE_hotplug_set:set hotplug bus private options:ss
 
 #
 # Trusted Extensions events:
--- a/usr/src/lib/libbsm/common/adt.xml	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/lib/libbsm/common/adt.xml	Mon Nov 02 15:58:28 2009 +0800
@@ -2016,8 +2016,83 @@
 	<see>tcsd(8)</see>
     </event>
 
+<!-- hotplug events recorded by hotplugd(1m) -->
+
+    <event id="AUE_hotplug_state" header="0" idNo="117" omit="JNI">
+        <title>change hotplug connection state</title>
+        <program>/usr/lib/hotplugd</program>
+        <see>hotplugd(1M)</see>
+	<entry id="subject">
+	    <internal token="subject"/>
+	    <external opt="none"/>
+	</entry>
+	<entry id="auth_used">
+	    <internal token="uauth"/>
+	    <external opt="required" type="char *"/>
+	    <comment>authorization used</comment>
+	</entry>
+        <entry id="device_path">
+            <internal token="path"/>
+            <external opt="required" type="char *"/>
+            <comment>device path</comment>
+        </entry>
+        <entry id="connection">
+            <internal token="text"/>
+            <external opt="required" type="char *"/>
+            <comment>connector or port</comment>
+        </entry>
+        <entry id="new_state">
+            <internal token="text"/>
+            <external opt="required" type="char *"/>
+            <comment>new connection state</comment>
+        </entry>
+        <entry id="old_state">
+            <internal token="text"/>
+            <external opt="required" type="char *"/>
+            <comment>old connection state</comment>
+        </entry>
+	<entry id="return">
+	    <internal token="return"/>
+	    <external opt="none"/>
+	</entry>
+    </event>
+
+    <event id="AUE_hotplug_set" header="0" idNo="118" omit="JNI">
+        <title>set hotplug bus private options</title>
+        <program>/usr/lib/hotplugd</program>
+        <see>hotplugd(1M)</see>
+	<entry id="subject">
+	    <internal token="subject"/>
+	    <external opt="none"/>
+	</entry>
+	<entry id="auth_used">
+	    <internal token="uauth"/>
+	    <external opt="required" type="char *"/>
+	    <comment>authorization used</comment>
+	</entry>
+        <entry id="device_path">
+            <internal token="path"/>
+            <external opt="required" type="char *"/>
+            <comment>device path</comment>
+        </entry>
+        <entry id="connection">
+            <internal token="text"/>
+            <external opt="required" type="char *"/>
+            <comment>connector or port</comment>
+        </entry>
+        <entry id="options">
+            <internal token="text"/>
+            <external opt="required" type="char *"/>
+            <comment>bus private options</comment>
+        </entry>
+	<entry id="return">
+	    <internal token="return"/>
+	    <external opt="none"/>
+	</entry>
+    </event>
+
 <!-- add new events here with the next higher idNo -->
-<!-- Highest idNo is 116, so next is 117, then fix this comment -->
+<!-- Highest idNo is 119, so next is 120, then fix this comment -->
 <!-- end of C Only events -->
 
 <!--
--- a/usr/src/lib/libcfgadm/common/config_admin.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/lib/libcfgadm/common/config_admin.c	Mon Nov 02 15:58:28 2009 +0800
@@ -22,12 +22,10 @@
 /* Portions Copyright 2005 Cyril Plisko */
 
 /*
- * 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 <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -177,6 +175,7 @@
 	stat_data_list_t *sdl;	/* Linked list of stat structures */
 	array_list_t *al;	/* Linked list of arrays of list structures */
 	vers_req_t use_vers;	/* plugin versions to be stat'ed */
+	char *shp_errstr;	/* only for shp plugin */
 } list_stat_t;
 
 /*
@@ -205,13 +204,24 @@
 static cfga_err_t resolve_lib_ref(plugin_lib_t *, lib_loc_t *);
 static cfga_err_t config_get_lib(const char *, lib_loc_t *, char **);
 static int check_ap(di_node_t, di_minor_t, void *);
+static int check_ap_hp(di_node_t, di_hp_t, void *);
+static int check_ap_impl(di_node_t, di_minor_t, di_hp_t, void *);
 static int check_ap_phys(di_node_t, di_minor_t, void *);
+static int check_ap_phys_hp(di_node_t, di_hp_t, void *);
+static int check_ap_phys_impl(di_node_t, di_minor_t, di_hp_t, void *);
 
 static cfga_err_t find_ap_common(lib_loc_t *libloc_p, const char *rootpath,
-    int (*fcn)(di_node_t node, di_minor_t minor, void *arg), char **errstring);
+    int (*fcn)(di_node_t node, di_minor_t minor, void *arg),
+    int (*fcn_hp)(di_node_t node, di_hp_t hp, void *arg),
+    char **errstring);
 
 static plugin_lib_t *lib_in_list(char *);
+static cfga_err_t find_lib(di_node_t, di_minor_t, lib_loc_t *);
+static cfga_err_t find_lib_hp(di_node_t, di_hp_t, lib_loc_t *);
+static cfga_err_t find_lib_impl(char *, lib_loc_t *);
 static cfga_err_t load_lib(di_node_t, di_minor_t, lib_loc_t *);
+static cfga_err_t load_lib_hp(di_node_t, di_hp_t, lib_loc_t *);
+static cfga_err_t load_lib_impl(di_node_t, di_minor_t, di_hp_t, lib_loc_t *);
 extern void bcopy(const void *, void *, size_t);
 static void config_err(int, int, char **);
 static void hold_lib(plugin_lib_t *);
@@ -222,6 +232,9 @@
 
 static cfga_err_t list_common(list_stat_t *lstatp, const char *class);
 static int do_list_common(di_node_t node, di_minor_t minor, void *arg);
+static int do_list_common_hp(di_node_t node, di_hp_t hp, void *arg);
+static int do_list_common_impl(di_node_t node, di_minor_t minor,
+    di_hp_t hp, void *arg);
 static cfga_err_t stat_common(int num_ap_ids, char *const *ap_ids,
     const char *class, list_stat_t *lstatp);
 
@@ -575,6 +588,7 @@
 	lstat.countp = &nstat;
 	lstat.opts = options;
 	lstat.errstr = errstring;
+	lstat.shp_errstr = NULL;
 	/*
 	 * This is a V1 interface which can use only V1 plugins
 	 */
@@ -611,6 +625,7 @@
 	lstat.countp = &nstat;
 	lstat.opts = options;
 	lstat.errstr = errstring;
+	lstat.shp_errstr = NULL;
 	/*
 	 * This is a V1 interface which can use only V1 plugins
 	 */
@@ -683,6 +698,7 @@
 	lstat.countp = &nstat;
 	lstat.opts = options;
 	lstat.errstr = errstring;
+	lstat.shp_errstr = NULL;
 	lstat.flags = flags;
 	/*
 	 * We support both V1 and V2 plugins through this entry
@@ -1127,6 +1143,35 @@
 }
 
 /*
+ * mklog_common - make a logical name from the driver and instance
+ */
+/*ARGSUSED*/
+static cfga_err_t
+mklog_hp(
+	di_node_t node,
+	di_hp_t hp,
+	plugin_lib_t *libp,
+	lib_loc_t *liblocp)
+{
+	const size_t len = CFGA_LOG_EXT_LEN;
+	int inst;
+	char *drv, *hp_name;
+
+	drv = di_driver_name(node);
+	inst = di_instance(node);
+	hp_name = di_hp_name(hp);
+
+	errno = 0;
+	if (drv != NULL && inst != -1 && hp_name != NULL &&
+	    snprintf(liblocp->ap_logical, len, "%s%d:%s", drv, inst,
+	    hp_name) < len) {	/* snprintf returns strlen */
+		return (CFGA_OK);
+	}
+
+	return (CFGA_LIB_ERROR);
+}
+
+/*
  * resolve_lib_ref - relocate to use plugin lib
  */
 static cfga_err_t
@@ -1352,6 +1397,9 @@
 	/*
 	 * find and load the library
 	 * The base component of the ap_id is used to locate the plug-in
+	 *
+	 * NOTE that PCIE/PCISHPC connectors also have minor nodes &
+	 * dev links created for now.
 	 */
 	if ((type = find_arg_type(lib_loc_p->ap_base)) == PHYSICAL_AP) {
 		/*
@@ -1360,14 +1408,15 @@
 		 * ap_id.
 		 */
 		ret = find_ap_common(lib_loc_p, lib_loc_p->ap_base,
-		    check_ap_phys, errstring);
+		    check_ap_phys, check_ap_phys_hp, errstring);
 	} else if ((type == LOGICAL_DRV_AP) ||
 	    (type == AP_TYPE && dyncomp == NULL)) {
 		/*
 		 * logical ap_id or ap_type: Use "/" as root for tree walk
 		 * Note: an aptype cannot have a dynamic component
 		 */
-		ret = find_ap_common(lib_loc_p, "/", check_ap, errstring);
+		ret = find_ap_common(lib_loc_p, "/", check_ap,
+		    check_ap_hp, errstring);
 	} else {
 		ret = CFGA_APID_NOEXIST;
 	}
@@ -1418,20 +1467,49 @@
 	return (ret);
 }
 
-
-/*
- * load_lib - Given a library pathname, create a entry for it
- * in the library list, if one does not already exist, and read
- * lock it to keep it there.
- */
+/* load_lib - load library for non-SHP attachment point node */
 static cfga_err_t
 load_lib(
 	di_node_t node,
 	di_minor_t minor,
 	lib_loc_t *libloc_p)
 {
+	return (load_lib_impl(node, minor, NULL, libloc_p));
+}
+
+/* load_lib_hp - load library for SHP attachment point node */
+static cfga_err_t
+load_lib_hp(
+	di_node_t node,
+	di_hp_t hp,
+	lib_loc_t *libloc_p)
+{
+	return (load_lib_impl(node, NULL, hp, libloc_p));
+}
+
+/*
+ * load_lib_impl - Given a library pathname, create a entry for it
+ * in the library list, * if one does not already exist, and read
+ * lock it to keep it there.
+ */
+static cfga_err_t
+load_lib_impl(
+	di_node_t node,
+	di_minor_t minor,
+	di_hp_t hp,
+	lib_loc_t *libloc_p)
+{
 	plugin_lib_t *libp, *list_libp;
 	char *devfs_path;
+	char *name;
+
+	if (minor != DI_MINOR_NIL && hp != DI_HP_NIL)
+		return (CFGA_LIB_ERROR);
+
+	if (minor != DI_MINOR_NIL)
+		name = di_minor_name(minor);
+	else
+		name = di_hp_name(hp);
 
 	/*
 	 * lock the library list
@@ -1448,15 +1526,22 @@
 
 		/* fill in logical and physical name in libloc_p */
 		libloc_p->libp = libp = list_libp;
-		if (libp->vers_ops->mklog(node, minor, libp, libloc_p)
-		    != CFGA_OK) {
-			rele_lib(list_libp);
-			return (CFGA_LIB_ERROR);
+		if (minor != DI_MINOR_NIL) {
+			if (libp->vers_ops->mklog(node, minor, libp, libloc_p)
+			    != CFGA_OK) {
+				rele_lib(list_libp);
+				return (CFGA_LIB_ERROR);
+			}
+		} else {
+			if (mklog_hp(node, hp, libp, libloc_p) != CFGA_OK) {
+				rele_lib(list_libp);
+				return (CFGA_LIB_ERROR);
+			}
 		}
 
 		devfs_path = di_devfs_path(node);
 		(void) snprintf(libloc_p->ap_physical, MAXPATHLEN, "%s%s:%s",
-		    DEVICES_DIR, devfs_path, di_minor_name(minor));
+		    DEVICES_DIR, devfs_path, name);
 		di_devfs_path_free(devfs_path);
 
 		return (CFGA_OK);
@@ -1482,12 +1567,23 @@
 		return (CFGA_NO_LIB);
 	}
 
-	if (resolve_lib_ref(libp, libloc_p) != CFGA_OK ||
-	    libp->vers_ops->mklog(node, minor, libp, libloc_p) != CFGA_OK) {
-		(void) mutex_unlock(&plugin_list_lock);
-		(void) dlclose(libp->handle);
-		free(libp);
-		return (CFGA_NO_LIB);
+	if (minor != DI_MINOR_NIL) {
+		if (resolve_lib_ref(libp, libloc_p) != CFGA_OK ||
+		    libp->vers_ops->mklog(node, minor, libp, libloc_p)
+		    != CFGA_OK) {
+			(void) mutex_unlock(&plugin_list_lock);
+			(void) dlclose(libp->handle);
+			free(libp);
+			return (CFGA_NO_LIB);
+		}
+	} else {
+		if (resolve_lib_ref(libp, libloc_p) != CFGA_OK ||
+		    mklog_hp(node, hp, libp, libloc_p) != CFGA_OK) {
+			(void) mutex_unlock(&plugin_list_lock);
+			(void) dlclose(libp->handle);
+			free(libp);
+			return (CFGA_NO_LIB);
+		}
 	}
 
 	/*
@@ -1511,7 +1607,7 @@
 	libloc_p->libp = libp;
 	devfs_path = di_devfs_path(node);
 	(void) snprintf(libloc_p->ap_physical, MAXPATHLEN, "%s%s:%s",
-	    DEVICES_DIR, devfs_path, di_minor_name(minor));
+	    DEVICES_DIR, devfs_path, name);
 	di_devfs_path_free(devfs_path);
 
 	return (CFGA_OK);
@@ -1521,8 +1617,7 @@
 #define	NUM_LIB_NAMES   2
 
 /*
- * find_lib - Given an attachment point node find it's library
- *
+ * find_lib - find library for non-SHP attachment point node
  */
 static cfga_err_t
 find_lib(
@@ -1530,34 +1625,13 @@
 	di_minor_t minor,
 	lib_loc_t *libloc_p)
 {
-	char lib[MAXPATHLEN];
 	char name[NUM_LIB_NAMES][MAXPATHLEN];
-	struct stat lib_stat;
-	void *dlhandle = NULL;
-	static char plat_name[SYSINFO_LENGTH];
-	static char machine_name[SYSINFO_LENGTH];
-	static char arch_name[SYSINFO_LENGTH];
-	int i = 0;
 	char *class = NULL, *drv = NULL;
+	int i;
 
 
 	/* Make sure pathname and class is null if we fail */
-	*libloc_p->ap_class = *libloc_p->pathname = *lib = '\0';
-
-	/*
-	 * Initialize machine name and arch name
-	 */
-	if (strncmp("", machine_name, MAXPATHLEN) == 0) {
-		if (sysinfo(SI_PLATFORM, plat_name, SYSINFO_LENGTH) == -1) {
-			return (CFGA_ERROR);
-		}
-		if (sysinfo(SI_ARCHITECTURE, arch_name, SYSINFO_LENGTH) == -1) {
-			return (CFGA_ERROR);
-		}
-		if (sysinfo(SI_MACHINE, machine_name, SYSINFO_LENGTH) == -1) {
-			return (CFGA_ERROR);
-		}
-	}
+	*libloc_p->ap_class = *libloc_p->pathname = '\0';
 
 	/*
 	 * Initialize possible library tags.
@@ -1584,72 +1658,174 @@
 			continue;
 		}
 
-		/*
-		 * Try path based upon platform name
-		 */
-		(void) snprintf(lib, sizeof (lib), "%s%s%s%s%s",
-		    LIB_PATH_BASE1, plat_name, LIB_PATH_MIDDLE,
-		    name[i], LIB_PATH_TAIL);
-
-		if (stat(lib, &lib_stat) == 0) {
-			/* file exists, is it a lib */
-			dlhandle = dlopen(lib, RTLD_LAZY);
-			if (dlhandle != NULL) {
-				goto found;
-			}
-		}
-
-		/*
-		 * Try path based upon machine name
-		 */
-		(void) snprintf(lib, sizeof (lib), "%s%s%s%s%s",
-		    LIB_PATH_BASE1, machine_name, LIB_PATH_MIDDLE,
-		    name[i], LIB_PATH_TAIL);
-
-
-		if (stat(lib, &lib_stat) == 0) {
-			/* file exists, is it a lib */
-			dlhandle = dlopen(lib, RTLD_LAZY);
-			if (dlhandle != NULL) {
-				goto found;
-			}
+		if (find_lib_impl(name[i], libloc_p) == CFGA_OK)
+			goto found;
+	}
+
+	return (CFGA_NO_LIB);
+
+found:
+
+	/* Record class name (if any) */
+	(void) snprintf(libloc_p->ap_class, sizeof (libloc_p->ap_class), "%s",
+	    class);
+
+	return (CFGA_OK);
+}
+
+/*
+ * find_lib_hp - find library for SHP attachment point
+ */
+/*ARGSUSED*/
+static cfga_err_t
+find_lib_hp(
+	di_node_t node,
+	di_hp_t hp,
+	lib_loc_t *libloc_p)
+{
+	char name[MAXPATHLEN];
+	char *class = NULL;
+
+
+	/* Make sure pathname and class is null if we fail */
+	*libloc_p->ap_class = *libloc_p->pathname = '\0';
+
+	/*
+	 * Initialize possible library tags.
+	 *
+	 * Only support PCI class for now, this will need to be
+	 * changed as other plugins are migrated to SHP plugin.
+	 */
+	class = "pci";
+#if 0
+	/*
+	 * No type check for now as PCI is the only class SHP plugin
+	 * supports. In the future we'll need to enable the type check
+	 * and set class accordingly, when non PCI plugins are migrated
+	 * to SHP. In that case we'll probably need to add an additional
+	 * interface between libcfgadm and the plugins, and SHP plugin will
+	 * implement this interface which will translate the bus specific
+	 * strings to standard classes that libcfgadm can recognize, for
+	 * all the buses it supports, e.g. for pci/pcie it will translate
+	 * PCIE_NATIVE_HP_TYPE to string "pci". We'll also need to bump up
+	 * SHP plugin version to 3 to use the new interface.
+	 */
+	class = di_hp_type(hp);
+	if ((strcmp(class, PCIE_NATIVE_HP_TYPE) == 0) ||
+	    (strcmp(class, PCIE_ACPI_HP_TYPE) == 0) ||
+	    (strcmp(class, PCIE_PCI_HP_TYPE) == 0)) {
+		class = "pci";
+	} else {
+		goto fail;
+	}
+#endif
+	(void) snprintf(&name[0], sizeof (name), "%s", "shp");
+
+	if (find_lib_impl(name, libloc_p) == CFGA_OK)
+		goto found;
+fail:
+	return (CFGA_NO_LIB);
+
+found:
+
+	/* Record class name (if any) */
+	(void) snprintf(libloc_p->ap_class, sizeof (libloc_p->ap_class), "%s",
+	    class);
+
+	return (CFGA_OK);
+}
+
+/*
+ * find_lib_impl - Given an attachment point node find it's library
+ */
+static cfga_err_t
+find_lib_impl(
+	char *name,
+	lib_loc_t *libloc_p)
+{
+	char lib[MAXPATHLEN];
+	struct stat lib_stat;
+	void *dlhandle = NULL;
+	static char plat_name[SYSINFO_LENGTH];
+	static char machine_name[SYSINFO_LENGTH];
+	static char arch_name[SYSINFO_LENGTH];
+
+	/*
+	 * Initialize machine name and arch name
+	 */
+	if (strncmp("", machine_name, MAXPATHLEN) == 0) {
+		if (sysinfo(SI_PLATFORM, plat_name, SYSINFO_LENGTH) == -1) {
+			return (CFGA_ERROR);
 		}
-
-		/*
-		 * Try path based upon arch name
-		 */
-		(void) snprintf(lib, sizeof (lib), "%s%s%s%s%s",
-		    LIB_PATH_BASE1, arch_name, LIB_PATH_MIDDLE,
-		    name[i], LIB_PATH_TAIL);
-
-		if (stat(lib, &lib_stat) == 0) {
-			/* file exists, is it a lib */
-			dlhandle = dlopen(lib, RTLD_LAZY);
-			if (dlhandle != NULL) {
-				goto found;
-			}
-
+		if (sysinfo(SI_ARCHITECTURE, arch_name, SYSINFO_LENGTH) == -1) {
+			return (CFGA_ERROR);
 		}
-
-		/*
-		 * Try generic location
-		 */
-		(void) snprintf(lib, sizeof (lib), "%s%s%s%s",
-		    LIB_PATH_BASE2, LIB_PATH_MIDDLE, name[i], LIB_PATH_TAIL);
-
-
-
-		if (stat(lib, &lib_stat) == 0) {
-			/* file exists, is it a lib */
-			dlhandle = dlopen(lib, RTLD_LAZY);
-			if (dlhandle != NULL) {
-				goto found;
-			}
-
+		if (sysinfo(SI_MACHINE, machine_name, SYSINFO_LENGTH) == -1) {
+			return (CFGA_ERROR);
 		}
 	}
 
-
+	/*
+	 * Try path based upon platform name
+	 */
+	(void) snprintf(lib, sizeof (lib), "%s%s%s%s%s",
+	    LIB_PATH_BASE1, plat_name, LIB_PATH_MIDDLE,
+	    name, LIB_PATH_TAIL);
+
+	if (stat(lib, &lib_stat) == 0) {
+		/* file exists, is it a lib */
+		dlhandle = dlopen(lib, RTLD_LAZY);
+		if (dlhandle != NULL) {
+			goto found;
+		}
+	}
+
+	/*
+	 * Try path based upon machine name
+	 */
+	(void) snprintf(lib, sizeof (lib), "%s%s%s%s%s",
+	    LIB_PATH_BASE1, machine_name, LIB_PATH_MIDDLE,
+	    name, LIB_PATH_TAIL);
+
+
+	if (stat(lib, &lib_stat) == 0) {
+		/* file exists, is it a lib */
+		dlhandle = dlopen(lib, RTLD_LAZY);
+		if (dlhandle != NULL) {
+			goto found;
+		}
+	}
+
+	/*
+	 * Try path based upon arch name
+	 */
+	(void) snprintf(lib, sizeof (lib), "%s%s%s%s%s",
+	    LIB_PATH_BASE1, arch_name, LIB_PATH_MIDDLE,
+	    name, LIB_PATH_TAIL);
+
+	if (stat(lib, &lib_stat) == 0) {
+		/* file exists, is it a lib */
+		dlhandle = dlopen(lib, RTLD_LAZY);
+		if (dlhandle != NULL) {
+			goto found;
+		}
+
+	}
+
+	/*
+	 * Try generic location
+	 */
+	(void) snprintf(lib, sizeof (lib), "%s%s%s%s",
+	    LIB_PATH_BASE2, LIB_PATH_MIDDLE, name, LIB_PATH_TAIL);
+
+	if (stat(lib, &lib_stat) == 0) {
+		/* file exists, is it a lib */
+		dlhandle = dlopen(lib, RTLD_LAZY);
+		if (dlhandle != NULL) {
+			goto found;
+		}
+
+	}
 	return (CFGA_NO_LIB);
 
 found:
@@ -1659,10 +1835,6 @@
 
 	(void) dlclose(dlhandle);
 
-	/* Record class name (if any) */
-	(void) snprintf(libloc_p->ap_class, sizeof (libloc_p->ap_class), "%s",
-	    class);
-
 	return (CFGA_OK);
 }
 
@@ -1746,6 +1918,7 @@
 	lib_loc_t *libloc_p,
 	const char *physpath,
 	int (*fcn)(di_node_t node, di_minor_t minor, void *arg),
+	int (*fcn_hp)(di_node_t node, di_hp_t hp, void *arg),
 	char **errstring)
 {
 	di_node_t rnode, wnode;
@@ -1781,37 +1954,84 @@
 
 	/*
 	 * begin walk of device tree
+	 *
+	 * Since we create minor nodes & dev links for both all PCI/PCIE
+	 * connectors, but only create hp nodes for PCIE/PCISHPC connectors
+	 * of the new framework, we should first match with hp nodes. If
+	 * the ap_id refers to a PCIE/PCISHPC connector, we'll be able to
+	 * find it here.
 	 */
-	rnode = di_init("/", DINFOCACHE);
+	rnode = di_init("/", DINFOSUBTREE | DINFOHP);
 	if (rnode)
 		wnode = di_lookup_node(rnode, rpath);
 	else
 		wnode = DI_NODE_NIL;
-	S_FREE(rpath);
 
 	if (wnode == DI_NODE_NIL) {
 		if (rnode == DI_NODE_NIL) {
+			S_FREE(rpath);
 			config_err(errno, DI_INIT_FAILED, errstring);
 			return (CFGA_LIB_ERROR);
 		} else {
 			/*
-			 * di_lookup_node() may fail because the ap_id
-			 * does not exist
+			 * di_lookup_node() may fail, either because the
+			 * ap_id does not exist, or because the ap_id refers
+			 * to a legacy PCI slot, thus we'll not able to
+			 * find node using DINFOHP, try to see if we can
+			 * find one using DINFOCACHE.
 			 */
 			di_fini(rnode);
-			return (CFGA_APID_NOEXIST);
+			goto find_minor;
 		}
 	}
 
 	libloc_p->libp = NULL;
 	libloc_p->status = CFGA_APID_NOEXIST;
 
-	(void) di_walk_minor(wnode, "ddi_ctl:attachment_point",
-	    DI_CHECK_ALIAS|DI_CHECK_INTERNAL_PATH,
-	    libloc_p, fcn);
+	(void) di_walk_hp(wnode, NULL, DI_HP_CONNECTOR,
+	    libloc_p, fcn_hp);
 
 	di_fini(rnode);
 
+	/*
+	 * Failed to find a matching hp node, try minor node.
+	 */
+	if (libloc_p->libp == NULL) {
+find_minor:
+		rnode = di_init("/", DINFOCACHE);
+		if (rnode)
+			wnode = di_lookup_node(rnode, rpath);
+		else
+			wnode = DI_NODE_NIL;
+
+		if (wnode == DI_NODE_NIL) {
+			if (rnode == DI_NODE_NIL) {
+				S_FREE(rpath);
+				config_err(errno, DI_INIT_FAILED, errstring);
+				return (CFGA_LIB_ERROR);
+			} else {
+				/*
+				 * di_lookup_node() may fail, because the
+				 * ap_id does not exist.
+				 */
+				S_FREE(rpath);
+				di_fini(rnode);
+				return (CFGA_APID_NOEXIST);
+			}
+		}
+
+		libloc_p->libp = NULL;
+		libloc_p->status = CFGA_APID_NOEXIST;
+
+		(void) di_walk_minor(wnode, "ddi_ctl:attachment_point",
+		    DI_CHECK_ALIAS|DI_CHECK_INTERNAL_PATH,
+		    libloc_p, fcn);
+
+		di_fini(rnode);
+	}
+
+	S_FREE(rpath);
+
 	if (libloc_p->libp != NULL) {
 		update_cache(libloc_p);
 		return (CFGA_OK);
@@ -1821,18 +2041,42 @@
 }
 
 /*
- * check_ap - called for each attachment point found
+ * check_ap - called for each non-SHP attachment point found
+ */
+static int
+check_ap(
+	di_node_t node,
+	di_minor_t minor,
+	void *arg)
+{
+	return (check_ap_impl(node, minor, NULL, arg));
+}
+
+/*
+ * check_ap_hp - called for each SHP attachment point found
+ */
+static int
+check_ap_hp(
+	di_node_t node,
+	di_hp_t hp,
+	void *arg)
+{
+	return (check_ap_impl(node, NULL, hp, arg));
+}
+
+/*
+ * check_ap_impl - called for each attachment point found
  *
  * This is used in cases where a particular attachment point
  * or type of attachment point is specified via a logical name or ap_type.
  * Not used for physical names or in the list case with no
  * ap's specified.
  */
-
 static int
-check_ap(
+check_ap_impl(
 	di_node_t node,
 	di_minor_t minor,
+	di_hp_t hp,
 	void *arg)
 {
 	char *cp = NULL;
@@ -1847,6 +2091,8 @@
 	int instance;
 	cfga_ap_types_t type;
 
+	if (minor != DI_MINOR_NIL && hp != DI_HP_NIL)
+		return (DI_WALK_CONTINUE);
 
 	libloc_p = (lib_loc_t *)arg;
 
@@ -1873,7 +2119,11 @@
 		return (DI_WALK_CONTINUE);
 	}
 
-	node_minor = di_minor_name(minor);
+	if (minor != DI_MINOR_NIL)
+		node_minor = di_minor_name(minor);
+	else
+		node_minor = di_hp_name(hp);
+
 	drv_name = di_driver_name(node);
 	instance = di_instance(node);
 
@@ -1910,13 +2160,24 @@
 		/*
 		 * save the correct type of error so user does not get confused
 		 */
-		if (find_lib(node, minor, libloc_p) != CFGA_OK) {
-			libloc_p->status = CFGA_NO_LIB;
-			return (DI_WALK_CONTINUE);
-		}
-		if (load_lib(node, minor, libloc_p) != CFGA_OK) {
-			libloc_p->status = CFGA_LIB_ERROR;
-			return (DI_WALK_CONTINUE);
+		if (minor != DI_MINOR_NIL) {
+			if (find_lib(node, minor, libloc_p) != CFGA_OK) {
+				libloc_p->status = CFGA_NO_LIB;
+				return (DI_WALK_CONTINUE);
+			}
+			if (load_lib(node, minor, libloc_p) != CFGA_OK) {
+				libloc_p->status = CFGA_LIB_ERROR;
+				return (DI_WALK_CONTINUE);
+			}
+		} else {
+			if (find_lib_hp(node, hp, libloc_p) != CFGA_OK) {
+				libloc_p->status = CFGA_NO_LIB;
+				return (DI_WALK_CONTINUE);
+			}
+			if (load_lib_hp(node, hp, libloc_p) != CFGA_OK) {
+				libloc_p->status = CFGA_LIB_ERROR;
+				return (DI_WALK_CONTINUE);
+			}
 		}
 		libloc_p->status = CFGA_OK;
 		return (DI_WALK_TERMINATE);
@@ -1928,27 +2189,57 @@
 
 
 /*
- * check_ap_phys - called for each attachment point found
- *
- * This is used in cases where a particular attachment point
- * is specified via a physical name. If the name matches then
- * we try and find and load the library for it.
+ * check_ap_phys - called for each non-SHP attachment point found
  */
-
 static int
 check_ap_phys(
 	di_node_t node,
 	di_minor_t minor,
 	void *arg)
 {
+	return (check_ap_phys_impl(node, minor, DI_HP_NIL, arg));
+}
+
+/*
+ * check_ap_phys_hp - called for each SHP attachment point found
+ */
+static int
+check_ap_phys_hp(
+	di_node_t node,
+	di_hp_t hp,
+	void *arg)
+{
+	return (check_ap_phys_impl(node, DI_HP_NIL, hp, arg));
+}
+
+/*
+ * check_ap_phys_impl - called for each attachment point found
+ *
+ * This is used in cases where a particular attachment point
+ * is specified via a physical name. If the name matches then
+ * we try and find and load the library for it.
+ */
+static int
+check_ap_phys_impl(
+	di_node_t node,
+	di_minor_t minor,
+	di_hp_t hp,
+	void *arg)
+{
 	lib_loc_t *libloc_p;
 	char phys_name[MAXPATHLEN];
 	char *devfs_path;
 	char *minor_name;
 
+	if (minor != DI_MINOR_NIL && hp != DI_HP_NIL)
+		return (DI_WALK_CONTINUE);
+
 	libloc_p = (lib_loc_t *)arg;
 	devfs_path = di_devfs_path(node);
-	minor_name = di_minor_name(minor);
+	if (minor != DI_MINOR_NIL)
+		minor_name = di_minor_name(minor);
+	else
+		minor_name = di_hp_name(hp);
 
 	if (devfs_path == NULL || minor_name == NULL) {
 		libloc_p->status = CFGA_APID_NOEXIST;
@@ -1961,14 +2252,26 @@
 	di_devfs_path_free(devfs_path);
 
 	if (strcmp(phys_name, libloc_p->ap_base) == 0) {
-		if (find_lib(node, minor, libloc_p) != CFGA_OK) {
-			libloc_p->status = CFGA_NO_LIB;
-			return (DI_WALK_CONTINUE);
+		if (minor != DI_MINOR_NIL) {
+			if (find_lib(node, minor, libloc_p) != CFGA_OK) {
+				libloc_p->status = CFGA_NO_LIB;
+				return (DI_WALK_CONTINUE);
+			}
+			if (load_lib(node, minor, libloc_p) != CFGA_OK) {
+				libloc_p->status = CFGA_LIB_ERROR;
+				return (DI_WALK_CONTINUE);
+			}
+		} else {
+			if (find_lib_hp(node, hp, libloc_p) != CFGA_OK) {
+				libloc_p->status = CFGA_NO_LIB;
+				return (DI_WALK_CONTINUE);
+			}
+			if (load_lib_hp(node, hp, libloc_p) != CFGA_OK) {
+				libloc_p->status = CFGA_LIB_ERROR;
+				return (DI_WALK_CONTINUE);
+			}
 		}
-		if (load_lib(node, minor, libloc_p) != CFGA_OK) {
-			libloc_p->status = CFGA_LIB_ERROR;
-			return (DI_WALK_CONTINUE);
-		}
+
 		libloc_p->status = CFGA_OK;
 		return (DI_WALK_TERMINATE);
 	} else {
@@ -2167,15 +2470,6 @@
 	char nodetype[MAXPATHLEN];
 	const char *l_class, *l_sep;
 
-
-	/*
-	 * begin walk of device tree
-	 */
-	if ((rnode = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
-		config_err(errno, DI_INIT_FAILED, lstatp->errstr);
-		return (CFGA_LIB_ERROR);
-	}
-
 	/*
 	 * May walk a subset of all attachment points in the device tree if
 	 * a class is specified
@@ -2190,10 +2484,38 @@
 	(void) snprintf(nodetype, sizeof (nodetype), "%s%s%s",
 	    DDI_NT_ATTACHMENT_POINT, l_sep, l_class);
 
+	/*
+	 * Walk all hp nodes
+	 */
+	if ((rnode = di_init("/", DINFOSUBTREE | DINFOHP)) == DI_NODE_NIL) {
+		config_err(errno, DI_INIT_FAILED, lstatp->errstr);
+		return (CFGA_LIB_ERROR);
+	}
+	/* No need to filter on class for now */
+	(void) di_walk_hp(rnode, NULL, DI_HP_CONNECTOR,
+	    lstatp, do_list_common_hp);
+
+	di_fini(rnode);
+
+	/*
+	 * Walk all minor nodes
+	 * but exclude PCIE/PCIESHPC connectors which have been walked above.
+	 */
+	if ((rnode = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
+		config_err(errno, DI_INIT_FAILED, lstatp->errstr);
+		return (CFGA_LIB_ERROR);
+	}
 	(void) di_walk_minor(rnode, nodetype,
 	    DI_CHECK_ALIAS|DI_CHECK_INTERNAL_PATH, lstatp, do_list_common);
+
 	di_fini(rnode);
 
+	if (lstatp->shp_errstr != NULL) {
+		*(lstatp->errstr) = strdup(lstatp->shp_errstr);
+		free(lstatp->shp_errstr);
+		lstatp->shp_errstr = NULL;
+	}
+
 	return (CFGA_OK);
 }
 
@@ -2245,11 +2567,7 @@
 }
 
 /*
- * do_list_common - Routine to list attachment point as part of
- * a config_list opertion. Used by both v1 and v2 interfaces.
- * This is somewhat similar to config_get_lib() and its helper routines
- * except that the ap_ids are always physical and don't have dynamic
- * components.
+ * do_list_common - list non-SHP attachment point
  */
 static int
 do_list_common(
@@ -2257,11 +2575,67 @@
 	di_minor_t minor,
 	void *arg)
 {
+	di_node_t rnode;
+	di_hp_t hp;
+	char *minor_name;
+
+	minor_name = di_minor_name(minor);
+
+	/*
+	 * since PCIE/PCIHSHPC connectors have both hp nodes and minor nodes
+	 * created for now, we need to specifically exclude these connectors
+	 * during walking minor nodes.
+	 */
+	if ((rnode = di_init(di_devfs_path(node), DINFOSUBTREE | DINFOHP))
+	    == DI_NODE_NIL) {
+		return (DI_WALK_CONTINUE);
+	}
+
+	for (hp = DI_HP_NIL; (hp = di_hp_next(rnode, hp)) != DI_HP_NIL; ) {
+		if (strcmp(di_hp_name(hp), minor_name) == 0) {
+			di_fini(rnode);
+			return (DI_WALK_CONTINUE);
+		}
+	}
+
+	di_fini(rnode);
+
+	return (do_list_common_impl(node, minor, NULL, arg));
+}
+
+/*
+ * do_list_common_hp - list SHP attachment point
+ */
+static int
+do_list_common_hp(
+	di_node_t node,
+	di_hp_t hp,
+	void *arg)
+{
+	return (do_list_common_impl(node, NULL, hp, arg));
+}
+
+/*
+ * do_list_common_impl - Routine to list attachment point as part of
+ * a config_list opertion. Used by both v1 and v2 interfaces.
+ * This is somewhat similar to config_get_lib() and its helper routines
+ * except that the ap_ids are always physical and don't have dynamic
+ * components.
+ */
+static int
+do_list_common_impl(
+	di_node_t node,
+	di_minor_t minor,
+	di_hp_t hp,
+	void *arg)
+{
 	lib_loc_t lib_loc;
 	plugin_lib_t *libp;
 	list_stat_t *lstatp = NULL;
 	cfga_err_t ret = CFGA_ERROR;
 
+	if (minor != DI_MINOR_NIL && hp != DI_HP_NIL)
+		return (DI_WALK_CONTINUE);
 
 	lstatp = (list_stat_t *)arg;
 
@@ -2269,7 +2643,12 @@
 	/*
 	 * try and find a lib for this node
 	 */
-	if (find_lib(node, minor, &lib_loc) != CFGA_OK) {
+	if (minor != DI_MINOR_NIL) {
+		ret = find_lib(node, minor, &lib_loc);
+	} else {
+		ret = find_lib_hp(node, hp, &lib_loc);
+	}
+	if (ret != CFGA_OK) {
 		return (DI_WALK_CONTINUE);
 	}
 
@@ -2280,7 +2659,11 @@
 	lib_loc.vers_req.v_min = CFGA_HSL_V1;
 	lib_loc.vers_req.v_max = CFGA_HSL_VERS;
 
-	ret = load_lib(node, minor, &lib_loc);
+	if (minor != DI_MINOR_NIL) {
+		ret = load_lib(node, minor, &lib_loc);
+	} else {
+		ret = load_lib_hp(node, hp, &lib_loc);
+	}
 	if (ret != CFGA_OK) {
 		return (DI_WALK_CONTINUE);
 	}
@@ -2294,7 +2677,32 @@
 	 * stop the walk if an error occurs in the plugin.
 	 */
 	if (compat_plugin(&lstatp->use_vers, libp->plugin_vers)) {
-		(void) libp->vers_ops->stat_plugin(lstatp, &lib_loc, NULL);
+		if (minor != DI_MINOR_NIL) {
+			(void) libp->vers_ops->stat_plugin(lstatp,
+			    &lib_loc, NULL);
+		} else {
+			/*
+			 * If the underlying hotplug daemon is not enabled,
+			 * the SHP attach points will not be shown, this
+			 * could confuse the uesrs. We specifically pass the
+			 * errstring to SHP plugin so that it can set the
+			 * errstring accordingly in this case, giving users
+			 * a hint.
+			 */
+			ret = libp->vers_ops->stat_plugin(lstatp,
+			    &lib_loc, lstatp->errstr);
+			if (ret == CFGA_NOTSUPP && *(lstatp->errstr) != NULL) {
+				if (lstatp->shp_errstr == NULL) {
+					lstatp->shp_errstr =
+					    strdup(*(lstatp->errstr));
+				}
+			}
+
+			if (*(lstatp->errstr) != NULL) {
+				free(*(lstatp->errstr));
+				*(lstatp->errstr) = NULL;
+			}
+		}
 	}
 	rele_lib(libp);
 
--- a/usr/src/lib/libdevinfo/devinfo.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/lib/libdevinfo/devinfo.c	Mon Nov 02 15:58:28 2009 +0800
@@ -44,6 +44,7 @@
 #include <sys/time.h>
 #include <sys/autoconf.h>
 #include <stdarg.h>
+#include <sys/ddi_hp.h>
 
 #define	NDEBUG 1
 #include <assert.h>
@@ -2522,6 +2523,284 @@
 }
 
 /*
+ * Hotplug information access
+ */
+
+typedef struct {
+	void		*arg;
+	const char	*type;
+	uint_t		flag;
+	int		(*hp_callback)(di_node_t, di_hp_t, void *);
+} di_walk_hp_arg_t;
+
+static int
+di_walk_hp_callback(di_node_t node, void *argp)
+{
+	di_walk_hp_arg_t 	*arg = (di_walk_hp_arg_t *)argp;
+	di_hp_t			hp;
+	char			*type_str;
+
+	for (hp = DI_HP_NIL; (hp = di_hp_next(node, hp)) != DI_HP_NIL; ) {
+
+		/* Exclude non-matching types if a type filter is specified */
+		if (arg->type != NULL) {
+			type_str = di_hp_description(hp);
+			if (type_str && (strcmp(arg->type, type_str) != 0))
+				continue;
+		}
+
+		/* Exclude ports if DI_HP_PORT flag not specified */
+		if (!(arg->flag & DI_HP_PORT) &&
+		    (di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT))
+			continue;
+
+		/* Exclude connectors if DI_HP_CONNECTOR flag not specified */
+		if (!(arg->flag & DI_HP_CONNECTOR) &&
+		    !(di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT))
+			continue;
+
+		/* Perform callback */
+		if (arg->hp_callback(node, hp, arg->arg) != DI_WALK_CONTINUE)
+			return (DI_WALK_TERMINATE);
+	}
+
+	return (DI_WALK_CONTINUE);
+}
+
+int
+di_walk_hp(di_node_t node, const char *type, uint_t flag, void *arg,
+    int (*hp_callback)(di_node_t node, di_hp_t hp, void *arg))
+{
+	di_walk_hp_arg_t	walk_arg;
+	caddr_t			pa;
+
+#ifdef DEBUG
+	char	*devfspath = di_devfs_path(node);
+	DPRINTF((DI_INFO, "walking hotplug nodes under %s\n", devfspath));
+	di_devfs_path_free(devfspath);
+#endif
+	/*
+	 * paranoid error checking
+	 */
+	if ((node == DI_NODE_NIL) || (hp_callback == NULL)) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	/* check if hotplug data is included in snapshot */
+	pa = (caddr_t)node - DI_NODE(node)->self;
+	if (!(DI_ALL(pa)->command & DINFOHP)) {
+		errno = ENOTSUP;
+		return (-1);
+	}
+
+	walk_arg.arg = arg;
+	walk_arg.type = type;
+	walk_arg.flag = flag;
+	walk_arg.hp_callback = hp_callback;
+	return (di_walk_node(node, DI_WALK_CLDFIRST, &walk_arg,
+	    di_walk_hp_callback));
+}
+
+di_hp_t
+di_hp_next(di_node_t node, di_hp_t hp)
+{
+	caddr_t pa;
+
+	/*
+	 * paranoid error checking
+	 */
+	if (node == DI_NODE_NIL) {
+		errno = EINVAL;
+		return (DI_HP_NIL);
+	}
+
+	/*
+	 * hotplug node is not NIL
+	 */
+	if (hp != DI_HP_NIL) {
+		if (DI_HP(hp)->next != 0)
+			return (DI_HP((caddr_t)hp - hp->self + hp->next));
+		else {
+			errno = ENXIO;
+			return (DI_HP_NIL);
+		}
+	}
+
+	/*
+	 * hotplug node is NIL-->caller asks for first hotplug node
+	 */
+	if (DI_NODE(node)->hp_data != 0) {
+		return (DI_HP((caddr_t)node - DI_NODE(node)->self +
+		    DI_NODE(node)->hp_data));
+	}
+
+	/*
+	 * no hotplug data-->check if snapshot includes hotplug data
+	 *	in order to set the correct errno
+	 */
+	pa = (caddr_t)node - DI_NODE(node)->self;
+	if (DINFOHP & DI_ALL(pa)->command)
+		errno = ENXIO;
+	else
+		errno = ENOTSUP;
+
+	return (DI_HP_NIL);
+}
+
+char *
+di_hp_name(di_hp_t hp)
+{
+	caddr_t pa;
+
+	/*
+	 * paranoid error checking
+	 */
+	if (hp == DI_HP_NIL) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	pa = (caddr_t)hp - DI_HP(hp)->self;
+
+	if (DI_HP(hp)->hp_name == 0) {
+		errno = ENXIO;
+		return (NULL);
+	}
+
+	return ((char *)(pa + DI_HP(hp)->hp_name));
+}
+
+int
+di_hp_connection(di_hp_t hp)
+{
+	/*
+	 * paranoid error checking
+	 */
+	if (hp == DI_HP_NIL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (DI_HP(hp)->hp_connection == -1)
+		errno = ENOENT;
+
+	return (DI_HP(hp)->hp_connection);
+}
+
+int
+di_hp_depends_on(di_hp_t hp)
+{
+	/*
+	 * paranoid error checking
+	 */
+	if (hp == DI_HP_NIL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (DI_HP(hp)->hp_depends_on == -1)
+		errno = ENOENT;
+
+	return (DI_HP(hp)->hp_depends_on);
+}
+
+int
+di_hp_state(di_hp_t hp)
+{
+	/*
+	 * paranoid error checking
+	 */
+	if (hp == DI_HP_NIL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	return (DI_HP(hp)->hp_state);
+}
+
+int
+di_hp_type(di_hp_t hp)
+{
+	/*
+	 * paranoid error checking
+	 */
+	if (hp == DI_HP_NIL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	return (DI_HP(hp)->hp_type);
+}
+
+char *
+di_hp_description(di_hp_t hp)
+{
+	caddr_t pa;
+
+	/*
+	 * paranoid error checking
+	 */
+	if (hp == DI_HP_NIL) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	pa = (caddr_t)hp - DI_HP(hp)->self;
+
+	if (DI_HP(hp)->hp_type_str == 0)
+		return (NULL);
+
+	return ((char *)(pa + DI_HP(hp)->hp_type_str));
+}
+
+di_node_t
+di_hp_child(di_hp_t hp)
+{
+	caddr_t pa;		/* starting address of map */
+
+	/*
+	 * paranoid error checking
+	 */
+	if (hp == DI_HP_NIL) {
+		errno = EINVAL;
+		return (DI_NODE_NIL);
+	}
+
+	pa = (caddr_t)hp - DI_HP(hp)->self;
+
+	if (DI_HP(hp)->hp_child > 0) {
+		return (DI_NODE(pa + DI_HP(hp)->hp_child));
+	}
+
+	/*
+	 * Deal with error condition:
+	 *   Child doesn't exist, figure out if DINFOSUBTREE is set.
+	 *   If it isn't, set errno to ENOTSUP.
+	 */
+	if (!(DINFOSUBTREE & DI_ALL(pa)->command))
+		errno = ENOTSUP;
+	else
+		errno = ENXIO;
+
+	return (DI_NODE_NIL);
+}
+
+time_t
+di_hp_last_change(di_hp_t hp)
+{
+	/*
+	 * paranoid error checking
+	 */
+	if (hp == DI_HP_NIL) {
+		errno = EINVAL;
+		return ((time_t)0);
+	}
+
+	return ((time_t)DI_HP(hp)->hp_last_change);
+}
+
+/*
  * PROM property access
  */
 
--- a/usr/src/lib/libdevinfo/libdevinfo.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/lib/libdevinfo/libdevinfo.h	Mon Nov 02 15:58:28 2009 +0800
@@ -71,6 +71,12 @@
 
 #define	DI_CHECK_MASK		0xf0
 
+/*
+ * flags for di_walk_hp
+ */
+#define	DI_HP_CONNECTOR		0x1
+#define	DI_HP_PORT		0x2
+
 /* nodeid types */
 #define	DI_PSEUDO_NODEID	-1
 #define	DI_SID_NODEID		-2
@@ -106,6 +112,7 @@
 typedef struct di_link		*di_link_t;		/* link */
 typedef struct di_lnode		*di_lnode_t;		/* endpoint */
 typedef struct di_devlink	*di_devlink_t;		/* devlink */
+typedef struct di_hp		*di_hp_t;		/* hotplug */
 
 typedef struct di_prop		*di_prop_t;		/* node property */
 typedef struct di_path_prop	*di_path_prop_t;	/* path property */
@@ -126,6 +133,7 @@
 #define	DI_PROP_NIL		NULL
 #define	DI_PROM_PROP_NIL	NULL
 #define	DI_PROM_HANDLE_NIL	NULL
+#define	DI_HP_NIL		NULL
 
 /*
  * IEEE 1275 properties and other standardized property names
@@ -320,6 +328,23 @@
 extern void		di_lnode_private_set(di_lnode_t lnode, void *data);
 extern void		*di_lnode_private_get(di_lnode_t lnode);
 
+/*
+ * hp_node: traversal, data access, and parameters
+ */
+extern int		di_walk_hp(di_node_t node, const char *type,
+			    uint_t flag, void *arg,
+			    int (*hp_callback)(di_node_t node, di_hp_t hp,
+			    void *arg));
+extern di_hp_t		di_hp_next(di_node_t node, di_hp_t hp);
+
+extern char		*di_hp_name(di_hp_t hp);
+extern int		di_hp_connection(di_hp_t hp);
+extern int		di_hp_depends_on(di_hp_t hp);
+extern int		di_hp_state(di_hp_t hp);
+extern int		di_hp_type(di_hp_t hp);
+extern char		*di_hp_description(di_hp_t hp);
+extern time_t		di_hp_last_change(di_hp_t hp);
+extern di_node_t	di_hp_child(di_hp_t hp);
 
 /*
  * Private interfaces
--- a/usr/src/lib/libdevinfo/mapfile-vers	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/lib/libdevinfo/mapfile-vers	Mon Nov 02 15:58:28 2009 +0800
@@ -199,6 +199,15 @@
 	di_dli_openw;
 	di_driver_private_data;
 	di_flags;
+	di_hp_child;
+	di_hp_connection;
+	di_hp_depends_on;
+	di_hp_description;
+	di_hp_last_change;
+	di_hp_name;
+	di_hp_next;
+	di_hp_state;
+	di_hp_type;
 	di_init_driver;
 	di_init_impl;
 	di_lookup_node;
@@ -238,6 +247,7 @@
 	di_unretire_device;
 	di_vhci_first_node;
 	di_vhci_next_node;
+	di_walk_hp;
 	finddev_close;
 	finddev_emptydir;
 	finddev_next;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libhotplug/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,49 @@
+#
+# 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.lib
+
+SUBDIRS=	$(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all :=		TARGET = all
+clean :=	TARGET = clean
+clobber :=	TARGET = clobber
+install :=	TARGET = install
+lint :=		TARGET = lint
+
+HDRS=		libhotplug.h libhotplug_impl.h
+HDRDIR=		common
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+check: $(CHECKHDRS)
+
+$(SUBDIRS):  FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libhotplug/Makefile.com	Mon Nov 02 15:58:28 2009 +0800
@@ -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.
+#
+
+LIBRARY=	libhotplug.a
+VERS=		.1
+OBJECTS=	libhotplug.o
+
+include ../../Makefile.lib
+
+LIBS =		$(DYNLIB) $(LINTLIB)
+LDLIBS +=	-lc -lnvpair
+
+SRCDIR =	../common
+CPPFLAGS +=	-I$(SRCDIR) -D_REENTRANT
+$(LINTLIB) := SRCS=	$(SRCDIR)/$(LINTSRC)
+
+.KEEP_STATE:
+
+all:	$(LIBS)
+
+lint:	lintcheck
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libhotplug/amd64/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libhotplug/common/libhotplug.c	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,1367 @@
+/*
+ * 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 <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <door.h>
+#include <libnvpair.h>
+#include <libhotplug.h>
+#include <libhotplug_impl.h>
+#include <sys/sunddi.h>
+#include <sys/ddi_hp.h>
+
+static void	i_hp_dprintf(const char *fmt, ...);
+static int	i_hp_pack_branch(hp_node_t, char **, size_t *);
+static int	i_hp_pack_node(hp_node_t, char **, size_t *);
+static int	i_hp_unpack_node(char *, size_t, hp_node_t, hp_node_t *);
+static int	i_hp_unpack_branch(char *, size_t, hp_node_t, hp_node_t *);
+static int	i_hp_call_hotplugd(nvlist_t *, nvlist_t **);
+static nvlist_t	*i_hp_set_args(hp_cmd_t, const char *, const char *, uint_t,
+		    const char *, int);
+static int	i_hp_parse_results(nvlist_t *, hp_node_t *, char **);
+
+/*
+ * Global flag to enable debug features.
+ */
+int	libhotplug_debug = 0;
+
+/*
+ * hp_init()
+ *
+ *	Initialize a hotplug information snapshot.
+ */
+hp_node_t
+hp_init(const char *path, const char *connection, uint_t flags)
+{
+	nvlist_t	*args;
+	nvlist_t	*results;
+	hp_node_t	root = NULL;
+	int		rv;
+
+	i_hp_dprintf("hp_init: path=%p, connection=%p, flags=0x%x\n",
+	    (void *)path, (void *)connection, flags);
+
+	/* Check arguments */
+	if ((path == NULL) || !HP_INIT_FLAGS_VALID(flags)) {
+		i_hp_dprintf("hp_init: invalid arguments.\n");
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	/* Build arguments for door call */
+	if ((args = i_hp_set_args(HP_CMD_GETINFO, path, connection, flags,
+	    NULL, 0)) == NULL) {
+		i_hp_dprintf("hp_init: cannot build arguments nvlist.\n");
+		errno = ENOMEM;
+		return (NULL);
+	}
+
+	/* Make the door call to hotplugd */
+	rv = i_hp_call_hotplugd(args, &results);
+
+	/* Arguments no longer needed */
+	nvlist_free(args);
+
+	/* Parse additional results, if any */
+	if ((rv == 0) && (results != NULL)) {
+		rv = i_hp_parse_results(results, &root, NULL);
+		nvlist_free(results);
+	}
+
+	/* Check for errors */
+	if (rv != 0) {
+		i_hp_dprintf("hp_init: failure (%s).\n", strerror(rv));
+		if (root)
+			hp_fini(root);
+		errno = rv;
+		return (NULL);
+	}
+
+	/* Success requires an info snapshot */
+	if (root == NULL) {
+		i_hp_dprintf("hp_init: missing info snapshot.\n");
+		errno = EFAULT;
+		return (NULL);
+	}
+
+	/* Success */
+	return (root);
+}
+
+/*
+ * hp_fini()
+ *
+ *	Terminate and clean-up a hotplug information snapshot.
+ */
+void
+hp_fini(hp_node_t root)
+{
+	hp_node_t	node;
+	hp_node_t	sibling;
+	char		*basepath;
+
+	i_hp_dprintf("hp_fini: root=%p\n", (void *)root);
+
+	if (root == NULL) {
+		i_hp_dprintf("hp_fini: invalid arguments.\n");
+		return;
+	}
+
+	/* Extract and free base path */
+	if (root->hp_basepath) {
+		basepath = root->hp_basepath;
+		for (node = root; node != NULL; node = node->hp_sibling)
+			node->hp_basepath = NULL;
+		free(basepath);
+	}
+
+	/* Destroy the nodes */
+	node = root;
+	while (node) {
+		sibling = node->hp_sibling;
+		if (node->hp_child)
+			hp_fini(node->hp_child);
+		if (node->hp_name)
+			free(node->hp_name);
+		if (node->hp_usage)
+			free(node->hp_usage);
+		if (node->hp_description)
+			free(node->hp_description);
+		free(node);
+		node = sibling;
+	}
+}
+
+/*
+ * hp_traverse()
+ *
+ *	Walk a graph of hotplug nodes, executing a callback on each node.
+ */
+int
+hp_traverse(hp_node_t root, void *arg, int (*hp_callback)(hp_node_t, void *arg))
+{
+	int		rv;
+	hp_node_t	node;
+
+	i_hp_dprintf("hp_traverse: root=%p, arg=%p, hp_callback=%p\n",
+	    (void *)root, arg, (void *)hp_callback);
+
+	/* Check arguments */
+	if ((root == NULL) || (hp_callback == NULL)) {
+		i_hp_dprintf("hp_traverse: invalid arguments.\n");
+		errno = EINVAL;
+		return (-1);
+	}
+
+	for (node = root; node; node = node->hp_sibling) {
+		rv = hp_callback(node, arg);
+
+		if (rv == HP_WALK_TERMINATE) {
+			i_hp_dprintf("hp_traverse: walk terminated.\n");
+			return (HP_WALK_TERMINATE);
+		}
+
+		if (node->hp_child && (rv != HP_WALK_PRUNECHILD))
+			if (hp_traverse(node->hp_child, arg, hp_callback) ==
+			    HP_WALK_TERMINATE) {
+				i_hp_dprintf("hp_traverse: walk terminated.\n");
+				return (HP_WALK_TERMINATE);
+			}
+
+		if (rv == HP_WALK_PRUNESIBLING)
+			break;
+	}
+
+	return (0);
+}
+
+/*
+ * hp_type()
+ *
+ *	Return a node's type.
+ */
+int
+hp_type(hp_node_t node)
+{
+	i_hp_dprintf("hp_type: node=%p\n", (void *)node);
+
+	if (node == NULL) {
+		i_hp_dprintf("hp_type: invalid arguments.\n");
+		errno = EINVAL;
+		return (-1);
+	}
+
+	return (node->hp_type);
+}
+
+/*
+ * hp_name()
+ *
+ *	Return a node's name.
+ */
+char *
+hp_name(hp_node_t node)
+{
+	i_hp_dprintf("hp_name: node=%p\n", (void *)node);
+
+	if (node == NULL) {
+		i_hp_dprintf("hp_name: invalid arguments.\n");
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if (node->hp_name == NULL) {
+		i_hp_dprintf("hp_name: missing name value.\n");
+		errno = EFAULT;
+	}
+
+	return (node->hp_name);
+}
+
+/*
+ * hp_state()
+ *
+ *	Return a node's current state.
+ */
+int
+hp_state(hp_node_t node)
+{
+	i_hp_dprintf("hp_state: node=%p\n", (void *)node);
+
+	if (node == NULL) {
+		i_hp_dprintf("hp_state: invalid arguments.\n");
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if ((node->hp_type != HP_NODE_CONNECTOR) &&
+	    (node->hp_type != HP_NODE_PORT)) {
+		i_hp_dprintf("hp_state: operation not supported.\n");
+		errno = ENOTSUP;
+		return (-1);
+	}
+
+	return (node->hp_state);
+}
+
+/*
+ * hp_usage()
+ *
+ *	Return a usage description for usage nodes.
+ */
+char *
+hp_usage(hp_node_t node)
+{
+	i_hp_dprintf("hp_usage: node=%p\n", (void *)node);
+
+	if (node == NULL) {
+		i_hp_dprintf("hp_usage: invalid arguments.\n");
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if (node->hp_type != HP_NODE_USAGE) {
+		i_hp_dprintf("hp_usage: operation not supported.\n");
+		errno = ENOTSUP;
+		return (NULL);
+	}
+
+	if (node->hp_usage == NULL) {
+		i_hp_dprintf("hp_usage: missing usage value.\n");
+		errno = EFAULT;
+	}
+
+	return (node->hp_usage);
+}
+
+/*
+ * hp_description()
+ *
+ *	Return a type description (e.g. "PCI slot") for connection nodes.
+ */
+char *
+hp_description(hp_node_t node)
+{
+	i_hp_dprintf("hp_description: node=%p\n", (void *)node);
+
+	if (node == NULL) {
+		i_hp_dprintf("hp_description: invalid arguments.\n");
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if ((node->hp_type != HP_NODE_CONNECTOR) &&
+	    (node->hp_type != HP_NODE_PORT)) {
+		i_hp_dprintf("hp_description: operation not supported.\n");
+		errno = ENOTSUP;
+		return (NULL);
+	}
+
+	if (node->hp_description == NULL) {
+		i_hp_dprintf("hp_description: missing description value.\n");
+		errno = EFAULT;
+	}
+
+	return (node->hp_description);
+}
+
+/*
+ * hp_last_change()
+ *
+ *	Return when the state of a connection was last changed.
+ */
+time_t
+hp_last_change(hp_node_t node)
+{
+	i_hp_dprintf("hp_last_change: node=%p\n", (void *)node);
+
+	if (node == NULL) {
+		i_hp_dprintf("hp_last_change: invalid arguments.\n");
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if ((node->hp_type != HP_NODE_CONNECTOR) &&
+	    (node->hp_type != HP_NODE_PORT)) {
+		i_hp_dprintf("hp_last_change: operation not supported.\n");
+		errno = ENOTSUP;
+		return (NULL);
+	}
+
+	return (node->hp_last_change);
+}
+
+/*
+ * hp_parent()
+ *
+ *	Return a node's parent node.
+ */
+hp_node_t
+hp_parent(hp_node_t node)
+{
+	i_hp_dprintf("hp_parent: node=%p\n", (void *)node);
+
+	if (node == NULL) {
+		i_hp_dprintf("hp_parent: invalid arguments.\n");
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if (node->hp_parent == NULL) {
+		i_hp_dprintf("hp_parent: node has no parent.\n");
+		errno = ENXIO;
+	}
+
+	return (node->hp_parent);
+}
+
+/*
+ * hp_child()
+ *
+ *	Return a node's first child node.
+ */
+hp_node_t
+hp_child(hp_node_t node)
+{
+	i_hp_dprintf("hp_child: node=%p\n", (void *)node);
+
+	if (node == NULL) {
+		i_hp_dprintf("hp_child: invalid arguments.\n");
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if (node->hp_child == NULL) {
+		i_hp_dprintf("hp_child: node has no child.\n");
+		errno = ENXIO;
+	}
+
+	return (node->hp_child);
+}
+
+/*
+ * hp_sibling()
+ *
+ *	Return a node's next sibling node.
+ */
+hp_node_t
+hp_sibling(hp_node_t node)
+{
+	i_hp_dprintf("hp_sibling: node=%p\n", (void *)node);
+
+	if (node == NULL) {
+		i_hp_dprintf("hp_sibling: invalid arguments.\n");
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if (node->hp_sibling == NULL) {
+		i_hp_dprintf("hp_sibling: node has no sibling.\n");
+		errno = ENXIO;
+	}
+
+	return (node->hp_sibling);
+}
+
+/*
+ * hp_path()
+ *
+ *	Return the path (and maybe connection name) of a node.
+ *	The caller must supply two buffers, each MAXPATHLEN size.
+ */
+int
+hp_path(hp_node_t node, char *path, char *connection)
+{
+	hp_node_t	root;
+	hp_node_t	parent;
+	int		i;
+	char		*s;
+	char		components[MAXPATHLEN];
+
+	i_hp_dprintf("hp_path: node=%p, path=%p, connection=%p\n", (void *)node,
+	    (void *)path, (void *)connection);
+
+	if ((node == NULL) || (path == NULL) || (connection == NULL)) {
+		i_hp_dprintf("hp_path: invalid arguments.\n");
+		return (EINVAL);
+	}
+
+	(void) memset(path, 0, MAXPATHLEN);
+	(void) memset(connection, 0, MAXPATHLEN);
+	(void) memset(components, 0, MAXPATHLEN);
+
+	/*  Set 'connection' only for connectors and ports */
+	if ((node->hp_type == HP_NODE_CONNECTOR) ||
+	    (node->hp_type == HP_NODE_PORT))
+		(void) strlcpy(connection, node->hp_name, MAXPATHLEN);
+
+	/* Trace back to the root node, accumulating components */
+	for (parent = node; parent != NULL; parent = parent->hp_parent) {
+		if (parent->hp_type == HP_NODE_DEVICE) {
+			(void) strlcat(components, "/", MAXPATHLEN);
+			(void) strlcat(components, parent->hp_name, MAXPATHLEN);
+		}
+		if (parent->hp_parent == NULL)
+			root = parent;
+	}
+
+	/* Ensure the snapshot actually contains a base path */
+	if (root->hp_basepath == NULL) {
+		i_hp_dprintf("hp_path: missing base pathname.\n");
+		return (EFAULT);
+	}
+
+	/*
+	 * Construct the path.  Start with the base path from the root
+	 * node, then append the accumulated components in reverse order.
+	 */
+	if (strcmp(root->hp_basepath, "/") != 0) {
+		(void) strlcat(path, root->hp_basepath, MAXPATHLEN);
+		if ((root->hp_type == HP_NODE_DEVICE) &&
+		    ((s = strrchr(path, '/')) != NULL))
+			*s = '\0';
+	}
+	for (i = strlen(components) - 1; i >= 0; i--) {
+		if (components[i] == '/') {
+			(void) strlcat(path, &components[i], MAXPATHLEN);
+			components[i] = '\0';
+		}
+	}
+
+	return (0);
+}
+
+/*
+ * hp_set_state()
+ *
+ *	Initiate a state change operation on a node.
+ */
+int
+hp_set_state(hp_node_t node, uint_t flags, int state, hp_node_t *resultsp)
+{
+	hp_node_t	root = NULL;
+	nvlist_t	*args;
+	nvlist_t	*results;
+	int		rv;
+	char		path[MAXPATHLEN];
+	char		connection[MAXPATHLEN];
+
+	i_hp_dprintf("hp_set_state: node=%p, flags=0x%x, state=0x%x, "
+	    "resultsp=%p\n", (void *)node, flags, state, (void *)resultsp);
+
+	/* Check arguments */
+	if ((node == NULL) || (resultsp == NULL) ||
+	    !HP_SET_STATE_FLAGS_VALID(flags)) {
+		i_hp_dprintf("hp_set_state: invalid arguments.\n");
+		return (EINVAL);
+	}
+
+	/* Check node type */
+	if ((node->hp_type != HP_NODE_CONNECTOR) &&
+	    (node->hp_type != HP_NODE_PORT)) {
+		i_hp_dprintf("hp_set_state: operation not supported.\n");
+		return (ENOTSUP);
+	}
+
+	/* Check that target state is valid */
+	switch (state) {
+	case DDI_HP_CN_STATE_PRESENT:
+	case DDI_HP_CN_STATE_POWERED:
+	case DDI_HP_CN_STATE_ENABLED:
+		if (node->hp_type != HP_NODE_CONNECTOR) {
+			i_hp_dprintf("hp_set_state: mismatched target.\n");
+			return (ENOTSUP);
+		}
+		break;
+	case DDI_HP_CN_STATE_PORT_PRESENT:
+	case DDI_HP_CN_STATE_OFFLINE:
+	case DDI_HP_CN_STATE_ONLINE:
+		if (node->hp_type != HP_NODE_PORT) {
+			i_hp_dprintf("hp_set_state: mismatched target.\n");
+			return (ENOTSUP);
+		}
+		break;
+	default:
+		i_hp_dprintf("hp_set_state: invalid target state.\n");
+		return (EINVAL);
+	}
+
+	/* Get path and connection of specified node */
+	if ((rv = hp_path(node, path, connection)) != 0)
+		return (rv);
+
+	/* Build arguments for door call */
+	if ((args = i_hp_set_args(HP_CMD_CHANGESTATE, path, connection, flags,
+	    NULL, state)) == NULL)
+		return (ENOMEM);
+
+	/* Make the door call to hotplugd */
+	rv = i_hp_call_hotplugd(args, &results);
+
+	/* Arguments no longer needed */
+	nvlist_free(args);
+
+	/* Parse additional results, if any */
+	if ((rv == 0) && (results != NULL)) {
+		rv = i_hp_parse_results(results, &root, NULL);
+		nvlist_free(results);
+		*resultsp = root;
+	}
+
+	/* Done */
+	return (rv);
+}
+
+/*
+ * hp_set_private()
+ *
+ *	Set bus private options on the hotplug connection
+ *	indicated by the given hotplug information node.
+ */
+int
+hp_set_private(hp_node_t node, const char *options, char **resultsp)
+{
+	int		rv;
+	nvlist_t	*args;
+	nvlist_t	*results;
+	char		*values = NULL;
+	char		path[MAXPATHLEN];
+	char		connection[MAXPATHLEN];
+
+	i_hp_dprintf("hp_set_private: node=%p, options=%p, resultsp=%p\n",
+	    (void *)node, (void *)options, (void *)resultsp);
+
+	/* Check arguments */
+	if ((node == NULL) || (options == NULL) || (resultsp == NULL)) {
+		i_hp_dprintf("hp_set_private: invalid arguments.\n");
+		return (EINVAL);
+	}
+
+	/* Check node type */
+	if (node->hp_type != HP_NODE_CONNECTOR) {
+		i_hp_dprintf("hp_set_private: operation not supported.\n");
+		return (ENOTSUP);
+	}
+
+	/* Initialize results */
+	*resultsp = NULL;
+
+	/* Get path and connection of specified node */
+	if ((rv = hp_path(node, path, connection)) != 0)
+		return (rv);
+
+	/* Build arguments for door call */
+	if ((args = i_hp_set_args(HP_CMD_SETPRIVATE, path, connection, 0,
+	    options, 0)) == NULL)
+		return (ENOMEM);
+
+	/* Make the door call to hotplugd */
+	rv = i_hp_call_hotplugd(args, &results);
+
+	/* Arguments no longer needed */
+	nvlist_free(args);
+
+	/* Parse additional results, if any */
+	if ((rv == 0) && (results != NULL)) {
+		rv = i_hp_parse_results(results, NULL, &values);
+		nvlist_free(results);
+		*resultsp = values;
+	}
+
+	/* Done */
+	return (rv);
+}
+
+/*
+ * hp_get_private()
+ *
+ *	Get bus private options on the hotplug connection
+ *	indicated by the given hotplug information node.
+ */
+int
+hp_get_private(hp_node_t node, const char *options, char **resultsp)
+{
+	int		rv;
+	nvlist_t	*args;
+	nvlist_t	*results;
+	char		*values = NULL;
+	char		path[MAXPATHLEN];
+	char		connection[MAXPATHLEN];
+
+	i_hp_dprintf("hp_get_private: node=%p, options=%p, resultsp=%p\n",
+	    (void *)node, (void *)options, (void *)resultsp);
+
+	/* Check arguments */
+	if ((node == NULL) || (options == NULL) || (resultsp == NULL)) {
+		i_hp_dprintf("hp_get_private: invalid arguments.\n");
+		return (EINVAL);
+	}
+
+	/* Check node type */
+	if (node->hp_type != HP_NODE_CONNECTOR) {
+		i_hp_dprintf("hp_get_private: operation not supported.\n");
+		return (ENOTSUP);
+	}
+
+	/* Initialize results */
+	*resultsp = NULL;
+
+	/* Get path and connection of specified node */
+	if ((rv = hp_path(node, path, connection)) != 0)
+		return (rv);
+
+	/* Build arguments for door call */
+	if ((args = i_hp_set_args(HP_CMD_GETPRIVATE, path, connection, 0,
+	    options, 0)) == NULL)
+		return (ENOMEM);
+
+	/* Make the door call to hotplugd */
+	rv = i_hp_call_hotplugd(args, &results);
+
+	/* Arguments no longer needed */
+	nvlist_free(args);
+
+	/* Parse additional results, if any */
+	if ((rv == 0) && (results != NULL)) {
+		rv = i_hp_parse_results(results, NULL, &values);
+		nvlist_free(results);
+		*resultsp = values;
+	}
+
+	/* Done */
+	return (rv);
+}
+
+/*
+ * hp_pack()
+ *
+ *	Given the root of a hotplug information snapshot, pack
+ *	it into a contiguous byte array so that it is suitable
+ *	for network transport.
+ */
+int
+hp_pack(hp_node_t root, char **bufp, size_t *lenp)
+{
+	hp_node_t	node;
+	nvlist_t	*nvl;
+	char		*buf;
+	size_t		len;
+	int		rv;
+
+	i_hp_dprintf("hp_pack: root=%p, bufp=%p, lenp=%p\n", (void *)root,
+	    (void *)bufp, (void *)lenp);
+
+	if ((root == NULL) || (bufp == NULL) || (lenp == NULL)) {
+		i_hp_dprintf("hp_pack: invalid arguments.\n");
+		return (EINVAL);
+	}
+
+	*lenp = 0;
+	*bufp = NULL;
+
+	if (nvlist_alloc(&nvl, 0, 0) != 0) {
+		i_hp_dprintf("hp_pack: nvlist_alloc() failed (%s).\n",
+		    strerror(errno));
+		return (ENOMEM);
+	}
+
+	if (root->hp_basepath != NULL) {
+		rv = nvlist_add_string(nvl, HP_INFO_BASE, root->hp_basepath);
+		if (rv != 0) {
+			nvlist_free(nvl);
+			return (rv);
+		}
+	}
+
+	for (node = root; node != NULL; node = node->hp_sibling) {
+		if ((rv = i_hp_pack_branch(node, &buf, &len)) == 0) {
+			rv = nvlist_add_byte_array(nvl, HP_INFO_BRANCH,
+			    (uchar_t *)buf, len);
+			free(buf);
+		}
+		if (rv != 0) {
+			nvlist_free(nvl);
+			return (rv);
+		}
+	}
+
+	len = 0;
+	buf = NULL;
+	if ((rv = nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0)) == 0) {
+		*lenp = len;
+		*bufp = buf;
+	}
+
+	nvlist_free(nvl);
+
+	return (rv);
+}
+
+/*
+ * hp_unpack()
+ *
+ *	Unpack a hotplug information snapshot for normal usage.
+ */
+int
+hp_unpack(char *packed_buf, size_t packed_len, hp_node_t *retp)
+{
+	hp_node_t	root;
+	hp_node_t	root_list = NULL;
+	hp_node_t	prev_root = NULL;
+	nvlist_t	*nvl = NULL;
+	nvpair_t	*nvp;
+	char		*basepath = NULL;
+	int		rv;
+
+	i_hp_dprintf("hp_unpack: packed_buf=%p, packed_len=%u, retp=%p\n",
+	    (void *)packed_buf, (uint32_t)packed_len, (void *)retp);
+
+	if ((packed_buf == NULL) || (packed_len == 0) || (retp == NULL)) {
+		i_hp_dprintf("hp_unpack: invalid arguments.\n");
+		return (EINVAL);
+	}
+
+	if ((rv = nvlist_unpack(packed_buf, packed_len, &nvl, 0)) != 0)
+		return (rv);
+
+	if (nvlist_next_nvpair(nvl, NULL) == NULL) {
+		nvlist_free(nvl);
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
+
+		rv = EINVAL;
+
+		if (strcmp(nvpair_name(nvp), HP_INFO_BASE) == 0) {
+			char	*val_string;
+
+			if ((rv = nvpair_value_string(nvp, &val_string)) == 0) {
+				if ((basepath = strdup(val_string)) == NULL)
+					rv = ENOMEM;
+			}
+
+		} else if (strcmp(nvpair_name(nvp), HP_INFO_BRANCH) == 0) {
+			size_t		len = 0;
+			char		*buf = NULL;
+
+			if ((rv = nvpair_value_byte_array(nvp,
+			    (uchar_t **)&buf, (uint_t *)&len)) == 0) {
+				rv = i_hp_unpack_branch(buf, len, NULL, &root);
+			}
+
+			if (rv == 0) {
+				if (prev_root) {
+					prev_root->hp_sibling = root;
+				} else {
+					root_list = root;
+				}
+				prev_root = root;
+			}
+		}
+
+		if (rv != 0) {
+			if (basepath)
+				free(basepath);
+			nvlist_free(nvl);
+			hp_fini(root_list);
+			*retp = NULL;
+			return (rv);
+		}
+	}
+
+	/* Store the base path in each root node */
+	if (basepath) {
+		for (root = root_list; root; root = root->hp_sibling)
+			root->hp_basepath = basepath;
+	}
+
+	nvlist_free(nvl);
+	*retp = root_list;
+	return (0);
+}
+
+/*
+ * i_hp_dprintf()
+ *
+ *	Print debug messages to stderr, but only when the debug flag
+ *	(libhotplug_debug) is set.
+ */
+/*PRINTFLIKE1*/
+static void
+i_hp_dprintf(const char *fmt, ...)
+{
+	va_list	ap;
+
+	if (libhotplug_debug) {
+		va_start(ap, fmt);
+		(void) vfprintf(stderr, fmt, ap);
+		va_end(ap);
+	}
+}
+
+/*
+ * i_hp_pack_branch()
+ *
+ *	Pack an individual branch of a hotplug information snapshot.
+ */
+static int
+i_hp_pack_branch(hp_node_t root, char **bufp, size_t *lenp)
+{
+	hp_node_t	child;
+	nvlist_t	*nvl;
+	char		*buf;
+	size_t		len;
+	int		rv;
+
+	*lenp = 0;
+	*bufp = NULL;
+
+	/* Allocate an nvlist for this branch */
+	if (nvlist_alloc(&nvl, 0, 0) != 0)
+		return (ENOMEM);
+
+	/* Pack the root of the branch and add it to the nvlist */
+	if ((rv = i_hp_pack_node(root, &buf, &len)) == 0) {
+		rv = nvlist_add_byte_array(nvl, HP_INFO_NODE,
+		    (uchar_t *)buf, len);
+		free(buf);
+	}
+	if (rv != 0) {
+		nvlist_free(nvl);
+		return (rv);
+	}
+
+	/* Pack each subordinate branch, and add it to the nvlist */
+	for (child = root->hp_child; child != NULL; child = child->hp_sibling) {
+		if ((rv = i_hp_pack_branch(child, &buf, &len)) == 0) {
+			rv = nvlist_add_byte_array(nvl, HP_INFO_BRANCH,
+			    (uchar_t *)buf, len);
+			free(buf);
+		}
+		if (rv != 0) {
+			nvlist_free(nvl);
+			return (rv);
+		}
+	}
+
+	/* Pack the resulting nvlist into a single buffer */
+	len = 0;
+	buf = NULL;
+	if ((rv = nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0)) == 0) {
+		*lenp = len;
+		*bufp = buf;
+	}
+
+	/* Free the nvlist */
+	nvlist_free(nvl);
+
+	return (rv);
+}
+
+/*
+ * i_hp_pack_node()
+ *
+ *	Pack an individual node of a hotplug information snapshot.
+ */
+static int
+i_hp_pack_node(hp_node_t node, char **bufp, size_t *lenp)
+{
+	nvlist_t	*nvl;
+	char		*buf = NULL;
+	size_t		len = 0;
+	int		rv;
+
+	if (nvlist_alloc(&nvl, 0, 0) != 0)
+		return (ENOMEM);
+
+	if ((rv = nvlist_add_uint32(nvl, HP_INFO_TYPE,
+	    (uint32_t)node->hp_type)) != 0)
+		goto fail;
+
+	if ((node->hp_name) &&
+	    ((rv = nvlist_add_string(nvl, HP_INFO_NAME, node->hp_name)) != 0))
+		goto fail;
+
+	if ((node->hp_usage) &&
+	    ((rv = nvlist_add_string(nvl, HP_INFO_USAGE, node->hp_usage)) != 0))
+		goto fail;
+
+	if ((node->hp_description) &&
+	    ((rv = nvlist_add_string(nvl, HP_INFO_DESC,
+	    node->hp_description)) != 0))
+		goto fail;
+
+	if ((rv = nvlist_add_uint32(nvl, HP_INFO_STATE, node->hp_state)) != 0)
+		goto fail;
+
+	if ((node->hp_last_change != 0) &&
+	    ((rv = nvlist_add_uint32(nvl, HP_INFO_TIME,
+	    node->hp_last_change)) != 0))
+		goto fail;
+
+	if ((rv = nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0)) != 0)
+		goto fail;
+
+	*bufp = buf;
+	*lenp = len;
+	nvlist_free(nvl);
+	return (0);
+
+fail:
+	*bufp = NULL;
+	*lenp = 0;
+	nvlist_free(nvl);
+	return (rv);
+}
+
+/*
+ * i_hp_unpack_branch()
+ *
+ *	Unpack a branch of hotplug information nodes.
+ */
+static int
+i_hp_unpack_branch(char *packed_buf, size_t packed_len, hp_node_t parent,
+    hp_node_t *retp)
+{
+	hp_node_t	node = NULL;
+	hp_node_t	child;
+	hp_node_t	prev_child = NULL;
+	nvlist_t	*nvl = NULL;
+	nvpair_t	*nvp;
+	char		*buf;
+	size_t		len;
+	int		rv;
+
+	/* Initialize results */
+	*retp = NULL;
+
+	/* Unpack the nvlist for this branch */
+	if ((rv = nvlist_unpack(packed_buf, packed_len, &nvl, 0)) != 0)
+		return (rv);
+
+	/*
+	 * Unpack the branch.  The first item in the nvlist is
+	 * always the root node.  And zero or more subordinate
+	 * branches may be packed afterward.
+	 */
+	for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
+
+		len = 0;
+		buf = NULL;
+
+		if (strcmp(nvpair_name(nvp), HP_INFO_NODE) == 0) {
+
+			/* Check that there is only one root node */
+			if (node != NULL) {
+				hp_fini(node);
+				nvlist_free(nvl);
+				return (EFAULT);
+			}
+
+			if ((rv = nvpair_value_byte_array(nvp, (uchar_t **)&buf,
+			    (uint_t *)&len)) == 0)
+				rv = i_hp_unpack_node(buf, len, parent, &node);
+
+			if (rv != 0) {
+				nvlist_free(nvl);
+				return (rv);
+			}
+
+		} else if (strcmp(nvpair_name(nvp), HP_INFO_BRANCH) == 0) {
+
+			if ((rv = nvpair_value_byte_array(nvp, (uchar_t **)&buf,
+			    (uint_t *)&len)) == 0)
+				rv = i_hp_unpack_branch(buf, len, node, &child);
+
+			if (rv != 0) {
+				hp_fini(node);
+				nvlist_free(nvl);
+				return (rv);
+			}
+
+			if (prev_child) {
+				prev_child->hp_sibling = child;
+			} else {
+				node->hp_child = child;
+			}
+			prev_child = child;
+		}
+	}
+
+	nvlist_free(nvl);
+	*retp = node;
+	return (0);
+}
+
+/*
+ * i_hp_unpack_node()
+ *
+ *	Unpack an individual hotplug information node.
+ */
+static int
+i_hp_unpack_node(char *buf, size_t len, hp_node_t parent, hp_node_t *retp)
+{
+	hp_node_t	node;
+	nvlist_t	*nvl;
+	nvpair_t	*nvp;
+	uint32_t	val_uint32;
+	char		*val_string;
+	int		rv = 0;
+
+	/* Initialize results */
+	*retp = NULL;
+
+	/* Unpack node into an nvlist */
+	if ((nvlist_unpack(buf, len, &nvl, 0) != 0))
+		return (EINVAL);
+
+	/* Allocate the new node */
+	if ((node = (hp_node_t)calloc(1, sizeof (struct hp_node))) == NULL) {
+		nvlist_free(nvl);
+		return (ENOMEM);
+	}
+
+	/* Iterate through nvlist, unpacking each field */
+	for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
+
+		if ((strcmp(nvpair_name(nvp), HP_INFO_TYPE) == 0) &&
+		    (nvpair_type(nvp) == DATA_TYPE_UINT32)) {
+
+			(void) nvpair_value_uint32(nvp, &val_uint32);
+			node->hp_type = val_uint32;
+
+		} else if ((strcmp(nvpair_name(nvp), HP_INFO_NAME) == 0) &&
+		    (nvpair_type(nvp) == DATA_TYPE_STRING)) {
+
+			(void) nvpair_value_string(nvp, &val_string);
+			if ((node->hp_name = strdup(val_string)) == NULL) {
+				rv = ENOMEM;
+				break;
+			}
+
+		} else if ((strcmp(nvpair_name(nvp), HP_INFO_STATE) == 0) &&
+		    (nvpair_type(nvp) == DATA_TYPE_UINT32)) {
+
+			(void) nvpair_value_uint32(nvp, &val_uint32);
+			node->hp_state = val_uint32;
+
+		} else if ((strcmp(nvpair_name(nvp), HP_INFO_USAGE) == 0) &&
+		    (nvpair_type(nvp) == DATA_TYPE_STRING)) {
+
+			(void) nvpair_value_string(nvp, &val_string);
+			if ((node->hp_usage = strdup(val_string)) == NULL) {
+				rv = ENOMEM;
+				break;
+			}
+
+		} else if ((strcmp(nvpair_name(nvp), HP_INFO_DESC) == 0) &&
+		    (nvpair_type(nvp) == DATA_TYPE_STRING)) {
+
+			(void) nvpair_value_string(nvp, &val_string);
+			if ((node->hp_description = strdup(val_string))
+			    == NULL) {
+				rv = ENOMEM;
+				break;
+			}
+
+		} else if ((strcmp(nvpair_name(nvp), HP_INFO_TIME) == 0) &&
+		    (nvpair_type(nvp) == DATA_TYPE_UINT32)) {
+
+			(void) nvpair_value_uint32(nvp, &val_uint32);
+			node->hp_last_change = (time_t)val_uint32;
+
+		} else {
+			i_hp_dprintf("i_hp_unpack_node: unrecognized: '%s'\n",
+			    nvpair_name(nvp));
+		}
+	}
+
+	/* Unpacked nvlist no longer needed */
+	nvlist_free(nvl);
+
+	/* Check for errors */
+	if (rv != 0) {
+		hp_fini(node);
+		return (rv);
+	}
+
+	/* Success */
+	node->hp_parent = parent;
+	*retp = node;
+	return (0);
+}
+
+/*
+ * i_hp_call_hotplugd()
+ *
+ *	Perform a door call to the hotplug daemon.
+ */
+static int
+i_hp_call_hotplugd(nvlist_t *args, nvlist_t **resultsp)
+{
+	door_arg_t	door_arg;
+	nvlist_t	*results = NULL;
+	char		*buf = NULL;
+	size_t		len = 0;
+	uint64_t	seqnum;
+	int		door_fd;
+	int		rv;
+
+	/* Initialize results */
+	*resultsp = NULL;
+
+	/* Open door */
+	if ((door_fd = open(HOTPLUGD_DOOR, O_RDONLY)) < 0) {
+		i_hp_dprintf("i_hp_call_hotplugd: cannot open door (%s)\n",
+		    strerror(errno));
+		return (EBADF);
+	}
+
+	/* Pack the nvlist of arguments */
+	if ((rv = nvlist_pack(args, &buf, &len, NV_ENCODE_NATIVE, 0)) != 0) {
+		i_hp_dprintf("i_hp_call_hotplugd: cannot pack arguments (%s)\n",
+		    strerror(rv));
+		return (rv);
+	}
+
+	/* Set the door argument using the packed arguments */
+	door_arg.data_ptr = buf;
+	door_arg.data_size = len;
+	door_arg.desc_ptr = NULL;
+	door_arg.desc_num = 0;
+	door_arg.rbuf = (char *)(uintptr_t)&rv;
+	door_arg.rsize = sizeof (rv);
+
+	/* Attempt the door call */
+	if (door_call(door_fd, &door_arg) != 0) {
+		rv = errno;
+		i_hp_dprintf("i_hp_call_hotplugd: door call failed (%s)\n",
+		    strerror(rv));
+		(void) close(door_fd);
+		free(buf);
+		return (rv);
+	}
+
+	/* The arguments are no longer needed */
+	free(buf);
+
+	/*
+	 * If results are not in the original buffer provided,
+	 * then check and process the new results buffer.
+	 */
+	if (door_arg.rbuf != (char *)(uintptr_t)&rv) {
+
+		/*
+		 * First check that the buffer is valid.  Then check for
+		 * the simple case where a short result code was sent.
+		 * The last case is a packed nvlist was returned, which
+		 * needs to be unpacked.
+		 */
+		if ((door_arg.rbuf == NULL) ||
+		    (door_arg.data_size < sizeof (rv))) {
+			i_hp_dprintf("i_hp_call_hotplugd: invalid results.\n");
+			rv = EFAULT;
+
+		} else if (door_arg.data_size == sizeof (rv)) {
+			rv = *(int *)(uintptr_t)door_arg.rbuf;
+
+		} else if ((rv = nvlist_unpack(door_arg.rbuf,
+		    door_arg.data_size, &results, 0)) != 0) {
+			i_hp_dprintf("i_hp_call_hotplugd: "
+			    "cannot unpack results (%s).\n", strerror(rv));
+			results = NULL;
+			rv = EFAULT;
+		}
+
+		/* Unmap the results buffer */
+		if (door_arg.rbuf != NULL)
+			(void) munmap(door_arg.rbuf, door_arg.rsize);
+
+		/*
+		 * In the case of a packed nvlist, notify the daemon
+		 * that it can free the result buffer from its heap.
+		 */
+		if ((results != NULL) &&
+		    (nvlist_lookup_uint64(results, HPD_SEQNUM, &seqnum) == 0)) {
+			door_arg.data_ptr = (char *)(uintptr_t)&seqnum;
+			door_arg.data_size = sizeof (seqnum);
+			door_arg.desc_ptr = NULL;
+			door_arg.desc_num = 0;
+			door_arg.rbuf = NULL;
+			door_arg.rsize = 0;
+			(void) door_call(door_fd, &door_arg);
+			if (door_arg.rbuf != NULL)
+				(void) munmap(door_arg.rbuf, door_arg.rsize);
+		}
+
+		*resultsp = results;
+	}
+
+	(void) close(door_fd);
+	return (rv);
+}
+
+/*
+ * i_hp_set_args()
+ *
+ *	Construct an nvlist of arguments for a hotplugd door call.
+ */
+static nvlist_t *
+i_hp_set_args(hp_cmd_t cmd, const char *path, const char *connection,
+    uint_t flags, const char *options, int state)
+{
+	nvlist_t	*args;
+
+	/* Allocate a new nvlist */
+	if (nvlist_alloc(&args, NV_UNIQUE_NAME_TYPE, 0) != 0)
+		return (NULL);
+
+	/* Add common arguments */
+	if ((nvlist_add_int32(args, HPD_CMD, cmd) != 0) ||
+	    (nvlist_add_string(args, HPD_PATH, path) != 0)) {
+		nvlist_free(args);
+		return (NULL);
+	}
+
+	/* Add connection, but only if defined */
+	if ((connection != NULL) && (connection[0] != '\0') &&
+	    (nvlist_add_string(args, HPD_CONNECTION, connection) != 0)) {
+		nvlist_free(args);
+		return (NULL);
+	}
+
+	/* Add flags, but only if defined */
+	if ((flags != 0) && (nvlist_add_uint32(args, HPD_FLAGS, flags) != 0)) {
+		nvlist_free(args);
+		return (NULL);
+	}
+
+	/* Add options, but only if defined */
+	if ((options != NULL) &&
+	    (nvlist_add_string(args, HPD_OPTIONS, options) != 0)) {
+		nvlist_free(args);
+		return (NULL);
+	}
+
+	/* Add state, but only for CHANGESTATE command */
+	if ((cmd == HP_CMD_CHANGESTATE) &&
+	    (nvlist_add_int32(args, HPD_STATE, state) != 0)) {
+		nvlist_free(args);
+		return (NULL);
+	}
+
+	return (args);
+}
+
+/*
+ * i_hp_parse_results()
+ *
+ *	Parse out individual fields of an nvlist of results from
+ *	a hotplugd door call.
+ */
+static int
+i_hp_parse_results(nvlist_t *results, hp_node_t *rootp, char **optionsp)
+{
+	int	rv;
+
+	/* Parse an information snapshot */
+	if (rootp) {
+		char	*buf = NULL;
+		size_t	len = 0;
+
+		*rootp = NULL;
+		if (nvlist_lookup_byte_array(results, HPD_INFO,
+		    (uchar_t **)&buf, (uint_t *)&len) == 0) {
+			if ((rv = hp_unpack(buf, len, rootp)) != 0)
+				return (rv);
+		}
+	}
+
+	/* Parse a bus private option string */
+	if (optionsp) {
+		char	*str;
+
+		*optionsp = NULL;
+		if ((nvlist_lookup_string(results, HPD_OPTIONS, &str) == 0) &&
+		    ((*optionsp = strdup(str)) == NULL)) {
+			return (ENOMEM);
+		}
+	}
+
+	/* Parse result code of the operation */
+	if (nvlist_lookup_int32(results, HPD_STATUS, &rv) != 0) {
+		i_hp_dprintf("i_hp_call_hotplugd: missing status.\n");
+		return (EFAULT);
+	}
+
+	return (rv);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libhotplug/common/libhotplug.h	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,104 @@
+/*
+ * 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 _LIBHOTPLUG_H
+#define	_LIBHOTPLUG_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+/*
+ * Define node types in hotplug snapshot.
+ */
+#define	HP_NODE_NONE		0
+#define	HP_NODE_DEVICE		1
+#define	HP_NODE_CONNECTOR	2
+#define	HP_NODE_PORT		3
+#define	HP_NODE_USAGE		4
+
+/*
+ * Define flags for hp_init().
+ */
+#define	HPINFOUSAGE		0x1
+#define	HPINFOSEARCH		0x2	/* private flag */
+
+/*
+ * Define flags for hp_set_state().
+ */
+#define	HPFORCE			0x1
+#define	HPQUERY			0x2
+
+/*
+ * Define private flags.
+ */
+
+/*
+ * Define return values for hp_traverse() callbacks.
+ */
+#define	HP_WALK_CONTINUE	0
+#define	HP_WALK_PRUNECHILD	1
+#define	HP_WALK_PRUNESIBLING	2
+#define	HP_WALK_TERMINATE	3
+
+/*
+ * Define opaque handle to hotplug nodes.
+ */
+typedef struct hp_node *hp_node_t;
+
+/*
+ * Interface prototypes.
+ */
+hp_node_t	hp_init(const char *path, const char *connection, uint_t flags);
+void		hp_fini(hp_node_t root);
+int		hp_traverse(hp_node_t root, void *arg,
+		    int (*hp_callback)(hp_node_t, void *arg));
+int		hp_type(hp_node_t node);
+char		*hp_name(hp_node_t node);
+char		*hp_usage(hp_node_t node);
+int		hp_state(hp_node_t node);
+char		*hp_description(hp_node_t node);
+time_t		hp_last_change(hp_node_t node);
+hp_node_t	hp_parent(hp_node_t node);
+hp_node_t	hp_child(hp_node_t node);
+hp_node_t	hp_sibling(hp_node_t node);
+int		hp_path(hp_node_t node, char *path, char *connection);
+int		hp_set_state(hp_node_t node, uint_t flags, int state,
+		    hp_node_t *resultsp);
+int		hp_set_private(hp_node_t node, const char *options,
+		    char **resultsp);
+int		hp_get_private(hp_node_t node, const char *options,
+		    char **resultsp);
+int		hp_pack(hp_node_t root, char **bufp, size_t *lenp);
+int		hp_unpack(char *packed_buf, size_t packed_len, hp_node_t *retp);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _LIBHOTPLUG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libhotplug/common/libhotplug_impl.h	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,105 @@
+/*
+ * 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 _LIBHOTPLUG_IMPL_H
+#define	_LIBHOTPLUG_IMPL_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/param.h>
+#include <libhotplug.h>
+
+/*
+ * Definition of a node in a hotplug information snapshot.
+ */
+struct hp_node {
+	int		hp_type;
+	char		*hp_name;
+	char		*hp_usage;
+	char		*hp_description;
+	char		*hp_basepath;
+	int		hp_state;
+	time_t		hp_last_change;
+	hp_node_t	hp_parent;
+	hp_node_t	hp_child;
+	hp_node_t	hp_sibling;
+};
+
+/*
+ * Definitions used for packing/unpacking snapshots.
+ */
+#define	HP_INFO_BASE	"hp_info.basepath"
+#define	HP_INFO_NODE	"hp_info.node"
+#define	HP_INFO_BRANCH	"hp_info.branch"
+#define	HP_INFO_TYPE	"hp_info.type"
+#define	HP_INFO_NAME	"hp_info.name"
+#define	HP_INFO_USAGE	"hp_info.usage"
+#define	HP_INFO_STATE	"hp_info.state"
+#define	HP_INFO_DESC	"hp_info.description"
+#define	HP_INFO_TIME	"hp_info.last_change"
+
+/*
+ * Definitions for the door interface to hotplugd(1m).
+ */
+#define	HOTPLUGD_PID	"/var/run/hotplugd.pid"
+#define	HOTPLUGD_DOOR	"/var/run/hotplugd_door"
+
+typedef enum {
+	HP_CMD_NONE = 0,
+	HP_CMD_GETINFO,
+	HP_CMD_CHANGESTATE,
+	HP_CMD_SETPRIVATE,
+	HP_CMD_GETPRIVATE
+} hp_cmd_t;
+
+#define	HPD_CMD		"hp_door.cmd"
+#define	HPD_PATH	"hp_door.path"
+#define	HPD_CONNECTION	"hp_door.connection"
+#define	HPD_FLAGS	"hp_door.flags"
+#define	HPD_STATE	"hp_door.state"
+#define	HPD_OPTIONS	"hp_door.options"
+#define	HPD_INFO	"hp_door.info"
+#define	HPD_STATUS	"hp_door.status"
+#define	HPD_SEQNUM	"hp_door.seqnum"
+
+/*
+ * Definition of macros to validate flags.
+ */
+#define	HP_INIT_FLAGS_VALID(f)		((f & ~(HPINFOUSAGE)) == 0)
+#define	HP_SET_STATE_FLAGS_VALID(f)	((f & ~(HPFORCE | HPQUERY)) == 0)
+
+/*
+ * Definition of global flag to enable debug.
+ */
+extern int	libhotplug_debug;
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _LIBHOTPLUG_IMPL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libhotplug/common/llib-lhotplug	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,29 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include <libhotplug.h>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libhotplug/common/mapfile-vers	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,63 @@
+#
+# 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
+#
+
+SUNWprivate_1.1 {
+    global:
+	hp_init;
+	hp_fini;
+	hp_traverse;
+	hp_name;
+	hp_type;
+	hp_description;
+	hp_state;
+	hp_usage;
+	hp_parent;
+	hp_child;
+	hp_sibling;
+	hp_path;
+	hp_set_state;
+	hp_set_private;
+	hp_get_private;
+	hp_pack;
+	hp_unpack;
+	hp_last_change;
+	libhotplug_debug;
+    local:
+	*;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libhotplug/i386/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,28 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libhotplug/sparc/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,28 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libhotplug/sparcv9/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
--- a/usr/src/lib/libsecdb/auth_attr.txt	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/lib/libsecdb/auth_attr.txt	Mon Nov 02 15:58:28 2009 +0800
@@ -58,6 +58,9 @@
 solaris.file.chown:::Change File Owner::help=FileChown.html
 solaris.file.owner:::Act as File Owner::help=FileOwner.html
 #
+solaris.hotplug.:::Hotplug::help=HotplugHeader.html
+solaris.hotplug.modify:::Modify Hotplug Connections::help=HotplugModify.html
+#
 solaris.jobs.:::Job Scheduler::help=JobHeader.html
 solaris.jobs.admin:::Manage All Jobs::help=AuthJobsAdmin.html
 solaris.jobs.grant:::Delegate Cron & At Administration::help=JobsGrant.html
@@ -129,6 +132,7 @@
 solaris.smf.manage.extended-accounting.process:::Manage Process Extended Accounting Service States::help=SmfExAcctProcessStates.html
 solaris.smf.manage.extended-accounting.flow:::Manage Task Extended Accounting Service States::help=SmfExAcctTaskStates.html
 solaris.smf.manage.hal:::Manage HAL Service States::help=SmfHALStates.html
+solaris.smf.manage.hotplug:::Manage Hotplug Service::help=SmfManageHotplug.html
 solaris.smf.manage.idmap:::Manage Identity Mapping Service States::help=SmfIdmapStates.html
 solaris.smf.manage.inetd:::Manage inetd and inetd managed services States::help=SmfIntedStates.html
 solaris.smf.manage.ipsec:::Manage IPsec Service States::help=SmfIPsecStates.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsecdb/help/auths/HotplugHeader.html	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,34 @@
+<HTML>
+<!--
+    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.
+-->
+<HEAD>
+	<TITLE> </TITLE>
+	 
+	
+</HEAD>
+<BODY>
+
+The authorizations allow users access and the ability to display and manage hotplug connections.
+</BODY>
+</HTML>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsecdb/help/auths/HotplugModify.html	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,39 @@
+<HTML>
+<!--
+    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
+-->
+<HEAD>
+<!--
+META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"
+-->
+<!-- 
+META NAME="GENERATOR" CONTENT="Mozilla/4.02 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]"
+-->
+</HEAD>
+<BODY>
+When Modify Hotplug Connections is in the Authorizations Included column, it grants the authorization to perform hotplug operations on devices in the system.
+<p>
+If Modify Hotplug Connections is grayed, then you are not entitled to Add or Remove this authorization.
+<BR>&nbsp;
+</BODY>
+</HTML>
--- a/usr/src/lib/libsecdb/help/auths/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/lib/libsecdb/help/auths/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -36,6 +36,8 @@
 	DevCDRW.html \
 	DevGrant.html \
 	DevRevoke.html \
+        HotplugHeader.html \
+	HotplugModify.html \
 	JobHeader.html \
 	AuthJobsAdmin.html \
 	JobsGrant.html \
@@ -75,6 +77,7 @@
 	SmfInetdStates.html \
 	SmfIPsecStates.html \
 	SmfManageHeader.html \
+	SmfManageHotplug.html \
 	SmfMDNSStates.html \
 	SmfModifyAppl.html \
 	SmfModifyDepend.html \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsecdb/help/auths/SmfManageHotplug.html	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,37 @@
+<HTML>
+<!--
+    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.
+-->
+<HEAD>
+        <TITLE> </TITLE>
+
+
+</HEAD>
+<BODY>
+
+When Manage Hotplug Service is in the Authorizations Include column, it grants the authorization to enable, disable, or restart the hotplug service.
+<p>
+If Manage Hotplug Service is grayed, then you are not entitled to Add or Remove this authorization.
+<p>
+</BODY>
+</HTML>
--- a/usr/src/lib/libsecdb/help/profiles/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/lib/libsecdb/help/profiles/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -46,6 +46,7 @@
 	RtFileSysMngmnt.html \
 	RtFileSysSecurity.html \
 	RtFTPMngmnt.html \
+	RtHotplugMngmnt.html \
 	RtInetdMngmnt.html \
 	RtIPFilterMngmnt.html \
 	RtKerberosClntMngmnt.html \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsecdb/help/profiles/RtHotplugMngmnt.html	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,37 @@
+<HTML>
+<!--
+    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.
+-->
+<HEAD>
+	<TITLE> </TITLE>
+	 
+	
+</HEAD>
+<BODY>
+
+When Hotplug Management is in the Rights Included column, it grants the right to manage hotplug connections for devices in the system.
+<p>
+If Hotplug Management is grayed, then you are not entitled to Add or Remove this right.
+<p>
+</BODY>
+</HTML>
--- a/usr/src/lib/libsecdb/prof_attr.txt	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/lib/libsecdb/prof_attr.txt	Mon Nov 02 15:58:28 2009 +0800
@@ -48,11 +48,12 @@
 File System Management:::Manage, mount, share file systems:profiles=SMB Management,VSCAN Management,SMBFS Management;auths=solaris.smf.manage.autofs,solaris.smf.manage.shares.*,solaris.smf.value.shares.*;help=RtFileSysMngmnt.html
 File System Security:::Manage file system security attributes:help=RtFileSysSecurity.html
 HAL Management:::Manage HAL SMF service:auths=solaris.smf.manage.hal;help=RtHALMngmnt.html
+Hotplug Management:::Manage Hotplug Connections:auths=solaris.smf.manage.hotplug,solaris.hotplug.*;help=RtHotplugMgmt.html
 Idmap Name Mapping Management:::Manage Name-based Mapping Rules of Identity Mapping Service:auths=solaris.admin.idmap.rules;help=RtIdmapNameRulesMngmnt.html
 Idmap Service Management:::Manage Identity Mapping Service:auths=solaris.smf.manage.idmap,solaris.smf.value.idmap;help=RtIdmapMngmnt.html
 Inetd Management:::Manage inetd configuration parameters:auths=solaris.smf.manage.inetd,solaris.smf.value.inetd;help=RtInetdMngmnt.html
 Mail Management:::Manage sendmail & queues:auths=solaris.smf.manage.sendmail;help=RtMailMngmnt.html
-Maintenance and Repair:::Maintain and repair a system:auths=solaris.smf.manage.system-log,solaris.label.range,solaris.smf.manage.coreadm,solaris.smf.value.coreadm;help=RtMaintAndRepair.html
+Maintenance and Repair:::Maintain and repair a system:auths=solaris.smf.manage.system-log,solaris.label.range,solaris.smf.manage.coreadm,solaris.smf.value.coreadm;profiles=Hotplug Management;help=RtMaintAndRepair.html
 Media Backup:::Backup files and file systems:profiles=NDMP Management;help=RtMediaBkup.html
 Media Catalog:::Catalog files and file systems:help=RtMediaCtlg.html
 Media Restore:::Restore files and file systems from backups:profiles=NDMP Management;help=RtMediaRestore.html
--- a/usr/src/pkgdefs/SUNW0on/prototype_com	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/pkgdefs/SUNW0on/prototype_com	Mon Nov 02 15:58:28 2009 +0800
@@ -212,6 +212,8 @@
 f none usr/lib/help/auths/locale/DevConfig.html 444 root bin
 f none usr/lib/help/auths/locale/DevGrant.html 444 root bin
 f none usr/lib/help/auths/locale/DevRevoke.html 444 root bin
+f none usr/lib/help/auths/locale/HotplugHeader.html 444 root bin
+f none usr/lib/help/auths/locale/HotplugModify.html 444 root bin
 f none usr/lib/help/auths/locale/JobHeader.html 444 root bin
 f none usr/lib/help/auths/locale/AuthJobsAdmin.html 444 root bin
 f none usr/lib/help/auths/locale/JobsGrant.html 444 root bin
@@ -248,6 +250,7 @@
 f none usr/lib/help/auths/locale/SmfHeader.html 444 root bin
 f none usr/lib/help/auths/locale/SmfInetdStates.html 444 root bin
 f none usr/lib/help/auths/locale/SmfManageHeader.html 444 root bin
+f none usr/lib/help/auths/locale/SmfManageHotplug.html 444 root bin
 f none usr/lib/help/auths/locale/SmfMDNSStates.html 444 root bin
 f none usr/lib/help/auths/locale/SmfModifyAppl.html 444 root bin
 f none usr/lib/help/auths/locale/SmfModifyDepend.html 444 root bin
@@ -360,6 +363,7 @@
 f none usr/lib/help/profiles/locale/RtDeviceSecurity.html 444 root bin
 f none usr/lib/help/profiles/locale/RtFileSysMngmnt.html 444 root bin
 f none usr/lib/help/profiles/locale/RtFTPMngmnt.html 444 root bin
+f none usr/lib/help/profiles/locale/RtHotplugMngmnt.html 444 root bin
 f none usr/lib/help/profiles/locale/RtInetdMngmnt.html 444 root bin
 f none usr/lib/help/profiles/locale/RtKerberosClntMngmnt.html 444 root bin
 f none usr/lib/help/profiles/locale/RtKerberosSrvrMngmnt.html 444 root bin
--- a/usr/src/pkgdefs/SUNWarc/prototype_com	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/pkgdefs/SUNWarc/prototype_com	Mon Nov 02 15:58:28 2009 +0800
@@ -113,6 +113,8 @@
 f none usr/lib/llib-lfstyp.ln 644 root bin
 f none usr/lib/llib-lexacct 644 root bin
 f none usr/lib/llib-lexacct.ln 644 root bin
+f none usr/lib/llib-lhotplug 644 root bin
+f none usr/lib/llib-lhotplug.ln 644 root bin
 f none usr/lib/llib-lidmap 644 root bin
 f none usr/lib/llib-lidmap.ln 644 root bin
 s none usr/lib/llib-lintl=../../lib/llib-lintl
--- a/usr/src/pkgdefs/SUNWarc/prototype_i386	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/pkgdefs/SUNWarc/prototype_i386	Mon Nov 02 15:58:28 2009 +0800
@@ -89,6 +89,7 @@
 f none usr/lib/amd64/llib-lform.ln 644 root bin
 s none usr/lib/amd64/llib-lgen.ln=../../../lib/amd64/llib-lgen.ln
 f none usr/lib/amd64/llib-lgss.ln 644 root bin
+f none usr/lib/amd64/llib-lhotplug.ln 644 root bin
 s none usr/lib/amd64/llib-lintl.ln=../../../lib/amd64/llib-lintl.ln
 f none usr/lib/amd64/llib-lipmi.ln 644 root bin
 f none usr/lib/amd64/llib-lipp.ln 644 root bin
--- a/usr/src/pkgdefs/SUNWarc/prototype_sparc	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/pkgdefs/SUNWarc/prototype_sparc	Mon Nov 02 15:58:28 2009 +0800
@@ -85,6 +85,7 @@
 f none usr/lib/sparcv9/llib-lform.ln 644 root bin
 s none usr/lib/sparcv9/llib-lgen.ln=../../../lib/sparcv9/llib-lgen.ln
 f none usr/lib/sparcv9/llib-lgss.ln 644 root bin
+f none usr/lib/sparcv9/llib-lhotplug.ln 644 root bin
 s none usr/lib/sparcv9/llib-lintl.ln=../../../lib/sparcv9/llib-lintl.ln
 f none usr/lib/sparcv9/llib-lipmi.ln 644 root bin
 f none usr/lib/sparcv9/llib-lipp.ln 644 root bin
--- a/usr/src/pkgdefs/SUNWckr/prototype_i386	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/pkgdefs/SUNWckr/prototype_i386	Mon Nov 02 15:58:28 2009 +0800
@@ -229,7 +229,6 @@
 f none kernel/misc/net80211 755 root sys
 f none kernel/misc/neti 755 root sys
 f none kernel/misc/pcicfg 755 root sys
-f none kernel/misc/pciehpc 755 root sys
 f none kernel/misc/pcihp 755 root sys
 f none kernel/misc/pci_autoconfig 755 root sys
 f none kernel/misc/pcmcia 755 root sys
@@ -450,7 +449,6 @@
 f none kernel/misc/amd64/net80211 755 root sys
 f none kernel/misc/amd64/neti 755 root sys
 f none kernel/misc/amd64/pcicfg 755 root sys
-f none kernel/misc/amd64/pciehpc 755 root sys
 f none kernel/misc/amd64/pcihp 755 root sys
 f none kernel/misc/amd64/pci_autoconfig 755 root sys
 f none kernel/misc/amd64/pcmcia 755 root sys
--- a/usr/src/pkgdefs/SUNWckr/prototype_sparc	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/pkgdefs/SUNWckr/prototype_sparc	Mon Nov 02 15:58:28 2009 +0800
@@ -211,8 +211,6 @@
 f none kernel/misc/sparcv9/neti 755 root sys
 f none kernel/misc/sparcv9/pcie 755 root sys
 f none kernel/misc/sparcv9/pcihp 755 root sys
-f none kernel/misc/sparcv9/pciehpc 755 root sys
-f none kernel/misc/sparcv9/pcishpc 755 root sys
 f none kernel/misc/sparcv9/pcmcia 755 root sys
 f none kernel/misc/sparcv9/rpcsec 755 root sys
 f none kernel/misc/sparcv9/scsi 755 root sys
--- a/usr/src/pkgdefs/SUNWcsl/prototype_com	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_com	Mon Nov 02 15:58:28 2009 +0800
@@ -54,6 +54,8 @@
 s none usr/lib/cfgadm/sdcard.so=./sdcard.so.1
 f none usr/lib/cfgadm/pci.so.1 755 root bin
 s none usr/lib/cfgadm/pci.so=./pci.so.1
+f none usr/lib/cfgadm/shp.so.1 755 root bin
+s none usr/lib/cfgadm/shp.so=./shp.so.1
 f none usr/lib/cfgadm/usb.so.1 755 root bin
 s none usr/lib/cfgadm/usb.so=./usb.so.1
 f none usr/lib/cfgadm/ib.so.1 755 root bin
@@ -134,6 +136,8 @@
 s none usr/lib/libgen.so.1=../../lib/libgen.so.1
 s none usr/lib/libgen.so=../../lib/libgen.so.1
 s none usr/ccs/lib/libgen.so=../../../lib/libgen.so.1
+s none usr/lib/libhotplug.so=./libhotplug.so.1
+f none usr/lib/libhotplug.so.1 755 root bin
 f none usr/lib/libidmap.so.1 755 root bin
 s none usr/lib/libidmap.so=./libidmap.so.1
 f none usr/lib/libinetsvc.so.1 755 root bin
--- a/usr/src/pkgdefs/SUNWcsl/prototype_i386	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_i386	Mon Nov 02 15:58:28 2009 +0800
@@ -67,6 +67,8 @@
 s none usr/lib/cfgadm/amd64/sdcard.so=./sdcard.so.1
 f none usr/lib/cfgadm/amd64/pci.so.1 755 root bin
 s none usr/lib/cfgadm/amd64/pci.so=./pci.so.1
+f none usr/lib/cfgadm/amd64/shp.so.1 755 root bin
+s none usr/lib/cfgadm/amd64/shp.so=./shp.so.1
 f none usr/lib/cfgadm/amd64/usb.so.1 755 root bin
 s none usr/lib/cfgadm/amd64/usb.so=./usb.so.1
 f none usr/lib/cfgadm/amd64/ib.so.1 755 root bin
@@ -184,6 +186,8 @@
 s none usr/lib/amd64/libform.so=libform.so.1
 s none usr/lib/amd64/libgen.so.1=../../../lib/amd64/libgen.so.1
 s none usr/lib/amd64/libgen.so=../../../lib/amd64/libgen.so.1
+f none usr/lib/amd64/libhotplug.so.1 755 root bin
+s none usr/lib/amd64/libhotplug.so=libhotplug.so.1
 f none usr/lib/amd64/libidmap.so.1 755 root bin
 s none usr/lib/amd64/libidmap.so=./libidmap.so.1
 f none usr/lib/amd64/libike.so.1 755 root bin
--- a/usr/src/pkgdefs/SUNWcsl/prototype_sparc	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_sparc	Mon Nov 02 15:58:28 2009 +0800
@@ -64,6 +64,8 @@
 s none usr/lib/cfgadm/sparcv9/sdcard.so=./sdcard.so.1
 f none usr/lib/cfgadm/sparcv9/pci.so.1 755 root bin
 s none usr/lib/cfgadm/sparcv9/pci.so=./pci.so.1
+f none usr/lib/cfgadm/sparcv9/shp.so.1 755 root bin
+s none usr/lib/cfgadm/sparcv9/shp.so=./shp.so.1
 f none usr/lib/cfgadm/sparcv9/usb.so.1 755 root bin
 s none usr/lib/cfgadm/sparcv9/usb.so=./usb.so.1
 f none usr/lib/cfgadm/sparcv9/ib.so.1 755 root bin
@@ -178,6 +180,8 @@
 s none usr/lib/sparcv9/libform.so=libform.so.1
 s none usr/lib/sparcv9/libgen.so.1=../../../lib/sparcv9/libgen.so.1
 s none usr/lib/sparcv9/libgen.so=../../../lib/sparcv9/libgen.so.1
+f none usr/lib/sparcv9/libhotplug.so.1 755 root bin
+s none usr/lib/sparcv9/libhotplug.so=libhotplug.so.1
 f none usr/lib/sparcv9/libidmap.so.1 755 root bin
 s none usr/lib/sparcv9/libidmap.so=./libidmap.so.1
 f none usr/lib/sparcv9/libike.so.1 755 root bin
--- a/usr/src/pkgdefs/SUNWcsr/prototype_com	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/pkgdefs/SUNWcsr/prototype_com	Mon Nov 02 15:58:28 2009 +0800
@@ -375,6 +375,7 @@
 f none lib/svc/method/svc-consadm 0555 root bin
 f none lib/svc/method/svc-cron 0555 root bin
 f none lib/svc/method/svc-forwarding 0555 root bin
+f none lib/svc/method/svc-hotplug 0555 root bin
 f none lib/svc/method/svc-legacy-routing 0555 root bin
 f none lib/svc/method/svc-dlmgmtd 0555 root bin
 f none lib/svc/method/svc-nscd 0555 root bin
@@ -546,6 +547,7 @@
 f manifest var/svc/manifest/system/filesystem/minimal-fs.xml 0444 root sys
 f manifest var/svc/manifest/system/filesystem/root-fs.xml 0444 root sys
 f manifest var/svc/manifest/system/filesystem/usr-fs.xml 0444 root sys
+f manifest var/svc/manifest/system/hotplug.xml 0444 root sys
 d none var/svc/manifest/system/security 755 root sys
 f manifest var/svc/manifest/system/auditd.xml 0444 root sys
 f manifest var/svc/manifest/system/consadm.xml 0444 root sys
--- a/usr/src/pkgdefs/SUNWcsu/prototype_com	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/pkgdefs/SUNWcsu/prototype_com	Mon Nov 02 15:58:28 2009 +0800
@@ -475,6 +475,8 @@
 f none usr/lib/help/auths/locale/C/DevRevoke.html 444 root bin
 f none usr/lib/help/auths/locale/C/DhcpmgrHeader.html 444 root bin
 f none usr/lib/help/auths/locale/C/DhcpmgrWrite.html 444 root bin
+f none usr/lib/help/auths/locale/C/HotplugHeader.html 444 root bin
+f none usr/lib/help/auths/locale/C/HotplugModify.html 444 root bin
 f none usr/lib/help/auths/locale/C/JobHeader.html 444 root bin
 f none usr/lib/help/auths/locale/C/JobsGrant.html 444 root bin
 f none usr/lib/help/auths/locale/C/LoginEnable.html 444 root bin
@@ -494,6 +496,7 @@
 f none usr/lib/help/auths/locale/C/SmfExAcctNetStates.html 444 root bin
 f none usr/lib/help/auths/locale/C/SmfHeader.html 444 root bin
 f none usr/lib/help/auths/locale/C/SmfManageHeader.html 444 root bin
+f none usr/lib/help/auths/locale/C/SmfManageHotplug.html 444 root bin
 f none usr/lib/help/auths/locale/C/SmfMDNSStates.html 444 root bin
 f none usr/lib/help/auths/locale/C/SmfModifyAppl.html 444 root bin
 f none usr/lib/help/auths/locale/C/SmfModifyDepend.html 444 root bin
@@ -586,6 +589,7 @@
 f none usr/lib/help/profiles/locale/C/RtFTPMngmnt.html 444 root bin
 f none usr/lib/help/profiles/locale/C/RtFileSysMngmnt.html 444 root bin
 f none usr/lib/help/profiles/locale/C/RtFileSysSecurity.html 444 root bin
+f none usr/lib/help/profiles/locale/C/RtHotplugMngmnt.html 444 root bin
 f none usr/lib/help/profiles/locale/C/RtInetdMngmnt.html 444 root bin
 f none usr/lib/help/profiles/locale/C/RtIPFilterMngmnt.html 444 root bin
 f none usr/lib/help/profiles/locale/C/RtKerberosClntMngmnt.html 444 root bin
@@ -633,6 +637,7 @@
 f none usr/lib/help/profiles/locale/C/RtMMSAdmin.html 444 root bin
 f none usr/lib/help/profiles/locale/C/RtMMSOper.html 444 root bin
 f none usr/lib/help/profiles/locale/C/RtMMSUser.html 444 root bin
+f none usr/lib/hotplugd 555 root bin
 d none usr/lib/iconv 755 root bin
 f none usr/lib/iconv/646da.8859.t 444 root bin
 f none usr/lib/iconv/646de.8859.t 444 root bin
@@ -864,6 +869,7 @@
 f none usr/sbin/grpck 555 root bin
 f none usr/sbin/halt 755 root bin
 s none usr/sbin/hostconfig=../../sbin/hostconfig
+f none usr/sbin/hotplug 555 root bin
 f none usr/sbin/idmap 555 root bin
 f none usr/sbin/if_mpadm 555 root bin
 s none usr/sbin/ifconfig=../../sbin/ifconfig
--- a/usr/src/pkgdefs/SUNWefck/prototype_com	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/pkgdefs/SUNWefck/prototype_com	Mon Nov 02 15:58:28 2009 +0800
@@ -19,9 +19,7 @@
 # CDDL HEADER END
 #
 #
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-#
-# Copyright 2006 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.
@@ -54,5 +52,5 @@
 d none kernel/misc/sparcv9 755 root sys
 f none kernel/misc/sparcv9/fcodem 755 root sys
 f none kernel/misc/sparcv9/fcpci 755 root sys
-f none kernel/misc/sparcv9/pcicfg.e 755 root sys
+f none kernel/misc/sparcv9/pcicfg 755 root sys
 
--- a/usr/src/pkgdefs/SUNWhea/prototype_com	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/pkgdefs/SUNWhea/prototype_com	Mon Nov 02 15:58:28 2009 +0800
@@ -751,6 +751,8 @@
 f none usr/include/sys/ddi.h 644 root bin
 f none usr/include/sys/ddifm.h 644 root bin
 f none usr/include/sys/ddifm_impl.h 644 root bin
+f none usr/include/sys/ddi_hp.h 644 root bin
+f none usr/include/sys/ddi_hp_impl.h 644 root bin
 f none usr/include/sys/ddi_impldefs.h 644 root bin
 f none usr/include/sys/ddi_implfuncs.h 644 root bin
 f none usr/include/sys/ddi_intr.h 644 root bin
--- a/usr/src/tools/scripts/bfu.sh	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/tools/scripts/bfu.sh	Mon Nov 02 15:58:28 2009 +0800
@@ -7180,6 +7180,46 @@
 	rm -f $usr/kernel/pcbe/sparcv9/pcbe.SUNW,UltraSPARC-T1
 
 	#
+	# Remove hotplug modules
+	#
+	rm -f $root/kernel/misc/pciehpc
+	rm -f $root/kernel/misc/amd64/pciehpc
+	rm -f $root/kernel/misc/sparcv9/pciehpc
+	rm -f $root/kernel/misc/sparcv9/pcishpc
+	rm -f $root/kernel/misc/sparcv9/pcicfg.e
+	rm -f $root/kernel/misc/sparcv9/pcicfg
+	rm -f $root/lib/svc/method/svc-hotplug
+	rm -f $root/var/svc/manifest/system/hotplug.xml
+	rm -f $usr/include/sys/ddi_hp.h
+	rm -f $usr/include/sys/ddi_hp_impl.h
+	rm -f $usr/lib/cfgadm/shp.so.1
+	rm -f $usr/lib/cfgadm/shp.so
+	rm -f $usr/lib/cfgadm/amd64/shp.so.1
+	rm -f $usr/lib/cfgadm/amd64/shp.so
+	rm -f $usr/lib/cfgadm/sparcv9/shp.so.1
+	rm -f $usr/lib/cfgadm/sparcv9/shp.so
+	rm -f $usr/lib/help/auths/locale/HotplugHeader.html
+	rm -f $usr/lib/help/auths/locale/HotplugModify.html
+	rm -f $usr/lib/help/auths/locale/SmfManageHotplug.html
+	rm -f $usr/lib/help/auths/locale/C/HotplugHeader.html
+	rm -f $usr/lib/help/auths/locale/C/HotplugModify.html
+	rm -f $usr/lib/help/auths/locale/C/SmfManageHotplug.html
+	rm -f $usr/lib/help/profiles/locale/RtHotplugMngmnt.html
+	rm -f $usr/lib/help/profiles/locale/C/RtHotplugMngmnt.html
+	rm -f $usr/lib/hotplugd
+	rm -f $usr/lib/libhotplug.so
+	rm -f $usr/lib/libhotplug.so.1
+	rm -f $usr/lib/amd64/libhotplug.so.1
+	rm -f $usr/lib/amd64/libhotplug.so
+	rm -f $usr/lib/sparcv9/libhotplug.so.1
+	rm -f $usr/lib/sparcv9/libhotplug.so
+	rm -f $usr/lib/llib-lhotplug
+	rm -f $usr/lib/llib-lhotplug.ln
+	rm -f $usr/lib/amd64/llib-lhotplug.ln
+	rm -f $usr/lib/sparcv9/llib-lhotplug.ln
+	rm -f $usr/sbin/hotplug
+
+	#
         # Remove the IPsec encryption and authentication modules.
         # IPsec now uses the Kernel Crypto Framework for crypto.
         #
--- a/usr/src/uts/common/Makefile.files	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/Makefile.files	Mon Nov 02 15:58:28 2009 +0800
@@ -132,6 +132,8 @@
 		cyclic.o	\
 		ddi.o		\
 		ddifm.o		\
+		ddi_hp_impl.o	\
+		ddi_hp_ndi.o	\
 		ddi_intr.o	\
 		ddi_intr_impl.o	\
 		ddi_intr_irm.o	\
@@ -978,11 +980,9 @@
 
 HPCSVC_OBJS += hpcsvc.o
 
-PCIHPNEXUS_OBJS += pcihp.o
+PCIE_MISC_OBJS += pcie.o pcie_fault.o pcie_hp.o pciehpc.o pcishpc.o pcie_pwr.o
 
-PCIEHPCNEXUS_OBJS += pciehpc.o
-
-PCISHPC_OBJS += pcishpc.o
+PCIHPNEXUS_OBJS += pcihp.o
 
 OPENEEPR_OBJS += openprom.o
 
@@ -1813,8 +1813,6 @@
 AS_INC_PATH	+= $(INC_PATH) -I$(UTSBASE)/common
 INCLUDE_PATH    += $(INC_PATH) $(CCYFLAG)$(UTSBASE)/common
 
-#
-PCIE_MISC_OBJS += pcie.o pcie_fault.o pcie_pwr.o
 PCIEB_OBJS += pcieb.o
 
 #	Chelsio N110 10G NIC driver module
--- a/usr/src/uts/common/Makefile.rules	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/Makefile.rules	Mon Nov 02 15:58:28 2009 +0800
@@ -716,11 +716,7 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
-$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/hotplug/pciehpc/%.c
-	$(COMPILE.c) -o $@ $<
-	$(CTFCONVERT_O)
-
-$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/hotplug/pcishpc/%.c
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/pciex/hotplug/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
@@ -1993,10 +1989,7 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/hotplug/hpcsvc/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
-$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/hotplug/pciehpc/%.c
-	@($(LHEAD) $(LINT.c) $< $(LTAIL))
-
-$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/hotplug/pcishpc/%.c
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/pciex/hotplug/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/hotplug/pcihp/%.c
--- a/usr/src/uts/common/io/busra.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/io/busra.c	Mon Nov 02 15:58:28 2009 +0800
@@ -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.
  */
 
@@ -127,6 +127,15 @@
 static int claim_pci_busnum(dev_info_t *dip, void *arg);
 static int ra_map_exist(dev_info_t *dip, char *type);
 
+static int pci_get_available_prop(dev_info_t *dip, uint64_t base,
+    uint64_t len, char *busra_type);
+static int pci_put_available_prop(dev_info_t *dip, uint64_t base,
+    uint64_t len, char *busra_type);
+static uint32_t pci_type_ra2pci(char *type);
+static boolean_t is_pcie_fabric(dev_info_t *dip);
+
+#define	PCI_ADDR_TYPE_MASK	(PCI_REG_ADDR_M | PCI_REG_PF_M)
+#define	PCI_ADDR_TYPE_INVAL	0xffffffff
 
 #define	RA_INSERT(prev, el) \
 	el->ra_next = *prev; \
@@ -151,7 +160,7 @@
 	int	ret;
 
 	mutex_init(&ra_lock, NULL, MUTEX_DRIVER,
-		(void *)(intptr_t)__ipltospl(SPL7 - 1));
+	    (void *)(intptr_t)__ipltospl(SPL7 - 1));
 	if ((ret = mod_install(&modlinkage)) != 0) {
 		mutex_destroy(&ra_lock);
 	}
@@ -206,9 +215,9 @@
 	if (dipmap == NULL) {
 		if (backtype == NULL) {
 			typemapp = (struct ra_type_map *)
-			kmem_zalloc(sizeof (*typemapp), KM_SLEEP);
+			    kmem_zalloc(sizeof (*typemapp), KM_SLEEP);
 			typemapp->type = (char *)kmem_zalloc(strlen(type) + 1,
-				KM_SLEEP);
+			    KM_SLEEP);
 			(void) strcpy(typemapp->type, type);
 			RA_INSERT(&ra_map_list_head, typemapp);
 		} else {
@@ -217,7 +226,7 @@
 		if (backdip == NULL) {
 			/* allocate and insert in list of dips for this type */
 			dipmap = (struct ra_dip_type *)
-			kmem_zalloc(sizeof (*dipmap), KM_SLEEP);
+			    kmem_zalloc(sizeof (*dipmap), KM_SLEEP);
 			dipmap->ra_dip = dip;
 			RA_INSERT(&typemapp->ra_dip_list, dipmap);
 		}
@@ -413,7 +422,7 @@
 		} else if (base < mapp->ra_base) {
 			/* somewhere in between so just an insert */
 			newmap = (struct ra_resource *)
-				kmem_zalloc(sizeof (*newmap), KM_SLEEP);
+			    kmem_zalloc(sizeof (*newmap), KM_SLEEP);
 			newmap->ra_base = base;
 			newmap->ra_len = len;
 			RA_INSERT(backp, newmap);
@@ -423,13 +432,20 @@
 	if (mapp == NULL) {
 		/* stick on end */
 		newmap = (struct ra_resource *)
-				kmem_zalloc(sizeof (*newmap), KM_SLEEP);
+		    kmem_zalloc(sizeof (*newmap), KM_SLEEP);
 		newmap->ra_base = base;
 		newmap->ra_len = len;
 		RA_INSERT(backp, newmap);
 	}
 
 	mutex_exit(&ra_lock);
+
+	/*
+	 * Update dip's "available" property, adding this piece of
+	 * resource to the pool.
+	 */
+	(void) pci_put_available_prop(dip, base, len, type);
+done:
 	return (NDI_SUCCESS);
 
 overlap:
@@ -485,10 +501,9 @@
 		} else {
 			/* in the middle */
 			newmap = (struct ra_resource *)
-					kmem_zalloc(sizeof (*newmap), KM_SLEEP);
+			    kmem_zalloc(sizeof (*newmap), KM_SLEEP);
 			newmap->ra_base = base + len;
-			newmap->ra_len = mapp->ra_len -
-				(len + newlen);
+			newmap->ra_len = mapp->ra_len - (len + newlen);
 			mapp->ra_len = newlen;
 			RA_INSERT(&(mapp->ra_next), newmap);
 		}
@@ -523,7 +538,7 @@
 	if (req->ra_flags & NDI_RA_ALIGN_SIZE) {
 		if (isnot_pow2(req->ra_len)) {
 			DEBUGPRT(CE_WARN, "ndi_ra_alloc: bad length(pow2) 0x%"
-				PRIx64, req->ra_len);
+			    PRIx64, req->ra_len);
 			*retbasep = 0;
 			*retlenp = 0;
 			return (NDI_FAILURE);
@@ -543,7 +558,7 @@
 	}
 
 	DEBUGPRT(CE_CONT, "ndi_ra_alloc: mapp = %p len=%" PRIx64 ", mask=%"
-			PRIx64 "\n", (void *)mapp, len, mask);
+	    PRIx64 "\n", (void *)mapp, len, mask);
 
 	backp = &(dipmap->ra_rangeset);
 	backlargestp = NULL;
@@ -560,11 +575,10 @@
 		if ((upper == 0) || (upper < req->ra_boundlen))
 			upper = ~(uint64_t)0;
 		DEBUGPRT(CE_CONT, "ndi_ra_alloc: ra_len = %" PRIx64 ", len = %"
-				PRIx64 " ra_base=%" PRIx64 ", mask=%" PRIx64
-				"\n", mapp->ra_len, len, mapp->ra_base, mask);
-		for (; mapp != NULL &&
-			(mapp->ra_base + mapp->ra_len) < lower;
-			backp = &(mapp->ra_next), mapp = mapp->ra_next) {
+		    PRIx64 " ra_base=%" PRIx64 ", mask=%" PRIx64
+		    "\n", mapp->ra_len, len, mapp->ra_base, mask);
+		for (; mapp != NULL && (mapp->ra_base + mapp->ra_len) < lower;
+		    backp = &(mapp->ra_next), mapp = mapp->ra_next) {
 			if (((mapp->ra_len + mapp->ra_base) == 0) ||
 			    ((mapp->ra_len + mapp->ra_base) < mapp->ra_len))
 				/*
@@ -583,9 +597,9 @@
 	if (!(req->ra_flags & NDI_RA_ALLOC_SPECIFIED)) {
 		/* first fit - not user specified */
 		DEBUGPRT(CE_CONT, "ndi_ra_alloc(unspecified request)"
-			"lower=%" PRIx64 ", upper=%" PRIx64 "\n", lower, upper);
+		    "lower=%" PRIx64 ", upper=%" PRIx64 "\n", lower, upper);
 		for (; mapp != NULL && mapp->ra_base <= upper;
-			backp = &(mapp->ra_next), mapp = mapp->ra_next) {
+		    backp = &(mapp->ra_next), mapp = mapp->ra_next) {
 
 			DEBUGPRT(CE_CONT, "ndi_ra_alloc: ra_len = %" PRIx64
 			    ", len = %" PRIx64 "", mapp->ra_len, len);
@@ -606,7 +620,7 @@
 				base = base & ~mask;
 				base += (mask + 1);
 				DEBUGPRT(CE_CONT, "\tnew base=%" PRIx64 "\n",
-					base);
+				    base);
 
 				/*
 				 * Check to see if the new base is past
@@ -622,7 +636,7 @@
 					remlen = upper - base;
 				else
 					remlen = mapp->ra_len -
-						(base - mapp->ra_base);
+					    (base - mapp->ra_base);
 
 				if ((backlargestp == NULL) ||
 				    (largestlen < remlen)) {
@@ -656,7 +670,7 @@
 		base = req->ra_addr;
 		len = req->ra_len;
 		for (; mapp != NULL && mapp->ra_base <= upper;
-			backp = &(mapp->ra_next), mapp = mapp->ra_next) {
+		    backp = &(mapp->ra_next), mapp = mapp->ra_next) {
 			if (base >= mapp->ra_base &&
 			    ((base - mapp->ra_base) < mapp->ra_len)) {
 				/*
@@ -696,7 +710,7 @@
 	    (req->ra_flags & NDI_RA_ALLOC_PARTIAL_OK) &&
 	    (backlargestp != NULL)) {
 		adjust_link(backlargestp, *backlargestp, largestbase,
-			largestlen);
+		    largestlen);
 
 		base = largestbase;
 		len = largestlen;
@@ -712,6 +726,14 @@
 		*retbasep = base;
 		*retlenp = len;
 	}
+
+	/*
+	 * Update dip's "available" property, substract this piece of
+	 * resource from the pool.
+	 */
+	if ((rval == NDI_SUCCESS) || (rval == NDI_RA_PARTIAL_REQ))
+		(void) pci_get_available_prop(dip, *retbasep, *retlenp, type);
+
 	return (rval);
 }
 
@@ -748,7 +770,7 @@
 	used = ddi_find_devinfo("used-resources", -1, 0);
 	if (used == NULL) {
 		DEBUGPRT(CE_CONT,
-			"isa_resource_setup: used-resources not found");
+		    "isa_resource_setup: used-resources not found");
 		return (NDI_FAILURE);
 	}
 
@@ -869,7 +891,7 @@
 		}
 		cmn_err(CE_CONT, "type is %s\n", typemap->type);
 		for (dipmap = typemap->ra_dip_list; dipmap != NULL;
-			dipmap = dipmap->ra_next) {
+		    dipmap = dipmap->ra_next) {
 			if (dip != NULL) {
 				if ((dipmap->ra_dip) != dip)
 					continue;
@@ -877,7 +899,7 @@
 			cmn_err(CE_CONT, "  dip is %p\n",
 			    (void *)dipmap->ra_dip);
 			for (res = dipmap->ra_rangeset; res != NULL;
-				res = res->ra_next) {
+			    res = res->ra_next) {
 				cmn_err(CE_CONT, "\t  range is %" PRIx64
 				    " %" PRIx64 "\n", res->ra_base,
 				    res->ra_len);
@@ -942,6 +964,26 @@
 	 * code would really become an assert to make sure this
 	 * function is not called for the same dip twice.
 	 */
+	/*
+	 * Another user for the check below is hotplug PCI/PCIe bridges.
+	 *
+	 * For PCI/PCIE devices under a PCIE hierarchy, ndi_ra_alloc/free
+	 * will update the devinfo node's "available" property, to reflect
+	 * the fact that a piece of resource has been removed/added to
+	 * a devinfo node.
+	 * During probe of a new PCI bridge in the hotplug case, PCI
+	 * configurator firstly allocates maximum MEM/IO from its parent,
+	 * then calls ndi_ra_free() to use these resources to setup busra
+	 * pool for the new bridge, as well as adding these resources to
+	 * the "available" property of the new devinfo node. Then configu-
+	 * rator will attach driver for the bridge before probing its
+	 * children, and the bridge driver will then initialize its hotplug
+	 * contollers (if it supports hotplug) and HPC driver will call
+	 * this function to setup the busra pool, but the resource pool
+	 * has already been setup at the first of pcicfg_probe_bridge(),
+	 * thus we need the check below to return directly in this case.
+	 * Otherwise the ndi_ra_free() below will see overlapping resources.
+	 */
 	{
 		if (ra_map_exist(dip, NDI_RA_TYPE_MEM) == NDI_SUCCESS) {
 			return (NDI_FAILURE);
@@ -979,45 +1021,54 @@
 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
 	    "available", (caddr_t)&regs, &rlen) == DDI_SUCCESS) {
 		/*
+		 * Remove "available" property as the entries will be
+		 * re-created in ndi_ra_free() below, note prom based
+		 * property will not be removed. But in ndi_ra_free()
+		 * we'll be creating non prom based property entries.
+		 */
+		(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "available");
+		/*
 		 * create the available resource list for both memory and
 		 * io space
 		 */
 		rcount = rlen / sizeof (pci_regspec_t);
 		for (i = 0; i < rcount; i++) {
-		    switch (PCI_REG_ADDR_G(regs[i].pci_phys_hi)) {
-		    case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
-			(void) ndi_ra_free(dip,
-			    (uint64_t)regs[i].pci_phys_low,
-			    (uint64_t)regs[i].pci_size_low,
-			    (regs[i].pci_phys_hi & PCI_REG_PF_M) ?
-			    NDI_RA_TYPE_PCI_PREFETCH_MEM : NDI_RA_TYPE_MEM,
-			    0);
-			break;
-		    case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
-			(void) ndi_ra_free(dip,
-			    ((uint64_t)(regs[i].pci_phys_mid) << 32) |
-			    ((uint64_t)(regs[i].pci_phys_low)),
-			    ((uint64_t)(regs[i].pci_size_hi) << 32) |
-			    ((uint64_t)(regs[i].pci_size_low)),
-			    (regs[i].pci_phys_hi & PCI_REG_PF_M) ?
-			    NDI_RA_TYPE_PCI_PREFETCH_MEM : NDI_RA_TYPE_MEM,
-			    0);
-			break;
-		    case PCI_REG_ADDR_G(PCI_ADDR_IO):
-			(void) ndi_ra_free(dip,
-			    (uint64_t)regs[i].pci_phys_low,
-			    (uint64_t)regs[i].pci_size_low,
-			    NDI_RA_TYPE_IO,
-			    0);
-			break;
-		    case PCI_REG_ADDR_G(PCI_ADDR_CONFIG):
-			break;
-		    default:
-			cmn_err(CE_WARN,
-			    "pci_resource_setup: bad addr type: %x\n",
-			    PCI_REG_ADDR_G(regs[i].pci_phys_hi));
-			break;
-		    }
+			switch (PCI_REG_ADDR_G(regs[i].pci_phys_hi)) {
+			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
+				(void) ndi_ra_free(dip,
+				    (uint64_t)regs[i].pci_phys_low,
+				    (uint64_t)regs[i].pci_size_low,
+				    (regs[i].pci_phys_hi & PCI_REG_PF_M) ?
+				    NDI_RA_TYPE_PCI_PREFETCH_MEM :
+				    NDI_RA_TYPE_MEM,
+				    0);
+				break;
+			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
+				(void) ndi_ra_free(dip,
+				    ((uint64_t)(regs[i].pci_phys_mid) << 32) |
+				    ((uint64_t)(regs[i].pci_phys_low)),
+				    ((uint64_t)(regs[i].pci_size_hi) << 32) |
+				    ((uint64_t)(regs[i].pci_size_low)),
+				    (regs[i].pci_phys_hi & PCI_REG_PF_M) ?
+				    NDI_RA_TYPE_PCI_PREFETCH_MEM :
+				    NDI_RA_TYPE_MEM,
+				    0);
+				break;
+			case PCI_REG_ADDR_G(PCI_ADDR_IO):
+				(void) ndi_ra_free(dip,
+				    (uint64_t)regs[i].pci_phys_low,
+				    (uint64_t)regs[i].pci_size_low,
+				    NDI_RA_TYPE_IO,
+				    0);
+				break;
+			case PCI_REG_ADDR_G(PCI_ADDR_CONFIG):
+				break;
+			default:
+				cmn_err(CE_WARN,
+				    "pci_resource_setup: bad addr type: %x\n",
+				    PCI_REG_ADDR_G(regs[i].pci_phys_hi));
+				break;
+			}
 		}
 		kmem_free(regs, rlen);
 	}
@@ -1174,22 +1225,16 @@
 
 		switch (PCI_REG_ADDR_G(avail_p->pci_phys_hi)) {
 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32): {
-			(void) ndi_ra_free(dip,
-				(uint64_t)avail_p->pci_phys_low,
-				(uint64_t)avail_p->pci_size_low,
-				(avail_p->pci_phys_hi &
-					PCI_REG_PF_M) ?
-					NDI_RA_TYPE_PCI_PREFETCH_MEM :
-					NDI_RA_TYPE_MEM,
-				0);
+			(void) ndi_ra_free(dip, (uint64_t)avail_p->pci_phys_low,
+			    (uint64_t)avail_p->pci_size_low,
+			    (avail_p->pci_phys_hi & PCI_REG_PF_M) ?
+			    NDI_RA_TYPE_PCI_PREFETCH_MEM : NDI_RA_TYPE_MEM,
+			    0);
 			}
 			break;
 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
-			(void) ndi_ra_free(dip,
-				(uint64_t)avail_p->pci_phys_low,
-				(uint64_t)avail_p->pci_size_low,
-				NDI_RA_TYPE_IO,
-				0);
+			(void) ndi_ra_free(dip, (uint64_t)avail_p->pci_phys_low,
+			    (uint64_t)avail_p->pci_size_low, NDI_RA_TYPE_IO, 0);
 			break;
 		default:
 			goto err;
@@ -1204,6 +1249,457 @@
 
 err:
 	cmn_err(CE_WARN, "pci_resource_setup_avail: bad entry[%d]=%x\n",
-		i, avail_p->pci_phys_hi);
+	    i, avail_p->pci_phys_hi);
 	return (NDI_FAILURE);
 }
+
+/*
+ * Return true if the devinfo node resides on PCI or PCI Express bus,
+ * sitting in a PCI Express hierarchy.
+ */
+static boolean_t
+is_pcie_fabric(dev_info_t *dip)
+{
+	dev_info_t *root = ddi_root_node();
+	dev_info_t *pdip;
+	boolean_t found = B_FALSE;
+	char *bus;
+
+	/*
+	 * Is this pci/pcie ?
+	 */
+	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "device_type", &bus) !=
+	    DDI_PROP_SUCCESS) {
+		DEBUGPRT(CE_WARN, "is_pcie_fabric: cannot find "
+		    "\"device_type\" property for dip %p\n", (void *)dip);
+		return (B_FALSE);
+	}
+
+	if (strcmp(bus, "pciex") == 0) {
+		/* pcie bus, done */
+		ddi_prop_free(bus);
+		return (B_TRUE);
+	} else if (strcmp(bus, "pci") == 0) {
+		/*
+		 * pci bus, fall through to check if it resides in
+		 * a pcie hierarchy.
+		 */
+		ddi_prop_free(bus);
+	} else {
+		/* other bus, return failure */
+		ddi_prop_free(bus);
+		return (B_FALSE);
+	}
+
+	/*
+	 * Does this device reside in a pcie fabric ?
+	 */
+	for (pdip = ddi_get_parent(dip); pdip && (pdip != root) &&
+	    !found; pdip = ddi_get_parent(pdip)) {
+		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
+		    DDI_PROP_DONTPASS, "device_type", &bus) !=
+		    DDI_PROP_SUCCESS)
+			break;
+
+		if (strcmp(bus, "pciex") == 0)
+			found = B_TRUE;
+
+		ddi_prop_free(bus);
+	}
+
+	return (found);
+}
+
+/*
+ * Remove a piece of IO/MEM resource from "available" property of 'dip'.
+ */
+static int
+pci_get_available_prop(dev_info_t *dip, uint64_t base, uint64_t len,
+    char *busra_type)
+{
+	pci_regspec_t	*regs, *newregs;
+	uint_t		status;
+	int		rlen, rcount;
+	int		i, j, k;
+	uint64_t	dlen;
+	boolean_t	found = B_FALSE;
+	uint32_t	type;
+
+	/* check if we're manipulating MEM/IO resource */
+	if ((type = pci_type_ra2pci(busra_type)) == PCI_ADDR_TYPE_INVAL)
+		return (DDI_SUCCESS);
+
+	/* check if dip is a pci/pcie device resides in a pcie fabric */
+	if (!is_pcie_fabric(dip))
+		return (DDI_SUCCESS);
+
+	status = ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
+	    "available", (caddr_t)&regs, &rlen);
+
+	ASSERT(status == DDI_SUCCESS);
+	if (status != DDI_SUCCESS)
+		return (status);
+
+	/*
+	 * The updated "available" property will at most have one more entry
+	 * than existing one (when the requested range is in the middle of
+	 * the matched property entry)
+	 */
+	newregs = kmem_alloc(rlen + sizeof (pci_regspec_t), KM_SLEEP);
+
+	rcount = rlen / sizeof (pci_regspec_t);
+	for (i = 0, j = 0; i < rcount; i++) {
+		if (type == (regs[i].pci_phys_hi & PCI_ADDR_TYPE_MASK)) {
+			uint64_t range_base, range_len;
+
+			range_base = ((uint64_t)(regs[i].pci_phys_mid) << 32) |
+			    ((uint64_t)(regs[i].pci_phys_low));
+			range_len = ((uint64_t)(regs[i].pci_size_hi) << 32) |
+			    ((uint64_t)(regs[i].pci_size_low));
+
+			if ((base < range_base) ||
+			    (base + len > range_base + range_len)) {
+				/*
+				 * not a match, copy the entry
+				 */
+				goto copy_entry;
+			}
+
+			/*
+			 * range_base	base	base+len	range_base
+			 *					+range_len
+			 *   +------------+-----------+----------+
+			 *   |		  |///////////|		 |
+			 *   +------------+-----------+----------+
+			 */
+			/*
+			 * Found a match, remove the range out of this entry.
+			 */
+			found = B_TRUE;
+
+			dlen = base - range_base;
+			if (dlen != 0) {
+				newregs[j].pci_phys_hi = regs[i].pci_phys_hi;
+				newregs[j].pci_phys_mid =
+				    (uint32_t)(range_base >> 32);
+				newregs[j].pci_phys_low =
+				    (uint32_t)(range_base);
+				newregs[j].pci_size_hi = (uint32_t)(dlen >> 32);
+				newregs[j].pci_size_low = (uint32_t)dlen;
+				j++;
+			}
+
+			dlen = (range_base + range_len) - (base + len);
+			if (dlen != 0) {
+				newregs[j].pci_phys_hi = regs[i].pci_phys_hi;
+				newregs[j].pci_phys_mid =
+				    (uint32_t)((base + len)>> 32);
+				newregs[j].pci_phys_low =
+				    (uint32_t)(base + len);
+				newregs[j].pci_size_hi = (uint32_t)(dlen >> 32);
+				newregs[j].pci_size_low = (uint32_t)dlen;
+				j++;
+			}
+
+			/*
+			 * We've allocated the resource from the matched
+			 * entry, almost finished but still need to copy
+			 * the rest entries from the original property
+			 * array.
+			 */
+			for (k = i + 1; k < rcount; k++) {
+				newregs[j] = regs[k];
+				j++;
+			}
+
+			goto done;
+
+		} else {
+copy_entry:
+			newregs[j] = regs[i];
+			j++;
+		}
+	}
+
+done:
+	/*
+	 * This should not fail so assert it. For non-debug kernel we don't
+	 * want to panic thus only logging a warning message.
+	 */
+	ASSERT(found == B_TRUE);
+	if (!found) {
+		cmn_err(CE_WARN, "pci_get_available_prop: failed to remove "
+		    "resource from dip %p : base 0x%" PRIx64 ", len 0x%" PRIX64
+		    ", type 0x%x\n", (void *)dip, base, len, type);
+		kmem_free(newregs, rlen + sizeof (pci_regspec_t));
+		kmem_free(regs, rlen);
+
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Found the resources from parent, update the "available"
+	 * property.
+	 */
+	if (j == 0) {
+		/* all the resources are consumed, remove the property */
+		(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "available");
+	} else {
+		/*
+		 * There are still resource available in the parent dip,
+		 * update with the remaining resources.
+		 */
+		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
+		    "available", (int *)newregs,
+		    (j * sizeof (pci_regspec_t)) / sizeof (int));
+	}
+
+	kmem_free(newregs, rlen + sizeof (pci_regspec_t));
+	kmem_free(regs, rlen);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Add a piece of IO/MEM resource to "available" property of 'dip'.
+ */
+static int
+pci_put_available_prop(dev_info_t *dip, uint64_t base, uint64_t len,
+    char *busra_type)
+{
+	pci_regspec_t	*regs, *newregs;
+	uint_t		status;
+	int		rlen, rcount;
+	int		i, j, k;
+	int		matched = 0;
+	uint64_t	orig_base = base;
+	uint64_t	orig_len = len;
+	uint32_t	type;
+
+	/* check if we're manipulating MEM/IO resource */
+	if ((type = pci_type_ra2pci(busra_type)) == PCI_ADDR_TYPE_INVAL)
+		return (DDI_SUCCESS);
+
+	/* check if dip is a pci/pcie device resides in a pcie fabric */
+	if (!is_pcie_fabric(dip))
+		return (DDI_SUCCESS);
+
+	status = ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
+	    "available", (caddr_t)&regs, &rlen);
+
+	switch (status) {
+		case DDI_PROP_NOT_FOUND:
+			goto not_found;
+
+		case DDI_PROP_SUCCESS:
+			break;
+
+		default:
+			return (status);
+	}
+
+	/*
+	 * The "available" property exist on the node, try to put this
+	 * resource back, merge if there are adjacent resources.
+	 *
+	 * The updated "available" property will at most have one more entry
+	 * than existing one (when there is no adjacent entries thus the new
+	 * resource is appended at the end)
+	 */
+	newregs = kmem_alloc(rlen + sizeof (pci_regspec_t), KM_SLEEP);
+
+	rcount = rlen / sizeof (pci_regspec_t);
+	for (i = 0, j = 0; i < rcount; i++) {
+		if (type == (regs[i].pci_phys_hi & PCI_ADDR_TYPE_MASK)) {
+			uint64_t range_base, range_len;
+
+			range_base = ((uint64_t)(regs[i].pci_phys_mid) << 32) |
+			    ((uint64_t)(regs[i].pci_phys_low));
+			range_len = ((uint64_t)(regs[i].pci_size_hi) << 32) |
+			    ((uint64_t)(regs[i].pci_size_low));
+
+			if ((base + len < range_base) ||
+			    (base > range_base + range_len)) {
+				/*
+				 * Not adjacent, copy the entry and contiue
+				 */
+				goto copy_entry;
+			}
+
+			/*
+			 * Adjacent or overlap?
+			 *
+			 * Should not have overlapping resources so assert it.
+			 * For non-debug kernel we don't want to panic thus
+			 * only logging a warning message.
+			 */
+#if 0
+			ASSERT((base + len == range_base) ||
+			    (base == range_base + range_len));
+#endif
+			if ((base + len != range_base) &&
+			    (base != range_base + range_len)) {
+				cmn_err(CE_WARN, "pci_put_available_prop: "
+				    "failed to add resource to dip %p : "
+				    "base 0x%" PRIx64 ", len 0x%" PRIx64 " "
+				    "overlaps with existing resource "
+				    "base 0x%" PRIx64 ", len 0x%" PRIx64 "\n",
+				    (void *)dip, orig_base, orig_len,
+				    range_base, range_len);
+
+				goto failure;
+			}
+
+			/*
+			 * On the left:
+			 *
+			 * base		range_base
+			 *   +-------------+-------------+
+			 *   |/////////////|		 |
+			 *   +-------------+-------------+
+			 *	len		range_len
+			 *
+			 * On the right:
+			 *
+			 * range_base	 base
+			 *   +-------------+-------------+
+			 *   |		   |/////////////|
+			 *   +-------------+-------------+
+			 *	range_len	len
+			 */
+			/*
+			 * There are at most two piece of resources adjacent
+			 * with this resource, assert it.
+			 */
+			ASSERT(matched < 2);
+
+			if (!(matched < 2)) {
+				cmn_err(CE_WARN, "pci_put_available_prop: "
+				    "failed to add resource to dip %p : "
+				    "base 0x%" PRIx64 ", len 0x%" PRIx64 " "
+				    "found overlaps in existing resources\n",
+				    (void *)dip, orig_base, orig_len);
+
+				goto failure;
+			}
+
+			/* setup base & len to refer to the merged range */
+			len += range_len;
+			if (base == range_base + range_len)
+				base = range_base;
+
+			if (matched == 0) {
+				/*
+				 * One adjacent entry, add this resource in
+				 */
+				newregs[j].pci_phys_hi = regs[i].pci_phys_hi;
+				newregs[j].pci_phys_mid =
+				    (uint32_t)(base >> 32);
+				newregs[j].pci_phys_low = (uint32_t)(base);
+				newregs[j].pci_size_hi = (uint32_t)(len >> 32);
+				newregs[j].pci_size_low = (uint32_t)len;
+
+				matched = 1;
+				k = j;
+				j++;
+			} else { /* matched == 1 */
+				/*
+				 * Two adjacent entries, merge them together
+				 */
+				newregs[k].pci_phys_hi = regs[i].pci_phys_hi;
+				newregs[k].pci_phys_mid =
+				    (uint32_t)(base >> 32);
+				newregs[k].pci_phys_low = (uint32_t)(base);
+				newregs[k].pci_size_hi = (uint32_t)(len >> 32);
+				newregs[k].pci_size_low = (uint32_t)len;
+
+				matched = 2;
+			}
+		} else {
+copy_entry:
+			newregs[j] = regs[i];
+			j++;
+		}
+	}
+
+	if (matched == 0) {
+		/* No adjacent entries, append at end */
+		ASSERT(j == rcount);
+
+		/*
+		 * According to page 15 of 1275 spec, bit "n" of "available"
+		 * should be set to 1.
+		 */
+		newregs[j].pci_phys_hi = type;
+		newregs[j].pci_phys_hi |= PCI_REG_REL_M;
+
+		newregs[j].pci_phys_mid = (uint32_t)(base >> 32);
+		newregs[j].pci_phys_low = (uint32_t)base;
+		newregs[j].pci_size_hi = (uint32_t)(len >> 32);
+		newregs[j].pci_size_low = (uint32_t)len;
+
+		j++;
+	}
+
+	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
+	    "available", (int *)newregs,
+	    (j * sizeof (pci_regspec_t)) / sizeof (int));
+
+	kmem_free(newregs, rlen + sizeof (pci_regspec_t));
+	kmem_free(regs, rlen);
+	return (DDI_SUCCESS);
+
+not_found:
+	/*
+	 * There is no "available" property on the parent node, create it.
+	 */
+	newregs = kmem_alloc(sizeof (pci_regspec_t), KM_SLEEP);
+
+	/*
+	 * According to page 15 of 1275 spec, bit "n" of "available" should
+	 * be set to 1.
+	 */
+	newregs[0].pci_phys_hi = type;
+	newregs[0].pci_phys_hi |= PCI_REG_REL_M;
+
+	newregs[0].pci_phys_mid = (uint32_t)(base >> 32);
+	newregs[0].pci_phys_low = (uint32_t)base;
+	newregs[0].pci_size_hi = (uint32_t)(len >> 32);
+	newregs[0].pci_size_low = (uint32_t)len;
+
+	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
+	    "available", (int *)newregs,
+	    sizeof (pci_regspec_t) / sizeof (int));
+	kmem_free(newregs, sizeof (pci_regspec_t));
+	return (DDI_SUCCESS);
+
+failure:
+	kmem_free(newregs, rlen + sizeof (pci_regspec_t));
+	kmem_free(regs, rlen);
+	return (DDI_FAILURE);
+}
+
+static uint32_t
+pci_type_ra2pci(char *type)
+{
+	uint32_t	pci_type = PCI_ADDR_TYPE_INVAL;
+
+	/*
+	 * No 64 bit mem support for now
+	 */
+	if (strcmp(type, NDI_RA_TYPE_IO) == 0) {
+		pci_type = PCI_ADDR_IO;
+
+	} else if (strcmp(type, NDI_RA_TYPE_MEM) == 0) {
+		pci_type = PCI_ADDR_MEM32;
+
+	} else if (strcmp(type, NDI_RA_TYPE_PCI_PREFETCH_MEM)  == 0) {
+		pci_type = PCI_ADDR_MEM32;
+		pci_type |= PCI_REG_PF_M;
+	}
+
+	return (pci_type);
+}
--- a/usr/src/uts/common/io/devinfo.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/io/devinfo.c	Mon Nov 02 15:58:28 2009 +0800
@@ -54,6 +54,10 @@
 #include <sys/disp.h>
 #include <sys/kobj.h>
 #include <sys/crc32.h>
+#include <sys/ddi_hp.h>
+#include <sys/ddi_hp_impl.h>
+#include <sys/sysmacros.h>
+#include <sys/list.h>
 
 
 #ifdef DEBUG
@@ -231,6 +235,12 @@
 	i_link_t	*link_out;
 } i_lnode_t;
 
+typedef struct i_hp {
+	di_off_t	hp_off;		/* Offset of di_hp_t in snapshot */
+	dev_info_t	*hp_child;	/* Child devinfo node of the di_hp_t */
+	list_node_t	hp_link;	/* List linkage */
+} i_hp_t;
+
 /*
  * Soft state associated with each instance of driver open.
  */
@@ -246,6 +256,8 @@
 
 	mod_hash_t	*lnode_hash;
 	mod_hash_t	*link_hash;
+
+	list_t		hp_list;
 } **di_states;
 
 static kmutex_t di_lock;	/* serialize instance assignment */
@@ -298,6 +310,8 @@
     struct di_state *);
 static di_off_t di_getppdata(struct dev_info *, di_off_t *, struct di_state *);
 static di_off_t di_getdpdata(struct dev_info *, di_off_t *, struct di_state *);
+static di_off_t di_gethpdata(ddi_hp_cn_handle_t *, di_off_t *,
+    struct di_state *);
 static di_off_t di_getprop(int, struct ddi_prop **, di_off_t *,
     struct di_state *, struct dev_info *);
 static void di_allocmem(struct di_state *, size_t);
@@ -320,6 +334,7 @@
 static void di_cache_print(di_cache_debug_t msglevel, char *fmt, ...);
 static int build_vhci_list(dev_info_t *vh_devinfo, void *arg);
 static int build_phci_list(dev_info_t *ph_devinfo, void *arg);
+static void di_hotplug_children(struct di_state *st);
 
 extern int modrootloaded;
 extern void mdi_walk_vhcis(int (*)(dev_info_t *, void *), void *);
@@ -1341,6 +1356,11 @@
 	    di_key_dtor, mod_hash_null_valdtor, di_hash_byptr,
 	    NULL, di_key_cmp, KM_SLEEP);
 
+	if (DINFOHP & st->command) {
+		list_create(&st->hp_list, sizeof (i_hp_t),
+		    offsetof(i_hp_t, hp_link));
+	}
+
 	/*
 	 * copy the device tree
 	 */
@@ -1350,6 +1370,10 @@
 		mdi_walk_vhcis(build_vhci_list, st);
 	}
 
+	if (DINFOHP & st->command) {
+		di_hotplug_children(st);
+	}
+
 	ddi_release_devi(rootnode);
 
 	/*
@@ -1696,7 +1720,8 @@
 {
 	di_off_t	off;
 	struct di_node	*me;
-	size_t		size;	struct dev_info *n;
+	size_t		size;
+	struct dev_info *n;
 
 	dcmn_err2((CE_CONT, "di_copynode: depth = %x\n", dsp->depth));
 	ASSERT((node != NULL) && (node == TOP_NODE(dsp)));
@@ -1820,7 +1845,7 @@
 	/*
 	 * An optimization to skip mutex_enter when not needed.
 	 */
-	if (!((DINFOMINOR | DINFOPROP | DINFOPATH) & st->command)) {
+	if (!((DINFOMINOR | DINFOPROP | DINFOPATH | DINFOHP) & st->command)) {
 		goto priv_data;
 	}
 
@@ -1873,7 +1898,7 @@
 
 property:
 	if (!(DINFOPROP & st->command)) {
-		goto priv_data;
+		goto hotplug_data;
 	}
 
 	if (node->devi_drv_prop_ptr) {	/* driver property list */
@@ -1913,6 +1938,16 @@
 		}
 	}
 
+hotplug_data:
+	if (!(DINFOHP & st->command)) {
+		goto priv_data;
+	}
+
+	if (node->devi_hp_hdlp) {	/* hotplug data */
+		me->hp_data = off;
+		off = di_gethpdata(node->devi_hp_hdlp, &me->hp_data, st);
+	}
+
 priv_data:
 	if (!(DINFOPRIVDATA & st->command)) {
 		goto pm_info;
@@ -3447,6 +3482,88 @@
 }
 
 /*
+ * Copy hotplug data associated with a devinfo node into the snapshot.
+ */
+static di_off_t
+di_gethpdata(ddi_hp_cn_handle_t *hp_hdl, di_off_t *off_p,
+    struct di_state *st)
+{
+	struct i_hp	*hp;
+	struct di_hp	*me;
+	size_t		size;
+	di_off_t	off;
+
+	dcmn_err2((CE_CONT, "di_gethpdata:\n"));
+
+	/*
+	 * check memory first
+	 */
+	off = di_checkmem(st, *off_p, sizeof (struct di_hp));
+	*off_p = off;
+
+	do {
+		me = DI_HP(di_mem_addr(st, off));
+		me->self = off;
+		me->hp_name = 0;
+		me->hp_connection = (int)hp_hdl->cn_info.cn_num;
+		me->hp_depends_on = (int)hp_hdl->cn_info.cn_num_dpd_on;
+		(void) ddihp_cn_getstate(hp_hdl);
+		me->hp_state = (int)hp_hdl->cn_info.cn_state;
+		me->hp_type = (int)hp_hdl->cn_info.cn_type;
+		me->hp_type_str = 0;
+		me->hp_last_change = (uint32_t)hp_hdl->cn_info.cn_last_change;
+		me->hp_child = 0;
+
+		/*
+		 * Child links are resolved later by di_hotplug_children().
+		 * Store a reference to this di_hp_t in the list used later
+		 * by di_hotplug_children().
+		 */
+		hp = kmem_zalloc(sizeof (i_hp_t), KM_SLEEP);
+		hp->hp_off = off;
+		hp->hp_child = hp_hdl->cn_info.cn_child;
+		list_insert_tail(&st->hp_list, hp);
+
+		off += sizeof (struct di_hp);
+
+		/* Add name of this di_hp_t to the snapshot */
+		if (hp_hdl->cn_info.cn_name) {
+			size = strlen(hp_hdl->cn_info.cn_name) + 1;
+			me->hp_name = off = di_checkmem(st, off, size);
+			(void) strcpy(di_mem_addr(st, off),
+			    hp_hdl->cn_info.cn_name);
+			off += size;
+		}
+
+		/* Add type description of this di_hp_t to the snapshot */
+		if (hp_hdl->cn_info.cn_type_str) {
+			size = strlen(hp_hdl->cn_info.cn_type_str) + 1;
+			me->hp_type_str = off = di_checkmem(st, off, size);
+			(void) strcpy(di_mem_addr(st, off),
+			    hp_hdl->cn_info.cn_type_str);
+			off += size;
+		}
+
+		/*
+		 * Set link to next in the chain of di_hp_t nodes,
+		 * or terminate the chain when processing the last node.
+		 */
+		if (hp_hdl->next != NULL) {
+			off = di_checkmem(st, off, sizeof (struct di_hp));
+			me->next = off;
+		} else {
+			me->next = 0;
+		}
+
+		/* Update pointer to next in the chain */
+		hp_hdl = hp_hdl->next;
+
+	} while (hp_hdl);
+
+	return (off);
+}
+
+/*
  * The driver is stateful across DINFOCPYALL and DINFOUSRLD.
  * This function encapsulates the state machine:
  *
@@ -4075,3 +4192,24 @@
 	vcmn_err(msglevel, fmt, ap);
 	va_end(ap);
 }
+
+static void
+di_hotplug_children(struct di_state *st)
+{
+	di_off_t	off;
+	struct di_hp	*hp;
+	struct i_hp	*hp_list_node;
+
+	while (hp_list_node = (struct i_hp *)list_remove_head(&st->hp_list)) {
+
+		if ((hp_list_node->hp_child != NULL) &&
+		    (di_dip_find(st, hp_list_node->hp_child, &off) == 0)) {
+			hp = DI_HP(di_mem_addr(st, hp_list_node->hp_off));
+			hp->hp_child = off;
+		}
+
+		kmem_free(hp_list_node, sizeof (i_hp_t));
+	}
+
+	list_destroy(&st->hp_list);
+}
--- a/usr/src/uts/common/io/hotplug/pciehpc/pciehpc.c	Sun Nov 01 14:14:46 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1982 +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 2008 Sun Microsystems, Inc.  All rights reserved.
- *  Use is subject to license terms.
- */
-
-/*
- * PCIEHPC - The Standard PCI Express HotPlug Controller driver module. This
- *           driver can be used with PCI Express HotPlug controllers that
- *           are compatible with the PCI Express ver 1.0a specification.
- */
-
-#include <sys/types.h>
-#include <sys/note.h>
-#include <sys/conf.h>
-#include <sys/kmem.h>
-#include <sys/debug.h>
-#include <sys/vtrace.h>
-#include <sys/modctl.h>
-#include <sys/autoconf.h>
-#include <sys/varargs.h>
-#include <sys/ddi_impldefs.h>
-#include <sys/pci.h>
-#include <sys/time.h>
-#include <sys/callb.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-#include <sys/pcie_impl.h>
-#include <sys/hotplug/pci/pciehpc_impl.h>
-
-/*
- * Local data/functions
- */
-
-/* mutex to protect pciehpc_head list */
-static kmutex_t pciehpc_list_mutex;
-
-/* pointer to linked list of pciehpc structures */
-static pciehpc_t *pciehpc_head = NULL;
-
-/* mutex to protect init/uninit controllers */
-static kmutex_t pciehpc_init_mutex;
-static int pciehpc_init_count = 0; /* count of pciehpc instances in use */
-
-static pciehpc_t *pciehpc_create_soft_state(dev_info_t *dip);
-static pciehpc_t *pciehpc_get_soft_state(dev_info_t *dip);
-static void pciehpc_destroy_soft_state(dev_info_t *dip);
-static char *pciehpc_led_state_text(hpc_led_state_t state);
-static void pciehpc_attn_btn_handler(pciehpc_t *ctrl_p);
-static void pciehpc_dev_info(pciehpc_t *ctrl_p);
-
-static int pciehpc_pcie_dev(dev_info_t *dip, ddi_acc_handle_t handle);
-static void pciehpc_disable_errors(pciehpc_t *ctrl_p);
-static void pciehpc_enable_errors(pciehpc_t *ctrl_p);
-
-#ifdef DEBUG
-int pciehpc_debug = 0;
-static void pciehpc_dump_hpregs(pciehpc_t *ctrl_p);
-#endif
-
-/*
- * Module linkage information for the kernel.
- */
-extern struct mod_ops mod_miscops;
-static struct modlmisc modlmisc =
-{
-	&mod_miscops,
-	"PCIe hotplug driver",
-};
-
-static struct modlinkage modlinkage =
-{
-	MODREV_1,
-	&modlmisc,
-	NULL
-};
-
-
-int
-_init(void)
-{
-	int error;
-
-	PCIEHPC_DEBUG3((CE_NOTE, "pciehpc: _init() called\n"));
-	mutex_init(&pciehpc_list_mutex, NULL, MUTEX_DRIVER, NULL);
-	mutex_init(&pciehpc_init_mutex, NULL, MUTEX_DRIVER, NULL);
-	if ((error = mod_install(&modlinkage)) != 0) {
-		mutex_destroy(&pciehpc_init_mutex);
-		mutex_destroy(&pciehpc_list_mutex);
-	}
-
-	return (error);
-}
-
-int
-_fini(void)
-{
-	int error;
-
-	PCIEHPC_DEBUG3((CE_NOTE, "pciehpc: _fini() called\n"));
-
-	mutex_enter(&pciehpc_init_mutex);
-	if (pciehpc_init_count != 0) {
-		mutex_exit(&pciehpc_init_mutex);
-		return (EBUSY);
-	}
-	error = mod_remove(&modlinkage);
-	if (error != 0) {
-		mutex_exit(&pciehpc_init_mutex);
-		return (error);
-	}
-	mutex_destroy(&pciehpc_list_mutex);
-	mutex_destroy(&pciehpc_init_mutex);
-	return (0);
-}
-
-int
-_info(struct modinfo *modinfop)
-{
-	PCIEHPC_DEBUG3((CE_NOTE, "pciehpc: _info() called\n"));
-	return (mod_info(&modlinkage, modinfop));
-}
-
-/*
- * pciehpc_init()
- *
- * Initialize Hot Plug Controller if present. The arguments are:
- *	dip	- Devinfo node pointer to the hot plug bus node
- *	regops	- register ops to access HPC registers for non-standard
- *		  HPC hw implementations (e.g: HPC in host PCI-E brdiges)
- *		  This is NULL for standard HPC in PCIe bridges.
- * Returns:
- *	DDI_SUCCESS for successful HPC initialization
- *	DDI_FAILURE for errors or if HPC hw not found
- */
-int
-pciehpc_init(dev_info_t *dip, pciehpc_regops_t *regops)
-{
-	pciehpc_t *ctrl_p;
-
-	PCIEHPC_DEBUG3((CE_NOTE, "pciehpc_init() called (dip=%p)",
-	    (void *)dip));
-
-	mutex_enter(&pciehpc_init_mutex);
-
-	/* Make sure that it is not already initialized */
-	if (pciehpc_get_soft_state(dip) != NULL) {
-	    PCIEHPC_DEBUG((CE_WARN,
-		"%s%d: pciehpc instance already initialized!",
-		ddi_driver_name(dip), ddi_get_instance(dip)));
-		mutex_exit(&pciehpc_init_mutex);
-		return (DDI_SUCCESS);
-	}
-
-	/* allocate a new soft state structure */
-	ctrl_p = pciehpc_create_soft_state(dip);
-
-	/* get PCI device info */
-	pciehpc_dev_info(ctrl_p);
-
-	/* setup access handle for HPC regs */
-	if (regops != NULL) {
-		/* HPC access is non-standard; use the supplied reg ops */
-		ctrl_p->regops = *regops;
-	} else {
-		/* standard HPC in a PCIe bridge */
-		if (pciehpc_regs_setup(dip, 0, 0, &ctrl_p->regs_base,
-		    &ctrl_p->cfghdl) != DDI_SUCCESS)
-		    goto cleanup;
-	}
-
-	pciehpc_disable_errors(ctrl_p);
-
-	/*
-	 * Set the platform specific hot plug mode.
-	 */
-	ctrl_p->hp_mode = PCIEHPC_NATIVE_HP_MODE; /* default is Native mode */
-	ctrl_p->ops.init_hpc_hw = pciehpc_hpc_init;
-	ctrl_p->ops.init_hpc_slotinfo = pciehpc_slotinfo_init;
-	ctrl_p->ops.disable_hpc_intr = pciehpc_disable_intr;
-	ctrl_p->ops.enable_hpc_intr = pciehpc_enable_intr;
-	ctrl_p->ops.uninit_hpc_hw = pciehpc_hpc_uninit;
-	ctrl_p->ops.uninit_hpc_slotinfo = pciehpc_slotinfo_uninit;
-	ctrl_p->ops.probe_hpc = pciehpc_probe_hpc;
-
-#if	defined(__i386) || defined(__amd64)
-	pciehpc_update_ops(ctrl_p);
-#endif
-	if (regops == NULL) { /* it is a standard HPC in a PCIe bridge */
-	    /* make sure we really have a hot plug controller */
-	    if ((ctrl_p->ops.probe_hpc)(ctrl_p) != DDI_SUCCESS)
-		goto cleanup1;
-	}
-
-	/* initialize hot plug controller hw */
-	if ((ctrl_p->ops.init_hpc_hw)(ctrl_p) != DDI_SUCCESS)
-		goto cleanup1;
-
-	/* initialize slot information soft state structure */
-	if ((ctrl_p->ops.init_hpc_slotinfo)(ctrl_p) != DDI_SUCCESS)
-		goto cleanup2;
-
-	/* register the hot plug slot with HPS framework */
-	if (pciehpc_register_slot(ctrl_p) != DDI_SUCCESS)
-		goto cleanup3;
-
-	/* HPC initialization is complete now */
-	ctrl_p->soft_state |= PCIEHPC_SOFT_STATE_INITIALIZED;
-	ctrl_p->soft_state &= ~PCIEHPC_SOFT_STATE_UNINITIALIZED;
-
-#ifdef DEBUG
-	/* For debug, dump the HPC registers */
-	if (pciehpc_debug > 2)
-		pciehpc_dump_hpregs(ctrl_p);
-#endif
-
-	/* enable hot plug interrupts/event */
-	(void) (ctrl_p->ops.enable_hpc_intr)(ctrl_p);
-
-	pciehpc_init_count++;
-
-	mutex_exit(&pciehpc_init_mutex);
-
-	return (DDI_SUCCESS);
-
-cleanup3:
-	(void) (ctrl_p->ops.uninit_hpc_slotinfo)(ctrl_p);
-
-cleanup2:
-	(void) (ctrl_p->ops.uninit_hpc_hw)(ctrl_p);
-
-cleanup1:
-	pciehpc_enable_errors(ctrl_p);
-	/* free up the HPC register mapping  if applicable */
-	if (ctrl_p->cfghdl)
-		pciehpc_regs_teardown(&ctrl_p->cfghdl);
-
-cleanup:
-	pciehpc_destroy_soft_state(dip);
-	mutex_exit(&pciehpc_init_mutex);
-	return (DDI_FAILURE);
-}
-
-/*
- * Uninitialize HPC soft state structure and free up any resources
- * used for the HPC instance.
- */
-int
-pciehpc_uninit(dev_info_t *dip)
-{
-	pciehpc_t *ctrl_p;
-
-	PCIEHPC_DEBUG3((CE_NOTE, "pciehpc_uninit() called (dip=%p)\n",
-	    (void *)dip));
-
-	mutex_enter(&pciehpc_init_mutex);
-
-	/* get the soft state structure for this dip */
-	if ((ctrl_p = pciehpc_get_soft_state(dip)) == NULL) {
-		mutex_exit(&pciehpc_init_mutex);
-		return (DDI_FAILURE);
-	}
-
-	/* disable interrupts */
-	(void) (ctrl_p->ops.disable_hpc_intr)(ctrl_p);
-
-	/* unregister the slot */
-	(void) pciehpc_unregister_slot(ctrl_p);
-
-	/* uninit any slot info data structures */
-	(void) (ctrl_p->ops.uninit_hpc_slotinfo)(ctrl_p);
-
-	/* uninitialize hpc, remove interrupt handler, etc. */
-	(void) (ctrl_p->ops.uninit_hpc_hw)(ctrl_p);
-
-	pciehpc_enable_errors(ctrl_p);
-
-	/* free up the HPC register mapping  if applicable */
-	if (ctrl_p->cfghdl)
-		pciehpc_regs_teardown(&ctrl_p->cfghdl);
-
-	/* destroy the soft state structure */
-	pciehpc_destroy_soft_state(dip);
-
-	ASSERT(pciehpc_init_count != 0);
-
-	pciehpc_init_count--;
-
-	mutex_exit(&pciehpc_init_mutex);
-
-	return (DDI_SUCCESS);
-}
-
-/*
- * Probe for the inband PCI-E hot plug controller. Returns DDI_SUCCESS
- * if found. This function works only for the standard PCI-E bridge
- * that has inband hot plug controller.
- *
- * NOTE: This won't work for Host-PCIE bridges.
- */
-int
-pciehpc_probe_hpc(pciehpc_t *ctrl_p)
-{
-	uint8_t cap_ptr;
-	uint8_t cap_id;
-	uint16_t status;
-
-	/* Read the PCI configuration status register. */
-	status = pciehpc_reg_get16(ctrl_p, PCI_CONF_STAT);
-
-	/* check for capabilities list */
-	if (!(status & PCI_STAT_CAP)) {
-		/* no capabilities list */
-		return (DDI_FAILURE);
-	}
-
-	/* Get a pointer to the PCI capabilities list. */
-	cap_ptr = pciehpc_reg_get8(ctrl_p, PCI_BCNF_CAP_PTR);
-	cap_ptr &= 0xFC; /* mask off reserved bits */
-
-	/*
-	 * Walk thru the capabilities list looking for PCI Express capability
-	 * structure.
-	 */
-	while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
-	    cap_id = pciehpc_reg_get8(ctrl_p, (uint_t)cap_ptr);
-
-	    PCIEHPC_DEBUG3((CE_NOTE, "pciehpc_probe_hpc() capability @"
-		" pointer=%02x (id=%02x)\n", cap_ptr, cap_id));
-
-	    if (cap_id == PCI_CAP_ID_PCI_E) {
-		uint32_t slot_cap;
-
-		/* Read the PCI Express Slot Capabilities Register */
-		slot_cap = pciehpc_reg_get32(ctrl_p,
-				(uint_t)cap_ptr + PCIE_SLOTCAP);
-
-		/* Does it have PCI Express HotPlug capability? */
-		if (slot_cap & PCIE_SLOTCAP_HP_CAPABLE) {
-		    /* Save the offset to PCI Express Capabilities structure */
-		    ctrl_p->pcie_caps_reg_offset = cap_ptr;
-		    return (DDI_SUCCESS);
-		}
-	    }
-
-	    /* Get the pointer to the next capability */
-	    cap_ptr = pciehpc_reg_get8(ctrl_p, (uint_t)cap_ptr + 1);
-	    cap_ptr &= 0xFC;
-	}
-
-	return (DDI_FAILURE);
-}
-
-/*
- * Setup slot information for use with HPS framework.
- */
-int
-pciehpc_slotinfo_init(pciehpc_t *ctrl_p)
-{
-	uint32_t slot_capabilities, link_capabilities;
-	pciehpc_slot_t *p = &ctrl_p->slot;
-
-	/*
-	 * setup HPS framework slot ops structure
-	 */
-	p->slot_ops.hpc_version = HPC_SLOT_OPS_VERSION;
-	p->slot_ops.hpc_op_connect = pciehpc_slot_connect;
-	p->slot_ops.hpc_op_disconnect = pciehpc_slot_disconnect;
-	p->slot_ops.hpc_op_insert = NULL;
-	p->slot_ops.hpc_op_remove = NULL;
-	p->slot_ops.hpc_op_control = pciehpc_slot_control;
-
-	/*
-	 * setup HPS framework slot information structure
-	 */
-	p->slot_info.version = HPC_SLOT_OPS_VERSION;
-	p->slot_info.slot_type = HPC_SLOT_TYPE_PCIE;
-	p->slot_info.slot_flags =
-		HPC_SLOT_CREATE_DEVLINK | HPC_SLOT_NO_AUTO_ENABLE;
-	p->slot_info.pci_slot_capabilities = HPC_SLOT_64BITS;
-	/* the device number is fixed as 0 as per the spec  */
-	p->slot_info.pci_dev_num = 0;
-
-	/* read Slot Capabilities Register */
-	slot_capabilities = pciehpc_reg_get32(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCAP);
-
-	/* set slot-name/slot-number info */
-	pciehpc_set_slot_name(ctrl_p);
-
-	/* check if Attn Button present */
-	ctrl_p->has_attn = (slot_capabilities & PCIE_SLOTCAP_ATTN_BUTTON) ?
-		B_TRUE : B_FALSE;
-
-	/* check if Manual Retention Latch sensor present */
-	ctrl_p->has_mrl = (slot_capabilities & PCIE_SLOTCAP_MRL_SENSOR) ?
-		B_TRUE : B_FALSE;
-
-	/*
-	 * PCI-E version 1.1 defines EMI Lock Present bit
-	 * in Slot Capabilities register. Check for it.
-	 */
-	ctrl_p->has_emi_lock = (slot_capabilities &
-		PCIE_SLOTCAP_EMI_LOCK_PRESENT) ? B_TRUE : B_FALSE;
-
-	link_capabilities = pciehpc_reg_get32(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_LINKCAP);
-	ctrl_p->dll_active_rep = (link_capabilities &
-		PCIE_LINKCAP_DLL_ACTIVE_REP_CAPABLE) ? B_TRUE : B_FALSE;
-	if (ctrl_p->dll_active_rep)
-		cv_init(&ctrl_p->slot.dll_active_cv, NULL, CV_DRIVER, NULL);
-
-	/* initialize synchronization conditional variable */
-	cv_init(&ctrl_p->slot.cmd_comp_cv, NULL, CV_DRIVER, NULL);
-	ctrl_p->slot.command_pending = B_FALSE;
-
-	/* setup thread for handling ATTN button events */
-	if (ctrl_p->has_attn) {
-		PCIEHPC_DEBUG3((CE_NOTE,
-		    "pciehpc_slotinfo_init: setting up ATTN button event "
-		    "handler thread for slot %d\n", ctrl_p->slot.slotNum));
-		cv_init(&ctrl_p->slot.attn_btn_cv, NULL, CV_DRIVER, NULL);
-		ctrl_p->slot.attn_btn_pending = B_FALSE;
-		ctrl_p->slot.attn_btn_threadp = thread_create(NULL, 0,
-			pciehpc_attn_btn_handler,
-			(void *)ctrl_p, 0, &p0, TS_RUN, minclsyspri);
-		ctrl_p->slot.attn_btn_thread_exit = B_FALSE;
-	}
-
-	/* get current slot state from the hw */
-	pciehpc_get_slot_state(ctrl_p);
-
-	return (DDI_SUCCESS);
-}
-
-/*ARGSUSED*/
-int
-pciehpc_slotinfo_uninit(pciehpc_t *ctrl_p)
-{
-	cv_destroy(&ctrl_p->slot.cmd_comp_cv);
-
-	if (ctrl_p->slot.attn_btn_threadp != NULL) {
-	    mutex_enter(&ctrl_p->pciehpc_mutex);
-	    ctrl_p->slot.attn_btn_thread_exit = B_TRUE;
-	    cv_signal(&ctrl_p->slot.attn_btn_cv);
-	    PCIEHPC_DEBUG3((CE_NOTE,
-		"pciehpc_slotinfo_uninit: waiting for ATTN thread exit\n"));
-	    cv_wait(&ctrl_p->slot.attn_btn_cv, &ctrl_p->pciehpc_mutex);
-	    PCIEHPC_DEBUG3((CE_NOTE,
-		"pciehpc_slotinfo_uninit: ATTN thread exit\n"));
-	    cv_destroy(&ctrl_p->slot.attn_btn_cv);
-	    ctrl_p->slot.attn_btn_threadp = NULL;
-	    mutex_exit(&ctrl_p->pciehpc_mutex);
-	}
-
-	if (ctrl_p->dll_active_rep)
-		cv_destroy(&ctrl_p->slot.dll_active_cv);
-
-	return (DDI_SUCCESS);
-}
-
-/*
- * Get the current state of the slot from the hw.
- */
-void
-pciehpc_get_slot_state(pciehpc_t *ctrl_p)
-{
-	pciehpc_slot_t *p = &ctrl_p->slot;
-	uint16_t control, status;
-
-	/* read the Slot Control Register */
-	control = pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-
-	p->fault_led_state = HPC_LED_OFF; /* no fault led */
-	p->active_led_state = HPC_LED_OFF; /* no active led */
-
-	/* read the current Slot Status Register */
-	status = pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS);
-
-	/* get POWER led state */
-	p->power_led_state =
-	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control));
-
-	/* get ATTN led state */
-	p->attn_led_state =
-	    pciehpc_led_state_to_hpc(pcie_slotctl_attn_indicator_get(control));
-
-	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED))
-		/* no device present; slot is empty */
-		p->slot_state = HPC_SLOT_EMPTY;
-
-	else if (!(control & PCIE_SLOTCTL_PWR_CONTROL))
-		/* device is present and powered up */
-		p->slot_state = HPC_SLOT_CONNECTED;
-	else
-		/* device is present and powered down */
-		p->slot_state = HPC_SLOT_DISCONNECTED;
-}
-
-
-/*
- * pciehpc_regs_setup()
- *
- * Setup PCI-E config registers for DDI access functions.
- *
- * Note: This is same as pci_config_setup() except that this may be
- * used to map specific reg set with an offset in the case of host
- * PCI-E bridges.
- */
-int
-pciehpc_regs_setup(dev_info_t *dip, uint_t rnum, offset_t off,
-	caddr_t *addrp, ddi_acc_handle_t *handle)
-{
-	ddi_device_acc_attr_t attr;
-
-	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
-	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
-	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
-
-	/* Check for fault management capabilities */
-	if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(dip)))
-		attr.devacc_attr_access = DDI_FLAGERR_ACC;
-
-	return (ddi_regs_map_setup(dip, rnum, addrp, off, 0, &attr, handle));
-}
-
-/*
- * pciehpc_regs_teardown()
- *
- * Unmap config register set.
- *
- * Note: This is same as pci_config_teardown() function.
- */
-void
-pciehpc_regs_teardown(ddi_acc_handle_t *handle)
-{
-	ddi_regs_map_free(handle);
-}
-
-/*
- * Find the soft state structure for the HPC associated with the dip.
- */
-static pciehpc_t *
-pciehpc_get_soft_state(dev_info_t *dip)
-{
-	pciehpc_t *ctrl_p;
-
-	mutex_enter(&pciehpc_list_mutex);
-
-	ctrl_p = pciehpc_head;
-
-	while (ctrl_p) {
-		if (ctrl_p->dip == dip) {
-			mutex_exit(&pciehpc_list_mutex);
-			return (ctrl_p);
-		}
-		ctrl_p = ctrl_p->nextp;
-	}
-
-	mutex_exit(&pciehpc_list_mutex);
-
-	return (NULL);
-}
-
-/*
- * Allocate a soft state structure for the HPC associated with this dip.
- */
-static pciehpc_t *
-pciehpc_create_soft_state(dev_info_t *dip)
-{
-	pciehpc_t *ctrl_p;
-
-	ctrl_p = kmem_zalloc(sizeof (pciehpc_t), KM_SLEEP);
-
-	ctrl_p->dip = dip;
-
-	mutex_enter(&pciehpc_list_mutex);
-	ctrl_p->nextp = pciehpc_head;
-	pciehpc_head = ctrl_p;
-	ctrl_p->soft_state = PCIEHPC_SOFT_STATE_UNINITIALIZED;
-	mutex_exit(&pciehpc_list_mutex);
-
-	return (ctrl_p);
-}
-
-/*
- * Remove the HPC soft state structure from the linked list.
- */
-static void
-pciehpc_destroy_soft_state(dev_info_t *dip)
-{
-	pciehpc_t **pp;
-	pciehpc_t *p;
-
-	mutex_enter(&pciehpc_list_mutex);
-	pp = &pciehpc_head;
-	while ((p = *pp) != NULL) {
-		if (p->dip == dip) {
-			*pp = p->nextp;
-			kmem_free(p, sizeof (pciehpc_t));
-			break;
-		}
-		pp = &(p->nextp);
-	}
-	mutex_exit(&pciehpc_list_mutex);
-}
-
-/*
- * convert LED state from PCIE HPC definition to hpc_led_state_t
- * definition.
- */
-hpc_led_state_t
-pciehpc_led_state_to_hpc(uint16_t state)
-{
-	switch (state) {
-	    case PCIE_SLOTCTL_INDICATOR_STATE_ON:
-		return (HPC_LED_ON);
-	    case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
-		return (HPC_LED_BLINK);
-	    case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
-	    default:
-		return (HPC_LED_OFF);
-	}
-}
-
-/*
- * convert LED state from hpc_led_state_t definition to PCIE HPC
- * definition.
- */
-uint16_t
-pciehpc_led_state_to_pciehpc(hpc_led_state_t state)
-{
-	switch (state) {
-	    case HPC_LED_ON:
-		return (PCIE_SLOTCTL_INDICATOR_STATE_ON);
-	    case HPC_LED_BLINK:
-		return (PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
-	    case HPC_LED_OFF:
-	    default:
-		return (PCIE_SLOTCTL_INDICATOR_STATE_OFF);
-	}
-}
-
-/*
- * Initialize HPC hardware, install interrupt handler, etc. It doesn't
- * enable hot plug interrupts.
- *
- * (Note: It is called only from pciehpc_init().)
- */
-int
-pciehpc_hpc_init(pciehpc_t *ctrl_p)
-{
-	uint16_t reg;
-
-	/* read the Slot Control Register */
-	reg = pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-
-	/* disable all interrupts */
-	reg &= ~(SLOTCTL_SUPPORTED_INTRS_MASK);
-	pciehpc_reg_put16(ctrl_p, ctrl_p->pcie_caps_reg_offset +
-		PCIE_SLOTCTL, reg);
-
-	/* clear any interrupt status bits */
-	reg = pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS);
-	pciehpc_reg_put16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS, reg);
-
-	/* initialize the interrupt mutex */
-	mutex_init(&ctrl_p->pciehpc_mutex, NULL, MUTEX_DRIVER,
-		(void *)PCIEHPC_INTR_PRI);
-
-	return (DDI_SUCCESS);
-}
-
-/*
- * Uninitialize HPC hardware, uninstall interrupt handler, etc.
- *
- * (Note: It is called only from pciehpc_uninit().)
- */
-int
-pciehpc_hpc_uninit(pciehpc_t *ctrl_p)
-{
-	/* disable interrupts */
-	(void) pciehpc_disable_intr(ctrl_p);
-
-	/* destroy the mutex */
-	mutex_destroy(&ctrl_p->pciehpc_mutex);
-
-	return (DDI_SUCCESS);
-}
-
-/*
- * Disable hot plug interrupts.
- * Note: this is only for Native hot plug mode.
- */
-int
-pciehpc_disable_intr(pciehpc_t *ctrl_p)
-{
-	uint16_t reg;
-
-	/* read the Slot Control Register */
-	reg = pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-
-	/* disable all interrupts */
-	reg &= ~(SLOTCTL_SUPPORTED_INTRS_MASK);
-	pciehpc_reg_put16(ctrl_p, ctrl_p->pcie_caps_reg_offset +
-		PCIE_SLOTCTL, reg);
-
-	/* clear any interrupt status bits */
-	reg = pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS);
-	pciehpc_reg_put16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS, reg);
-
-	return (DDI_SUCCESS);
-}
-
-/*
- * Enable hot plug interrupts.
- * Note: this is only for Native hot plug mode.
- */
-int
-pciehpc_enable_intr(pciehpc_t *ctrl_p)
-{
-	uint16_t reg;
-
-	/* clear any interrupt status bits */
-	reg = pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS);
-	pciehpc_reg_put16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS, reg);
-
-	/* read the Slot Control Register */
-	reg = pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-
-	/*
-	 * enable interrupts: power fault detection interrupt is enabled
-	 * only when the slot is 'connected', i.e. power is ON
-	 */
-	if (ctrl_p->slot.slot_state == HPC_SLOT_CONNECTED)
-		pciehpc_reg_put16(ctrl_p, ctrl_p->pcie_caps_reg_offset +
-			PCIE_SLOTCTL, reg | SLOTCTL_SUPPORTED_INTRS_MASK);
-	else
-		pciehpc_reg_put16(ctrl_p, ctrl_p->pcie_caps_reg_offset +
-			PCIE_SLOTCTL, reg | (SLOTCTL_SUPPORTED_INTRS_MASK &
-					~PCIE_SLOTCTL_PWR_FAULT_EN));
-
-	return (DDI_SUCCESS);
-}
-
-/*
- * Register the PCI-E hot plug slot with HPS framework.
- */
-int
-pciehpc_register_slot(pciehpc_t *ctrl_p)
-{
-	char nexus_path[MAXNAMELEN];
-	pciehpc_slot_t *p = &ctrl_p->slot;
-
-	/* get nexus path name */
-	(void) ddi_pathname(ctrl_p->dip, nexus_path);
-
-	/* register the slot with HPS framework */
-	if (hpc_slot_register(ctrl_p->dip, nexus_path,
-	    &p->slot_info, &p->slot_handle,
-	    &p->slot_ops, (caddr_t)ctrl_p, 0) != 0) {
-		PCIEHPC_DEBUG((CE_WARN,
-		    "pciehpc_register_slot() failed to register slot %d\n",
-		    p->slotNum));
-		return (DDI_FAILURE);
-	}
-
-	PCIEHPC_DEBUG3((CE_NOTE,
-	    "pciehpc_register_slot(): registered slot %d\n", p->slotNum));
-	return (DDI_SUCCESS);
-}
-
-/*
- * Unregister the PCI-E hot plug slot from the HPS framework.
- */
-int
-pciehpc_unregister_slot(pciehpc_t *ctrl_p)
-{
-	pciehpc_slot_t *p = &ctrl_p->slot;
-
-	if (hpc_slot_unregister(&p->slot_handle) != 0) {
-		PCIEHPC_DEBUG((CE_WARN,
-		    "pciehpc_unregister_slot() failed to unregister slot %d\n",
-		    p->slotNum));
-		return (DDI_FAILURE);
-	}
-	PCIEHPC_DEBUG3((CE_NOTE,
-	    "pciehpc_unregister_slot(): unregistered slot %d\n", p->slotNum));
-	return (DDI_SUCCESS);
-}
-
-/*
- * pciehpc_intr()
- *
- * Interrupt handler for PCI-E Hot plug controller interrupts.
- *
- * Note: This is only for native mode hot plug. This is called
- * by the nexus driver at interrupt context. Interrupt Service Routine
- * registration is done by the nexus driver for both hot plug and
- * non-hot plug interrupts. This function is called from the ISR
- * of the nexus driver to handle hot-plug interrupts.
- */
-int
-pciehpc_intr(dev_info_t *dip)
-{
-	pciehpc_t *ctrl_p;
-	uint16_t status, control;
-
-	/* get the soft state structure for this dip */
-	if ((ctrl_p = pciehpc_get_soft_state(dip)) == NULL)
-		return (DDI_INTR_UNCLAIMED);
-
-	mutex_enter(&ctrl_p->pciehpc_mutex);
-
-	/* make sure the controller soft state is initialized */
-	if (ctrl_p->soft_state & PCIEHPC_SOFT_STATE_UNINITIALIZED) {
-		mutex_exit(&ctrl_p->pciehpc_mutex);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	/* if it is not NATIVE hot plug mode then return */
-	if (ctrl_p->hp_mode != PCIEHPC_NATIVE_HP_MODE) {
-		mutex_exit(&ctrl_p->pciehpc_mutex);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	/* read the current slot status register */
-	status = pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS);
-
-	/* check if there are any hot plug interrupts occurred */
-	if (!(status & SLOT_STATUS_EVENTS)) {
-		/* no hot plug events occurred */
-		mutex_exit(&ctrl_p->pciehpc_mutex);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	/* clear the interrupt status bits */
-	pciehpc_reg_put16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS, status);
-
-	/* check for CMD COMPLETE interrupt */
-	if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
-	    PCIEHPC_DEBUG3((CE_NOTE,
-		"pciehpc_intr(): CMD COMPLETED interrupt received\n"));
-	    /* wake up any one waiting for Command Completion event */
-	    cv_signal(&ctrl_p->slot.cmd_comp_cv);
-	}
-
-	/* check for ATTN button interrupt */
-	if (status & PCIE_SLOTSTS_ATTN_BTN_PRESSED) {
-	    PCIEHPC_DEBUG3((CE_NOTE,
-		"pciehpc_intr(): ATTN BUTTON interrupt received\n"));
-	    /* if ATTN button event is still pending then cancel it */
-	    if (ctrl_p->slot.attn_btn_pending == B_TRUE)
-		ctrl_p->slot.attn_btn_pending = B_FALSE;
-	    else
-		ctrl_p->slot.attn_btn_pending = B_TRUE;
-	    /* wake up the ATTN event handler */
-	    cv_signal(&ctrl_p->slot.attn_btn_cv);
-	}
-
-	/* check for power fault interrupt */
-	if (status & PCIE_SLOTSTS_PWR_FAULT_DETECTED) {
-	    PCIEHPC_DEBUG3((CE_NOTE,
-		"pciehpc_intr(): POWER FAULT interrupt received"
-		" on slot %d\n", ctrl_p->slot.slotNum));
-	    control =  pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-	    if (control & PCIE_SLOTCTL_PWR_FAULT_EN) {
-		/* disable power fault detction interrupt */
-		pciehpc_reg_put16(ctrl_p, ctrl_p->pcie_caps_reg_offset +
-		    PCIE_SLOTCTL, control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
-
-		/* send the event to HPS framework */
-		(void) hpc_slot_event_notify(ctrl_p->slot.slot_handle,
-		    HPC_EVENT_SLOT_POWER_FAULT, HPC_EVENT_NORMAL);
-	    }
-	}
-
-	/* check for MRL SENSOR CHANGED interrupt */
-	if (status & PCIE_SLOTSTS_MRL_SENSOR_CHANGED) {
-	    PCIEHPC_DEBUG3((CE_NOTE,
-		"pciehpc_intr(): MRL SENSOR CHANGED interrupt received"
-		" on slot %d\n", ctrl_p->slot.slotNum));
-	    /* For now (phase-I), no action is taken on this event */
-	}
-
-	/* check for PRESENCE CHANGED interrupt */
-	if (status & PCIE_SLOTSTS_PRESENCE_CHANGED) {
-	    PCIEHPC_DEBUG3((CE_NOTE,
-		"pciehpc_intr(): PRESENCE CHANGED interrupt received"
-		" on slot %d\n", ctrl_p->slot.slotNum));
-
-	    if (status & PCIE_SLOTSTS_PRESENCE_DETECTED) {
-		/* card is inserted into the slot */
-
-		/* send the event to HPS framework */
-		(void) hpc_slot_event_notify(ctrl_p->slot.slot_handle,
-		    HPC_EVENT_SLOT_INSERTION, HPC_EVENT_NORMAL);
-	    } else {
-		/* card is removed from the slot */
-
-		/* make sure to disable power fault detction interrupt */
-		control =  pciehpc_reg_get16(ctrl_p,
-		    ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-		if (control & PCIE_SLOTCTL_PWR_FAULT_EN)
-		    pciehpc_reg_put16(ctrl_p, ctrl_p->pcie_caps_reg_offset +
-			PCIE_SLOTCTL, control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
-
-		/* send the event to HPS framework */
-		(void) hpc_slot_event_notify(ctrl_p->slot.slot_handle,
-		    HPC_EVENT_SLOT_REMOVAL, HPC_EVENT_NORMAL);
-	    }
-	}
-
-	/* check for DLL state changed interrupt */
-	if (ctrl_p->dll_active_rep &&
-		(status & PCIE_SLOTSTS_DLL_STATE_CHANGED)) {
-	    PCIEHPC_DEBUG3((CE_NOTE,
-		"pciehpc_intr(): DLL STATE CHANGED interrupt received"
-		" on slot %d\n", ctrl_p->slot.slotNum));
-
-	    cv_signal(&ctrl_p->slot.dll_active_cv);
-	}
-
-	mutex_exit(&ctrl_p->pciehpc_mutex);
-
-	return (DDI_INTR_CLAIMED);
-}
-
-#ifdef DEBUG
-/*
- * Dump PCI-E Hot Plug registers.
- */
-static void
-pciehpc_dump_hpregs(pciehpc_t *ctrl_p)
-{
-	uint16_t control;
-	uint32_t capabilities;
-
-	capabilities = pciehpc_reg_get32(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCAP);
-
-	control =  pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-
-	cmn_err(CE_NOTE, "pciehpc_dump_hpregs: Found PCI-E hot plug slot %d\n",
-		ctrl_p->slot.slotNum);
-	cmn_err(CE_NOTE, "Attention Button Present = %s",
-	    capabilities & PCIE_SLOTCAP_ATTN_BUTTON ? "Yes":"No");
-
-	cmn_err(CE_NOTE, "Power controller Present = %s",
-	    capabilities & PCIE_SLOTCAP_POWER_CONTROLLER ? "Yes":"No");
-
-	cmn_err(CE_NOTE, "MRL Sensor Present       = %s",
-	    capabilities & PCIE_SLOTCAP_MRL_SENSOR ? "Yes":"No");
-
-	cmn_err(CE_NOTE, "Attn Indicator Present   = %s",
-	    capabilities & PCIE_SLOTCAP_ATTN_INDICATOR ? "Yes":"No");
-
-	cmn_err(CE_NOTE, "Power Indicator Present  = %s",
-	    capabilities & PCIE_SLOTCAP_PWR_INDICATOR ? "Yes":"No");
-
-	cmn_err(CE_NOTE, "HotPlug Surprise         = %s",
-	    capabilities & PCIE_SLOTCAP_HP_SURPRISE ? "Yes":"No");
-
-	cmn_err(CE_NOTE, "HotPlug Capable          = %s",
-	    capabilities & PCIE_SLOTCAP_HP_CAPABLE ? "Yes":"No");
-
-	cmn_err(CE_NOTE, "Physical Slot Number     = %d",
-	    PCIE_SLOTCAP_PHY_SLOT_NUM(capabilities));
-
-	cmn_err(CE_NOTE, "Attn Button interrupt Enabled  = %s",
-	    control & PCIE_SLOTCTL_ATTN_BTN_EN ? "Yes":"No");
-
-	cmn_err(CE_NOTE, "Power Fault interrupt Enabled  = %s",
-	    control & PCIE_SLOTCTL_PWR_FAULT_EN ? "Yes":"No");
-
-	cmn_err(CE_NOTE, "MRL Sensor INTR Enabled   = %s",
-	    control & PCIE_SLOTCTL_MRL_SENSOR_EN ? "Yes":"No");
-
-	cmn_err(CE_NOTE, "Presence interrupt Enabled     = %s",
-	    control & PCIE_SLOTCTL_PRESENCE_CHANGE_EN ? "Yes":"No");
-
-	cmn_err(CE_NOTE, "Cmd Complete interrupt Enabled = %s",
-	    control & PCIE_SLOTCTL_CMD_INTR_EN ? "Yes":"No");
-
-	cmn_err(CE_NOTE, "HotPlug interrupt Enabled      = %s",
-	    control & PCIE_SLOTCTL_HP_INTR_EN ? "Yes":"No");
-
-	cmn_err(CE_NOTE, "Power Indicator LED = %s", pciehpc_led_state_text(
-	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))));
-
-	cmn_err(CE_NOTE, "Attn Indicator LED = %s",
-	    pciehpc_led_state_text(pciehpc_led_state_to_hpc(
-			pcie_slotctl_attn_indicator_get(control))));
-}
-
-static char *
-pciehpc_led_state_text(hpc_led_state_t state)
-{
-	switch (state) {
-		case HPC_LED_ON:
-			return ("on");
-		case HPC_LED_OFF:
-			return ("off");
-		case HPC_LED_BLINK:
-		default:
-			return ("blink");
-	}
-}
-#endif /* DEBUG */
-
-/*
- * pciehpc_slot_connect()
- *
- * Connect power to the PCI-E slot.
- *
- * Returns: HPC_SUCCESS if the slot is powered up and enabled.
- *	    HPC_ERR_FAILED if the slot can't be enabled.
- *
- * (Note: This function is called by HPS framework at kernel context only.)
- */
-/*ARGSUSED*/
-int
-pciehpc_slot_connect(caddr_t ops_arg, hpc_slot_t slot_hdl,
-	void *data, uint_t flags)
-{
-	uint16_t status, control;
-
-	pciehpc_t *ctrl_p = (pciehpc_t *)ops_arg;
-
-	ASSERT(slot_hdl == ctrl_p->slot.slot_handle);
-
-	mutex_enter(&ctrl_p->pciehpc_mutex);
-
-	/* get the current state of the slot */
-	pciehpc_get_slot_state(ctrl_p);
-
-	/* check if the slot is already in the 'connected' state */
-	if (ctrl_p->slot.slot_state == HPC_SLOT_CONNECTED) {
-		/* slot is already in the 'connected' state */
-		PCIEHPC_DEBUG3((CE_NOTE,
-		    "pciehpc_slot_connect() slot %d already connected\n",
-		    ctrl_p->slot.slotNum));
-		mutex_exit(&ctrl_p->pciehpc_mutex);
-		return (HPC_SUCCESS);
-	}
-
-	/* read the Slot Status Register */
-	status =  pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS);
-
-	/* make sure the MRL switch is closed if present */
-	if ((ctrl_p->has_mrl) && (status & PCIE_SLOTSTS_MRL_SENSOR_OPEN)) {
-		/* MRL switch is open */
-		cmn_err(CE_WARN, "MRL switch is open on slot %d\n",
-			ctrl_p->slot.slotNum);
-		goto cleanup;
-	}
-
-	/* make sure the slot has a device present */
-	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
-		/* slot is empty */
-		PCIEHPC_DEBUG((CE_NOTE,
-		    "slot %d is empty\n", ctrl_p->slot.slotNum));
-		goto cleanup;
-	}
-
-	/* get the current state of Slot Control Register */
-	control =  pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-
-	/* check if the slot's power state is ON */
-	if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
-		/* slot is already powered up */
-		PCIEHPC_DEBUG3((CE_NOTE,
-		    "pciehpc_slot_connect() slot %d already connected\n",
-		    ctrl_p->slot.slotNum));
-		ctrl_p->slot.slot_state = HPC_SLOT_CONNECTED;
-		mutex_exit(&ctrl_p->pciehpc_mutex);
-		return (HPC_SUCCESS);
-	}
-
-	/*
-	 * Enable power to the slot involves:
-	 *	1. Set power LED to blink and ATTN led to OFF.
-	 *	2. Set power control ON in Slot Control Reigster and
-	 *	   wait for Command Completed Interrupt or 1 sec timeout.
-	 *	3. If Data Link Layer State Changed events are supported
-	 *	   then wait for the event to indicate Data Layer Link
-	 *	   is active. The time out value for this event is 1 second.
-	 *	   This is specified in PCI-E version 1.1.
-	 *	4. Set power LED to be ON.
-	 */
-
-	/* 1. set power LED to blink & ATTN led to OFF */
-	pciehpc_set_led_state(ctrl_p, HPC_POWER_LED, HPC_LED_BLINK);
-	pciehpc_set_led_state(ctrl_p, HPC_ATTN_LED, HPC_LED_OFF);
-
-	/* 2. set power control to ON */
-	control =  pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-	control &= ~PCIE_SLOTCTL_PWR_CONTROL;
-	pciehpc_issue_hpc_command(ctrl_p, control);
-
-	/* 3. wait for DLL State Change event, if it's supported */
-	if (ctrl_p->dll_active_rep) {
-		status =  pciehpc_reg_get16(ctrl_p,
-		    ctrl_p->pcie_caps_reg_offset + PCIE_LINKSTS);
-
-		if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE)) {
-			/* wait 1 sec for the DLL State Changed event */
-			(void) cv_timedwait(&ctrl_p->slot.dll_active_cv,
-			    &ctrl_p->pciehpc_mutex,
-			    ddi_get_lbolt() +
-			    SEC_TO_TICK(PCIEHPC_DLL_STATE_CHANGE_TIMEOUT));
-
-			/* check Link status */
-			status =  pciehpc_reg_get16(ctrl_p,
-			    ctrl_p->pcie_caps_reg_offset +
-			    PCIE_LINKSTS);
-			if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE))
-				goto cleanup2;
-		}
-	}
-
-	/* wait 1 sec for link to come up */
-	delay(drv_usectohz(1000000));
-
-	/* check power is really turned ON */
-	control =  pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-	if (control & PCIE_SLOTCTL_PWR_CONTROL) {
-		PCIEHPC_DEBUG((CE_NOTE,
-		    "slot %d fails to turn on power on connect\n",
-		    ctrl_p->slot.slotNum));
-
-		goto cleanup1;
-	}
-
-	/* clear power fault status */
-	status =  pciehpc_reg_get16(ctrl_p,
-	    ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS);
-	status |= PCIE_SLOTSTS_PWR_FAULT_DETECTED;
-	pciehpc_reg_put16(ctrl_p, ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS,
-	    status);
-
-	/* enable power fault detection interrupt */
-	control |= PCIE_SLOTCTL_PWR_FAULT_EN;
-	pciehpc_issue_hpc_command(ctrl_p, control);
-
-	/* 4. Set power LED to be ON */
-	pciehpc_set_led_state(ctrl_p, HPC_POWER_LED, HPC_LED_ON);
-
-	/* if EMI is present, turn it ON */
-	if (ctrl_p->has_emi_lock) {
-		status =  pciehpc_reg_get16(ctrl_p,
-		    ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS);
-
-		if (!(status & PCIE_SLOTSTS_EMI_LOCK_SET)) {
-			control =  pciehpc_reg_get16(ctrl_p,
-			    ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-			control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
-			pciehpc_issue_hpc_command(ctrl_p, control);
-
-			/* wait 1 sec after toggling the state of EMI lock */
-			delay(drv_usectohz(1000000));
-		}
-	}
-
-	ctrl_p->slot.slot_state = HPC_SLOT_CONNECTED;
-	mutex_exit(&ctrl_p->pciehpc_mutex);
-	return (HPC_SUCCESS);
-
-cleanup2:
-	control =  pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-	/* if power is ON, set power control to OFF */
-	if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
-		control |= PCIE_SLOTCTL_PWR_CONTROL;
-		pciehpc_issue_hpc_command(ctrl_p, control);
-	}
-
-cleanup1:
-	/* set power led to OFF */
-	pciehpc_set_led_state(ctrl_p, HPC_POWER_LED, HPC_LED_OFF);
-
-cleanup:
-	mutex_exit(&ctrl_p->pciehpc_mutex);
-	return (HPC_ERR_FAILED);
-}
-
-/*
- * pciehpc_slot_disconnect()
- *
- * Disconnect power to the slot.
- *
- * Returns: HPC_SUCCESS if the slot is powered up and enabled.
- *	    HPC_ERR_FAILED if the slot can't be enabled.
- *
- * (Note: This function is called by HPS framework at kernel context only.)
- */
-/*ARGSUSED*/
-int
-pciehpc_slot_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl,
-	void *data, uint_t flags)
-{
-	uint16_t status;
-	uint16_t control;
-
-	pciehpc_t *ctrl_p = (pciehpc_t *)ops_arg;
-
-	ASSERT(slot_hdl == ctrl_p->slot.slot_handle);
-
-	mutex_enter(&ctrl_p->pciehpc_mutex);
-
-	/* get the current state of the slot */
-	pciehpc_get_slot_state(ctrl_p);
-
-	/* check if the slot is already in the 'disconnected' state */
-	if (ctrl_p->slot.slot_state == HPC_SLOT_DISCONNECTED) {
-		/* slot is in the 'disconnected' state */
-		PCIEHPC_DEBUG3((CE_NOTE,
-		    "pciehpc_slot_disconnect(): slot %d already disconnected\n",
-		    ctrl_p->slot.slotNum));
-		ASSERT(ctrl_p->slot.power_led_state == HPC_LED_OFF);
-		mutex_exit(&ctrl_p->pciehpc_mutex);
-		return (HPC_SUCCESS);
-	}
-
-	/* read the Slot Status Register */
-	status =  pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS);
-
-	/* make sure the slot has a device present */
-	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
-		/* slot is empty */
-		PCIEHPC_DEBUG((CE_NOTE,
-		    "pciehpc_slot_disconnect(): slot %d is empty\n",
-		    ctrl_p->slot.slotNum));
-		goto cleanup;
-	}
-
-	/*
-	 * Disable power to the slot involves:
-	 *	1. Set power LED to blink.
-	 *	2. Set power control OFF in Slot Control Reigster and
-	 *	   wait for Command Completed Interrupt or 1 sec timeout.
-	 *	3. Set POWER led and ATTN led to be OFF.
-	 */
-
-	/* 1. set power LED to blink */
-	pciehpc_set_led_state(ctrl_p, HPC_POWER_LED, HPC_LED_BLINK);
-
-	/* disable power fault detection interrupt */
-	control = pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-	control &= ~PCIE_SLOTCTL_PWR_FAULT_EN;
-	pciehpc_issue_hpc_command(ctrl_p, control);
-
-	/* 2. set power control to OFF */
-	control =  pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-	control |= PCIE_SLOTCTL_PWR_CONTROL;
-	pciehpc_issue_hpc_command(ctrl_p, control);
-
-#ifdef DEBUG
-	/* check for power control bit to be OFF */
-	control =  pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-	ASSERT(control & PCIE_SLOTCTL_PWR_CONTROL);
-#endif
-
-	/* 3. Set power LED to be OFF */
-	pciehpc_set_led_state(ctrl_p, HPC_POWER_LED, HPC_LED_OFF);
-	pciehpc_set_led_state(ctrl_p, HPC_ATTN_LED, HPC_LED_OFF);
-
-	/* if EMI is present, turn it OFF */
-	if (ctrl_p->has_emi_lock) {
-		status =  pciehpc_reg_get16(ctrl_p,
-		    ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS);
-
-		if (status & PCIE_SLOTSTS_EMI_LOCK_SET) {
-			control =  pciehpc_reg_get16(ctrl_p,
-			    ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-			control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
-			pciehpc_issue_hpc_command(ctrl_p, control);
-
-			/* wait 1 sec after toggling the state of EMI lock */
-			delay(drv_usectohz(1000000));
-		}
-	}
-
-	ctrl_p->slot.slot_state = HPC_SLOT_DISCONNECTED;
-	mutex_exit(&ctrl_p->pciehpc_mutex);
-	return (HPC_SUCCESS);
-
-cleanup:
-	mutex_exit(&ctrl_p->pciehpc_mutex);
-	return (HPC_ERR_FAILED);
-}
-
-/*ARGSUSED*/
-int
-pciehpc_slot_control(caddr_t ops_arg, hpc_slot_t slot_hdl,
-	int request, caddr_t arg)
-{
-	pciehpc_t	*ctrl_p;
-	hpc_led_info_t	*led_info;
-	int		ret = HPC_SUCCESS;
-
-	ctrl_p = (pciehpc_t *)ops_arg;
-
-	ASSERT(ctrl_p != NULL);
-
-	mutex_enter(&ctrl_p->pciehpc_mutex);
-
-	/* get the current slot state */
-	pciehpc_get_slot_state(ctrl_p);
-
-	switch (request) {
-
-	    case HPC_CTRL_GET_SLOT_STATE:
-		*(hpc_slot_state_t *)arg = ctrl_p->slot.slot_state;
-		break;
-
-	    case HPC_CTRL_GET_BOARD_TYPE:
-		if (ctrl_p->slot.slot_state == HPC_SLOT_EMPTY)
-			*(hpc_board_type_t *)arg = HPC_BOARD_UNKNOWN;
-		else
-			*(hpc_board_type_t *)arg = HPC_BOARD_PCI_HOTPLUG;
-		break;
-
-	    case HPC_CTRL_GET_LED_STATE:
-		led_info = (hpc_led_info_t *)arg;
-		switch (led_info->led) {
-		    case HPC_ATTN_LED:
-			led_info->state = ctrl_p->slot.attn_led_state;
-			break;
-		    case HPC_POWER_LED:
-			led_info->state = ctrl_p->slot.power_led_state;
-			break;
-		    case HPC_FAULT_LED:
-		    case HPC_ACTIVE_LED:
-			led_info->state = HPC_LED_OFF;
-			break;
-		    default:
-			PCIEHPC_DEBUG((CE_WARN, "pciehpc_slot_control:"
-			    " unknown led state\n"));
-			ret = HPC_ERR_NOTSUPPORTED;
-			break;
-		}
-		break;
-	    case HPC_CTRL_SET_LED_STATE:
-		led_info = (hpc_led_info_t *)arg;
-		switch (led_info->led) {
-		    case HPC_ATTN_LED:
-			pciehpc_set_led_state(ctrl_p, led_info->led,
-				led_info->state);
-			break;
-		    case HPC_POWER_LED:
-			PCIEHPC_DEBUG((CE_WARN, "pciehpc_slot_control: power"
-			    " LED control is not allowed on slot #%d\n",
-			    ctrl_p->slot.slotNum));
-			ret = HPC_ERR_NOTSUPPORTED;
-			break;
-		    case HPC_FAULT_LED:
-		    case HPC_ACTIVE_LED:
-			break;
-		    default:
-			PCIEHPC_DEBUG((CE_WARN, "pciehpc_slot_control:"
-			    " unknown led type %d\n", led_info->led));
-			ret = HPC_ERR_NOTSUPPORTED;
-			break;
-		}
-		break;
-	    case HPC_CTRL_DEV_CONFIG_FAILURE:
-		/* turn the ATTN led ON for configure failure */
-		pciehpc_set_led_state(ctrl_p, HPC_ATTN_LED, HPC_LED_ON);
-		/* if power to the slot is still on then set Power led to ON */
-		if (ctrl_p->slot.slot_state == HPC_SLOT_CONNECTED)
-		    pciehpc_set_led_state(ctrl_p, HPC_POWER_LED, HPC_LED_ON);
-		break;
-	    case HPC_CTRL_DEV_UNCONFIG_FAILURE:
-		/* if power to the slot is still on then set Power led to ON */
-		if (ctrl_p->slot.slot_state == HPC_SLOT_CONNECTED)
-		    pciehpc_set_led_state(ctrl_p, HPC_POWER_LED, HPC_LED_ON);
-		pciehpc_enable_errors(ctrl_p);
-		break;
-	    case HPC_CTRL_ENABLE_AUTOCFG:
-	    case HPC_CTRL_DISABLE_AUTOCFG:
-		/* no action is needed here */
-		break;
-
-	    case HPC_CTRL_DISABLE_SLOT:
-	    case HPC_CTRL_ENABLE_SLOT:
-		/* no action is needed here */
-		break;
-
-	    case HPC_CTRL_DEV_CONFIG_START:
-	    case HPC_CTRL_DEV_UNCONFIG_START:
-		pciehpc_disable_errors(ctrl_p);
-		/* no action is needed here */
-		break;
-	    case HPC_CTRL_DEV_CONFIGURED:
-	    case HPC_CTRL_DEV_UNCONFIGURED:
-		/* no action is needed here */
-		if (request == HPC_CTRL_DEV_CONFIGURED) {
-			pciehpc_enable_errors(ctrl_p);
-		}
-		break;
-	    default:
-		PCIEHPC_DEBUG((CE_WARN,
-		    "pciehpc_slot_control: unsupported operation\n"));
-		ret = HPC_ERR_NOTSUPPORTED;
-	}
-
-	mutex_exit(&ctrl_p->pciehpc_mutex);
-
-	return (ret);
-}
-
-/*
- * Get the state of an LED.
- */
-hpc_led_state_t
-pciehpc_get_led_state(pciehpc_t *ctrl_p, hpc_led_t led)
-{
-	uint16_t control;
-	uint16_t state;
-
-	/* get the current state of Slot Control register */
-	control =  pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-
-	switch (led) {
-	    case HPC_POWER_LED:
-		state = pcie_slotctl_pwr_indicator_get(control);
-		break;
-	    case HPC_ATTN_LED:
-		state = pcie_slotctl_attn_indicator_get(control);
-		break;
-	    default:
-		PCIEHPC_DEBUG((CE_WARN,
-		    "pciehpc_get_led_state() invalid LED %d\n", led));
-		return (HPC_LED_OFF);
-	}
-
-	switch (state) {
-	    case PCIE_SLOTCTL_INDICATOR_STATE_ON:
-		return (HPC_LED_ON);
-
-	    case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
-		return (HPC_LED_BLINK);
-
-	    case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
-	    default:
-		return (HPC_LED_OFF);
-	}
-}
-
-/*
- * Set the state of an LED. It updates both hw and sw state.
- */
-void
-pciehpc_set_led_state(pciehpc_t *ctrl_p, hpc_led_t led, hpc_led_state_t state)
-{
-	uint16_t control;
-
-	/* get the current state of Slot Control register */
-	control =  pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-
-	switch (led) {
-	    case HPC_POWER_LED:
-		/* clear led mask */
-		control &= ~PCIE_SLOTCTL_PWR_INDICATOR_MASK;
-		ctrl_p->slot.power_led_state = state;
-		break;
-	    case HPC_ATTN_LED:
-		/* clear led mask */
-		control &= ~PCIE_SLOTCTL_ATTN_INDICATOR_MASK;
-		ctrl_p->slot.attn_led_state = state;
-		break;
-	    default:
-		PCIEHPC_DEBUG((CE_WARN,
-		    "pciehpc_set_led_state() invalid LED %d\n", led));
-		return;
-	}
-
-	switch (state) {
-	    case HPC_LED_ON:
-		if (led == HPC_POWER_LED)
-		    control = pcie_slotctl_pwr_indicator_set(control,
-					PCIE_SLOTCTL_INDICATOR_STATE_ON);
-		else if (led == HPC_ATTN_LED)
-		    control = pcie_slotctl_attn_indicator_set(control,
-					PCIE_SLOTCTL_INDICATOR_STATE_ON);
-		break;
-	    case HPC_LED_OFF:
-		if (led == HPC_POWER_LED)
-		    control = pcie_slotctl_pwr_indicator_set(control,
-					PCIE_SLOTCTL_INDICATOR_STATE_OFF);
-		else if (led == HPC_ATTN_LED)
-		    control = pcie_slotctl_attn_indicator_set(control,
-					PCIE_SLOTCTL_INDICATOR_STATE_OFF);
-		break;
-	    case HPC_LED_BLINK:
-		if (led == HPC_POWER_LED)
-		    control = pcie_slotctl_pwr_indicator_set(control,
-					PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
-		else if (led == HPC_ATTN_LED)
-		    control = pcie_slotctl_attn_indicator_set(control,
-					PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
-		break;
-
-	    default:
-		PCIEHPC_DEBUG((CE_WARN,
-		    "pciehpc_set_led_state() invalid LED state %d\n", state));
-		return;
-	}
-
-	/* update the Slot Control Register */
-	pciehpc_issue_hpc_command(ctrl_p, control);
-
-#ifdef DEBUG
-	/* get the current state of Slot Control register */
-	control =  pciehpc_reg_get16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-
-	PCIEHPC_DEBUG3((CE_NOTE, "pciehpc_set_led_state: "
-		"slot %d power-led %s attn-led %s\n",
-		ctrl_p->slot.slotNum,
-		pciehpc_led_state_text(
-		pciehpc_led_state_to_hpc(
-		pcie_slotctl_pwr_indicator_get(control))),
-		pciehpc_led_state_text(
-		pciehpc_led_state_to_hpc(
-		pcie_slotctl_attn_indicator_get(control)))));
-#endif
-}
-
-/*
- * Send a command to the PCI-E Hot Plug Controller.
- *
- * NOTES: The PCI-E spec defines the following semantics for issuing hot plug
- * commands.
- * 1) If Command Complete events/interrupts are supported then software
- *    waits for Command Complete event after issuing a command (i.e writing
- *    to the Slot Control register). The command completion could take as
- *    long as 1 second so software should be prepared to wait for 1 second
- *    before issuing another command.
- *
- * 2) If Command Complete events/interrupts are not supported then
- *    software could issue multiple Slot Control writes without any delay
- *    between writes.
- */
-void
-pciehpc_issue_hpc_command(pciehpc_t *ctrl_p, uint16_t control)
-{
-
-	uint16_t status;
-	uint32_t slot_cap;
-
-	/*
-	 * PCI-E version 1.1 spec defines No Command Completed
-	 * Support bit (bit#18) in Slot Capabilities register. If this
-	 * bit is set then slot doesn't support notification of command
-	 * completion events.
-	 */
-	slot_cap =  pciehpc_reg_get32(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCAP);
-	/*
-	 * If no Command Completion event is supported or it is ACPI
-	 * hot plug mode then just issue the command and return.
-	 */
-	if ((slot_cap & PCIE_SLOTCAP_NO_CMD_COMP_SUPP) ||
-	    (ctrl_p->hp_mode == PCIEHPC_ACPI_HP_MODE)) {
-		pciehpc_reg_put16(ctrl_p,
-		    ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL, control);
-		return;
-	}
-
-	/*
-	 * **************************************
-	 * Command Complete events are supported.
-	 * **************************************
-	 */
-
-	/*
-	 * If HPC is not yet initialized then just poll for the Command
-	 * Completion interrupt.
-	 */
-	if (!(ctrl_p->soft_state & PCIEHPC_SOFT_STATE_INITIALIZED)) {
-		int retry = PCIEHPC_CMD_WAIT_RETRY;
-
-		/* write the command to the HPC */
-		pciehpc_reg_put16(ctrl_p,
-		    ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL,
-		    control);
-
-		/* poll for status completion */
-		while (retry--) {
-		    /* wait for 10 msec before checking the status */
-		    delay(drv_usectohz(PCIEHPC_CMD_WAIT_TIME));
-
-		    status = pciehpc_reg_get16(ctrl_p,
-			ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS);
-
-		    if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
-			/* clear the status bits */
-			pciehpc_reg_put16(ctrl_p,
-			    ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS,
-			    status);
-			break;
-		    }
-		}
-		return;
-	}
-
-	/* HPC is already initialized */
-
-	ASSERT(MUTEX_HELD(&ctrl_p->pciehpc_mutex));
-
-	/*
-	 * If previous command is still pending then wait for its
-	 * completion. i.e cv_wait()
-	 */
-
-	while (ctrl_p->slot.command_pending == B_TRUE)
-		cv_wait(&ctrl_p->slot.cmd_comp_cv, &ctrl_p->pciehpc_mutex);
-
-	/*
-	 * Issue the command and wait for Command Completion or
-	 * the 1 sec timeout.
-	 */
-	pciehpc_reg_put16(ctrl_p,
-		ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL, control);
-
-	ctrl_p->slot.command_pending = B_TRUE;
-
-	if (cv_timedwait(&ctrl_p->slot.cmd_comp_cv, &ctrl_p->pciehpc_mutex,
-		ddi_get_lbolt() + SEC_TO_TICK(1)) == -1) {
-		/* it is a timeout */
-		PCIEHPC_DEBUG2((CE_NOTE,
-		    "pciehpc_issue_hpc_command: Command Complete"
-		    " interrupt is not received for slot %d\n",
-		    ctrl_p->slot.slotNum));
-
-		/* clear the status info in case interrupts are disabled? */
-		status = pciehpc_reg_get16(ctrl_p,
-			ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS);
-
-		if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
-			/* clear the status bits */
-			pciehpc_reg_put16(ctrl_p,
-			    ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS,
-			    status);
-		}
-	}
-
-	ctrl_p->slot.command_pending = B_FALSE;
-
-	/* wake up any one waiting for issuing another command to HPC */
-	cv_signal(&ctrl_p->slot.cmd_comp_cv);
-}
-
-/*
- * pciehcp_attn_btn_handler()
- *
- * This handles ATTN button pressed event as per the PCI-E 1.1 spec.
- */
-static void
-pciehpc_attn_btn_handler(pciehpc_t *ctrl_p)
-{
-	hpc_led_state_t power_led_state;
-	callb_cpr_t cprinfo;
-
-	PCIEHPC_DEBUG3((CE_NOTE, "pciehpc_attn_btn_handler: thread started\n"));
-
-	CALLB_CPR_INIT(&cprinfo, &ctrl_p->pciehpc_mutex, callb_generic_cpr,
-	    "pciehpc_attn_btn_handler");
-
-	mutex_enter(&ctrl_p->pciehpc_mutex);
-
-	/* wait for ATTN button event */
-	cv_wait(&ctrl_p->slot.attn_btn_cv, &ctrl_p->pciehpc_mutex);
-
-	while (ctrl_p->slot.attn_btn_thread_exit == B_FALSE) {
-
-	    if (ctrl_p->slot.attn_btn_pending == B_TRUE) {
-
-		/* get the current state of power LED */
-		power_led_state = pciehpc_get_led_state(ctrl_p, HPC_POWER_LED);
-
-		/* Blink the Power LED while we wait for 5 seconds */
-		pciehpc_set_led_state(ctrl_p, HPC_POWER_LED, HPC_LED_BLINK);
-
-		/* wait for 5 seconds before taking any action */
-		if (cv_timedwait(&ctrl_p->slot.attn_btn_cv,
-			&ctrl_p->pciehpc_mutex,
-			ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) {
-			/*
-			 * It is a time out; make sure the ATTN pending flag is
-			 * still ON before sending the event to HPS framework.
-			 */
-			if (ctrl_p->slot.attn_btn_pending == B_TRUE) {
-			    /* send the ATTN button event to HPS framework */
-			    ctrl_p->slot.attn_btn_pending = B_FALSE;
-			    (void) hpc_slot_event_notify(
-				ctrl_p->slot.slot_handle,
-				HPC_EVENT_SLOT_ATTN, HPC_EVENT_NORMAL);
-			}
-		}
-		/* restore the power LED state */
-		pciehpc_set_led_state(ctrl_p, HPC_POWER_LED, power_led_state);
-		continue;
-	    }
-
-	    /* wait for another ATTN button event */
-	    cv_wait(&ctrl_p->slot.attn_btn_cv, &ctrl_p->pciehpc_mutex);
-	}
-
-	PCIEHPC_DEBUG3((CE_NOTE, "pciehpc_attn_btn_handler: thread exit\n"));
-	cv_signal(&ctrl_p->slot.attn_btn_cv);
-	CALLB_CPR_EXIT(&cprinfo);
-	thread_exit();
-}
-
-/*
- * Read/Write access to HPC registers. If platform nexus has non-standard
- * HPC access mechanism then regops functions are used to do reads/writes.
- */
-uint8_t
-pciehpc_reg_get8(pciehpc_t *ctrl_p, uint_t off)
-{
-	PCIEHPC_DEBUG3((CE_NOTE, "read reg8 (offset %x)", off));
-
-	if (ctrl_p->regops.get != NULL)
-	    return ((uint8_t)ctrl_p->regops.get(ctrl_p->regops.cookie,
-			(off_t)off));
-	else
-	    return (ddi_get8(ctrl_p->cfghdl,
-			(uint8_t *)(ctrl_p->regs_base + off)));
-}
-
-uint16_t
-pciehpc_reg_get16(pciehpc_t *ctrl_p, uint_t off)
-{
-	PCIEHPC_DEBUG3((CE_NOTE, "read reg16 (offset %x)", off));
-
-	if (ctrl_p->regops.get != NULL)
-	    return ((uint16_t)ctrl_p->regops.get(ctrl_p->regops.cookie,
-			(off_t)off));
-	else
-	    return (ddi_get16(ctrl_p->cfghdl,
-			(uint16_t *)(ctrl_p->regs_base + off)));
-}
-
-uint32_t
-pciehpc_reg_get32(pciehpc_t *ctrl_p, uint_t off)
-{
-	PCIEHPC_DEBUG3((CE_NOTE, "read reg32 (offset %x)", off));
-
-	if (ctrl_p->regops.get != NULL)
-	    return ((uint32_t)ctrl_p->regops.get(ctrl_p->regops.cookie,
-			(off_t)off));
-	else
-	    return (ddi_get32(ctrl_p->cfghdl,
-			(uint32_t *)(ctrl_p->regs_base + off)));
-}
-
-void
-pciehpc_reg_put8(pciehpc_t *ctrl_p, uint_t off, uint8_t val)
-{
-	PCIEHPC_DEBUG3((CE_NOTE, "write reg8 (offset %x, val %x)",
-		off, val));
-
-	if (ctrl_p->regops.put != NULL)
-	    ctrl_p->regops.put(ctrl_p->regops.cookie, (off_t)off, (uint_t)val);
-	else
-	    ddi_put8(ctrl_p->cfghdl,
-			(uint8_t *)(ctrl_p->regs_base + off), val);
-}
-
-void
-pciehpc_reg_put16(pciehpc_t *ctrl_p, uint_t off, uint16_t val)
-{
-	PCIEHPC_DEBUG3((CE_NOTE, "write reg16 (offset %x, val %x)",
-		off, val));
-
-	if (ctrl_p->regops.put != NULL)
-	    ctrl_p->regops.put(ctrl_p->regops.cookie, (off_t)off, (uint_t)val);
-	else
-	    ddi_put16(ctrl_p->cfghdl,
-			(uint16_t *)(ctrl_p->regs_base + off), val);
-}
-
-void
-pciehpc_reg_put32(pciehpc_t *ctrl_p, uint_t off, uint32_t val)
-{
-	PCIEHPC_DEBUG3((CE_NOTE, "write reg32 (offset %x, val %x)",
-		off, val));
-
-	if (ctrl_p->regops.put != NULL)
-	    ctrl_p->regops.put(ctrl_p->regops.cookie, (off_t)off, (uint_t)val);
-	else
-	    ddi_put32(ctrl_p->cfghdl,
-			(uint32_t *)(ctrl_p->regs_base + off), val);
-}
-
-static void
-pciehpc_dev_info(pciehpc_t *ctrl_p)
-{
-	pci_regspec_t *regspec;
-	int reglen;
-	dev_info_t *dip = ctrl_p->dip;
-
-	/*
-	 * Check if it is a PCIe fabric hotplug nexus. This is specially
-	 * not so for Rootcomplex nodes supporting PCIe hotplug.
-	 * We save this information so as to implement hardening for
-	 * fabric nodes only via pcie services.
-	 */
-	if (pciehpc_pcie_dev(dip, ctrl_p->cfghdl) == DDI_SUCCESS)
-		ctrl_p->soft_state |= PCIEHPC_SOFT_STATE_PCIE_DEV;
-
-	/* Get the device number. */
-	if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
-		"reg", (caddr_t)&regspec, &reglen) != DDI_SUCCESS) {
-	    return;
-	}
-
-	ctrl_p->bus  = PCI_REG_BUS_G(regspec[0].pci_phys_hi);
-	ctrl_p->dev  = PCI_REG_DEV_G(regspec[0].pci_phys_hi);
-	ctrl_p->func = PCI_REG_FUNC_G(regspec[0].pci_phys_hi);
-
-	kmem_free(regspec, reglen);
-
-	PCIEHPC_DEBUG3((CE_NOTE, "pciehpc_dev_info: bus=%x, dev=%x, func=%x",
-	    ctrl_p->bus, ctrl_p->dev, ctrl_p->func));
-}
-
-/*
- * setup slot name/slot-number info.
- */
-void
-pciehpc_set_slot_name(pciehpc_t *ctrl_p)
-{
-	pciehpc_slot_t *p = &ctrl_p->slot;
-	uchar_t *slotname_data;
-	int *slotnum;
-	uint_t count;
-	int len;
-	int invalid_slotnum = 0;
-	uint32_t slot_capabilities;
-
-	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->dip,
-		DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
-		DDI_PROP_SUCCESS) {
-		p->slotNum = slotnum[0];
-		ddi_prop_free(slotnum);
-	} else {
-		slot_capabilities = pciehpc_reg_get32(ctrl_p,
-			ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCAP);
-		p->slotNum = PCIE_SLOTCAP_PHY_SLOT_NUM(slot_capabilities);
-	}
-
-	if (!p->slotNum) { /* platform may not have initialized it */
-		PCIEHPC_DEBUG((CE_WARN, "%s#%d: Invalid slot number! ",
-				ddi_driver_name(ctrl_p->dip),
-				ddi_get_instance(ctrl_p->dip)));
-		p->slotNum = pciehpc_reg_get8(ctrl_p, PCI_BCNF_SECBUS);
-		invalid_slotnum = 1;
-	}
-
-	/*
-	 * construct the slot_name:
-	 * 	if "slot-names" property exists then use that name
-	 *	else if valid slot number exists then it is "pcie<slot-num>".
-	 *	else it will be "pcie<sec-bus-number>dev0"
-	 */
-	if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->dip, DDI_PROP_DONTPASS,
-		"slot-names", (caddr_t)&slotname_data,
-		&len) == DDI_PROP_SUCCESS) {
-		/*
-		 * Note: for PCI-E slots, the device number is always 0 so the
-		 * first (and only) string is the slot name for this slot.
-		 */
-		(void) sprintf(p->slot_info.pci_slot_name,
-					(char *)slotname_data + 4);
-		kmem_free(slotname_data, len);
-	} else {
-		if (invalid_slotnum)	/* use device number ie. 0 */
-		    (void) snprintf(p->slot_info.pci_slot_name,
-			sizeof (p->slot_info.pci_slot_name), "pcie0");
-		else
-		    (void) snprintf(p->slot_info.pci_slot_name,
-			sizeof (p->slot_info.pci_slot_name), "pcie%d",
-			p->slotNum);
-	}
-}
-
-/*ARGSUSED*/
-static int
-pciehpc_pcie_dev(dev_info_t *dip, ddi_acc_handle_t handle)
-{
-	/* get parent device's device_type property */
-	char *device_type;
-	int rc;
-	dev_info_t *pdip = ddi_get_parent(dip);
-
-	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
-		DDI_PROP_DONTPASS, "device_type", &device_type)
-			!= DDI_PROP_SUCCESS) {
-		PCIEHPC_DEBUG2((CE_NOTE, "device_type property missing for "
-			"%s#%d", ddi_get_name(pdip), ddi_get_instance(pdip)));
-		return (DDI_FAILURE);
-	}
-
-	PCIEHPC_DEBUG((CE_NOTE, "device_type=<%s>\n", device_type));
-	rc = DDI_FAILURE;
-	if (strcmp(device_type, "pciex") == 0)
-		rc = DDI_SUCCESS;
-	ddi_prop_free(device_type);
-	return (rc);
-}
-
-static void
-pciehpc_disable_errors(pciehpc_t *ctrl_p)
-{
-	if (ctrl_p->soft_state & PCIEHPC_SOFT_STATE_PCIE_DEV) {
-		PCIE_DISABLE_ERRORS(ctrl_p->dip);
-		PCIEHPC_DEBUG3((CE_NOTE, "%s%d: pciehpc_disable_errors\n",
-		    ddi_driver_name(ctrl_p->dip),
-		    ddi_get_instance(ctrl_p->dip)));
-	}
-}
-
-static void
-pciehpc_enable_errors(pciehpc_t *ctrl_p)
-{
-	if (ctrl_p->soft_state & PCIEHPC_SOFT_STATE_PCIE_DEV) {
-		(void) PCIE_ENABLE_ERRORS(ctrl_p->dip);
-		PCIEHPC_DEBUG3((CE_NOTE, "%s%d: pciehpc_enable_errors\n",
-		    ddi_driver_name(ctrl_p->dip),
-		    ddi_get_instance(ctrl_p->dip)));
-	}
-}
--- a/usr/src/uts/common/io/hotplug/pcihp/pcihp.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/io/hotplug/pcihp/pcihp.c	Mon Nov 02 15:58:28 2009 +0800
@@ -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.
  */
 
@@ -258,9 +258,6 @@
 /* sysevent function */
 static void pcihp_gen_sysevent(char *, int, int, dev_info_t *, int);
 
-extern int pcicfg_configure(dev_info_t *, uint_t);
-extern int pcicfg_unconfigure(dev_info_t *, uint_t);
-
 static int pcihp_list_occupants(dev_info_t *, void *);
 static int pcihp_indirect_map(dev_info_t *dip);
 
@@ -1558,7 +1555,8 @@
 	/*
 	 * Call the configurator to configure the card.
 	 */
-	if (pcicfg_configure(self, pci_dev) != PCICFG_SUCCESS) {
+	if (pcicfg_configure(self, pci_dev, PCICFG_ALL_FUNC, 0)
+	    != PCICFG_SUCCESS) {
 		if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
 			if (pcihp_cpci_blue_led)
 				pcihp_hs_csr_op(pcihp_p, pci_dev,
@@ -1717,8 +1715,8 @@
 			(void) hpc_nexus_control(slotinfop->slot_hdl,
 			    HPC_CTRL_DEV_UNCONFIG_START, NULL);
 
-			if (pcicfg_unconfigure(self,
-			    pci_dev) == PCICFG_SUCCESS) {
+			if (pcicfg_unconfigure(self, pci_dev,
+			    PCICFG_ALL_FUNC, 0) == PCICFG_SUCCESS) {
 				/*
 				 * Now that resources are freed,
 				 * clear EXT and Turn LED ON.
@@ -2155,7 +2153,8 @@
 			/*
 			 * Call the configurator to configure the card.
 			 */
-			if (pcicfg_configure(dip, pci_dev) != PCICFG_SUCCESS) {
+			if (pcicfg_configure(dip, pci_dev, PCICFG_ALL_FUNC, 0)
+			    != PCICFG_SUCCESS) {
 				if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
 					if (pcihp_cpci_blue_led)
 						pcihp_hs_csr_op(pcihp_p,
@@ -2465,7 +2464,8 @@
 		/*
 		 * Call the configurator to configure the card.
 		 */
-		if (pcicfg_configure(pcihp_p->dip, pci_dev) != PCICFG_SUCCESS) {
+		if (pcicfg_configure(pcihp_p->dip, pci_dev, PCICFG_ALL_FUNC, 0)
+		    != PCICFG_SUCCESS) {
 			if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
 				if (pcihp_cpci_blue_led)
 					pcihp_hs_csr_op(pcihp_p, pci_dev,
@@ -2611,8 +2611,8 @@
 				(void) hpc_nexus_control(slotinfop->slot_hdl,
 				    HPC_CTRL_DEV_UNCONFIG_START, NULL);
 
-				if (pcicfg_unconfigure(pcihp_p->dip,
-				    pci_dev) == PCICFG_SUCCESS) {
+				if (pcicfg_unconfigure(pcihp_p->dip, pci_dev,
+				    PCICFG_ALL_FUNC, 0) == PCICFG_SUCCESS) {
 
 				/* Resources freed. Turn LED on. Clear EXT. */
 				if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
--- a/usr/src/uts/common/io/hotplug/pcishpc/pcishpc.c	Sun Nov 01 14:14:46 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2656 +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 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * PCISHPC - The Standard PCI HotPlug Controller driver module. This driver
- * can be used with PCI HotPlug controllers that are compatible
- * with the PCI SHPC specification 1.x.
- */
-
-#include <sys/note.h>
-#include <sys/conf.h>
-#include <sys/kmem.h>
-#include <sys/kstat.h>
-#include <sys/debug.h>
-#include <sys/vtrace.h>
-#include <sys/modctl.h>
-#include <sys/autoconf.h>
-#include <sys/varargs.h>
-#include <sys/hwconf.h>
-#include <sys/ddi_impldefs.h>
-#include <sys/pci.h>
-#include <sys/callb.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-#include <sys/sunndi.h>
-#include <sys/ndi_impldefs.h>
-#include <sys/hotplug/pci/pcishpc.h>
-#include <sys/hotplug/pci/pcishpc_regs.h>
-#include <sys/hotplug/hpcsvc.h>
-
-
-/* General Register bit weights for the 32-bit SHPC registers */
-#define	REG_BIT0	0x00000001
-#define	REG_BIT1	0x00000002
-#define	REG_BIT2	0x00000004
-#define	REG_BIT3	0x00000008
-#define	REG_BIT4	0x00000010
-#define	REG_BIT5	0x00000020
-#define	REG_BIT6	0x00000040
-#define	REG_BIT7	0x00000080
-#define	REG_BIT8	0x00000100
-#define	REG_BIT9	0x00000200
-#define	REG_BIT10	0x00000400
-#define	REG_BIT11	0x00000800
-#define	REG_BIT12	0x00001000
-#define	REG_BIT13	0x00002000
-#define	REG_BIT14	0x00004000
-#define	REG_BIT15	0x00008000
-#define	REG_BIT16	0x00010000
-#define	REG_BIT17	0x00020000
-#define	REG_BIT18	0x00040000
-#define	REG_BIT19	0x00080000
-#define	REG_BIT20	0x00100000
-#define	REG_BIT21	0x00200000
-#define	REG_BIT22	0x00400000
-#define	REG_BIT23	0x00800000
-#define	REG_BIT24	0x01000000
-#define	REG_BIT25	0x02000000
-#define	REG_BIT26	0x04000000
-#define	REG_BIT27	0x08000000
-#define	REG_BIT28	0x10000000
-#define	REG_BIT29	0x20000000
-#define	REG_BIT30	0x40000000
-#define	REG_BIT31	0x80000000
-
-/* Definitions used with the SHPC SHPC_SLOTS_AVAIL_I_REG register */
-#define	SHPC_AVAIL_33MHZ_CONV_SPEED_SHIFT	0
-#define	SHPC_AVAIL_66MHZ_PCIX_SPEED_SHIFT	8
-#define	SHPC_AVAIL_100MHZ_PCIX_SPEED_SHIFT	16
-#define	SHPC_AVAIL_133MHZ_PCIX_SPEED_SHIFT	24
-#define	SHPC_AVAIL_SPEED_MASK			0x1F
-
-/* Definitions used with the SHPC SHPC_SLOTS_AVAIL_II_REG register */
-#define	SHPC_AVAIL_66MHZ_CONV_SPEED_SHIFT	0
-
-/* Register bits used with the SHPC SHPC_PROF_IF_SBCR_REG register */
-#define	SHPC_SBCR_33MHZ_CONV_SPEED	0
-#define	SHPC_SBCR_66MHZ_CONV_SPEED	REG_BIT0
-#define	SHPC_SBCR_66MHZ_PCIX_SPEED	REG_BIT1
-#define	SHPC_SBCR_100MHZ_PCIX_SPEED	(REG_BIT0|REG_BIT1)
-#define	SHPC_SBCR_133MHZ_PCIX_SPEED	REG_BIT2
-#define	SHPC_SBCR_SPEED_MASK		(REG_BIT0|REG_BIT1|REG_BIT2)
-
-/* Register bits used with the SHPC SHPC_COMMAND_STATUS_REG register */
-#define	SHPC_COMM_STS_ERR_INVALID_SPEED		REG_BIT19
-#define	SHPC_COMM_STS_ERR_INVALID_COMMAND	REG_BIT18
-#define	SHPC_COMM_STS_ERR_MRL_OPEN		REG_BIT17
-#define	SHPC_COMM_STS_ERR_MASK			(REG_BIT17|REG_BIT18|REG_BIT19)
-#define	SHPC_COMM_STS_CTRL_BUSY			REG_BIT16
-#define	SHPC_COMM_STS_SET_SPEED			REG_BIT6
-
-/* Register bits used with the SHPC SHPC_CTRL_SERR_INT_REG register */
-#define	SHPC_SERR_INT_GLOBAL_IRQ_MASK	REG_BIT0
-#define	SHPC_SERR_INT_GLOBAL_SERR_MASK	REG_BIT1
-#define	SHPC_SERR_INT_CMD_COMPLETE_MASK	REG_BIT2
-#define	SHPC_SERR_INT_ARBITER_SERR_MASK	REG_BIT3
-#define	SHPC_SERR_INT_CMD_COMPLETE_IRQ	REG_BIT16
-#define	SHPC_SERR_INT_ARBITER_IRQ	REG_BIT17
-#define	SHPC_SERR_INT_MASK_ALL		(REG_BIT0|REG_BIT1|REG_BIT2|REG_BIT3)
-
-/* Register bits used with the SHPC SHPC_LOGICAL_SLOT_REGS register */
-#define	SHPC_SLOT_POWER_ONLY		REG_BIT0
-#define	SHPC_SLOT_ENABLED		REG_BIT1
-#define	SHPC_SLOT_DISABLED		(REG_BIT0 | REG_BIT1)
-#define	SHPC_SLOT_STATE_MASK		(REG_BIT0 | REG_BIT1)
-#define	SHPC_SLOT_MRL_STATE_MASK	REG_BIT8
-#define	SHPC_SLOT_66MHZ_CONV_CAPABLE	REG_BIT9
-#define	SHPC_SLOT_CARD_EMPTY_MASK	(REG_BIT10 | REG_BIT11)
-#define	SHPC_SLOT_66MHZ_PCIX_CAPABLE	REG_BIT12
-#define	SHPC_SLOT_100MHZ_PCIX_CAPABLE	REG_BIT13
-#define	SHPC_SLOT_133MHZ_PCIX_CAPABLE	(REG_BIT12 | REG_BIT13)
-#define	SHPC_SLOT_PCIX_CAPABLE_MASK	(REG_BIT12 | REG_BIT13)
-#define	SHPC_SLOT_PCIX_CAPABLE_SHIFT	12
-#define	SHPC_SLOT_PRESENCE_DETECTED	REG_BIT16
-#define	SHPC_SLOT_ISO_PWR_DETECTED	REG_BIT17
-#define	SHPC_SLOT_ATTN_DETECTED		REG_BIT18
-#define	SHPC_SLOT_MRL_DETECTED		REG_BIT19
-#define	SHPC_SLOT_POWER_DETECTED	REG_BIT20
-#define	SHPC_SLOT_PRESENCE_MASK		REG_BIT24
-#define	SHPC_SLOT_ISO_PWR_MASK		REG_BIT25
-#define	SHPC_SLOT_ATTN_MASK		REG_BIT26
-#define	SHPC_SLOT_MRL_MASK		REG_BIT27
-#define	SHPC_SLOT_POWER_MASK		REG_BIT28
-#define	SHPC_SLOT_MRL_SERR_MASK		REG_BIT29
-#define	SHPC_SLOT_POWER_SERR_MASK	REG_BIT30
-#define	SHPC_SLOT_MASK_ALL		(REG_BIT24|REG_BIT25|REG_BIT26|\
-					REG_BIT27|REG_BIT28|REG_BIT30)
-
-/* Register bits used with the SHPC SHPC_IRQ_LOCATOR_REG register. */
-#define	SHPC_IRQ_CMD_COMPLETE		REG_BIT0
-#define	SHPC_IRQ_SLOT_N_PENDING		REG_BIT1
-
-/* Register bits used with the SHPC SHPC_SERR_LOCATOR_REG register. */
-#define	SHPC_IRQ_SERR_ARBITER_PENDING	REG_BIT0
-#define	SHPC_IRQ_SERR_SLOT_N_PENDING	REG_BIT1
-
-/* Register bits used with the SHPC SHPC_SLOT_CONFIGURATION_REG register */
-#define	SHPC_SLOT_CONFIG_MRL_SENSOR		REG_BIT30
-#define	SHPC_SLOT_CONFIG_ATTN_BUTTON		REG_BIT31
-#define	SHPC_SLOT_CONFIG_PHY_SLOT_NUM_SHIFT	16
-#define	SHPC_SLOT_CONFIG_PHY_SLOT_NUM_MASK	0x3FF
-#define	SHPC_SLOT_CONFIG_PHY_SLOT_NUM(reg)	(((reg) >> 16) & 0x3FF)
-
-/* Max PCISHPC controller slots */
-#define	MAX_SHPC_SLOTS	31
-
-/* PCISHPC controller command complete delay in microseconds. */
-#define	SHPC_COMMAND_WAIT_TIME			10000
-
-/*
- * Power good wait time after issuing a command to change the slot state
- * to power only state.
- */
-#define	SHPC_POWER_GOOD_WAIT_TIME		220000
-
-/* reset delay to 1 sec. */
-static int pcishpc_reset_delay = 1000000;
-
-/* PCISHPC controller softstate structure */
-typedef struct pcishpc_ctrl {
-	dev_info_t	*shpc_dip;		/* DIP for SHPC Nexus */
-	ddi_acc_handle_t shpc_config_hdl;	/* SHPC DDI cfg handle */
-	kmutex_t	shpc_intr_mutex;	/* Interrupt mutex lock */
-	boolean_t	interrupt_installed;	/* Interrupt installed */
-	boolean_t	command_complete;	/* Got a cmd complete IRQ */
-	kcondvar_t	cmd_comp_cv;
-	boolean_t	arbiter_timeout;	/* Got a Arb timeout IRQ */
-	kmutex_t	shpc_mutex;		/* Mutex for this SHPC */
-	char		nexus_path[MAXNAMELEN]; /* Pathname of Nexus */
-	uint32_t	shpc_bus;		/* SHPC bus */
-	uint32_t	shpc_dev;		/* SHPC device */
-	uint32_t	shpc_func;		/* SHPC function */
-	uint8_t		shpc_dword_select;	/* SHPC register offset */
-	uint8_t		shpc_dword_data_reg;	/* SHPC data register */
-	uint32_t	shpc_slots_avail1_reg;	/* SHPC Slots Available1 Reg */
-	uint32_t	shpc_slots_avail2_reg;	/* SHPC Slots Available2 Reg */
-	uint32_t	numSlotsImpl;		/* # of HP Slots Implemented */
-	uint32_t	numSlotsConn;		/* # of HP Slots Connected */
-	int		currBusSpeed;		/* Current Bus Speed */
-	uint32_t	deviceStart;		/* 1st PCI Device # */
-	uint32_t	physStart;		/* 1st Phys Device # */
-	uint32_t	deviceIncreases;	/* Device # Increases */
-	struct pcishpc	*slots[MAX_SHPC_SLOTS]; /* Slot pointers */
-	boolean_t	has_attn;		/* Do we have attn btn?	*/
-	boolean_t	has_mrl;		/* Do we have MRL? */
-	struct pcishpc_ctrl *nextp;		/* Linked list pointer */
-} pcishpc_ctrl_t;
-
-/* PCISHPC slot softstate structure */
-typedef struct pcishpc {
-	pcishpc_ctrl_t	*ctrl;			/* SHPC ctrl for this slot */
-	hpc_slot_info_t	slot_info;		/* HPS framework slot info */
-	hpc_slot_t	slot_handle;		/* HPS framework handle */
-	hpc_slot_ops_t	 *slot_ops;		/* HPS framework callbacks */
-	uint32_t  fault_led_state;		/* Fault LED state */
-	uint32_t  power_led_state;		/* Power LED state */
-	uint32_t  attn_led_state;		/* Attn LED state */
-	uint32_t  active_led_state;		/* Active LED state */
-	hpc_slot_state_t slot_state;		/* Slot State */
-	uint32_t  deviceNum;			/* PCI device num for slot */
-	uint32_t  slotNum;			/* SHPC slot number */
-	uint32_t  phy_slot_num;			/* physical slot number */
-	uint32_t  slot_events;			/* Slot event(s) IRQ */
-	kcondvar_t attn_btn_cv;			/* ATTN button pressed intr */
-	boolean_t attn_btn_pending;
-	kthread_t *attn_btn_threadp;		/* ATTN button event thread */
-	boolean_t attn_btn_thread_exit;
-	struct pcishpc *nextp;			/* Linked list pointer */
-} pcishpc_t;
-/* mutex to protect the shpc_head and shpc_ctrl_head linked lists */
-static kmutex_t pcishpc_list_mutex;
-
-/* Pointer to a linked list of shpc slot softstate structures */
-static pcishpc_t *pcishpc_head = NULL;
-
-/* Pointer to a linked list of shpc controller softstate structures */
-static pcishpc_ctrl_t *pcishpc_ctrl_head = NULL;
-
-/* mutex to protect access to the controller */
-static kmutex_t pcishpc_control_mutex;
-
-/* SHPC static function prototypes */
-static pcishpc_ctrl_t *pcishpc_create_controller(dev_info_t *dip);
-static int	 pcishpc_destroy_controller(dev_info_t *dip);
-static pcishpc_ctrl_t *pcishpc_get_controller(dev_info_t *dip);
-static pcishpc_t	*pcishpc_create_slot(pcishpc_ctrl_t *ctrl_p);
-static int	pcishpc_destroy_slots(pcishpc_ctrl_t *ctrl_p);
-static pcishpc_t	*pcishpc_hpc_get_slot_state(hpc_slot_t slot);
-static int	pcishpc_setup_controller(pcishpc_ctrl_t *ctrl_p);
-static int	pcishpc_register_slot(pcishpc_ctrl_t *ctrl_p, int slot);
-static int	pcishpc_connect(caddr_t ops_arg,
-					hpc_slot_t slot_hdl, void *data,
-					uint_t flags);
-static int	pcishpc_disconnect(caddr_t ops_arg,
-					hpc_slot_t slot_hdl, void *data,
-					uint_t flags);
-static int	pcishpc_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl,
-				int request, caddr_t arg);
-static int	pcishpc_setled(pcishpc_t *pcishpc_p, hpc_led_t led,
-				hpc_led_state_t state);
-static int	pcishpc_set_power_state(pcishpc_t *pcishpc_p,
-					hpc_slot_state_t state);
-static int	pcishpc_set_bus_speed(pcishpc_t *pcishpc_p);
-static int	pcishpc_probe_controller(pcishpc_ctrl_t *pcishpc_p);
-static int	pcishpc_get_pci_info(pcishpc_ctrl_t *pcishpc_p);
-static void	pcishpc_get_slot_state(pcishpc_t *pcishpc_p);
-static int	pcishpc_process_intr(pcishpc_ctrl_t *ctrl_p);
-static int	pcishpc_enable_irqs(pcishpc_ctrl_t *ctrl_p);
-static int	pcishpc_disable_irqs(pcishpc_ctrl_t *ctrl_p);
-static void	pcishpc_set_soft_int(pcishpc_ctrl_t *ctrl_p);
-static int	pcishpc_wait_busy(pcishpc_ctrl_t *ctrl_p);
-static int	pcishpc_issue_command(pcishpc_ctrl_t *ctrl_p,
-				uint32_t cmd_code);
-static int	pcishpc_led_shpc_to_hpc(int state);
-static int	pcishpc_led_hpc_to_shpc(int state);
-static int	pcishpc_slot_shpc_to_hpc(int state);
-static int	pcishpc_slot_hpc_to_shpc(int state);
-static char	*pcishpc_textledstate(hpc_led_state_t state);
-static char	*pcishpc_textslotstate(hpc_slot_state_t state);
-static char	*pcishpc_textrequest(int request);
-static int	pcishpc_set_slot_state(pcishpc_t *pcishpc_p);
-static void	pcishpc_dump_regs(pcishpc_ctrl_t *ctrl_p);
-static void	pcishpc_write_reg(pcishpc_ctrl_t *ctrl_p, int reg,
-				uint32_t data);
-static uint32_t	pcishpc_read_reg(pcishpc_ctrl_t *ctrl_p, int reg);
-static void	pcishpc_debug(char *fmt, ...);
-
-static void pcishpc_attn_btn_handler(pcishpc_t *pcishpc_p);
-static void pcishpc_set_slot_name(pcishpc_ctrl_t *ctrl_p, int slot);
-
-static int pcishpc_debug_enabled = 0;
-
-/* Module operations information for the kernel */
-extern struct mod_ops mod_miscops;
-static struct modlmisc modlmisc = {
-	&mod_miscops,
-	"PCI SHPC hotplug module",
-};
-
-/* Module linkage information for the kernel */
-static struct modlinkage modlinkage = {
-	MODREV_1,
-	&modlmisc,
-	NULL
-};
-
-int
-_init(void)
-{
-	int rc;
-
-	if ((rc = mod_install(&modlinkage)) != 0) {
-		pcishpc_debug("pcishpc: install error=%d", rc);
-		return (rc);
-	}
-
-	/* Init the shpc driver list mutex. */
-	mutex_init(&pcishpc_list_mutex, NULL, MUTEX_DRIVER, NULL);
-	/* Init the shpc control mutex. */
-	mutex_init(&pcishpc_control_mutex, NULL, MUTEX_DRIVER, NULL);
-
-	pcishpc_debug("pcishpc: installed");
-	return (rc);
-}
-
-int
-_fini(void)
-{
-	pcishpc_debug("pcishpc: _fini called()");
-	/* XXX - to be fixed later */
-	return (EBUSY);
-}
-
-int
-_info(struct modinfo *modinfop)
-{
-	pcishpc_debug("pcishpc: _info called()");
-	return (mod_info(&modlinkage, modinfop));
-}
-
-
-/*
- * pcishpc_create_controller()
- *
- * This function allocates and creates an SHPC controller state structure
- * and adds it to the linked list of controllers.
- */
-static pcishpc_ctrl_t *
-pcishpc_create_controller(dev_info_t *dip)
-{
-	pcishpc_ctrl_t *ctrl_p;
-
-	pcishpc_debug("pcishpc: create controller for %s#%d",
-			ddi_driver_name(dip), ddi_get_instance(dip));
-
-	ctrl_p = kmem_zalloc(sizeof (pcishpc_ctrl_t), KM_SLEEP);
-
-	ctrl_p->interrupt_installed = B_FALSE;
-	ctrl_p->shpc_dip = dip;
-
-	(void) ddi_pathname(dip, ctrl_p->nexus_path);
-
-	/* Get the PCI BUS,DEVICE,FUNCTION for this SHPC controller. */
-	if (pcishpc_get_pci_info(ctrl_p) != DDI_SUCCESS) {
-
-		pcishpc_debug("pcishpc_create_controller() "
-			"Error: pcishpc_get_pci_info() failed");
-		kmem_free(ctrl_p, sizeof (pcishpc_ctrl_t));
-		return (NULL);
-	}
-
-	if (pci_config_setup(dip, &ctrl_p->shpc_config_hdl) != DDI_SUCCESS) {
-		pcishpc_debug("pcishpc_create_controller() "
-			"Error: Unable to map SHPC PCI Config registers");
-		kmem_free(ctrl_p, sizeof (pcishpc_ctrl_t));
-		return (NULL);
-	}
-
-	/* Make sure the SHPC is listed in the PCI capibilities list. */
-	if (pcishpc_probe_controller(ctrl_p) != DDI_SUCCESS) {
-		pcishpc_debug("pcishpc_create_controller() "
-			"Error: Unable to find SHPC controller");
-		pci_config_teardown(&ctrl_p->shpc_config_hdl);
-		kmem_free(ctrl_p, sizeof (pcishpc_ctrl_t));
-		return (NULL);
-	}
-
-	/* Init the interrupt mutex */
-	mutex_init(&ctrl_p->shpc_intr_mutex, NULL, MUTEX_DRIVER,
-		(void *)PCISHPC_INTR_PRI);
-
-	/* Interrupts are now enabled. */
-	ctrl_p->interrupt_installed = B_TRUE;
-
-	/* Init the shpc controller's mutex. */
-	mutex_init(&ctrl_p->shpc_mutex, NULL, MUTEX_DRIVER, NULL);
-
-	mutex_enter(&pcishpc_list_mutex);
-
-	/* Insert new softstate into linked list of current soft states. */
-	ctrl_p->nextp  = pcishpc_ctrl_head;
-	pcishpc_ctrl_head = ctrl_p;
-
-	mutex_exit(&pcishpc_list_mutex);
-
-	pcishpc_debug("pcishpc_create_controller() success");
-
-	return (ctrl_p);
-}
-
-
-/*
- * pcishpc_probe_controller()
- *
- * This function probes to make sure there is indeed an SHPC controller.
- */
-static int
-pcishpc_probe_controller(pcishpc_ctrl_t *ctrl_p)
-{
-	uint8_t cap_ptr;
-	uint8_t cap_id;
-	uint16_t status;
-
-	status = pci_config_get16(ctrl_p->shpc_config_hdl, PCI_CONF_STAT);
-	if (!(status & PCI_STAT_CAP)) {
-		return (DDI_FAILURE);
-	}
-
-	/* Get a pointer to the PCI capabilities list. */
-	cap_ptr = pci_config_get8(ctrl_p->shpc_config_hdl, PCI_BCNF_CAP_PTR);
-
-	cap_ptr &= 0xFC;
-
-	/* Walk PCI capabilities list searching for the SHPC capability. */
-	while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
-		cap_id = pci_config_get8(ctrl_p->shpc_config_hdl, cap_ptr);
-
-		pcishpc_debug("pcishpc_probe_controller() capability @ "
-				"pointer=%02x (id=%02x)", cap_ptr, cap_id);
-
-		if (cap_id == PCI_CAP_ID_PCI_HOTPLUG) {
-			/* Save the SHPC register offset. */
-			ctrl_p->shpc_dword_select	= cap_ptr+2;
-			/* Save the SHPC data register. */
-			ctrl_p->shpc_dword_data_reg = cap_ptr+4;
-			break;
-		}
-
-		/* Get the pointer to the next capability. */
-		cap_ptr = pci_config_get8(ctrl_p->shpc_config_hdl,
-			cap_ptr+1);
-
-		cap_ptr &= 0xFC;
-	}
-
-	if (cap_ptr == PCI_CAP_NEXT_PTR_NULL) {
-		return (DDI_FAILURE);
-	}
-
-	pcishpc_debug("pcishpc_probe_controller() Found SHPC capibility");
-
-	return (DDI_SUCCESS);
-}
-
-
-/*
- * pcishpc_destroy_controller()
- *
- * This function deallocates all of the SHPC controller resources.
- */
-static int
-pcishpc_destroy_controller(dev_info_t *dip)
-{
-	pcishpc_ctrl_t *ctrl_p;
-	pcishpc_ctrl_t **ctrl_pp;
-
-	pcishpc_debug("pcishpc_destroy_controller() called(dip=%p)", dip);
-
-	mutex_enter(&pcishpc_list_mutex);
-
-	ctrl_pp = &pcishpc_ctrl_head;
-
-	/* Walk the linked list of softstates. */
-	while ((ctrl_p = *ctrl_pp) != NULL) {
-		if (ctrl_p->shpc_dip == dip) {
-			/*
-			 * Deallocate the slot state structures for
-			 * this controller.
-			 */
-			(void) pcishpc_destroy_slots(ctrl_p);
-
-			*ctrl_pp = ctrl_p->nextp;
-
-			pci_config_teardown(&ctrl_p->shpc_config_hdl);
-
-			cv_destroy(&ctrl_p->cmd_comp_cv);
-
-			mutex_destroy(&ctrl_p->shpc_mutex);
-			mutex_destroy(&ctrl_p->shpc_intr_mutex);
-			kmem_free(ctrl_p, sizeof (pcishpc_ctrl_t));
-			mutex_exit(&pcishpc_list_mutex);
-
-			pcishpc_debug("pcishpc_destroy_controller() success");
-			return (DDI_SUCCESS);
-		}
-		ctrl_pp = &(ctrl_p->nextp);
-	}
-
-	mutex_exit(&pcishpc_list_mutex);
-
-	pcishpc_debug("pcishpc_destroy_controller() not found");
-
-	return (DDI_FAILURE);
-}
-
-
-/*
- * pcishpc_intr()
- *
- * This is the SHPC controller interrupt handler.
- */
-int
-pcishpc_intr(dev_info_t *dip)
-{
-	pcishpc_ctrl_t *ctrl_p = pcishpc_get_controller(dip);
-	int slot;
-	uint32_t irq_locator, irq_serr_locator, reg;
-	boolean_t slot_event = B_FALSE;
-
-	pcishpc_debug("pcishpc_intr() called");
-
-	if (ctrl_p->interrupt_installed == B_TRUE) {
-		mutex_enter(&ctrl_p->shpc_intr_mutex);
-
-		pcishpc_debug("pcishpc_intr() interrupt received");
-
-		reg = pcishpc_read_reg(ctrl_p, SHPC_CTRL_SERR_INT_REG);
-
-		if (reg & SHPC_SERR_INT_CMD_COMPLETE_IRQ) {
-			pcishpc_debug("pcishpc_intr() "
-				"SHPC_SERR_INT_CMD_COMPLETE_IRQ detected");
-			ctrl_p->command_complete = B_TRUE;
-			cv_signal(&ctrl_p->cmd_comp_cv);
-		}
-
-		if (reg & SHPC_SERR_INT_ARBITER_IRQ) {
-			pcishpc_debug("pcishpc_intr() SHPC_SERR_INT_ARBITER_IRQ"
-					" detected");
-			ctrl_p->arbiter_timeout = B_TRUE;
-		}
-
-		/* Write back the SERR INT register to acknowledge the IRQs. */
-		pcishpc_write_reg(ctrl_p, SHPC_CTRL_SERR_INT_REG, reg);
-
-		irq_locator = pcishpc_read_reg(ctrl_p, SHPC_IRQ_LOCATOR_REG);
-
-		irq_serr_locator = pcishpc_read_reg(ctrl_p,
-					SHPC_SERR_LOCATOR_REG);
-
-		/* Check for slot events that might have occured. */
-		for (slot = 0; slot < ctrl_p->numSlotsImpl; slot++) {
-			if ((irq_locator & (SHPC_IRQ_SLOT_N_PENDING<<slot)) ||
-					(irq_serr_locator &
-					(SHPC_IRQ_SERR_SLOT_N_PENDING<<slot))) {
-				pcishpc_debug("pcishpc_intr() slot %d and "
-						"pending IRQ", slot+1);
-
-				/*
-				 * Note that we will need to generate a
-				 * slot event interrupt.
-				 */
-				slot_event = B_TRUE;
-
-				reg = pcishpc_read_reg(ctrl_p,
-						SHPC_LOGICAL_SLOT_REGS+slot);
-
-				/* Record any pending slot interrupts/events. */
-				ctrl_p->slots[slot]->slot_events |= reg;
-
-				/* Acknoledge any slot interrupts */
-				pcishpc_write_reg(ctrl_p,
-					SHPC_LOGICAL_SLOT_REGS+slot, reg);
-			}
-		}
-
-		if (slot_event == B_TRUE) {
-			pcishpc_debug("pcishpc_intr() slot(s) have event(s)");
-			(void) pcishpc_process_intr(ctrl_p);
-		} else {
-			pcishpc_debug("pcishpc_intr() No slot event(s)");
-		}
-
-		mutex_exit(&ctrl_p->shpc_intr_mutex);
-
-		pcishpc_debug("pcishpc_intr() claimed");
-
-		return (DDI_INTR_CLAIMED);
-	}
-
-	pcishpc_debug("pcishpc_intr() unclaimed");
-
-	return (DDI_INTR_UNCLAIMED);
-}
-
-/*
- * pcishpc_process_intr()
- *
- * This is the SHPC soft interrupt handler.
- */
-static int
-pcishpc_process_intr(pcishpc_ctrl_t *ctrl_p)
-{
-	int slot;
-
-	mutex_enter(&ctrl_p->shpc_mutex);
-
-	pcishpc_debug("pcishpc_process_intr() called");
-
-	/* XXX - add event handling code here */
-	for (slot = 0; slot < ctrl_p->numSlotsImpl; slot++) {
-		if (ctrl_p->slots[slot]->slot_events &
-				SHPC_SLOT_PRESENCE_DETECTED)
-			pcishpc_debug("slot %d: SHPC_SLOT_PRESENCE_DETECTED",
-					slot+1);
-
-		if (ctrl_p->slots[slot]->slot_events &
-				SHPC_SLOT_ISO_PWR_DETECTED)
-			pcishpc_debug("slot %d: SHPC_SLOT_ISO_PWR_DETECTED",
-					slot+1);
-
-		if (ctrl_p->slots[slot]->slot_events &
-		    SHPC_SLOT_ATTN_DETECTED) {
-			pcishpc_debug("slot %d: SHPC_SLOT_ATTN_DETECTED",
-					slot+1);
-			/*
-			 * if ATTN button event is still pending
-			 * then cancel it
-			 */
-			if (ctrl_p->slots[slot]->attn_btn_pending == B_TRUE)
-				ctrl_p->slots[slot]->attn_btn_pending = B_FALSE;
-
-			/* wake up the ATTN event handler */
-			cv_signal(&ctrl_p->slots[slot]->attn_btn_cv);
-		}
-
-		if (ctrl_p->slots[slot]->slot_events & SHPC_SLOT_MRL_DETECTED)
-			pcishpc_debug("slot %d: SHPC_SLOT_MRL_DETECTED",
-					slot+1);
-
-		if (ctrl_p->slots[slot]->slot_events & SHPC_SLOT_POWER_DETECTED)
-			pcishpc_debug("slot %d: SHPC_SLOT_POWER_DETECTED",
-					slot+1);
-
-		/* Clear the events now that we've processed all of them. */
-		ctrl_p->slots[slot]->slot_events = 0;
-	}
-
-	mutex_exit(&ctrl_p->shpc_mutex);
-
-	return (DDI_INTR_CLAIMED);
-}
-
-
-/*
- * pcishpc_get_controller()
- *
- * This function retrieves the hot plug SHPC controller soft state.
- */
-static pcishpc_ctrl_t *
-pcishpc_get_controller(dev_info_t *dip)
-{
-	pcishpc_ctrl_t *ctrl_p;
-
-	pcishpc_debug("pcishpc_get_controller() called (dip=%p)", dip);
-
-	mutex_enter(&pcishpc_list_mutex);
-
-	ctrl_p = pcishpc_ctrl_head;
-
-	while (ctrl_p) {
-		if (ctrl_p->shpc_dip == dip)
-			break;
-		ctrl_p = ctrl_p->nextp;
-	}
-
-	mutex_exit(&pcishpc_list_mutex);
-
-	pcishpc_debug("pcishpc_get_controller() (ctrl_p=%llx)", ctrl_p);
-
-	return (ctrl_p);
-}
-
-
-/*
- * pcishpc_hpc_get_slot_state()
- *
- * This function retrieves the hot plug SHPC soft state from the
- * the HPS framework slot handle.
- */
-static pcishpc_t *
-pcishpc_hpc_get_slot_state(hpc_slot_t slot)
-{
-	pcishpc_t *pcishpc_p;
-
-	pcishpc_debug("pcishpc_hpc_get_slot_state() called (hpc_slot=%x)",
-		slot);
-
-	mutex_enter(&pcishpc_list_mutex);
-
-	pcishpc_p = pcishpc_head;
-
-	while (pcishpc_p) {
-		if (pcishpc_p->slot_handle == slot) {
-			pcishpc_debug("pcishpc_hpc_get_slot_state() found "
-					"(pcishpc=%x)", pcishpc_p);
-			mutex_exit(&pcishpc_list_mutex);
-			return (pcishpc_p);
-		}
-		pcishpc_p = pcishpc_p->nextp;
-	}
-
-	mutex_exit(&pcishpc_list_mutex);
-
-	pcishpc_debug("pcishpc_hpc_get_slot_state() failed (slot=%x)", slot);
-
-	return (NULL);
-}
-
-
-/*
- * pcishpc_get_pci_info()
- *
- * Read the PCI Bus, PCI Device, and PCI function for the SHPC controller.
- */
-static int
-pcishpc_get_pci_info(pcishpc_ctrl_t *pcishpc_p)
-{
-	pci_regspec_t *regspec;
-	int reglen;
-
-	pcishpc_debug("pcishpc_get_pci_info() called");
-
-	if (ddi_getlongprop(DDI_DEV_T_NONE, pcishpc_p->shpc_dip,
-			DDI_PROP_DONTPASS, "reg", (caddr_t)&regspec, &reglen)
-				!= DDI_SUCCESS) {
-		pcishpc_debug("pcishpc_get_pci_info() failed to get regspec.");
-		return (DDI_FAILURE);
-	}
-
-	pcishpc_p->shpc_bus  = PCI_REG_BUS_G(regspec[0].pci_phys_hi);
-	pcishpc_p->shpc_dev  = PCI_REG_DEV_G(regspec[0].pci_phys_hi);
-	pcishpc_p->shpc_func = PCI_REG_FUNC_G(regspec[0].pci_phys_hi);
-
-	kmem_free(regspec, reglen);
-
-	pcishpc_debug("pcishpc_get_pci_info() %s%d: bus=%d, dev=%d, func=%d",
-			ddi_driver_name(pcishpc_p->shpc_dip),
-			ddi_get_instance(pcishpc_p->shpc_dip),
-			pcishpc_p->shpc_bus, pcishpc_p->shpc_dev,
-				pcishpc_p->shpc_func);
-
-	return (DDI_SUCCESS);
-}
-
-
-/*
- * pcishpc_init()
- *
- * Install and configure an SHPC controller and register the HotPlug slots
- * with the Solaris HotPlug framework. This function is usually called by
- * a PCI bridge Nexus driver that has a built in SHPC controller.
- */
-int
-pcishpc_init(dev_info_t *dip)
-{
-	pcishpc_ctrl_t *ctrl_p;
-	int i;
-
-	pcishpc_debug("pcishpc_init() called from %s#%d",
-			ddi_driver_name(dip), ddi_get_instance(dip));
-
-	mutex_enter(&pcishpc_control_mutex);
-
-	if (pcishpc_get_controller(dip) != NULL) {
-		pcishpc_debug("pcishpc_init() shpc instance already "
-				"initialized!");
-		mutex_exit(&pcishpc_control_mutex);
-		return (DDI_SUCCESS);
-	}
-
-	/* Initialize soft state structure for the SHPC instance. */
-	ctrl_p = pcishpc_create_controller(dip);
-
-	if (ctrl_p == NULL) {
-		pcishpc_debug("pcishpc_init() failed to create shpc softstate");
-		mutex_exit(&pcishpc_control_mutex);
-		return (DDI_FAILURE);
-	}
-
-	if (pcishpc_setup_controller(ctrl_p) != DDI_SUCCESS) {
-		pcishpc_debug("pcishpc_init() failed to setup controller");
-		(void) pcishpc_destroy_controller(dip);
-		mutex_exit(&pcishpc_control_mutex);
-		return (DDI_FAILURE);
-	}
-
-#if 0
-	pcishpc_debug("%s%d: P2P bridge register dump:",
-		ddi_driver_name(dip), ddi_get_instance(dip));
-
-	for (i = 0; i < 0x100; i += 4) {
-		pcishpc_debug("SHPC Cfg reg 0x%02x: %08x", i,
-			pci_config_get32(ctrl_p->shpc_config_hdl, i));
-	}
-#endif
-
-	/* Setup each HotPlug slot on this SHPC controller. */
-	for (i = 0; i < ctrl_p->numSlotsImpl; i++) {
-		if (pcishpc_register_slot(ctrl_p, i) != DDI_SUCCESS) {
-			pcishpc_debug("pcishpc_init() failed to register "
-				"slot %d", i);
-			(void) pcishpc_destroy_controller(dip);
-			mutex_exit(&pcishpc_control_mutex);
-			return (DDI_FAILURE);
-		}
-	}
-
-	(void) pcishpc_enable_irqs(ctrl_p);
-
-	if (pcishpc_debug_enabled) {
-		/* Dump out the SHPC registers. */
-		pcishpc_dump_regs(ctrl_p);
-	}
-
-	mutex_exit(&pcishpc_control_mutex);
-
-	pcishpc_debug("pcishpc_init() success(dip=%p)", dip);
-	return (DDI_SUCCESS);
-}
-
-
-/*
- * pcishpc_enable_irqs()
- *
- * Enable/unmask the different IRQ's we support from the SHPC controller.
- */
-static int
-pcishpc_enable_irqs(pcishpc_ctrl_t *ctrl_p)
-{
-	uint32_t reg;
-	int slot;
-
-	reg = pcishpc_read_reg(ctrl_p, SHPC_CTRL_SERR_INT_REG);
-
-	/* Enable all interrupts. */
-	reg &= ~SHPC_SERR_INT_MASK_ALL;
-
-	pcishpc_write_reg(ctrl_p, SHPC_CTRL_SERR_INT_REG, reg);
-
-	/* Unmask the interrupts for each slot. */
-	for (slot = 0; slot < ctrl_p->numSlotsImpl; slot++) {
-		ctrl_p->slots[slot]->slot_events = 0;
-
-		reg = pcishpc_read_reg(ctrl_p, SHPC_LOGICAL_SLOT_REGS+slot);
-		if ((reg & SHPC_SLOT_STATE_MASK) == SHPC_SLOT_ENABLED) {
-			reg &= ~(SHPC_SLOT_MASK_ALL | SHPC_SLOT_MRL_SERR_MASK);
-			ctrl_p->numSlotsConn++;
-			if (ctrl_p->currBusSpeed == -1)
-				ctrl_p->currBusSpeed = pcishpc_read_reg(ctrl_p,
-				    SHPC_PROF_IF_SBCR_REG) &
-				    SHPC_SBCR_SPEED_MASK;
-		} else {
-			reg &= ~(SHPC_SLOT_MASK_ALL);
-		}
-
-		/* Enable/Unmask all slot interrupts. */
-		pcishpc_write_reg(ctrl_p, SHPC_LOGICAL_SLOT_REGS+slot, reg);
-	}
-
-	pcishpc_debug("pcishpc_enable_irqs: ctrl_p 0x%p, "
-	    "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p,
-	    ctrl_p->currBusSpeed, ctrl_p->numSlotsConn);
-
-	return (DDI_SUCCESS);
-}
-
-
-/*
- * pcishpc_disable_irqs()
- *
- * Disable/Mask the different IRQ's we support from the SHPC controller.
- */
-static int
-pcishpc_disable_irqs(pcishpc_ctrl_t *ctrl_p)
-{
-	uint32_t reg;
-	int slot;
-
-	reg = pcishpc_read_reg(ctrl_p, SHPC_CTRL_SERR_INT_REG);
-
-	/* Mask all interrupts. */
-	reg |= SHPC_SERR_INT_MASK_ALL;
-
-	pcishpc_write_reg(ctrl_p, SHPC_CTRL_SERR_INT_REG, reg);
-
-	/* Unmask the interrupts for each slot. */
-	for (slot = 0; slot < ctrl_p->numSlotsImpl; slot++) {
-		reg = pcishpc_read_reg(ctrl_p, SHPC_LOGICAL_SLOT_REGS+slot);
-
-		/* Disable/Mask all slot interrupts. */
-		reg |= SHPC_SLOT_MASK_ALL;
-
-		pcishpc_write_reg(ctrl_p, SHPC_LOGICAL_SLOT_REGS+slot, reg);
-	}
-
-	pcishpc_debug("pcishpc_disable_irqs: ctrl_p 0x%p, "
-	    "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p,
-	    ctrl_p->currBusSpeed, ctrl_p->numSlotsConn);
-
-	return (DDI_SUCCESS);
-}
-
-
-/*
- * pcishpc_register_slot()
- *
- * Create and register a slot with the Solaris HotPlug framework.
- */
-static int
-pcishpc_register_slot(pcishpc_ctrl_t *ctrl_p, int slot)
-{
-	pcishpc_t *pcishpc_p;
-
-	pcishpc_p = pcishpc_create_slot(ctrl_p);
-
-	ctrl_p->slots[slot] = pcishpc_p;
-
-	pcishpc_p->slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
-
-	pcishpc_p->slot_ops->hpc_version = HPC_SLOT_OPS_VERSION;
-
-	pcishpc_p->slotNum = slot;
-
-	/* Setup the PCI device # for this SHPC slot. */
-	if (ctrl_p->deviceIncreases)
-		pcishpc_p->deviceNum = ctrl_p->deviceStart + pcishpc_p->slotNum;
-	else
-		pcishpc_p->deviceNum = ctrl_p->deviceStart - pcishpc_p->slotNum;
-
-	/* Setup the HPS framework slot ops callbacks for the SHPC driver. */
-	pcishpc_p->slot_ops->hpc_op_connect	 = pcishpc_connect;
-	pcishpc_p->slot_ops->hpc_op_disconnect = pcishpc_disconnect;
-	pcishpc_p->slot_ops->hpc_op_control	 = pcishpc_pci_control;
-	/* PCI HPC drivers do not support the insert/remove callbacks. */
-	pcishpc_p->slot_ops->hpc_op_insert	  = NULL;
-	pcishpc_p->slot_ops->hpc_op_remove	  = NULL;
-
-	/* Setup the HPS framework slot information. */
-	pcishpc_p->slot_info.version = HPC_SLOT_OPS_VERSION;
-	pcishpc_p->slot_info.slot_type = HPC_SLOT_TYPE_PCI;
-	/* Do not auto enable the deivce in this slot. */
-	pcishpc_p->slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE |
-						HPC_SLOT_CREATE_DEVLINK;
-
-	pcishpc_p->slot_info.slot.pci.device_number = pcishpc_p->deviceNum;
-	pcishpc_p->slot_info.slot.pci.slot_capabilities = HPC_SLOT_64BITS;
-
-	/* setup thread for handling ATTN button events */
-	if (ctrl_p->has_attn) {
-		pcishpc_debug("pcishpc_register_slot: "
-		    "setting up ATTN button event "
-		    "handler thread for slot %d\n", slot);
-		cv_init(&pcishpc_p->attn_btn_cv, NULL, CV_DRIVER, NULL);
-		pcishpc_p->attn_btn_pending = B_FALSE;
-		pcishpc_p->attn_btn_threadp = thread_create(NULL, 0,
-		    pcishpc_attn_btn_handler,
-		    (void *)pcishpc_p, 0, &p0, TS_RUN, minclsyspri);
-		pcishpc_p->attn_btn_thread_exit = B_FALSE;
-	}
-
-	/* setup the slot name (used for ap-id) */
-	pcishpc_set_slot_name(ctrl_p, slot);
-
-	pcishpc_get_slot_state(pcishpc_p);
-
-	/* Register this SHPC slot with the HPS framework. */
-	if (hpc_slot_register(ctrl_p->shpc_dip, ctrl_p->nexus_path,
-		&pcishpc_p->slot_info, &pcishpc_p->slot_handle,
-			pcishpc_p->slot_ops, (caddr_t)pcishpc_p, 0) != 0) {
-
-		pcishpc_debug("pcishpc_register_slot() failed to Register "
-			"slot");
-
-		hpc_free_slot_ops(pcishpc_p->slot_ops);
-		pcishpc_p->slot_ops = NULL;
-
-		return (DDI_FAILURE);
-	}
-
-	pcishpc_debug("pcishpc_register_slot() success for slot %d", slot);
-
-	return (DDI_SUCCESS);
-}
-
-
-/*
- * pcishpc_create_slot()
- *
- * Allocate and add a new HotPlug slot state structure to the linked list.
- */
-static pcishpc_t *
-pcishpc_create_slot(pcishpc_ctrl_t *ctrl_p)
-{
-	pcishpc_t *pcishpc_p;
-
-	pcishpc_debug("pcishpc_create_slot() called(ctrl_p=%x)", ctrl_p);
-
-	/* Allocate a new slot structure. */
-	pcishpc_p = kmem_zalloc(sizeof (pcishpc_t), KM_SLEEP);
-
-	pcishpc_p->ctrl = ctrl_p;
-
-	mutex_enter(&pcishpc_list_mutex);
-
-	/* Insert new slot into linked list of current slots. */
-	pcishpc_p->nextp  = pcishpc_head;
-	pcishpc_head = pcishpc_p;
-
-	mutex_exit(&pcishpc_list_mutex);
-
-	pcishpc_debug("pcishpc_create_slot() success");
-	return (pcishpc_p);
-}
-
-/*
- * pcishpc_setup_controller()
- *
- * Get the number of HotPlug Slots, and the PCI device information
- * for this HotPlug controller.
- */
-static int
-pcishpc_setup_controller(pcishpc_ctrl_t *ctrl_p)
-{
-	uint32_t config;
-	dev_info_t *ppdip;
-
-	config = pcishpc_read_reg(ctrl_p, SHPC_SLOT_CONFIGURATION_REG);
-
-	/* Get the number of HotPlug slots implemented */
-	ctrl_p->numSlotsImpl = ((config)&31);
-
-	/*
-	 * Initilize the current bus speed and number of hotplug slots
-	 * currently connected.
-	 */
-	ctrl_p->currBusSpeed = -1;
-	ctrl_p->numSlotsConn = 0;
-
-	/* Save the value of Slots Available 1 and 2 registers */
-	ctrl_p->shpc_slots_avail1_reg = pcishpc_read_reg(ctrl_p,
-	    SHPC_SLOTS_AVAIL_I_REG);
-	ctrl_p->shpc_slots_avail2_reg = pcishpc_read_reg(ctrl_p,
-	    SHPC_SLOTS_AVAIL_II_REG);
-
-	/* Get the first PCI device Number used. */
-	/*
-	 * PCI-X I/O boat workaround.
-	 * The register doesn't set up the correct value.
-	 */
-	ppdip = ddi_get_parent(ddi_get_parent(ctrl_p->shpc_dip));
-	if ((ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS,
-	    "vendor-id", -1) == 0x108e) &&
-	    (ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS,
-	    "device-id", -1) == 0x9010))
-		ctrl_p->deviceStart = 4;
-	else
-		ctrl_p->deviceStart = ((config>>8)&31);
-
-	/* Get the first Physical device number. */
-	ctrl_p->physStart = ((config>>16)&0x7ff);
-	/* Check if the device numbers increase or decrease. */
-	ctrl_p->deviceIncreases = ((config>>29)&0x1);
-
-	ctrl_p->has_attn =
-		(config & SHPC_SLOT_CONFIG_ATTN_BUTTON) ? B_TRUE : B_FALSE;
-	ctrl_p->has_mrl =
-		(config & SHPC_SLOT_CONFIG_MRL_SENSOR) ? B_TRUE : B_FALSE;
-
-	cv_init(&ctrl_p->cmd_comp_cv, NULL, CV_DRIVER, NULL);
-	ctrl_p->command_complete = B_FALSE;
-	ctrl_p->arbiter_timeout = B_FALSE;
-
-	if (ctrl_p->numSlotsImpl > MAX_SHPC_SLOTS) {
-		pcishpc_debug("pcishpc_setup_controller() too many SHPC "
-			"slots error");
-		return (DDI_FAILURE);
-	}
-
-	return (DDI_SUCCESS);
-}
-
-
-/*
- * pcishpc_uninit()
- * Unload the HogPlug controller driver and deallocate all resources.
- */
-int
-pcishpc_uninit(dev_info_t *dip)
-{
-	pcishpc_ctrl_t *ctrl_p;
-
-	pcishpc_debug("pcishpc_uninit() called(dip=%p)", dip);
-
-	mutex_enter(&pcishpc_control_mutex);
-
-	ctrl_p = pcishpc_get_controller(dip);
-
-	if (!ctrl_p) {
-		pcishpc_debug("pcishpc_uninit() Unable to find softstate");
-		mutex_exit(&pcishpc_control_mutex);
-		return (DDI_FAILURE);
-	}
-
-	(void) pcishpc_disable_irqs(ctrl_p);
-	ctrl_p->interrupt_installed = B_FALSE;
-
-	(void) pcishpc_destroy_controller(dip);
-
-	mutex_exit(&pcishpc_control_mutex);
-
-	pcishpc_debug("pcishpc_uninit() success(dip=%p)", dip);
-
-	return (DDI_SUCCESS);
-}
-
-/*
- * pcishpc_destroy_slots()
- *
- * Free up all of the slot resources for this controller.
- */
-static int
-pcishpc_destroy_slots(pcishpc_ctrl_t *ctrl_p)
-{
-	pcishpc_t *pcishpc_p;
-	pcishpc_t **pcishpc_pp;
-
-	pcishpc_debug("pcishpc_destroy_slots() called(ctrl_p=%p)", ctrl_p);
-
-	pcishpc_pp = &pcishpc_head;
-
-	while ((pcishpc_p = *pcishpc_pp) != NULL) {
-		if (pcishpc_p->ctrl == ctrl_p) {
-			if (pcishpc_p->attn_btn_threadp != NULL) {
-				mutex_enter(&ctrl_p->shpc_mutex);
-				pcishpc_p->attn_btn_thread_exit = B_TRUE;
-				cv_signal(&pcishpc_p->attn_btn_cv);
-				pcishpc_debug("pcishpc_destroy_slots: "
-				    "waiting for ATTN thread exit\n");
-				cv_wait(&pcishpc_p->attn_btn_cv,
-				    &ctrl_p->shpc_mutex);
-				pcishpc_debug("pcishpc_destroy_slots: "
-				    "ATTN thread exit\n");
-				cv_destroy(&pcishpc_p->attn_btn_cv);
-				pcishpc_p->attn_btn_threadp = NULL;
-				mutex_exit(&ctrl_p->shpc_mutex);
-			}
-
-			*pcishpc_pp = pcishpc_p->nextp;
-
-			pcishpc_debug("pcishpc_destroy_slots() (shpc_p=%p) "
-			    "destroyed", pcishpc_p);
-			if (pcishpc_p->slot_ops)
-				if (hpc_slot_unregister(
-				    &pcishpc_p->slot_handle) != 0) {
-					pcishpc_debug("pcishpc_destroy_slots() "
-					    "failed to unregister slot");
-					return (DDI_FAILURE);
-				} else {
-					hpc_free_slot_ops(pcishpc_p->slot_ops);
-					pcishpc_p->slot_ops = NULL;
-				}
-			kmem_free(pcishpc_p, sizeof (pcishpc_t));
-		} else
-			pcishpc_pp = &(pcishpc_p->nextp);
-	}
-
-	return (DDI_SUCCESS);
-}
-
-
-/*
- * pcishpc_connect()
- *
- * Called by Hot Plug Services to connect a slot on the bus.
- */
-/*ARGSUSED*/
-static int
-pcishpc_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
-{
-	pcishpc_t *pcishpc_p;
-	uint32_t status;
-
-	pcishpc_debug("pcishpc_connect called()");
-
-	pcishpc_p = pcishpc_hpc_get_slot_state(slot_hdl);
-
-	if (!pcishpc_p) {
-		pcishpc_debug("pcishpc_connect() "
-			"Failed to find soft state for slot_hdl %x", slot_hdl);
-		return (HPC_ERR_FAILED);
-	}
-
-	mutex_enter(&pcishpc_p->ctrl->shpc_mutex);
-
-	/* make sure the MRL sensor is closed */
-	status = pcishpc_read_reg(pcishpc_p->ctrl,
-		SHPC_LOGICAL_SLOT_REGS+pcishpc_p->slotNum);
-
-	if (status & SHPC_SLOT_MRL_STATE_MASK) {
-		pcishpc_debug("pcishpc_connect() failed: MRL open");
-		goto cleanup;
-	}
-
-	if (pcishpc_set_power_state(pcishpc_p, HPC_SLOT_CONNECTED) !=
-				DDI_SUCCESS) {
-		pcishpc_debug("pcishpc_connect() failed: set power state");
-		goto cleanup;
-	}
-
-	mutex_exit(&pcishpc_p->ctrl->shpc_mutex);
-
-	pcishpc_debug("pcishpc_connect() success!");
-
-	return (HPC_SUCCESS);
-
-cleanup:
-	mutex_exit(&pcishpc_p->ctrl->shpc_mutex);
-	return (HPC_ERR_FAILED);
-}
-
-
-/*
- * pcishpc_set_power_state()
- *
- * Changed a slot's power state.
- */
-static int
-pcishpc_set_power_state(pcishpc_t *pcishpc_p, hpc_slot_state_t state)
-{
-	pcishpc_get_slot_state(pcishpc_p);
-
-	/* Check to see if the slot is already in this state. */
-	if (pcishpc_p->slot_state == state) {
-		pcishpc_debug("pcishpc_set_power_state() slot already in "
-			"this state");
-		return (DDI_SUCCESS);
-	}
-
-	if ((pcishpc_p->slot_state == HPC_SLOT_EMPTY) &&
-	    ((state == HPC_SLOT_CONNECTED) ||
-	    (state == HPC_SLOT_DISCONNECTED))) {
-		pcishpc_debug("pcishpc_set_power_state() slot in "
-		    "empty state");
-		return (DDI_FAILURE);
-	}
-
-	/* Set the Power LED to blink. */
-	(void) pcishpc_setled(pcishpc_p, HPC_POWER_LED, HPC_LED_BLINK);
-
-	/* Turn all other LEDS off. */
-	(void) pcishpc_setled(pcishpc_p, HPC_FAULT_LED, HPC_LED_OFF);
-	(void) pcishpc_setled(pcishpc_p, HPC_ATTN_LED, HPC_LED_OFF);
-	(void) pcishpc_setled(pcishpc_p, HPC_ACTIVE_LED, HPC_LED_OFF);
-
-	/* Set the slot state to the new slot state. */
-	pcishpc_p->slot_state = state;
-
-	/* Set the bus speed only if the bus segment is not running */
-	if (state == HPC_SLOT_CONNECTED) {
-		if (pcishpc_set_bus_speed(pcishpc_p) != DDI_SUCCESS)
-			return (DDI_FAILURE);
-
-		pcishpc_p->ctrl->numSlotsConn++;
-	} else {
-		if (--pcishpc_p->ctrl->numSlotsConn == 0)
-			pcishpc_p->ctrl->currBusSpeed = -1;
-	}
-
-	pcishpc_debug("pcishpc_set_power_state(): ctrl_p 0x%p, "
-	    "pcishpc_p 0x%p, slot state 0x%x,  current bus speed 0x%x, "
-	    "slots connected 0x%x\n", pcishpc_p->ctrl, pcishpc_p, state,
-	    pcishpc_p->ctrl->currBusSpeed, pcishpc_p->ctrl->numSlotsConn);
-
-	/* Mask or Unmask MRL Sensor SEER bit based on new slot state */
-	if (pcishpc_p->ctrl->has_mrl == B_TRUE) {
-		uint32_t reg;
-
-		reg = pcishpc_read_reg(pcishpc_p->ctrl,
-		    SHPC_LOGICAL_SLOT_REGS+pcishpc_p->slotNum);
-		reg = (state == HPC_SLOT_CONNECTED) ?
-		    (reg & ~SHPC_SLOT_MRL_SERR_MASK) :
-		    (reg | SHPC_SLOT_MRL_SERR_MASK);
-
-		pcishpc_write_reg(pcishpc_p->ctrl,
-		    SHPC_LOGICAL_SLOT_REGS+pcishpc_p->slotNum, reg);
-	}
-
-	/* Update the hardweare slot state. */
-	if (pcishpc_set_slot_state(pcishpc_p) != DDI_SUCCESS) {
-		pcishpc_debug("pcishpc_set_power_state() failed");
-		(void) pcishpc_setled(pcishpc_p, HPC_POWER_LED, HPC_LED_OFF);
-		pcishpc_get_slot_state(pcishpc_p);
-		return (DDI_FAILURE);
-	}
-
-	/* Turn the Power LED ON for a connected slot. */
-	if (state == HPC_SLOT_CONNECTED) {
-		(void) pcishpc_setled(pcishpc_p, HPC_POWER_LED, HPC_LED_ON);
-	}
-
-	/* Turn the Power LED OFF for a disconnected slot. */
-	if (state == HPC_SLOT_DISCONNECTED) {
-		(void) pcishpc_setled(pcishpc_p, HPC_POWER_LED, HPC_LED_OFF);
-	}
-
-	/* Turn all other LEDS off. */
-	(void) pcishpc_setled(pcishpc_p, HPC_FAULT_LED, HPC_LED_OFF);
-	(void) pcishpc_setled(pcishpc_p, HPC_ATTN_LED, HPC_LED_OFF);
-	(void) pcishpc_setled(pcishpc_p, HPC_ACTIVE_LED, HPC_LED_OFF);
-
-	pcishpc_debug("pcishpc_set_power_state() success!");
-
-	pcishpc_get_slot_state(pcishpc_p);
-
-	/* delay after powerON to let the device initialize itself */
-	delay(drv_usectohz(pcishpc_reset_delay));
-
-	return (DDI_SUCCESS);
-}
-
-/*
- * pcishpc_set_bus_speed()
- *
- * Set the bus speed and mode.
- */
-static int
-pcishpc_set_bus_speed(pcishpc_t *pcishpc_p)
-{
-	pcishpc_ctrl_t	*ctrl_p = pcishpc_p->ctrl;
-	int		curr_speed = ctrl_p->currBusSpeed;
-	int		speed = -1;
-	int		avail_slots;
-	uint32_t	status;
-
-	/* Make sure that the slot is in a correct state */
-	status = pcishpc_read_reg(ctrl_p,
-	    SHPC_LOGICAL_SLOT_REGS+pcishpc_p->slotNum);
-
-	/* Return failure if the slot is empty */
-	if ((status & SHPC_SLOT_CARD_EMPTY_MASK) ==
-	    SHPC_SLOT_CARD_EMPTY_MASK) {
-		pcishpc_debug("pcishpc_set_bus_speed() failed: "
-		    "the slot is empty.");
-		return (DDI_FAILURE);
-	}
-
-	/* Return failure if the slot is not in disabled state */
-	if ((status & SHPC_SLOT_STATE_MASK) != SHPC_SLOT_DISABLED) {
-		pcishpc_debug("pcishpc_set_bus_speed() failed: "
-		    "incorrect slot state.");
-		return (DDI_FAILURE);
-	}
-
-	/* Set the "power-only" mode for the slot */
-	if (pcishpc_issue_command(ctrl_p, ((1+pcishpc_p->slotNum)<<8) |
-	    SHPC_SLOT_POWER_ONLY) != DDI_SUCCESS) {
-		pcishpc_debug("pcishpc_set_bus_speed() failed to set "
-		    "the slot %d in the power-only mode", pcishpc_p->slotNum);
-		return (DDI_FAILURE);
-	}
-
-	/* Wait for power good */
-	delay(drv_usectohz(SHPC_POWER_GOOD_WAIT_TIME));
-
-	/* Make sure that the slot is in "power-only" state */
-	status = pcishpc_read_reg(ctrl_p,
-	    SHPC_LOGICAL_SLOT_REGS+pcishpc_p->slotNum);
-
-	if ((status & SHPC_SLOT_STATE_MASK) != SHPC_SLOT_POWER_ONLY) {
-		pcishpc_debug("pcishpc_set_bus_speed() "
-		    "power-only failed: incorrect slot state.");
-		return (DDI_FAILURE);
-	}
-
-	/*
-	 * Check if SHPC has available slots and select the highest
-	 * available bus speed for the slot.
-	 *
-	 * The bus speed codes are:
-	 * 100 - 133Mhz; <--+
-	 * 011 - 100Mhz; <--+   PCI-X
-	 * 010 - 66Mhz;  <--+
-	 *
-	 * 001 - 66Mhz;  <--+
-	 * 000 - 33Mhz   <--+   Conv PCI
-	 */
-	switch (status & SHPC_SLOT_PCIX_CAPABLE_MASK) {
-	case SHPC_SLOT_133MHZ_PCIX_CAPABLE:
-		avail_slots = (ctrl_p->shpc_slots_avail1_reg >>
-		    SHPC_AVAIL_133MHZ_PCIX_SPEED_SHIFT) & SHPC_AVAIL_SPEED_MASK;
-
-		if (((curr_speed == -1) && avail_slots) ||
-		    (curr_speed == SHPC_SBCR_133MHZ_PCIX_SPEED)) {
-			speed = SHPC_SBCR_133MHZ_PCIX_SPEED;
-			break;
-		}
-		/* FALLTHROUGH */
-	case SHPC_SLOT_100MHZ_PCIX_CAPABLE:
-		avail_slots = (ctrl_p->shpc_slots_avail1_reg >>
-		    SHPC_AVAIL_100MHZ_PCIX_SPEED_SHIFT) & SHPC_AVAIL_SPEED_MASK;
-
-		if (((curr_speed == -1) && avail_slots) ||
-		    (curr_speed == SHPC_SBCR_100MHZ_PCIX_SPEED)) {
-			speed = SHPC_SBCR_100MHZ_PCIX_SPEED;
-			break;
-		}
-		/* FALLTHROUGH */
-	case SHPC_SLOT_66MHZ_PCIX_CAPABLE:
-		avail_slots = (ctrl_p->shpc_slots_avail1_reg >>
-		    SHPC_AVAIL_66MHZ_PCIX_SPEED_SHIFT) & SHPC_AVAIL_SPEED_MASK;
-
-		if (((curr_speed == -1) && avail_slots) ||
-		    (curr_speed == SHPC_SBCR_66MHZ_PCIX_SPEED)) {
-			speed = SHPC_SBCR_66MHZ_PCIX_SPEED;
-			break;
-		}
-		/* FALLTHROUGH */
-	default:
-		avail_slots = (ctrl_p->shpc_slots_avail2_reg >>
-		    SHPC_AVAIL_66MHZ_CONV_SPEED_SHIFT) & SHPC_AVAIL_SPEED_MASK;
-
-		if ((status & SHPC_SLOT_66MHZ_CONV_CAPABLE) &&
-		    (((curr_speed == -1) && avail_slots) ||
-		    (curr_speed == SHPC_SBCR_66MHZ_CONV_SPEED))) {
-			speed = SHPC_SBCR_66MHZ_CONV_SPEED;
-		} else {
-			avail_slots = (ctrl_p->shpc_slots_avail1_reg >>
-			    SHPC_AVAIL_33MHZ_CONV_SPEED_SHIFT) &
-			    SHPC_AVAIL_SPEED_MASK;
-
-			if (((curr_speed == -1) && (avail_slots)) ||
-			    (curr_speed == SHPC_SBCR_33MHZ_CONV_SPEED)) {
-				speed = SHPC_SBCR_33MHZ_CONV_SPEED;
-			} else {
-				pcishpc_debug("pcishpc_set_bus_speed() "
-				    " failed to set the bus speed, slot# %d",
-				    pcishpc_p->slotNum);
-				return (DDI_FAILURE);
-			}
-		}
-		break;
-	}
-
-	/*
-	 * If the bus segment is already running, check to see the card
-	 * in the slot can support the current bus speed.
-	 */
-	if (curr_speed == speed) {
-		/*
-		 * Check to see there is any slot available for the current
-		 * bus speed. Otherwise, we need fail the current slot connect
-		 * request.
-		 */
-		return ((avail_slots <= ctrl_p->numSlotsConn) ?
-		    DDI_FAILURE : DDI_SUCCESS);
-	}
-
-	/* Set the bus speed */
-	if (pcishpc_issue_command(ctrl_p, SHPC_COMM_STS_SET_SPEED |
-	    speed) == DDI_FAILURE) {
-		pcishpc_debug("pcishpc_set_bus_speed() failed "
-		    "to set bus %d speed", pcishpc_p->slotNum);
-		return (DDI_FAILURE);
-	}
-
-	/* Check the current bus speed */
-	status = pcishpc_read_reg(ctrl_p, SHPC_PROF_IF_SBCR_REG) &
-	    SHPC_SBCR_SPEED_MASK;
-	if ((status & SHPC_SBCR_SPEED_MASK) != speed) {
-		pcishpc_debug("pcishpc_set_bus_speed() an incorrect "
-		    "bus speed, slot = 0x%x, speed = 0x%x",
-		    pcishpc_p->slotNum, status & SHPC_SBCR_SPEED_MASK);
-		return (DDI_FAILURE);
-	}
-
-
-	/* Save the current bus speed */
-	ctrl_p->currBusSpeed = speed;
-
-	return (DDI_SUCCESS);
-}
-
-/*
- * pcishpc_disconnect()
- *
- * Called by Hot Plug Services to disconnect a slot on the bus.
- */
-/*ARGSUSED*/
-static int
-pcishpc_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data,
-	uint_t flags)
-{
-	pcishpc_t *pcishpc_p;
-
-	pcishpc_debug("pcishpc_disconnect called()");
-
-	pcishpc_p = pcishpc_hpc_get_slot_state(slot_hdl);
-
-	if (!pcishpc_p) {
-		pcishpc_debug("pcishpc_disconnect() "
-			"Failed to find soft state for slot_hdl %x", slot_hdl);
-		return (HPC_ERR_FAILED);
-	}
-
-	mutex_enter(&pcishpc_p->ctrl->shpc_mutex);
-
-	if (pcishpc_set_power_state(pcishpc_p, HPC_SLOT_DISCONNECTED)
-					!= DDI_SUCCESS) {
-		pcishpc_debug("pcishpc_disconnect() failed");
-		goto cleanup;
-	}
-
-	mutex_exit(&pcishpc_p->ctrl->shpc_mutex);
-
-	pcishpc_debug("pcishpc_disconnect() success!");
-
-	return (HPC_SUCCESS);
-
-cleanup:
-	mutex_exit(&pcishpc_p->ctrl->shpc_mutex);
-	return (HPC_ERR_FAILED);
-}
-
-
-/*
- * pcishpc_pci_control()
- *
- * Called by Hot Plug Services to perform a attachment point specific
- * operation on a Hot Pluggable Standard PCI Slot.
- */
-/*ARGSUSED*/
-static int
-pcishpc_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request,
-		caddr_t arg)
-{
-	hpc_slot_state_t *hpc_slot_state;
-	hpc_board_type_t *hpc_board_type;
-	hpc_led_info_t	*hpc_led_info;
-	pcishpc_t		*pcishpc_p;
-	int ret = HPC_SUCCESS;
-
-	pcishpc_debug("pcishpc_pci_control called(Request %s)",
-		pcishpc_textrequest(request));
-
-	pcishpc_p = pcishpc_hpc_get_slot_state(slot_hdl);
-
-	if (!pcishpc_p) {
-		pcishpc_debug("pcishpc_pci_control() Error: "
-			"Failed to find soft state for slot_hdl %x", slot_hdl);
-		return (HPC_ERR_FAILED);
-	}
-
-	mutex_enter(&pcishpc_p->ctrl->shpc_mutex);
-
-	switch (request) {
-		case HPC_CTRL_GET_SLOT_STATE:
-			hpc_slot_state = (hpc_slot_state_t *)arg;
-			pcishpc_get_slot_state(pcishpc_p);
-			*hpc_slot_state = pcishpc_p->slot_state;
-			pcishpc_debug("pcishpc_pci_control() - "
-				"HPC_CTRL_GET_SLOT_STATE (state=%s)",
-				pcishpc_textslotstate(pcishpc_p->slot_state));
-			break;
-
-		case HPC_CTRL_GET_BOARD_TYPE:
-			hpc_board_type = (hpc_board_type_t *)arg;
-			pcishpc_debug("pcishpc_pci_control() - "
-					"HPC_CTRL_GET_BOARD_TYPE");
-			pcishpc_get_slot_state(pcishpc_p);
-			/*
-			 * The HPS framework does not know what board
-			 * type is plugged in.
-			 */
-			if (pcishpc_p->slot_state == HPC_SLOT_EMPTY)
-				*hpc_board_type = HPC_BOARD_UNKNOWN;
-			else
-				*hpc_board_type = HPC_BOARD_PCI_HOTPLUG;
-			break;
-
-		case HPC_CTRL_GET_LED_STATE:
-			hpc_led_info = (hpc_led_info_t *)arg;
-
-			pcishpc_get_slot_state(pcishpc_p);
-
-			switch (hpc_led_info->led) {
-				case HPC_FAULT_LED:
-					hpc_led_info->state =
-						pcishpc_p->fault_led_state;
-					pcishpc_debug("pcishpc_pci_control() - "
-						"GET_LED FAULT (state=%s)",
-						pcishpc_textledstate(
-							hpc_led_info->state));
-					break;
-
-				case HPC_POWER_LED:
-					hpc_led_info->state =
-						pcishpc_p->power_led_state;
-					pcishpc_debug("pcishpc_pci_control() - "
-						"GET_LED POWER (state=%s)",
-						pcishpc_textledstate(
-							hpc_led_info->state));
-					break;
-
-				case HPC_ATTN_LED:
-					hpc_led_info->state =
-						pcishpc_p->attn_led_state;
-					pcishpc_debug("pcishpc_pci_control() - "
-						"GET_LED ATTN(state = %s)",
-						pcishpc_textledstate(
-							hpc_led_info->state));
-					break;
-
-				case HPC_ACTIVE_LED:
-					hpc_led_info->state =
-						pcishpc_p->active_led_state;
-					pcishpc_debug("pcishpc_pci_control() - "
-						"GET_LED ACTIVE(state = %s)",
-						pcishpc_textledstate(
-							hpc_led_info->state));
-					break;
-
-				default:
-					pcishpc_debug("pcishpc_pci_control() "
-						"Error: GET_LED - "
-						"Invalid LED %x",
-							hpc_led_info->led);
-					ret = HPC_ERR_NOTSUPPORTED;
-					break;
-				}
-			break;
-
-		case HPC_CTRL_SET_LED_STATE:
-			hpc_led_info = (hpc_led_info_t *)arg;
-			switch (hpc_led_info->led) {
-				case HPC_ATTN_LED:
-					(void) pcishpc_setled(pcishpc_p,
-					    hpc_led_info->led,
-					    hpc_led_info->state);
-					break;
-				case HPC_POWER_LED:
-					pcishpc_debug("pcishpc_pci_control() "
-					    "Error: SET_LED - power LED");
-					ret = HPC_ERR_NOTSUPPORTED;
-					break;
-				case HPC_FAULT_LED:
-				case HPC_ACTIVE_LED:
-					break;
-				default:
-					pcishpc_debug("pcishpc_pci_control() "
-					    "Error: SET_LED - Unknown LED %x",
-					    hpc_led_info->led);
-					ret = HPC_ERR_NOTSUPPORTED;
-					break;
-				}
-			break;
-
-		case HPC_CTRL_DEV_UNCONFIG_FAILURE:
-		case HPC_CTRL_DEV_CONFIG_FAILURE:
-			pcishpc_debug("pcishpc_pci_control() Config/Unconfig "
-				"failed.");
-			(void) pcishpc_setled(pcishpc_p, HPC_ATTN_LED,
-				HPC_LED_BLINK);
-			break;
-
-		case HPC_CTRL_ENABLE_AUTOCFG:
-		case HPC_CTRL_DISABLE_AUTOCFG:
-		case HPC_CTRL_DISABLE_SLOT:
-		case HPC_CTRL_DEV_UNCONFIGURED:
-		case HPC_CTRL_ENABLE_SLOT:
-		case HPC_CTRL_DISABLE_ENUM:
-		case HPC_CTRL_DEV_UNCONFIG_START:
-		case HPC_CTRL_DEV_CONFIG_START:
-		case HPC_CTRL_DEV_CONFIGURED:
-			pcishpc_debug("pcishpc_pci_control() - %s",
-				pcishpc_textrequest(request));
-			break;
-
-		case HPC_CTRL_ENABLE_ENUM:
-		default:
-			pcishpc_debug("pcishpc_pci_control() - Error: "
-				"request (%d) NOT SUPPORTED", request);
-			ret = HPC_ERR_NOTSUPPORTED;
-			break;
-	}
-
-	mutex_exit(&pcishpc_p->ctrl->shpc_mutex);
-	return (ret);
-}
-
-
-/*
- * pcishpc_setled()
- *
- * Change the state of a slot's LED.
- */
-static int
-pcishpc_setled(pcishpc_t *pcishpc_p, hpc_led_t led, hpc_led_state_t state)
-{
-	switch (led) {
-		case HPC_FAULT_LED:
-			pcishpc_debug("pcishpc_setled() - HPC_FAULT_LED "
-				"(set %s)", pcishpc_textledstate(state));
-			pcishpc_p->fault_led_state = state;
-			break;
-
-		case HPC_POWER_LED:
-			pcishpc_debug("pcishpc_setled() - HPC_POWER_LED "
-				"(set %s)", pcishpc_textledstate(state));
-			pcishpc_p->power_led_state = state;
-			break;
-
-		case HPC_ATTN_LED:
-			pcishpc_debug("pcishpc_setled() - HPC_ATTN_LED "
-				"(set %s)", pcishpc_textledstate(state));
-			pcishpc_p->attn_led_state = state;
-			break;
-
-		case HPC_ACTIVE_LED:
-			pcishpc_debug("pcishpc_setled() - HPC_ACTIVE_LED "
-				"(set %s)", pcishpc_textledstate(state));
-			pcishpc_p->active_led_state = state;
-			break;
-	}
-
-	return (pcishpc_set_slot_state(pcishpc_p));
-}
-
-
-/*
- * pcishpc_set_slot_state()
- *
- * Updates the slot's state and leds.
- */
-static int
-pcishpc_set_slot_state(pcishpc_t *pcishpc_p)
-{
-	uint32_t reg;
-	uint32_t cmd_code;
-	hpc_slot_state_t slot_state;
-
-	reg = pcishpc_read_reg(pcishpc_p->ctrl,
-		SHPC_LOGICAL_SLOT_REGS+pcishpc_p->slotNum);
-
-	/* Default all states to unchanged. */
-	cmd_code = ((1+pcishpc_p->slotNum)<<8);
-
-	/* Has the slot state changed? */
-	if ((reg & SHPC_SLOT_CARD_EMPTY_MASK) == SHPC_SLOT_CARD_EMPTY_MASK)
-		slot_state = HPC_SLOT_EMPTY;
-	else
-		slot_state = pcishpc_slot_shpc_to_hpc(reg & 3);
-	if (pcishpc_p->slot_state != slot_state) {
-		pcishpc_debug("pcishpc_set_slot_state() Slot State changed");
-		/* Set the new slot state in the Slot operation command. */
-		cmd_code |= pcishpc_slot_hpc_to_shpc(pcishpc_p->slot_state);
-	}
-
-	/* Has the Power LED state changed? */
-	if (pcishpc_p->power_led_state != pcishpc_led_shpc_to_hpc((reg>>2)&3)) {
-		pcishpc_debug("pcishpc_set_slot_state() Power LED State "
-				"changed");
-		/* Set the new power led state in the Slot operation command. */
-		cmd_code |=
-			(pcishpc_led_hpc_to_shpc(pcishpc_p->power_led_state)
-					<< 2);
-	}
-
-	/* Has the Attn LED state changed? */
-	if (pcishpc_p->attn_led_state != pcishpc_led_shpc_to_hpc((reg>>4)&3)) {
-		pcishpc_debug("pcishpc_set_slot_state() Attn LED State "
-			"changed");
-		/* Set the new attn led state in the Slot operation command. */
-		cmd_code |= (pcishpc_led_hpc_to_shpc(pcishpc_p->attn_led_state)
-				<< 4);
-	}
-
-	return (pcishpc_issue_command(pcishpc_p->ctrl, cmd_code));
-}
-
-
-/*
- * pcishpc_wait_busy()
- *
- * Wait until the SHPC controller is not busy.
- */
-static int
-pcishpc_wait_busy(pcishpc_ctrl_t *ctrl_p)
-{
-	uint32_t	status;
-
-	/* Wait until SHPC controller is NOT busy */
-	/*CONSTCOND*/
-	while (1) {
-		status = pcishpc_read_reg(ctrl_p, SHPC_COMMAND_STATUS_REG);
-
-		/* Is there an MRL Sensor error? */
-		if ((status & SHPC_COMM_STS_ERR_MASK) ==
-		    SHPC_COMM_STS_ERR_MRL_OPEN) {
-			pcishpc_debug("pcishpc_wait_busy() ERROR: MRL Sensor "
-				"error");
-			break;
-		}
-
-		/* Is there an Invalid command error? */
-		if ((status & SHPC_COMM_STS_ERR_MASK) ==
-		    SHPC_COMM_STS_ERR_INVALID_COMMAND) {
-			pcishpc_debug("pcishpc_wait_busy() ERROR: Invalid "
-				"command error");
-			break;
-		}
-
-		/* Is there an Invalid Speed/Mode error? */
-		if ((status & SHPC_COMM_STS_ERR_MASK) ==
-		    SHPC_COMM_STS_ERR_INVALID_SPEED) {
-			pcishpc_debug("pcishpc_wait_busy() ERROR: Invalid "
-				"Speed/Mode error");
-			break;
-		}
-
-		/* Is the SHPC controller not BUSY? */
-		if (!(status & SHPC_COMM_STS_CTRL_BUSY)) {
-			/* Return Success. */
-			return (DDI_SUCCESS);
-		}
-
-		pcishpc_debug("pcishpc_wait_busy() SHPC controller busy. "
-			"Waiting");
-
-		/* Wait before polling the status register again. */
-		delay(drv_usectohz(SHPC_COMMAND_WAIT_TIME));
-	}
-
-	return (DDI_FAILURE);
-}
-
-
-/*
- * pcishpc_issue_command()
- *
- * Sends a command to the SHPC controller.
- */
-static int
-pcishpc_issue_command(pcishpc_ctrl_t *ctrl_p, uint32_t cmd_code)
-{
-	int	retCode;
-
-	pcishpc_debug("pcishpc_issue_command() cmd_code=%02x", cmd_code);
-
-	mutex_enter(&ctrl_p->shpc_intr_mutex);
-
-	ctrl_p->command_complete = B_FALSE;
-
-	/* Write the command to the SHPC controller. */
-	pcishpc_write_reg(ctrl_p, SHPC_COMMAND_STATUS_REG, cmd_code);
-
-	while (ctrl_p->command_complete == B_FALSE)
-		cv_wait(&ctrl_p->cmd_comp_cv, &ctrl_p->shpc_intr_mutex);
-
-	/* Wait until the SHPC controller processes the command. */
-	retCode = pcishpc_wait_busy(ctrl_p);
-
-	/* Make sure the command completed. */
-	if (retCode == DDI_SUCCESS) {
-		/* Did the command fail to generate the command complete IRQ? */
-		if (ctrl_p->command_complete != B_TRUE) {
-			pcishpc_debug("pcishpc_issue_command() Failed on "
-				"generate cmd complete IRQ");
-			retCode = DDI_FAILURE;
-		}
-	}
-
-	mutex_exit(&ctrl_p->shpc_intr_mutex);
-
-	if (retCode == DDI_FAILURE)
-		pcishpc_debug("pcishpc_issue_command() Failed on cmd_code=%02x",
-				cmd_code);
-	else
-		pcishpc_debug("pcishpc_issue_command() Success on "
-			"cmd_code=%02x", cmd_code);
-
-	return (retCode);
-}
-
-/*
- * pcishpc_led_shpc_to_hpc()
- *
- * Convert from SHPC indicator status to HPC indicator status.
- */
-static int
-pcishpc_led_shpc_to_hpc(int state)
-{
-	switch (state) {
-		case 1:	/* SHPC On bits b01 */
-			return (HPC_LED_ON);
-		case 2:	/* SHPC Blink bits b10 */
-			return (HPC_LED_BLINK);
-		case 3:	/* SHPC Off bits b11 */
-			return (HPC_LED_OFF);
-	}
-
-	return (HPC_LED_OFF);
-}
-
-
-/*
- * pcishpc_led_hpc_to_shpc()
- *
- * Convert from HPC indicator status to SHPC indicator status.
- */
-static int
-pcishpc_led_hpc_to_shpc(int state)
-{
-	switch (state) {
-		case HPC_LED_ON:
-			return (1); /* SHPC On bits b01 */
-		case HPC_LED_BLINK:
-			return (2); /* SHPC Blink bits b10 */
-		case HPC_LED_OFF:
-			return (3); /* SHPC Off bits b11 */
-	}
-
-	return (3); /* SHPC Off bits b11 */
-}
-
-/*
- * pcishpc_slot_shpc_to_hpc()
- *
- * Convert from SHPC slot state to HPC slot state.
- */
-static int
-pcishpc_slot_shpc_to_hpc(int state)
-{
-	switch (state) {
-		case 0: /* SHPC Reserved */
-			return (HPC_SLOT_EMPTY);
-
-		case 1: /* SHPC Powered Only */
-			return (HPC_SLOT_UNKNOWN);
-
-		case 2: /* SHPC Enabled */
-			return (HPC_SLOT_CONNECTED);
-
-		case 3: /* SHPC Disabled */
-			return (HPC_SLOT_DISCONNECTED);
-	}
-
-	/* Unknown slot state. */
-	return (HPC_SLOT_UNKNOWN);
-}
-
-
-/*
- * pcishpc_slot_hpc_to_shpc()
- *
- * Convert from HPC slot state to SHPC slot state.
- */
-static int
-pcishpc_slot_hpc_to_shpc(int state)
-{
-	switch (state) {
-		case HPC_SLOT_EMPTY:
-			return (0); /* SHPC Reserved */
-
-		case HPC_SLOT_UNKNOWN:
-			return (1); /* SHPC Powered Only */
-
-		case HPC_SLOT_CONNECTED:
-			return (2); /* SHPC Enabled */
-
-		case HPC_SLOT_DISCONNECTED:
-			return (3); /* SHPC Disabled */
-	}
-
-	/* Known slot state is reserved. */
-	return (0);
-}
-
-
-/*
- * pcishpc_get_slot_state()
- *
- * Get the state of the slot.
- */
-static void
-pcishpc_get_slot_state(pcishpc_t *pcishpc_p)
-{
-	uint32_t reg;
-
-	/* Read the logical slot register for this Slot. */
-	reg = pcishpc_read_reg(pcishpc_p->ctrl,
-		SHPC_LOGICAL_SLOT_REGS+pcishpc_p->slotNum);
-
-	/* Convert from the SHPC slot state to the HPC slot state. */
-	if ((reg & SHPC_SLOT_CARD_EMPTY_MASK) == SHPC_SLOT_CARD_EMPTY_MASK)
-		pcishpc_p->slot_state = HPC_SLOT_EMPTY;
-	else
-		pcishpc_p->slot_state = pcishpc_slot_shpc_to_hpc(reg & 3);
-
-	/* Convert from the SHPC Power LED state to the HPC Power LED state. */
-	pcishpc_p->power_led_state  = pcishpc_led_shpc_to_hpc((reg>>2)&3);
-
-	/* Convert from the SHPC Attn LED state to the HPC Attn LED state. */
-	pcishpc_p->attn_led_state	= pcishpc_led_shpc_to_hpc((reg>>4)&3);
-
-	/* We don't have a fault LED so just default it to OFF. */
-	pcishpc_p->fault_led_state  = HPC_LED_OFF;
-
-	/* We don't have an active LED so just default it to OFF. */
-	pcishpc_p->active_led_state = HPC_LED_OFF;
-}
-
-/*
- * pcishpc_textledstate()
- *
- * Convert the led state into a text message.
- */
-static char *
-pcishpc_textledstate(hpc_led_state_t state)
-{
-	/* Convert an HPC led state into a textual string. */
-	switch (state) {
-		case HPC_LED_OFF:
-			return ("off");
-
-		case HPC_LED_ON:
-			return ("on");
-
-		case HPC_LED_BLINK:
-			return ("blink");
-	}
-	return ("unknown");
-}
-
-/*
- * pcishpc_textrequest()
- *
- * Convert the request into a text message.
- */
-static char *
-pcishpc_textrequest(int request)
-{
-	/* Convert an HPC request into a textual string. */
-	switch (request) {
-		case HPC_CTRL_GET_LED_STATE:
-			return ("HPC_CTRL_GET_LED_STATE");
-		case HPC_CTRL_SET_LED_STATE:
-			return ("HPC_CTRL_SET_LED_STATE");
-		case HPC_CTRL_GET_SLOT_STATE:
-			return ("HPC_CTRL_GET_SLOT_STATE");
-		case HPC_CTRL_DEV_CONFIGURED:
-			return ("HPC_CTRL_DEV_CONFIGURED");
-		case HPC_CTRL_DEV_UNCONFIGURED:
-			return ("HPC_CTRL_DEV_UNCONFIGURED");
-		case HPC_CTRL_GET_BOARD_TYPE:
-			return ("HPC_CTRL_GET_BOARD_TYPE");
-		case HPC_CTRL_DISABLE_AUTOCFG:
-			return ("HPC_CTRL_DISABLE_AUTOCFG");
-		case HPC_CTRL_ENABLE_AUTOCFG:
-			return ("HPC_CTRL_ENABLE_AUTOCFG");
-		case HPC_CTRL_DISABLE_SLOT:
-			return ("HPC_CTRL_DISABLE_SLOT");
-		case HPC_CTRL_ENABLE_SLOT:
-			return ("HPC_CTRL_ENABLE_SLOT");
-		case HPC_CTRL_DISABLE_ENUM:
-			return ("HPC_CTRL_DISABLE_ENUM");
-		case HPC_CTRL_ENABLE_ENUM:
-			return ("HPC_CTRL_ENABLE_ENUM");
-		case HPC_CTRL_DEV_CONFIG_FAILURE:
-			return ("HPC_CTRL_DEV_CONFIG_FAILURE");
-		case HPC_CTRL_DEV_UNCONFIG_FAILURE:
-			return ("HPC_CTRL_DEV_UNCONFIG_FAILURE");
-		case HPC_CTRL_DEV_CONFIG_START:
-			return ("HPC_CTRL_DEV_CONFIG_START");
-		case HPC_CTRL_DEV_UNCONFIG_START:
-			return ("HPC_CTRL_DEV_UNCONFIG_START");
-	}
-	return ("Unknown");
-}
-
-/*
- * pcishpc_textslotstate()
- *
- * Convert the request into a text message.
- */
-static char *
-pcishpc_textslotstate(hpc_slot_state_t state)
-{
-	/* Convert an HPC slot state into a textual string. */
-	switch (state) {
-		case HPC_SLOT_EMPTY:
-			return ("HPC_SLOT_EMPTY");
-		case HPC_SLOT_DISCONNECTED:
-			return ("HPC_SLOT_DISCONNECTED");
-		case HPC_SLOT_CONNECTED:
-			return ("HPC_SLOT_CONNECTED");
-		case HPC_SLOT_UNKNOWN:
-			return ("HPC_SLOT_UNKNOWN");
-	}
-	return ("Unknown");
-}
-
-
-/*
- * pcishpc_write_reg()
- *
- * Write to a SHPC controller register.
- */
-static void
-pcishpc_write_reg(pcishpc_ctrl_t *ctrl_p, int reg, uint32_t data)
-{
-	/* Setup the SHPC dword select register. */
-	pci_config_put8(ctrl_p->shpc_config_hdl,
-		ctrl_p->shpc_dword_select, (uint8_t)reg);
-
-	/* Read back the SHPC dword select register and verify. */
-	if (pci_config_get8(ctrl_p->shpc_config_hdl,
-		ctrl_p->shpc_dword_select) != (uint8_t)reg) {
-		pcishpc_debug("pcishpc_write_reg() - Failed writing "
-				"DWORD select reg");
-		return;
-	}
-
-	/* Write to the SHPC dword data register. */
-	pci_config_put32(ctrl_p->shpc_config_hdl,
-		ctrl_p->shpc_dword_data_reg, data);
-
-	/*
-	 * Issue a read of the VendorID/DeviceID just to force the previous
-	 * write to complete. This is probably not necessary, but it does
-	 * help enforce ordering if there is an issue.
-	 */
-	(void) pci_config_get16(ctrl_p->shpc_config_hdl, PCI_CONF_VENID);
-}
-
-
-/*
- * pcishpc_read_reg()
- *
- * Read from a SHPC controller register.
- */
-static uint32_t
-pcishpc_read_reg(pcishpc_ctrl_t *ctrl_p, int reg)
-{
-	/* Setup the SHPC dword select register. */
-	pci_config_put8(ctrl_p->shpc_config_hdl,
-		ctrl_p->shpc_dword_select, (uint8_t)reg);
-
-	/* Read back the SHPC dword select register and verify. */
-	if (pci_config_get8(ctrl_p->shpc_config_hdl,
-		ctrl_p->shpc_dword_select) != (uint8_t)reg) {
-		pcishpc_debug("pcishpc_read_reg() - Failed writing DWORD "
-			"select reg");
-		return (0xFFFFFFFF);
-	}
-
-	/* Read from the SHPC dword data register. */
-	return (pci_config_get32(ctrl_p->shpc_config_hdl,
-		ctrl_p->shpc_dword_data_reg));
-}
-
-
-/*
- * pcishpc_debug()
- *
- * Controls debug output if enabled.
- */
-static void
-pcishpc_debug(char *fmt, ...)
-{
-	va_list ap;
-
-	if (pcishpc_debug_enabled) {
-		va_start(ap, fmt);
-		vcmn_err(CE_WARN, fmt, ap);
-		va_end(ap);
-	}
-}
-
-
-/*
- * pcishpc_dump_regs()
- *
- * Dumps all of the SHPC controller registers.
- */
-static void
-pcishpc_dump_regs(pcishpc_ctrl_t *ctrl_p)
-{
-	int slot, numSlots;
-	uint32_t reg;
-	char *state;
-
-	cmn_err(CE_WARN, "pcishpc_dump_regs() called:");
-	cmn_err(CE_WARN, "================================================"
-			"==========");
-
-	cmn_err(CE_WARN, "SHPC Base Offset				"
-		": 0x%08x", pcishpc_read_reg(ctrl_p, SHPC_BASE_OFFSET_REG));
-
-	reg = pcishpc_read_reg(ctrl_p, SHPC_SLOTS_AVAIL_I_REG);
-
-	cmn_err(CE_WARN, "Number of PCIX slots avail (33 Mhz)		 : %d",
-		(reg & 31));
-
-	cmn_err(CE_WARN, "Number of PCIX slots avail (66 Mhz)		 : %d",
-		((reg>>8) & 31));
-
-	cmn_err(CE_WARN, "Number of PCIX slots avail (100 Mhz)		: %d",
-		((reg>>16) & 31));
-
-	cmn_err(CE_WARN, "Number of PCIX slots avail (133 Mhz)		: %d",
-		((reg>>24) & 31));
-
-	reg = pcishpc_read_reg(ctrl_p, SHPC_SLOTS_AVAIL_II_REG);
-
-	cmn_err(CE_WARN, "Number of conventional PCI slots (66 Mhz) : %d",
-		(reg & 31));
-
-	reg = pcishpc_read_reg(ctrl_p, SHPC_SLOT_CONFIGURATION_REG);
-
-	numSlots = (reg & 31);
-
-	cmn_err(CE_WARN, "Number of Slots connected to this port	 : %d",
-			numSlots);
-
-	cmn_err(CE_WARN, "PCI Device # for First HotPlug Slot		 : %d",
-		((reg>>8) & 31));
-
-	cmn_err(CE_WARN, "Physical Slot # for First PCI Device #	 : %d",
-		((reg>>16) & 0x7ff));
-
-	cmn_err(CE_WARN, "Physical Slot Number Up/Down			"
-			": %d", ((reg>>29) & 0x1));
-
-	cmn_err(CE_WARN, "MRL Sensor Implemented			"
-			": %s", (reg & SHPC_SLOT_CONFIG_MRL_SENSOR) ? "Yes" :
-				"No");
-
-	cmn_err(CE_WARN, "Attention Button Implemented			"
-			": %s", (reg & SHPC_SLOT_CONFIG_ATTN_BUTTON) ? "Yes" :
-				"No");
-
-	reg = pcishpc_read_reg(ctrl_p, SHPC_PROF_IF_SBCR_REG);
-
-	switch (reg & 7) {
-		case 0:
-			state = "33Mhz Conventional PCI";
-			break;
-		case 1:
-			state = "66Mhz Conventional PCI";
-			break;
-		case 2:
-			state = "66Mhz PCI-X";
-			break;
-		case 3:
-			state = "100Mhz PCI-X";
-			break;
-		case 4:
-			state = "133Mhz PCI-X";
-			break;
-		default:
-			state = "Reserved (Error)";
-			break;
-	}
-
-	cmn_err(CE_WARN, "Current Port Operation Mode		"
-		": %s", state);
-
-	cmn_err(CE_WARN, "SHPC Interrupt Message Number		"
-			": %d", ((reg>>16) &31));
-
-	cmn_err(CE_WARN, "SHPC Programming Interface		"
-			": %d", ((reg>>24) & 0xff));
-
-	reg = pcishpc_read_reg(ctrl_p, SHPC_COMMAND_STATUS_REG);
-
-	cmn_err(CE_WARN, "SHPC Command Code			"
-			": %d", (reg & 0xff));
-
-	cmn_err(CE_WARN, "SHPC Target Slot			"
-			": %d", ((reg>>8) & 31));
-
-	cmn_err(CE_WARN, "SHPC Controller Busy			"
-			": %s", ((reg>>16) & 1) ? "Yes" : "No");
-
-	cmn_err(CE_WARN, "SHPC Controller Err: MRL Sensor		"
-			": %s", ((reg>>17) & 1) ? "Yes" : "No");
-
-	cmn_err(CE_WARN, "SHPC Controller Err: Invalid Command		: %s",
-		((reg>>18) & 1) ? "Yes" : "No");
-
-	cmn_err(CE_WARN, "SHPC Controller Err: Invalid Speed/Mode	: %s",
-		((reg>>19) & 1) ? "Yes" : "No");
-
-	reg = pcishpc_read_reg(ctrl_p, SHPC_IRQ_LOCATOR_REG);
-
-	cmn_err(CE_WARN, "Command Completion Interrupt Pending		: %s",
-		(reg & SHPC_IRQ_CMD_COMPLETE) ? "Yes" : "No");
-
-	for (slot = 0; slot < numSlots; slot++) {
-		cmn_err(CE_WARN, "Slot %d Interrupt Pending		"
-			": %s", slot+1,
-			(reg & (SHPC_IRQ_SLOT_N_PENDING<<slot)) ? "Yes" : "No");
-	}
-
-	reg = pcishpc_read_reg(ctrl_p, SHPC_SERR_LOCATOR_REG);
-
-	cmn_err(CE_WARN, "Arbiter SERR Pending				"
-			": %s", (reg & SHPC_IRQ_SERR_ARBITER_PENDING) ?
-				"Yes" : "No");
-
-	for (slot = 0; slot < numSlots; slot++) {
-		cmn_err(CE_WARN, "Slot %d SERR Pending			"
-				": %s", slot+1, (reg &
-					(SHPC_IRQ_SERR_SLOT_N_PENDING<<slot)) ?
-						"Yes" : "No");
-	}
-
-	reg = pcishpc_read_reg(ctrl_p, SHPC_CTRL_SERR_INT_REG);
-
-	cmn_err(CE_WARN, "Global Interrupt Mask				"
-			": %s", (reg & SHPC_SERR_INT_GLOBAL_IRQ_MASK) ?
-				"Yes" : "No");
-
-	cmn_err(CE_WARN, "Global SERR Mask				"
-			": %s", (reg & SHPC_SERR_INT_GLOBAL_SERR_MASK) ?
-				"Yes" : "No");
-
-	cmn_err(CE_WARN, "Command Completion Interrupt Mask		"
-			": %s", (reg & SHPC_SERR_INT_CMD_COMPLETE_MASK) ?
-				"Yes" : "No");
-
-	cmn_err(CE_WARN, "Arbiter SERR Mask				"
-			": %s", (reg & SHPC_SERR_INT_ARBITER_SERR_MASK) ?
-				"Yes" : "No");
-
-	cmn_err(CE_WARN, "Command Completion Detected			"
-			": %s", (reg & SHPC_SERR_INT_CMD_COMPLETE_IRQ) ?
-				"Yes" : "No");
-
-	cmn_err(CE_WARN, "Arbiter Timeout Detected			"
-			": %s", (reg & SHPC_SERR_INT_ARBITER_IRQ) ?
-				"Yes" : "No");
-
-
-	for (slot = 0; slot < numSlots; slot++) {
-		cmn_err(CE_WARN, "Logical Slot %d Registers:", slot+1);
-		cmn_err(CE_WARN, "------------------------------------");
-
-		reg = pcishpc_read_reg(ctrl_p, SHPC_LOGICAL_SLOT_REGS+slot);
-
-		cmn_err(CE_WARN, "Slot %d state				"
-				": %s", slot+1,
-				pcishpc_textslotstate(pcishpc_slot_shpc_to_hpc(
-					(reg & 3))));
-
-		cmn_err(CE_WARN, "Slot %d Power Indicator State		"
-				": %s", slot+1,
-				pcishpc_textledstate(pcishpc_led_shpc_to_hpc(
-					(reg>>2) &3)));
-
-		cmn_err(CE_WARN, "Slot %d Attention Indicator State	"
-			": %s", slot+1,
-			pcishpc_textledstate(pcishpc_led_shpc_to_hpc(
-					(reg>>4)&3)));
-
-		cmn_err(CE_WARN, "Slot %d Power Fault			"
-			": %s", slot+1, ((reg>>6)&1) ? "Fault Detected" :
-				"No Fault");
-		cmn_err(CE_WARN, "Slot %d Attention Button		"
-			": %s", slot+1, ((reg>>7)&1) ? "Depressed" :
-				"Not Depressed");
-		cmn_err(CE_WARN, "Slot %d MRL Sensor			"
-				": %s", slot+1, ((reg>>8)&1) ? "Not Closed" :
-					"Closed");
-		cmn_err(CE_WARN, "Slot %d 66mhz Capable			"
-			": %s", slot+1, ((reg>>9)&1) ? "66mhz" : "33mgz");
-
-		switch ((reg>>10)&3) {
-			case 0:
-				state = "Card Present 7.5W";
-				break;
-			case 1:
-				state = "Card Present 15W";
-				break;
-			case 2:
-				state = "Card Present 25W";
-				break;
-			case 3:
-				state = "Slot Empty";
-				break;
-		}
-
-		cmn_err(CE_WARN, "Slot %d PRSNT1#/PRSNT2#		"
-				": %s", slot+1, state);
-
-		switch ((reg>>12)&3) {
-			case 0:
-				state = "Non PCI-X";
-				break;
-			case 1:
-				state = "66mhz PCI-X";
-				break;
-			case 2:
-				state = "Reserved";
-				break;
-			case 3:
-				state = "133mhz PCI-X";
-				break;
-		}
-
-		cmn_err(CE_WARN, "Slot %d Card Presence Change Detected	  : %s",
-			slot+1, (reg & SHPC_SLOT_PRESENCE_DETECTED) ? "Yes" :
-				"No");
-		cmn_err(CE_WARN, "Slot %d Isolated Power Fault Detected	  : %s",
-			slot+1, (reg & SHPC_SLOT_ISO_PWR_DETECTED) ? "Yes" :
-				"No");
-		cmn_err(CE_WARN, "Slot %d Attention Button Press Detected"
-				": %s", slot+1,
-				(reg & SHPC_SLOT_ATTN_DETECTED) ? "Yes" : "No");
-		cmn_err(CE_WARN, "Slot %d MRL Sensor Change Detected	"
-			": %s", slot+1,
-			(reg & SHPC_SLOT_MRL_DETECTED) ? "Yes" : "No");
-		cmn_err(CE_WARN, "Slot %d Connected Power Fault Detected"
-			": %s", slot+1,
-			(reg & SHPC_SLOT_POWER_DETECTED) ? "Yes" : "No");
-
-		cmn_err(CE_WARN, "Slot %d Card Presence IRQ Masked	"
-			": %s", slot+1,
-			(reg & SHPC_SLOT_PRESENCE_MASK) ? "Yes" : "No");
-		cmn_err(CE_WARN, "Slot %d Isolated Power Fault IRQ Masked"
-			": %s", slot+1,
-			(reg & SHPC_SLOT_ISO_PWR_MASK) ? "Yes" : "No");
-		cmn_err(CE_WARN, "Slot %d Attention Button IRQ Masked	"
-			": %s", slot+1, (reg & SHPC_SLOT_ATTN_MASK) ? "Yes" :
-				"No");
-		cmn_err(CE_WARN, "Slot %d MRL Sensor IRQ Masked		"
-			": %s", slot+1,
-			(reg & SHPC_SLOT_MRL_MASK) ? "Yes" : "No");
-		cmn_err(CE_WARN, "Slot %d Connected Power Fault IRQ Masked"
-			" : %s", slot+1,
-			(reg & SHPC_SLOT_POWER_MASK) ? "Yes" : "No");
-		cmn_err(CE_WARN, "Slot %d MRL Sensor SERR Masked "
-			": %s", slot+1,
-			(reg & SHPC_SLOT_MRL_SERR_MASK) ? "Yes" : "No");
-		cmn_err(CE_WARN, "Slot %d Connected Power Fault SERR Masked :"
-			"%s", slot+1,
-			(reg & SHPC_SLOT_POWER_SERR_MASK) ? "Yes" : "No");
-	}
-}
-
-static void
-pcishpc_attn_btn_handler(pcishpc_t *pcishpc_p)
-{
-	hpc_led_state_t power_led_state;
-	callb_cpr_t cprinfo;
-
-	pcishpc_debug("pcishpc_attn_btn_handler: thread started\n");
-
-	CALLB_CPR_INIT(&cprinfo, &pcishpc_p->ctrl->shpc_mutex,
-	    callb_generic_cpr, "pcishpc_attn_btn_handler");
-
-	mutex_enter(&pcishpc_p->ctrl->shpc_mutex);
-
-	/* wait for ATTN button event */
-	cv_wait(&pcishpc_p->attn_btn_cv, &pcishpc_p->ctrl->shpc_mutex);
-
-	while (pcishpc_p->attn_btn_thread_exit == B_FALSE) {
-		if (pcishpc_p->attn_btn_pending == B_TRUE) {
-			/* get the current state of power LED */
-			power_led_state = pcishpc_p->power_led_state;
-
-			/* Blink the Power LED while we wait for 5 seconds */
-			(void) pcishpc_setled(pcishpc_p, HPC_POWER_LED,
-			    HPC_LED_BLINK);
-
-			/* wait for 5 seconds before taking any action */
-			if (cv_timedwait(&pcishpc_p->attn_btn_cv,
-			    &pcishpc_p->ctrl->shpc_mutex,
-			    ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) {
-				/*
-				 * It is a time out;
-				 * make sure the ATTN pending flag is
-				 * still ON before sending the event
-				 * to HPS framework.
-				 */
-				if (pcishpc_p->attn_btn_pending == B_TRUE) {
-					/*
-					 * send the ATTN button event
-					 * to HPS framework
-					 */
-					pcishpc_p->attn_btn_pending = B_FALSE;
-					(void) hpc_slot_event_notify(
-					    pcishpc_p->slot_handle,
-					    HPC_EVENT_SLOT_ATTN,
-					    HPC_EVENT_NORMAL);
-				}
-			}
-
-			/* restore the power LED state ??? XXX */
-			(void) pcishpc_setled(pcishpc_p, HPC_POWER_LED,
-			    power_led_state);
-			continue;
-		}
-
-		/* wait for another ATTN button event */
-		cv_wait(&pcishpc_p->attn_btn_cv, &pcishpc_p->ctrl->shpc_mutex);
-	}
-
-	pcishpc_debug("pcishpc_attn_btn_handler: thread exit\n");
-	cv_signal(&pcishpc_p->attn_btn_cv);
-	CALLB_CPR_EXIT(&cprinfo);
-	thread_exit();
-}
-
-/*
- * setup slot name/slot-number info.
- */
-static void
-pcishpc_set_slot_name(pcishpc_ctrl_t *ctrl_p, int slot)
-{
-	pcishpc_t *p = ctrl_p->slots[slot];
-	uchar_t *slotname_data;
-	int *slotnum;
-	uint_t count;
-	int len;
-	uchar_t *s;
-	uint32_t bit_mask;
-	int pci_id_cnt, pci_id_bit;
-	int slots_before, found;
-	int invalid_slotnum = 0;
-
-	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->shpc_dip,
-		DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
-		DDI_PROP_SUCCESS) {
-		p->phy_slot_num = slotnum[0];
-		ddi_prop_free(slotnum);
-	} else {
-		if (ctrl_p->deviceIncreases)
-			p->phy_slot_num = ctrl_p->physStart + slot;
-		else
-			p->phy_slot_num = ctrl_p->physStart - slot;
-
-		if ((ndi_prop_update_int(DDI_DEV_T_NONE, ctrl_p->shpc_dip,
-			"physical-slot#", p->phy_slot_num)) != DDI_SUCCESS) {
-			pcishpc_debug("pcishpc_set_slot_name(): failed to "
-				"create phyical-slot#%d", p->phy_slot_num);
-			}
-	}
-
-	if (!p->phy_slot_num) { /* platform may not have initialized it */
-		p->phy_slot_num = pci_config_get8(ctrl_p->shpc_config_hdl,
-				PCI_BCNF_SECBUS);
-		invalid_slotnum = 1;
-	}
-
-	/*
-	 * construct the slot_name:
-	 * 	if "slot-names" property exists then use that name
-	 *	else if valid slot number exists then it is "pci<slot-num>".
-	 *	else it will be "pci<sec-bus-number>dev<dev-number>"
-	 */
-	if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->shpc_dip, DDI_PROP_DONTPASS,
-		"slot-names", (caddr_t)&slotname_data,
-		&len) == DDI_PROP_SUCCESS) {
-
-		bit_mask = slotname_data[3] | (slotname_data[2] << 8) |
-		    (slotname_data[1] << 16) | (slotname_data[0] << 24);
-
-		pci_id_bit = 1;
-		pci_id_cnt = slots_before = found = 0;
-
-		/*
-		 * Walk the bit mask until we find the bit that corresponds
-		 * to our slots device number.  We count how many bits
-		 * we find before we find our slot's bit.
-		 */
-		while (!found && (pci_id_cnt < 32)) {
-
-			while (p->deviceNum != pci_id_cnt) {
-
-				/*
-				 * Find the next bit set.
-				 */
-				while (!(bit_mask & pci_id_bit) &&
-				    (pci_id_cnt < 32)) {
-					pci_id_bit = pci_id_bit << 1;
-					pci_id_cnt++;
-				}
-
-				if (p->deviceNum != pci_id_cnt)
-					slots_before++;
-				else
-					found = 1;
-			}
-		}
-
-		if (pci_id_cnt < 32) {
-
-			/*
-			 * Set ptr to first string.
-			 */
-			s = slotname_data + 4;
-
-			/*
-			 * Increment past all the strings for the slots
-			 * before ours.
-			 */
-			while (slots_before) {
-				while (*s != NULL)
-					s++;
-				s++;
-				slots_before--;
-			}
-
-			(void) sprintf(p->slot_info.pci_slot_name, (char *)s);
-
-			kmem_free(slotname_data, len);
-			return;
-		}
-
-		/* slot-names entry not found */
-		pcishpc_debug("pcishpc_set_slot_name(): "
-			"No slot-names entry found for slot #%d",
-			p->phy_slot_num);
-		kmem_free(slotname_data, len);
-	}
-
-	if (invalid_slotnum)
-	    (void) sprintf(p->slot_info.pci_slot_name, "pci%d",
-		p->deviceNum);
-	else
-	    (void) sprintf(p->slot_info.pci_slot_name, "pci%d",
-		p->phy_slot_num);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/pciex/hotplug/pcie_hp.c	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,1300 @@
+/*
+ * 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 file contains the common hotplug code that is used by Standard
+ * PCIe and PCI HotPlug Controller code.
+ *
+ * NOTE: This file is compiled and delivered through misc/pcie module.
+ */
+
+#include <sys/types.h>
+#include <sys/conf.h>
+#include <sys/kmem.h>
+#include <sys/debug.h>
+#include <sys/vtrace.h>
+#include <sys/autoconf.h>
+#include <sys/varargs.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/time.h>
+#include <sys/note.h>
+#include <sys/callb.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/sysevent.h>
+#include <sys/sysevent/eventdefs.h>
+#include <sys/sysevent/dr.h>
+#include <sys/pci_impl.h>
+#include <sys/pci_cap.h>
+#include <sys/hotplug/pci/pcicfg.h>
+#include <sys/hotplug/pci/pcie_hp.h>
+#include <sys/hotplug/pci/pciehpc.h>
+#include <sys/hotplug/pci/pcishpc.h>
+#include <io/pciex/pcieb.h>
+
+/* Local functions prototype */
+static int pcie_hp_list_occupants(dev_info_t *dip, void *arg);
+static int pcie_hp_register_port(dev_info_t *dip, dev_info_t *pdip,
+    char *cn_name);
+static int pcie_hp_register_ports_for_dev(dev_info_t *dip, int device_num);
+static int pcie_hp_unregister_ports_cb(ddi_hp_cn_info_t *info, void *arg);
+static int pcie_hp_get_port_state(ddi_hp_cn_info_t *info, void *arg);
+static int pcie_hp_match_dev_func(dev_info_t *dip, void *hdl);
+static boolean_t pcie_hp_match_dev(dev_info_t *dip, int dev_num);
+static int pcie_hp_get_df_from_port_name(char *cn_name, int *dev_num,
+    int *func_num);
+static int pcie_hp_create_port_name_num(dev_info_t *dip,
+    ddi_hp_cn_info_t *cn_info);
+static int pcie_hp_check_hardware_existence(dev_info_t *dip, int dev_num,
+    int func_num);
+
+/*
+ * Global functions (called by other drivers/modules)
+ */
+
+/*
+ * return description text for led state
+ */
+char *
+pcie_led_state_text(pcie_hp_led_state_t state)
+{
+	switch (state) {
+	case PCIE_HP_LED_ON:
+		return (PCIEHPC_PROP_VALUE_ON);
+	case PCIE_HP_LED_OFF:
+		return (PCIEHPC_PROP_VALUE_OFF);
+	case PCIE_HP_LED_BLINK:
+	default:
+		return (PCIEHPC_PROP_VALUE_BLINK);
+	}
+}
+
+/*
+ * return description text for slot condition
+ */
+char *
+pcie_slot_condition_text(ap_condition_t condition)
+{
+	switch (condition) {
+	case AP_COND_UNKNOWN:
+		return (PCIEHPC_PROP_VALUE_UNKNOWN);
+	case AP_COND_OK:
+		return (PCIEHPC_PROP_VALUE_OK);
+	case AP_COND_FAILING:
+		return (PCIEHPC_PROP_VALUE_FAILING);
+	case AP_COND_FAILED:
+		return (PCIEHPC_PROP_VALUE_FAILED);
+	case AP_COND_UNUSABLE:
+		return (PCIEHPC_PROP_VALUE_UNUSABLE);
+	default:
+		return (PCIEHPC_PROP_VALUE_UNKNOWN);
+	}
+}
+
+/*
+ * routine to copy in a nvlist from userland
+ */
+int
+pcie_copyin_nvlist(char *packed_buf, size_t packed_sz, nvlist_t **nvlp)
+{
+	int		ret = DDI_SUCCESS;
+	char		*packed;
+	nvlist_t	*dest = NULL;
+
+	if (packed_buf == NULL || packed_sz == 0)
+		return (DDI_EINVAL);
+
+	/* copyin packed nvlist */
+	if ((packed = kmem_alloc(packed_sz, KM_SLEEP)) == NULL)
+		return (DDI_ENOMEM);
+
+	if (copyin(packed_buf, packed, packed_sz) != 0) {
+		cmn_err(CE_WARN, "pcie_copyin_nvlist: copyin failed.\n");
+		ret = DDI_FAILURE;
+		goto copyin_cleanup;
+	}
+
+	/* unpack packed nvlist */
+	if ((ret = nvlist_unpack(packed, packed_sz, &dest, KM_SLEEP)) != 0) {
+		cmn_err(CE_WARN, "pcie_copyin_nvlist: nvlist_unpack "
+		    "failed with err %d\n", ret);
+		switch (ret) {
+		case EINVAL:
+		case ENOTSUP:
+			ret = DDI_EINVAL;
+			goto copyin_cleanup;
+		case ENOMEM:
+			ret = DDI_ENOMEM;
+			goto copyin_cleanup;
+		default:
+			ret = DDI_FAILURE;
+			goto copyin_cleanup;
+		}
+	}
+	*nvlp = dest;
+copyin_cleanup:
+	kmem_free(packed, packed_sz);
+	return (ret);
+}
+
+/*
+ * routine to copy out a nvlist to userland
+ */
+int
+pcie_copyout_nvlist(nvlist_t *nvl, char *packed_buf, size_t *buf_sz)
+{
+	int	err = 0;
+	char	*buf = NULL;
+	size_t	packed_sz;
+
+	if (nvl == NULL || packed_buf == NULL || buf_sz == NULL)
+		return (DDI_EINVAL);
+
+	/* pack nvlist, the library will allocate memory */
+	if ((err = nvlist_pack(nvl, &buf, &packed_sz, NV_ENCODE_NATIVE, 0))
+	    != 0) {
+		cmn_err(CE_WARN, "pcie_copyout_nvlist: nvlist_pack "
+		    "failed with err %d\n", err);
+		switch (err) {
+		case EINVAL:
+		case ENOTSUP:
+			return (DDI_EINVAL);
+		case ENOMEM:
+			return (DDI_ENOMEM);
+		default:
+			return (DDI_FAILURE);
+		}
+	}
+	if (packed_sz > *buf_sz) {
+		return (DDI_EINVAL);
+	}
+
+	/* copyout packed nvlist */
+	if (copyout(buf, packed_buf, packed_sz) != 0) {
+		cmn_err(CE_WARN, "pcie_copyout_nvlist: copyout " "failed.\n");
+		kmem_free(buf, packed_sz);
+		return (DDI_FAILURE);
+	}
+
+	*buf_sz = packed_sz;
+	kmem_free(buf, packed_sz);
+	return (DDI_SUCCESS);
+}
+
+/*
+ * init bus_hp_op entry and init hotpluggable slots & virtual ports
+ */
+int
+pcie_hp_init(dev_info_t *dip, caddr_t arg)
+{
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
+	int		ret = DDI_SUCCESS, count;
+	dev_info_t	*cdip;
+
+	if (PCIE_IS_PCIE_HOTPLUG_CAPABLE(bus_p)) {
+		/* Init hotplug controller */
+		ret = pciehpc_init(dip, arg);
+	} else if (PCIE_IS_PCI_HOTPLUG_CAPABLE(bus_p)) {
+		ret = pcishpc_init(dip);
+	}
+
+	if (ret != DDI_SUCCESS) {
+		cmn_err(CE_WARN, "pcie_hp_init: initialize hotplug "
+		    "controller failed with %d\n", ret);
+		return (ret);
+	}
+
+	ndi_devi_enter(dip, &count);
+
+	/* Create port for the first level children */
+	cdip = ddi_get_child(dip);
+	while (cdip != NULL) {
+		if ((ret = pcie_hp_register_port(cdip, dip, NULL))
+		    != DDI_SUCCESS) {
+			/* stop and cleanup */
+			break;
+		}
+		cdip = ddi_get_next_sibling(cdip);
+	}
+	ndi_devi_exit(dip, count);
+	if (ret != DDI_SUCCESS) {
+		cmn_err(CE_WARN, "pcie_hp_init: initialize virtual "
+		    "hotplug port failed with %d\n", ret);
+		(void) pcie_hp_uninit(dip);
+
+		return (ret);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * uninit the hotpluggable slots and virtual ports
+ */
+int
+pcie_hp_uninit(dev_info_t *dip)
+{
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
+	pcie_hp_unreg_port_t arg;
+
+	/*
+	 * Must set arg.rv to NDI_SUCCESS so that if there's no port
+	 * under this dip, we still return success thus the bridge
+	 * driver can be successfully detached.
+	 *
+	 * Note that during the probe PCI configurator calls
+	 * ndi_devi_offline() to detach driver for a new probed bridge,
+	 * so that it can reprogram the resources for the bridge,
+	 * ndi_devi_offline() calls into pcieb_detach() which in turn
+	 * calls into this function. In this case there are no ports
+	 * created under a new probe bridge dip, as ports are only
+	 * created after the configurator finishing probing, thus the
+	 * ndi_hp_walk_cn() will see no ports when this is called
+	 * from the PCI configurtor.
+	 */
+	arg.nexus_dip = dip;
+	arg.connector_num = DDI_HP_CN_NUM_NONE;
+	arg.rv = NDI_SUCCESS;
+
+	/* tear down all virtual hotplug handles */
+	ndi_hp_walk_cn(dip, pcie_hp_unregister_ports_cb, &arg);
+
+	if (arg.rv != NDI_SUCCESS)
+		return (DDI_FAILURE);
+
+	if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p))
+		(void) pciehpc_uninit(dip);
+	else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p))
+		(void) pcishpc_uninit(dip);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * interrupt handler
+ */
+int
+pcie_hp_intr(dev_info_t *dip)
+{
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
+	int		ret = DDI_INTR_UNCLAIMED;
+
+	if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p))
+		ret = pciehpc_intr(dip);
+	else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p))
+		ret = pcishpc_intr(dip);
+
+	return (ret);
+}
+
+/*
+ * Probe the given PCIe/PCI Hotplug Connection (CN).
+ */
+/*ARGSUSED*/
+int
+pcie_hp_probe(pcie_hp_slot_t *slot_p)
+{
+	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
+	dev_info_t	*dip = ctrl_p->hc_dip;
+
+	/*
+	 * Call the configurator to probe a given PCI hotplug
+	 * Hotplug Connection (CN).
+	 */
+	if (pcicfg_configure(dip, slot_p->hs_device_num, PCICFG_ALL_FUNC, 0)
+	    != PCICFG_SUCCESS) {
+		PCIE_DBG("pcie_hp_probe() failed\n");
+		return (DDI_FAILURE);
+	}
+	slot_p->hs_condition = AP_COND_OK;
+	pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
+	    slot_p->hs_minor), slot_p->hs_device_num);
+
+	/*
+	 * Create ports for the newly probed devices.
+	 * Note, this is only for the first level children because the
+	 * descendants' ports will be created during bridge driver attach.
+	 */
+	return (pcie_hp_register_ports_for_dev(dip, slot_p->hs_device_num));
+}
+
+/*
+ * Unprobe the given PCIe/PCI Hotplug Connection (CN):
+ *	1. remove all child device nodes
+ *	2. unregister all dependent ports
+ */
+/*ARGSUSED*/
+int
+pcie_hp_unprobe(pcie_hp_slot_t *slot_p)
+{
+	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
+	dev_info_t	*dip = ctrl_p->hc_dip;
+	pcie_hp_unreg_port_t arg;
+
+	/*
+	 * Call the configurator to unprobe a given PCI hotplug
+	 * Hotplug Connection (CN).
+	 */
+	if (pcicfg_unconfigure(dip, slot_p->hs_device_num, PCICFG_ALL_FUNC, 0)
+	    != PCICFG_SUCCESS) {
+		PCIE_DBG("pcie_hp_unprobe() failed\n");
+		return (DDI_FAILURE);
+	}
+	slot_p->hs_condition = AP_COND_UNKNOWN;
+	pcie_hp_delete_occupant_props(dip, makedevice(ddi_driver_major(dip),
+	    slot_p->hs_minor));
+
+	/*
+	 * Remove ports for the unprobed devices.
+	 * Note, this is only for the first level children because the
+	 * descendants' ports were already removed during bridge driver dettach.
+	 */
+	arg.nexus_dip = dip;
+	arg.connector_num = slot_p->hs_info.cn_num;
+	arg.rv = NDI_SUCCESS;
+	ndi_hp_walk_cn(dip, pcie_hp_unregister_ports_cb, &arg);
+
+	return (arg.rv == NDI_SUCCESS) ? (DDI_SUCCESS) : (DDI_FAILURE);
+}
+
+/* Read-only probe: no hardware register programming. */
+int
+pcie_read_only_probe(dev_info_t *dip, char *cn_name, dev_info_t **pcdip)
+{
+	long dev, func;
+	int ret;
+	char *sp;
+	dev_info_t *cdip;
+
+	*pcdip = NULL;
+	/*
+	 * Parse the string of a pci Port name and get the device number
+	 * and function number.
+	 */
+	if (ddi_strtol(cn_name + 4, &sp, 10, &dev) != 0)
+		return (DDI_EINVAL);
+	if (ddi_strtol(sp + 1, NULL, 10, &func) != 0)
+		return (DDI_EINVAL);
+
+	ret = pcicfg_configure(dip, (int)dev, (int)func,
+	    PCICFG_FLAG_READ_ONLY);
+	if (ret == PCICFG_SUCCESS) {
+		cdip = pcie_hp_devi_find(dip, (int)dev, (int)func);
+		*pcdip = cdip;
+	}
+	return (ret);
+}
+
+/* Read-only unprobe: no hardware register programming. */
+int
+pcie_read_only_unprobe(dev_info_t *dip, char *cn_name)
+{
+	long dev, func;
+	int ret;
+	char *sp;
+
+	/*
+	 * Parse the string of a pci Port name and get the device number
+	 * and function number.
+	 */
+	if (ddi_strtol(cn_name + 4, &sp, 10, &dev) != 0)
+		return (DDI_EINVAL);
+	if (ddi_strtol(sp + 1, NULL, 10, &func) != 0)
+		return (DDI_EINVAL);
+
+	ret = pcicfg_unconfigure(dip, (int)dev, (int)func,
+	    PCICFG_FLAG_READ_ONLY);
+
+	return (ret);
+}
+
+/* Control structure used to find a device in the devinfo tree */
+struct pcie_hp_find_ctrl {
+	uint_t		device;
+	uint_t		function;
+	dev_info_t	*dip;
+};
+
+/*
+ * find a devinfo node with specified device and function number
+ * in the device tree under 'dip'
+ */
+dev_info_t *
+pcie_hp_devi_find(dev_info_t *dip, uint_t device, uint_t function)
+{
+	struct pcie_hp_find_ctrl	ctrl;
+	int				count;
+
+	ctrl.device = device;
+	ctrl.function = function;
+	ctrl.dip = NULL;
+
+	ndi_devi_enter(dip, &count);
+	ddi_walk_devs(ddi_get_child(dip), pcie_hp_match_dev_func,
+	    (void *)&ctrl);
+	ndi_devi_exit(dip, count);
+
+	return (ctrl.dip);
+}
+
+/*
+ * routine to create 'pci-occupant' property for a hotplug slot
+ */
+void
+pcie_hp_create_occupant_props(dev_info_t *dip, dev_t dev, int pci_dev)
+{
+	pcie_bus_t		*bus_p = PCIE_DIP2BUS(dip);
+	pcie_hp_ctrl_t		*ctrl_p = (pcie_hp_ctrl_t *)bus_p->bus_hp_ctrl;
+	pcie_hp_slot_t		*slotp;
+	pcie_hp_cn_cfg_t	cn_cfg;
+	pcie_hp_occupant_info_t	*occupant;
+	int			circular, i;
+
+	ndi_devi_enter(dip, &circular);
+
+	if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) {
+		slotp = (ctrl_p && (pci_dev == 0)) ?
+		    ctrl_p->hc_slots[pci_dev] : NULL;
+	} else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p)) {
+		if (ctrl_p) {
+			int	slot_num;
+
+			slot_num = (ctrl_p->hc_device_increases) ?
+			    (pci_dev - ctrl_p->hc_device_start) :
+			    (pci_dev + ctrl_p->hc_device_start);
+
+			slotp = ctrl_p->hc_slots[slot_num];
+		} else {
+			slotp = NULL;
+		}
+	}
+
+	if (slotp == NULL)
+		return;
+
+	occupant = kmem_alloc(sizeof (pcie_hp_occupant_info_t), KM_SLEEP);
+	occupant->i = 0;
+
+	cn_cfg.flag = B_FALSE;
+	cn_cfg.rv = NDI_SUCCESS;
+	cn_cfg.dip = NULL;
+	cn_cfg.slotp = (void *)slotp;
+	cn_cfg.cn_private = (void *)occupant;
+
+	ddi_walk_devs(ddi_get_child(dip), pcie_hp_list_occupants,
+	    (void *)&cn_cfg);
+
+	if (occupant->i == 0) {
+		/* no occupants right now, need to create stub property */
+		char *c[] = { "" };
+		(void) ddi_prop_update_string_array(dev, dip, "pci-occupant",
+		    c, 1);
+	} else {
+		(void) ddi_prop_update_string_array(dev, dip, "pci-occupant",
+		    occupant->id, occupant->i);
+	}
+
+	for (i = 0; i < occupant->i; i++)
+		kmem_free(occupant->id[i], sizeof (char[MAXPATHLEN]));
+
+	kmem_free(occupant, sizeof (pcie_hp_occupant_info_t));
+
+	ndi_devi_exit(dip, circular);
+}
+
+/*
+ * routine to remove 'pci-occupant' property for a hotplug slot
+ */
+void
+pcie_hp_delete_occupant_props(dev_info_t *dip, dev_t dev)
+{
+	(void) ddi_prop_remove(dev, dip, "pci-occupant");
+}
+
+/*
+ * general code to create a minor node, called from hotplug controller
+ * drivers.
+ */
+int
+pcie_create_minor_node(pcie_hp_ctrl_t *ctrl_p, int slot)
+{
+	dev_info_t		*dip = ctrl_p->hc_dip;
+	pcie_hp_slot_t		*slot_p = ctrl_p->hc_slots[slot];
+	ddi_hp_cn_info_t	*info_p = &slot_p->hs_info;
+
+	if (ddi_create_minor_node(dip, info_p->cn_name,
+	    S_IFCHR, slot_p->hs_minor,
+	    DDI_NT_PCI_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
+		return (DDI_FAILURE);
+	}
+
+	(void) ddi_prop_update_int(DDI_DEV_T_NONE,
+	    dip, "ap-names", 1 << slot_p->hs_device_num);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * general code to remove a minor node, called from hotplug controller
+ * drivers.
+ */
+void
+pcie_remove_minor_node(pcie_hp_ctrl_t *ctrl_p, int slot)
+{
+	ddi_remove_minor_node(ctrl_p->hc_dip,
+	    ctrl_p->hc_slots[slot]->hs_info.cn_name);
+}
+
+/*
+ * Local functions (called within this file)
+ */
+
+/*
+ * Register ports for all the children with device number device_num
+ */
+static int
+pcie_hp_register_ports_for_dev(dev_info_t *dip, int device_num)
+{
+	dev_info_t	*cdip;
+	int		rv;
+
+	for (cdip = ddi_get_child(dip); cdip;
+	    cdip = ddi_get_next_sibling(cdip)) {
+		if (pcie_hp_match_dev(cdip, device_num)) {
+			/*
+			 * Found the newly probed device under the
+			 * current slot. Register a port for it.
+			 */
+			if ((rv = pcie_hp_register_port(cdip, dip, NULL))
+			    != DDI_SUCCESS)
+				return (rv);
+		} else {
+			continue;
+		}
+	}
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Unregister ports of a pci bridge dip, get called from ndi_hp_walk_cn()
+ *
+ * If connector_num is specified, then unregister the slot's dependent ports
+ * only; Otherwise, unregister all ports of a pci bridge dip.
+ */
+static int
+pcie_hp_unregister_ports_cb(ddi_hp_cn_info_t *info, void *arg)
+{
+	pcie_hp_unreg_port_t *unreg_arg = (pcie_hp_unreg_port_t *)arg;
+	dev_info_t *dip = unreg_arg->nexus_dip;
+	int rv = NDI_SUCCESS;
+
+	if (info->cn_type != DDI_HP_CN_TYPE_VIRTUAL_PORT) {
+		unreg_arg->rv = rv;
+		return (DDI_WALK_CONTINUE);
+	}
+
+	if (unreg_arg->connector_num != DDI_HP_CN_NUM_NONE) {
+		/* Unregister ports for all unprobed devices under a slot. */
+		if (unreg_arg->connector_num == info->cn_num_dpd_on) {
+
+			rv = ndi_hp_unregister(dip, info->cn_name);
+		}
+	} else {
+
+		/* Unregister all ports of a pci bridge dip. */
+		rv = ndi_hp_unregister(dip, info->cn_name);
+	}
+
+	unreg_arg->rv = rv;
+	if (rv == NDI_SUCCESS)
+		return (DDI_WALK_CONTINUE);
+	else
+		return (DDI_WALK_TERMINATE);
+}
+
+/*
+ * Find a port according to cn_name and get the port's state.
+ */
+static int
+pcie_hp_get_port_state(ddi_hp_cn_info_t *info, void *arg)
+{
+	pcie_hp_port_state_t *port = (pcie_hp_port_state_t *)arg;
+
+	if (info->cn_type != DDI_HP_CN_TYPE_VIRTUAL_PORT)
+		return (DDI_WALK_CONTINUE);
+
+	if (strcmp(info->cn_name, port->cn_name) == 0) {
+		/* Matched. */
+		port->cn_state = info->cn_state;
+		port->rv = DDI_SUCCESS;
+
+		return (DDI_WALK_TERMINATE);
+	}
+
+	return (DDI_WALK_CONTINUE);
+}
+
+/*
+ * Find the physical slot with the given device number;
+ * return the slot if found.
+ */
+static pcie_hp_slot_t *
+pcie_find_physical_slot(dev_info_t *dip, int dev_num)
+{
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
+	pcie_hp_ctrl_t	*ctrl = PCIE_GET_HP_CTRL(dip);
+
+	if (PCIE_IS_PCIE_HOTPLUG_CAPABLE(bus_p)) {
+		/* PCIe has only one slot */
+		return (dev_num == 0) ? (ctrl->hc_slots[0]) : (NULL);
+	} else if (PCIE_IS_PCI_HOTPLUG_CAPABLE(bus_p)) {
+		for (int slot = 0; slot < ctrl->hc_num_slots_impl; slot++) {
+			if (ctrl->hc_slots[slot]->hs_device_num == dev_num) {
+				/* found */
+				return (ctrl->hc_slots[slot]);
+			}
+		}
+	}
+
+	return (NULL);
+}
+
+/*
+ * setup slot name/slot-number info for the port which is being registered.
+ */
+static int
+pcie_hp_create_port_name_num(dev_info_t *dip, ddi_hp_cn_info_t *cn_info)
+{
+	int		ret, dev_num, func_num, name_len;
+	dev_info_t	*pdip = ddi_get_parent(dip);
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(pdip);
+	pcie_hp_slot_t	*slot;
+	pcie_req_id_t	bdf;
+	char		tmp[PCIE_HP_DEV_FUNC_NUM_STRING_LEN];
+
+	ret = pcie_get_bdf_from_dip(dip, &bdf);
+	if (ret != DDI_SUCCESS) {
+		return (ret);
+	}
+	if (PCIE_IS_RP(bus_p) || PCIE_IS_SWD(bus_p) ||
+	    PCIE_IS_PCI2PCIE(bus_p)) {
+		/*
+		 * It is under a PCIe device, devcie number is always 0;
+		 * function number might > 8 in ARI supported case.
+		 */
+		dev_num = 0;
+		func_num = (bdf & ((~PCI_REG_BUS_M) >> 8));
+	} else {
+		dev_num = (bdf & (PCI_REG_DEV_M >> 8)) >> 3;
+		func_num = bdf & (PCI_REG_FUNC_M >> 8);
+	}
+	/*
+	 * The string length of dev_num and func_num must be no longer than 4
+	 * including the string end mark. (With ARI case considered, e.g.,
+	 * dev_num=0x0, func_num=0xff.)
+	 */
+	(void) snprintf(tmp, PCIE_HP_DEV_FUNC_NUM_STRING_LEN, "%x%x",
+	    dev_num, func_num);
+	/*
+	 * Calculate the length of cn_name.
+	 * The format of pci port name is: pci.d,f
+	 * d stands for dev_num, f stands for func_num. So the length of the
+	 * name string can be calculated as following.
+	 */
+	name_len = strlen(tmp) + PCIE_HP_PORT_NAME_STRING_LEN + 1;
+
+	cn_info->cn_name = (char *)kmem_zalloc(name_len, KM_SLEEP);
+	(void) snprintf(cn_info->cn_name, name_len, "pci.%x,%x",
+	    dev_num, func_num);
+	cn_info->cn_num = (dev_num << 8) | func_num;
+	slot = pcie_find_physical_slot(pdip, dev_num);
+
+	cn_info->cn_num_dpd_on = slot ?
+	    slot->hs_info.cn_num : DDI_HP_CN_NUM_NONE;
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Extract device and function number from port name, whose format is
+ * something like 'pci.1,0'
+ */
+static int
+pcie_hp_get_df_from_port_name(char *cn_name, int *dev_num, int *func_num)
+{
+	int name_len, ret;
+	long d, f;
+	char *sp;
+
+	/* some checks for the input name */
+	name_len = strlen(cn_name);
+	if ((name_len <= PCIE_HP_PORT_NAME_STRING_LEN) ||
+	    (name_len > (PCIE_HP_PORT_NAME_STRING_LEN +
+	    PCIE_HP_DEV_FUNC_NUM_STRING_LEN - 1)) ||
+	    (strncmp("pci.", cn_name, 4) != 0)) {
+		return (DDI_EINVAL);
+	}
+	ret = ddi_strtol(cn_name + 4, &sp, 10, &d);
+	if (ret != DDI_SUCCESS)
+		return (ret);
+
+	if (strncmp(",", sp, 1) != 0)
+		return (DDI_EINVAL);
+
+	ret = ddi_strtol(sp + 1, NULL, 10, &f);
+	if (ret != DDI_SUCCESS)
+		return (ret);
+	*dev_num = (int)d;
+	*func_num = (int)f;
+
+	return (ret);
+}
+
+/*
+ * Check/copy cn_name and set connection numbers.
+ * If it is a valid name, then setup cn_info for the newly created port.
+ */
+static int
+pcie_hp_setup_port_name_num(dev_info_t *pdip, char *cn_name,
+    ddi_hp_cn_info_t *cn_info)
+{
+	int dev_num, func_num, ret;
+	pcie_hp_slot_t *slot;
+
+	if ((ret = pcie_hp_get_df_from_port_name(cn_name, &dev_num, &func_num))
+	    != DDI_SUCCESS)
+		return (ret);
+
+	if (pcie_hp_check_hardware_existence(pdip, dev_num, func_num) ==
+	    DDI_SUCCESS) {
+		cn_info->cn_state = DDI_HP_CN_STATE_PRESENT;
+	} else {
+		cn_info->cn_state = DDI_HP_CN_STATE_EMPTY;
+	}
+
+	cn_info->cn_name = ddi_strdup(cn_name, KM_SLEEP);
+	cn_info->cn_num = (dev_num << 8) | func_num;
+
+	slot = pcie_find_physical_slot(pdip, dev_num);
+	if (slot) {
+		cn_info->cn_num_dpd_on = slot->hs_info.cn_num;
+	} else {
+		cn_info->cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
+	}
+	return (DDI_SUCCESS);
+}
+
+static int
+ndi2ddi(int n)
+{
+	int ret;
+
+	switch (n) {
+	case NDI_SUCCESS:
+		ret = DDI_SUCCESS;
+		break;
+	case NDI_NOMEM:
+		ret = DDI_ENOMEM;
+		break;
+	case NDI_BUSY:
+		ret = DDI_EBUSY;
+		break;
+	case NDI_EINVAL:
+		ret = DDI_EINVAL;
+		break;
+	case NDI_ENOTSUP:
+		ret = DDI_ENOTSUP;
+		break;
+	case NDI_FAILURE:
+	default:
+		ret = DDI_FAILURE;
+		break;
+	}
+	return (ret);
+}
+
+/*
+ * Common routine to create and register a new port
+ *
+ * Create an empty port if dip is NULL, and cn_name needs to be specified in
+ * this case. Otherwise, create a port mapping to the specified dip, and cn_name
+ * is not needed in this case.
+ */
+static int
+pcie_hp_register_port(dev_info_t *dip, dev_info_t *pdip, char *cn_name)
+{
+	ddi_hp_cn_info_t	*cn_info;
+	int			ret;
+
+	ASSERT((dip == NULL) != (cn_name == NULL));
+	cn_info = kmem_zalloc(sizeof (ddi_hp_cn_info_t), KM_SLEEP);
+	if (dip != NULL)
+		ret = pcie_hp_create_port_name_num(dip, cn_info);
+	else
+		ret = pcie_hp_setup_port_name_num(pdip, cn_name, cn_info);
+
+	if (ret != DDI_SUCCESS) {
+		kmem_free(cn_info, sizeof (ddi_hp_cn_info_t));
+		return (ret);
+	}
+
+	cn_info->cn_child = dip;
+	cn_info->cn_type = DDI_HP_CN_TYPE_VIRTUAL_PORT;
+	cn_info->cn_type_str = DDI_HP_CN_TYPE_STR_PORT;
+
+	ret = ndi_hp_register(pdip, cn_info);
+
+	kmem_free(cn_info->cn_name, strlen(cn_info->cn_name) + 1);
+	kmem_free(cn_info, sizeof (ddi_hp_cn_info_t));
+
+	return (ndi2ddi(ret));
+}
+
+/* Check if there is a piece of hardware exist corresponding to the cn_name */
+static int
+pcie_hp_check_hardware_existence(dev_info_t *dip, int dev_num, int func_num)
+{
+
+	/*
+	 * VHPTODO:
+	 * According to device and function number, check if there is a hardware
+	 * device exists. Currently, this function can not be reached before
+	 * we enable state transition to or from "Port-Empty" or "Port-Present"
+	 * states. When the pci device type project is integrated, we are going
+	 * to call the pci config space access interfaces introduced by it.
+	 */
+	_NOTE(ARGUNUSED(dip, dev_num, func_num));
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Dispatch hotplug commands to different hotplug controller drivers, including
+ * physical and virtual hotplug operations.
+ */
+/* ARGSUSED */
+int
+pcie_hp_common_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
+    void *arg, void *result)
+{
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
+	int		ret = DDI_SUCCESS;
+
+	PCIE_DBG("pcie_hp_common_ops: dip=%p cn_name=%s op=%x arg=%p\n",
+	    dip, cn_name, op, arg);
+
+	switch (op) {
+	case DDI_HPOP_CN_CREATE_PORT:
+	{
+		/* create an empty port */
+		return (pcie_hp_register_port(NULL, dip, cn_name));
+	}
+	case DDI_HPOP_CN_CHANGE_STATE:
+	{
+		ddi_hp_cn_state_t curr_state;
+		ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
+		pcie_hp_port_state_t state_arg;
+
+		if (target_state < DDI_HP_CN_STATE_PORT_EMPTY) {
+			/* this is for physical slot state change */
+			break;
+		}
+		PCIE_DBG("pcie_hp_common_ops: change port state"
+		    " dip=%p cn_name=%s"
+		    " op=%x arg=%p\n", (void *)dip, cn_name, op, arg);
+
+		state_arg.rv = DDI_FAILURE;
+		state_arg.cn_name = cn_name;
+		ndi_hp_walk_cn(dip, pcie_hp_get_port_state, &state_arg);
+		if (state_arg.rv != DDI_SUCCESS) {
+			/* can not find the port */
+			return (DDI_EINVAL);
+		}
+		curr_state = state_arg.cn_state;
+		/*
+		 * Check if this is for changing port's state: change to/from
+		 * PORT_EMPTY/PRESENT states.
+		 */
+		if (curr_state < target_state) {
+			/* Upgrade state */
+			switch (curr_state) {
+			case DDI_HP_CN_STATE_PORT_EMPTY:
+				if (target_state ==
+				    DDI_HP_CN_STATE_PORT_PRESENT) {
+					int dev_num, func_num;
+
+					ret = pcie_hp_get_df_from_port_name(
+					    cn_name, &dev_num, &func_num);
+					if (ret != DDI_SUCCESS)
+						goto port_state_done;
+
+					ret = pcie_hp_check_hardware_existence(
+					    dip, dev_num, func_num);
+				} else if (target_state ==
+				    DDI_HP_CN_STATE_OFFLINE) {
+					ret = pcie_read_only_probe(dip,
+					    cn_name, (dev_info_t **)result);
+				} else
+					ret = DDI_EINVAL;
+
+				goto port_state_done;
+			case DDI_HP_CN_STATE_PORT_PRESENT:
+				if (target_state ==
+				    DDI_HP_CN_STATE_OFFLINE)
+					ret = pcie_read_only_probe(dip,
+					    cn_name, (dev_info_t **)result);
+				else
+					ret = DDI_EINVAL;
+
+				goto port_state_done;
+			default:
+				ASSERT("unexpected state");
+			}
+		} else {
+			/* Downgrade state */
+			switch (curr_state) {
+			case DDI_HP_CN_STATE_PORT_PRESENT:
+			{
+				int dev_num, func_num;
+
+				ret = pcie_hp_get_df_from_port_name(cn_name,
+				    &dev_num, &func_num);
+				if (ret != DDI_SUCCESS)
+					goto port_state_done;
+
+				ret = pcie_hp_check_hardware_existence(dip,
+				    dev_num, func_num);
+
+				goto port_state_done;
+			}
+			case DDI_HP_CN_STATE_OFFLINE:
+				ret = pcie_read_only_unprobe(dip, cn_name);
+
+				goto port_state_done;
+			default:
+				ASSERT("unexpected state");
+			}
+		}
+port_state_done:
+		*(ddi_hp_cn_state_t *)result = curr_state;
+		return (ret);
+	}
+	default:
+		break;
+	}
+
+	if (PCIE_IS_PCIE_HOTPLUG_CAPABLE(bus_p)) {
+		/* PCIe hotplug */
+		ret = pciehpc_hp_ops(dip, cn_name, op, arg, result);
+	} else if (PCIE_IS_PCI_HOTPLUG_CAPABLE(bus_p)) {
+		/* PCI SHPC hotplug */
+		ret = pcishpc_hp_ops(dip, cn_name, op, arg, result);
+	} else {
+		cmn_err(CE_WARN, "pcie_hp_common_ops: op is not supported."
+		    " dip=%p cn_name=%s"
+		    " op=%x arg=%p\n", (void *)dip, cn_name, op, arg);
+		ret = DDI_ENOTSUP;
+	}
+
+#if defined(__i386) || defined(__amd64)
+	/*
+	 * like in attach, since hotplugging can change error registers,
+	 * we need to ensure that the proper bits are set on this port
+	 * after a configure operation
+	 */
+	if ((ret == DDI_SUCCESS) && (op == DDI_HPOP_CN_CHANGE_STATE) &&
+	    (*(ddi_hp_cn_state_t *)arg == DDI_HP_CN_STATE_ENABLED))
+		pcieb_intel_error_workaround(dip);
+#endif
+
+	return (ret);
+}
+
+/*
+ * pcie_hp_match_dev_func:
+ * Match dip's PCI device number and function number with input ones.
+ */
+static int
+pcie_hp_match_dev_func(dev_info_t *dip, void *hdl)
+{
+	struct pcie_hp_find_ctrl	*ctrl = (struct pcie_hp_find_ctrl *)hdl;
+	pci_regspec_t			*pci_rp;
+	int				length;
+	int				pci_dev, pci_func;
+
+	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
+		ctrl->dip = NULL;
+		return (DDI_WALK_TERMINATE);
+	}
+
+	/* get the PCI device address info */
+	pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
+	pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
+
+	/*
+	 * free the memory allocated by ddi_prop_lookup_int_array
+	 */
+	ddi_prop_free(pci_rp);
+
+	if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
+		/* found the match for the specified device address */
+		ctrl->dip = dip;
+		return (DDI_WALK_TERMINATE);
+	}
+
+	/*
+	 * continue the walk to the next sibling to look for a match.
+	 */
+	return (DDI_WALK_PRUNECHILD);
+}
+
+/*
+ * pcie_hp_match_dev:
+ * Match the dip's pci device number with the input dev_num
+ */
+static boolean_t
+pcie_hp_match_dev(dev_info_t *dip, int dev_num)
+{
+	pci_regspec_t			*pci_rp;
+	int				length;
+	int				pci_dev;
+
+	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
+		return (B_FALSE);
+	}
+
+	/* get the PCI device address info */
+	pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
+
+	/*
+	 * free the memory allocated by ddi_prop_lookup_int_array
+	 */
+	ddi_prop_free(pci_rp);
+
+	if (pci_dev == dev_num) {
+		/* found the match for the specified device address */
+		return (B_TRUE);
+	}
+
+	return (B_FALSE);
+}
+
+/*
+ * Callback function to match with device number in order to list
+ * occupants under a specific slot
+ */
+static int
+pcie_hp_list_occupants(dev_info_t *dip, void *arg)
+{
+	pcie_hp_cn_cfg_t	*cn_cfg_p = (pcie_hp_cn_cfg_t *)arg;
+	pcie_hp_occupant_info_t	*occupant =
+	    (pcie_hp_occupant_info_t *)cn_cfg_p->cn_private;
+	pcie_hp_slot_t		*slot_p =
+	    (pcie_hp_slot_t *)cn_cfg_p->slotp;
+	int			pci_dev;
+	pci_regspec_t		*pci_rp;
+	int			length;
+	major_t			major;
+
+	/*
+	 * Get the PCI device number information from the devinfo
+	 * node. Since the node may not have the address field
+	 * setup (this is done in the DDI_INITCHILD of the parent)
+	 * we look up the 'reg' property to decode that information.
+	 */
+	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
+	    (uint_t *)&length) != DDI_PROP_SUCCESS) {
+		cn_cfg_p->rv = DDI_FAILURE;
+		cn_cfg_p->dip = dip;
+		return (DDI_WALK_TERMINATE);
+	}
+
+	/* get the pci device id information */
+	pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
+
+	/*
+	 * free the memory allocated by ddi_prop_lookup_int_array
+	 */
+	ddi_prop_free(pci_rp);
+
+	/*
+	 * Match the node for the device number of the slot.
+	 */
+	if (pci_dev == slot_p->hs_device_num) {
+
+		major = ddi_driver_major(dip);
+
+		/*
+		 * If the node is not yet attached, then don't list it
+		 * as an occupant. This is valid, since nothing can be
+		 * consuming it until it is attached, and cfgadm will
+		 * ask for the property explicitly which will cause it
+		 * to be re-freshed right before checking with rcm.
+		 */
+		if ((major == DDI_MAJOR_T_NONE) || !i_ddi_devi_attached(dip))
+			return (DDI_WALK_PRUNECHILD);
+
+		/*
+		 * If we have used all our occupants then print mesage
+		 * and terminate walk.
+		 */
+		if (occupant->i >= PCIE_HP_MAX_OCCUPANTS) {
+			cmn_err(CE_WARN,
+			    "pcie (%s%d): unable to list all occupants",
+			    ddi_driver_name(ddi_get_parent(dip)),
+			    ddi_get_instance(ddi_get_parent(dip)));
+			return (DDI_WALK_TERMINATE);
+		}
+
+		/*
+		 * No need to hold the dip as ddi_walk_devs
+		 * has already arranged that for us.
+		 */
+		occupant->id[occupant->i] =
+		    kmem_alloc(sizeof (char[MAXPATHLEN]), KM_SLEEP);
+		(void) ddi_pathname(dip, (char *)occupant->id[occupant->i]);
+		occupant->i++;
+	}
+
+	/*
+	 * continue the walk to the next sibling to look for a match
+	 * or to find other nodes if this card is a multi-function card.
+	 */
+	return (DDI_WALK_PRUNECHILD);
+}
+
+/*
+ * Generate the System Event for ESC_DR_REQ.
+ * One of the consumers is pcidr, it calls to libcfgadm to perform a
+ * configure or unconfigure operation to the AP.
+ */
+void
+pcie_hp_gen_sysevent_req(char *slot_name, int hint,
+    dev_info_t *self, int kmflag)
+{
+	sysevent_id_t	eid;
+	nvlist_t	*ev_attr_list = NULL;
+	char		cn_path[MAXPATHLEN];
+	char		*ap_id;
+	int		err, ap_id_len;
+
+	/*
+	 * Minor device name (AP) will be bus path
+	 * concatenated with slot name
+	 */
+	(void) strcpy(cn_path, "/devices");
+	(void) ddi_pathname(self, cn_path + strlen("/devices"));
+
+	ap_id_len = strlen(cn_path) + strlen(":") +
+	    strlen(slot_name) + 1;
+	ap_id = kmem_zalloc(ap_id_len, kmflag);
+	if (ap_id == NULL) {
+		cmn_err(CE_WARN,
+		    "%s%d: Failed to allocate memory for AP ID: %s:%s",
+		    ddi_driver_name(self), ddi_get_instance(self),
+		    cn_path, slot_name);
+
+		return;
+	}
+
+	(void) strcpy(ap_id, cn_path);
+	(void) strcat(ap_id, ":");
+	(void) strcat(ap_id, slot_name);
+
+	err = nvlist_alloc(&ev_attr_list, NV_UNIQUE_NAME_TYPE, kmflag);
+	if (err != 0) {
+		cmn_err(CE_WARN,
+		    "%s%d: Failed to allocate memory "
+		    "for event attributes%s", ddi_driver_name(self),
+		    ddi_get_instance(self), ESC_DR_REQ);
+
+		kmem_free(ap_id, ap_id_len);
+		return;
+	}
+
+	switch (hint) {
+
+	case SE_INVESTIGATE_RES:	/* fall through */
+	case SE_INCOMING_RES:		/* fall through */
+	case SE_OUTGOING_RES:		/* fall through */
+
+		err = nvlist_add_string(ev_attr_list, DR_REQ_TYPE,
+		    SE_REQ2STR(hint));
+
+		if (err != 0) {
+			cmn_err(CE_WARN,
+			    "%s%d: Failed to add attr [%s] "
+			    "for %s event", ddi_driver_name(self),
+			    ddi_get_instance(self),
+			    DR_REQ_TYPE, ESC_DR_REQ);
+
+			goto done;
+		}
+		break;
+
+	default:
+		cmn_err(CE_WARN, "%s%d:  Unknown hint on sysevent",
+		    ddi_driver_name(self), ddi_get_instance(self));
+
+		goto done;
+	}
+
+	/*
+	 * Add attachment point as attribute (common attribute)
+	 */
+
+	err = nvlist_add_string(ev_attr_list, DR_AP_ID, ap_id);
+
+	if (err != 0) {
+		cmn_err(CE_WARN, "%s%d: Failed to add attr [%s] for %s event",
+		    ddi_driver_name(self), ddi_get_instance(self),
+		    DR_AP_ID, EC_DR);
+
+		goto done;
+	}
+
+
+	/*
+	 * Log this event with sysevent framework.
+	 */
+
+	err = ddi_log_sysevent(self, DDI_VENDOR_SUNW, EC_DR,
+	    ESC_DR_REQ, ev_attr_list, &eid,
+	    ((kmflag == KM_SLEEP) ? DDI_SLEEP : DDI_NOSLEEP));
+	if (err != 0) {
+		cmn_err(CE_WARN, "%s%d: Failed to log %s event",
+		    ddi_driver_name(self), ddi_get_instance(self), EC_DR);
+	}
+
+done:
+	nvlist_free(ev_attr_list);
+	kmem_free(ap_id, ap_id_len);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/pciex/hotplug/pciehpc.c	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,2285 @@
+/*
+ * 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 file contains Standard PCI Express HotPlug functionality that is
+ * compatible with the PCI Express ver 1.1 specification.
+ *
+ * NOTE: This file is compiled and delivered through misc/pcie module.
+ */
+
+#include <sys/types.h>
+#include <sys/note.h>
+#include <sys/conf.h>
+#include <sys/kmem.h>
+#include <sys/debug.h>
+#include <sys/vtrace.h>
+#include <sys/autoconf.h>
+#include <sys/varargs.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/time.h>
+#include <sys/callb.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/sysevent/dr.h>
+#include <sys/pci_impl.h>
+#include <sys/hotplug/pci/pcie_hp.h>
+#include <sys/hotplug/pci/pciehpc.h>
+
+typedef struct pciehpc_prop {
+	char	*prop_name;
+	char	*prop_value;
+} pciehpc_prop_t;
+
+static pciehpc_prop_t	pciehpc_props[] = {
+	{ PCIEHPC_PROP_LED_FAULT,	PCIEHPC_PROP_VALUE_LED },
+	{ PCIEHPC_PROP_LED_POWER,	PCIEHPC_PROP_VALUE_LED },
+	{ PCIEHPC_PROP_LED_ATTN,	PCIEHPC_PROP_VALUE_LED },
+	{ PCIEHPC_PROP_LED_ACTIVE,	PCIEHPC_PROP_VALUE_LED },
+	{ PCIEHPC_PROP_CARD_TYPE,	PCIEHPC_PROP_VALUE_TYPE },
+	{ PCIEHPC_PROP_BOARD_TYPE,	PCIEHPC_PROP_VALUE_TYPE },
+	{ PCIEHPC_PROP_SLOT_CONDITION,	PCIEHPC_PROP_VALUE_TYPE }
+};
+
+/* Local functions prototype */
+static int pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p);
+static int pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p);
+static int pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p);
+static int pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p);
+static int pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p);
+static int pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p);
+static pcie_hp_ctrl_t *pciehpc_create_controller(dev_info_t *dip);
+static void pciehpc_destroy_controller(dev_info_t *dip);
+static int pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p);
+static int pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p);
+static int pciehpc_slot_get_property(pcie_hp_slot_t *slot_p,
+    ddi_hp_property_t *arg, ddi_hp_property_t *rval);
+static int pciehpc_slot_set_property(pcie_hp_slot_t *slot_p,
+    ddi_hp_property_t *arg, ddi_hp_property_t *rval);
+static void pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control);
+static void pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p);
+static pcie_hp_led_state_t pciehpc_led_state_to_hpc(uint16_t state);
+static pcie_hp_led_state_t pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p,
+    pcie_hp_led_t led);
+static void pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
+    pcie_hp_led_state_t state);
+
+static int pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
+    ddi_hp_cn_state_t target_state);
+static int pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
+    ddi_hp_cn_state_t target_state);
+static int pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
+    ddi_hp_cn_state_t target_state);
+static int
+    pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
+static int
+    pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
+static int pciehpc_slot_probe(pcie_hp_slot_t *slot_p);
+static int pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p);
+
+#ifdef	DEBUG
+static void pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p);
+#endif	/* DEBUG */
+
+/*
+ * Global functions (called by other drivers/modules)
+ */
+
+/*
+ * Initialize Hot Plug Controller if present. The arguments are:
+ *	dip	- Devinfo node pointer to the hot plug bus node
+ *	regops	- register ops to access HPC registers for non-standard
+ *		  HPC hw implementations (e.g: HPC in host PCI-E brdiges)
+ *		  This is NULL for standard HPC in PCIe bridges.
+ * Returns:
+ *	DDI_SUCCESS for successful HPC initialization
+ *	DDI_FAILURE for errors or if HPC hw not found
+ */
+int
+pciehpc_init(dev_info_t *dip, caddr_t arg)
+{
+	pcie_hp_regops_t	*regops = (pcie_hp_regops_t *)(void *)arg;
+	pcie_hp_ctrl_t		*ctrl_p;
+
+	PCIE_DBG("pciehpc_init() called (dip=%p)\n", (void *)dip);
+
+	/* Make sure that it is not already initialized */
+	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) {
+		PCIE_DBG("%s%d: pciehpc instance already initialized!\n",
+		    ddi_driver_name(dip), ddi_get_instance(dip));
+		return (DDI_SUCCESS);
+	}
+
+	/* Allocate a new hotplug controller and slot structures */
+	ctrl_p = pciehpc_create_controller(dip);
+
+	/* setup access handle for HPC regs */
+	if (regops != NULL) {
+		/* HPC access is non-standard; use the supplied reg ops */
+		ctrl_p->hc_regops = *regops;
+	}
+
+	/*
+	 * Setup resource maps for this bus node.
+	 */
+	(void) pci_resource_setup(dip);
+
+	PCIE_DISABLE_ERRORS(dip);
+
+	/*
+	 * Set the platform specific hot plug mode.
+	 */
+	ctrl_p->hc_ops.init_hpc_hw = pciehpc_hpc_init;
+	ctrl_p->hc_ops.uninit_hpc_hw = pciehpc_hpc_uninit;
+	ctrl_p->hc_ops.init_hpc_slotinfo = pciehpc_slotinfo_init;
+	ctrl_p->hc_ops.uninit_hpc_slotinfo = pciehpc_slotinfo_uninit;
+	ctrl_p->hc_ops.poweron_hpc_slot = pciehpc_slot_poweron;
+	ctrl_p->hc_ops.poweroff_hpc_slot = pciehpc_slot_poweroff;
+
+	ctrl_p->hc_ops.enable_hpc_intr = pciehpc_enable_intr;
+	ctrl_p->hc_ops.disable_hpc_intr = pciehpc_disable_intr;
+
+#if	defined(__i386) || defined(__amd64)
+	pciehpc_update_ops(ctrl_p);
+#endif
+
+	/* initialize hot plug controller hw */
+	if ((ctrl_p->hc_ops.init_hpc_hw)(ctrl_p) != DDI_SUCCESS)
+		goto cleanup1;
+
+	/* initialize slot information soft state structure */
+	if ((ctrl_p->hc_ops.init_hpc_slotinfo)(ctrl_p) != DDI_SUCCESS)
+		goto cleanup2;
+
+	/* register the hot plug slot with DDI HP framework */
+	if (pciehpc_register_slot(ctrl_p) != DDI_SUCCESS)
+		goto cleanup3;
+
+	/* create minor node for this slot */
+	if (pcie_create_minor_node(ctrl_p, 0) != DDI_SUCCESS)
+		goto cleanup4;
+
+	/* HPC initialization is complete now */
+	ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG;
+
+#ifdef	DEBUG
+	/* For debug, dump the HPC registers */
+	pciehpc_dump_hpregs(ctrl_p);
+#endif	/* DEBUG */
+
+	/* enable hot plug interrupts/event */
+	(void) (ctrl_p->hc_ops.enable_hpc_intr)(ctrl_p);
+
+	return (DDI_SUCCESS);
+cleanup4:
+	(void) pciehpc_unregister_slot(ctrl_p);
+cleanup3:
+	(void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
+
+cleanup2:
+	(void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
+
+cleanup1:
+	PCIE_ENABLE_ERRORS(dip);
+	(void) pci_resource_destroy(dip);
+
+	pciehpc_destroy_controller(dip);
+	return (DDI_FAILURE);
+}
+
+/*
+ * Uninitialize HPC soft state structure and free up any resources
+ * used for the HPC instance.
+ */
+int
+pciehpc_uninit(dev_info_t *dip)
+{
+	pcie_hp_ctrl_t *ctrl_p;
+
+	PCIE_DBG("pciehpc_uninit() called (dip=%p)\n", (void *)dip);
+
+	/* get the soft state structure for this dip */
+	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
+		return (DDI_FAILURE);
+	}
+
+	pcie_remove_minor_node(ctrl_p, 0);
+
+	/* disable interrupts */
+	(void) (ctrl_p->hc_ops.disable_hpc_intr)(ctrl_p);
+
+	/* unregister the slot */
+	(void) pciehpc_unregister_slot(ctrl_p);
+
+	/* uninit any slot info data structures */
+	(void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
+
+	/* uninitialize hpc, remove interrupt handler, etc. */
+	(void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
+
+	PCIE_ENABLE_ERRORS(dip);
+
+	/*
+	 * Destroy resource maps for this bus node.
+	 */
+	(void) pci_resource_destroy(dip);
+
+	/* destroy the soft state structure */
+	pciehpc_destroy_controller(dip);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * pciehpc_intr()
+ *
+ * Interrupt handler for PCI-E Hot plug controller interrupts.
+ *
+ * Note: This is only for native mode hot plug. This is called
+ * by the nexus driver at interrupt context. Interrupt Service Routine
+ * registration is done by the nexus driver for both hot plug and
+ * non-hot plug interrupts. This function is called from the ISR
+ * of the nexus driver to handle hot-plug interrupts.
+ */
+int
+pciehpc_intr(dev_info_t *dip)
+{
+	pcie_hp_ctrl_t	*ctrl_p;
+	pcie_hp_slot_t	*slot_p;
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
+	uint16_t	status, control;
+
+	/* get the soft state structure for this dip */
+	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
+		return (DDI_INTR_UNCLAIMED);
+
+	mutex_enter(&ctrl_p->hc_mutex);
+
+	/* make sure the controller soft state is initialized */
+	if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
+		mutex_exit(&ctrl_p->hc_mutex);
+		return (DDI_INTR_UNCLAIMED);
+	}
+
+	/* if it is not NATIVE hot plug mode then return */
+	if (bus_p->bus_hp_curr_mode != PCIE_NATIVE_HP_MODE) {
+		mutex_exit(&ctrl_p->hc_mutex);
+		return (DDI_INTR_UNCLAIMED);
+	}
+
+	slot_p = ctrl_p->hc_slots[0];
+
+	/* read the current slot status register */
+	status = pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
+
+	/* check if there are any hot plug interrupts occurred */
+	if (!(status & PCIE_SLOTSTS_STATUS_EVENTS)) {
+		/* no hot plug events occurred */
+		mutex_exit(&ctrl_p->hc_mutex);
+		return (DDI_INTR_UNCLAIMED);
+	}
+
+	/* clear the interrupt status bits */
+	pciehpc_reg_put16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
+
+	/* check for CMD COMPLETE interrupt */
+	if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
+		PCIE_DBG("pciehpc_intr(): CMD COMPLETED interrupt received\n");
+		/* wake up any one waiting for Command Completion event */
+		cv_signal(&ctrl_p->hc_cmd_comp_cv);
+	}
+
+	/* check for ATTN button interrupt */
+	if (status & PCIE_SLOTSTS_ATTN_BTN_PRESSED) {
+		PCIE_DBG("pciehpc_intr(): ATTN BUTTON interrupt received\n");
+
+		/* if ATTN button event is still pending then cancel it */
+		if (slot_p->hs_attn_btn_pending == B_TRUE)
+			slot_p->hs_attn_btn_pending = B_FALSE;
+		else
+			slot_p->hs_attn_btn_pending = B_TRUE;
+
+		/* wake up the ATTN event handler */
+		cv_signal(&slot_p->hs_attn_btn_cv);
+	}
+
+	/* check for power fault interrupt */
+	if (status & PCIE_SLOTSTS_PWR_FAULT_DETECTED) {
+
+		PCIE_DBG("pciehpc_intr(): POWER FAULT interrupt received"
+		    " on slot %d\n", slot_p->hs_phy_slot_num);
+		control =  pciehpc_reg_get16(ctrl_p,
+		    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+
+		if (control & PCIE_SLOTCTL_PWR_FAULT_EN) {
+			slot_p->hs_condition = AP_COND_FAILED;
+
+			/* disable power fault detction interrupt */
+			pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
+			    PCIE_SLOTCTL, control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
+
+			/*
+			 * Send the event to DDI Hotplug framework, power off
+			 * the slot
+			 */
+			(void) ndi_hp_state_change_req(dip,
+			    slot_p->hs_info.cn_name,
+			    DDI_HP_CN_STATE_EMPTY, DDI_HP_REQ_ASYNC);
+
+			pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
+			    PCIE_HP_LED_ON);
+		}
+	}
+
+	/* check for MRL SENSOR CHANGED interrupt */
+	if (status & PCIE_SLOTSTS_MRL_SENSOR_CHANGED) {
+		/* For now (phase-I), no action is taken on this event */
+		PCIE_DBG("pciehpc_intr(): MRL SENSOR CHANGED interrupt received"
+		    " on slot %d\n", slot_p->hs_phy_slot_num);
+	}
+
+	/* check for PRESENCE CHANGED interrupt */
+	if (status & PCIE_SLOTSTS_PRESENCE_CHANGED) {
+
+		PCIE_DBG("pciehpc_intr(): PRESENCE CHANGED interrupt received"
+		    " on slot %d\n", slot_p->hs_phy_slot_num);
+
+		if (status & PCIE_SLOTSTS_PRESENCE_DETECTED) {
+			/*
+			 * card is inserted into the slot, ask DDI Hotplug
+			 * framework to change state to Present.
+			 */
+			(void) ndi_hp_state_change_req(dip,
+			    slot_p->hs_info.cn_name,
+			    DDI_HP_CN_STATE_PRESENT,
+			    DDI_HP_REQ_ASYNC);
+		} else { /* card is removed from the slot */
+			cmn_err(CE_NOTE, "pciehpc (%s%d): card is removed"
+			    " from the slot %s",
+			    ddi_driver_name(dip),
+			    ddi_get_instance(dip),
+			    slot_p->hs_info.cn_name);
+
+			if (slot_p->hs_info.cn_state ==
+			    DDI_HP_CN_STATE_ENABLED) {
+				/* Card is removed when slot is enabled */
+				slot_p->hs_condition = AP_COND_FAILED;
+			} else {
+				slot_p->hs_condition = AP_COND_UNKNOWN;
+			}
+			/* make sure to disable power fault detction intr */
+			control =  pciehpc_reg_get16(ctrl_p,
+			    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+
+			if (control & PCIE_SLOTCTL_PWR_FAULT_EN)
+				pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
+				    PCIE_SLOTCTL,
+				    control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
+
+			/*
+			 * Ask DDI Hotplug framework to change state to Empty
+			 */
+			(void) ndi_hp_state_change_req(dip,
+			    slot_p->hs_info.cn_name,
+			    DDI_HP_CN_STATE_EMPTY,
+			    DDI_HP_REQ_ASYNC);
+		}
+	}
+
+	/* check for DLL state changed interrupt */
+	if (ctrl_p->hc_dll_active_rep &&
+	    (status & PCIE_SLOTSTS_DLL_STATE_CHANGED)) {
+		PCIE_DBG("pciehpc_intr(): DLL STATE CHANGED interrupt received"
+		    " on slot %d\n", slot_p->hs_phy_slot_num);
+
+		cv_signal(&slot_p->hs_dll_active_cv);
+	}
+
+	mutex_exit(&ctrl_p->hc_mutex);
+
+	return (DDI_INTR_CLAIMED);
+}
+
+/*
+ * Handle hotplug commands
+ *
+ * Note: This function is called by DDI HP framework at kernel context only
+ */
+/* ARGSUSED */
+int
+pciehpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
+    void *arg, void *result)
+{
+	pcie_hp_ctrl_t	*ctrl_p;
+	pcie_hp_slot_t	*slot_p;
+	int		ret = DDI_SUCCESS;
+
+	PCIE_DBG("pciehpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n",
+	    dip, cn_name, op, arg);
+
+	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
+		return (DDI_FAILURE);
+
+	slot_p = ctrl_p->hc_slots[0];
+
+	if (strcmp(cn_name, slot_p->hs_info.cn_name) != 0)
+		return (DDI_EINVAL);
+
+	switch (op) {
+	case DDI_HPOP_CN_GET_STATE:
+	{
+		mutex_enter(&slot_p->hs_ctrl->hc_mutex);
+
+		/* get the current slot state */
+		pciehpc_get_slot_state(slot_p);
+
+		*((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
+
+		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
+		break;
+	}
+	case DDI_HPOP_CN_CHANGE_STATE:
+	{
+		ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
+
+		mutex_enter(&slot_p->hs_ctrl->hc_mutex);
+
+		ret = pciehpc_change_slot_state(slot_p, target_state);
+		*(ddi_hp_cn_state_t *)result = slot_p->hs_info.cn_state;
+
+		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
+		break;
+	}
+	case DDI_HPOP_CN_PROBE:
+
+		ret = pciehpc_slot_probe(slot_p);
+
+		break;
+	case DDI_HPOP_CN_UNPROBE:
+		ret = pciehpc_slot_unprobe(slot_p);
+
+		break;
+	case DDI_HPOP_CN_GET_PROPERTY:
+		ret = pciehpc_slot_get_property(slot_p,
+		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
+		break;
+	case DDI_HPOP_CN_SET_PROPERTY:
+		ret = pciehpc_slot_set_property(slot_p,
+		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
+		break;
+	default:
+		ret = DDI_ENOTSUP;
+		break;
+	}
+
+	return (ret);
+}
+
+/*
+ * Get the current state of the slot from the hw.
+ *
+ * The slot state should have been initialized before this function gets called.
+ */
+void
+pciehpc_get_slot_state(pcie_hp_slot_t *slot_p)
+{
+	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+	uint16_t	control, status;
+	ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state;
+
+	/* read the Slot Control Register */
+	control = pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+
+	slot_p->hs_fault_led_state = PCIE_HP_LED_OFF; /* no fault led */
+	slot_p->hs_active_led_state = PCIE_HP_LED_OFF; /* no active led */
+
+	/* read the current Slot Status Register */
+	status = pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
+
+	/* get POWER led state */
+	slot_p->hs_power_led_state =
+	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control));
+
+	/* get ATTN led state */
+	slot_p->hs_attn_led_state =
+	    pciehpc_led_state_to_hpc(pcie_slotctl_attn_indicator_get(control));
+
+	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
+		/* no device present; slot is empty */
+		slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
+
+		return;
+	}
+
+	/* device is present */
+	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT;
+
+	if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
+		/*
+		 * Device is powered on. Set to "ENABLED" state (skip
+		 * POWERED state) because there is not a explicit "enable"
+		 * action exists for PCIe.
+		 * If it is already in "POWERED" state, then keep it until
+		 * user explicitly change it to other states.
+		 */
+		if (curr_state == DDI_HP_CN_STATE_POWERED) {
+			slot_p->hs_info.cn_state = curr_state;
+		} else {
+			slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED;
+		}
+	}
+}
+
+/*
+ * setup slot name/slot-number info.
+ */
+void
+pciehpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p)
+{
+	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+	uchar_t		*slotname_data;
+	int		*slotnum;
+	uint_t		count;
+	int		len;
+	int		invalid_slotnum = 0;
+	uint32_t	slot_capabilities;
+
+	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip,
+	    DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
+	    DDI_PROP_SUCCESS) {
+		slot_p->hs_phy_slot_num = slotnum[0];
+		ddi_prop_free(slotnum);
+	} else {
+		slot_capabilities = pciehpc_reg_get32(ctrl_p,
+		    bus_p->bus_pcie_off + PCIE_SLOTCAP);
+		slot_p->hs_phy_slot_num =
+		    PCIE_SLOTCAP_PHY_SLOT_NUM(slot_capabilities);
+	}
+
+	/* platform may not have initialized it */
+	if (!slot_p->hs_phy_slot_num) {
+		PCIE_DBG("%s#%d: Invalid slot number!\n",
+		    ddi_driver_name(ctrl_p->hc_dip),
+		    ddi_get_instance(ctrl_p->hc_dip));
+		slot_p->hs_phy_slot_num = pciehpc_reg_get8(ctrl_p,
+		    PCI_BCNF_SECBUS);
+		invalid_slotnum = 1;
+	}
+	slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num;
+	slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
+
+	/*
+	 * construct the slot_name:
+	 *	if "slot-names" property exists then use that name
+	 *	else if valid slot number exists then it is "pcie<slot-num>".
+	 *	else it will be "pcie<sec-bus-number>dev0"
+	 */
+	if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS,
+	    "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) {
+		char tmp_name[256];
+
+		/*
+		 * Note: for PCI-E slots, the device number is always 0 so the
+		 * first (and only) string is the slot name for this slot.
+		 */
+		(void) snprintf(tmp_name, sizeof (tmp_name),
+		    (char *)slotname_data + 4);
+		slot_p->hs_info.cn_name = ddi_strdup(tmp_name, KM_SLEEP);
+		kmem_free(slotname_data, len);
+	} else {
+		if (invalid_slotnum) {
+			/* use device number ie. 0 */
+			slot_p->hs_info.cn_name = ddi_strdup("pcie0",
+			    KM_SLEEP);
+		} else {
+			char tmp_name[256];
+
+			(void) snprintf(tmp_name, sizeof (tmp_name), "pcie%d",
+			    slot_p->hs_phy_slot_num);
+			slot_p->hs_info.cn_name = ddi_strdup(tmp_name,
+			    KM_SLEEP);
+		}
+	}
+}
+
+/*
+ * Read/Write access to HPC registers. If platform nexus has non-standard
+ * HPC access mechanism then regops functions are used to do reads/writes.
+ */
+uint8_t
+pciehpc_reg_get8(pcie_hp_ctrl_t *ctrl_p, uint_t off)
+{
+	if (ctrl_p->hc_regops.get != NULL) {
+		return ((uint8_t)ctrl_p->hc_regops.get(
+		    ctrl_p->hc_regops.cookie, (off_t)off));
+	} else {
+		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+
+		return (pci_config_get8(bus_p->bus_cfg_hdl, off));
+	}
+}
+
+uint16_t
+pciehpc_reg_get16(pcie_hp_ctrl_t *ctrl_p, uint_t off)
+{
+	if (ctrl_p->hc_regops.get != NULL) {
+		return ((uint16_t)ctrl_p->hc_regops.get(
+		    ctrl_p->hc_regops.cookie, (off_t)off));
+	} else {
+		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+
+		return (pci_config_get16(bus_p->bus_cfg_hdl, off));
+	}
+}
+
+uint32_t
+pciehpc_reg_get32(pcie_hp_ctrl_t *ctrl_p, uint_t off)
+{
+	if (ctrl_p->hc_regops.get != NULL) {
+		return ((uint32_t)ctrl_p->hc_regops.get(
+		    ctrl_p->hc_regops.cookie, (off_t)off));
+	} else {
+		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+
+		return (pci_config_get32(bus_p->bus_cfg_hdl, off));
+	}
+}
+
+void
+pciehpc_reg_put8(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint8_t val)
+{
+	if (ctrl_p->hc_regops.put != NULL) {
+		ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
+		    (off_t)off, (uint_t)val);
+	} else {
+		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+
+		pci_config_put8(bus_p->bus_cfg_hdl, off, val);
+	}
+}
+
+void
+pciehpc_reg_put16(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint16_t val)
+{
+	if (ctrl_p->hc_regops.put != NULL) {
+		ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
+		    (off_t)off, (uint_t)val);
+	} else {
+		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+
+		pci_config_put16(bus_p->bus_cfg_hdl, off, val);
+	}
+}
+
+void
+pciehpc_reg_put32(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint32_t val)
+{
+	if (ctrl_p->hc_regops.put != NULL) {
+		ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
+		    (off_t)off, (uint_t)val);
+	} else {
+		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+
+		pci_config_put32(bus_p->bus_cfg_hdl, off, val);
+	}
+}
+
+/*
+ * ************************************************************************
+ * ***	Local functions (called within this file)
+ * ***	PCIe Native Hotplug mode specific functions
+ * ************************************************************************
+ */
+
+/*
+ * Initialize HPC hardware, install interrupt handler, etc. It doesn't
+ * enable hot plug interrupts.
+ *
+ * (Note: It is called only from pciehpc_init().)
+ */
+static int
+pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p)
+{
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+	uint16_t	reg;
+
+	/* read the Slot Control Register */
+	reg = pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+
+	/* disable all interrupts */
+	reg &= ~(PCIE_SLOTCTL_INTR_MASK);
+	pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
+	    PCIE_SLOTCTL, reg);
+
+	/* clear any interrupt status bits */
+	reg = pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
+	pciehpc_reg_put16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Uninitialize HPC hardware, uninstall interrupt handler, etc.
+ *
+ * (Note: It is called only from pciehpc_uninit().)
+ */
+static int
+pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p)
+{
+	/* disable interrupts */
+	(void) pciehpc_disable_intr(ctrl_p);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Setup slot information for use with DDI HP framework.
+ */
+static int
+pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p)
+{
+	uint32_t	slot_capabilities, link_capabilities;
+	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+
+	mutex_enter(&ctrl_p->hc_mutex);
+	/*
+	 * setup DDI HP framework slot information structure
+	 */
+	slot_p->hs_device_num = 0;
+
+	slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCIE;
+	slot_p->hs_info.cn_type_str = (ctrl_p->hc_regops.get == NULL) ?
+	    PCIE_NATIVE_HP_TYPE : PCIE_PROP_HP_TYPE;
+	slot_p->hs_info.cn_child = NULL;
+
+	slot_p->hs_minor =
+	    PCI_MINOR_NUM(ddi_get_instance(ctrl_p->hc_dip),
+	    slot_p->hs_device_num);
+	slot_p->hs_condition = AP_COND_UNKNOWN;
+
+	/* read Slot Capabilities Register */
+	slot_capabilities = pciehpc_reg_get32(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCAP);
+
+	/* set slot-name/slot-number info */
+	pciehpc_set_slot_name(ctrl_p);
+
+	/* check if Attn Button present */
+	ctrl_p->hc_has_attn = (slot_capabilities & PCIE_SLOTCAP_ATTN_BUTTON) ?
+	    B_TRUE : B_FALSE;
+
+	/* check if Manual Retention Latch sensor present */
+	ctrl_p->hc_has_mrl = (slot_capabilities & PCIE_SLOTCAP_MRL_SENSOR) ?
+	    B_TRUE : B_FALSE;
+
+	/*
+	 * PCI-E version 1.1 defines EMI Lock Present bit
+	 * in Slot Capabilities register. Check for it.
+	 */
+	ctrl_p->hc_has_emi_lock = (slot_capabilities &
+	    PCIE_SLOTCAP_EMI_LOCK_PRESENT) ? B_TRUE : B_FALSE;
+
+	link_capabilities = pciehpc_reg_get32(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_LINKCAP);
+	ctrl_p->hc_dll_active_rep = (link_capabilities &
+	    PCIE_LINKCAP_DLL_ACTIVE_REP_CAPABLE) ? B_TRUE : B_FALSE;
+	if (ctrl_p->hc_dll_active_rep)
+		cv_init(&slot_p->hs_dll_active_cv, NULL, CV_DRIVER, NULL);
+
+	/* setup thread for handling ATTN button events */
+	if (ctrl_p->hc_has_attn) {
+		PCIE_DBG("pciehpc_slotinfo_init: setting up ATTN button event "
+		    "handler thread for slot %d\n", slot_p->hs_phy_slot_num);
+
+		cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL);
+		slot_p->hs_attn_btn_pending = B_FALSE;
+		slot_p->hs_attn_btn_threadp = thread_create(NULL, 0,
+		    pciehpc_attn_btn_handler,
+		    (void *)ctrl_p, 0, &p0, TS_RUN, minclsyspri);
+		slot_p->hs_attn_btn_thread_exit = B_FALSE;
+	}
+
+	/* get current slot state from the hw */
+	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
+	pciehpc_get_slot_state(slot_p);
+	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED)
+		slot_p->hs_condition = AP_COND_OK;
+
+	mutex_exit(&ctrl_p->hc_mutex);
+
+	return (DDI_SUCCESS);
+}
+
+/*ARGSUSED*/
+static int
+pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p)
+{
+	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
+
+	if (slot_p->hs_attn_btn_threadp != NULL) {
+		mutex_enter(&ctrl_p->hc_mutex);
+		slot_p->hs_attn_btn_thread_exit = B_TRUE;
+		cv_signal(&slot_p->hs_attn_btn_cv);
+		PCIE_DBG("pciehpc_slotinfo_uninit: "
+		    "waiting for ATTN thread exit\n");
+		cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
+		PCIE_DBG("pciehpc_slotinfo_uninit: ATTN thread exit\n");
+		cv_destroy(&slot_p->hs_attn_btn_cv);
+		slot_p->hs_attn_btn_threadp = NULL;
+		mutex_exit(&ctrl_p->hc_mutex);
+	}
+
+	if (ctrl_p->hc_dll_active_rep)
+		cv_destroy(&slot_p->hs_dll_active_cv);
+	if (slot_p->hs_info.cn_name)
+		kmem_free(slot_p->hs_info.cn_name,
+		    strlen(slot_p->hs_info.cn_name) + 1);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Enable hot plug interrupts.
+ * Note: this is only for Native hot plug mode.
+ */
+static int
+pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p)
+{
+	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+	uint16_t	reg;
+
+	/* clear any interrupt status bits */
+	reg = pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
+	pciehpc_reg_put16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
+
+	/* read the Slot Control Register */
+	reg = pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+
+	/*
+	 * enable interrupts: power fault detection interrupt is enabled
+	 * only when the slot is powered ON
+	 */
+	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
+		pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
+		    PCIE_SLOTCTL, reg | PCIE_SLOTCTL_INTR_MASK);
+	else
+		pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
+		    PCIE_SLOTCTL, reg | (PCIE_SLOTCTL_INTR_MASK &
+		    ~PCIE_SLOTCTL_PWR_FAULT_EN));
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Disable hot plug interrupts.
+ * Note: this is only for Native hot plug mode.
+ */
+static int
+pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p)
+{
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+	uint16_t	reg;
+
+	/* read the Slot Control Register */
+	reg = pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+
+	/* disable all interrupts */
+	reg &= ~(PCIE_SLOTCTL_INTR_MASK);
+	pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL, reg);
+
+	/* clear any interrupt status bits */
+	reg = pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
+	pciehpc_reg_put16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Allocate a new hotplug controller and slot structures for HPC
+ * associated with this dip.
+ */
+static pcie_hp_ctrl_t *
+pciehpc_create_controller(dev_info_t *dip)
+{
+	pcie_hp_ctrl_t	*ctrl_p;
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
+
+	ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP);
+	ctrl_p->hc_dip = dip;
+
+	/* Allocate a new slot structure. */
+	ctrl_p->hc_slots[0] = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP);
+	ctrl_p->hc_slots[0]->hs_num = 0;
+	ctrl_p->hc_slots[0]->hs_ctrl = ctrl_p;
+
+	/* Initialize the interrupt mutex */
+	mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER,
+	    (void *)PCIE_INTR_PRI);
+
+	/* Initialize synchronization conditional variable */
+	cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL);
+	ctrl_p->hc_cmd_pending = B_FALSE;
+
+	bus_p->bus_hp_curr_mode = PCIE_NATIVE_HP_MODE;
+	PCIE_SET_HP_CTRL(dip, ctrl_p);
+
+	return (ctrl_p);
+}
+
+/*
+ * Remove the HPC controller and slot structures
+ */
+static void
+pciehpc_destroy_controller(dev_info_t *dip)
+{
+	pcie_hp_ctrl_t	*ctrl_p;
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
+
+	/* get the soft state structure for this dip */
+	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
+		return;
+
+	PCIE_SET_HP_CTRL(dip, NULL);
+	bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE;
+
+	mutex_destroy(&ctrl_p->hc_mutex);
+	cv_destroy(&ctrl_p->hc_cmd_comp_cv);
+	kmem_free(ctrl_p->hc_slots[0], sizeof (pcie_hp_slot_t));
+	kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t));
+}
+
+/*
+ * Register the PCI-E hot plug slot with DDI HP framework.
+ */
+static int
+pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p)
+{
+	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
+	dev_info_t	*dip = ctrl_p->hc_dip;
+
+	/* register the slot with DDI HP framework */
+	if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) {
+		PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n",
+		    slot_p->hs_phy_slot_num);
+		return (DDI_FAILURE);
+	}
+
+	pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
+	    slot_p->hs_minor), slot_p->hs_device_num);
+
+	PCIE_DBG("pciehpc_register_slot(): registered slot %d\n",
+	    slot_p->hs_phy_slot_num);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Unregister the PCI-E hot plug slot from DDI HP framework.
+ */
+static int
+pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p)
+{
+	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
+	dev_info_t	*dip = ctrl_p->hc_dip;
+
+	pcie_hp_delete_occupant_props(dip, makedevice(ddi_driver_major(dip),
+	    slot_p->hs_minor));
+
+	/* unregister the slot with DDI HP framework */
+	if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) != NDI_SUCCESS) {
+		PCIE_DBG("pciehpc_unregister_slot() "
+		    "failed to unregister slot %d\n", slot_p->hs_phy_slot_num);
+		return (DDI_FAILURE);
+	}
+
+	PCIE_DBG("pciehpc_unregister_slot(): unregistered slot %d\n",
+	    slot_p->hs_phy_slot_num);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * pciehpc_slot_poweron()
+ *
+ * Poweron/Enable the slot.
+ *
+ * Note: This function is called by DDI HP framework at kernel context only
+ */
+/*ARGSUSED*/
+static int
+pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
+{
+	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+	uint16_t	status, control;
+
+	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
+
+	/* get the current state of the slot */
+	pciehpc_get_slot_state(slot_p);
+
+	/* check if the slot is already in the 'enabled' state */
+	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
+		/* slot is already in the 'enabled' state */
+		PCIE_DBG("pciehpc_slot_poweron() slot %d already enabled\n",
+		    slot_p->hs_phy_slot_num);
+
+		*result = slot_p->hs_info.cn_state;
+		return (DDI_SUCCESS);
+	}
+
+	/* read the Slot Status Register */
+	status =  pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
+
+	/* make sure the MRL switch is closed if present */
+	if ((ctrl_p->hc_has_mrl) && (status & PCIE_SLOTSTS_MRL_SENSOR_OPEN)) {
+		/* MRL switch is open */
+		cmn_err(CE_WARN, "MRL switch is open on slot %d\n",
+		    slot_p->hs_phy_slot_num);
+		goto cleanup;
+	}
+
+	/* make sure the slot has a device present */
+	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
+		/* slot is empty */
+		PCIE_DBG("slot %d is empty\n", slot_p->hs_phy_slot_num);
+		goto cleanup;
+	}
+
+	/* get the current state of Slot Control Register */
+	control =  pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+
+	/*
+	 * Enable power to the slot involves:
+	 *	1. Set power LED to blink and ATTN led to OFF.
+	 *	2. Set power control ON in Slot Control Reigster and
+	 *	   wait for Command Completed Interrupt or 1 sec timeout.
+	 *	3. If Data Link Layer State Changed events are supported
+	 *	   then wait for the event to indicate Data Layer Link
+	 *	   is active. The time out value for this event is 1 second.
+	 *	   This is specified in PCI-E version 1.1.
+	 *	4. Set power LED to be ON.
+	 */
+
+	/* 1. set power LED to blink & ATTN led to OFF */
+	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
+	pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
+
+	/* 2. set power control to ON */
+	control =  pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+	control &= ~PCIE_SLOTCTL_PWR_CONTROL;
+	pciehpc_issue_hpc_command(ctrl_p, control);
+
+	/* 3. wait for DLL State Change event, if it's supported */
+	if (ctrl_p->hc_dll_active_rep) {
+		status =  pciehpc_reg_get16(ctrl_p,
+		    bus_p->bus_pcie_off + PCIE_LINKSTS);
+
+		if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE)) {
+			/* wait 1 sec for the DLL State Changed event */
+			(void) cv_timedwait(&slot_p->hs_dll_active_cv,
+			    &ctrl_p->hc_mutex,
+			    ddi_get_lbolt() +
+			    SEC_TO_TICK(PCIE_HP_DLL_STATE_CHANGE_TIMEOUT));
+
+			/* check Link status */
+			status =  pciehpc_reg_get16(ctrl_p,
+			    bus_p->bus_pcie_off +
+			    PCIE_LINKSTS);
+			if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE))
+				goto cleanup2;
+		}
+	}
+
+	/* wait 1 sec for link to come up */
+	delay(drv_usectohz(1000000));
+
+	/* check power is really turned ON */
+	control =  pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+
+	if (control & PCIE_SLOTCTL_PWR_CONTROL) {
+		PCIE_DBG("slot %d fails to turn on power on connect\n",
+		    slot_p->hs_phy_slot_num);
+
+		goto cleanup1;
+	}
+
+	/* clear power fault status */
+	status =  pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
+	status |= PCIE_SLOTSTS_PWR_FAULT_DETECTED;
+	pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS,
+	    status);
+
+	/* enable power fault detection interrupt */
+	control |= PCIE_SLOTCTL_PWR_FAULT_EN;
+	pciehpc_issue_hpc_command(ctrl_p, control);
+
+	/* 4. Set power LED to be ON */
+	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON);
+
+	/* if EMI is present, turn it ON */
+	if (ctrl_p->hc_has_emi_lock) {
+		status =  pciehpc_reg_get16(ctrl_p,
+		    bus_p->bus_pcie_off + PCIE_SLOTSTS);
+
+		if (!(status & PCIE_SLOTSTS_EMI_LOCK_SET)) {
+			control =  pciehpc_reg_get16(ctrl_p,
+			    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+			control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
+			pciehpc_issue_hpc_command(ctrl_p, control);
+
+			/* wait 1 sec after toggling the state of EMI lock */
+			delay(drv_usectohz(1000000));
+		}
+	}
+
+	*result = slot_p->hs_info.cn_state =
+	    DDI_HP_CN_STATE_POWERED;
+
+	return (DDI_SUCCESS);
+
+cleanup2:
+	control =  pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+
+	/* if power is ON, set power control to OFF */
+	if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
+		control |= PCIE_SLOTCTL_PWR_CONTROL;
+		pciehpc_issue_hpc_command(ctrl_p, control);
+	}
+
+cleanup1:
+	/* set power led to OFF */
+	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
+
+cleanup:
+	return (DDI_FAILURE);
+}
+
+/*ARGSUSED*/
+static int
+pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
+{
+	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+	uint16_t	status, control;
+
+	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
+
+	/* get the current state of the slot */
+	pciehpc_get_slot_state(slot_p);
+
+	/* check if the slot is not in the "enabled' state */
+	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
+		/* slot is in the 'disabled' state */
+		PCIE_DBG("pciehpc_slot_poweroff(): "
+		    "slot %d already disabled\n", slot_p->hs_phy_slot_num);
+		ASSERT(slot_p->hs_power_led_state == PCIE_HP_LED_OFF);
+
+		*result = slot_p->hs_info.cn_state;
+		return (DDI_SUCCESS);
+	}
+
+	/* read the Slot Status Register */
+	status =  pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
+
+	/* make sure the slot has a device present */
+	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
+		/* slot is empty */
+		PCIE_DBG("pciehpc_slot_poweroff(): slot %d is empty\n",
+		    slot_p->hs_phy_slot_num);
+		goto cleanup;
+	}
+
+	/*
+	 * Disable power to the slot involves:
+	 *	1. Set power LED to blink.
+	 *	2. Set power control OFF in Slot Control Reigster and
+	 *	   wait for Command Completed Interrupt or 1 sec timeout.
+	 *	3. Set POWER led and ATTN led to be OFF.
+	 */
+
+	/* 1. set power LED to blink */
+	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
+
+	/* disable power fault detection interrupt */
+	control = pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+	control &= ~PCIE_SLOTCTL_PWR_FAULT_EN;
+	pciehpc_issue_hpc_command(ctrl_p, control);
+
+	/* 2. set power control to OFF */
+	control =  pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+	control |= PCIE_SLOTCTL_PWR_CONTROL;
+	pciehpc_issue_hpc_command(ctrl_p, control);
+
+#ifdef DEBUG
+	/* check for power control bit to be OFF */
+	control =  pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+	ASSERT(control & PCIE_SLOTCTL_PWR_CONTROL);
+#endif
+
+	/* 3. Set power LED to be OFF */
+	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
+	pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
+
+	/* if EMI is present, turn it OFF */
+	if (ctrl_p->hc_has_emi_lock) {
+		status =  pciehpc_reg_get16(ctrl_p,
+		    bus_p->bus_pcie_off + PCIE_SLOTSTS);
+
+		if (status & PCIE_SLOTSTS_EMI_LOCK_SET) {
+			control =  pciehpc_reg_get16(ctrl_p,
+			    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+			control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
+			pciehpc_issue_hpc_command(ctrl_p, control);
+
+			/* wait 1 sec after toggling the state of EMI lock */
+			delay(drv_usectohz(1000000));
+		}
+	}
+
+	/* get the current state of the slot */
+	pciehpc_get_slot_state(slot_p);
+
+	*result = slot_p->hs_info.cn_state;
+
+	return (DDI_SUCCESS);
+
+cleanup:
+	return (DDI_FAILURE);
+}
+
+/*
+ * pciehpc_slot_probe()
+ *
+ * Probe the slot.
+ *
+ * Note: This function is called by DDI HP framework at kernel context only
+ */
+/*ARGSUSED*/
+static int
+pciehpc_slot_probe(pcie_hp_slot_t *slot_p)
+{
+	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
+	int		ret = DDI_SUCCESS;
+
+	mutex_enter(&ctrl_p->hc_mutex);
+
+	/* get the current state of the slot */
+	pciehpc_get_slot_state(slot_p);
+
+	/*
+	 * Probe a given PCIe Hotplug Connection (CN).
+	 */
+	PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
+	ret = pcie_hp_probe(slot_p);
+
+	if (ret != DDI_SUCCESS) {
+		PCIE_DBG("pciehpc_slot_probe() failed\n");
+
+		/* turn the ATTN led ON for configure failure */
+		pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_ON);
+
+		/* if power to the slot is still on then set Power led to ON */
+		if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
+			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
+			    PCIE_HP_LED_ON);
+
+		mutex_exit(&ctrl_p->hc_mutex);
+		return (DDI_FAILURE);
+	}
+
+	PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
+
+	/* get the current state of the slot */
+	pciehpc_get_slot_state(slot_p);
+
+	mutex_exit(&ctrl_p->hc_mutex);
+	return (DDI_SUCCESS);
+}
+
+/*
+ * pciehpc_slot_unprobe()
+ *
+ * Unprobe the slot.
+ *
+ * Note: This function is called by DDI HP framework at kernel context only
+ */
+/*ARGSUSED*/
+static int
+pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p)
+{
+	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
+	int		ret;
+
+	mutex_enter(&ctrl_p->hc_mutex);
+
+	/* get the current state of the slot */
+	pciehpc_get_slot_state(slot_p);
+
+	/*
+	 * Unprobe a given PCIe Hotplug Connection (CN).
+	 */
+	PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
+	ret = pcie_hp_unprobe(slot_p);
+
+	if (ret != DDI_SUCCESS) {
+		PCIE_DBG("pciehpc_slot_unprobe() failed\n");
+
+		/* if power to the slot is still on then set Power led to ON */
+		if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
+			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
+			    PCIE_HP_LED_ON);
+
+		PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
+
+		mutex_exit(&ctrl_p->hc_mutex);
+		return (DDI_FAILURE);
+	}
+
+	/* get the current state of the slot */
+	pciehpc_get_slot_state(slot_p);
+
+	mutex_exit(&ctrl_p->hc_mutex);
+	return (DDI_SUCCESS);
+}
+
+static int
+pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
+    ddi_hp_cn_state_t target_state)
+{
+	ddi_hp_cn_state_t curr_state;
+	int rv = DDI_SUCCESS;
+
+	if (target_state > DDI_HP_CN_STATE_ENABLED) {
+		return (DDI_EINVAL);
+	}
+
+	curr_state = slot_p->hs_info.cn_state;
+	while ((curr_state < target_state) && (rv == DDI_SUCCESS)) {
+
+		switch (curr_state) {
+		case DDI_HP_CN_STATE_EMPTY:
+			/*
+			 * From EMPTY to PRESENT, just check the hardware
+			 * slot state.
+			 */
+			pciehpc_get_slot_state(slot_p);
+			curr_state = slot_p->hs_info.cn_state;
+			if (curr_state < DDI_HP_CN_STATE_PRESENT)
+				rv = DDI_FAILURE;
+			break;
+		case DDI_HP_CN_STATE_PRESENT:
+			rv = (slot_p->hs_ctrl->hc_ops.poweron_hpc_slot)(slot_p,
+			    &curr_state);
+
+			break;
+		case DDI_HP_CN_STATE_POWERED:
+			curr_state = slot_p->hs_info.cn_state =
+			    DDI_HP_CN_STATE_ENABLED;
+			break;
+		default:
+			/* should never reach here */
+			ASSERT("unknown devinfo state");
+		}
+	}
+
+	return (rv);
+}
+
+static int
+pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
+    ddi_hp_cn_state_t target_state)
+{
+	ddi_hp_cn_state_t curr_state;
+	int rv = DDI_SUCCESS;
+
+
+	curr_state = slot_p->hs_info.cn_state;
+	while ((curr_state > target_state) && (rv == DDI_SUCCESS)) {
+
+		switch (curr_state) {
+		case DDI_HP_CN_STATE_PRESENT:
+			/*
+			 * From PRESENT to EMPTY, just check hardware slot
+			 * state.
+			 */
+			pciehpc_get_slot_state(slot_p);
+			curr_state = slot_p->hs_info.cn_state;
+			if (curr_state >= DDI_HP_CN_STATE_PRESENT)
+				rv = DDI_FAILURE;
+			break;
+		case DDI_HP_CN_STATE_POWERED:
+			rv = (slot_p->hs_ctrl->hc_ops.poweroff_hpc_slot)(
+			    slot_p, &curr_state);
+
+			break;
+		case DDI_HP_CN_STATE_ENABLED:
+			curr_state = slot_p->hs_info.cn_state =
+			    DDI_HP_CN_STATE_POWERED;
+
+			break;
+		default:
+			/* should never reach here */
+			ASSERT("unknown devinfo state");
+		}
+	}
+
+	return (rv);
+}
+
+/* Change slot state to a target state */
+static int
+pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
+    ddi_hp_cn_state_t target_state)
+{
+	ddi_hp_cn_state_t curr_state;
+	int rv;
+
+	pciehpc_get_slot_state(slot_p);
+	curr_state = slot_p->hs_info.cn_state;
+
+	if (curr_state == target_state) {
+		return (DDI_SUCCESS);
+	}
+	if (curr_state < target_state) {
+
+		rv = pciehpc_upgrade_slot_state(slot_p, target_state);
+	} else {
+		rv = pciehpc_downgrade_slot_state(slot_p, target_state);
+	}
+
+	return (rv);
+}
+
+int
+pciehpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
+    ddi_hp_property_t *rval)
+{
+	ddi_hp_property_t request, result;
+#ifdef _SYSCALL32_IMPL
+	ddi_hp_property32_t request32, result32;
+#endif
+	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
+	nvlist_t	*prop_list;
+	nvlist_t	*prop_rlist; /* nvlist for return values */
+	nvpair_t	*prop_pair;
+	char		*name, *value;
+	int		ret = DDI_SUCCESS;
+	int		i, n;
+	boolean_t	get_all_prop = B_FALSE;
+
+	if (get_udatamodel() == DATAMODEL_NATIVE) {
+		if (copyin(arg, &request, sizeof (ddi_hp_property_t)) ||
+		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
+			return (DDI_FAILURE);
+	}
+#ifdef _SYSCALL32_IMPL
+	else {
+		bzero(&request, sizeof (request));
+		bzero(&result, sizeof (result));
+		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) ||
+		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
+			return (DDI_FAILURE);
+		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
+		request.buf_size = request32.buf_size;
+		result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf;
+		result.buf_size = result32.buf_size;
+	}
+#endif
+
+	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
+	    &prop_list)) != DDI_SUCCESS)
+		return (ret);
+
+	if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
+		ret = DDI_ENOMEM;
+		goto get_prop_cleanup;
+	}
+
+	/* check whether the requested property is "all" or "help" */
+	prop_pair = nvlist_next_nvpair(prop_list, NULL);
+	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) {
+		name = nvpair_name(prop_pair);
+		n = sizeof (pciehpc_props) / sizeof (pciehpc_prop_t);
+
+		if (strcmp(name, PCIEHPC_PROP_ALL) == 0) {
+			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL);
+
+			/*
+			 * Add all properties into the request list, so that we
+			 * will get the values in the following for loop.
+			 */
+			for (i = 0; i < n; i++) {
+				if (nvlist_add_string(prop_list,
+				    pciehpc_props[i].prop_name, "") != 0) {
+					ret = DDI_FAILURE;
+					goto get_prop_cleanup1;
+				}
+			}
+			get_all_prop = B_TRUE;
+		} else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) {
+			/*
+			 * Empty the request list, and add help strings into the
+			 * return list. We will pass the following for loop.
+			 */
+			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP);
+
+			for (i = 0; i < n; i++) {
+				if (nvlist_add_string(prop_rlist,
+				    pciehpc_props[i].prop_name,
+				    pciehpc_props[i].prop_value) != 0) {
+					ret = DDI_FAILURE;
+					goto get_prop_cleanup1;
+				}
+			}
+		}
+	}
+
+	mutex_enter(&ctrl_p->hc_mutex);
+
+	/* get the current slot state */
+	pciehpc_get_slot_state(slot_p);
+
+	/* for each requested property, get the value and add it to nvlist */
+	prop_pair = NULL;
+	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
+		name = nvpair_name(prop_pair);
+
+		if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) {
+			value = pcie_led_state_text(
+			    slot_p->hs_fault_led_state);
+		} else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) {
+			value = pcie_led_state_text(
+			    slot_p->hs_power_led_state);
+		} else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
+			value = pcie_led_state_text(
+			    slot_p->hs_attn_led_state);
+		} else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) {
+			value = pcie_led_state_text(
+			    slot_p->hs_active_led_state);
+		} else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) {
+			ddi_acc_handle_t handle;
+			dev_info_t	*cdip;
+			uint8_t		prog_class, base_class, sub_class;
+			int		i;
+
+			mutex_exit(&ctrl_p->hc_mutex);
+			cdip = pcie_hp_devi_find(
+			    ctrl_p->hc_dip, slot_p->hs_device_num, 0);
+			mutex_enter(&ctrl_p->hc_mutex);
+
+			if ((slot_p->hs_info.cn_state
+			    != DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) {
+				/*
+				 * When getting all properties, just ignore the
+				 * one that's not available under certain state.
+				 */
+				if (get_all_prop)
+					continue;
+
+				ret = DDI_ENOTSUP;
+				goto get_prop_cleanup2;
+			}
+
+			if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) {
+				ret = DDI_FAILURE;
+				goto get_prop_cleanup2;
+			}
+
+			prog_class = pci_config_get8(handle,
+			    PCI_CONF_PROGCLASS);
+			base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
+			sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
+			pci_config_teardown(&handle);
+
+			for (i = 0; i < class_pci_items; i++) {
+				if ((base_class == class_pci[i].base_class) &&
+				    (sub_class == class_pci[i].sub_class) &&
+				    (prog_class == class_pci[i].prog_class)) {
+					value = class_pci[i].short_desc;
+					break;
+				}
+			}
+			if (i == class_pci_items)
+				value = PCIEHPC_PROP_VALUE_UNKNOWN;
+		} else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) {
+			if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY)
+				value = PCIEHPC_PROP_VALUE_UNKNOWN;
+			else
+				value = PCIEHPC_PROP_VALUE_PCIHOTPLUG;
+		} else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) {
+			value = pcie_slot_condition_text(slot_p->hs_condition);
+		} else {
+			/* unsupported property */
+			cmn_err(CE_WARN, "Unsupported property: %s\n", name);
+
+			ret = DDI_ENOTSUP;
+			goto get_prop_cleanup2;
+		}
+		if (nvlist_add_string(prop_rlist, name, value) != 0) {
+			ret = DDI_FAILURE;
+			goto get_prop_cleanup2;
+		}
+	}
+
+	/* pack nvlist and copyout */
+	if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
+	    &result.buf_size)) != DDI_SUCCESS) {
+		goto get_prop_cleanup2;
+	}
+	if (get_udatamodel() == DATAMODEL_NATIVE) {
+		if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
+			ret = DDI_FAILURE;
+	}
+#ifdef _SYSCALL32_IMPL
+	else {
+		if (result.buf_size > UINT32_MAX) {
+			ret = DDI_FAILURE;
+		} else {
+			result32.buf_size = (uint32_t)result.buf_size;
+			if (copyout(&result32, rval,
+			    sizeof (ddi_hp_property32_t)))
+				ret = DDI_FAILURE;
+		}
+	}
+#endif
+
+get_prop_cleanup2:
+	mutex_exit(&ctrl_p->hc_mutex);
+get_prop_cleanup1:
+	nvlist_free(prop_rlist);
+get_prop_cleanup:
+	nvlist_free(prop_list);
+	return (ret);
+}
+
+int
+pciehpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
+    ddi_hp_property_t *rval)
+{
+	ddi_hp_property_t	request, result;
+#ifdef _SYSCALL32_IMPL
+	ddi_hp_property32_t	request32, result32;
+#endif
+	pcie_hp_ctrl_t		*ctrl_p = slot_p->hs_ctrl;
+	nvlist_t		*prop_list;
+	nvlist_t		*prop_rlist;
+	nvpair_t		*prop_pair;
+	char			*name, *value;
+	pcie_hp_led_state_t	led_state;
+	int			ret = DDI_SUCCESS;
+
+	if (get_udatamodel() == DATAMODEL_NATIVE) {
+		if (copyin(arg, &request, sizeof (ddi_hp_property_t)))
+			return (DDI_FAILURE);
+		if (rval &&
+		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
+			return (DDI_FAILURE);
+	}
+#ifdef _SYSCALL32_IMPL
+	else {
+		bzero(&request, sizeof (request));
+		bzero(&result, sizeof (result));
+		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)))
+			return (DDI_FAILURE);
+		if (rval &&
+		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
+			return (DDI_FAILURE);
+		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
+		request.buf_size = request32.buf_size;
+		if (rval) {
+			result.nvlist_buf =
+			    (char *)(uintptr_t)result32.nvlist_buf;
+			result.buf_size = result32.buf_size;
+		}
+	}
+#endif
+
+	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
+	    &prop_list)) != DDI_SUCCESS)
+		return (ret);
+
+	/* check whether the requested property is "help" */
+	prop_pair = nvlist_next_nvpair(prop_list, NULL);
+	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) &&
+	    (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) {
+		if (!rval) {
+			ret = DDI_ENOTSUP;
+			goto set_prop_cleanup;
+		}
+
+		if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
+			ret = DDI_ENOMEM;
+			goto set_prop_cleanup;
+		}
+		if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN,
+		    PCIEHPC_PROP_VALUE_LED) != 0) {
+			ret = DDI_FAILURE;
+			goto set_prop_cleanup1;
+		}
+
+		if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
+		    &result.buf_size)) != DDI_SUCCESS) {
+			goto set_prop_cleanup1;
+		}
+		if (get_udatamodel() == DATAMODEL_NATIVE) {
+			if (copyout(&result, rval,
+			    sizeof (ddi_hp_property_t))) {
+				ret =  DDI_FAILURE;
+				goto set_prop_cleanup1;
+			}
+		}
+#ifdef _SYSCALL32_IMPL
+		else {
+			if (result.buf_size > UINT32_MAX) {
+				ret =  DDI_FAILURE;
+				goto set_prop_cleanup1;
+			} else {
+				result32.buf_size = (uint32_t)result.buf_size;
+				if (copyout(&result32, rval,
+				    sizeof (ddi_hp_property32_t))) {
+					ret =  DDI_FAILURE;
+					goto set_prop_cleanup1;
+				}
+			}
+		}
+#endif
+set_prop_cleanup1:
+		nvlist_free(prop_rlist);
+		nvlist_free(prop_list);
+		return (ret);
+	}
+
+	/* Validate the request */
+	prop_pair = NULL;
+	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
+		name = nvpair_name(prop_pair);
+		if (nvpair_type(prop_pair) != DATA_TYPE_STRING) {
+			cmn_err(CE_WARN, "Unexpected data type of setting "
+			    "property %s.\n", name);
+			ret = DDI_EINVAL;
+			goto set_prop_cleanup;
+		}
+		if (nvpair_value_string(prop_pair, &value)) {
+			cmn_err(CE_WARN, "Get string value failed for property "
+			    "%s.\n", name);
+			ret = DDI_FAILURE;
+			goto set_prop_cleanup;
+		}
+
+		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
+			if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) &&
+			    (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) &&
+			    (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) {
+				cmn_err(CE_WARN, "Unsupported value of setting "
+				    "property %s\n", name);
+				ret = DDI_ENOTSUP;
+				goto set_prop_cleanup;
+			}
+		} else {
+			cmn_err(CE_WARN, "Unsupported property: %s\n", name);
+			ret = DDI_ENOTSUP;
+			goto set_prop_cleanup;
+		}
+	}
+	mutex_enter(&ctrl_p->hc_mutex);
+
+	/* get the current slot state */
+	pciehpc_get_slot_state(slot_p);
+
+	/* set each property */
+	prop_pair = NULL;
+	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
+		name = nvpair_name(prop_pair);
+
+		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
+			if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0)
+				led_state = PCIE_HP_LED_ON;
+			else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0)
+				led_state = PCIE_HP_LED_OFF;
+			else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0)
+				led_state = PCIE_HP_LED_BLINK;
+
+			pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
+			    led_state);
+		}
+	}
+
+	mutex_exit(&ctrl_p->hc_mutex);
+set_prop_cleanup:
+	nvlist_free(prop_list);
+	return (ret);
+}
+
+/*
+ * Send a command to the PCI-E Hot Plug Controller.
+ *
+ * NOTES: The PCI-E spec defines the following semantics for issuing hot plug
+ * commands.
+ * 1) If Command Complete events/interrupts are supported then software
+ *    waits for Command Complete event after issuing a command (i.e writing
+ *    to the Slot Control register). The command completion could take as
+ *    long as 1 second so software should be prepared to wait for 1 second
+ *    before issuing another command.
+ *
+ * 2) If Command Complete events/interrupts are not supported then
+ *    software could issue multiple Slot Control writes without any delay
+ *    between writes.
+ */
+static void
+pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control)
+{
+	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+	uint16_t	status;
+	uint32_t	slot_cap;
+
+	/*
+	 * PCI-E version 1.1 spec defines No Command Completed
+	 * Support bit (bit#18) in Slot Capabilities register. If this
+	 * bit is set then slot doesn't support notification of command
+	 * completion events.
+	 */
+	slot_cap =  pciehpc_reg_get32(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCAP);
+
+	/*
+	 * If no Command Completion event is supported or it is ACPI
+	 * hot plug mode then just issue the command and return.
+	 */
+	if ((slot_cap & PCIE_SLOTCAP_NO_CMD_COMP_SUPP) ||
+	    (bus_p->bus_hp_curr_mode == PCIE_ACPI_HP_MODE)) {
+		pciehpc_reg_put16(ctrl_p,
+		    bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
+		return;
+	}
+
+	/*
+	 * **************************************
+	 * Command Complete events are supported.
+	 * **************************************
+	 */
+
+	/*
+	 * If HPC is not yet initialized then just poll for the Command
+	 * Completion interrupt.
+	 */
+	if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
+		int retry = PCIE_HP_CMD_WAIT_RETRY;
+
+		/* write the command to the HPC */
+		pciehpc_reg_put16(ctrl_p,
+		    bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
+
+		/* poll for status completion */
+		while (retry--) {
+			/* wait for 10 msec before checking the status */
+			delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME));
+
+			status = pciehpc_reg_get16(ctrl_p,
+			    bus_p->bus_pcie_off + PCIE_SLOTSTS);
+
+			if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
+				/* clear the status bits */
+				pciehpc_reg_put16(ctrl_p,
+				    bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
+				break;
+			}
+		}
+		return;
+	}
+
+	/* HPC is already initialized */
+
+	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
+
+	/*
+	 * If previous command is still pending then wait for its
+	 * completion. i.e cv_wait()
+	 */
+
+	while (ctrl_p->hc_cmd_pending == B_TRUE)
+		cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex);
+
+	/*
+	 * Issue the command and wait for Command Completion or
+	 * the 1 sec timeout.
+	 */
+	pciehpc_reg_put16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
+
+	ctrl_p->hc_cmd_pending = B_TRUE;
+
+	if (cv_timedwait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex,
+	    ddi_get_lbolt() + SEC_TO_TICK(1)) == -1) {
+
+		/* it is a timeout */
+		PCIE_DBG("pciehpc_issue_hpc_command: Command Complete"
+		    " interrupt is not received for slot %d\n",
+		    slot_p->hs_phy_slot_num);
+
+		/* clear the status info in case interrupts are disabled? */
+		status = pciehpc_reg_get16(ctrl_p,
+		    bus_p->bus_pcie_off + PCIE_SLOTSTS);
+
+		if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
+			/* clear the status bits */
+			pciehpc_reg_put16(ctrl_p,
+			    bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
+		}
+	}
+
+	ctrl_p->hc_cmd_pending = B_FALSE;
+
+	/* wake up any one waiting for issuing another command to HPC */
+	cv_signal(&ctrl_p->hc_cmd_comp_cv);
+}
+
+/*
+ * pciehcp_attn_btn_handler()
+ *
+ * This handles ATTN button pressed event as per the PCI-E 1.1 spec.
+ */
+static void
+pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p)
+{
+	pcie_hp_slot_t		*slot_p = ctrl_p->hc_slots[0];
+	pcie_hp_led_state_t	power_led_state;
+	callb_cpr_t		cprinfo;
+
+	PCIE_DBG("pciehpc_attn_btn_handler: thread started\n");
+
+	CALLB_CPR_INIT(&cprinfo, &ctrl_p->hc_mutex, callb_generic_cpr,
+	    "pciehpc_attn_btn_handler");
+
+	mutex_enter(&ctrl_p->hc_mutex);
+
+	/* wait for ATTN button event */
+	cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
+
+	while (slot_p->hs_attn_btn_thread_exit == B_FALSE) {
+		if (slot_p->hs_attn_btn_pending == B_TRUE) {
+			/* get the current state of power LED */
+			power_led_state = pciehpc_get_led_state(ctrl_p,
+			    PCIE_HP_POWER_LED);
+
+			/* Blink the Power LED while we wait for 5 seconds */
+			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
+			    PCIE_HP_LED_BLINK);
+
+			/* wait for 5 seconds before taking any action */
+			if (cv_timedwait(&slot_p->hs_attn_btn_cv,
+			    &ctrl_p->hc_mutex,
+			    ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) {
+				/*
+				 * It is a time out; make sure the ATTN pending
+				 * flag is still ON before sending the event to
+				 * DDI HP framework.
+				 */
+				if (slot_p->hs_attn_btn_pending == B_TRUE) {
+					int hint;
+
+					slot_p->hs_attn_btn_pending = B_FALSE;
+					pciehpc_get_slot_state(slot_p);
+
+					if (slot_p->hs_info.cn_state <=
+					    DDI_HP_CN_STATE_PRESENT) {
+						/*
+						 * Insertion.
+						 */
+						hint = SE_INCOMING_RES;
+					} else {
+						/*
+						 * Want to remove;
+						 */
+						hint = SE_OUTGOING_RES;
+					}
+
+					/*
+					 * We can't call ddihp_cn_gen_sysevent
+					 * here since it's not a DDI interface.
+					 */
+					pcie_hp_gen_sysevent_req(
+					    slot_p->hs_info.cn_name,
+					    hint,
+					    ctrl_p->hc_dip,
+					    KM_SLEEP);
+				}
+			}
+
+			/* restore the power LED state */
+			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
+			    power_led_state);
+			continue;
+		}
+
+		/* wait for another ATTN button event */
+		cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
+	}
+
+	PCIE_DBG("pciehpc_attn_btn_handler: thread exit\n");
+	cv_signal(&slot_p->hs_attn_btn_cv);
+	CALLB_CPR_EXIT(&cprinfo);
+	thread_exit();
+}
+
+/*
+ * convert LED state from PCIE HPC definition to pcie_hp_led_state_t
+ * definition.
+ */
+static pcie_hp_led_state_t
+pciehpc_led_state_to_hpc(uint16_t state)
+{
+	switch (state) {
+	case PCIE_SLOTCTL_INDICATOR_STATE_ON:
+		return (PCIE_HP_LED_ON);
+	case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
+		return (PCIE_HP_LED_BLINK);
+	case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
+	default:
+		return (PCIE_HP_LED_OFF);
+	}
+}
+
+/*
+ * Get the state of an LED.
+ */
+static pcie_hp_led_state_t
+pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led)
+{
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+	uint16_t	control, state;
+
+	/* get the current state of Slot Control register */
+	control =  pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+
+	switch (led) {
+	case PCIE_HP_POWER_LED:
+		state = pcie_slotctl_pwr_indicator_get(control);
+		break;
+	case PCIE_HP_ATTN_LED:
+		state = pcie_slotctl_attn_indicator_get(control);
+		break;
+	default:
+		PCIE_DBG("pciehpc_get_led_state() invalid LED %d\n", led);
+		return (PCIE_HP_LED_OFF);
+	}
+
+	switch (state) {
+	case PCIE_SLOTCTL_INDICATOR_STATE_ON:
+		return (PCIE_HP_LED_ON);
+
+	case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
+		return (PCIE_HP_LED_BLINK);
+
+	case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
+	default:
+		return (PCIE_HP_LED_OFF);
+	}
+}
+
+/*
+ * Set the state of an LED. It updates both hw and sw state.
+ */
+static void
+pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
+    pcie_hp_led_state_t state)
+{
+	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+	uint16_t	control;
+
+	/* get the current state of Slot Control register */
+	control =  pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+
+	switch (led) {
+	case PCIE_HP_POWER_LED:
+		/* clear led mask */
+		control &= ~PCIE_SLOTCTL_PWR_INDICATOR_MASK;
+		slot_p->hs_power_led_state = state;
+		break;
+	case PCIE_HP_ATTN_LED:
+		/* clear led mask */
+		control &= ~PCIE_SLOTCTL_ATTN_INDICATOR_MASK;
+		slot_p->hs_attn_led_state = state;
+		break;
+	default:
+		PCIE_DBG("pciehpc_set_led_state() invalid LED %d\n", led);
+		return;
+	}
+
+	switch (state) {
+	case PCIE_HP_LED_ON:
+		if (led == PCIE_HP_POWER_LED)
+			control = pcie_slotctl_pwr_indicator_set(control,
+			    PCIE_SLOTCTL_INDICATOR_STATE_ON);
+		else if (led == PCIE_HP_ATTN_LED)
+			control = pcie_slotctl_attn_indicator_set(control,
+			    PCIE_SLOTCTL_INDICATOR_STATE_ON);
+		break;
+	case PCIE_HP_LED_OFF:
+		if (led == PCIE_HP_POWER_LED)
+			control = pcie_slotctl_pwr_indicator_set(control,
+			    PCIE_SLOTCTL_INDICATOR_STATE_OFF);
+		else if (led == PCIE_HP_ATTN_LED)
+			control = pcie_slotctl_attn_indicator_set(control,
+			    PCIE_SLOTCTL_INDICATOR_STATE_OFF);
+		break;
+	case PCIE_HP_LED_BLINK:
+		if (led == PCIE_HP_POWER_LED)
+			control = pcie_slotctl_pwr_indicator_set(control,
+			    PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
+		else if (led == PCIE_HP_ATTN_LED)
+			control = pcie_slotctl_attn_indicator_set(control,
+			    PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
+		break;
+
+	default:
+		PCIE_DBG("pciehpc_set_led_state() invalid LED state %d\n",
+		    state);
+		return;
+	}
+
+	/* update the Slot Control Register */
+	pciehpc_issue_hpc_command(ctrl_p, control);
+
+#ifdef DEBUG
+	/* get the current state of Slot Control register */
+	control =  pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+
+	PCIE_DBG("pciehpc_set_led_state: slot %d power-led %s attn-led %s\n",
+	    slot_p->hs_phy_slot_num, pcie_led_state_text(
+	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))),
+	    pcie_led_state_text(pciehpc_led_state_to_hpc(
+	    pcie_slotctl_attn_indicator_get(control))));
+#endif
+}
+
+#ifdef DEBUG
+/*
+ * Dump PCI-E Hot Plug registers.
+ */
+static void
+pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p)
+{
+	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+	uint16_t	control;
+	uint32_t	capabilities;
+
+	if (!pcie_debug_flags)
+		return;
+
+	capabilities = pciehpc_reg_get32(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCAP);
+
+	control =  pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+
+	PCIE_DBG("pciehpc_dump_hpregs: Found PCI-E hot plug slot %d\n",
+	    slot_p->hs_phy_slot_num);
+
+	PCIE_DBG("Attention Button Present = %s\n",
+	    capabilities & PCIE_SLOTCAP_ATTN_BUTTON ? "Yes":"No");
+
+	PCIE_DBG("Power controller Present = %s\n",
+	    capabilities & PCIE_SLOTCAP_POWER_CONTROLLER ? "Yes":"No");
+
+	PCIE_DBG("MRL Sensor Present	   = %s\n",
+	    capabilities & PCIE_SLOTCAP_MRL_SENSOR ? "Yes":"No");
+
+	PCIE_DBG("Attn Indicator Present   = %s\n",
+	    capabilities & PCIE_SLOTCAP_ATTN_INDICATOR ? "Yes":"No");
+
+	PCIE_DBG("Power Indicator Present  = %s\n",
+	    capabilities & PCIE_SLOTCAP_PWR_INDICATOR ? "Yes":"No");
+
+	PCIE_DBG("HotPlug Surprise	   = %s\n",
+	    capabilities & PCIE_SLOTCAP_HP_SURPRISE ? "Yes":"No");
+
+	PCIE_DBG("HotPlug Capable	   = %s\n",
+	    capabilities & PCIE_SLOTCAP_HP_CAPABLE ? "Yes":"No");
+
+	PCIE_DBG("Physical Slot Number	   = %d\n",
+	    PCIE_SLOTCAP_PHY_SLOT_NUM(capabilities));
+
+	PCIE_DBG("Attn Button interrupt Enabled  = %s\n",
+	    control & PCIE_SLOTCTL_ATTN_BTN_EN ? "Yes":"No");
+
+	PCIE_DBG("Power Fault interrupt Enabled  = %s\n",
+	    control & PCIE_SLOTCTL_PWR_FAULT_EN ? "Yes":"No");
+
+	PCIE_DBG("MRL Sensor INTR Enabled   = %s\n",
+	    control & PCIE_SLOTCTL_MRL_SENSOR_EN ? "Yes":"No");
+
+	PCIE_DBG("Presence interrupt Enabled	 = %s\n",
+	    control & PCIE_SLOTCTL_PRESENCE_CHANGE_EN ? "Yes":"No");
+
+	PCIE_DBG("Cmd Complete interrupt Enabled = %s\n",
+	    control & PCIE_SLOTCTL_CMD_INTR_EN ? "Yes":"No");
+
+	PCIE_DBG("HotPlug interrupt Enabled	 = %s\n",
+	    control & PCIE_SLOTCTL_HP_INTR_EN ? "Yes":"No");
+
+	PCIE_DBG("Power Indicator LED = %s", pcie_led_state_text(
+	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))));
+
+	PCIE_DBG("Attn Indicator LED = %s\n",
+	    pcie_led_state_text(pciehpc_led_state_to_hpc(
+	    pcie_slotctl_attn_indicator_get(control))));
+}
+#endif	/* DEBUG */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/pciex/hotplug/pcishpc.c	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,2645 @@
+/*
+ * 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 file contains PCI HotPlug functionality that is compatible with the
+ * PCI SHPC specification 1.x.
+ *
+ * NOTE: This file is compiled and delivered through misc/pcie module.
+ */
+
+#include <sys/note.h>
+#include <sys/conf.h>
+#include <sys/kmem.h>
+#include <sys/kstat.h>
+#include <sys/debug.h>
+#include <sys/vtrace.h>
+#include <sys/autoconf.h>
+#include <sys/varargs.h>
+#include <sys/hwconf.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/callb.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/sysevent/dr.h>
+#include <sys/ndi_impldefs.h>
+#include <sys/pci_impl.h>
+#include <sys/hotplug/pci/pcie_hp.h>
+#include <sys/hotplug/pci/pcishpc.h>
+
+typedef struct pcishpc_prop {
+	char	*prop_name;
+	char	*prop_value;
+} pcishpc_prop_t;
+
+static pcishpc_prop_t	pcishpc_props[] = {
+	{ PCIEHPC_PROP_LED_FAULT,	PCIEHPC_PROP_VALUE_LED },
+	{ PCIEHPC_PROP_LED_POWER,	PCIEHPC_PROP_VALUE_LED },
+	{ PCIEHPC_PROP_LED_ATTN,	PCIEHPC_PROP_VALUE_LED },
+	{ PCIEHPC_PROP_LED_ACTIVE,	PCIEHPC_PROP_VALUE_LED },
+	{ PCIEHPC_PROP_CARD_TYPE,	PCIEHPC_PROP_VALUE_TYPE },
+	{ PCIEHPC_PROP_BOARD_TYPE,	PCIEHPC_PROP_VALUE_TYPE },
+	{ PCIEHPC_PROP_SLOT_CONDITION,	PCIEHPC_PROP_VALUE_TYPE }
+};
+
+/* reset delay to 1 sec. */
+static int pcishpc_reset_delay = 1000000;
+
+/* Local function prototype */
+static pcie_hp_ctrl_t *pcishpc_create_controller(dev_info_t *dip);
+static int	pcishpc_setup_controller(pcie_hp_ctrl_t *ctrl_p);
+static int	pcishpc_destroy_controller(dev_info_t *dip);
+static pcie_hp_slot_t	*pcishpc_create_slot(pcie_hp_ctrl_t *ctrl_p);
+static int	pcishpc_register_slot(pcie_hp_ctrl_t *ctrl_p, int slot);
+static int	pcishpc_destroy_slots(pcie_hp_ctrl_t *ctrl_p);
+static int	pcishpc_enable_irqs(pcie_hp_ctrl_t *ctrl_p);
+static int	pcishpc_disable_irqs(pcie_hp_ctrl_t *ctrl_p);
+static int	pcishpc_slot_get_property(pcie_hp_slot_t *slot_p,
+		    ddi_hp_property_t *arg, ddi_hp_property_t *rval);
+static int	pcishpc_slot_set_property(pcie_hp_slot_t *slot_p,
+		    ddi_hp_property_t *arg, ddi_hp_property_t *rval);
+static int	pcishpc_issue_command(pcie_hp_ctrl_t *ctrl_p,
+		    uint32_t cmd_code);
+static int	pcishpc_wait_busy(pcie_hp_ctrl_t *ctrl_p);
+static void	pcishpc_attn_btn_handler(pcie_hp_slot_t *slot_p);
+static void	pcishpc_get_slot_state(pcie_hp_slot_t *slot_p);
+static int	pcishpc_set_slot_state(pcie_hp_slot_t *slot_p,
+		    ddi_hp_cn_state_t new_slot_state);
+static void	pcishpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p, int slot);
+static int	pcishpc_set_bus_speed(pcie_hp_slot_t *slot_p);
+static int	pcishpc_setled(pcie_hp_slot_t *slot_p, pcie_hp_led_t led,
+		    pcie_hp_led_state_t state);
+static int	pcishpc_led_shpc_to_hpc(int state);
+static int	pcishpc_led_hpc_to_shpc(int state);
+static int	pcishpc_slot_shpc_to_hpc(int shpc_state);
+static int	pcishpc_slot_hpc_to_shpc(int state);
+static char	*pcishpc_slot_textslotstate(ddi_hp_cn_state_t state);
+static char	*pcishpc_slot_textledstate(pcie_hp_led_state_t state);
+
+static uint32_t	pcishpc_read_reg(pcie_hp_ctrl_t *ctrl_p, int reg);
+static void	pcishpc_write_reg(pcie_hp_ctrl_t *ctrl_p, int reg,
+		    uint32_t data);
+
+static int	pcishpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
+		    ddi_hp_cn_state_t target_state);
+static int	pcishpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
+		    ddi_hp_cn_state_t target_state);
+static int	pcishpc_change_slot_state(pcie_hp_slot_t *slot_p,
+		    ddi_hp_cn_state_t target_state);
+
+static int	pcishpc_slot_poweron(pcie_hp_slot_t *slot_p,
+		    ddi_hp_cn_state_t *result_state);
+static int	pcishpc_slot_poweroff(pcie_hp_slot_t *slot_p,
+		    ddi_hp_cn_state_t *result_state);
+static int	pcishpc_slot_probe(pcie_hp_slot_t *slot_p);
+static int	pcishpc_slot_unprobe(pcie_hp_slot_t *slot_p);
+#ifdef	DEBUG
+static void	pcishpc_dump_regs(pcie_hp_ctrl_t *ctrl_p);
+#endif	/* DEBUG */
+
+
+/*
+ * Global functions (called by other drivers/modules)
+ */
+
+/*
+ * pcishpc_init()
+ *
+ * Install and configure an SHPC controller and register the HotPlug slots
+ * with the Solaris HotPlug framework. This function is usually called by
+ * a PCI bridge Nexus driver that has a built in SHPC controller.
+ */
+int
+pcishpc_init(dev_info_t *dip)
+{
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
+	pcie_hp_ctrl_t	*ctrl_p;
+	int		i;
+
+	PCIE_DBG("pcishpc_init() called from %s#%d\n",
+	    ddi_driver_name(dip), ddi_get_instance(dip));
+
+	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) {
+		PCIE_DBG("pcishpc_init() shpc instance already "
+		    "initialized!\n");
+		return (DDI_SUCCESS);
+	}
+
+	/* Initialize soft state structure for the SHPC instance. */
+	ctrl_p = pcishpc_create_controller(dip);
+
+	if (ctrl_p == NULL) {
+		PCIE_DBG("pcishpc_init() failed to create shpc softstate\n");
+		return (DDI_FAILURE);
+	}
+
+	if (pcishpc_setup_controller(ctrl_p) != DDI_SUCCESS) {
+		PCIE_DBG("pcishpc_init() failed to setup controller\n");
+		goto cleanup;
+	}
+
+	/*
+	 * Setup resource maps for this bus node.
+	 */
+	(void) pci_resource_setup(dip);
+
+#ifdef	DEBUG
+	PCIE_DBG("%s%d: P2P bridge register dump:\n",
+	    ddi_driver_name(dip), ddi_get_instance(dip));
+
+	for (i = 0; i < 0x100; i += 4) {
+		PCIE_DBG("SHPC Cfg reg 0x%02x: %08x\n", i,
+		    pci_config_get32(bus_p->bus_cfg_hdl, i));
+	}
+#endif	/* DEBUG */
+
+	/* Setup each HotPlug slot on this SHPC controller. */
+	for (i = 0; i < ctrl_p->hc_num_slots_impl; i++) {
+		if (pcishpc_register_slot(ctrl_p, i) != DDI_SUCCESS) {
+			PCIE_DBG("pcishpc_init() failed to register "
+			    "slot %d\n", i);
+			goto cleanup1;
+		}
+		if (pcie_create_minor_node(ctrl_p, i) != DDI_SUCCESS) {
+			PCIE_DBG("pcishpc_init() failed to create "
+			    "minor node for slot %d\n", i);
+			goto cleanup1;
+		}
+	}
+
+	(void) pcishpc_enable_irqs(ctrl_p);
+
+#ifdef	DEBUG
+	/* Dump out the SHPC registers. */
+	pcishpc_dump_regs(ctrl_p);
+#endif	/* DEBUG */
+
+	PCIE_DBG("pcishpc_init() success(dip=%p)\n", dip);
+	return (DDI_SUCCESS);
+
+cleanup1:
+	for (i = 0; i < ctrl_p->hc_num_slots_impl; i++) {
+		if (ctrl_p->hc_slots[i] == NULL)
+			continue;
+
+		pcie_remove_minor_node(ctrl_p, i);
+	}
+	(void) pci_resource_destroy(dip);
+cleanup:
+	(void) pcishpc_destroy_controller(dip);
+	return (DDI_FAILURE);
+}
+
+/*
+ * pcishpc_uninit()
+ * Unload the HogPlug controller driver and deallocate all resources.
+ */
+int
+pcishpc_uninit(dev_info_t *dip)
+{
+	pcie_hp_ctrl_t *ctrl_p;
+	int i;
+
+	PCIE_DBG("pcishpc_uninit() called(dip=%p)\n", dip);
+
+	ctrl_p = PCIE_GET_HP_CTRL(dip);
+
+	if (!ctrl_p) {
+		PCIE_DBG("pcishpc_uninit() Unable to find softstate\n");
+		return (DDI_FAILURE);
+	}
+
+	for (i = 0; i < PCIE_HP_MAX_SLOTS; i++) {
+		if (ctrl_p->hc_slots[i] == NULL)
+			continue;
+
+		pcie_remove_minor_node(ctrl_p, i);
+	}
+
+	(void) pcishpc_disable_irqs(ctrl_p);
+	ctrl_p->hc_flags = 0;
+
+	/*
+	 * Destroy resource maps for this bus node.
+	 */
+	(void) pci_resource_destroy(dip);
+
+	(void) pcishpc_destroy_controller(dip);
+
+	PCIE_DBG("pcishpc_uninit() success(dip=%p)\n", dip);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * pcishpc_intr()
+ *
+ * This is the SHPC controller interrupt handler.
+ */
+int
+pcishpc_intr(dev_info_t *dip)
+{
+	pcie_hp_ctrl_t	*ctrl_p;
+	uint32_t	irq_locator, irq_serr_locator, reg;
+	int		slot;
+
+	PCIE_DBG("pcishpc_intr() called\n");
+
+	/* get the soft state structure for this dip */
+	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
+		return (DDI_INTR_UNCLAIMED);
+
+	mutex_enter(&ctrl_p->hc_mutex);
+
+	if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
+		PCIE_DBG("pcishpc_intr() unclaimed\n");
+		mutex_exit(&ctrl_p->hc_mutex);
+		return (DDI_INTR_UNCLAIMED);
+	}
+
+	PCIE_DBG("pcishpc_intr() interrupt received\n");
+
+	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
+
+	if (reg & PCI_HP_SERR_INT_CMD_COMPLETE_IRQ) {
+		PCIE_DBG("pcishpc_intr() "
+		    "PCI_HP_SERR_INT_CMD_COMPLETE_IRQ detected\n");
+		ctrl_p->hc_cmd_pending = B_FALSE;
+		cv_signal(&ctrl_p->hc_cmd_comp_cv);
+	}
+
+	if (reg & PCI_HP_SERR_INT_ARBITER_IRQ) {
+		PCIE_DBG("pcishpc_intr() PCI_HP_SERR_INT_ARBITER_IRQ "
+		    "detected\n");
+		ctrl_p->hc_arbiter_timeout = B_TRUE;
+	}
+
+	/* Write back the SERR INT register to acknowledge the IRQs. */
+	pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg);
+
+	irq_locator = pcishpc_read_reg(ctrl_p, PCI_HP_IRQ_LOCATOR_REG);
+	irq_serr_locator = pcishpc_read_reg(ctrl_p, PCI_HP_SERR_LOCATOR_REG);
+
+	/* Check for slot events that might have occured. */
+	for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) {
+		if ((irq_locator & (PCI_HP_IRQ_SLOT_N_PENDING<<slot)) ||
+		    (irq_serr_locator &
+		    (PCI_HP_IRQ_SERR_SLOT_N_PENDING<<slot))) {
+			PCIE_DBG("pcishpc_intr() slot %d and "
+			    "pending IRQ\n", slot+1);
+
+			reg = pcishpc_read_reg(ctrl_p,
+			    PCI_HP_LOGICAL_SLOT_REGS+slot);
+
+			if (reg & PCI_HP_SLOT_PRESENCE_DETECTED)
+				PCIE_DBG("slot %d: "
+				    "PCI_HP_SLOT_PRESENCE_DETECTED\n",
+				    slot+1);
+
+			if (reg & PCI_HP_SLOT_ISO_PWR_DETECTED)
+				PCIE_DBG("slot %d: "
+				    "PCI_HP_SLOT_ISO_PWR_DETECTED\n",
+				    slot+1);
+
+			if (reg & PCI_HP_SLOT_ATTN_DETECTED) {
+				PCIE_DBG("slot %d: "
+				    "PCI_HP_SLOT_ATTN_DETECTED\n", slot+1);
+
+				/*
+				 * if ATTN button event is still pending
+				 * then cancel it
+				 */
+				if (ctrl_p->hc_slots[slot]->
+				    hs_attn_btn_pending == B_TRUE)
+					ctrl_p->hc_slots[slot]->
+					    hs_attn_btn_pending = B_FALSE;
+
+				/* wake up the ATTN event handler */
+				cv_signal(&ctrl_p->hc_slots[slot]->
+				    hs_attn_btn_cv);
+			}
+
+			if (reg & PCI_HP_SLOT_MRL_DETECTED)
+				PCIE_DBG("slot %d: "
+				    "PCI_HP_SLOT_MRL_DETECTED\n", slot+1);
+
+			if (reg & PCI_HP_SLOT_POWER_DETECTED)
+				PCIE_DBG("slot %d: "
+				    "PCI_HP_SLOT_POWER_DETECTED\n", slot+1);
+
+			/* Acknoledge any slot interrupts */
+			pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot,
+			    reg);
+		}
+	}
+
+	mutex_exit(&ctrl_p->hc_mutex);
+
+	PCIE_DBG("pcishpc_intr() claimed\n");
+
+	return (DDI_INTR_CLAIMED);
+}
+
+int
+pcishpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
+    ddi_hp_property_t *rval)
+{
+	ddi_hp_property_t request, result;
+#ifdef _SYSCALL32_IMPL
+	ddi_hp_property32_t request32, result32;
+#endif
+	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
+	nvlist_t 	*prop_list;
+	nvlist_t	*prop_rlist; /* nvlist for return values */
+	nvpair_t 	*prop_pair;
+	char 		*name, *value;
+	int		ret = DDI_SUCCESS;
+	int		i, n;
+	boolean_t	get_all_prop = B_FALSE;
+
+	if (get_udatamodel() == DATAMODEL_NATIVE) {
+		if (copyin(arg, &request, sizeof (ddi_hp_property_t)) ||
+		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
+			return (DDI_FAILURE);
+	}
+#ifdef _SYSCALL32_IMPL
+	else {
+		bzero(&request, sizeof (request));
+		bzero(&result, sizeof (result));
+		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) ||
+		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
+			return (DDI_FAILURE);
+		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
+		request.buf_size = request32.buf_size;
+		result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf;
+		result.buf_size = result32.buf_size;
+	}
+#endif
+
+	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
+	    &prop_list)) != DDI_SUCCESS)
+		return (ret);
+
+	if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
+		ret = DDI_ENOMEM;
+		goto get_prop_cleanup;
+	}
+
+	/* check whether the requested property is "all" or "help" */
+	prop_pair = nvlist_next_nvpair(prop_list, NULL);
+	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) {
+		name = nvpair_name(prop_pair);
+		n = sizeof (pcishpc_props) / sizeof (pcishpc_prop_t);
+
+		if (strcmp(name, PCIEHPC_PROP_ALL) == 0) {
+			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL);
+
+			/*
+			 * Add all properties into the request list, so that we
+			 * will get the values in the following for loop.
+			 */
+			for (i = 0; i < n; i++) {
+				if (nvlist_add_string(prop_list,
+				    pcishpc_props[i].prop_name, "") != 0) {
+					ret = DDI_FAILURE;
+					goto get_prop_cleanup1;
+				}
+			}
+			get_all_prop = B_TRUE;
+		} else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) {
+			/*
+			 * Empty the request list, and add help strings into the
+			 * return list. We will pass the following for loop.
+			 */
+			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP);
+
+			for (i = 0; i < n; i++) {
+				if (nvlist_add_string(prop_rlist,
+				    pcishpc_props[i].prop_name,
+				    pcishpc_props[i].prop_value) != 0) {
+					ret = DDI_FAILURE;
+					goto get_prop_cleanup1;
+				}
+			}
+		}
+	}
+
+	mutex_enter(&ctrl_p->hc_mutex);
+
+	/* get the current slot state */
+	pcishpc_get_slot_state(slot_p);
+
+	/* for each requested property, get the value and add it to nvlist */
+	prop_pair = NULL;
+	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
+		name = nvpair_name(prop_pair);
+
+		if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) {
+			value = pcie_led_state_text(
+			    slot_p->hs_fault_led_state);
+		} else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) {
+			value = pcie_led_state_text(
+			    slot_p->hs_power_led_state);
+		} else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
+			value = pcie_led_state_text(
+			    slot_p->hs_attn_led_state);
+		} else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) {
+			value = pcie_led_state_text(
+			    slot_p->hs_active_led_state);
+		} else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) {
+			ddi_acc_handle_t	handle;
+			dev_info_t	*cdip;
+			uint8_t		prog_class, base_class, sub_class;
+			int		i;
+
+			mutex_exit(&ctrl_p->hc_mutex);
+			cdip = pcie_hp_devi_find(
+			    ctrl_p->hc_dip, slot_p->hs_device_num, 0);
+			mutex_enter(&ctrl_p->hc_mutex);
+
+			if ((slot_p->hs_info.cn_state !=
+			    DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) {
+				/*
+				 * When getting all properties, just ignore the
+				 * one that's not available under certain state.
+				 */
+				if (get_all_prop)
+					continue;
+
+				ret = DDI_ENOTSUP;
+				goto get_prop_cleanup2;
+			}
+
+			if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) {
+				ret = DDI_FAILURE;
+				goto get_prop_cleanup2;
+			}
+
+			prog_class = pci_config_get8(handle,
+			    PCI_CONF_PROGCLASS);
+			base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
+			sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
+			pci_config_teardown(&handle);
+
+			for (i = 0; i < class_pci_items; i++) {
+				if ((base_class == class_pci[i].base_class) &&
+				    (sub_class == class_pci[i].sub_class) &&
+				    (prog_class == class_pci[i].prog_class)) {
+					value = class_pci[i].short_desc;
+					break;
+				}
+			}
+			if (i == class_pci_items)
+				value = PCIEHPC_PROP_VALUE_UNKNOWN;
+		} else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) {
+			if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY)
+				value = PCIEHPC_PROP_VALUE_UNKNOWN;
+			else
+				value = PCIEHPC_PROP_VALUE_PCIHOTPLUG;
+		} else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) {
+			value = pcie_slot_condition_text(slot_p->hs_condition);
+		} else {
+			/* unsupported property */
+			cmn_err(CE_WARN, "Unsupported property: %s\n", name);
+
+			ret = DDI_ENOTSUP;
+			goto get_prop_cleanup2;
+		}
+		if (nvlist_add_string(prop_rlist, name, value) != 0) {
+			ret = DDI_FAILURE;
+			goto get_prop_cleanup2;
+		}
+	}
+
+	// pack nvlist and copyout
+	if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
+	    &result.buf_size)) != DDI_SUCCESS) {
+		goto get_prop_cleanup2;
+	}
+	if (get_udatamodel() == DATAMODEL_NATIVE) {
+		if (copyout(&result, rval, sizeof (ddi_hp_property_t))) {
+			ret = DDI_FAILURE;
+			goto get_prop_cleanup2;
+		}
+	}
+#ifdef _SYSCALL32_IMPL
+	else {
+		if (result.buf_size > UINT32_MAX) {
+			ret = DDI_FAILURE;
+		} else {
+			result32.buf_size = (uint32_t)result.buf_size;
+			if (copyout(&result32, rval,
+			    sizeof (ddi_hp_property32_t)))
+				ret = DDI_FAILURE;
+		}
+	}
+#endif
+
+get_prop_cleanup2:
+	mutex_exit(&ctrl_p->hc_mutex);
+get_prop_cleanup1:
+	nvlist_free(prop_rlist);
+get_prop_cleanup:
+	nvlist_free(prop_list);
+	return (ret);
+}
+
+int
+pcishpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
+    ddi_hp_property_t *rval)
+{
+	ddi_hp_property_t request, result;
+#ifdef _SYSCALL32_IMPL
+	ddi_hp_property32_t request32, result32;
+#endif
+	pcie_hp_ctrl_t		*ctrl_p = slot_p->hs_ctrl;
+	nvlist_t		*prop_list;
+	nvlist_t		*prop_rlist;
+	nvpair_t		*prop_pair;
+	char			*name, *value;
+	pcie_hp_led_state_t	led_state;
+	int			ret = DDI_SUCCESS;
+
+	if (get_udatamodel() == DATAMODEL_NATIVE) {
+		if (copyin(arg, &request, sizeof (ddi_hp_property_t)))
+			return (DDI_FAILURE);
+		if (rval &&
+		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
+			return (DDI_FAILURE);
+	}
+#ifdef _SYSCALL32_IMPL
+	else {
+		bzero(&request, sizeof (request));
+		bzero(&result, sizeof (result));
+		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)))
+			return (DDI_FAILURE);
+		if (rval &&
+		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
+			return (DDI_FAILURE);
+		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
+		request.buf_size = request32.buf_size;
+		if (rval) {
+			result.nvlist_buf =
+			    (char *)(uintptr_t)result32.nvlist_buf;
+			result.buf_size = result32.buf_size;
+		}
+	}
+#endif
+
+	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
+	    &prop_list)) != DDI_SUCCESS)
+		return (ret);
+
+	/* check whether the requested property is "help" */
+	prop_pair = nvlist_next_nvpair(prop_list, NULL);
+	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) &&
+	    (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) {
+		if (!rval) {
+			ret = DDI_ENOTSUP;
+			goto set_prop_cleanup;
+		}
+
+		if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
+			ret = DDI_ENOMEM;
+			goto set_prop_cleanup;
+		}
+		if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN,
+		    PCIEHPC_PROP_VALUE_LED) != 0) {
+			ret = DDI_FAILURE;
+			goto set_prop_cleanup1;
+		}
+
+		if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
+		    &result.buf_size)) != DDI_SUCCESS) {
+			goto set_prop_cleanup1;
+		}
+		if (get_udatamodel() == DATAMODEL_NATIVE) {
+			if (copyout(&result, rval,
+			    sizeof (ddi_hp_property_t))) {
+				ret =  DDI_FAILURE;
+				goto set_prop_cleanup1;
+			}
+		}
+#ifdef _SYSCALL32_IMPL
+		else {
+			if (result.buf_size > UINT32_MAX) {
+				ret =  DDI_FAILURE;
+				goto set_prop_cleanup1;
+			} else {
+				result32.buf_size = (uint32_t)result.buf_size;
+				if (copyout(&result32, rval,
+				    sizeof (ddi_hp_property32_t))) {
+					ret =  DDI_FAILURE;
+					goto set_prop_cleanup1;
+				}
+			}
+		}
+#endif
+set_prop_cleanup1:
+		nvlist_free(prop_rlist);
+		nvlist_free(prop_list);
+		return (ret);
+	}
+
+	/* Validate the request */
+	prop_pair = NULL;
+	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
+		name = nvpair_name(prop_pair);
+		if (nvpair_type(prop_pair) != DATA_TYPE_STRING) {
+			cmn_err(CE_WARN, "Unexpected data type of setting "
+			    "property %s.\n", name);
+			ret = DDI_EINVAL;
+			goto set_prop_cleanup;
+		}
+		if (nvpair_value_string(prop_pair, &value)) {
+			cmn_err(CE_WARN, "Get string value failed for property "
+			    "%s.\n", name);
+			ret = DDI_FAILURE;
+			goto set_prop_cleanup;
+		}
+
+		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
+			if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) &&
+			    (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) &&
+			    (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) {
+				cmn_err(CE_WARN, "Unsupported value of setting "
+				    "property %s\n", name);
+				ret = DDI_ENOTSUP;
+				goto set_prop_cleanup;
+			}
+		} else {
+			cmn_err(CE_WARN, "Unsupported property: %s\n", name);
+			ret = DDI_ENOTSUP;
+			goto set_prop_cleanup;
+		}
+	}
+
+	mutex_enter(&ctrl_p->hc_mutex);
+
+	/* get the current slot state */
+	pcishpc_get_slot_state(slot_p);
+
+	// set each property
+	prop_pair = NULL;
+	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
+		name = nvpair_name(prop_pair);
+
+		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
+			if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0)
+				led_state = PCIE_HP_LED_ON;
+			else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0)
+				led_state = PCIE_HP_LED_OFF;
+			else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0)
+				led_state = PCIE_HP_LED_BLINK;
+
+			(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED,
+			    led_state);
+		}
+	}
+
+	mutex_exit(&ctrl_p->hc_mutex);
+set_prop_cleanup:
+	nvlist_free(prop_list);
+	return (ret);
+}
+
+/*
+ * pcishpc_hp_ops()
+ *
+ * Handle hotplug commands
+ *
+ * Note: This function is called by DDI HP framework at kernel context only
+ */
+/* ARGSUSED */
+int
+pcishpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
+    void *arg, void *result)
+{
+	pcie_hp_slot_t	*slot_p = NULL;
+	pcie_hp_ctrl_t	*ctrl_p;
+	int		ret = DDI_SUCCESS, i;
+
+	PCIE_DBG("pcishpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n",
+	    dip, cn_name, op, arg);
+
+	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
+		return (DDI_FAILURE);
+
+	for (i = 0; i < PCIE_HP_MAX_SLOTS && ctrl_p->hc_slots[i]; i++) {
+		if (strcmp(ctrl_p->hc_slots[i]->hs_info.cn_name, cn_name)
+		    == 0) {
+			/* Match with a physical slot, found */
+			slot_p = ctrl_p->hc_slots[i];
+			break;
+		}
+	}
+	if (!slot_p) {
+		PCIE_DBG("pcishpc_hp_ops: Failed to find the slot under"
+		    "dip %p with name: %s; op=%x arg=%p\n",
+		    dip, cn_name, op, arg);
+		return (DDI_EINVAL);
+	}
+	switch (op) {
+	case DDI_HPOP_CN_GET_STATE:
+	{
+		mutex_enter(&ctrl_p->hc_mutex);
+
+		/* get the current slot state */
+		pcishpc_get_slot_state(slot_p);
+
+		*((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
+
+		mutex_exit(&ctrl_p->hc_mutex);
+		break;
+	}
+	case DDI_HPOP_CN_CHANGE_STATE:
+	{
+		ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
+
+		mutex_enter(&slot_p->hs_ctrl->hc_mutex);
+
+		ret = pcishpc_change_slot_state(slot_p, target_state);
+		*((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
+
+		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
+		break;
+	}
+	case DDI_HPOP_CN_PROBE:
+		ret = pcishpc_slot_probe(slot_p);
+
+		break;
+	case DDI_HPOP_CN_UNPROBE:
+		ret = pcishpc_slot_unprobe(slot_p);
+
+		break;
+	case DDI_HPOP_CN_GET_PROPERTY:
+		ret = pcishpc_slot_get_property(slot_p,
+		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
+		break;
+	case DDI_HPOP_CN_SET_PROPERTY:
+		ret = pcishpc_slot_set_property(slot_p,
+		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
+		break;
+	default:
+		ret = DDI_ENOTSUP;
+		break;
+	}
+
+	return (ret);
+}
+
+/*
+ * Local functions (called within this file)
+ */
+
+/*
+ * pcishpc_create_controller()
+ *
+ * This function allocates and creates an SHPC controller state structure
+ * and adds it to the linked list of controllers.
+ */
+static pcie_hp_ctrl_t *
+pcishpc_create_controller(dev_info_t *dip)
+{
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
+	pcie_hp_ctrl_t	*ctrl_p;
+
+	PCIE_DBG("pcishpc: create controller for %s#%d\n",
+	    ddi_driver_name(dip), ddi_get_instance(dip));
+
+	ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP);
+	ctrl_p->hc_dip = dip;
+
+	cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL);
+
+	/* Init the shpc controller's mutex. */
+	mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER, NULL);
+
+	/* HPC initialization is complete now */
+	ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG;
+	bus_p->bus_hp_curr_mode = PCIE_PCI_HP_MODE;
+
+	PCIE_SET_HP_CTRL(dip, ctrl_p);
+
+	PCIE_DBG("pcishpc_create_controller() success\n");
+
+	return (ctrl_p);
+}
+
+
+/*
+ * pcishpc_setup_controller()
+ *
+ * Get the number of HotPlug Slots, and the PCI device information
+ * for this HotPlug controller.
+ */
+static int
+pcishpc_setup_controller(pcie_hp_ctrl_t *ctrl_p)
+{
+	uint32_t config;
+	dev_info_t *ppdip;
+
+	config = pcishpc_read_reg(ctrl_p, PCI_HP_SLOT_CONFIGURATION_REG);
+
+	/* Get the number of HotPlug slots implemented */
+	ctrl_p->hc_num_slots_impl = ((config)&31);
+
+	/*
+	 * Initilize the current bus speed and number of hotplug slots
+	 * currently connected.
+	 */
+	ctrl_p->hc_curr_bus_speed = -1;
+	ctrl_p->hc_num_slots_connected = 0;
+
+	/*
+	 * Get the first PCI device Number used.
+	 *
+	 * PCI-X I/O boat workaround.
+	 * The register doesn't set up the correct value.
+	 */
+	ppdip = ddi_get_parent(ddi_get_parent(ctrl_p->hc_dip));
+	if ((ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS,
+	    "vendor-id", -1) == 0x108e) &&
+	    (ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS,
+	    "device-id", -1) == 0x9010))
+		ctrl_p->hc_device_start = 4;
+	else
+		ctrl_p->hc_device_start = ((config>>8)&31);
+
+	/* Get the first Physical device number. */
+	ctrl_p->hc_phys_start = ((config>>16)&0x7ff);
+
+	/* Check if the device numbers increase or decrease. */
+	ctrl_p->hc_device_increases = ((config>>29)&0x1);
+
+	ctrl_p->hc_has_attn =
+	    (config & PCI_HP_SLOT_CONFIG_ATTN_BUTTON) ? B_TRUE : B_FALSE;
+	ctrl_p->hc_has_mrl =
+	    (config & PCI_HP_SLOT_CONFIG_MRL_SENSOR) ? B_TRUE : B_FALSE;
+
+	ctrl_p->hc_cmd_pending = B_FALSE;
+	ctrl_p->hc_arbiter_timeout = B_FALSE;
+
+	if (ctrl_p->hc_num_slots_impl > PCIE_HP_MAX_SLOTS) {
+		PCIE_DBG("pcishpc_setup_controller() too many SHPC "
+		    "slots error\n");
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+
+/*
+ * pcishpc_destroy_controller()
+ *
+ * This function deallocates all of the SHPC controller resources.
+ */
+static int
+pcishpc_destroy_controller(dev_info_t *dip)
+{
+	pcie_hp_ctrl_t	*ctrl_p;
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
+
+	PCIE_DBG("pcishpc_destroy_controller() called(dip=%p)\n", dip);
+
+	/* get the soft state structure for this dip */
+	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
+		PCIE_DBG("pcishpc_destroy_controller() not found\n");
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Deallocate the slot state structures for this controller.
+	 */
+	(void) pcishpc_destroy_slots(ctrl_p);
+	cv_destroy(&ctrl_p->hc_cmd_comp_cv);
+	mutex_destroy(&ctrl_p->hc_mutex);
+	kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t));
+	bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE;
+
+	PCIE_DBG("pcishpc_destroy_controller() success\n");
+	return (DDI_SUCCESS);
+}
+
+/*
+ * pcishpc_create_slot()
+ *
+ * Allocate and add a new HotPlug slot state structure to the linked list.
+ */
+static pcie_hp_slot_t *
+pcishpc_create_slot(pcie_hp_ctrl_t *ctrl_p)
+{
+	pcie_hp_slot_t *slot_p;
+
+	PCIE_DBG("pcishpc_create_slot() called(ctrl_p=%x)\n", ctrl_p);
+
+	/* Allocate a new slot structure. */
+	slot_p = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP);
+	slot_p->hs_ctrl = ctrl_p;
+
+	/* Assign an initial value */
+	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
+
+	PCIE_DBG("pcishpc_create_slot() success\n");
+	return (slot_p);
+}
+
+/*
+ * pcishpc_register_slot()
+ *
+ * Create and register a slot with the Solaris HotPlug framework.
+ */
+static int
+pcishpc_register_slot(pcie_hp_ctrl_t *ctrl_p, int slot)
+{
+	dev_info_t	*dip = ctrl_p->hc_dip;
+	pcie_hp_slot_t	*slot_p;
+
+	slot_p = pcishpc_create_slot(ctrl_p);
+	ctrl_p->hc_slots[slot] = slot_p;
+	slot_p->hs_num = slot;
+
+	/* Setup the PCI device # for this SHPC slot. */
+	if (ctrl_p->hc_device_increases)
+		slot_p->hs_device_num = ctrl_p->hc_device_start +
+		    slot_p->hs_num;
+	else
+		slot_p->hs_device_num = ctrl_p->hc_device_start -
+		    slot_p->hs_num;
+
+	/* Setup the DDI HP framework slot information. */
+	slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCI;
+	slot_p->hs_info.cn_type_str = PCIE_PCI_HP_TYPE;
+	slot_p->hs_info.cn_child = NULL;
+
+	slot_p->hs_minor = PCI_MINOR_NUM(
+	    ddi_get_instance(dip), slot_p->hs_device_num);
+	slot_p->hs_condition = AP_COND_UNKNOWN;
+
+	/* setup thread for handling ATTN button events */
+	if (ctrl_p->hc_has_attn) {
+		PCIE_DBG("pcishpc_register_slot: "
+		    "setting up ATTN button event "
+		    "handler thread for slot %d\n", slot);
+
+		cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL);
+		slot_p->hs_attn_btn_pending = B_FALSE;
+		slot_p->hs_attn_btn_threadp = thread_create(NULL, 0,
+		    pcishpc_attn_btn_handler,
+		    (void *)slot_p, 0, &p0, TS_RUN, minclsyspri);
+		slot_p->hs_attn_btn_thread_exit = B_FALSE;
+	}
+
+	/* setup the slot name (used for ap-id) */
+	pcishpc_set_slot_name(ctrl_p, slot);
+
+	pcishpc_get_slot_state(slot_p);
+	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED)
+		slot_p->hs_condition = AP_COND_OK;
+
+	/* register the slot with DDI HP framework */
+	if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) {
+		PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n",
+		    slot_p->hs_phy_slot_num);
+		return (DDI_FAILURE);
+	}
+
+	pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
+	    slot_p->hs_minor), slot_p->hs_device_num);
+
+	PCIE_DBG("pcishpc_register_slot() success for slot %d\n", slot);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * pcishpc_destroy_slots()
+ *
+ * Free up all of the slot resources for this controller.
+ */
+static int
+pcishpc_destroy_slots(pcie_hp_ctrl_t *ctrl_p)
+{
+	dev_info_t	*dip = ctrl_p->hc_dip;
+	pcie_hp_slot_t	*slot_p;
+	int		i;
+
+	PCIE_DBG("pcishpc_destroy_slots() called(ctrl_p=%p)\n", ctrl_p);
+
+	for (i = 0; i < PCIE_HP_MAX_SLOTS; i++) {
+		if ((slot_p = ctrl_p->hc_slots[i]) == NULL)
+			continue;
+
+		if (slot_p->hs_attn_btn_threadp != NULL) {
+			mutex_enter(&ctrl_p->hc_mutex);
+			slot_p->hs_attn_btn_thread_exit = B_TRUE;
+			cv_signal(&slot_p->hs_attn_btn_cv);
+			PCIE_DBG("pcishpc_destroy_slots: "
+			    "waiting for ATTN thread exit\n");
+			cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
+			PCIE_DBG("pcishpc_destroy_slots: "
+			    "ATTN thread exit\n");
+			cv_destroy(&slot_p->hs_attn_btn_cv);
+			slot_p->hs_attn_btn_threadp = NULL;
+			mutex_exit(&ctrl_p->hc_mutex);
+		}
+
+		PCIE_DBG("pcishpc_destroy_slots() (shpc_p=%p)\n"
+		    "destroyed", slot_p);
+
+		pcie_hp_delete_occupant_props(dip,
+		    makedevice(ddi_driver_major(dip),
+		    slot_p->hs_minor));
+
+		/* unregister the slot with DDI HP framework */
+		if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) !=
+		    NDI_SUCCESS) {
+			PCIE_DBG("pcishpc_destroy_slots() "
+			    "failed to unregister slot %d\n",
+			    slot_p->hs_phy_slot_num);
+			return (DDI_FAILURE);
+		}
+		kmem_free(slot_p->hs_info.cn_name,
+		    strlen(slot_p->hs_info.cn_name) + 1);
+		kmem_free(slot_p, sizeof (pcie_hp_slot_t));
+	}
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * pcishpc_enable_irqs()
+ *
+ * Enable/unmask the different IRQ's we support from the SHPC controller.
+ */
+static int
+pcishpc_enable_irqs(pcie_hp_ctrl_t *ctrl_p)
+{
+	uint32_t reg;
+	int slot;
+
+	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
+
+	/* Enable all interrupts. */
+	reg &= ~PCI_HP_SERR_INT_MASK_ALL;
+
+	pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg);
+
+	/* Unmask the interrupts for each slot. */
+	for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) {
+		reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot);
+		if ((reg & PCI_HP_SLOT_STATE_MASK) == PCI_HP_SLOT_ENABLED) {
+			reg &= ~(PCI_HP_SLOT_MASK_ALL |
+			    PCI_HP_SLOT_MRL_SERR_MASK);
+			ctrl_p->hc_num_slots_connected++;
+			if (ctrl_p->hc_curr_bus_speed == -1)
+				ctrl_p->hc_curr_bus_speed =
+				    pcishpc_read_reg(ctrl_p,
+				    PCI_HP_PROF_IF_SBCR_REG) &
+				    PCI_HP_SBCR_SPEED_MASK;
+		} else {
+			reg &= ~(PCI_HP_SLOT_MASK_ALL);
+		}
+
+		/* Enable/Unmask all slot interrupts. */
+		pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, reg);
+	}
+
+	PCIE_DBG("pcishpc_enable_irqs: ctrl_p 0x%p, "
+	    "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p,
+	    ctrl_p->hc_curr_bus_speed, ctrl_p->hc_num_slots_connected);
+
+	return (DDI_SUCCESS);
+}
+
+
+/*
+ * pcishpc_disable_irqs()
+ *
+ * Disable/Mask the different IRQ's we support from the SHPC controller.
+ */
+static int
+pcishpc_disable_irqs(pcie_hp_ctrl_t *ctrl_p)
+{
+	uint32_t reg;
+	int slot;
+
+	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
+
+	/* Mask all interrupts. */
+	reg |= PCI_HP_SERR_INT_MASK_ALL;
+
+	pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg);
+
+	/* Unmask the interrupts for each slot. */
+	for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) {
+		reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot);
+
+		/* Disable/Mask all slot interrupts. */
+		reg |= PCI_HP_SLOT_MASK_ALL;
+
+		pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, reg);
+	}
+
+	PCIE_DBG("pcishpc_disable_irqs: ctrl_p 0x%p, "
+	    "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p,
+	    ctrl_p->hc_curr_bus_speed, ctrl_p->hc_num_slots_connected);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * pcishpc_slot_poweron()
+ *
+ * Poweron/Enable the slot.
+ *
+ * Note: This function is called by DDI HP framework at kernel context only
+ */
+/*ARGSUSED*/
+static int
+pcishpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result_state)
+{
+	uint32_t	status;
+
+	PCIE_DBG("pcishpc_slot_poweron called()\n");
+
+	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
+
+	/* get the current slot state */
+	pcishpc_get_slot_state(slot_p);
+
+	/* check if the slot is already in the 'enabled' state */
+	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
+		/* slot is already in the 'enabled' state */
+		PCIE_DBG("pcishpc_slot_poweron() slot %d already enabled\n",
+		    slot_p->hs_phy_slot_num);
+
+		*result_state = slot_p->hs_info.cn_state;
+		return (DDI_SUCCESS);
+	}
+
+	if (slot_p->hs_info.cn_state == DDI_HP_CN_STATE_EMPTY) {
+		PCIE_DBG("pcishpc_slot_poweron() slot in empty state\n");
+		goto cleanup;
+	}
+
+	/* make sure the MRL sensor is closed */
+	status = pcishpc_read_reg(slot_p->hs_ctrl,
+	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
+
+	if (status & PCI_HP_SLOT_MRL_STATE_MASK) {
+		PCIE_DBG("pcishpc_slot_poweron() failed: MRL open\n");
+		goto cleanup;
+	}
+
+	/* Set the Power LED to blink */
+	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
+
+	/* Turn all other LEDS off */
+	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
+	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
+	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
+
+	/* Set the bus speed only if the bus segment is not running */
+	if (pcishpc_set_bus_speed(slot_p) != DDI_SUCCESS) {
+		PCIE_DBG("pcishpc_slot_poweron() setting speed failed\n");
+		goto cleanup;
+	}
+
+	slot_p->hs_ctrl->hc_num_slots_connected++;
+
+	PCIE_DBG("pcishpc_slot_poweron(): slot_p 0x%p, slot state 0x%x, "
+	    "current bus speed 0x%x, slots connected 0x%x\n", slot_p,
+	    slot_p->hs_info.cn_state, slot_p->hs_ctrl->hc_curr_bus_speed,
+	    slot_p->hs_ctrl->hc_num_slots_connected);
+
+	/* Mask or Unmask MRL Sensor SEER bit based on new slot state */
+	if (slot_p->hs_ctrl->hc_has_mrl == B_TRUE) {
+		uint32_t reg;
+
+		reg = pcishpc_read_reg(slot_p->hs_ctrl,
+		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
+
+		pcishpc_write_reg(slot_p->hs_ctrl,
+		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num,
+		    reg & ~PCI_HP_SLOT_MRL_SERR_MASK);
+	}
+
+	/* Update the hardware slot state. */
+	if (pcishpc_set_slot_state(slot_p,
+	    DDI_HP_CN_STATE_ENABLED) != DDI_SUCCESS) {
+		PCIE_DBG("pcishpc_slot_poweron() failed\n");
+
+		pcishpc_get_slot_state(slot_p);
+		goto cleanup;
+	}
+	/* Update the current state. It will be used in pcishpc_setled() */
+	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED;
+
+	/* Turn the Power LED ON for a enabled slot. */
+	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON);
+
+	/* Turn all other LEDS off. */
+	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
+	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
+	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
+
+	/* delay after powerON to let the device initialize itself */
+	delay(drv_usectohz(pcishpc_reset_delay));
+
+	PCIE_DBG("pcishpc_slot_poweron() success!\n");
+
+	/*
+	 * Want to show up as POWERED state for now. It will be updated to
+	 * ENABLED state when user explicitly enable the slot.
+	 */
+	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED;
+
+	/* get the current slot state */
+	pcishpc_get_slot_state(slot_p);
+	/*
+	 * It should be poweron'ed now. Have a check here in case any
+	 * hardware problems.
+	 */
+	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
+		PCIE_DBG("pcishpc_slot_poweron() failed after hardware"
+		    " registers all programmed.\n");
+
+		goto cleanup;
+	}
+
+	*result_state = slot_p->hs_info.cn_state;
+
+	return (DDI_SUCCESS);
+
+cleanup:
+	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
+	return (DDI_FAILURE);
+}
+
+/*ARGSUSED*/
+static int
+pcishpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result_state)
+{
+	PCIE_DBG("pcishpc_slot_poweroff called()\n");
+
+	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
+
+	/* get the current slot state */
+	pcishpc_get_slot_state(slot_p);
+
+	/* check if the slot is not in the "enabled" or "powered" state */
+	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
+		/* slot is in the 'disabled' state */
+		PCIE_DBG("pcishpc_slot_poweroff(): "
+		    "slot %d already disabled\n", slot_p->hs_phy_slot_num);
+
+		*result_state = slot_p->hs_info.cn_state;
+		return (DDI_SUCCESS);
+	}
+
+	/* Set the Power LED to blink */
+	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
+
+	/* Turn all other LEDS off */
+	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
+	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
+	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
+
+	if (--slot_p->hs_ctrl->hc_num_slots_connected == 0)
+		slot_p->hs_ctrl->hc_curr_bus_speed = -1;
+
+	PCIE_DBG("pcishpc_slot_poweroff(): slot_p 0x%p, slot state 0x%x, "
+	    "current bus speed 0x%x, slots connected 0x%x\n", slot_p,
+	    slot_p->hs_info.cn_state, slot_p->hs_ctrl->hc_curr_bus_speed,
+	    slot_p->hs_ctrl->hc_num_slots_connected);
+
+	/* Mask or Unmask MRL Sensor SEER bit based on new slot state */
+	if (slot_p->hs_ctrl->hc_has_mrl == B_TRUE) {
+		uint32_t reg;
+
+		reg = pcishpc_read_reg(slot_p->hs_ctrl,
+		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
+
+		pcishpc_write_reg(slot_p->hs_ctrl,
+		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num,
+		    reg | PCI_HP_SLOT_MRL_SERR_MASK);
+	}
+
+	/* Update the hardware slot state. */
+	if (pcishpc_set_slot_state(slot_p, DDI_HP_CN_STATE_PRESENT) !=
+	    DDI_SUCCESS) {
+		PCIE_DBG("pcishpc_slot_poweroff() failed\n");
+
+		pcishpc_get_slot_state(slot_p);
+		goto cleanup;
+	}
+
+	/* Update the current state. It will be used in pcishpc_setled() */
+	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT;
+
+	/* Turn the Power LED OFF for a disabled slot. */
+	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
+
+	/* Turn all other LEDS off. */
+	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
+	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
+	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
+
+	/* delay after powerON to let the device initialize itself */
+	delay(drv_usectohz(pcishpc_reset_delay));
+
+	pcishpc_get_slot_state(slot_p);
+	/*
+	 * It should be poweroff'ed now. Have a check here in case any
+	 * hardware problems.
+	 */
+	if (slot_p->hs_info.cn_state > DDI_HP_CN_STATE_PRESENT) {
+		PCIE_DBG("pcishpc_slot_poweroff() failed after hardware"
+		    " registers all programmed.\n");
+
+		goto cleanup;
+	}
+
+	PCIE_DBG("pcishpc_slot_poweroff() success!\n");
+
+	*result_state = slot_p->hs_info.cn_state;
+	return (DDI_SUCCESS);
+
+cleanup:
+	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
+	return (DDI_FAILURE);
+}
+
+/*
+ * pcishpc_slot_probe()
+ *
+ * Probe the slot.
+ *
+ * Note: This function is called by DDI HP framework at kernel context only
+ */
+/*ARGSUSED*/
+static int
+pcishpc_slot_probe(pcie_hp_slot_t *slot_p)
+{
+	mutex_enter(&slot_p->hs_ctrl->hc_mutex);
+
+	PCIE_DBG("pcishpc_slot_probe called()\n");
+
+	/* get the current slot state */
+	pcishpc_get_slot_state(slot_p);
+
+	/*
+	 * Probe a given PCI Hotplug Connection (CN).
+	 */
+	if (pcie_hp_probe(slot_p) != DDI_SUCCESS) {
+		(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED,
+		    PCIE_HP_LED_BLINK);
+
+		PCIE_DBG("pcishpc_slot_probe() failed\n");
+
+		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
+		return (DDI_FAILURE);
+	}
+
+	PCIE_DBG("pcishpc_slot_probe() success!\n");
+
+	/* get the current slot state */
+	pcishpc_get_slot_state(slot_p);
+
+	mutex_exit(&slot_p->hs_ctrl->hc_mutex);
+	return (DDI_SUCCESS);
+}
+
+/*
+ * pcishpc_slot_unprobe()
+ *
+ * Unprobe the slot.
+ *
+ * Note: This function is called by DDI HP framework at kernel context only
+ */
+/*ARGSUSED*/
+static int
+pcishpc_slot_unprobe(pcie_hp_slot_t *slot_p)
+{
+	mutex_enter(&slot_p->hs_ctrl->hc_mutex);
+
+	PCIE_DBG("pcishpc_slot_unprobe called()\n");
+
+	/* get the current slot state */
+	pcishpc_get_slot_state(slot_p);
+
+	/*
+	 * Unprobe a given PCI Hotplug Connection (CN).
+	 */
+	if (pcie_hp_unprobe(slot_p) != DDI_SUCCESS) {
+		(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED,
+		    PCIE_HP_LED_BLINK);
+
+		PCIE_DBG("pcishpc_slot_unprobe() failed\n");
+
+		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
+		return (DDI_FAILURE);
+	}
+
+	PCIE_DBG("pcishpc_slot_unprobe() success!\n");
+
+	/* get the current slot state */
+	pcishpc_get_slot_state(slot_p);
+
+	mutex_exit(&slot_p->hs_ctrl->hc_mutex);
+	return (DDI_SUCCESS);
+}
+
+static int
+pcishpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
+    ddi_hp_cn_state_t target_state)
+{
+	ddi_hp_cn_state_t curr_state;
+	int rv = DDI_SUCCESS;
+
+	if (target_state > DDI_HP_CN_STATE_ENABLED) {
+		return (DDI_EINVAL);
+	}
+
+	curr_state = slot_p->hs_info.cn_state;
+	while ((curr_state < target_state) && (rv == DDI_SUCCESS)) {
+
+		switch (curr_state) {
+		case DDI_HP_CN_STATE_EMPTY:
+			/*
+			 * From EMPTY to PRESENT, just check the hardware
+			 * slot state.
+			 */
+			pcishpc_get_slot_state(slot_p);
+			curr_state = slot_p->hs_info.cn_state;
+			if (curr_state < DDI_HP_CN_STATE_PRESENT)
+				rv = DDI_FAILURE;
+			break;
+		case DDI_HP_CN_STATE_PRESENT:
+			rv = pcishpc_slot_poweron(slot_p, &curr_state);
+			break;
+		case DDI_HP_CN_STATE_POWERED:
+			curr_state = slot_p->hs_info.cn_state =
+			    DDI_HP_CN_STATE_ENABLED;
+			break;
+		default:
+			/* should never reach here */
+			ASSERT("unknown devinfo state");
+		}
+	}
+
+	return (rv);
+}
+
+static int
+pcishpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
+    ddi_hp_cn_state_t target_state)
+{
+	ddi_hp_cn_state_t curr_state;
+	int rv = DDI_SUCCESS;
+
+
+	curr_state = slot_p->hs_info.cn_state;
+	while ((curr_state > target_state) && (rv == DDI_SUCCESS)) {
+
+		switch (curr_state) {
+		case DDI_HP_CN_STATE_PRESENT:
+			/*
+			 * From PRESENT to EMPTY, just check hardware
+			 * slot state.
+			 */
+			pcishpc_get_slot_state(slot_p);
+			curr_state = slot_p->hs_info.cn_state;
+			if (curr_state >= DDI_HP_CN_STATE_PRESENT)
+				rv = DDI_FAILURE;
+			break;
+		case DDI_HP_CN_STATE_POWERED:
+			rv = pcishpc_slot_poweroff(slot_p, &curr_state);
+
+			break;
+		case DDI_HP_CN_STATE_ENABLED:
+			curr_state = slot_p->hs_info.cn_state =
+			    DDI_HP_CN_STATE_POWERED;
+
+			break;
+		default:
+			/* should never reach here */
+			ASSERT("unknown devinfo state");
+		}
+	}
+
+	return (rv);
+}
+
+/* Change slot state to a target state */
+static int
+pcishpc_change_slot_state(pcie_hp_slot_t *slot_p,
+    ddi_hp_cn_state_t target_state)
+{
+	ddi_hp_cn_state_t curr_state;
+	int rv;
+
+	pcishpc_get_slot_state(slot_p);
+	curr_state = slot_p->hs_info.cn_state;
+
+	if (curr_state == target_state) {
+		return (DDI_SUCCESS);
+	}
+	if (curr_state < target_state) {
+
+		rv = pcishpc_upgrade_slot_state(slot_p, target_state);
+	} else {
+		rv = pcishpc_downgrade_slot_state(slot_p, target_state);
+	}
+
+	return (rv);
+}
+
+/*
+ * pcishpc_issue_command()
+ *
+ * Sends a command to the SHPC controller.
+ */
+static int
+pcishpc_issue_command(pcie_hp_ctrl_t *ctrl_p, uint32_t cmd_code)
+{
+	int	retCode;
+
+	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
+
+	PCIE_DBG("pcishpc_issue_command() cmd_code=%02x\n", cmd_code);
+
+	ctrl_p->hc_cmd_pending = B_TRUE;
+
+	/* Write the command to the SHPC controller. */
+	pcishpc_write_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG, cmd_code);
+
+	while (ctrl_p->hc_cmd_pending == B_TRUE)
+		cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex);
+
+	/* Wait until the SHPC controller processes the command. */
+	retCode = pcishpc_wait_busy(ctrl_p);
+
+	/* Make sure the command completed. */
+	if (retCode == DDI_SUCCESS) {
+		/* Did the command fail to generate the command complete IRQ? */
+		if (ctrl_p->hc_cmd_pending != B_FALSE) {
+			PCIE_DBG("pcishpc_issue_command() Failed on "
+			    "generate cmd complete IRQ\n");
+			retCode = DDI_FAILURE;
+		}
+	}
+
+	if (retCode == DDI_FAILURE)
+		PCIE_DBG("pcishpc_issue_command() Failed on cmd_code=%02x\n",
+		    cmd_code);
+	else
+		PCIE_DBG("pcishpc_issue_command() Success on "
+		    "cmd_code=%02x\n", cmd_code);
+
+	return (retCode);
+}
+
+/*
+ * pcishpc_wait_busy()
+ *
+ * Wait until the SHPC controller is not busy.
+ */
+static int
+pcishpc_wait_busy(pcie_hp_ctrl_t *ctrl_p)
+{
+	uint32_t	status;
+
+	/* Wait until SHPC controller is NOT busy */
+	for (;;) {
+		status = pcishpc_read_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG);
+
+		/* Is there an MRL Sensor error? */
+		if ((status & PCI_HP_COMM_STS_ERR_MASK) ==
+		    PCI_HP_COMM_STS_ERR_MRL_OPEN) {
+			PCIE_DBG("pcishpc_wait_busy() ERROR: "
+			    "MRL Sensor error\n");
+			break;
+		}
+
+		/* Is there an Invalid command error? */
+		if ((status & PCI_HP_COMM_STS_ERR_MASK) ==
+		    PCI_HP_COMM_STS_ERR_INVALID_COMMAND) {
+			PCIE_DBG("pcishpc_wait_busy() ERROR: Invalid "
+			    "command error\n");
+			break;
+		}
+
+		/* Is there an Invalid Speed/Mode error? */
+		if ((status & PCI_HP_COMM_STS_ERR_MASK) ==
+		    PCI_HP_COMM_STS_ERR_INVALID_SPEED) {
+			PCIE_DBG("pcishpc_wait_busy() ERROR: Invalid "
+			    "Speed/Mode error\n");
+			break;
+		}
+
+		/* Is the SHPC controller not BUSY? */
+		if (!(status & PCI_HP_COMM_STS_CTRL_BUSY)) {
+			/* Return Success. */
+			return (DDI_SUCCESS);
+		}
+
+		PCIE_DBG("pcishpc_wait_busy() SHPC controller busy. Waiting\n");
+
+		/* Wait before polling the status register again. */
+		delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME));
+	}
+
+	return (DDI_FAILURE);
+}
+
+static void
+pcishpc_attn_btn_handler(pcie_hp_slot_t *slot_p)
+{
+	pcie_hp_led_state_t hs_power_led_state;
+	callb_cpr_t cprinfo;
+
+	PCIE_DBG("pcishpc_attn_btn_handler: thread started\n");
+
+	CALLB_CPR_INIT(&cprinfo, &slot_p->hs_ctrl->hc_mutex,
+	    callb_generic_cpr, "pcishpc_attn_btn_handler");
+
+	mutex_enter(&slot_p->hs_ctrl->hc_mutex);
+
+	/* wait for ATTN button event */
+	cv_wait(&slot_p->hs_attn_btn_cv, &slot_p->hs_ctrl->hc_mutex);
+
+	while (slot_p->hs_attn_btn_thread_exit == B_FALSE) {
+		if (slot_p->hs_attn_btn_pending == B_TRUE) {
+			/* get the current state of power LED */
+			hs_power_led_state = slot_p->hs_power_led_state;
+
+			/* Blink the Power LED while we wait for 5 seconds */
+			(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED,
+			    PCIE_HP_LED_BLINK);
+
+			/* wait for 5 seconds before taking any action */
+			if (cv_timedwait(&slot_p->hs_attn_btn_cv,
+			    &slot_p->hs_ctrl->hc_mutex,
+			    ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) {
+				/*
+				 * It is a time out;
+				 * make sure the ATTN pending flag is
+				 * still ON before sending the event
+				 * to DDI HP framework.
+				 */
+				if (slot_p->hs_attn_btn_pending == B_TRUE) {
+					int hint;
+
+					/* restore the power LED state */
+					(void) pcishpc_setled(slot_p,
+					    PCIE_HP_POWER_LED,
+					    hs_power_led_state);
+					/*
+					 * send the ATTN button event
+					 * to DDI HP framework
+					 */
+					slot_p->hs_attn_btn_pending = B_FALSE;
+
+					pcishpc_get_slot_state(slot_p);
+
+					if (slot_p->hs_info.cn_state <=
+					    DDI_HP_CN_STATE_PRESENT) {
+						/*
+						 * Insertion.
+						 */
+						hint = SE_INCOMING_RES;
+					} else {
+						/*
+						 * Want to remove;
+						 */
+						hint = SE_OUTGOING_RES;
+					}
+					pcie_hp_gen_sysevent_req(
+					    slot_p->hs_info.cn_name,
+					    hint,
+					    slot_p->hs_ctrl->hc_dip,
+					    KM_SLEEP);
+
+					continue;
+				}
+			}
+
+			/* restore the power LED state */
+			(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED,
+			    hs_power_led_state);
+			continue;
+		}
+
+		/* wait for another ATTN button event */
+		cv_wait(&slot_p->hs_attn_btn_cv, &slot_p->hs_ctrl->hc_mutex);
+	}
+
+	PCIE_DBG("pcishpc_attn_btn_handler: thread exit\n");
+	cv_signal(&slot_p->hs_attn_btn_cv);
+	CALLB_CPR_EXIT(&cprinfo);
+	thread_exit();
+}
+
+/*
+ * pcishpc_get_slot_state()
+ *
+ * Get the state of the slot.
+ * The slot state should have been initialized before this function gets called.
+ */
+static void
+pcishpc_get_slot_state(pcie_hp_slot_t *slot_p)
+{
+	uint32_t reg;
+	ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state;
+
+	/* Read the logical slot register for this Slot. */
+	reg = pcishpc_read_reg(slot_p->hs_ctrl,
+	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
+
+	/* Convert from the SHPC slot state to the HPC slot state. */
+	slot_p->hs_info.cn_state = pcishpc_slot_shpc_to_hpc(reg);
+	if (curr_state == DDI_HP_CN_STATE_POWERED &&
+	    slot_p->hs_info.cn_state > DDI_HP_CN_STATE_POWERED) {
+		/*
+		 * Keep POWERED state if it is currently POWERED state because
+		 * this driver does not really implement enable/disable
+		 * slot operations. That is, when poweron, it actually enables
+		 * the slot also.
+		 * So, from hardware view, POWERED == ENABLED.
+		 * But, when user explicitly change to POWERED state, it should
+		 * be kept until user explicitly change to other states later.
+		 */
+		slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED;
+	}
+
+	/* Convert from the SHPC Power LED state to the HPC Power LED state. */
+	slot_p->hs_power_led_state = pcishpc_led_shpc_to_hpc((reg>>2)&3);
+
+	/* Convert from the SHPC Attn LED state to the HPC Attn LED state. */
+	slot_p->hs_attn_led_state = pcishpc_led_shpc_to_hpc((reg>>4)&3);
+
+	/* We don't have a fault LED so just default it to OFF. */
+	slot_p->hs_fault_led_state = PCIE_HP_LED_OFF;
+
+	/* We don't have an active LED so just default it to OFF. */
+	slot_p->hs_active_led_state = PCIE_HP_LED_OFF;
+}
+
+/*
+ * pcishpc_set_slot_state()
+ *
+ * Updates the slot's state and leds.
+ */
+static int
+pcishpc_set_slot_state(pcie_hp_slot_t *slot_p,
+    ddi_hp_cn_state_t new_slot_state)
+{
+	uint32_t		reg, cmd_code;
+	ddi_hp_cn_state_t	curr_state;
+
+	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
+
+	reg = pcishpc_read_reg(slot_p->hs_ctrl,
+	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
+
+	/* Default all states to unchanged. */
+	cmd_code = ((1 + slot_p->hs_num) << 8);
+
+	/* Has the slot state changed? */
+	curr_state = pcishpc_slot_shpc_to_hpc(reg);
+	if (curr_state != new_slot_state) {
+		PCIE_DBG("pcishpc_set_slot_state() Slot State changed");
+
+		/* Set the new slot state in the Slot operation command. */
+		cmd_code |= pcishpc_slot_hpc_to_shpc(new_slot_state);
+	}
+
+	/* Has the Power LED state changed? */
+	if (slot_p->hs_power_led_state != pcishpc_led_shpc_to_hpc((reg>>2)&3)) {
+		PCIE_DBG("pcishpc_set_slot_state() Power LED State changed\n");
+
+		/* Set the new power led state in the Slot operation command. */
+		cmd_code |=
+		    (pcishpc_led_hpc_to_shpc(slot_p->hs_power_led_state) << 2);
+	}
+
+	/* Has the Attn LED state changed? */
+	if (slot_p->hs_attn_led_state != pcishpc_led_shpc_to_hpc((reg>>4)&3)) {
+		PCIE_DBG("pcishpc_set_slot_state() Attn LED State changed\n");
+
+		/* Set the new attn led state in the Slot operation command. */
+		cmd_code |=
+		    (pcishpc_led_hpc_to_shpc(slot_p->hs_attn_led_state) << 4);
+	}
+
+	return (pcishpc_issue_command(slot_p->hs_ctrl, cmd_code));
+}
+
+/*
+ * setup slot name/slot-number info.
+ */
+static void
+pcishpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p, int slot)
+{
+	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[slot];
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+	uchar_t *slotname_data;
+	int *slotnum;
+	uint_t count;
+	int len;
+	uchar_t *s;
+	uint32_t bit_mask;
+	int pci_id_cnt, pci_id_bit;
+	int slots_before, found;
+	int invalid_slotnum = 0;
+
+	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip,
+	    DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
+	    DDI_PROP_SUCCESS) {
+		slot_p->hs_phy_slot_num = slotnum[0];
+		ddi_prop_free(slotnum);
+	} else {
+		if (ctrl_p->hc_device_increases)
+			slot_p->hs_phy_slot_num = ctrl_p->hc_phys_start + slot;
+		else
+			slot_p->hs_phy_slot_num = ctrl_p->hc_phys_start - slot;
+
+		if ((ndi_prop_update_int(DDI_DEV_T_NONE, ctrl_p->hc_dip,
+		    "physical-slot#", slot_p->hs_phy_slot_num)) != DDI_SUCCESS)
+			PCIE_DBG("pcishpc_set_slot_name(): failed to "
+			    "create phyical-slot#%d\n",
+			    slot_p->hs_phy_slot_num);
+	}
+
+	/* Platform may not have initialized it */
+	if (!slot_p->hs_phy_slot_num) {
+		slot_p->hs_phy_slot_num = pci_config_get8(bus_p->bus_cfg_hdl,
+		    PCI_BCNF_SECBUS);
+		invalid_slotnum = 1;
+	}
+	slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num;
+	slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
+
+	/*
+	 * construct the slot_name:
+	 * 	if "slot-names" property exists then use that name
+	 *	else if valid slot number exists then it is "pci<slot-num>".
+	 *	else it will be "pci<sec-bus-number>dev<dev-number>"
+	 */
+	if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS,
+	    "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) {
+		bit_mask = slotname_data[3] | (slotname_data[2] << 8) |
+		    (slotname_data[1] << 16) | (slotname_data[0] << 24);
+
+		pci_id_bit = 1;
+		pci_id_cnt = slots_before = found = 0;
+
+		/*
+		 * Walk the bit mask until we find the bit that corresponds
+		 * to our slots device number.  We count how many bits
+		 * we find before we find our slot's bit.
+		 */
+		while (!found && (pci_id_cnt < 32)) {
+			while (slot_p->hs_device_num != pci_id_cnt) {
+
+				/*
+				 * Find the next bit set.
+				 */
+				while (!(bit_mask & pci_id_bit) &&
+				    (pci_id_cnt < 32)) {
+					pci_id_bit = pci_id_bit << 1;
+					pci_id_cnt++;
+				}
+
+				if (slot_p->hs_device_num != pci_id_cnt)
+					slots_before++;
+				else
+					found = 1;
+			}
+		}
+
+		if (pci_id_cnt < 32) {
+
+			/*
+			 * Set ptr to first string.
+			 */
+			s = slotname_data + 4;
+
+			/*
+			 * Increment past all the strings for the slots
+			 * before ours.
+			 */
+			while (slots_before) {
+				while (*s != NULL)
+					s++;
+				s++;
+				slots_before--;
+			}
+
+			slot_p->hs_info.cn_name = i_ddi_strdup((char *)s,
+			    KM_SLEEP);
+			kmem_free(slotname_data, len);
+			return;
+		}
+
+		/* slot-names entry not found */
+		PCIE_DBG("pcishpc_set_slot_name(): "
+		    "No slot-names entry found for slot #%d\n",
+		    slot_p->hs_phy_slot_num);
+		kmem_free(slotname_data, len);
+	}
+
+	if (invalid_slotnum) {
+		char tmp_name[256];
+
+		(void) snprintf(tmp_name, sizeof (tmp_name), "pci%d",
+		    slot_p->hs_device_num);
+		slot_p->hs_info.cn_name = i_ddi_strdup(tmp_name, KM_SLEEP);
+	} else {
+		char tmp_name[256];
+
+		(void) snprintf(tmp_name, sizeof (tmp_name), "pci%d",
+		    slot_p->hs_phy_slot_num);
+		slot_p->hs_info.cn_name = i_ddi_strdup(tmp_name, KM_SLEEP);
+	}
+}
+
+/*
+ * pcishpc_set_bus_speed()
+ *
+ * Set the bus speed and mode.
+ */
+static int
+pcishpc_set_bus_speed(pcie_hp_slot_t *slot_p)
+{
+	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
+	int		curr_speed = ctrl_p->hc_curr_bus_speed;
+	int		speed = -1;
+	int		avail_slots;
+	uint32_t	status, slots_avail1_reg, slots_avail2_reg;
+
+	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
+
+	/* Make sure that the slot is in a correct state */
+	status = pcishpc_read_reg(ctrl_p,
+	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
+
+	/* Return failure if the slot is empty */
+	if ((status & PCI_HP_SLOT_CARD_EMPTY_MASK) ==
+	    PCI_HP_SLOT_CARD_EMPTY_MASK) {
+		PCIE_DBG("pcishpc_set_bus_speed() failed: "
+		    "the slot is empty\n");
+		return (DDI_FAILURE);
+	}
+
+	/* Return failure if the slot is not in disabled state */
+	if ((status & PCI_HP_SLOT_STATE_MASK) != PCI_HP_SLOT_DISABLED) {
+		PCIE_DBG("pcishpc_set_bus_speed() failed: "
+		    "incorrect slot state\n");
+		return (DDI_FAILURE);
+	}
+
+	/* Set the "power-only" mode for the slot */
+	if (pcishpc_issue_command(ctrl_p, ((1+slot_p->hs_num)<<8) |
+	    PCI_HP_SLOT_POWER_ONLY) != DDI_SUCCESS) {
+		PCIE_DBG("pcishpc_set_bus_speed() failed to set "
+		    "the slot %d in the power-only mode\n", slot_p->hs_num);
+		return (DDI_FAILURE);
+	}
+
+	/* Wait for power good */
+	delay(drv_usectohz(PCIE_HP_POWER_GOOD_WAIT_TIME));
+
+	/* Make sure that the slot is in "power-only" state */
+	status = pcishpc_read_reg(ctrl_p,
+	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
+
+	if ((status & PCI_HP_SLOT_STATE_MASK) != PCI_HP_SLOT_POWER_ONLY) {
+		PCIE_DBG("pcishpc_set_bus_speed() "
+		    "power-only failed: incorrect slot state\n");
+		return (DDI_FAILURE);
+	}
+
+	slots_avail1_reg = pcishpc_read_reg(ctrl_p,
+	    PCI_HP_SLOTS_AVAIL_I_REG);
+	slots_avail2_reg = pcishpc_read_reg(ctrl_p,
+	    PCI_HP_SLOTS_AVAIL_II_REG);
+
+	/*
+	 * Check if SHPC has available slots and select the highest
+	 * available bus speed for the slot.
+	 *
+	 * The bus speed codes are:
+	 * 100 - 133Mhz; <--+
+	 * 011 - 100Mhz; <--+   PCI-X
+	 * 010 - 66Mhz;  <--+
+	 *
+	 * 001 - 66Mhz;  <--+
+	 * 000 - 33Mhz   <--+   Conv PCI
+	 */
+	switch (status & PCI_HP_SLOT_PCIX_CAPABLE_MASK) {
+	case PCI_HP_SLOT_133MHZ_PCIX_CAPABLE:
+		avail_slots = (slots_avail1_reg >>
+		    PCI_HP_AVAIL_133MHZ_PCIX_SPEED_SHIFT) &
+		    PCI_HP_AVAIL_SPEED_MASK;
+
+		if (((curr_speed == -1) && avail_slots) ||
+		    (curr_speed == PCI_HP_SBCR_133MHZ_PCIX_SPEED)) {
+			speed = PCI_HP_SBCR_133MHZ_PCIX_SPEED;
+			break;
+		}
+		/* FALLTHROUGH */
+	case PCI_HP_SLOT_100MHZ_PCIX_CAPABLE:
+		avail_slots = (slots_avail1_reg >>
+		    PCI_HP_AVAIL_100MHZ_PCIX_SPEED_SHIFT) &
+		    PCI_HP_AVAIL_SPEED_MASK;
+
+		if (((curr_speed == -1) && avail_slots) ||
+		    (curr_speed == PCI_HP_SBCR_100MHZ_PCIX_SPEED)) {
+			speed = PCI_HP_SBCR_100MHZ_PCIX_SPEED;
+			break;
+		}
+		/* FALLTHROUGH */
+	case PCI_HP_SLOT_66MHZ_PCIX_CAPABLE:
+		avail_slots = (slots_avail1_reg >>
+		    PCI_HP_AVAIL_66MHZ_PCIX_SPEED_SHIFT) &
+		    PCI_HP_AVAIL_SPEED_MASK;
+
+		if (((curr_speed == -1) && avail_slots) ||
+		    (curr_speed == PCI_HP_SBCR_66MHZ_PCIX_SPEED)) {
+			speed = PCI_HP_SBCR_66MHZ_PCIX_SPEED;
+			break;
+		}
+		/* FALLTHROUGH */
+	default:
+		avail_slots = (slots_avail2_reg >>
+		    PCI_HP_AVAIL_66MHZ_CONV_SPEED_SHIFT) &
+		    PCI_HP_AVAIL_SPEED_MASK;
+
+		if ((status & PCI_HP_SLOT_66MHZ_CONV_CAPABLE) &&
+		    (((curr_speed == -1) && avail_slots) ||
+		    (curr_speed == PCI_HP_SBCR_66MHZ_CONV_SPEED))) {
+			speed = PCI_HP_SBCR_66MHZ_CONV_SPEED;
+		} else {
+			avail_slots = (slots_avail1_reg >>
+			    PCI_HP_AVAIL_33MHZ_CONV_SPEED_SHIFT) &
+			    PCI_HP_AVAIL_SPEED_MASK;
+
+			if (((curr_speed == -1) && (avail_slots)) ||
+			    (curr_speed == PCI_HP_SBCR_33MHZ_CONV_SPEED)) {
+				speed = PCI_HP_SBCR_33MHZ_CONV_SPEED;
+			} else {
+				PCIE_DBG("pcishpc_set_bus_speed() "
+				    " failed to set the bus speed, slot# %d\n",
+				    slot_p->hs_num);
+				return (DDI_FAILURE);
+			}
+		}
+		break;
+	}
+
+	/*
+	 * If the bus segment is already running, check to see the card
+	 * in the slot can support the current bus speed.
+	 */
+	if (curr_speed == speed) {
+		/*
+		 * Check to see there is any slot available for the current
+		 * bus speed. Otherwise, we need fail the current slot connect
+		 * request.
+		 */
+		return ((avail_slots <= ctrl_p->hc_num_slots_connected) ?
+		    DDI_FAILURE : DDI_SUCCESS);
+	}
+
+	/* Set the bus speed */
+	if (pcishpc_issue_command(ctrl_p, PCI_HP_COMM_STS_SET_SPEED |
+	    speed) == DDI_FAILURE) {
+		PCIE_DBG("pcishpc_set_bus_speed() failed "
+		    "to set bus %d speed\n", slot_p->hs_num);
+		return (DDI_FAILURE);
+	}
+
+	/* Check the current bus speed */
+	status = pcishpc_read_reg(ctrl_p, PCI_HP_PROF_IF_SBCR_REG) &
+	    PCI_HP_SBCR_SPEED_MASK;
+	if ((status & PCI_HP_SBCR_SPEED_MASK) != speed) {
+		PCIE_DBG("pcishpc_set_bus_speed() an incorrect "
+		    "bus speed, slot = 0x%x, speed = 0x%x\n",
+		    slot_p->hs_num, status & PCI_HP_SBCR_SPEED_MASK);
+		return (DDI_FAILURE);
+	}
+
+
+	/* Save the current bus speed */
+	ctrl_p->hc_curr_bus_speed = speed;
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * pcishpc_setled()
+ *
+ * Change the state of a slot's LED.
+ */
+static int
+pcishpc_setled(pcie_hp_slot_t *slot_p, pcie_hp_led_t led,
+    pcie_hp_led_state_t state)
+{
+	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
+
+	switch (led) {
+		case PCIE_HP_FAULT_LED:
+			PCIE_DBG("pcishpc_setled() - PCIE_HP_FAULT_LED "
+			    "(set %s)\n", pcishpc_slot_textledstate(state));
+			slot_p->hs_fault_led_state = state;
+			break;
+
+		case PCIE_HP_POWER_LED:
+			PCIE_DBG("pcishpc_setled() - PCIE_HP_POWER_LED "
+			    "(set %s)\n", pcishpc_slot_textledstate(state));
+			slot_p->hs_power_led_state = state;
+			break;
+
+		case PCIE_HP_ATTN_LED:
+			PCIE_DBG("pcishpc_setled() - PCIE_HP_ATTN_LED "
+			    "(set %s)\n", pcishpc_slot_textledstate(state));
+			slot_p->hs_attn_led_state = state;
+			break;
+
+		case PCIE_HP_ACTIVE_LED:
+			PCIE_DBG("pcishpc_setled() - PCIE_HP_ACTIVE_LED "
+			    "(set %s)\n", pcishpc_slot_textledstate(state));
+			slot_p->hs_active_led_state = state;
+			break;
+	}
+
+	return (pcishpc_set_slot_state(slot_p, slot_p->hs_info.cn_state));
+}
+
+/*
+ * pcishpc_led_shpc_to_hpc()
+ *
+ * Convert from SHPC indicator status to HPC indicator status.
+ */
+static int
+pcishpc_led_shpc_to_hpc(int state)
+{
+	switch (state) {
+		case 1:	/* SHPC On bits b01 */
+			return (PCIE_HP_LED_ON);
+		case 2:	/* SHPC Blink bits b10 */
+			return (PCIE_HP_LED_BLINK);
+		case 3:	/* SHPC Off bits b11 */
+			return (PCIE_HP_LED_OFF);
+	}
+
+	return (PCIE_HP_LED_OFF);
+}
+
+
+/*
+ * pcishpc_led_hpc_to_shpc()
+ *
+ * Convert from HPC indicator status to SHPC indicator status.
+ */
+static int
+pcishpc_led_hpc_to_shpc(int state)
+{
+	switch (state) {
+		case PCIE_HP_LED_ON:
+			return (1); /* SHPC On bits b01 */
+		case PCIE_HP_LED_BLINK:
+			return (2); /* SHPC Blink bits b10 */
+		case PCIE_HP_LED_OFF:
+			return (3); /* SHPC Off bits b11 */
+	}
+
+	return (3); /* SHPC Off bits b11 */
+}
+
+/*
+ * pcishpc_slot_shpc_to_hpc()
+ *
+ * Convert from SHPC slot state to HPC slot state.
+ * The argument shpc_state is expected to be read from the slot register.
+ */
+static int
+pcishpc_slot_shpc_to_hpc(int shpc_state)
+{
+	if ((shpc_state & PCI_HP_SLOT_CARD_EMPTY_MASK) ==
+	    PCI_HP_SLOT_CARD_EMPTY_MASK)
+		return (DDI_HP_CN_STATE_EMPTY);
+
+	switch (shpc_state & PCI_HP_SLOT_STATE_MASK) {
+		case PCI_HP_SLOT_POWER_ONLY: /* SHPC Powered Only */
+			return (DDI_HP_CN_STATE_POWERED);
+
+		case PCI_HP_SLOT_ENABLED: /* SHPC Enabled */
+			return (DDI_HP_CN_STATE_ENABLED);
+
+		case PCI_HP_SLOT_DISABLED:	/* SHPC Disabled */
+		default :			/* SHPC Reserved */
+			return (DDI_HP_CN_STATE_PRESENT);
+	}
+}
+
+/*
+ * pcishpc_slot_hpc_to_shpc()
+ *
+ * Convert from HPC slot state to SHPC slot state.
+ */
+static int
+pcishpc_slot_hpc_to_shpc(int state)
+{
+	switch (state) {
+		case DDI_HP_CN_STATE_EMPTY:
+			return (0);
+
+		case DDI_HP_CN_STATE_POWERED:
+			return (PCI_HP_SLOT_POWER_ONLY);
+
+		case DDI_HP_CN_STATE_ENABLED:
+			return (PCI_HP_SLOT_ENABLED);
+
+		default:
+			return (PCI_HP_SLOT_DISABLED);
+	}
+}
+
+/*
+ * pcishpc_slot_textslotstate()
+ *
+ * Convert the request into a text message.
+ */
+static char *
+pcishpc_slot_textslotstate(ddi_hp_cn_state_t state)
+{
+	/* Convert an HPC slot state into a textual string. */
+	if (state == DDI_HP_CN_STATE_EMPTY)
+		return ("HPC_SLOT_EMPTY");
+	else if (state == DDI_HP_CN_STATE_ENABLED)
+		return ("HPC_SLOT_ENABLED");
+	else if (state == DDI_HP_CN_STATE_POWERED)
+		return ("HPC_SLOT_POWERED_ONLY");
+	else
+		return ("HPC_SLOT_DISABLED");
+}
+
+
+/*
+ * pcishpc_slot_textledstate()
+ *
+ * Convert the led state into a text message.
+ */
+static char *
+pcishpc_slot_textledstate(pcie_hp_led_state_t state)
+{
+	/* Convert an HPC led state into a textual string. */
+	switch (state) {
+		case PCIE_HP_LED_OFF:
+			return ("off");
+
+		case PCIE_HP_LED_ON:
+			return ("on");
+
+		case PCIE_HP_LED_BLINK:
+			return ("blink");
+	}
+	return ("unknown");
+}
+
+
+/*
+ * pcishpc_read_reg()
+ *
+ * Read from a SHPC controller register.
+ */
+static uint32_t
+pcishpc_read_reg(pcie_hp_ctrl_t *ctrl_p, int reg)
+{
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+
+	/* Setup the SHPC dword select register. */
+	pci_config_put8(bus_p->bus_cfg_hdl,
+	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_SELECT_OFF, (uint8_t)reg);
+
+	/* Read back the SHPC dword select register and verify. */
+	if (pci_config_get8(bus_p->bus_cfg_hdl, bus_p->bus_pci_hp_off +
+	    PCI_HP_DWORD_SELECT_OFF) != (uint8_t)reg) {
+		PCIE_DBG("pcishpc_read_reg() - Failed writing DWORD "
+		    "select reg\n");
+		return (0xFFFFFFFF);
+	}
+
+	/* Read from the SHPC dword data register. */
+	return (pci_config_get32(bus_p->bus_cfg_hdl,
+	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_DATA_OFF));
+}
+
+
+/*
+ * pcishpc_write_reg()
+ *
+ * Write to a SHPC controller register.
+ */
+static void
+pcishpc_write_reg(pcie_hp_ctrl_t *ctrl_p, int reg, uint32_t data)
+{
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+
+	/* Setup the SHPC dword select register. */
+	pci_config_put8(bus_p->bus_cfg_hdl,
+	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_SELECT_OFF, (uint8_t)reg);
+
+	/* Read back the SHPC dword select register and verify. */
+	if (pci_config_get8(bus_p->bus_cfg_hdl, bus_p->bus_pci_hp_off +
+	    PCI_HP_DWORD_SELECT_OFF) != (uint8_t)reg) {
+		PCIE_DBG("pcishpc_write_reg() - Failed writing "
+		    "DWORD select reg\n");
+		return;
+	}
+
+	/* Write to the SHPC dword data register. */
+	pci_config_put32(bus_p->bus_cfg_hdl,
+	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_DATA_OFF, data);
+
+	/*
+	 * Issue a read of the VendorID/DeviceID just to force the previous
+	 * write to complete. This is probably not necessary, but it does
+	 * help enforce ordering if there is an issue.
+	 */
+	(void) pci_config_get16(bus_p->bus_cfg_hdl, PCI_CONF_VENID);
+}
+
+
+#ifdef	DEBUG
+/*
+ * pcishpc_dump_regs()
+ *
+ * Dumps all of the SHPC controller registers.
+ */
+static void
+pcishpc_dump_regs(pcie_hp_ctrl_t *ctrl_p)
+{
+	int slot, numSlots;
+	uint32_t reg;
+	char *state;
+
+	if (!pcie_debug_flags)
+		return;
+
+	PCIE_DBG("pcishpc_dump_regs() called:\n");
+	PCIE_DBG("==========================================================");
+
+	PCIE_DBG("SHPC Base Offset				"
+	    ": 0x%08x\n", pcishpc_read_reg(ctrl_p, PCI_HP_BASE_OFFSET_REG));
+
+	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOTS_AVAIL_I_REG);
+
+	PCIE_DBG("Number of PCIX slots avail (33 Mhz)		 : %d\n",
+	    (reg & 31));
+
+	PCIE_DBG("Number of PCIX slots avail (66 Mhz)		 : %d\n",
+	    ((reg>>8) & 31));
+
+	PCIE_DBG("Number of PCIX slots avail (100 Mhz)		: %d\n",
+	    ((reg>>16) & 31));
+
+	PCIE_DBG("Number of PCIX slots avail (133 Mhz)		: %d\n",
+	    ((reg>>24) & 31));
+
+	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOTS_AVAIL_II_REG);
+
+	PCIE_DBG("Number of conventional PCI slots (66 Mhz) : %d\n",
+	    (reg & 31));
+
+	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOT_CONFIGURATION_REG);
+
+	numSlots = (reg & 31);
+
+	PCIE_DBG("Number of Slots connected to this port	 : %d\n",
+	    numSlots);
+
+	PCIE_DBG("PCI Device # for First HotPlug Slot		 : %d\n",
+	    ((reg>>8) & 31));
+
+	PCIE_DBG("Physical Slot # for First PCI Device #	 : %d\n",
+	    ((reg>>16) & 0x7ff));
+
+	PCIE_DBG("Physical Slot Number Up/Down			 : %d\n",
+	    ((reg>>29) & 0x1));
+
+	PCIE_DBG("MRL Sensor Implemented			 : %s\n",
+	    (reg & PCI_HP_SLOT_CONFIG_MRL_SENSOR) ? "Yes" : "No");
+
+	PCIE_DBG("Attention Button Implemented			 : %s\n",
+	    (reg & PCI_HP_SLOT_CONFIG_ATTN_BUTTON) ? "Yes" : "No");
+
+	reg = pcishpc_read_reg(ctrl_p, PCI_HP_PROF_IF_SBCR_REG);
+
+	switch (reg & 7) {
+		case 0:
+			state = "33Mhz Conventional PCI";
+			break;
+		case 1:
+			state = "66Mhz Conventional PCI";
+			break;
+		case 2:
+			state = "66Mhz PCI-X";
+			break;
+		case 3:
+			state = "100Mhz PCI-X";
+			break;
+		case 4:
+			state = "133Mhz PCI-X";
+			break;
+		default:
+			state = "Reserved (Error)";
+			break;
+	}
+
+	PCIE_DBG("Current Port Operation Mode		: %s\n", state);
+
+	PCIE_DBG("SHPC Interrupt Message Number		: %d\n",
+	    ((reg>>16) &31));
+
+	PCIE_DBG("SHPC Programming Interface		: %d\n",
+	    ((reg>>24) & 0xff));
+
+	reg = pcishpc_read_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG);
+
+	PCIE_DBG("SHPC Command Code			: %d\n",
+	    (reg & 0xff));
+
+	PCIE_DBG("SHPC Target Slot			: %d\n",
+	    ((reg>>8) & 31));
+
+	PCIE_DBG("SHPC Controller Busy			: %s\n",
+	    ((reg>>16) & 1) ? "Yes" : "No");
+
+	PCIE_DBG("SHPC Controller Err: MRL Sensor	: %s\n",
+	    ((reg>>17) & 1) ? "Yes" : "No");
+
+	PCIE_DBG("SHPC Controller Err: Invalid Command	: %s\n",
+	    ((reg>>18) & 1) ? "Yes" : "No");
+
+	PCIE_DBG("SHPC Controller Err: Invalid Speed/Mode : %s\n",
+	    ((reg>>19) & 1) ? "Yes" : "No");
+
+	reg = pcishpc_read_reg(ctrl_p, PCI_HP_IRQ_LOCATOR_REG);
+
+	PCIE_DBG("Command Completion Interrupt Pending	: %s\n",
+	    (reg & PCI_HP_IRQ_CMD_COMPLETE) ? "Yes" : "No");
+
+	for (slot = 0; slot < numSlots; slot++) {
+		PCIE_DBG("Slot %d Interrupt Pending	: %s\n", slot+1,
+		    (reg & (PCI_HP_IRQ_SLOT_N_PENDING<<slot)) ? "Yes" : "No");
+	}
+
+	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SERR_LOCATOR_REG);
+
+	PCIE_DBG("Arbiter SERR Pending			: %s\n",
+	    (reg & PCI_HP_IRQ_SERR_ARBITER_PENDING) ? "Yes" : "No");
+
+	for (slot = 0; slot < numSlots; slot++) {
+		PCIE_DBG("Slot %d SERR Pending		: %s\n",
+		    slot+1, (reg &
+		    (PCI_HP_IRQ_SERR_SLOT_N_PENDING<<slot)) ? "Yes" : "No");
+	}
+
+	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
+
+	PCIE_DBG("Global Interrupt Mask			: %s\n",
+	    (reg & PCI_HP_SERR_INT_GLOBAL_IRQ_MASK) ? "Yes" : "No");
+
+	PCIE_DBG("Global SERR Mask			: %s\n",
+	    (reg & PCI_HP_SERR_INT_GLOBAL_SERR_MASK) ? "Yes" : "No");
+
+	PCIE_DBG("Command Completion Interrupt Mask	: %s\n",
+	    (reg & PCI_HP_SERR_INT_CMD_COMPLETE_MASK) ? "Yes" : "No");
+
+	PCIE_DBG("Arbiter SERR Mask			: %s\n",
+	    (reg & PCI_HP_SERR_INT_ARBITER_SERR_MASK) ? "Yes" : "No");
+
+	PCIE_DBG("Command Completion Detected		: %s\n",
+	    (reg & PCI_HP_SERR_INT_CMD_COMPLETE_IRQ) ? "Yes" : "No");
+
+	PCIE_DBG("Arbiter Timeout Detected		: %s\n",
+	    (reg & PCI_HP_SERR_INT_ARBITER_IRQ) ? "Yes" : "No");
+
+	for (slot = 0; slot < numSlots; slot++) {
+		PCIE_DBG("Logical Slot %d Registers:\n", slot+1);
+		PCIE_DBG("------------------------------------\n");
+
+		reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot);
+
+		PCIE_DBG("Slot %d state			: %s\n", slot+1,
+		    pcishpc_slot_textslotstate(pcishpc_slot_shpc_to_hpc(reg)));
+
+		PCIE_DBG("Slot %d Power Indicator State	: %s\n", slot+1,
+		    pcishpc_slot_textledstate(pcishpc_led_shpc_to_hpc(
+		    (reg>>2) &3)));
+
+		PCIE_DBG("Slot %d Attention Indicator State : %s\n", slot+1,
+		    pcishpc_slot_textledstate(pcishpc_led_shpc_to_hpc(
+		    (reg>>4)&3)));
+
+		PCIE_DBG("Slot %d Power Fault		: %s\n", slot+1,
+		    ((reg>>6)&1) ? "Fault Detected" : "No Fault");
+		PCIE_DBG("Slot %d Attention Button	: %s\n", slot+1,
+		    ((reg>>7)&1) ? "Depressed" : "Not Depressed");
+		PCIE_DBG("Slot %d MRL Sensor		: %s\n", slot+1,
+		    ((reg>>8)&1) ? "Not Closed" : "Closed");
+		PCIE_DBG("Slot %d 66mhz Capable		: %s\n", slot+1,
+		    ((reg>>9)&1) ? "66mhz" : "33mgz");
+
+		switch ((reg>>10)&3) {
+			case 0:
+				state = "Card Present 7.5W";
+				break;
+			case 1:
+				state = "Card Present 15W";
+				break;
+			case 2:
+				state = "Card Present 25W";
+				break;
+			case 3:
+				state = "Slot Empty";
+				break;
+		}
+
+		PCIE_DBG("Slot %d PRSNT1#/PRSNT2#	: %s\n", slot+1,
+		    state);
+
+		switch ((reg>>12)&3) {
+			case 0:
+				state = "Non PCI-X";
+				break;
+			case 1:
+				state = "66mhz PCI-X";
+				break;
+			case 2:
+				state = "Reserved";
+				break;
+			case 3:
+				state = "133mhz PCI-X";
+				break;
+		}
+
+		PCIE_DBG("Slot %d Card Presence Change Detected	  : %s\n",
+		    slot+1, (reg & PCI_HP_SLOT_PRESENCE_DETECTED) ? "Yes" :
+		    "No");
+		PCIE_DBG("Slot %d Isolated Power Fault Detected	  : %s\n",
+		    slot+1, (reg & PCI_HP_SLOT_ISO_PWR_DETECTED) ? "Yes" :
+		    "No");
+		PCIE_DBG("Slot %d Attention Button Press Detected : %s\n",
+		    slot+1, (reg & PCI_HP_SLOT_ATTN_DETECTED) ? "Yes" : "No");
+		PCIE_DBG("Slot %d MRL Sensor Change Detected	  : %s\n",
+		    slot+1, (reg & PCI_HP_SLOT_MRL_DETECTED) ? "Yes" : "No");
+		PCIE_DBG("Slot %d Connected Power Fault Detected  : %s\n",
+		    slot+1, (reg & PCI_HP_SLOT_POWER_DETECTED) ? "Yes" : "No");
+
+		PCIE_DBG("Slot %d Card Presence IRQ Masked	  : %s\n",
+		    slot+1, (reg & PCI_HP_SLOT_PRESENCE_MASK) ? "Yes" : "No");
+		PCIE_DBG("Slot %d Isolated Power Fault IRQ Masked : %s\n",
+		    slot+1, (reg & PCI_HP_SLOT_ISO_PWR_MASK) ? "Yes" : "No");
+		PCIE_DBG("Slot %d Attention Button IRQ Masked	  : %s\n",
+		    slot+1, (reg & PCI_HP_SLOT_ATTN_MASK) ? "Yes" : "No");
+		PCIE_DBG("Slot %d MRL Sensor IRQ Masked		  : %s\n",
+		    slot+1, (reg & PCI_HP_SLOT_MRL_MASK) ? "Yes" : "No");
+		PCIE_DBG("Slot %d Connected Power Fault IRQ Masked : %s\n",
+		    slot+1, (reg & PCI_HP_SLOT_POWER_MASK) ? "Yes" : "No");
+		PCIE_DBG("Slot %d MRL Sensor SERR Masked          : %s\n",
+		    slot+1, (reg & PCI_HP_SLOT_MRL_SERR_MASK) ? "Yes" : "No");
+		PCIE_DBG("Slot %d Connected Power Fault SERR Masked : %s\n",
+		    slot+1, (reg & PCI_HP_SLOT_POWER_SERR_MASK) ? "Yes" : "No");
+	}
+}
+#endif	/* DEBUG */
--- a/usr/src/uts/common/io/pciex/pcie.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/io/pciex/pcie.c	Mon Nov 02 15:58:28 2009 +0800
@@ -34,10 +34,15 @@
 #include <sys/fm/util.h>
 #include <sys/promif.h>
 #include <sys/disp.h>
-#include <sys/pcie.h>
+#include <sys/stat.h>
+#include <sys/file.h>
 #include <sys/pci_cap.h>
+#include <sys/pci_impl.h>
 #include <sys/pcie_impl.h>
+#include <sys/hotplug/pci/pcie_hp.h>
+#include <sys/hotplug/pci/pcicfg.h>
 
+/* Local functions prototypes */
 static void pcie_init_pfd(dev_info_t *);
 static void pcie_fini_pfd(dev_info_t *);
 
@@ -48,6 +53,7 @@
 #ifdef DEBUG
 uint_t pcie_debug_flags = 0;
 static void pcie_print_bus(pcie_bus_t *bus_p);
+void pcie_dbg(char *fmt, ...);
 #endif /* DEBUG */
 
 /* Variable to control default PCI-Express config settings */
@@ -114,7 +120,7 @@
  * If a particular platform wants to disable certain errors such as UR/MA,
  * instead of using #defines have the platform's PCIe Root Complex driver set
  * these masks using the pcie_get_XXX_mask and pcie_set_XXX_mask functions.  For
- * x86 the closest thing to a PCIe root complex driver is NPE.  For SPARC the
+ * x86 the closest thing to a PCIe root complex driver is NPE.	For SPARC the
  * closest PCIe root complex driver is PX.
  *
  * pcie_serr_disable_flag : disable SERR only (in RCR and command reg) x86
@@ -135,13 +141,14 @@
     PCIE_AER_SUCE_USC_MSG_DATA_ERR;
 
 int pcie_max_mps = PCIE_DEVCTL_MAX_PAYLOAD_4096 >> 5;
+int pcie_disable_ari = 0;
 
 static void pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip,
 	int *max_supported);
 static int pcie_get_max_supported(dev_info_t *dip, void *arg);
 static int pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
     caddr_t *addrp, ddi_acc_handle_t *handlep);
-static void pcie_unmap_phys(ddi_acc_handle_t *handlep,  pci_regspec_t *ph);
+static void pcie_unmap_phys(ddi_acc_handle_t *handlep,	pci_regspec_t *ph);
 
 /*
  * modload support
@@ -149,7 +156,7 @@
 
 static struct modlmisc modlmisc	= {
 	&mod_miscops,	/* Type	of module */
-	"PCIE: PCI framework"
+	"PCI Express Framework Module"
 };
 
 static struct modlinkage modlinkage = {
@@ -199,6 +206,195 @@
 	return (mod_info(&modlinkage, modinfop));
 }
 
+/* ARGSUSED */
+int
+pcie_init(dev_info_t *dip, caddr_t arg)
+{
+	int	ret = DDI_SUCCESS;
+
+	/*
+	 * Create a "devctl" minor node to support DEVCTL_DEVICE_*
+	 * and DEVCTL_BUS_* ioctls to this bus.
+	 */
+	if ((ret = ddi_create_minor_node(dip, "devctl", S_IFCHR,
+	    PCI_MINOR_NUM(ddi_get_instance(dip), PCI_DEVCTL_MINOR),
+	    DDI_NT_NEXUS, 0)) != DDI_SUCCESS) {
+		PCIE_DBG("Failed to create devctl minor node for %s%d\n",
+		    ddi_driver_name(dip), ddi_get_instance(dip));
+
+		return (ret);
+	}
+
+	if ((ret = pcie_hp_init(dip, arg)) != DDI_SUCCESS) {
+		/*
+		 * On a few x86 platforms, we observed unexpected hotplug
+		 * initialization failures in recent years. Continue with
+		 * a message printed because we don't want to stop PCI
+		 * driver attach and system boot because of this hotplug
+		 * initialization failure before we address all those issues.
+		 */
+		cmn_err(CE_WARN, "%s%d: Failed setting hotplug framework\n",
+		    ddi_driver_name(dip), ddi_get_instance(dip));
+
+#if defined(__sparc)
+		ddi_remove_minor_node(dip, "devctl");
+
+		return (ret);
+#endif /* defined(__sparc) */
+	}
+
+	if ((pcie_ari_supported(dip) == PCIE_ARI_FORW_SUPPORTED) &&
+	    (pcie_ari_is_enabled(dip) == PCIE_ARI_FORW_DISABLED))
+		(void) pcicfg_configure(dip, 0, PCICFG_ALL_FUNC,
+		    PCICFG_FLAG_ENABLE_ARI);
+
+	return (DDI_SUCCESS);
+}
+
+/* ARGSUSED */
+int
+pcie_uninit(dev_info_t *dip)
+{
+	int	ret = DDI_SUCCESS;
+
+	if (pcie_ari_is_enabled(dip) == PCIE_ARI_FORW_ENABLED)
+		(void) pcie_ari_disable(dip);
+
+	if ((ret = pcie_hp_uninit(dip)) != DDI_SUCCESS) {
+		PCIE_DBG("Failed to uninitialize hotplug for %s%d\n",
+		    ddi_driver_name(dip), ddi_get_instance(dip));
+
+		return (ret);
+	}
+
+	ddi_remove_minor_node(dip, "devctl");
+
+	return (ret);
+}
+
+/* ARGSUSED */
+int
+pcie_intr(dev_info_t *dip)
+{
+	return (pcie_hp_intr(dip));
+}
+
+/* ARGSUSED */
+int
+pcie_open(dev_info_t *dip, dev_t *devp, int flags, int otyp, cred_t *credp)
+{
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
+
+	/*
+	 * Make sure the open is for the right file type.
+	 */
+	if (otyp != OTYP_CHR)
+		return (EINVAL);
+
+	/*
+	 * Handle the open by tracking the device state.
+	 */
+	if ((bus_p->bus_soft_state == PCI_SOFT_STATE_OPEN_EXCL) ||
+	    ((flags & FEXCL) &&
+	    (bus_p->bus_soft_state != PCI_SOFT_STATE_CLOSED))) {
+		return (EBUSY);
+	}
+
+	if (flags & FEXCL)
+		bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN_EXCL;
+	else
+		bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN;
+
+	return (0);
+}
+
+/* ARGSUSED */
+int
+pcie_close(dev_info_t *dip, dev_t dev, int flags, int otyp, cred_t *credp)
+{
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
+
+	if (otyp != OTYP_CHR)
+		return (EINVAL);
+
+	bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
+
+	return (0);
+}
+
+/* ARGSUSED */
+int
+pcie_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, int mode,
+    cred_t *credp, int *rvalp)
+{
+	struct devctl_iocdata	*dcp;
+	uint_t			bus_state;
+	int			rv = DDI_SUCCESS;
+
+	/*
+	 * We can use the generic implementation for devctl ioctl
+	 */
+	switch (cmd) {
+	case DEVCTL_DEVICE_GETSTATE:
+	case DEVCTL_DEVICE_ONLINE:
+	case DEVCTL_DEVICE_OFFLINE:
+	case DEVCTL_BUS_GETSTATE:
+		return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0));
+	default:
+		break;
+	}
+
+	/*
+	 * read devctl ioctl data
+	 */
+	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
+		return (EFAULT);
+
+	switch (cmd) {
+	case DEVCTL_BUS_QUIESCE:
+		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
+			if (bus_state == BUS_QUIESCED)
+				break;
+		(void) ndi_set_bus_state(dip, BUS_QUIESCED);
+		break;
+	case DEVCTL_BUS_UNQUIESCE:
+		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
+			if (bus_state == BUS_ACTIVE)
+				break;
+		(void) ndi_set_bus_state(dip, BUS_ACTIVE);
+		break;
+	case DEVCTL_BUS_RESET:
+	case DEVCTL_BUS_RESETALL:
+	case DEVCTL_DEVICE_RESET:
+		rv = ENOTSUP;
+		break;
+	default:
+		rv = ENOTTY;
+	}
+
+	ndi_dc_freehdl(dcp);
+	return (rv);
+}
+
+/* ARGSUSED */
+int
+pcie_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
+    int flags, char *name, caddr_t valuep, int *lengthp)
+{
+	if (dev == DDI_DEV_T_ANY)
+		goto skip;
+
+	if (PCIE_IS_HOTPLUG_CAPABLE(dip) &&
+	    strcmp(name, "pci-occupant") == 0) {
+		int	pci_dev = PCI_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev));
+
+		pcie_hp_create_occupant_props(dip, dev, pci_dev);
+	}
+
+skip:
+	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
+}
+
 /*
  * PCI-Express child device initialization.
  * This function enables generic pci-express interrupts and error
@@ -312,6 +508,13 @@
 		pcie_enable_errors(cdip);
 	}
 
+	bus_p->bus_ari = B_FALSE;
+	if ((pcie_ari_is_enabled(ddi_get_parent(cdip))
+	    == PCIE_ARI_FORW_ENABLED) && (pcie_ari_device(cdip)
+	    == PCIE_ARI_DEVICE)) {
+		bus_p->bus_ari = B_TRUE;
+	}
+
 	if (pcie_initchild_mps(cdip) == DDI_FAILURE)
 		return (DDI_FAILURE);
 
@@ -528,6 +731,7 @@
 pcie_rc_fini_bus(dev_info_t *dip)
 {
 	pcie_bus_t *bus_p = (pcie_bus_t *)ndi_get_bus_private(dip, B_FALSE);
+
 	ndi_set_bus_private(dip, B_FALSE, NULL, NULL);
 	kmem_free(bus_p, sizeof (pcie_bus_t));
 }
@@ -552,7 +756,6 @@
 	/* allocate memory for pcie bus data */
 	bus_p = kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP);
 
-
 	/* Set back pointer to dip */
 	bus_p->bus_dip = cdip;
 
@@ -561,8 +764,10 @@
 		errstr = "Cannot setup config access";
 		goto fail;
 	}
+
 	bus_p->bus_cfg_hdl = eh;
 	bus_p->bus_fm_flags = 0;
+	bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
 
 	/* get device's bus/dev/function number */
 	if (pcie_get_bdf_from_dip(cdip, &bus_p->bus_bdf) != DDI_SUCCESS) {
@@ -588,6 +793,14 @@
 		if (PCI_CAP_LOCATE(eh, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_AER),
 		    &bus_p->bus_aer_off) != DDI_SUCCESS)
 			bus_p->bus_aer_off = NULL;
+
+		/* Check and save PCIe hotplug capability information */
+		if ((PCIE_IS_RP(bus_p) || PCIE_IS_SWD(bus_p)) &&
+		    (PCI_CAP_GET16(eh, NULL, bus_p->bus_pcie_off, PCIE_PCIECAP)
+		    & PCIE_PCIECAP_SLOT_IMPL) &&
+		    (PCI_CAP_GET32(eh, NULL, bus_p->bus_pcie_off, PCIE_SLOTCAP)
+		    & PCIE_SLOTCAP_HP_CAPABLE))
+			bus_p->bus_hp_sup_modes |= PCIE_NATIVE_HP_MODE;
 	} else {
 		bus_p->bus_pcie_off = NULL;
 		bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO;
@@ -608,6 +821,11 @@
 
 	/* Save the Range information if device is a switch/bridge */
 	if (PCIE_IS_BDG(bus_p)) {
+		/* Check and save PCI hotplug (SHPC) capability information */
+		if ((PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCI_HOTPLUG,
+		    &bus_p->bus_pci_hp_off)) == DDI_SUCCESS)
+			bus_p->bus_hp_sup_modes |= PCIE_PCI_HP_MODE;
+
 		/* get "bus_range" property */
 		range_size = sizeof (pci_bus_range_t);
 		if (ddi_getlongprop_buf(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
@@ -661,6 +879,10 @@
 
 	ndi_set_bus_private(cdip, B_TRUE, DEVI_PORT_TYPE_PCI, (void *)bus_p);
 
+	if (PCIE_IS_HOTPLUG_CAPABLE(cdip))
+		(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip,
+		    "hotplug-capable");
+
 	pcie_init_pfd(cdip);
 
 	bus_p->bus_mps = 0;
@@ -717,6 +939,10 @@
 
 	bus_p = PCIE_DIP2UPBUS(cdip);
 	ASSERT(bus_p);
+
+	if (PCIE_IS_HOTPLUG_CAPABLE(cdip))
+		(void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, "hotplug-capable");
+
 	pci_config_teardown(&bus_p->bus_cfg_hdl);
 	ndi_set_bus_private(cdip, B_TRUE, NULL, NULL);
 	kmem_free(bus_p->bus_assigned_addr,
@@ -1025,7 +1251,7 @@
 	/*
 	 * As part of the probing, the PCI fcode interpreter may setup a DMA
 	 * request if a given card has a fcode on it using dip and rdip of the
-	 * AP (attachment point) i.e, dip and rdip of px/pcieb driver. In this
+	 * hotplug connector i.e, dip and rdip of px/pcieb driver. In this
 	 * case, return a invalid value for the bdf since we cannot get to the
 	 * bdf value of the actual device which will be initiating this DMA.
 	 */
@@ -1152,6 +1378,7 @@
 	int		max_payload_size;
 	pcie_bus_t	*bus_p;
 	dev_info_t	*pdip = ddi_get_parent(cdip);
+	uint8_t		dev_type;
 
 	bus_p = PCIE_DIP2BUS(cdip);
 	if (bus_p == NULL) {
@@ -1160,6 +1387,21 @@
 		return (DDI_FAILURE);
 	}
 
+	dev_type = bus_p->bus_dev_type;
+
+	/*
+	 * For ARI Devices, only function zero's MPS needs to be set.
+	 */
+	if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) &&
+	    (pcie_ari_is_enabled(pdip) == PCIE_ARI_FORW_ENABLED)) {
+		pcie_req_id_t child_bdf;
+
+		if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE)
+			return (DDI_FAILURE);
+		if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) != 0)
+			return (DDI_SUCCESS);
+	}
+
 	if (PCIE_IS_RP(bus_p)) {
 		/*
 		 * If this device is a root port, then the mps scan
@@ -1202,6 +1444,7 @@
 
 		bus_p->bus_mps = mps;
 	}
+
 	return (DDI_SUCCESS);
 }
 
@@ -1244,6 +1487,7 @@
 	ddi_walk_devs(dip, pcie_get_max_supported,
 	    (void *)&max_pay_load_supported);
 	ndi_devi_exit(ddi_get_parent(dip), circular_count);
+
 	*max_supported = max_pay_load_supported.highest_common_mps;
 }
 
@@ -1313,7 +1557,7 @@
  * dip - dip of root complex
  *
  * Returns - DDI_SUCCESS if there is at least one root port otherwise
- *           DDI_FAILURE.
+ *	     DDI_FAILURE.
  */
 int
 pcie_root_port(dev_info_t *dip)
@@ -1473,6 +1717,211 @@
 	return (rp_bus_p->bus_pfd->pe_rber_fatal);
 }
 
+int
+pcie_ari_supported(dev_info_t *dip)
+{
+	uint32_t devcap2;
+	uint16_t pciecap;
+	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+	uint8_t dev_type;
+
+	PCIE_DBG("pcie_ari_supported: dip=%p\n", dip);
+
+	if (bus_p == NULL)
+		return (PCIE_ARI_FORW_NOT_SUPPORTED);
+
+	dev_type = bus_p->bus_dev_type;
+
+	if ((dev_type != PCIE_PCIECAP_DEV_TYPE_DOWN) &&
+	    (dev_type != PCIE_PCIECAP_DEV_TYPE_ROOT))
+		return (PCIE_ARI_FORW_NOT_SUPPORTED);
+
+	if (pcie_disable_ari) {
+		PCIE_DBG("pcie_ari_supported: dip=%p: ARI Disabled\n", dip);
+		return (PCIE_ARI_FORW_NOT_SUPPORTED);
+	}
+
+	pciecap = PCIE_CAP_GET(16, bus_p, PCIE_PCIECAP);
+
+	if ((pciecap & PCIE_PCIECAP_VER_MASK) < PCIE_PCIECAP_VER_2_0) {
+		PCIE_DBG("pcie_ari_supported: dip=%p: Not 2.0\n", dip);
+		return (PCIE_ARI_FORW_NOT_SUPPORTED);
+	}
+
+	devcap2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCAP2);
+
+	PCIE_DBG("pcie_ari_supported: dip=%p: DevCap2=0x%x\n",
+	    dip, devcap2);
+
+	if (devcap2 & PCIE_DEVCAP2_ARI_FORWARD) {
+		PCIE_DBG("pcie_ari_supported: "
+		    "dip=%p: ARI Forwarding is supported\n", dip);
+		return (PCIE_ARI_FORW_SUPPORTED);
+	}
+	return (PCIE_ARI_FORW_NOT_SUPPORTED);
+}
+
+int
+pcie_ari_enable(dev_info_t *dip)
+{
+	uint16_t devctl2;
+	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+
+	PCIE_DBG("pcie_ari_enable: dip=%p\n", dip);
+
+	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
+		return (DDI_FAILURE);
+
+	devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2);
+	devctl2 |= PCIE_DEVCTL2_ARI_FORWARD_EN;
+	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2);
+
+	PCIE_DBG("pcie_ari_enable: dip=%p: writing 0x%x to DevCtl2\n",
+	    dip, devctl2);
+
+	return (DDI_SUCCESS);
+}
+
+int
+pcie_ari_disable(dev_info_t *dip)
+{
+	uint16_t devctl2;
+	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+
+	PCIE_DBG("pcie_ari_disable: dip=%p\n", dip);
+
+	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
+		return (DDI_FAILURE);
+
+	devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2);
+	devctl2 &= ~PCIE_DEVCTL2_ARI_FORWARD_EN;
+	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2);
+
+	PCIE_DBG("pcie_ari_disable: dip=%p: writing 0x%x to DevCtl2\n",
+	    dip, devctl2);
+
+	return (DDI_SUCCESS);
+}
+
+int
+pcie_ari_is_enabled(dev_info_t *dip)
+{
+	uint16_t devctl2;
+	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+
+	PCIE_DBG("pcie_ari_is_enabled: dip=%p\n", dip);
+
+	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
+		return (PCIE_ARI_FORW_DISABLED);
+
+	devctl2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCTL2);
+
+	PCIE_DBG("pcie_ari_is_enabled: dip=%p: DevCtl2=0x%x\n",
+	    dip, devctl2);
+
+	if (devctl2 & PCIE_DEVCTL2_ARI_FORWARD_EN) {
+		PCIE_DBG("pcie_ari_is_enabled: "
+		    "dip=%p: ARI Forwarding is enabled\n", dip);
+		return (PCIE_ARI_FORW_ENABLED);
+	}
+
+	return (PCIE_ARI_FORW_DISABLED);
+}
+
+int
+pcie_ari_device(dev_info_t *dip)
+{
+	ddi_acc_handle_t handle;
+	uint16_t cap_ptr;
+
+	PCIE_DBG("pcie_ari_device: dip=%p\n", dip);
+
+	/*
+	 * XXX - This function may be called before the bus_p structure
+	 * has been populated.  This code can be changed to remove
+	 * pci_config_setup()/pci_config_teardown() when the RFE
+	 * to populate the bus_p structures early in boot is putback.
+	 */
+
+	/* First make sure it is a PCIe device */
+
+	if (pci_config_setup(dip, &handle) != DDI_SUCCESS)
+		return (PCIE_NOT_ARI_DEVICE);
+
+	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr))
+	    != DDI_SUCCESS) {
+		pci_config_teardown(&handle);
+		return (PCIE_NOT_ARI_DEVICE);
+	}
+
+	/* Locate the ARI Capability */
+
+	if ((PCI_CAP_LOCATE(handle, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI),
+	    &cap_ptr)) == DDI_FAILURE) {
+		pci_config_teardown(&handle);
+		return (PCIE_NOT_ARI_DEVICE);
+	}
+
+	/* ARI Capability was found so it must be a ARI device */
+	PCIE_DBG("pcie_ari_device: ARI Device dip=%p\n", dip);
+
+	pci_config_teardown(&handle);
+	return (PCIE_ARI_DEVICE);
+}
+
+int
+pcie_ari_get_next_function(dev_info_t *dip, int *func)
+{
+	uint32_t val;
+	uint16_t cap_ptr, next_function;
+	ddi_acc_handle_t handle;
+
+	/*
+	 * XXX - This function may be called before the bus_p structure
+	 * has been populated.  This code can be changed to remove
+	 * pci_config_setup()/pci_config_teardown() when the RFE
+	 * to populate the bus_p structures early in boot is putback.
+	 */
+
+	if (pci_config_setup(dip, &handle) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+
+	if ((PCI_CAP_LOCATE(handle,
+	    PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI), &cap_ptr)) == DDI_FAILURE) {
+		pci_config_teardown(&handle);
+		return (DDI_FAILURE);
+	}
+
+	val = PCI_CAP_GET32(handle, NULL, cap_ptr, PCIE_ARI_CAP);
+
+	next_function = (val >> PCIE_ARI_CAP_NEXT_FUNC_SHIFT) &
+	    PCIE_ARI_CAP_NEXT_FUNC_MASK;
+
+	pci_config_teardown(&handle);
+
+	*func = next_function;
+
+	return (DDI_SUCCESS);
+}
+
+dev_info_t *
+pcie_func_to_dip(dev_info_t *dip, pcie_req_id_t function)
+{
+	pcie_req_id_t child_bdf;
+	dev_info_t *cdip;
+
+	for (cdip = ddi_get_child(dip); cdip;
+	    cdip = ddi_get_next_sibling(cdip)) {
+
+		if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE)
+			return (NULL);
+
+		if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) == function)
+			return (cdip);
+	}
+	return (NULL);
+}
+
 #ifdef	DEBUG
 
 static void
--- a/usr/src/uts/common/io/pciex/pcieb.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/io/pciex/pcieb.c	Mon Nov 02 15:58:28 2009 +0800
@@ -39,18 +39,16 @@
 #include <sys/sunddi.h>
 #include <sys/sunndi.h>
 #include <sys/fm/util.h>
-#include <sys/pcie.h>
 #include <sys/pci_cap.h>
+#include <sys/pci_impl.h>
 #include <sys/pcie_impl.h>
-#include <sys/hotplug/pci/pcihp.h>
-#include <sys/hotplug/pci/pciehpc.h>
-#include <sys/hotplug/pci/pcishpc.h>
 #include <sys/open.h>
 #include <sys/stat.h>
 #include <sys/file.h>
 #include <sys/promif.h>		/* prom_printf */
 #include <sys/disp.h>
 #include <sys/pcie_pwr.h>
+#include <sys/hotplug/pci/pcie_hp.h>
 #include "pcieb.h"
 #ifdef PX_PLX
 #include <io/pciex/pcieb_plx.h>
@@ -120,14 +118,13 @@
 	i_ndi_busop_access_enter,	/* (*bus_fm_access_enter)(); 	*/
 	i_ndi_busop_access_exit,	/* (*bus_fm_access_exit)(); 	*/
 	pcie_bus_power,			/* (*bus_power)(); 	*/
-	pcieb_intr_ops			/* (*bus_intr_op)(); 		*/
+	pcieb_intr_ops,			/* (*bus_intr_op)(); 		*/
+	pcie_hp_common_ops		/* (*bus_hp_op)(); 		*/
 };
 
 static int	pcieb_open(dev_t *, int, int, cred_t *);
 static int	pcieb_close(dev_t, int, int, cred_t *);
 static int	pcieb_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
-static int	pcieb_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
-		    caddr_t, int *);
 static int	pcieb_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
 static uint_t 	pcieb_intr_handler(caddr_t arg1, caddr_t arg2);
 
@@ -138,9 +135,6 @@
 static int	pcieb_pwr_disable(dev_info_t *dip);
 
 /* Hotplug related functions */
-static int pcieb_pciehpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle);
-static int pcieb_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle);
-static int pcieb_init_hotplug(pcieb_devstate_t *pcieb);
 static void pcieb_id_props(pcieb_devstate_t *pcieb);
 
 /*
@@ -161,7 +155,7 @@
 	nodev,				/* mmap */
 	nodev,				/* segmap */
 	nochpoll,			/* poll */
-	pcieb_prop_op,			/* cb_prop_op */
+	pcie_prop_op,			/* cb_prop_op */
 	NULL,				/* streamtab */
 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
 	CB_REV,				/* rev */
@@ -194,7 +188,7 @@
 
 static struct modldrv modldrv = {
 	&mod_driverops, /* Type of module */
-	"PCIe to PCI nexus driver",
+	"PCIe bridge/switch driver",
 	&pcieb_ops,	/* driver ops */
 };
 
@@ -246,6 +240,36 @@
 	return (mod_info(&modlinkage, modinfop));
 }
 
+/* ARGSUSED */
+static int
+pcieb_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
+{
+	minor_t		minor = getminor((dev_t)arg);
+	int		instance = PCI_MINOR_NUM_TO_INSTANCE(minor);
+	pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state, instance);
+	int		ret = DDI_SUCCESS;
+
+	switch (infocmd) {
+	case DDI_INFO_DEVT2INSTANCE:
+		*result = (void *)(intptr_t)instance;
+		break;
+	case DDI_INFO_DEVT2DEVINFO:
+		if (pcieb == NULL) {
+			ret = DDI_FAILURE;
+			break;
+		}
+
+		*result = (void *)pcieb->pcieb_dip;
+		break;
+	default:
+		ret = DDI_FAILURE;
+		break;
+	}
+
+	return (ret);
+}
+
+
 /*ARGSUSED*/
 static int
 pcieb_probe(dev_info_t *devi)
@@ -261,7 +285,6 @@
 	pcieb_devstate_t	*pcieb;
 	pcie_bus_t		*bus_p = PCIE_DIP2UPBUS(devi);
 	ddi_acc_handle_t	config_handle = bus_p->bus_cfg_hdl;
-	uint8_t			dev_type = bus_p->bus_dev_type;
 
 	switch (cmd) {
 	case DDI_RESUME:
@@ -297,7 +320,6 @@
 		return (DDI_FAILURE);
 	pcieb = ddi_get_soft_state(pcieb_state, instance);
 	pcieb->pcieb_dip = devi;
-	pcieb->pcieb_soft_state = PCIEB_SOFT_STATE_CLOSED;
 
 	if ((pcieb_fm_init(pcieb)) != DDI_SUCCESS) {
 		PCIEB_DEBUG(DBG_ATTACH, devi, "Failed in pcieb_fm_init\n");
@@ -356,37 +378,14 @@
 	pcieb_attach_plx_workarounds(pcieb);
 #endif /* PX_PLX */
 
-	/* Initialize hotplug */
-	pcieb->pcieb_hotplug_capable = B_FALSE;
-
-	if ((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
-	    (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
-	    (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) ||
-	    (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE)) {
-		(void) pcieb_init_hotplug(pcieb);
-	}
+	if (pcie_init(devi, NULL) != DDI_SUCCESS)
+		goto fail;
 
 	/*
 	 * Initialize interrupt handlers. Ignore return value.
 	 */
 	(void) pcieb_intr_attach(pcieb);
 
-	if (pcieb->pcieb_hotplug_capable == B_FALSE) {
-		/*
-		 * (for non hotplug bus) this would create ":devctl" minor
-		 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls
-		 * to this bus.
-		 */
-		if (ddi_create_minor_node(devi, "devctl", S_IFCHR,
-		    PCIHP_AP_MINOR_NUM(instance, PCIHP_DEVCTL_MINOR),
-		    DDI_NT_NEXUS, 0) != DDI_SUCCESS)
-			goto fail;
-	}
-
-	PCIEB_DEBUG(DBG_ATTACH, devi,
-	    "pcieb_attach: this nexus %s hotplug slots\n",
-	    pcieb->pcieb_hotplug_capable == B_TRUE ? "has":"has no");
-
 	/* Do any platform specific workarounds needed at this time */
 	pcieb_plat_attach_workaround(devi);
 
@@ -429,19 +428,8 @@
 	/* remove interrupt handlers */
 	pcieb_intr_fini(pcieb);
 
-	if (pcieb->pcieb_hotplug_capable == B_TRUE) {
-		if (pcihp_uninit(devi) == DDI_FAILURE)
-			error = DDI_FAILURE;
-
-		if (pcieb->pcieb_hpc_type == HPC_PCIE)
-			(void) pciehpc_uninit(devi);
-		else if (pcieb->pcieb_hpc_type == HPC_SHPC)
-			(void) pcishpc_uninit(devi);
-
-		(void) ndi_prop_remove(DDI_DEV_T_NONE, devi, "hotplug-capable");
-	} else {
-		ddi_remove_minor_node(devi, "devctl");
-	}
+	/* uninitialize inband PCI-E HPC if present */
+	(void) pcie_uninit(devi);
 
 	(void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type");
 
@@ -640,7 +628,7 @@
 pcieb_name_child(dev_info_t *child, char *name, int namelen)
 {
 	pci_regspec_t *pci_rp;
-	uint_t slot, func;
+	uint_t device, func;
 	char **unit_addr;
 	uint_t n;
 
@@ -677,13 +665,19 @@
 	}
 
 	/* copy the device identifications */
-	slot = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi);
+	device = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi);
 	func = PCI_REG_FUNC_G(pci_rp[0].pci_phys_hi);
 
+	if (pcie_ari_is_enabled(ddi_get_parent(child))
+	    == PCIE_ARI_FORW_ENABLED) {
+		func = (device << 3) | func;
+		device = 0;
+	}
+
 	if (func != 0)
-		(void) snprintf(name, namelen, "%x,%x", slot, func);
+		(void) snprintf(name, namelen, "%x,%x", device, func);
 	else
-		(void) snprintf(name, namelen, "%x", slot);
+		(void) snprintf(name, namelen, "%x", device);
 
 	ddi_prop_free(pci_rp);
 	return (DDI_SUCCESS);
@@ -911,7 +905,7 @@
 	    (intr_type == DDI_INTR_TYPE_MSI) ? "MSI" : "INTx");
 
 	request = 0;
-	if (pcieb->pcieb_hotplug_capable) {
+	if (PCIE_IS_HOTPLUG_ENABLED(dip)) {
 		request++;
 		is_hp = B_TRUE;
 	}
@@ -1220,204 +1214,54 @@
 static int
 pcieb_open(dev_t *devp, int flags, int otyp, cred_t *credp)
 {
-	pcieb_devstate_t *pcieb_p;
-	minor_t		minor = getminor(*devp);
-	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
+	int		inst = PCI_MINOR_NUM_TO_INSTANCE(getminor(*devp));
+	pcieb_devstate_t	*pcieb = ddi_get_soft_state(pcieb_state, inst);
+	int	rv;
 
-	/*
-	 * Make sure the open is for the right file type.
-	 */
-	if (otyp != OTYP_CHR)
-		return (EINVAL);
-
-	/*
-	 * Get the soft state structure for the device.
-	 */
-	pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
-	    instance);
-
-	if (pcieb_p == NULL)
+	if (pcieb == NULL)
 		return (ENXIO);
 
-	if (pcieb_p->pcieb_hotplug_capable == B_TRUE)
-		return ((pcihp_get_cb_ops())->cb_open(devp, flags,
-		    otyp, credp));
+	mutex_enter(&pcieb->pcieb_mutex);
+	rv = pcie_open(pcieb->pcieb_dip, devp, flags, otyp, credp);
+	mutex_exit(&pcieb->pcieb_mutex);
 
-	/*
-	 * Handle the open by tracking the device state.
-	 */
-	mutex_enter(&pcieb_p->pcieb_mutex);
-	if (flags & FEXCL) {
-		if (pcieb_p->pcieb_soft_state != PCIEB_SOFT_STATE_CLOSED) {
-			mutex_exit(&pcieb_p->pcieb_mutex);
-			return (EBUSY);
-		}
-		pcieb_p->pcieb_soft_state = PCIEB_SOFT_STATE_OPEN_EXCL;
-	} else {
-		if (pcieb_p->pcieb_soft_state == PCIEB_SOFT_STATE_OPEN_EXCL) {
-			mutex_exit(&pcieb_p->pcieb_mutex);
-			return (EBUSY);
-		}
-		pcieb_p->pcieb_soft_state = PCIEB_SOFT_STATE_OPEN;
-	}
-	mutex_exit(&pcieb_p->pcieb_mutex);
-	return (0);
+	return (rv);
 }
 
 static int
 pcieb_close(dev_t dev, int flags, int otyp, cred_t *credp)
 {
-	pcieb_devstate_t *pcieb_p;
-	minor_t		minor = getminor(dev);
-	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
+	int		inst = PCI_MINOR_NUM_TO_INSTANCE(getminor(dev));
+	pcieb_devstate_t	*pcieb = ddi_get_soft_state(pcieb_state, inst);
+	int	rv;
 
-	if (otyp != OTYP_CHR)
-		return (EINVAL);
-
-	pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
-	    instance);
-
-	if (pcieb_p == NULL)
+	if (pcieb == NULL)
 		return (ENXIO);
 
-	if (pcieb_p->pcieb_hotplug_capable == B_TRUE)
-		return ((pcihp_get_cb_ops())->cb_close(dev, flags,
-		    otyp, credp));
+	mutex_enter(&pcieb->pcieb_mutex);
+	rv = pcie_close(pcieb->pcieb_dip, dev, flags, otyp, credp);
+	mutex_exit(&pcieb->pcieb_mutex);
 
-	mutex_enter(&pcieb_p->pcieb_mutex);
-	pcieb_p->pcieb_soft_state = PCIEB_SOFT_STATE_CLOSED;
-	mutex_exit(&pcieb_p->pcieb_mutex);
-	return (0);
+	return (rv);
 }
 
 static int
 pcieb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
 	int *rvalp)
 {
-	pcieb_devstate_t *pcieb_p;
-	dev_info_t *self;
-	struct devctl_iocdata *dcp;
-	uint_t bus_state;
-	int rv = 0;
-	minor_t		minor = getminor(dev);
-	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
+	int		inst = PCI_MINOR_NUM_TO_INSTANCE(getminor(dev));
+	pcieb_devstate_t	*pcieb = ddi_get_soft_state(pcieb_state, inst);
+	int		rv;
 
-	pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
-	    instance);
-
-	if (pcieb_p == NULL)
+	if (pcieb == NULL)
 		return (ENXIO);
 
-	self = pcieb_p->pcieb_dip;
-	if (pcieb_p->pcieb_hotplug_capable == B_TRUE) {
-		rv = ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd,
-		    arg, mode, credp, rvalp));
-
-		pcieb_plat_ioctl_hotplug(self, rv, cmd);
-		return (rv);
-	}
-
-	/*
-	 * We can use the generic implementation for these ioctls
-	 */
-	switch (cmd) {
-	case DEVCTL_DEVICE_GETSTATE:
-	case DEVCTL_DEVICE_ONLINE:
-	case DEVCTL_DEVICE_OFFLINE:
-	case DEVCTL_BUS_GETSTATE:
-		return (ndi_devctl_ioctl(self, cmd, arg, mode, 0));
-	}
-
-	/*
-	 * read devctl ioctl data
-	 */
-	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
-		return (EFAULT);
-
-	switch (cmd) {
-
-	case DEVCTL_DEVICE_RESET:
-		rv = ENOTSUP;
-		break;
-
-	case DEVCTL_BUS_QUIESCE:
-		if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
-			if (bus_state == BUS_QUIESCED)
-				break;
-		(void) ndi_set_bus_state(self, BUS_QUIESCED);
-		break;
-
-	case DEVCTL_BUS_UNQUIESCE:
-		if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
-			if (bus_state == BUS_ACTIVE)
-				break;
-		(void) ndi_set_bus_state(self, BUS_ACTIVE);
-		break;
-
-	case DEVCTL_BUS_RESET:
-		rv = ENOTSUP;
-		break;
-
-	case DEVCTL_BUS_RESETALL:
-		rv = ENOTSUP;
-		break;
+	/* To handle devctl and hotplug related ioctls */
+	rv = pcie_ioctl(pcieb->pcieb_dip, dev, cmd, arg, mode, credp, rvalp);
 
-	default:
-		rv = ENOTTY;
-	}
-
-	ndi_dc_freehdl(dcp);
 	return (rv);
 }
 
-static int
-pcieb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
-	int flags, char *name, caddr_t valuep, int *lengthp)
-{
-	pcieb_devstate_t *pcieb_p;
-	minor_t		minor = getminor(dev);
-	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
-
-	pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
-	    instance);
-
-	if (pcieb_p == NULL)
-		return (ENXIO);
-
-	if (pcieb_p->pcieb_hotplug_capable == B_TRUE)
-		return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op,
-		    flags, name, valuep, lengthp));
-
-	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
-}
-
-/*ARGSUSED*/
-static int
-pcieb_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
-{
-	pcieb_devstate_t *pcieb_p;	/* per pcieb state pointer */
-	minor_t		minor = getminor((dev_t)arg);
-	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
-
-	pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
-	    instance);
-
-	switch (infocmd) {
-	default:
-		return (DDI_FAILURE);
-
-	case DDI_INFO_DEVT2INSTANCE:
-		*result = (void *)(intptr_t)instance;
-		return (DDI_SUCCESS);
-
-	case DDI_INFO_DEVT2DEVINFO:
-		if (pcieb_p == NULL)
-			return (DDI_FAILURE);
-		*result = (void *)pcieb_p->pcieb_dip;
-		return (DDI_SUCCESS);
-	}
-}
-
 /*
  * Common interrupt handler for hotplug, PME and errors.
  */
@@ -1444,12 +1288,8 @@
 	if (isrc == PCIEB_INTR_SRC_UNKNOWN)
 		goto FAIL;
 
-	if (isrc & PCIEB_INTR_SRC_HP) {
-		if (pcieb_p->pcieb_hpc_type == HPC_PCIE)
-			ret = pciehpc_intr(dip);
-		else if (pcieb_p->pcieb_hpc_type == HPC_SHPC)
-			ret = pcishpc_intr(dip);
-	}
+	if (isrc & PCIEB_INTR_SRC_HP)
+		ret = pcie_intr(dip);
 
 	if (isrc & PCIEB_INTR_SRC_PME)
 		ret = DDI_INTR_CLAIMED;
@@ -1576,99 +1416,6 @@
 
 }
 
-/*ARGSUSED*/
-static int pcieb_pciehpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle)
-{
-	uint16_t cap_ptr;
-
-	if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr)) !=
-	    DDI_FAILURE) {
-		uint16_t slotimpl = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
-		    PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL;
-		if (slotimpl)
-			if (PCI_CAP_GET32(config_handle, NULL, cap_ptr,
-			    PCIE_SLOTCAP) & PCIE_SLOTCAP_HP_CAPABLE)
-				return (DDI_SUCCESS);
-	}
-
-	return (DDI_FAILURE);
-}
-
-static int pcieb_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle)
-{
-	return (pcieb_plat_pcishpc_probe(dip, config_handle));
-}
-
-/*
- * Initialize hotplug framework if we are hotpluggable.
- * Sets flag in the soft state if Hot Plug is supported and initialized
- * properly.
- */
-/*ARGSUSED*/
-static int
-pcieb_init_hotplug(pcieb_devstate_t *pcieb)
-{
-	int rv = DDI_FAILURE;
-	pcie_bus_t *bus_p = PCIE_DIP2BUS(pcieb->pcieb_dip);
-	ddi_acc_handle_t config_handle = bus_p->bus_cfg_hdl;
-	uint8_t dev_type = bus_p->bus_dev_type;
-
-#ifdef PX_PLX
-	uint16_t vid = bus_p->bus_dev_ven_id & 0xFFFF;
-	uint16_t did = bus_p->bus_dev_ven_id >> 16;
-	if ((vid == PXB_VENDOR_PLX) && (did == PXB_DEVICE_PLX_8532) &&
-	    (bus_p->bus_rev_id <= PXB_DEVICE_PLX_AA_REV))
-		return (DDI_SUCCESS);
-#endif /* PX_PLX */
-
-	if (((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
-	    (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE) ||
-	    (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT)) &&
-	    (pcieb_pciehpc_probe(pcieb->pcieb_dip,
-	    config_handle) == DDI_SUCCESS)) {
-		pcieb->pcieb_hpc_type = HPC_PCIE;
-	} else if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) &&
-	    (pcieb_pcishpc_probe(pcieb->pcieb_dip,
-	    config_handle) == DDI_SUCCESS)) {
-		pcieb->pcieb_hpc_type = HPC_SHPC;
-	} else {
-		pcieb->pcieb_hpc_type = HPC_NONE;
-		return (DDI_SUCCESS);
-	}
-
-	pcieb->pcieb_hotplug_capable = B_TRUE;
-
-	if (pcieb->pcieb_hpc_type == HPC_PCIE)
-		rv = pciehpc_init(pcieb->pcieb_dip, NULL);
-	else if (pcieb->pcieb_hpc_type == HPC_SHPC)
-		rv = pcishpc_init(pcieb->pcieb_dip);
-
-	if (rv != DDI_SUCCESS)
-		goto fail;
-
-	if (pcihp_init(pcieb->pcieb_dip) != DDI_SUCCESS) {
-		if (pcieb->pcieb_hpc_type == HPC_PCIE)
-			(void) pciehpc_uninit(pcieb->pcieb_dip);
-		else if (pcieb->pcieb_hpc_type == HPC_SHPC)
-			(void) pcishpc_uninit(pcieb->pcieb_dip);
-
-		goto fail;
-	}
-
-	(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, pcieb->pcieb_dip,
-	    "hotplug-capable");
-
-	return (DDI_SUCCESS);
-
-fail:
-	pcieb->pcieb_hpc_type = HPC_NONE;
-	pcieb->pcieb_hotplug_capable = B_FALSE;
-	PCIEB_DEBUG(DBG_ATTACH, pcieb->pcieb_dip, "Failed setting hotplug"
-	    " framework\n");
-
-	return (DDI_FAILURE);
-}
-
 /*
  * Power management related initialization specific to pcieb.
  * Called by pcieb_attach()
@@ -1922,10 +1669,10 @@
 	ddi_acc_handle_t config_handle)
 {
 	uint32_t base, limit;
-	pcieb_ranges_t	ranges[PCIEB_RANGE_LEN];
+	ppb_ranges_t	ranges[PCIEB_RANGE_LEN];
 	uint8_t io_base_lo, io_limit_lo;
 	uint16_t io_base_hi, io_limit_hi, mem_base, mem_limit;
-	int i = 0, rangelen = sizeof (pcieb_ranges_t)/sizeof (int);
+	int i = 0, rangelen = sizeof (ppb_ranges_t)/sizeof (int);
 
 	io_base_lo = pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW);
 	io_limit_lo = pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW);
--- a/usr/src/uts/common/io/pciex/pcieb.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/io/pciex/pcieb.h	Mon Nov 02 15:58:28 2009 +0800
@@ -70,7 +70,6 @@
 #define	PX_MDT_11	0x01
 #define	PX_MDT_22	0x10
 
-
 #define	NUM_LOGICAL_SLOTS	32
 #define	PCIEB_RANGE_LEN		2
 #define	PCIEB_32BIT_IO		1
@@ -82,30 +81,9 @@
 #define	PCIEB_LADDR(lo, hi) (((uint16_t)(hi) << 16) | (uint16_t)(lo))
 #define	PCIEB_32bit_MEMADDR(addr) (PCIEB_LADDR(0, ((uint16_t)(addr) & 0xFFF0)))
 
-/*
- * The following typedef is used to represent an entry in the "ranges"
- * property of a device node.
- */
-typedef struct {
-	uint32_t	child_high;
-	uint32_t	child_mid;
-	uint32_t	child_low;
-	uint32_t	parent_high;
-	uint32_t	parent_mid;
-	uint32_t	parent_low;
-	uint32_t	size_high;
-	uint32_t	size_low;
-} pcieb_ranges_t;
-
-typedef enum { HPC_NONE, HPC_PCIE, HPC_SHPC, HPC_OUTBAND } pcieb_hpc_type_t;
-
 typedef struct {
 	dev_info_t		*pcieb_dip;
 
-	/* Hotplug support */
-	boolean_t		pcieb_hotplug_capable;
-	pcieb_hpc_type_t	pcieb_hpc_type;
-
 	/* Interrupt support */
 	ddi_intr_handle_t	*pcieb_htable;		/* Intr Handlers */
 	int			pcieb_htable_size;	/* htable size */
@@ -114,7 +92,6 @@
 	int			pcieb_intr_type;	/* (MSI | FIXED) */
 	int			pcieb_isr_tab[4];	/* MSI source offset */
 
-	uint_t			pcieb_soft_state;
 	int			pcieb_init_flags;
 	kmutex_t		pcieb_mutex;		/* Soft state mutex */
 	kmutex_t		pcieb_intr_mutex;	/* Intr handler mutex */
@@ -156,13 +133,13 @@
  */
 #define	NVIDIA_VENDOR_ID	0x10de	/* Nvidia Vendor Id */
 
-#ifdef	BCM_SW_WORKAROUNDS
+#ifdef	PCIEB_BCM
 
 /* Workaround for address space limitation in Broadcom 5714/5715 */
 #define	PCIEB_ADDR_LIMIT_LO		0ull
 #define	PCIEB_ADDR_LIMIT_HI		((1ull << 40) - 1)
 
-#endif	/* BCM_SW_WORKAROUNDS */
+#endif	/* PCIEB_BCM */
 
 /*
  * The following values are used to initialize the cache line size
@@ -177,7 +154,6 @@
 extern void 	pcieb_plat_intr_attach(pcieb_devstate_t *pcieb);
 extern void 	pcieb_plat_initchild(dev_info_t *child);
 extern void 	pcieb_plat_uninitchild(dev_info_t *child);
-extern void 	pcieb_plat_ioctl_hotplug(dev_info_t *dip, int rv, int cmd);
 extern int	pcieb_plat_ctlops(dev_info_t *rdip, ddi_ctl_enum_t ctlop,
     void *arg);
 extern int 	pcieb_plat_pcishpc_probe(dev_info_t *dip,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/os/ddi_hp_impl.c	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,1139 @@
+/*
+ * 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.
+ */
+
+/*
+ * Sun DDI hotplug implementation specific functions
+ */
+
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+#include <sys/debug.h>
+#include <sys/avintr.h>
+#include <sys/autoconf.h>
+#include <sys/ddi.h>
+#include <sys/sunndi.h>
+#include <sys/ndi_impldefs.h>
+#include <sys/sysevent.h>
+#include <sys/sysevent/eventdefs.h>
+#include <sys/sysevent/dr.h>
+#include <sys/fs/dv_node.h>
+
+/*
+ * Local function prototypes
+ */
+/* Connector operations */
+static int ddihp_cn_pre_change_state(ddi_hp_cn_handle_t *hdlp,
+    ddi_hp_cn_state_t target_state);
+static int ddihp_cn_post_change_state(ddi_hp_cn_handle_t *hdlp,
+    ddi_hp_cn_state_t new_state);
+static int ddihp_cn_handle_state_change(ddi_hp_cn_handle_t *hdlp);
+static int ddihp_cn_change_children_state(ddi_hp_cn_handle_t *hdlp,
+    boolean_t online);
+static int ddihp_change_node_state(dev_info_t *dip, void *arg);
+/* Port operations */
+static int ddihp_port_change_state(ddi_hp_cn_handle_t *hdlp,
+    ddi_hp_cn_state_t target_state);
+static int ddihp_port_upgrade_state(ddi_hp_cn_handle_t *hdlp,
+    ddi_hp_cn_state_t target_state);
+static int ddihp_port_downgrade_state(ddi_hp_cn_handle_t *hdlp,
+    ddi_hp_cn_state_t target_state);
+/* Misc routines */
+static void ddihp_update_last_change(ddi_hp_cn_handle_t *hdlp);
+static boolean_t ddihp_check_status_prop(dev_info_t *dip);
+
+/*
+ * Global functions (called within hotplug framework)
+ */
+
+/*
+ * Implement modctl() commands for hotplug.
+ * Called by modctl_hp() in modctl.c
+ */
+int
+ddihp_modctl(int hp_op, char *path, char *cn_name, uintptr_t arg,
+    uintptr_t rval)
+{
+	dev_info_t		*dip;
+	ddi_hp_cn_handle_t	*hdlp;
+	ddi_hp_op_t		op = (ddi_hp_op_t)hp_op;
+	int			count, rv, error;
+
+	/* Get the dip of nexus node */
+	dip = e_ddi_hold_devi_by_path(path, 0);
+
+	if (dip == NULL)
+		return (ENXIO);
+
+	DDI_HP_IMPLDBG((CE_CONT, "ddihp_modctl: dip %p op %x path %s "
+	    "cn_name %s arg %p rval %p\n", (void *)dip, hp_op, path, cn_name,
+	    (void *)arg, (void *)rval));
+
+	if (!NEXUS_HAS_HP_OP(dip)) {
+		ddi_release_devi(dip);
+		return (ENOTSUP);
+	}
+
+	/* Lock before access */
+	ndi_devi_enter(dip, &count);
+
+	hdlp = ddihp_cn_name_to_handle(dip, cn_name);
+
+	if (hp_op == DDI_HPOP_CN_CREATE_PORT) {
+		if (hdlp != NULL) {
+			/* this port already exists. */
+			error = EEXIST;
+
+			goto done;
+		}
+		rv = (*(DEVI(dip)->devi_ops->devo_bus_ops->bus_hp_op))(
+		    dip, cn_name, op, NULL, NULL);
+	} else {
+		if (hdlp == NULL) {
+			/* Invalid Connection name */
+			error = ENXIO;
+
+			goto done;
+		}
+		if (hp_op == DDI_HPOP_CN_CHANGE_STATE) {
+			ddi_hp_cn_state_t target_state = (ddi_hp_cn_state_t)arg;
+			ddi_hp_cn_state_t result_state = 0;
+
+			DDIHP_CN_OPS(hdlp, op, (void *)&target_state,
+			    (void *)&result_state, rv);
+
+			DDI_HP_IMPLDBG((CE_CONT, "ddihp_modctl: target_state="
+			    "%x, result_state=%x, rv=%x \n",
+			    target_state, result_state, rv));
+		} else {
+			DDIHP_CN_OPS(hdlp, op, (void *)arg, (void *)rval, rv);
+		}
+	}
+	switch (rv) {
+	case DDI_SUCCESS:
+		error = 0;
+		break;
+	case DDI_EINVAL:
+		error = EINVAL;
+		break;
+	case DDI_EBUSY:
+		error = EBUSY;
+		break;
+	case DDI_ENOTSUP:
+		error = ENOTSUP;
+		break;
+	case DDI_ENOMEM:
+		error = ENOMEM;
+		break;
+	default:
+		error = EIO;
+	}
+
+done:
+	ndi_devi_exit(dip, count);
+
+	ddi_release_devi(dip);
+
+	return (error);
+}
+
+/*
+ * Return the state of Hotplug Connection (CN)
+ */
+int
+ddihp_cn_getstate(ddi_hp_cn_handle_t *hdlp)
+{
+	ddi_hp_cn_state_t	new_state;
+	int			ret;
+
+	DDI_HP_IMPLDBG((CE_CONT, "ddihp_cn_getstate: pdip %p hdlp %p\n",
+	    (void *)hdlp->cn_dip, (void *)hdlp));
+
+	ASSERT(DEVI_BUSY_OWNED(hdlp->cn_dip));
+
+	DDIHP_CN_OPS(hdlp, DDI_HPOP_CN_GET_STATE,
+	    NULL, (void *)&new_state, ret);
+	if (ret != DDI_SUCCESS) {
+		DDI_HP_IMPLDBG((CE_CONT, "ddihp_cn_getstate: "
+		    "CN %p getstate command failed\n", (void *)hdlp));
+
+		return (ret);
+	}
+
+	DDI_HP_IMPLDBG((CE_CONT, "ddihp_cn_getstate: hdlp %p "
+	    "current Connection state %x new Connection state %x\n",
+	    (void *)hdlp, hdlp->cn_info.cn_state, new_state));
+
+	if (new_state != hdlp->cn_info.cn_state) {
+		hdlp->cn_info.cn_state = new_state;
+		ddihp_update_last_change(hdlp);
+	}
+
+	return (ret);
+}
+
+/*
+ * Implementation function for unregistering the Hotplug Connection (CN)
+ */
+int
+ddihp_cn_unregister(ddi_hp_cn_handle_t *hdlp)
+{
+	dev_info_t	*dip = hdlp->cn_dip;
+
+	DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_unregister: hdlp %p\n",
+	    (void *)hdlp));
+
+	ASSERT(DEVI_BUSY_OWNED(dip));
+
+	(void) ddihp_cn_getstate(hdlp);
+
+	if (hdlp->cn_info.cn_state > DDI_HP_CN_STATE_OFFLINE) {
+		DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_unregister: dip %p, hdlp %p "
+		    "state %x. Device busy, failed to unregister connection!\n",
+		    (void *)dip, (void *)hdlp, hdlp->cn_info.cn_state));
+
+		return (DDI_EBUSY);
+	}
+
+	/* unlink the handle */
+	DDIHP_LIST_REMOVE(ddi_hp_cn_handle_t, (DEVI(dip)->devi_hp_hdlp), hdlp);
+
+	kmem_free(hdlp->cn_info.cn_name, strlen(hdlp->cn_info.cn_name) + 1);
+	kmem_free(hdlp, sizeof (ddi_hp_cn_handle_t));
+	return (DDI_SUCCESS);
+}
+
+/*
+ * For a given Connection name and the dip node where the Connection is
+ * supposed to be, find the corresponding hotplug handle.
+ */
+ddi_hp_cn_handle_t *
+ddihp_cn_name_to_handle(dev_info_t *dip, char *cn_name)
+{
+	ddi_hp_cn_handle_t *hdlp;
+
+	ASSERT(DEVI_BUSY_OWNED(dip));
+
+	DDI_HP_IMPLDBG((CE_CONT, "ddihp_cn_name_to_handle: "
+	    "dip %p cn_name to find: %s", (void *)dip, cn_name));
+	for (hdlp = DEVI(dip)->devi_hp_hdlp; hdlp; hdlp = hdlp->next) {
+		DDI_HP_IMPLDBG((CE_CONT, "ddihp_cn_name_to_handle: "
+		    "current cn_name: %s", hdlp->cn_info.cn_name));
+
+		if (strcmp(cn_name, hdlp->cn_info.cn_name) == 0) {
+			/* found */
+			return (hdlp);
+		}
+	}
+	DDI_HP_IMPLDBG((CE_CONT, "ddihp_cn_name_to_handle: "
+	    "failed to find cn_name"));
+	return (NULL);
+}
+
+/*
+ * Process the hotplug operations for Connector and also create Port
+ * upon user command.
+ */
+int
+ddihp_connector_ops(ddi_hp_cn_handle_t *hdlp, ddi_hp_op_t op,
+    void *arg, void *result)
+{
+	int			rv = DDI_SUCCESS;
+	dev_info_t		*dip = hdlp->cn_dip;
+
+	ASSERT(DEVI_BUSY_OWNED(dip));
+
+	DDI_HP_IMPLDBG((CE_CONT, "ddihp_connector_ops: pdip=%p op=%x "
+	    "hdlp=%p arg=%p\n", (void *)dip, op, (void *)hdlp, arg));
+
+	if (op == DDI_HPOP_CN_CHANGE_STATE) {
+		ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
+
+		rv = ddihp_cn_pre_change_state(hdlp, target_state);
+		if (rv != DDI_SUCCESS) {
+			/* the state is not changed */
+			*((ddi_hp_cn_state_t *)result) =
+			    hdlp->cn_info.cn_state;
+			return (rv);
+		}
+	}
+	ASSERT(NEXUS_HAS_HP_OP(dip));
+	rv = (*(DEVI(dip)->devi_ops->devo_bus_ops->bus_hp_op))(
+	    dip, hdlp->cn_info.cn_name, op, arg, result);
+
+	if (rv != DDI_SUCCESS) {
+		DDI_HP_IMPLDBG((CE_CONT, "ddihp_connector_ops: "
+		    "bus_hp_op failed: pdip=%p cn_name:%s op=%x "
+		    "hdlp=%p arg=%p\n", (void *)dip, hdlp->cn_info.cn_name,
+		    op, (void *)hdlp, arg));
+	}
+	if (op == DDI_HPOP_CN_CHANGE_STATE) {
+		int rv_post;
+
+		DDI_HP_IMPLDBG((CE_CONT, "ddihp_connector_ops: "
+		    "old_state=%x, new_state=%x, rv=%x\n",
+		    hdlp->cn_info.cn_state, *(ddi_hp_cn_state_t *)result, rv));
+
+		/*
+		 * After state change op is successfully done or
+		 * failed at some stages, continue to do some jobs.
+		 */
+		rv_post = ddihp_cn_post_change_state(hdlp,
+		    *(ddi_hp_cn_state_t *)result);
+
+		if (rv_post != DDI_SUCCESS)
+			rv = rv_post;
+	}
+
+	return (rv);
+}
+
+/*
+ * Process the hotplug op for Port
+ */
+int
+ddihp_port_ops(ddi_hp_cn_handle_t *hdlp, ddi_hp_op_t op,
+    void *arg, void *result)
+{
+	int		ret = DDI_SUCCESS;
+
+	ASSERT(DEVI_BUSY_OWNED(hdlp->cn_dip));
+
+	DDI_HP_IMPLDBG((CE_CONT, "ddihp_port_ops: pdip=%p op=%x hdlp=%p "
+	    "arg=%p\n", (void *)hdlp->cn_dip, op, (void *)hdlp, arg));
+
+	switch (op) {
+	case DDI_HPOP_CN_GET_STATE:
+	{
+		int state;
+
+		state = hdlp->cn_info.cn_state;
+
+		if (hdlp->cn_info.cn_child == NULL) {
+			/* No child. Either present or empty. */
+			if (state >= DDI_HP_CN_STATE_PORT_PRESENT)
+				state = DDI_HP_CN_STATE_PORT_PRESENT;
+			else
+				state = DDI_HP_CN_STATE_PORT_EMPTY;
+
+		} else { /* There is a child of this Port */
+
+			/* Check DEVI(dip)->devi_node_state */
+			switch (i_ddi_node_state(hdlp->cn_info.cn_child)) {
+			case	DS_INVAL:
+			case	DS_PROTO:
+			case	DS_LINKED:
+			case	DS_BOUND:
+			case	DS_INITIALIZED:
+			case	DS_PROBED:
+				state = DDI_HP_CN_STATE_OFFLINE;
+				break;
+			case	DS_ATTACHED:
+				state = DDI_HP_CN_STATE_MAINTENANCE;
+				break;
+			case	DS_READY:
+				state = DDI_HP_CN_STATE_ONLINE;
+				break;
+			default:
+				/* should never reach here */
+				ASSERT("unknown devinfo state");
+			}
+			/*
+			 * Check DEVI(dip)->devi_state in case the node is
+			 * downgraded or quiesced.
+			 */
+			if (state == DDI_HP_CN_STATE_ONLINE &&
+			    ddi_get_devstate(hdlp->cn_info.cn_child) !=
+			    DDI_DEVSTATE_UP)
+				state = DDI_HP_CN_STATE_MAINTENANCE;
+		}
+
+		*((ddi_hp_cn_state_t *)result) = state;
+
+		break;
+	}
+	case DDI_HPOP_CN_CHANGE_STATE:
+	{
+		ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
+		ddi_hp_cn_state_t curr_state = hdlp->cn_info.cn_state;
+
+		ret = ddihp_port_change_state(hdlp, target_state);
+		if (curr_state != hdlp->cn_info.cn_state) {
+			ddihp_update_last_change(hdlp);
+		}
+		*((ddi_hp_cn_state_t *)result) = hdlp->cn_info.cn_state;
+
+		break;
+	}
+	case DDI_HPOP_CN_REMOVE_PORT:
+	{
+		(void) ddihp_cn_getstate(hdlp);
+
+		if (hdlp->cn_info.cn_state != DDI_HP_CN_STATE_PORT_EMPTY) {
+			/* Only empty PORT can be removed by commands */
+			ret = DDI_EBUSY;
+
+			break;
+		}
+
+		ret = ddihp_cn_unregister(hdlp);
+		break;
+	}
+	default:
+		ret = DDI_ENOTSUP;
+		break;
+	}
+
+	return (ret);
+}
+
+/*
+ * Generate the system event with a possible hint
+ */
+/* ARGSUSED */
+void
+ddihp_cn_gen_sysevent(ddi_hp_cn_handle_t *hdlp,
+    ddi_hp_cn_sysevent_t event_sub_class, int hint, int kmflag)
+{
+	dev_info_t	*dip = hdlp->cn_dip;
+	char		*cn_path, *ap_id;
+	char		*ev_subclass = NULL;
+	nvlist_t	*ev_attr_list = NULL;
+	sysevent_id_t	eid;
+	int		ap_id_len, err;
+
+	cn_path = kmem_zalloc(MAXPATHLEN, kmflag);
+	if (cn_path == NULL) {
+		cmn_err(CE_WARN,
+		    "%s%d: Failed to allocate memory for hotplug"
+		    " connection: %s\n",
+		    ddi_driver_name(dip), ddi_get_instance(dip),
+		    hdlp->cn_info.cn_name);
+
+		return;
+	}
+
+	/*
+	 * Minor device name will be bus path
+	 * concatenated with connection name.
+	 * One of consumers of the sysevent will pass it
+	 * to cfgadm as AP ID.
+	 */
+	(void) strcpy(cn_path, "/devices");
+	(void) ddi_pathname(dip, cn_path + strlen("/devices"));
+
+	ap_id_len = strlen(cn_path) + strlen(":") +
+	    strlen(hdlp->cn_info.cn_name) + 1;
+	ap_id = kmem_zalloc(ap_id_len, kmflag);
+	if (ap_id == NULL) {
+		cmn_err(CE_WARN,
+		    "%s%d: Failed to allocate memory for AP ID: %s:%s\n",
+		    ddi_driver_name(dip), ddi_get_instance(dip),
+		    cn_path, hdlp->cn_info.cn_name);
+		kmem_free(cn_path, MAXPATHLEN);
+
+		return;
+	}
+
+	(void) strcpy(ap_id, cn_path);
+	(void) strcat(ap_id, ":");
+	(void) strcat(ap_id, hdlp->cn_info.cn_name);
+	kmem_free(cn_path, MAXPATHLEN);
+
+	err = nvlist_alloc(&ev_attr_list, NV_UNIQUE_NAME_TYPE, kmflag);
+
+	if (err != 0) {
+		cmn_err(CE_WARN,
+		    "%s%d: Failed to allocate memory for event subclass %d\n",
+		    ddi_driver_name(dip), ddi_get_instance(dip),
+		    event_sub_class);
+		kmem_free(ap_id, ap_id_len);
+
+		return;
+	}
+
+	switch (event_sub_class) {
+	case DDI_HP_CN_STATE_CHANGE:
+		ev_subclass = ESC_DR_AP_STATE_CHANGE;
+
+		switch (hint) {
+		case SE_NO_HINT:	/* fall through */
+		case SE_HINT_INSERT:	/* fall through */
+		case SE_HINT_REMOVE:
+			err = nvlist_add_string(ev_attr_list, DR_HINT,
+			    SE_HINT2STR(hint));
+
+			if (err != 0) {
+				cmn_err(CE_WARN, "%s%d: Failed to add attr [%s]"
+				    " for %s event\n", ddi_driver_name(dip),
+				    ddi_get_instance(dip), DR_HINT,
+				    ESC_DR_AP_STATE_CHANGE);
+
+				goto done;
+			}
+			break;
+
+		default:
+			cmn_err(CE_WARN, "%s%d: Unknown hint on sysevent\n",
+			    ddi_driver_name(dip), ddi_get_instance(dip));
+
+			goto done;
+		}
+
+		break;
+
+	/* event sub class: DDI_HP_CN_REQ */
+	case DDI_HP_CN_REQ:
+		ev_subclass = ESC_DR_REQ;
+
+		switch (hint) {
+		case SE_INVESTIGATE_RES: /* fall through */
+		case SE_INCOMING_RES:	/* fall through */
+		case SE_OUTGOING_RES:	/* fall through */
+			err = nvlist_add_string(ev_attr_list, DR_REQ_TYPE,
+			    SE_REQ2STR(hint));
+
+			if (err != 0) {
+				cmn_err(CE_WARN,
+				    "%s%d: Failed to add attr [%s] for %s \n"
+				    "event", ddi_driver_name(dip),
+				    ddi_get_instance(dip),
+				    DR_REQ_TYPE, ESC_DR_REQ);
+
+				goto done;
+			}
+			break;
+
+		default:
+			cmn_err(CE_WARN, "%s%d:  Unknown hint on sysevent\n",
+			    ddi_driver_name(dip), ddi_get_instance(dip));
+
+			goto done;
+		}
+
+		break;
+
+	default:
+		cmn_err(CE_WARN, "%s%d:  Unknown Event subclass\n",
+		    ddi_driver_name(dip), ddi_get_instance(dip));
+
+		goto done;
+	}
+
+	/*
+	 * Add Hotplug Connection (CN) as attribute (common attribute)
+	 */
+	err = nvlist_add_string(ev_attr_list, DR_AP_ID, ap_id);
+	if (err != 0) {
+		cmn_err(CE_WARN, "%s%d: Failed to add attr [%s] for %s event\n",
+		    ddi_driver_name(dip), ddi_get_instance(dip),
+		    DR_AP_ID, EC_DR);
+
+		goto done;
+	}
+
+	/*
+	 * Log this event with sysevent framework.
+	 */
+	err = ddi_log_sysevent(dip, DDI_VENDOR_SUNW, EC_DR,
+	    ev_subclass, ev_attr_list, &eid,
+	    ((kmflag == KM_SLEEP) ? DDI_SLEEP : DDI_NOSLEEP));
+
+	if (err != 0) {
+		cmn_err(CE_WARN, "%s%d: Failed to log %s event\n",
+		    ddi_driver_name(dip), ddi_get_instance(dip), EC_DR);
+	}
+
+done:
+	nvlist_free(ev_attr_list);
+	kmem_free(ap_id, ap_id_len);
+}
+
+/*
+ * Local functions (called within this file)
+ */
+
+/*
+ * Connector operations
+ */
+
+/*
+ * Prepare to change state for a Connector: offline, unprobe, etc.
+ */
+static int
+ddihp_cn_pre_change_state(ddi_hp_cn_handle_t *hdlp,
+    ddi_hp_cn_state_t target_state)
+{
+	ddi_hp_cn_state_t	curr_state = hdlp->cn_info.cn_state;
+	dev_info_t		*dip = hdlp->cn_dip;
+	int			rv = DDI_SUCCESS;
+
+	if (curr_state > target_state &&
+	    curr_state == DDI_HP_CN_STATE_ENABLED) {
+		/*
+		 * If the Connection goes to a lower state from ENABLED,
+		 *  then offline all children under it.
+		 */
+		rv = ddihp_cn_change_children_state(hdlp, B_FALSE);
+		if (rv != DDI_SUCCESS) {
+			cmn_err(CE_WARN,
+			    "(%s%d): "
+			    "failed to unconfigure the device in the"
+			    " Connection %s\n", ddi_driver_name(dip),
+			    ddi_get_instance(dip),
+			    hdlp->cn_info.cn_name);
+
+			return (rv);
+		}
+		ASSERT(NEXUS_HAS_HP_OP(dip));
+		/*
+		 * Remove all the children and their ports
+		 * after they are offlined.
+		 */
+		rv = (*(DEVI(dip)->devi_ops->devo_bus_ops->bus_hp_op))(
+		    dip, hdlp->cn_info.cn_name, DDI_HPOP_CN_UNPROBE,
+		    NULL, NULL);
+		if (rv != DDI_SUCCESS) {
+			cmn_err(CE_WARN,
+			    "(%s%d): failed"
+			    " to unprobe the device in the Connector"
+			    " %s\n", ddi_driver_name(dip),
+			    ddi_get_instance(dip),
+			    hdlp->cn_info.cn_name);
+
+			return (rv);
+		}
+
+		DDI_HP_NEXDBG((CE_CONT,
+		    "ddihp_connector_ops (%s%d): device"
+		    " is unconfigured and unprobed in Connector %s\n",
+		    ddi_driver_name(dip), ddi_get_instance(dip),
+		    hdlp->cn_info.cn_name));
+	}
+
+	return (rv);
+}
+
+/*
+ * Jobs after change state of a Connector: update last change time,
+ * probe, online, sysevent, etc.
+ */
+static int
+ddihp_cn_post_change_state(ddi_hp_cn_handle_t *hdlp,
+    ddi_hp_cn_state_t new_state)
+{
+	int			rv = DDI_SUCCESS;
+	ddi_hp_cn_state_t	curr_state = hdlp->cn_info.cn_state;
+
+	/* Update the state in handle */
+	if (new_state != curr_state) {
+		hdlp->cn_info.cn_state = new_state;
+		ddihp_update_last_change(hdlp);
+	}
+
+	if (curr_state < new_state &&
+	    new_state == DDI_HP_CN_STATE_ENABLED) {
+		/*
+		 * Probe and online devices if state is
+		 * upgraded to ENABLED.
+		 */
+		rv = ddihp_cn_handle_state_change(hdlp);
+	}
+	if (curr_state != hdlp->cn_info.cn_state) {
+		/*
+		 * For Connector, generate a sysevent on
+		 * state change.
+		 */
+		ddihp_cn_gen_sysevent(hdlp, DDI_HP_CN_STATE_CHANGE,
+		    SE_NO_HINT, KM_SLEEP);
+	}
+
+	return (rv);
+}
+
+/*
+ * Handle Connector state change.
+ *
+ * This function is called after connector is upgraded to ENABLED sate.
+ * It probes the device plugged in the connector to setup devinfo nodes
+ * and then online the nodes.
+ */
+static int
+ddihp_cn_handle_state_change(ddi_hp_cn_handle_t *hdlp)
+{
+	dev_info_t		*dip = hdlp->cn_dip;
+	int			rv = DDI_SUCCESS;
+
+	ASSERT(DEVI_BUSY_OWNED(dip));
+	ASSERT(NEXUS_HAS_HP_OP(dip));
+	/*
+	 * If the Connection went to state ENABLED from a lower state,
+	 * probe it.
+	 */
+	rv = (*(DEVI(dip)->devi_ops->devo_bus_ops->bus_hp_op))(
+	    dip, hdlp->cn_info.cn_name, DDI_HPOP_CN_PROBE, NULL, NULL);
+
+	if (rv != DDI_SUCCESS) {
+		ddi_hp_cn_state_t	target_state = DDI_HP_CN_STATE_POWERED;
+		ddi_hp_cn_state_t	result_state = 0;
+
+		/*
+		 * Probe failed. Disable the connector so that it can
+		 * be enabled again by a later try from userland.
+		 */
+		(void) (*(DEVI(dip)->devi_ops->devo_bus_ops->bus_hp_op))(
+		    dip, hdlp->cn_info.cn_name, DDI_HPOP_CN_CHANGE_STATE,
+		    (void *)&target_state, (void *)&result_state);
+
+		if (result_state && result_state != hdlp->cn_info.cn_state) {
+			hdlp->cn_info.cn_state = result_state;
+			ddihp_update_last_change(hdlp);
+		}
+
+		cmn_err(CE_WARN,
+		    "(%s%d): failed to probe the Connection %s\n",
+		    ddi_driver_name(dip), ddi_get_instance(dip),
+		    hdlp->cn_info.cn_name);
+
+		return (rv);
+	}
+	/*
+	 * Try to online all the children of CN.
+	 */
+	(void) ddihp_cn_change_children_state(hdlp, B_TRUE);
+
+	DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_event_handler (%s%d): "
+	    "device is configured in the Connection %s\n",
+	    ddi_driver_name(dip), ddi_get_instance(dip),
+	    hdlp->cn_info.cn_name));
+	return (rv);
+}
+
+/*
+ * Online/Offline all the children under the Hotplug Connection (CN)
+ *
+ * Do online operation when the online parameter is true; otherwise do offline.
+ */
+static int
+ddihp_cn_change_children_state(ddi_hp_cn_handle_t *hdlp, boolean_t online)
+{
+	ddi_hp_cn_cfg_t		cn_cfg;
+	dev_info_t		*dip = hdlp->cn_dip;
+	dev_info_t		*cdip;
+	ddi_hp_cn_handle_t	*h;
+	int			rv = DDI_SUCCESS;
+
+	DDI_HP_IMPLDBG((CE_CONT, "ddihp_cn_change_children_state:"
+	    " dip %p hdlp %p, online %x\n",
+	    (void *)dip, (void *)hdlp, online));
+
+	cn_cfg.online = online;
+	ASSERT(DEVI_BUSY_OWNED(dip));
+
+	/*
+	 * Return invalid if Connection state is < DDI_HP_CN_STATE_ENABLED
+	 * when try to online children.
+	 */
+	if (online && hdlp->cn_info.cn_state < DDI_HP_CN_STATE_ENABLED) {
+		DDI_HP_IMPLDBG((CE_CONT, "ddihp_cn_change_children_state: "
+		    "Connector %p is not in probed state\n", (void *)hdlp));
+
+		return (DDI_EINVAL);
+	}
+
+	/* Now, online/offline all the devices depending on the Connector */
+
+	if (!online) {
+		/*
+		 * For offline operation we need to firstly clean up devfs
+		 * so as not to prevent driver detach.
+		 */
+		(void) devfs_clean(dip, NULL, DV_CLEAN_FORCE);
+	}
+	for (h = DEVI(dip)->devi_hp_hdlp; h; h = h->next) {
+		if (h->cn_info.cn_type != DDI_HP_CN_TYPE_VIRTUAL_PORT)
+			continue;
+
+		if (h->cn_info.cn_num_dpd_on !=
+		    hdlp->cn_info.cn_num)
+			continue;
+
+		cdip = h->cn_info.cn_child;
+		ASSERT(cdip);
+		if (online) {
+			/* online children */
+			if (!ddihp_check_status_prop(dip))
+				continue;
+
+			if (ndi_devi_online(cdip,
+			    NDI_ONLINE_ATTACH | NDI_CONFIG) != NDI_SUCCESS) {
+				cmn_err(CE_WARN,
+				    "(%s%d):"
+				    " failed to attach driver for a device"
+				    " (%s%d) under the Connection %s\n",
+				    ddi_driver_name(dip), ddi_get_instance(dip),
+				    ddi_driver_name(cdip),
+				    ddi_get_instance(cdip),
+				    hdlp->cn_info.cn_name);
+				/*
+				 * One of the devices failed to online, but we
+				 * want to continue to online the rest siblings
+				 * after mark the failure here.
+				 */
+				rv = DDI_FAILURE;
+
+				continue;
+			}
+			cn_cfg.rv = NDI_SUCCESS;
+			if (ddi_get_child(cdip)) {
+				/* Continue to online grand children */
+				int c;
+
+				ndi_devi_enter(cdip, &c);
+				ddi_walk_devs(ddi_get_child(cdip),
+				    ddihp_change_node_state,
+				    (void *)&cn_cfg);
+				ndi_devi_exit(cdip, c);
+			}
+			if (cn_cfg.rv != NDI_SUCCESS) {
+				/*
+				 * one of the grand children is not ONLINE'd.
+				 */
+				cmn_err(CE_WARN,
+				    "(%s%d):"
+				    " failed to attach driver for a grandchild"
+				    "device (%s%d) in the Connection %s\n",
+				    ddi_driver_name(dip), ddi_get_instance(dip),
+				    ddi_driver_name(cdip),
+				    ddi_get_instance(cdip),
+				    hdlp->cn_info.cn_name);
+
+				rv = DDI_FAILURE;
+			}
+
+		} else {
+			/* offline children */
+			if (ndi_devi_offline(cdip, NDI_UNCONFIG) !=
+			    NDI_SUCCESS) {
+				cmn_err(CE_WARN,
+				    "(%s%d):"
+				    " failed to dettach driver for the device"
+				    " (%s%d) in the Connection %s\n",
+				    ddi_driver_name(dip), ddi_get_instance(dip),
+				    ddi_driver_name(cdip),
+				    ddi_get_instance(cdip),
+				    hdlp->cn_info.cn_name);
+
+				return (DDI_EBUSY);
+			}
+		}
+	}
+
+	return (rv);
+}
+
+/*
+ * This function is called to online or offline the dev_info nodes for an
+ * Hotplug Connection (CN).
+ */
+static int
+ddihp_change_node_state(dev_info_t *dip, void *arg)
+{
+	ddi_hp_cn_cfg_t		*cn_cfg_p = (ddi_hp_cn_cfg_t *)arg;
+	int			rv;
+
+	if (cn_cfg_p->online) {
+		/* It is online operation */
+		if (!ddihp_check_status_prop(dip))
+			return (DDI_WALK_PRUNECHILD);
+
+		rv = ndi_devi_online(dip, NDI_ONLINE_ATTACH | NDI_CONFIG);
+	} else {
+		/* It is offline operation */
+		(void) devfs_clean(ddi_get_parent(dip), NULL, DV_CLEAN_FORCE);
+		rv = ndi_devi_offline(dip, NDI_UNCONFIG);
+	}
+	if (rv != NDI_SUCCESS) {
+		DDI_HP_IMPLDBG((CE_CONT, "ddihp_change_devinfo_node_state:"
+		    " failed op %x rv %d\n", cn_cfg_p->online, rv));
+		cn_cfg_p->rv = rv;
+
+		/* Failed to attach/detach the driver(s) */
+		return (DDI_WALK_PRUNECHILD);
+	}
+
+	/* Continue the walk */
+	return (DDI_WALK_CONTINUE);
+}
+
+/*
+ * Port operations
+ */
+
+/*
+ * Change Port state to target_state.
+ */
+static int
+ddihp_port_change_state(ddi_hp_cn_handle_t *hdlp,
+    ddi_hp_cn_state_t target_state)
+{
+	ddi_hp_cn_state_t curr_state = hdlp->cn_info.cn_state;
+
+	if (target_state < DDI_HP_CN_STATE_PORT_EMPTY ||
+	    target_state > DDI_HP_CN_STATE_ONLINE) {
+
+		return (DDI_EINVAL);
+	}
+
+	if (curr_state < target_state)
+		return (ddihp_port_upgrade_state(hdlp, target_state));
+	else if (curr_state > target_state)
+		return (ddihp_port_downgrade_state(hdlp, target_state));
+	else
+		return (DDI_SUCCESS);
+}
+
+/*
+ * Upgrade port state to target_state.
+ */
+static int
+ddihp_port_upgrade_state(ddi_hp_cn_handle_t *hdlp,
+    ddi_hp_cn_state_t target_state)
+{
+	ddi_hp_cn_state_t	curr_state, new_state, result_state;
+	dev_info_t		*cdip;
+	int			rv = DDI_SUCCESS;
+
+	curr_state = hdlp->cn_info.cn_state;
+	while (curr_state < target_state) {
+		switch (curr_state) {
+		case DDI_HP_CN_STATE_PORT_EMPTY:
+			/* Check the existence of the corresponding hardware */
+			new_state = DDI_HP_CN_STATE_PORT_PRESENT;
+			rv = ddihp_connector_ops(hdlp,
+			    DDI_HPOP_CN_CHANGE_STATE,
+			    (void *)&new_state, (void *)&result_state);
+			if (rv == DDI_SUCCESS) {
+				hdlp->cn_info.cn_state =
+				    result_state;
+			}
+			break;
+		case DDI_HP_CN_STATE_PORT_PRESENT:
+			/* Read-only probe the corresponding hardware. */
+			new_state = DDI_HP_CN_STATE_OFFLINE;
+			rv = ddihp_connector_ops(hdlp,
+			    DDI_HPOP_CN_CHANGE_STATE,
+			    (void *)&new_state, &cdip);
+			if (rv == DDI_SUCCESS) {
+				hdlp->cn_info.cn_state =
+				    DDI_HP_CN_STATE_OFFLINE;
+
+				ASSERT(hdlp->cn_info.cn_child == NULL);
+				hdlp->cn_info.cn_child = cdip;
+			}
+			break;
+		case DDI_HP_CN_STATE_OFFLINE:
+			/* fall through */
+		case DDI_HP_CN_STATE_MAINTENANCE:
+
+			cdip = hdlp->cn_info.cn_child;
+
+			rv = ndi_devi_online(cdip,
+			    NDI_ONLINE_ATTACH | NDI_CONFIG);
+			if (rv == NDI_SUCCESS) {
+				hdlp->cn_info.cn_state =
+				    DDI_HP_CN_STATE_ONLINE;
+				rv = DDI_SUCCESS;
+			} else {
+				rv = DDI_FAILURE;
+				DDI_HP_IMPLDBG((CE_CONT,
+				    "ddihp_port_upgrade_state: "
+				    "failed to online device %p at port: %s\n",
+				    (void *)cdip, hdlp->cn_info.cn_name));
+			}
+			break;
+		case DDI_HP_CN_STATE_ONLINE:
+
+			break;
+		default:
+			/* should never reach here */
+			ASSERT("unknown devinfo state");
+		}
+		curr_state = hdlp->cn_info.cn_state;
+		if (rv != DDI_SUCCESS) {
+			DDI_HP_IMPLDBG((CE_CONT, "ddihp_port_upgrade_state: "
+			    "failed curr_state=%x, target_state=%x \n",
+			    curr_state, target_state));
+			return (rv);
+		}
+	}
+
+	return (rv);
+}
+
+/*
+ * Downgrade state to target_state
+ */
+static int
+ddihp_port_downgrade_state(ddi_hp_cn_handle_t *hdlp,
+    ddi_hp_cn_state_t target_state)
+{
+	ddi_hp_cn_state_t	curr_state, new_state, result_state;
+	dev_info_t		*dip = hdlp->cn_dip;
+	dev_info_t		*cdip;
+	int			rv = DDI_SUCCESS;
+
+	curr_state = hdlp->cn_info.cn_state;
+	while (curr_state > target_state) {
+
+		switch (curr_state) {
+		case DDI_HP_CN_STATE_PORT_EMPTY:
+
+			break;
+		case DDI_HP_CN_STATE_PORT_PRESENT:
+			/* Check the existence of the corresponding hardware */
+			new_state = DDI_HP_CN_STATE_PORT_EMPTY;
+			rv = ddihp_connector_ops(hdlp,
+			    DDI_HPOP_CN_CHANGE_STATE,
+			    (void *)&new_state, (void *)&result_state);
+			if (rv == DDI_SUCCESS)
+				hdlp->cn_info.cn_state =
+				    result_state;
+
+			break;
+		case DDI_HP_CN_STATE_OFFLINE:
+			/*
+			 * Read-only unprobe the corresponding hardware:
+			 * 1. release the assigned resource;
+			 * 2. remove the node pointed by the port's cn_child
+			 */
+			new_state = DDI_HP_CN_STATE_PORT_PRESENT;
+			rv = ddihp_connector_ops(hdlp,
+			    DDI_HPOP_CN_CHANGE_STATE,
+			    (void *)&new_state, (void *)&result_state);
+			if (rv == DDI_SUCCESS)
+				hdlp->cn_info.cn_state =
+				    DDI_HP_CN_STATE_PORT_PRESENT;
+			break;
+		case DDI_HP_CN_STATE_MAINTENANCE:
+			/* fall through. */
+		case DDI_HP_CN_STATE_ONLINE:
+			cdip = hdlp->cn_info.cn_child;
+
+			(void) devfs_clean(dip, NULL, DV_CLEAN_FORCE);
+			rv = ndi_devi_offline(cdip, NDI_UNCONFIG);
+			if (rv == NDI_SUCCESS) {
+				hdlp->cn_info.cn_state =
+				    DDI_HP_CN_STATE_OFFLINE;
+				rv = DDI_SUCCESS;
+			} else {
+				rv = DDI_EBUSY;
+				DDI_HP_IMPLDBG((CE_CONT,
+				    "ddihp_port_downgrade_state: failed "
+				    "to offline node, rv=%x, cdip=%p \n",
+				    rv, (void *)cdip));
+			}
+
+			break;
+		default:
+			/* should never reach here */
+			ASSERT("unknown devinfo state");
+		}
+		curr_state = hdlp->cn_info.cn_state;
+		if (rv != DDI_SUCCESS) {
+			DDI_HP_IMPLDBG((CE_CONT,
+			    "ddihp_port_downgrade_state: failed "
+			    "curr_state=%x, target_state=%x \n",
+			    curr_state, target_state));
+			return (rv);
+		}
+	}
+
+	return (rv);
+}
+
+/*
+ * Misc routines
+ */
+
+/* Update the last state change time */
+static void
+ddihp_update_last_change(ddi_hp_cn_handle_t *hdlp)
+{
+	time_t			time;
+
+	if (drv_getparm(TIME, (void *)&time) != DDI_SUCCESS)
+		hdlp->cn_info.cn_last_change = (time_t)-1;
+	else
+		hdlp->cn_info.cn_last_change = (time32_t)time;
+}
+
+/*
+ * Check the device for a 'status' property.  A conforming device
+ * should have a status of "okay", "disabled", "fail", or "fail-xxx".
+ *
+ * Return FALSE for a conforming device that is disabled or faulted.
+ * Return TRUE in every other case.
+ *
+ * 'status' property is NOT a bus specific property. It is defined in page 184,
+ * IEEE 1275 spec. The full name of the spec is "IEEE Standard for
+ * Boot (Initialization Configuration) Firmware: Core Requirements and
+ * Practices".
+ */
+static boolean_t
+ddihp_check_status_prop(dev_info_t *dip)
+{
+	char		*status_prop;
+	boolean_t	rv = B_TRUE;
+
+	/* try to get the 'status' property */
+	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "status", &status_prop) == DDI_PROP_SUCCESS) {
+		/*
+		 * test if the status is "disabled", "fail", or
+		 * "fail-xxx".
+		 */
+		if (strcmp(status_prop, "disabled") == 0) {
+			rv = B_FALSE;
+			DDI_HP_IMPLDBG((CE_CONT, "ddihp_check_status_prop "
+			    "(%s%d): device is in disabled state",
+			    ddi_driver_name(dip), ddi_get_instance(dip)));
+		} else if (strncmp(status_prop, "fail", 4) == 0) {
+			rv = B_FALSE;
+			cmn_err(CE_WARN,
+			    "hotplug (%s%d): device is in fault state (%s)\n",
+			    ddi_driver_name(dip), ddi_get_instance(dip),
+			    status_prop);
+		}
+
+		ddi_prop_free(status_prop);
+	}
+
+	return (rv);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/os/ddi_hp_ndi.c	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,405 @@
+/*
+ * 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.
+ */
+
+/*
+ * Sun NDI hotplug interfaces
+ */
+
+#include <sys/note.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+#include <sys/debug.h>
+#include <sys/avintr.h>
+#include <sys/autoconf.h>
+#include <sys/sunndi.h>
+#include <sys/ndi_impldefs.h>
+#include <sys/ddi.h>
+#include <sys/disp.h>
+#include <sys/stat.h>
+#include <sys/callb.h>
+#include <sys/sysevent.h>
+#include <sys/sysevent/eventdefs.h>
+#include <sys/sysevent/dr.h>
+#include <sys/taskq.h>
+
+/* Local functions prototype */
+static void ddihp_cn_run_event(void *arg);
+static int ddihp_cn_req_handler(ddi_hp_cn_handle_t *hdlp,
+    ddi_hp_cn_state_t target_state);
+
+/*
+ * Global functions (called by hotplug controller or nexus drivers)
+ */
+
+/*
+ * Register the Hotplug Connection (CN)
+ */
+int
+ndi_hp_register(dev_info_t *dip, ddi_hp_cn_info_t *info_p)
+{
+	ddi_hp_cn_handle_t	*hdlp;
+	int			count;
+
+	DDI_HP_NEXDBG((CE_CONT, "ndi_hp_register: dip %p, info_p %p\n",
+	    (void *)dip, (void *)info_p));
+
+	ASSERT(!servicing_interrupt());
+	if (servicing_interrupt())
+		return (NDI_FAILURE);
+
+	/* Validate the arguments */
+	if ((dip == NULL) || (info_p == NULL))
+		return (NDI_EINVAL);
+
+	if (!NEXUS_HAS_HP_OP(dip)) {
+		return (NDI_ENOTSUP);
+	}
+	/* Lock before access */
+	ndi_devi_enter(dip, &count);
+
+	hdlp = ddihp_cn_name_to_handle(dip, info_p->cn_name);
+	if (hdlp) {
+		/* This cn_name is already registered. */
+		ndi_devi_exit(dip, count);
+
+		return (NDI_SUCCESS);
+	}
+	/*
+	 * Create and initialize hotplug Connection handle
+	 */
+	hdlp = (ddi_hp_cn_handle_t *)kmem_zalloc(
+	    (sizeof (ddi_hp_cn_handle_t)), KM_SLEEP);
+
+	/* Copy the Connection information */
+	hdlp->cn_dip = dip;
+	bcopy(info_p, &(hdlp->cn_info), sizeof (*info_p));
+
+	/* Copy cn_name */
+	hdlp->cn_info.cn_name = ddi_strdup(info_p->cn_name, KM_SLEEP);
+
+	if (ddihp_cn_getstate(hdlp) != DDI_SUCCESS) {
+		DDI_HP_NEXDBG((CE_CONT, "ndi_hp_register: dip %p, hdlp %p"
+		    "ddi_cn_getstate failed\n", (void *)dip, (void *)hdlp));
+
+		goto fail;
+	}
+
+	/*
+	 * Append the handle to the list
+	 */
+	DDIHP_LIST_APPEND(ddi_hp_cn_handle_t, (DEVI(dip)->devi_hp_hdlp),
+	    hdlp);
+
+	ndi_devi_exit(dip, count);
+
+	return (NDI_SUCCESS);
+
+fail:
+	kmem_free(hdlp->cn_info.cn_name, strlen(hdlp->cn_info.cn_name) + 1);
+	kmem_free(hdlp, sizeof (ddi_hp_cn_handle_t));
+	ndi_devi_exit(dip, count);
+
+	return (NDI_FAILURE);
+}
+
+/*
+ * Unregister a Hotplug Connection (CN)
+ */
+int
+ndi_hp_unregister(dev_info_t *dip, char *cn_name)
+{
+	ddi_hp_cn_handle_t	*hdlp;
+	int			count;
+	int			ret;
+
+	DDI_HP_NEXDBG((CE_CONT, "ndi_hp_unregister: dip %p, cn name %s\n",
+	    (void *)dip, cn_name));
+
+	ASSERT(!servicing_interrupt());
+	if (servicing_interrupt())
+		return (NDI_FAILURE);
+
+	/* Validate the arguments */
+	if ((dip == NULL) || (cn_name == NULL))
+		return (NDI_EINVAL);
+
+	ndi_devi_enter(dip, &count);
+
+	hdlp = ddihp_cn_name_to_handle(dip, cn_name);
+	if (hdlp == NULL) {
+		ndi_devi_exit(dip, count);
+		return (NDI_EINVAL);
+	}
+
+	switch (ddihp_cn_unregister(hdlp)) {
+	case DDI_SUCCESS:
+		ret = NDI_SUCCESS;
+		break;
+	case DDI_EINVAL:
+		ret = NDI_EINVAL;
+		break;
+	case DDI_EBUSY:
+		ret = NDI_BUSY;
+		break;
+	default:
+		ret = NDI_FAILURE;
+		break;
+	}
+
+	ndi_devi_exit(dip, count);
+
+	return (ret);
+}
+
+/*
+ * Notify the Hotplug Connection (CN) to change state.
+ * Flag:
+ *	DDI_HP_REQ_SYNC	    Return after the change is finished.
+ *	DDI_HP_REQ_ASYNC    Return after the request is dispatched.
+ */
+int
+ndi_hp_state_change_req(dev_info_t *dip, char *cn_name,
+    ddi_hp_cn_state_t state, uint_t flag)
+{
+	ddi_hp_cn_async_event_entry_t	*eventp;
+
+	DDI_HP_NEXDBG((CE_CONT, "ndi_hp_state_change_req: dip %p "
+	    "cn_name: %s, state %x, flag %x\n",
+	    (void *)dip, cn_name, state, flag));
+
+	/* Validate the arguments */
+	if (dip == NULL || cn_name == NULL)
+		return (NDI_EINVAL);
+
+	if (!NEXUS_HAS_HP_OP(dip)) {
+		return (NDI_ENOTSUP);
+	}
+	/*
+	 * If the request is to handle the event synchronously, then call
+	 * the event handler without queuing the event.
+	 */
+	if (flag & DDI_HP_REQ_SYNC) {
+		ddi_hp_cn_handle_t	*hdlp;
+		int			count;
+		int			ret;
+
+		ASSERT(!servicing_interrupt());
+		if (servicing_interrupt())
+			return (NDI_FAILURE);
+
+		ndi_devi_enter(dip, &count);
+
+		hdlp = ddihp_cn_name_to_handle(dip, cn_name);
+		if (hdlp == NULL) {
+			ndi_devi_exit(dip, count);
+
+			return (NDI_EINVAL);
+		}
+
+		DDI_HP_NEXDBG((CE_CONT, "ndi_hp_state_change_req: hdlp %p "
+		    "calling ddihp_cn_req_handler() directly to handle "
+		    "target_state %x\n", (void *)hdlp, state));
+
+		ret = ddihp_cn_req_handler(hdlp, state);
+
+		ndi_devi_exit(dip, count);
+
+		return (ret);
+	}
+
+	eventp = kmem_zalloc(sizeof (ddi_hp_cn_async_event_entry_t),
+	    KM_NOSLEEP);
+	if (eventp == NULL)
+		return (NDI_NOMEM);
+
+	eventp->cn_name = ddi_strdup(cn_name, KM_NOSLEEP);
+	if (eventp->cn_name == NULL) {
+		kmem_free(eventp, sizeof (ddi_hp_cn_async_event_entry_t));
+		return (NDI_NOMEM);
+	}
+	eventp->dip = dip;
+	eventp->target_state = state;
+
+	/*
+	 * Hold the parent's ref so that it won't disappear when the taskq is
+	 * scheduled to run.
+	 */
+	ndi_hold_devi(dip);
+
+	if (!taskq_dispatch(system_taskq, ddihp_cn_run_event, eventp,
+	    TQ_NOSLEEP)) {
+		ndi_rele_devi(dip);
+		DDI_HP_NEXDBG((CE_CONT, "ndi_hp_state_change_req: "
+		    "taskq_dispatch failed! dip %p "
+		    "target_state %x\n", (void *)dip, state));
+		return (NDI_NOMEM);
+	}
+
+	return (NDI_CLAIMED);
+}
+
+/*
+ * Walk the link of Hotplug Connection handles of a dip:
+ *	DEVI(dip)->devi_hp_hdlp->[link of connections]
+ */
+void
+ndi_hp_walk_cn(dev_info_t *dip, int (*f)(ddi_hp_cn_info_t *,
+    void *), void *arg)
+{
+	int			count;
+	ddi_hp_cn_handle_t	*head, *curr, *prev;
+
+	DDI_HP_NEXDBG((CE_CONT, "ndi_hp_walk_cn: dip %p arg %p\n",
+	    (void *)dip, arg));
+
+	ASSERT(!servicing_interrupt());
+	if (servicing_interrupt())
+		return;
+
+	/* Validate the arguments */
+	if (dip == NULL)
+		return;
+
+	ndi_devi_enter(dip, &count);
+
+	head = DEVI(dip)->devi_hp_hdlp;
+	curr = head;
+	prev = NULL;
+	while (curr != NULL) {
+		DDI_HP_NEXDBG((CE_CONT, "ndi_hp_walk_cn: dip %p "
+		    "current cn_name: %s\n",
+		    (void *)dip, curr->cn_info.cn_name));
+		switch ((*f)(&(curr->cn_info), arg)) {
+		case DDI_WALK_TERMINATE:
+			ndi_devi_exit(dip, count);
+
+			return;
+		case DDI_WALK_CONTINUE:
+		default:
+			if (DEVI(dip)->devi_hp_hdlp != head) {
+				/*
+				 * The current node is head and it is removed
+				 * by last call to (*f)()
+				 */
+				head = DEVI(dip)->devi_hp_hdlp;
+				curr = head;
+				prev = NULL;
+			} else if (prev && prev->next != curr) {
+				/*
+				 * The current node is a middle node or tail
+				 * node and it is removed by last call to
+				 * (*f)()
+				 */
+				curr = prev->next;
+			} else {
+				/* no removal accurred on curr node */
+				prev = curr;
+				curr = curr->next;
+			}
+		}
+	}
+	ndi_devi_exit(dip, count);
+}
+
+/*
+ * Local functions (called within this file)
+ */
+
+/*
+ * Wrapper function for ddihp_cn_req_handler() called from taskq
+ */
+static void
+ddihp_cn_run_event(void *arg)
+{
+	ddi_hp_cn_async_event_entry_t	*eventp =
+	    (ddi_hp_cn_async_event_entry_t *)arg;
+	dev_info_t			*dip = eventp->dip;
+	ddi_hp_cn_handle_t		*hdlp;
+	int				count;
+
+	/* Lock before access */
+	ndi_devi_enter(dip, &count);
+
+	hdlp = ddihp_cn_name_to_handle(dip, eventp->cn_name);
+	if (hdlp) {
+		(void) ddihp_cn_req_handler(hdlp, eventp->target_state);
+	} else {
+		DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_run_event: no handle for "
+		    "cn_name: %s dip %p. Request for target_state %x is"
+		    " dropped. \n",
+		    eventp->cn_name, (void *)dip, eventp->target_state));
+	}
+
+	ndi_devi_exit(dip, count);
+
+	/* Release the devi's ref that is held from interrupt context. */
+	ndi_rele_devi((dev_info_t *)DEVI(dip));
+	kmem_free(eventp->cn_name, strlen(eventp->cn_name) + 1);
+	kmem_free(eventp, sizeof (ddi_hp_cn_async_event_entry_t));
+}
+
+/*
+ * Handle state change request of a Hotplug Connection (CN)
+ */
+static int
+ddihp_cn_req_handler(ddi_hp_cn_handle_t *hdlp,
+    ddi_hp_cn_state_t target_state)
+{
+	dev_info_t	*dip = hdlp->cn_dip;
+	int		ret = DDI_SUCCESS;
+
+	DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_req_handler:"
+	    " hdlp %p, target_state %x\n",
+	    (void *)hdlp, target_state));
+
+	ASSERT(DEVI_BUSY_OWNED(dip));
+
+	if (ddihp_cn_getstate(hdlp) != DDI_SUCCESS) {
+		DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_req_handler: dip %p, "
+		    "hdlp %p ddi_cn_getstate failed\n", (void *)dip,
+		    (void *)hdlp));
+
+		return (NDI_UNCLAIMED);
+	}
+	if (hdlp->cn_info.cn_state != target_state) {
+		ddi_hp_cn_state_t result_state = 0;
+
+		DDIHP_CN_OPS(hdlp, DDI_HPOP_CN_CHANGE_STATE,
+		    (void *)&target_state, (void *)&result_state, ret);
+
+		DDI_HP_NEXDBG((CE_CONT, "ddihp_cn_req_handler: dip %p, "
+		    "hdlp %p changed state to %x, ret=%x\n",
+		    (void *)dip, (void *)hdlp, result_state, ret));
+	}
+
+	if (ret == DDI_SUCCESS)
+		return (NDI_CLAIMED);
+	else
+		return (NDI_UNCLAIMED);
+}
--- a/usr/src/uts/common/os/devcfg.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/os/devcfg.c	Mon Nov 02 15:58:28 2009 +0800
@@ -407,6 +407,7 @@
 	ASSERT(devi->devi_addr == NULL);
 	ASSERT(devi->devi_node_state == DS_PROTO);
 	ASSERT(devi->devi_child == NULL);
+	ASSERT(devi->devi_hp_hdlp == NULL);
 
 #if defined(__x86) && !defined(__xpv)
 	for (gfxp = gfx_devinfo_list; gfxp; gfxp = gfxp->g_next) {
@@ -652,7 +653,7 @@
 	 * This is a temporary workaround for Bug 4618861.
 	 * We keep the scsi_vhci nexus node on the left side of the devinfo
 	 * tree (under the root nexus driver), so that virtual nodes under
-	 * scsi_vhci will be SUSPENDed first and RESUMEd last.  This ensures
+	 * scsi_vhci will be SUSPENDed first and RESUMEd last.	This ensures
 	 * that the pHCI nodes are active during times when their clients
 	 * may be depending on them.  This workaround embodies the knowledge
 	 * that system PM and CPR both traverse the tree left-to-right during
@@ -695,6 +696,7 @@
 	struct dev_info *devi = DEVI(dip);
 	struct dev_info *parent = devi->devi_parent;
 	dev_info_t **dipp;
+	ddi_hp_cn_handle_t *hdlp;
 
 	ASSERT(parent != NULL);
 	ASSERT(devi->devi_node_state == DS_LINKED);
@@ -737,6 +739,11 @@
 		remove_from_dn_list(&orphanlist, dip);
 	}
 
+	/* Update parent's hotplug handle list */
+	for (hdlp = DEVI(parent)->devi_hp_hdlp; hdlp; hdlp = hdlp->next) {
+		if (hdlp->cn_info.cn_child == dip)
+			hdlp->cn_info.cn_child = NULL;
+	}
 	return (DDI_SUCCESS);
 }
 
@@ -2453,7 +2460,7 @@
 	n += get_class(ddi_driver_name(dip), buf);
 	unlock_hw_class_list();
 
-	ASSERT(n == nclass);    /* make sure buf wasn't overrun */
+	ASSERT(n == nclass);	/* make sure buf wasn't overrun */
 	return (nclass);
 }
 
@@ -3094,7 +3101,7 @@
 }
 #else /* DEBUG */
 #define	debug_dtree(a1, a2, a3)	 /* nothing */
-#endif  /* DEBUG */
+#endif	/* DEBUG */
 
 static void
 ddi_optimize_dtree(dev_info_t *devi)
@@ -3288,7 +3295,7 @@
 	 * when uhci/ohci reset themselves, it induces a port change on
 	 * the ehci companion controller.  Since there's no interrupt handler
 	 * installed at the time, the moment that interrupt is unmasked, an
-	 * interrupt storm will occur.  All this is averted when ehci is
+	 * interrupt storm will occur.	All this is averted when ehci is
 	 * loaded first.  And now you know..... the REST of the story.
 	 *
 	 * Regardless of platform, ehci needs to initialize first to avoid
@@ -4226,7 +4233,7 @@
  * outstanding attach or detach operations in progress when quiesce_devices() or
  * reset_leaves()is invoked.  It must be called before the system becomes
  * single-threaded because device attach and detach are multi-threaded
- * operations.  (note that during system shutdown the system doesn't actually
+ * operations.	(note that during system shutdown the system doesn't actually
  * become single-thread since other threads still exist, but the shutdown thread
  * will disable preemption for itself, raise it's pil, and stop all the other
  * cpus in the system there by effectively making the system single-threaded.)
@@ -4420,7 +4427,7 @@
 	 * We are called either from rem_drv or update_drv when reloading
 	 * a driver.conf file. In either case, we unbind persistent nodes
 	 * and destroy .conf nodes. In the case of rem_drv, this will be
-	 * the final state. In the case of update_drv,  i_ddi_bind_devs()
+	 * the final state. In the case of update_drv,	i_ddi_bind_devs()
 	 * may be invoked later to re-enumerate (new) driver.conf rebind
 	 * persistent nodes.
 	 */
@@ -5371,7 +5378,7 @@
 	 * We may have a genericname on a system that creates drivername
 	 * nodes (from .conf files).  Find the drivername by nodeid. If we
 	 * can't find a node with devnm as the node name then we search by
-	 * drivername.  This allows an implementation to supply a genericly
+	 * drivername.	This allows an implementation to supply a genericly
 	 * named boot path (disk) and locate drivename nodes (sd).  The
 	 * NDI_PROMNAME flag does not apply to /devices/pseudo paths.
 	 */
@@ -8480,7 +8487,7 @@
 static int
 mark_and_fence(dev_info_t *dip, void *arg)
 {
-	char    *fencepath = (char *)arg;
+	char	*fencepath = (char *)arg;
 
 	/*
 	 * We have already decided to retire this device. The various
@@ -8541,7 +8548,7 @@
 	    (void *)dip, path));
 
 	/*
-	 * Check if this device is in the "retired" store i.e.  should
+	 * Check if this device is in the "retired" store i.e.	should
 	 * be retired. If not, we have nothing to do.
 	 */
 	if (e_ddi_device_retired(path) == 0) {
--- a/usr/src/uts/common/os/modctl.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/os/modctl.c	Mon Nov 02 15:58:28 2009 +0800
@@ -174,7 +174,7 @@
 	num_devs = read_binding_file(majbind, mb_hashtab, make_mbind);
 	/*
 	 * Since read_binding_file is common code, it doesn't enforce that all
-	 * of the binding file entries have major numbers <= MAXMAJ32.  Thus,
+	 * of the binding file entries have major numbers <= MAXMAJ32.	Thus,
 	 * ensure that we don't allocate some massive amount of space due to a
 	 * bad entry.  We can't have major numbers bigger than MAXMAJ32
 	 * until file system support for larger major numbers exists.
@@ -1232,7 +1232,7 @@
 	char		*minor_name = NULL;
 	dev_info_t	*dip = NULL;
 	int		circ;
-	struct ddi_minor_data   *dmdp;
+	struct ddi_minor_data	*dmdp;
 	char		*path = NULL;
 	int		ulens;
 	int		lens;
@@ -1998,7 +1998,7 @@
 	 * instance of a device bound to the driver being
 	 * removed, remove any underlying devfs attribute nodes.
 	 *
-	 * This is a two-step process.  First we go through
+	 * This is a two-step process.	First we go through
 	 * the instance data itself, constructing a list of
 	 * the nodes discovered.  The second step is then
 	 * to find and remove any devfs attribute nodes
@@ -2261,6 +2261,67 @@
 	return (ret);
 }
 
+static int
+modctl_hp(int subcmd, const char *path, char *cn_name, uintptr_t arg,
+    uintptr_t rval)
+{
+	int error = 0;
+	size_t pathsz, namesz;
+	char *devpath, *cn_name_str;
+
+	if (path == NULL)
+		return (EINVAL);
+
+	devpath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+	error = copyinstr(path, devpath, MAXPATHLEN, &pathsz);
+	if (error != 0) {
+		kmem_free(devpath, MAXPATHLEN);
+		return (EFAULT);
+	}
+
+	cn_name_str = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
+	error = copyinstr(cn_name, cn_name_str, MAXNAMELEN, &namesz);
+	if (error != 0) {
+		kmem_free(devpath, MAXPATHLEN);
+		kmem_free(cn_name_str, MAXNAMELEN);
+
+		return (EFAULT);
+	}
+
+	switch (subcmd) {
+	case MODHPOPS_CHANGE_STATE:
+		error = ddihp_modctl(DDI_HPOP_CN_CHANGE_STATE, devpath,
+		    cn_name_str, arg, NULL);
+		break;
+	case MODHPOPS_CREATE_PORT:
+		/* Create an empty PORT */
+		error = ddihp_modctl(DDI_HPOP_CN_CREATE_PORT, devpath,
+		    cn_name_str, NULL, NULL);
+		break;
+	case MODHPOPS_REMOVE_PORT:
+		/* Remove an empty PORT */
+		error = ddihp_modctl(DDI_HPOP_CN_REMOVE_PORT, devpath,
+		    cn_name_str, NULL, NULL);
+		break;
+	case MODHPOPS_BUS_GET:
+		error = ddihp_modctl(DDI_HPOP_CN_GET_PROPERTY, devpath,
+		    cn_name_str, arg, rval);
+		break;
+	case MODHPOPS_BUS_SET:
+		error = ddihp_modctl(DDI_HPOP_CN_SET_PROPERTY, devpath,
+		    cn_name_str, arg, rval);
+		break;
+	default:
+		error = ENOTSUP;
+		break;
+	}
+
+	kmem_free(devpath, MAXPATHLEN);
+	kmem_free(cn_name_str, MAXNAMELEN);
+
+	return (error);
+}
+
 int
 modctl_moddevname(int subcmd, uintptr_t a1, uintptr_t a2)
 {
@@ -2421,7 +2482,7 @@
 #endif
 		break;
 
-	case MODGETDEVFSPATH:   	/* get path name of (dev_t,spec) type */
+	case MODGETDEVFSPATH:		/* get path name of (dev_t,spec) type */
 		if (get_udatamodel() == DATAMODEL_NATIVE) {
 			error = modctl_devfspath((dev_t)a1, (int)a2,
 			    (uint_t)a3, (char *)a4);
@@ -2439,7 +2500,7 @@
 		    (uint_t *)a3);
 		break;
 
-	case MODGETDEVFSPATH_MI:   	/* get path name of (major,instance) */
+	case MODGETDEVFSPATH_MI:	/* get path name of (major,instance) */
 		error = modctl_devfspath_mi((major_t)a1, (int)a2,
 		    (uint_t)a3, (char *)a4);
 		break;
@@ -2536,6 +2597,11 @@
 		error = modctl_unretire((char *)a1);
 		break;
 
+	case MODHPOPS:	/* hotplug operations */
+		/* device named by physpath a2 and Connection name a3 */
+		error = modctl_hp((int)a1, (char *)a2, (char *)a3, a4, a5);
+		break;
+
 	default:
 		error = EINVAL;
 		break;
@@ -3235,7 +3301,7 @@
 
 /*
  * Lookup a symbol in a specified module.  These are wrapper routines that
- * call kobj_lookup().  kobj_lookup() may go away but these wrappers will
+ * call kobj_lookup().	kobj_lookup() may go away but these wrappers will
  * prevent callers from noticing.
  */
 uintptr_t
@@ -4171,7 +4237,7 @@
 		 * which are dependent on it from being uninstalled and
 		 * unloaded. "on_mod"'s mod_ref count decremented in
 		 * mod_release_requisites when the "dependent" module
-		 * unload is complete.  "on_mod" must be loaded, but may not
+		 * unload is complete.	"on_mod" must be loaded, but may not
 		 * yet be installed.
 		 */
 		on_mod->mod_ref++;
--- a/usr/src/uts/common/sys/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/sys/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -148,6 +148,8 @@
 	ddi.h			\
 	ddifm.h			\
 	ddifm_impl.h		\
+	ddi_hp.h		\
+	ddi_hp_impl.h		\
 	ddi_intr.h		\
 	ddi_intr_impl.h		\
 	ddi_impldefs.h		\
--- a/usr/src/uts/common/sys/autoconf.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/sys/autoconf.h	Mon Nov 02 15:58:28 2009 +0800
@@ -26,7 +26,6 @@
 #ifndef _SYS_AUTOCONF_H
 #define	_SYS_AUTOCONF_H
 
-
 /* Derived from autoconf.h, SunOS 4.1.1 1.15 */
 
 #ifdef	__cplusplus
@@ -113,6 +112,9 @@
 #define	LDI_EV_DEBUG		0x8000  /* LDI events debug messages */
 #define	LDI_EV_TRACE		0x10000 /* LDI events trace messages */
 #define	DDI_INTR_IRM		0x20000 /* interrupt resource management */
+#define	DDI_HP_API		0x40000	/* Hotplug interface messages  */
+#define	DDI_HP_IMPL		0x80000	/* Hotplug implementation msgs */
+#define	DDI_HP_NEXUS		0x100000 /* Hotplug messages from nexuses */
 
 extern int ddidebug;
 
@@ -133,6 +135,9 @@
 #define	LDI_EVDBG(args)		if (ddidebug & LDI_EV_DEBUG) cmn_err args
 #define	LDI_EVTRC(args)		if (ddidebug & LDI_EV_TRACE) cmn_err args
 #define	DDI_INTR_IRMDBG(args)	if (ddidebug & DDI_INTR_IRM) cmn_err args
+#define	DDI_HP_APIDBG(args)	if (ddidebug & DDI_HP_API) cmn_err args
+#define	DDI_HP_IMPLDBG(args)	if (ddidebug & DDI_HP_IMPL) cmn_err args
+#define	DDI_HP_NEXDBG(args)	if (ddidebug & DDI_HP_NEXUS) cmn_err args
 #else
 #define	NDI_CONFIG_DEBUG(args)
 #define	BMDPRINTF(args)
@@ -150,6 +155,9 @@
 #define	LDI_EVDBG(args)		if (ddidebug & LDI_EV_DEBUG) cmn_err args
 #define	LDI_EVTRC(args)		if (ddidebug & LDI_EV_TRACE) cmn_err args
 #define	DDI_INTR_IRMDBG(args)
+#define	DDI_HP_APIDBG(args)
+#define	DDI_HP_IMPLDBG(args)
+#define	DDI_HP_NEXDBG(args)
 #endif
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/ddi_hp.h	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,126 @@
+/*
+ * 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	_SYS_DDI_HP_H
+#define	_SYS_DDI_HP_H
+
+/*
+ * Sun DDI hotplug support definitions
+ */
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * ddi_hp_cn_state_t
+ *
+ * Typedef of generic hotplug state machine for Hotplug Connection (CN)
+ */
+typedef enum {
+	DDI_HP_CN_STATE_EMPTY		= 0x1000, /* Empty */
+	DDI_HP_CN_STATE_PRESENT		= 0x2000, /* A Device Present */
+	DDI_HP_CN_STATE_POWERED		= 0x3000, /* Powered */
+	DDI_HP_CN_STATE_ENABLED		= 0x4000, /* Enabled */
+	DDI_HP_CN_STATE_PORT_EMPTY	= 0x5000, /* PORT Empty */
+	DDI_HP_CN_STATE_PORT_PRESENT	= 0x6000, /* A Device Node Present */
+	DDI_HP_CN_STATE_OFFLINE		= 0x7000, /* Driver not attached */
+	DDI_HP_CN_STATE_ATTACHED	= 0x8000, /* Device driver attached */
+	DDI_HP_CN_STATE_MAINTENANCE	= 0x9000, /* Device in maintenance */
+	DDI_HP_CN_STATE_ONLINE		= 0xa000  /* Device is ready */
+} ddi_hp_cn_state_t;
+
+/*
+ * ddi_hp_cn_type_t
+ *
+ * Typedef for Hotplug Connection (CN) types.
+ */
+typedef enum {
+	DDI_HP_CN_TYPE_VIRTUAL_PORT	= 0x1,	/* Virtual Hotplug Port */
+	DDI_HP_CN_TYPE_PCI		= 0x2,	/* PCI bus slot */
+	DDI_HP_CN_TYPE_PCIE		= 0x3	/* PCI Express slot */
+} ddi_hp_cn_type_t;
+
+#define	DDI_HP_CN_TYPE_STR_PORT "Virtual-Port"
+/*
+ * The value set to ddi_hp_cn_info_t->cn_num_dpd_on in the case of the
+ * connection does not depend on any other connections.
+ */
+#define	DDI_HP_CN_NUM_NONE	-1
+
+/*
+ * ddi_hp_cn_info_t
+ *
+ * Hotplug Connection (CN) information structure
+ */
+typedef struct ddi_hp_cn_info {
+	char			*cn_name;	/* Name of the Connection */
+	/*
+	 * Connection number.
+	 */
+	int			cn_num;
+	/*
+	 * Depend-on connection number;
+	 * The connection number on which this connection is depending on.
+	 * If this connection does not depend on any other connections
+	 * under the same parent node, then it's cn_num_dpd_on is set to
+	 * DDI_HP_CN_NUM_NONE.
+	 */
+	int			cn_num_dpd_on;
+
+	ddi_hp_cn_type_t	cn_type;	/* Type: Port, PCI, PCIE, ... */
+
+	/*
+	 * Description string for types of Connection. Set by bus software
+	 * and read by users only.
+	 */
+	char			*cn_type_str;
+	/*
+	 * The child device of this Port.
+	 * It is NULL if this is a Connector.
+	 */
+	dev_info_t		*cn_child;
+
+	ddi_hp_cn_state_t	cn_state;	/* Hotplug Connection state */
+	time32_t		cn_last_change;	/* Last time state changed. */
+} ddi_hp_cn_info_t;
+
+typedef struct ddi_hp_property {
+	char	*nvlist_buf;
+	size_t	buf_size;
+} ddi_hp_property_t;
+
+#if defined(_SYSCALL32)
+typedef struct ddi_hp_property32 {
+	caddr32_t	nvlist_buf;
+	uint32_t	buf_size;
+} ddi_hp_property32_t;
+#endif
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_DDI_HP_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/ddi_hp_impl.h	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,160 @@
+/*
+ * 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	_SYS_DDI_HP_IMPL_H
+#define	_SYS_DDI_HP_IMPL_H
+
+/*
+ * Sun DDI hotplug implementation specific definitions
+ */
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#ifdef _KERNEL
+
+/* Flags for sync request and async hotplug request */
+#define	DDI_HP_REQ_SYNC 0x0001
+#define	DDI_HP_REQ_ASYNC 0x0002
+
+/* Check if a handle represents a port or a connector */
+#define	DDI_HP_IS_VIRTUAL_PORT(hdlp)		\
+	(hdlp->cn_info.cn_type == DDI_HP_CN_TYPE_VIRTUAL_PORT)
+
+/*
+ * ddi_hp_cn_handle_t
+ *
+ * DDI handle for a registered Hotplug Connection (CN)
+ */
+typedef struct ddi_hp_cn_handle {
+	dev_info_t		*cn_dip; /* The dip that the handle is linked */
+	ddi_hp_cn_info_t	cn_info; /* Connection info */
+	struct ddi_hp_cn_handle	*next;	 /* Next Connector/Port. */
+} ddi_hp_cn_handle_t;
+
+typedef struct ddi_hp_cn_async_event_entry {
+	dev_info_t			*dip;
+	char				*cn_name;
+	ddi_hp_cn_state_t		target_state;
+} ddi_hp_cn_async_event_entry_t;
+
+/*
+ * ddi_hp_op_t
+ *
+ * Typedef for Hotplug OPS commands used with bus_hp_op()
+ */
+typedef enum {
+	DDI_HPOP_CN_GET_STATE = 1,	/* Get Connection state */
+	DDI_HPOP_CN_CHANGE_STATE,	/* Change Connection state */
+	DDI_HPOP_CN_PROBE,		/* Probe Connection */
+	DDI_HPOP_CN_UNPROBE,		/* Unprobe Connection */
+	DDI_HPOP_CN_GET_PROPERTY,	/* Get bus specific property */
+	DDI_HPOP_CN_SET_PROPERTY,	/* Set bus specific property */
+	DDI_HPOP_CN_CREATE_PORT,	/* Create a port for virtual hotplug */
+	DDI_HPOP_CN_REMOVE_PORT		/* Remove an empty port */
+} ddi_hp_op_t;
+
+#define	DDIHP_CN_OPS(hdlp, op, arg, result, ret)		\
+	if (DDI_HP_IS_VIRTUAL_PORT(hdlp))			\
+		ret = ddihp_port_ops(hdlp, op, arg, result);	\
+	else							\
+		ret = ddihp_connector_ops(hdlp, op, arg, result);
+
+#define	NEXUS_HAS_HP_OP(dip)						\
+	((DEVI(dip)->devi_ops->devo_bus_ops) &&				\
+	(DEVI(dip)->devi_ops->devo_bus_ops->busops_rev >= BUSO_REV_10) && \
+	(DEVI(dip)->devi_ops->devo_bus_ops->bus_hp_op))
+
+/*
+ * ddi_hp_cn_sysevent_t
+ *
+ * The following correspond to sysevent defined subclasses
+ */
+typedef enum {
+	DDI_HP_CN_STATE_CHANGE,
+	DDI_HP_CN_REQ
+} ddi_hp_cn_sysevent_t;
+
+/*
+ * Control structure for tree walk during configure/unconfigure operation.
+ */
+typedef struct ddi_hp_cn_cfg {
+	boolean_t	online;		/* TRUE for online children; */
+					/* FALSE for offline children. */
+	int		rv;		/* Return error code */
+} ddi_hp_cn_cfg_t;
+
+/*
+ * Misc
+ */
+
+/* Append a node to list */
+#define	DDIHP_LIST_APPEND(type, head, node)				\
+if (node) {								\
+	type *curr, *prev = NULL;					\
+	(node)->next = NULL;						\
+	for (curr = (head); curr; prev = curr, curr = curr->next);	\
+	if (prev == NULL)						\
+		(head) = (node);					\
+	else								\
+		prev->next = (node);					\
+}
+
+/* Remove a node from a list */
+#define	DDIHP_LIST_REMOVE(type, head, node)				\
+if (node) {								\
+	type *curr, *prev = NULL;					\
+	for (curr = (head); curr; prev = curr, curr = curr->next) {	\
+		if (curr == (node))					\
+			break;						\
+	}								\
+    if (curr) {								\
+	if (prev == NULL)						\
+		(head) = (head)->next;					\
+	else								\
+		prev->next = curr->next;				\
+	}								\
+}
+
+int ddihp_modctl(int hp_op, char *path, char *cn_name, uintptr_t arg,
+    uintptr_t rval);
+ddi_hp_cn_handle_t *ddihp_cn_name_to_handle(dev_info_t *dip, char *cn_name);
+int ddihp_cn_getstate(ddi_hp_cn_handle_t *hdlp);
+int ddihp_port_ops(ddi_hp_cn_handle_t *hdlp, ddi_hp_op_t op,
+    void *arg, void *result);
+int ddihp_connector_ops(ddi_hp_cn_handle_t *hdlp,
+    ddi_hp_op_t op, void *arg, void *result);
+void ddihp_cn_gen_sysevent(ddi_hp_cn_handle_t *hdlp,
+    ddi_hp_cn_sysevent_t event_sub_class, int hint, int kmflag);
+int ddihp_cn_unregister(ddi_hp_cn_handle_t *hdlp);
+
+#endif /* _KERNEL */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_DDI_HP_IMPL_H */
--- a/usr/src/uts/common/sys/ddi_impldefs.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/sys/ddi_impldefs.h	Mon Nov 02 15:58:28 2009 +0800
@@ -39,6 +39,8 @@
 #include <sys/epm.h>
 #include <sys/ddidmareq.h>
 #include <sys/ddi_intr.h>
+#include <sys/ddi_hp.h>
+#include <sys/ddi_hp_impl.h>
 #include <sys/ddi_isa.h>
 #include <sys/id_space.h>
 #include <sys/modhash.h>
@@ -69,12 +71,12 @@
  * Definitions for generic callback mechanism.
  */
 typedef enum {
-	DDI_CB_INTR_ADD,
-	DDI_CB_INTR_REMOVE
+	DDI_CB_INTR_ADD,		/* More available interrupts */
+	DDI_CB_INTR_REMOVE		/* Fewer available interrupts */
 } ddi_cb_action_t;
 
 typedef enum {
-	DDI_CB_FLAG_INTR = 0x1
+	DDI_CB_FLAG_INTR = 0x1		/* Driver is IRM aware */
 } ddi_cb_flags_t;
 
 #define	DDI_CB_FLAG_VALID(f)	((f) & DDI_CB_FLAG_INTR)
@@ -119,6 +121,7 @@
 struct iommulib_unit;
 typedef struct iommulib_unit *iommulib_handle_t;
 typedef uint8_t	ndi_flavor_t;
+struct ddi_hp_cn_handle;
 
 struct dev_info  {
 
@@ -231,8 +234,8 @@
 
 	uint_t		devi_cpr_flags;
 
-	/* For interrupt support */
-	devinfo_intr_t		*devi_intr_p;
+	/* Owned by DDI interrupt framework */
+	devinfo_intr_t	*devi_intr_p;
 
 	void		*devi_nex_pm;		/* nexus PM private */
 
@@ -267,6 +270,9 @@
 	ndi_flavor_t	devi_flavor;		/* flavor assigned by parent */
 	ndi_flavor_t	devi_flavorv_n;		/* number of child-flavors */
 	void		**devi_flavorv;		/* child-flavor specific data */
+
+	/* Owned by hotplug framework */
+	struct ddi_hp_cn_handle *devi_hp_hdlp;   /* hotplug handle list */
 };
 
 #define	DEVI(dev_info_type)	((struct dev_info *)(dev_info_type))
--- a/usr/src/uts/common/sys/devinfo_impl.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/sys/devinfo_impl.h	Mon Nov 02 15:58:28 2009 +0800
@@ -64,6 +64,9 @@
 /* new public flag for the layered drivers framework */
 #define	DINFOLYR	(DIIOC | 0x40)	/* get device layering information */
 
+/* new public flag for the hotplug framework */
+#define	DINFOHP		(DIIOC | 0x400000)  /* include hotplug information */
+
 /*
  * Straight ioctl commands, not bitwise operation
  */
@@ -119,6 +122,7 @@
 #define	DI_LINK(addr)		((struct di_link *)((void *)(addr)))
 #define	DI_LNODE(addr)		((struct di_lnode *)((void *)(addr)))
 #define	DI_PRIV_FORMAT(addr)	((struct di_priv_format *)((void *)(addr)))
+#define	DI_HP(addr)		((struct di_hp *)((void *)(addr)))
 
 /*
  * multipath component definitions:  Follows the registered component of
@@ -269,12 +273,15 @@
 	di_off_t top_phci;
 	di_off_t next_phci;
 	uint32_t multipath_component;	/* stores MDI_COMPONENT_* value. */
-
 	/*
 	 * devi_flags field
 	 */
 	uint32_t flags;
 	uint32_t di_pad2;	/* 4 byte padding for 32bit x86 app. */
+	/*
+	 * offset to hotplug nodes.
+	 */
+	di_off_t hp_data;
 };
 
 /*
@@ -321,6 +328,22 @@
 };
 
 /*
+ * chain of hotplug information structures
+ */
+struct di_hp {
+	di_off_t	self;		/* make it self addressable */
+	di_off_t	next;		/* next one in chain */
+	di_off_t	hp_name;	/* name of hotplug connection */
+	int		hp_connection;	/* connection number */
+	int		hp_depends_on;	/* connection number depended upon */
+	int		hp_state;	/* current hotplug state */
+	int		hp_type;	/* connection type: PCI, ... */
+	di_off_t	hp_type_str;	/* description of connection type */
+	uint32_t	hp_last_change;	/* timestamp of last change */
+	di_off_t	hp_child;	/* child device node */
+};
+
+/*
  * Flags for snap_state
  */
 #define	DI_PATH_SNAP_NOCLIENT	0x01	/* client endpt not in snapshot */
--- a/usr/src/uts/common/sys/devops.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/sys/devops.h	Mon Nov 02 15:58:28 2009 +0800
@@ -19,14 +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_DEVOPS_H
 #define	_SYS_DEVOPS_H
 
-
 #include <sys/types.h>
 #include <sys/cred.h>
 #include <sys/uio.h>
@@ -42,6 +41,8 @@
 #include <sys/ddifm.h>
 #include <sys/nexusdefs.h>
 #include <sys/ddi_intr.h>
+#include <sys/ddi_hp.h>
+#include <sys/ddi_hp_impl.h>
 #include <sys/aio_req.h>
 #include <vm/page.h>
 
@@ -145,7 +146,8 @@
 #define	BUSO_REV_7	7
 #define	BUSO_REV_8	8
 #define	BUSO_REV_9	9
-#define	BUSO_REV	BUSO_REV_9
+#define	BUSO_REV_10	10
+#define	BUSO_REV	BUSO_REV_10
 
 
 struct bus_ops  {
@@ -268,6 +270,13 @@
 	int		(*bus_intr_op)(dev_info_t *dip, dev_info_t *rdip,
 			    ddi_intr_op_t op, ddi_intr_handle_impl_t *hdlp,
 			    void *result);
+
+	/*
+	 * NOTE: the following busop entrypoint is available with version
+	 * 10 or greater.
+	 */
+	int		(*bus_hp_op)(dev_info_t *dip, char *cn_name,
+			    ddi_hp_op_t op, void *arg, void *result);
 };
 
 /*
--- a/usr/src/uts/common/sys/hotplug/pci/pcicfg.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/sys/hotplug/pci/pcicfg.h	Mon Nov 02 15:58:28 2009 +0800
@@ -20,28 +20,35 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_SYS_HOTPLUG_PCI_PCICFG_H
 #define	_SYS_HOTPLUG_PCI_PCICFG_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
+typedef enum pcicfg_flags {
+	/* No probing; used in case of virtual hotplug */
+	PCICFG_FLAG_READ_ONLY = 0x1,
+	/* Enable ARI; used in case of boot case */
+	PCICFG_FLAG_ENABLE_ARI = 0x2
+} pcicfg_flags_t;
+
 /*
  * Interfaces exported by PCI configurator module, kernel/misc/pcicfg.
  */
-int pcicfg_configure(dev_info_t *, uint_t);
-int pcicfg_unconfigure(dev_info_t *, uint_t);
+int pcicfg_configure(dev_info_t *, uint_t, uint_t, pcicfg_flags_t);
+int pcicfg_unconfigure(dev_info_t *, uint_t, uint_t, pcicfg_flags_t);
 
 #define	PCICFG_SUCCESS DDI_SUCCESS
 #define	PCICFG_FAILURE DDI_FAILURE
 
+#define	PCICFG_ALL_FUNC 0xffffffff
+
 /*
  * The following subclass definition for Non Transparent bridge should
  * be moved to pci.h.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/hotplug/pci/pcie_hp.h	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,332 @@
+/*
+ * 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	_SYS_PCIE_HP_H
+#define	_SYS_PCIE_HP_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#ifdef _KERNEL
+#include <sys/ddi_hp.h>
+#include <sys/pcie_impl.h>
+#endif /* _KERNEL */
+#include "../../../../../common/pci/pci_strings.h"
+#include <sys/hotplug/pci/pcihp.h>
+
+#define	PCIEHPC_PROP_HELP		"help"
+#define	PCIEHPC_PROP_ALL		"all"
+#define	PCIEHPC_PROP_LED_FAULT		"fault_led"
+#define	PCIEHPC_PROP_LED_POWER		"power_led"
+#define	PCIEHPC_PROP_LED_ATTN		"attn_led"
+#define	PCIEHPC_PROP_LED_ACTIVE		"active_led"
+#define	PCIEHPC_PROP_CARD_TYPE		"card_type"
+#define	PCIEHPC_PROP_BOARD_TYPE		"board_type"
+#define	PCIEHPC_PROP_SLOT_CONDITION	"slot_condition"
+
+#define	PCIEHPC_PROP_VALUE_UNKNOWN	"unknown"
+#define	PCIEHPC_PROP_VALUE_ON		"on"
+#define	PCIEHPC_PROP_VALUE_OFF		"off"
+#define	PCIEHPC_PROP_VALUE_BLINK	"blink"
+#define	PCIEHPC_PROP_VALUE_PCIHOTPLUG	"pci hotplug"
+#define	PCIEHPC_PROP_VALUE_OK		"ok"
+#define	PCIEHPC_PROP_VALUE_FAILING	"failing"
+#define	PCIEHPC_PROP_VALUE_FAILED	"failed"
+#define	PCIEHPC_PROP_VALUE_UNUSABLE	"unusable"
+#define	PCIEHPC_PROP_VALUE_LED		"<on|off|blink>"
+#define	PCIEHPC_PROP_VALUE_TYPE		"<type description>"
+#define	PCIEHPC_PROP_VALUE_CONDITION	"<unknown|ok|failing|failed|unusable>"
+
+/* condition */
+#define	PCIEHPC_PROP_COND_OK		"ok"
+#define	PCIEHPC_PROP_COND_FAILING	"failing"
+#define	PCIEHPC_PROP_COND_FAILED	"failed"
+#define	PCIEHPC_PROP_COND_UNUSABLE	"unusable"
+#define	PCIEHPC_PROP_COND_UNKNOWN	"unknown"
+
+#ifdef _KERNEL
+
+#define	PCIE_HP_MAX_SLOTS		31	/* Max # of slots */
+#define	PCIE_HP_CMD_WAIT_TIME		10000	/* Delay in microseconds */
+#define	PCIE_HP_CMD_WAIT_RETRY		100	/* Max retry count */
+#define	PCIE_HP_DLL_STATE_CHANGE_TIMEOUT 1	/* Timeout in seconds */
+#define	PCIE_HP_POWER_GOOD_WAIT_TIME	220000	/* Wait time after issuing a */
+						/* cmd to change slot state */
+
+/* definations for PCIEHPC/PCISHPC */
+#define	PCIE_NATIVE_HP_TYPE	"PCIe-Native"		/* PCIe Native type */
+#define	PCIE_ACPI_HP_TYPE	"PCIe-ACPI"		/* PCIe ACPI type */
+#define	PCIE_PROP_HP_TYPE	"PCIe-Proprietary"	/* PCIe Prop type */
+#define	PCIE_PCI_HP_TYPE	"PCI-SHPC"		/* PCI (SHPC) type */
+
+#define	PCIE_GET_HP_CTRL(dip)	\
+	(pcie_hp_ctrl_t *)PCIE_DIP2BUS(dip)->bus_hp_ctrl
+
+#define	PCIE_SET_HP_CTRL(dip, ctrl_p) \
+	(PCIE_DIP2BUS(dip)->bus_hp_ctrl) = (pcie_hp_ctrl_t *)ctrl_p
+
+#define	PCIE_IS_PCIE_HOTPLUG_CAPABLE(bus_p) \
+	((bus_p->bus_hp_sup_modes & PCIE_ACPI_HP_MODE) || \
+	(bus_p->bus_hp_sup_modes & PCIE_NATIVE_HP_MODE))
+
+#define	PCIE_IS_PCI_HOTPLUG_CAPABLE(bus_p) \
+	(bus_p->bus_hp_sup_modes & PCIE_PCI_HP_MODE)
+
+#define	PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p) \
+	((bus_p->bus_hp_curr_mode == PCIE_ACPI_HP_MODE) || \
+	(bus_p->bus_hp_curr_mode == PCIE_NATIVE_HP_MODE))
+
+#define	PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p) \
+	(bus_p->bus_hp_curr_mode & PCIE_PCI_HP_MODE)
+
+typedef struct pcie_hp_ctrl pcie_hp_ctrl_t;
+typedef struct pcie_hp_slot pcie_hp_slot_t;
+
+/*
+ * Maximum length of the string converted from the digital number of pci device
+ * number and function number, including the string's end mark. For example,
+ * device number 0 and function number 255 (ARI case), then the length is
+ * (1 + 3 + 1).
+ */
+#define	PCIE_HP_DEV_FUNC_NUM_STRING_LEN 5
+
+/*
+ * Length of the characters in a PCI port name.
+ * The format of the PCI port name is: pci.d,f where d is device number, f is
+ * function number. The constant string and characters are "pci." and ",".
+ */
+#define	PCIE_HP_PORT_NAME_STRING_LEN	5
+
+/* Platform specific ops (Native HP, ACPI, etc.) */
+typedef struct pcie_hp_ops {
+	/* initialize/setup hot plug controller hw */
+	int	(*init_hpc_hw)(pcie_hp_ctrl_t *ctrl_p);
+
+	/* uninitialize hot plug controller hw */
+	int	(*uninit_hpc_hw)(pcie_hp_ctrl_t *ctrl_p);
+
+	/* initialize slot information structure */
+	int	(*init_hpc_slotinfo)(pcie_hp_ctrl_t *ctrl_p);
+
+	/* uninitialize slot information structure */
+	int	(*uninit_hpc_slotinfo)(pcie_hp_ctrl_t *ctrl_p);
+
+	/* slot poweron */
+	int	(*poweron_hpc_slot)(pcie_hp_slot_t *slot_p,
+	    ddi_hp_cn_state_t *result);
+
+	/* slot poweroff */
+	/* uninitialize hot plug controller hw */
+	int	(*poweroff_hpc_slot)(pcie_hp_slot_t *slot_p,
+	    ddi_hp_cn_state_t *result);
+
+	/* enable hot plug interrupts/events */
+	int	(*enable_hpc_intr)(pcie_hp_ctrl_t *ctrl_p);
+
+	/* disable hot plug interrupts/events */
+	int	(*disable_hpc_intr)(pcie_hp_ctrl_t *ctrl_p);
+} pcie_hp_ops_t;
+
+/* Slot occupant information structure */
+#define	PCIE_HP_MAX_OCCUPANTS	128
+typedef struct pcie_hp_occupant_info {
+	int	i;
+	char	*id[PCIE_HP_MAX_OCCUPANTS];
+} pcie_hp_occupant_info_t;
+
+/*
+ * pcie_hp_led_t
+ *
+ * Type definitions for LED type
+ */
+typedef	enum {
+	PCIE_HP_FAULT_LED,
+	PCIE_HP_POWER_LED,
+	PCIE_HP_ATTN_LED,
+	PCIE_HP_ACTIVE_LED
+} pcie_hp_led_t;
+
+/*
+ * pcie_hp_led_state_t
+ *
+ * Type definitions for LED state
+ */
+typedef	enum {
+	PCIE_HP_LED_OFF,
+	PCIE_HP_LED_ON,
+	PCIE_HP_LED_BLINK
+} pcie_hp_led_state_t;
+
+/*
+ * PCI and PCI Express Hotplug slot structure
+ */
+struct pcie_hp_slot {
+	uint32_t	hs_num;			/* Logical slot number */
+	uint32_t	hs_phy_slot_num;	/* Physical slot number */
+	uint32_t	hs_device_num;		/* PCI device num for slot */
+	uint16_t	hs_minor;		/* Minor num for this slot */
+	ddi_hp_cn_info_t hs_info;		/* Slot information */
+	ddi_hp_cn_state_t hs_state;		/* Slot state */
+
+	pcie_hp_led_state_t hs_power_led_state;		/* Power LED state */
+	pcie_hp_led_state_t hs_attn_led_state;		/* Attn LED state */
+	pcie_hp_led_state_t hs_active_led_state;	/* Active LED state */
+	pcie_hp_led_state_t hs_fault_led_state;		/* Fault LED state */
+
+	ap_condition_t	hs_condition;		/* Condition of the slot. */
+						/* For cfgadm condition. */
+
+	/* Synchronization variable(s) for hot plug events */
+	kcondvar_t	hs_attn_btn_cv;		/* ATTN button pressed intr */
+	boolean_t	hs_attn_btn_pending;
+	kthread_t	*hs_attn_btn_threadp;	/* ATTN button event thread */
+	boolean_t	hs_attn_btn_thread_exit;
+	kcondvar_t	hs_dll_active_cv;	/* DLL State Changed intr */
+
+	pcie_hp_ctrl_t	*hs_ctrl;		/* Hotplug ctrl for this slot */
+};
+
+/*
+ * Register ops for read/write of non-standard HPC (e.g: OPL platform).
+ */
+typedef struct pcie_hp_regops {
+	uint_t	(*get)(void *cookie, off_t offset);
+	uint_t	(*put)(void *cookie, off_t offset, uint_t val);
+	void	*cookie;
+} pcie_hp_regops_t;
+
+/*
+ * PCI and PCI Express Hotplug controller structure
+ */
+struct pcie_hp_ctrl {
+	dev_info_t	*hc_dip;		/* DIP for HP controller */
+	kmutex_t	hc_mutex;		/* Mutex for this ctrl */
+	uint_t		hc_flags;		/* Misc flags */
+
+	/* Slot information */
+	pcie_hp_slot_t	*hc_slots[PCIE_HP_MAX_SLOTS]; /* Slot pointers */
+	boolean_t	hc_has_attn;		/* Do we have attn btn?	*/
+	boolean_t	hc_has_mrl;		/* Do we have MRL? */
+	kcondvar_t	hc_cmd_comp_cv;		/* Command Completion intr */
+	boolean_t	hc_cmd_pending;		/* Command completion pending */
+
+	/* PCI Express Hotplug specific fields */
+	boolean_t	hc_has_emi_lock;	/* Do we have EMI Lock? */
+	boolean_t	hc_dll_active_rep;	/* Report DLL DL_Active state */
+	pcie_hp_ops_t	hc_ops;			/* Platform specific ops */
+						/* (Native, ACPI) */
+
+	/* PCI Hotplug (SHPC) specific fields */
+	uint32_t	hc_num_slots_impl;	/* # of HP Slots Implemented */
+	uint32_t	hc_num_slots_connected;	/* # of HP Slots Connected */
+	int		hc_curr_bus_speed;	/* Current Bus Speed */
+	uint32_t	hc_device_start;	/* 1st PCI Device # */
+	uint32_t	hc_phys_start;		/* 1st Phys Device # */
+	uint32_t	hc_device_increases;	/* Device # Increases */
+	boolean_t	hc_arbiter_timeout;	/* Got a Arb timeout IRQ */
+
+	/* Register read/write ops for non-standard HPC (e.g: OPL) */
+	pcie_hp_regops_t hc_regops;
+
+	/* Platform implementation specific data if any: ACPI, CK804,... */
+	void		*hc_misc_data;
+};
+
+/*
+ * Control structure for tree walk during configure/unconfigure operation.
+ */
+typedef struct pcie_hp_cn_cfg_t {
+	void *slotp;
+	boolean_t		flag;		/* Flag to ignore errors */
+	int			rv;		/* Return error code */
+	dev_info_t		*dip;		/* dip at which the (first) */
+						/* error occurred */
+	void			*cn_private;	/* Connection specific data */
+} pcie_hp_cn_cfg_t;
+
+/*
+ * arg for unregistering port of a pci bridge
+ */
+typedef struct pcie_hp_unreg_port {
+	/* pci bridge dip to which the port is associated */
+	dev_info_t	*nexus_dip;
+	/*
+	 * Connector number of the physical slot whose dependent ports will be
+	 * unregistered. If NULL, then all the ports of the pci bridge dip will
+	 * be unregistered.
+	 */
+	int		connector_num;
+	int		rv;
+} pcie_hp_unreg_port_t;
+
+/*
+ * arg for getting a port's state
+ */
+typedef struct pcie_hp_port_state {
+	char			*cn_name;
+	ddi_hp_cn_state_t	cn_state;
+	int			rv;
+} pcie_hp_port_state_t;
+
+/* hc_flags */
+#define	PCIE_HP_INITIALIZED_FLAG	(1 << 0) /* HPC initialized */
+
+/* PCIe hotplug friendly functions */
+extern int pcie_hp_init(dev_info_t *dip, caddr_t arg);
+extern int pcie_hp_uninit(dev_info_t *dip);
+extern int pcie_hp_intr(dev_info_t *dip);
+extern int pcie_hp_probe(pcie_hp_slot_t *slot_p);
+extern int pcie_hp_unprobe(pcie_hp_slot_t *slot_p);
+extern int pcie_hp_common_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
+    void *arg, void *result);
+extern dev_info_t *pcie_hp_devi_find(dev_info_t *dip, uint_t device,
+    uint_t function);
+extern void pcie_hp_create_occupant_props(dev_info_t *self, dev_t dev,
+    int pci_dev);
+extern void pcie_hp_create_occupant_props(dev_info_t *self, dev_t dev,
+    int pci_dev);
+extern void pcie_hp_delete_occupant_props(dev_info_t *dip, dev_t dev);
+extern int pcie_copyin_nvlist(char *packed_buf, size_t packed_sz,
+    nvlist_t **nvlp);
+extern int pcie_copyout_nvlist(nvlist_t *nvl, char *packed_buf,
+    size_t *packed_sz);
+extern char *pcie_led_state_text(pcie_hp_led_state_t state);
+extern char *pcie_slot_condition_text(ap_condition_t condition);
+extern int pcie_create_minor_node(pcie_hp_ctrl_t *, int);
+extern void pcie_remove_minor_node(pcie_hp_ctrl_t *, int);
+extern void pcie_hp_gen_sysevent_req(char *slot_name, int hint,
+    dev_info_t *self, int kmflag);
+
+extern const struct pci_class_strings_s class_pci[];
+extern int class_pci_items;
+
+#endif /* _KERNEL */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_PCIE_HP_H */
--- a/usr/src/uts/common/sys/hotplug/pci/pciehpc.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/sys/hotplug/pci/pciehpc.h	Mon Nov 02 15:58:28 2009 +0800
@@ -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.
@@ -19,17 +18,14 @@
  *
  * 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.
  */
 
 #ifndef	_SYS_HOTPLUG_PCI_PCIEHPC_H
 #define	_SYS_HOTPLUG_PCI_PCIEHPC_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -37,17 +33,22 @@
 /*
  * Interfaces exported by PCI-E nexus Hot Plug Controller extension module
  */
-
-/* register ops for read/write of non-standard HPC (e.g: OPL platform) */
-typedef struct pciehpc_regops {
-	uint_t	(*get)(void *cookie, off_t offset);
-	uint_t	(*put)(void *cookie, off_t offset, uint_t val);
-	void	*cookie;
-} pciehpc_regops_t;
-
-int pciehpc_init(dev_info_t *, pciehpc_regops_t *);
-int pciehpc_uninit(dev_info_t *);
-int pciehpc_intr(dev_info_t *);
+int pciehpc_init(dev_info_t *dip, caddr_t arg);
+int pciehpc_uninit(dev_info_t *dip);
+int pciehpc_intr(dev_info_t *dip);
+int pciehpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op, void *arg,
+    void *result);
+void pciehpc_get_slot_state(pcie_hp_slot_t *slot_p);
+void pciehpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p);
+uint8_t pciehpc_reg_get8(pcie_hp_ctrl_t *ctrl_p, uint_t off);
+uint16_t pciehpc_reg_get16(pcie_hp_ctrl_t *ctrl_p, uint_t off);
+uint32_t pciehpc_reg_get32(pcie_hp_ctrl_t *ctrl_p, uint_t off);
+void pciehpc_reg_put8(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint8_t val);
+void pciehpc_reg_put16(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint16_t val);
+void pciehpc_reg_put32(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint32_t val);
+#if	defined(__i386) || defined(__amd64)
+extern void pciehpc_update_ops(pcie_hp_ctrl_t *ctrl_p);
+#endif	/* defined(__i386) || defined(__amd64) */
 
 #ifdef	__cplusplus
 }
--- a/usr/src/uts/common/sys/hotplug/pci/pciehpc_impl.h	Sun Nov 01 14:14:46 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,233 +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 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef	_SYS_HOTPLUG_PCI_PCIEHPC_IMPL_H
-#define	_SYS_HOTPLUG_PCI_PCIEHPC_IMPL_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-#include <sys/disp.h>
-#include <sys/stat.h>
-#include <sys/condvar.h>
-#include <sys/pcie.h>
-#include <sys/hotplug/hpcsvc.h>
-#include <sys/hotplug/pci/pciehpc.h>
-
-/*
- * PCI Express Hot Plug slot softstate structure
- *
- */
-typedef struct pciehpc_slot
-{
-	hpc_slot_info_t	slot_info;		/* HPS framework slot info */
-	hpc_slot_t	slot_handle;		/* HPS framework handle */
-	hpc_slot_ops_t	slot_ops;		/* HPS framework callbacks */
-	uint32_t	fault_led_state;	/* Fault LED state */
-	uint32_t	power_led_state;	/* Power LED state */
-	uint32_t	attn_led_state;		/* Attn LED state */
-	uint32_t	active_led_state;	/* Active LED state */
-	hpc_slot_state_t slot_state;		/* Slot State */
-	uint32_t	slotNum;		/* slot number */
-	/* synchronization variable(s) for hot plug events */
-	kcondvar_t	cmd_comp_cv;		/* Command Completion intr. */
-	boolean_t	command_pending;
-	kcondvar_t	attn_btn_cv;		/* ATTN button pressed intr */
-	boolean_t	attn_btn_pending;
-	kthread_t	*attn_btn_threadp;	/* ATTN button event thread */
-	boolean_t	attn_btn_thread_exit;
-	kcondvar_t	dll_active_cv;		/* DLL State Changed intr */
-} pciehpc_slot_t;
-
-typedef enum {
-	PCIEHPC_NATIVE_HP_MODE, PCIEHPC_ACPI_HP_MODE
-} pciehpc_hp_mode_t;
-
-typedef uint32_t pciehpc_soft_state_t;
-
-/* init_flags */
-#define	PCIEHPC_SOFT_STATE_UNINITIALIZED	0x01
-#define	PCIEHPC_SOFT_STATE_INITIALIZED		0x02
-#define	PCIEHPC_SOFT_STATE_INIT_HTABLE		0x04
-#define	PCIEHPC_SOFT_STATE_INIT_ALLOC		0x08
-#define	PCIEHPC_SOFT_STATE_INIT_HANDLER		0x10
-#define	PCIEHPC_SOFT_STATE_INIT_ENABLE		0x20
-#define	PCIEHPC_SOFT_STATE_INIT_BLOCK		0x40
-#define	PCIEHPC_SOFT_STATE_INIT_FM		0x80
-#define	PCIEHPC_SOFT_STATE_PCIE_DEV		0x10000
-
-/*
- * PCI Express Hotplug controller soft state structure
- */
-typedef struct pciehpc
-{
-	dev_info_t		*dip;		/* DIP for the Nexus */
-	uint8_t			bus;		/* primary bus number */
-	uint8_t			dev;		/* device number */
-	uint8_t			func;		/* function number */
-	kmutex_t		pciehpc_mutex;	/* Mutex for this ctrl */
-	pciehpc_soft_state_t	soft_state;	/* soft state flags */
-	pciehpc_hp_mode_t	hp_mode;	/* HP mode (Native, ACPI) */
-	struct pciehpc		*nextp;		/* Linked list pointer */
-
-	/* PCIE Hot Plug Controller register access */
-	ddi_acc_handle_t	cfghdl;		/* PCI cfg access handle */
-	caddr_t			regs_base;	/* config regs base */
-	uint_t		pcie_caps_reg_offset;	/* offset to PCIE Cap regs */
-
-	/* slot information */
-	pciehpc_slot_t		slot;		/* Slot info */
-	boolean_t		has_attn;	/* Do we have attn btn? */
-	boolean_t		has_mrl;	/* Do we have MRL? */
-	boolean_t		has_emi_lock;	/* Do we have EMI Lock? */
-
-	/* link capablities */
-	boolean_t	dll_active_rep;	/* Do we report DLL DL_Active state? */
-
-	/* register read/write ops for non-standard HPC (e.g: OPL) */
-	pciehpc_regops_t	regops;
-
-	/* platform specific ops (Native HP, ACPI, etc.) */
-	struct pciehpc_ops {
-		/* initialize/setup hot plug controller hw */
-		int	(*init_hpc_hw)(struct pciehpc *ctrl_p);
-		/* initialize slot information structure */
-		int	(*init_hpc_slotinfo)(struct pciehpc *ctrl_p);
-		/* disable hot plug interrupts/events */
-		int	(*disable_hpc_intr)(struct pciehpc *ctrl_p);
-		/* enable hot plug interrupts/events */
-		int	(*enable_hpc_intr)(struct pciehpc *ctrl_p);
-		/* uninitialize hot plug controller hw */
-		int	(*uninit_hpc_hw)(struct pciehpc *ctrl_p);
-		/* uninitialize slot information structure */
-		int	(*uninit_hpc_slotinfo)(struct pciehpc *ctrl_p);
-		/* probe for HPC */
-		int	(*probe_hpc)(struct pciehpc *ctrl_p);
-	} ops;
-
-	/* platform implementation specific data if any: ACPI, CK804,... */
-	void			*misc_data;
-} pciehpc_t;
-
-typedef struct pciehpc_ops pciehpc_ops_t;
-
-/*
- * PCI-E HPC Command Completion delay in microseconds and the max retry
- * count.
- */
-#define	PCIEHPC_CMD_WAIT_TIME	10000
-#define	PCIEHPC_CMD_WAIT_RETRY	100
-
-/*
- * PCI-E HPC Dll State Change time out in seconds
- */
-#define	PCIEHPC_DLL_STATE_CHANGE_TIMEOUT 1
-
-#define	SLOTCTL_SUPPORTED_INTRS_MASK	\
-	(PCIE_SLOTCTL_ATTN_BTN_EN \
-	| PCIE_SLOTCTL_PWR_FAULT_EN \
-	| PCIE_SLOTCTL_MRL_SENSOR_EN \
-	| PCIE_SLOTCTL_PRESENCE_CHANGE_EN \
-	| PCIE_SLOTCTL_CMD_INTR_EN \
-	| PCIE_SLOTCTL_HP_INTR_EN \
-	| PCIE_SLOTCTL_DLL_STATE_EN)
-
-#define	SLOT_STATUS_EVENTS	\
-	(PCIE_SLOTSTS_ATTN_BTN_PRESSED \
-	| PCIE_SLOTSTS_PWR_FAULT_DETECTED \
-	| PCIE_SLOTSTS_MRL_SENSOR_CHANGED \
-	| PCIE_SLOTSTS_COMMAND_COMPLETED \
-	| PCIE_SLOTSTS_PRESENCE_CHANGED \
-	| PCIE_SLOTSTS_DLL_STATE_CHANGED)
-
-/*
- * function prototype defintions for common native mode functions in
- * PCIEHPC module.
- */
-int pciehpc_hpc_init(pciehpc_t *ctrl_p);
-int pciehpc_hpc_uninit(pciehpc_t *ctrl_p);
-int pciehpc_slotinfo_init(pciehpc_t *ctrl_p);
-int pciehpc_enable_intr(pciehpc_t *ctrl_p);
-int pciehpc_disable_intr(pciehpc_t *ctrl_p);
-int pciehpc_slotinfo_uninit(pciehpc_t *ctrl_p);
-int pciehpc_probe_hpc(pciehpc_t *ctrl_p);
-hpc_led_state_t pciehpc_led_state_to_hpc(uint16_t state);
-uint16_t pciehpc_led_state_to_pciehpc(hpc_led_state_t state);
-hpc_led_state_t pciehpc_get_led_state(pciehpc_t *ctrl_p, hpc_led_t led);
-void pciehpc_set_led_state(pciehpc_t *ctrl_p, hpc_led_t led,
-	hpc_led_state_t state);
-int pciehpc_slot_connect(caddr_t ops_arg, hpc_slot_t slot_hdl,
-	void *data, uint_t flags);
-int pciehpc_slot_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl,
-	void *data, uint_t flags);
-int pciehpc_slot_control(caddr_t ops_arg, hpc_slot_t slot_hdl,
-	int request, caddr_t arg);
-void pciehpc_get_slot_state(pciehpc_t *ctrl_p);
-void pciehpc_issue_hpc_command(pciehpc_t *ctrl_p, uint16_t control);
-int pciehpc_regs_setup(dev_info_t *dip, uint_t rnum, offset_t off,
-	caddr_t *addrp, ddi_acc_handle_t *handle);
-void pciehpc_regs_teardown(ddi_acc_handle_t *handle);
-int pciehpc_register_slot(pciehpc_t *ctrl_p);
-int pciehpc_unregister_slot(pciehpc_t *ctrl_p);
-uint8_t pciehpc_reg_get8(pciehpc_t *ctrl_p, uint_t off);
-uint16_t pciehpc_reg_get16(pciehpc_t *ctrl_p, uint_t off);
-uint32_t pciehpc_reg_get32(pciehpc_t *ctrl_p, uint_t off);
-void pciehpc_reg_put8(pciehpc_t *ctrl_p, uint_t off, uint8_t val);
-void pciehpc_reg_put16(pciehpc_t *ctrl_p, uint_t off, uint16_t val);
-void pciehpc_reg_put32(pciehpc_t *ctrl_p, uint_t off, uint32_t val);
-void pciehpc_set_slot_name(pciehpc_t *ctrl_p);
-
-#if	defined(__i386) || defined(__amd64)
-void pciehpc_update_ops(pciehpc_t *ctrl_p);
-#endif	/* defined(__i386) || defined(__amd64) */
-
-#ifdef DEBUG
-extern int pciehpc_debug;
-#define	PCIEHPC_DEBUG(args)	if (pciehpc_debug >= 1) cmn_err args
-#define	PCIEHPC_DEBUG2(args)	if (pciehpc_debug >= 2) cmn_err args
-#define	PCIEHPC_DEBUG3(args)	if (pciehpc_debug >= 3) cmn_err args
-#else
-#define	PCIEHPC_DEBUG(args)
-#define	PCIEHPC_DEBUG2(args)
-#define	PCIEHPC_DEBUG3(args)
-#endif
-
-/* default interrupt priority for Hot Plug interrupts */
-#define	PCIEHPC_INTR_PRI	1
-
-#define	PCIE_ENABLE_ERRORS(arg1)	\
-	pcie_enable_errors(arg1);	\
-	(void) pcie_enable_ce(arg1)
-#define	PCIE_DISABLE_ERRORS(arg1)	pcie_disable_errors(arg1)
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif	/* _SYS_HOTPLUG_PCI_PCIEHPC_IMPL_H */
--- a/usr/src/uts/common/sys/hotplug/pci/pcihp.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/sys/hotplug/pci/pcihp.h	Mon Nov 02 15:58:28 2009 +0800
@@ -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_HOTPLUG_PCI_PCIHP_H
 #define	_SYS_HOTPLUG_PCI_PCIHP_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
--- a/usr/src/uts/common/sys/hotplug/pci/pcishpc.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/sys/hotplug/pci/pcishpc.h	Mon Nov 02 15:58:28 2009 +0800
@@ -18,32 +18,26 @@
  *
  * 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_PCISHPC_H
-#define	_SYS_PCISHPC_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#ifndef	_SYS_HOTPLUG_PCI_PCISHPC_H
+#define	_SYS_HOTPLUG_PCI_PCISHPC_H
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
-/*
- * Interfaces exported by SHPC Nexus extension module
- */
+int pcishpc_init(dev_info_t *dip);
+int pcishpc_uninit(dev_info_t *dip);
+int pcishpc_intr(dev_info_t *dip);
+int pcishpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op, void *arg,
+    void *result);
 
-int pcishpc_init(dev_info_t *);
-int pcishpc_uninit(dev_info_t *);
-int pcishpc_intr(dev_info_t *);
-
-#define	PCISHPC_INTR_PRI	(LOCK_LEVEL - 1)
 #ifdef	__cplusplus
 }
 #endif
 
-#endif	/* _SYS_PCISHPC_H */
+#endif	/* _SYS_HOTPLUG_PCI_PCISHPC_H */
--- a/usr/src/uts/common/sys/hotplug/pci/pcishpc_regs.h	Sun Nov 01 14:14:46 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +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_HOTPLUG_PCI_PCISHPC_REGS_H
-#define	_SYS_HOTPLUG_PCI_PCISHPC_REGS_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-/*
- * SHPC controller registers accessed via the SHPC DWORD select and DATA
- * registers in PCI configuration space relative to the SHPC capibility
- * pointer.
- */
-#define	SHPC_DWORD_SELECT_OFF		0x2
-#define	SHPC_DWORD_DATA_OFF		0x4
-
-#define	SHPC_BASE_OFFSET_REG		0x00
-#define	SHPC_SLOTS_AVAIL_I_REG		0x01
-#define	SHPC_SLOTS_AVAIL_II_REG		0x02
-#define	SHPC_SLOT_CONFIGURATION_REG	0x03
-#define	SHPC_PROF_IF_SBCR_REG		0x04
-#define	SHPC_COMMAND_STATUS_REG		0x05
-#define	SHPC_IRQ_LOCATOR_REG		0x06
-#define	SHPC_SERR_LOCATOR_REG		0x07
-#define	SHPC_CTRL_SERR_INT_REG		0x08
-#define	SHPC_LOGICAL_SLOT_REGS		0x09
-#define	SHPC_VENDOR_SPECIFIC		0x28
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif	/* _SYS_HOTPLUG_PCI_PCISHPC_REGS_H */
--- a/usr/src/uts/common/sys/modctl.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/sys/modctl.h	Mon Nov 02 15:58:28 2009 +0800
@@ -269,6 +269,7 @@
 #define	MODISRETIRED		42
 #define	MODDEVEMPTYDIR		43
 #define	MODREMDRVALIAS		44
+#define	MODHPOPS		45
 
 /*
  * sub cmds for MODEVENTS
@@ -289,6 +290,15 @@
 #define	MODDEVNAME_RECONFIG	4
 #define	MODDEVNAME_SYSAVAIL	5
 
+/*
+ * subcmds for MODHPOPS
+ */
+#define	MODHPOPS_CHANGE_STATE	0
+#define	MODHPOPS_CREATE_PORT	1
+#define	MODHPOPS_REMOVE_PORT	2
+#define	MODHPOPS_BUS_GET	3
+#define	MODHPOPS_BUS_SET	4
+
 
 /*
  * Data structure passed to modconfig command in kernel to build devfs tree
--- a/usr/src/uts/common/sys/pci.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/sys/pci.h	Mon Nov 02 15:58:28 2009 +0800
@@ -603,7 +603,7 @@
 #define	PCI_CAP_ID_VS		0x9	/* Vendor Specific */
 #define	PCI_CAP_ID_DEBUG_PORT	0xA	/* Debug Port supported */
 #define	PCI_CAP_ID_cPCI_CRC	0xB	/* CompactPCI central resource ctrl */
-#define	PCI_CAP_ID_PCI_HOTPLUG	0xC	/* PCI Hot Plug supported */
+#define	PCI_CAP_ID_PCI_HOTPLUG	0xC	/* PCI Hot Plug (SHPC) supported */
 #define	PCI_CAP_ID_P2P_SUBSYS	0xD	/* PCI bridge Sub-system ID */
 #define	PCI_CAP_ID_AGP_8X	0xE	/* AGP 8X supported */
 #define	PCI_CAP_ID_SECURE_DEV	0xF	/* Secure Device supported */
@@ -796,6 +796,104 @@
 #define	PCI_PCIX_BSS_SPL_DLY	0x20	/* Secondary split comp delayed */
 
 /*
+ * PCI Hotplug capability entry offsets
+ *
+ * SHPC based PCI hotplug controller registers accessed via the DWORD
+ * select and DATA registers in PCI configuration space relative to the
+ * PCI HP capibility pointer.
+ */
+#define	PCI_HP_DWORD_SELECT_OFF		0x2
+#define	PCI_HP_DWORD_DATA_OFF		0x4
+
+#define	PCI_HP_BASE_OFFSET_REG		0x00
+#define	PCI_HP_SLOTS_AVAIL_I_REG	0x01
+#define	PCI_HP_SLOTS_AVAIL_II_REG	0x02
+#define	PCI_HP_SLOT_CONFIGURATION_REG	0x03
+#define	PCI_HP_PROF_IF_SBCR_REG		0x04
+#define	PCI_HP_COMMAND_STATUS_REG	0x05
+#define	PCI_HP_IRQ_LOCATOR_REG		0x06
+#define	PCI_HP_SERR_LOCATOR_REG		0x07
+#define	PCI_HP_CTRL_SERR_INT_REG	0x08
+#define	PCI_HP_LOGICAL_SLOT_REGS	0x09
+#define	PCI_HP_VENDOR_SPECIFIC		0x28
+
+/* Definitions used with the PCI_HP_SLOTS_AVAIL_I_REG register */
+#define	PCI_HP_AVAIL_33MHZ_CONV_SPEED_SHIFT	0
+#define	PCI_HP_AVAIL_66MHZ_PCIX_SPEED_SHIFT	8
+#define	PCI_HP_AVAIL_100MHZ_PCIX_SPEED_SHIFT	16
+#define	PCI_HP_AVAIL_133MHZ_PCIX_SPEED_SHIFT	24
+#define	PCI_HP_AVAIL_SPEED_MASK			0x1F
+
+/* Definitions used with the PCI_HP_SLOTS_AVAIL_II_REG register */
+#define	PCI_HP_AVAIL_66MHZ_CONV_SPEED_SHIFT	0
+
+/* Register bits used with the PCI_HP_PROF_IF_SBCR_REG register */
+#define	PCI_HP_SBCR_33MHZ_CONV_SPEED		0x0
+#define	PCI_HP_SBCR_66MHZ_CONV_SPEED		0x1
+#define	PCI_HP_SBCR_66MHZ_PCIX_SPEED		0x2
+#define	PCI_HP_SBCR_100MHZ_PCIX_SPEED		0x3
+#define	PCI_HP_SBCR_133MHZ_PCIX_SPEED		0x4
+#define	PCI_HP_SBCR_SPEED_MASK			0x7
+
+/* Register bits used with the PCI_HP_COMMAND_STATUS_REG register */
+#define	PCI_HP_COMM_STS_ERR_INVALID_SPEED	0x80000
+#define	PCI_HP_COMM_STS_ERR_INVALID_COMMAND	0x40000
+#define	PCI_HP_COMM_STS_ERR_MRL_OPEN		0x20000
+#define	PCI_HP_COMM_STS_ERR_MASK		0xe0000
+#define	PCI_HP_COMM_STS_CTRL_BUSY		0x10000
+#define	PCI_HP_COMM_STS_SET_SPEED		0x40
+
+/* Register bits used with the PCI_HP_CTRL_SERR_INT_REG register */
+#define	PCI_HP_SERR_INT_GLOBAL_IRQ_MASK		0x1
+#define	PCI_HP_SERR_INT_GLOBAL_SERR_MASK	0x2
+#define	PCI_HP_SERR_INT_CMD_COMPLETE_MASK	0x4
+#define	PCI_HP_SERR_INT_ARBITER_SERR_MASK	0x8
+#define	PCI_HP_SERR_INT_CMD_COMPLETE_IRQ	0x10000
+#define	PCI_HP_SERR_INT_ARBITER_IRQ		0x20000
+#define	PCI_HP_SERR_INT_MASK_ALL		0xf
+
+/* Register bits used with the PCI_HP_LOGICAL_SLOT_REGS register */
+#define	PCI_HP_SLOT_POWER_ONLY			0x1
+#define	PCI_HP_SLOT_ENABLED			0x2
+#define	PCI_HP_SLOT_DISABLED			0x3
+#define	PCI_HP_SLOT_STATE_MASK			0x3
+#define	PCI_HP_SLOT_MRL_STATE_MASK		0x100
+#define	PCI_HP_SLOT_66MHZ_CONV_CAPABLE		0x200
+#define	PCI_HP_SLOT_CARD_EMPTY_MASK		0xc00
+#define	PCI_HP_SLOT_66MHZ_PCIX_CAPABLE		0x1000
+#define	PCI_HP_SLOT_100MHZ_PCIX_CAPABLE		0x2000
+#define	PCI_HP_SLOT_133MHZ_PCIX_CAPABLE		0x3000
+#define	PCI_HP_SLOT_PCIX_CAPABLE_MASK		0x3000
+#define	PCI_HP_SLOT_PCIX_CAPABLE_SHIFT		12
+#define	PCI_HP_SLOT_PRESENCE_DETECTED		0x10000
+#define	PCI_HP_SLOT_ISO_PWR_DETECTED		0x20000
+#define	PCI_HP_SLOT_ATTN_DETECTED		0x40000
+#define	PCI_HP_SLOT_MRL_DETECTED		0x80000
+#define	PCI_HP_SLOT_POWER_DETECTED		0x100000
+#define	PCI_HP_SLOT_PRESENCE_MASK		0x1000000
+#define	PCI_HP_SLOT_ISO_PWR_MASK		0x2000000
+#define	PCI_HP_SLOT_ATTN_MASK			0x4000000
+#define	PCI_HP_SLOT_MRL_MASK			0x8000000
+#define	PCI_HP_SLOT_POWER_MASK			0x10000000
+#define	PCI_HP_SLOT_MRL_SERR_MASK		0x20000000
+#define	PCI_HP_SLOT_POWER_SERR_MASK		0x40000000
+#define	PCI_HP_SLOT_MASK_ALL			0x5f000000
+
+/* Register bits used with the PCI_HP_IRQ_LOCATOR_REG register */
+#define	PCI_HP_IRQ_CMD_COMPLETE			0x1
+#define	PCI_HP_IRQ_SLOT_N_PENDING		0x2
+
+/* Register bits used with the PCI_HP_SERR_LOCATOR_REG register */
+#define	PCI_HP_IRQ_SERR_ARBITER_PENDING		0x1
+#define	PCI_HP_IRQ_SERR_SLOT_N_PENDING		0x2
+
+/* Register bits used with the PCI_HP_SLOT_CONFIGURATION_REG register */
+#define	PCI_HP_SLOT_CONFIG_MRL_SENSOR		0x40000000
+#define	PCI_HP_SLOT_CONFIG_ATTN_BUTTON		0x80000000
+#define	PCI_HP_SLOT_CONFIG_PHY_SLOT_NUM_SHIFT	16
+#define	PCI_HP_SLOT_CONFIG_PHY_SLOT_NUM_MASK	0x3FF
+
+/*
  * PCI Message Signalled Interrupts (MSI) capability entry offsets for 32-bit
  */
 #define	PCI_MSI_CTRL		0x02	/* MSI control register, 2 bytes */
--- a/usr/src/uts/common/sys/pci_impl.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/sys/pci_impl.h	Mon Nov 02 15:58:28 2009 +0800
@@ -26,7 +26,6 @@
 #ifndef _SYS_PCI_IMPL_H
 #define	_SYS_PCI_IMPL_H
 
-
 #include <sys/dditypes.h>
 #include <sys/memlist.h>
 
@@ -133,6 +132,24 @@
 
 #endif /* __i386 || __amd64 */
 
+/* Definitions for minor numbers */
+#define	PCI_MINOR_NUM(x, y)		(((uint_t)(x) << 8) | ((y) & 0xFF))
+#define	PCI_MINOR_NUM_TO_PCI_DEVNUM(x)	((x) & 0xFF)
+#define	PCI_MINOR_NUM_TO_INSTANCE(x)	((x) >> 8)
+#define	PCI_DEVCTL_MINOR		0xFF
+
+/*
+ * Minor numbers for dedicated pcitool nodes.
+ * Note that FF and FE minor numbers are used for other minor nodes.
+ */
+#define	PCI_TOOL_REG_MINOR_NUM		0xFD
+#define	PCI_TOOL_INTR_MINOR_NUM		0xFC
+
+/* pci devctl soft state flag */
+#define	PCI_SOFT_STATE_CLOSED		0x0
+#define	PCI_SOFT_STATE_OPEN		0x1
+#define	PCI_SOFT_STATE_OPEN_EXCL	0x2
+
 /*
  * PCI capability related definitions.
  */
--- a/usr/src/uts/common/sys/pcie.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/sys/pcie.h	Mon Nov 02 15:58:28 2009 +0800
@@ -50,6 +50,15 @@
 #define	PCIE_SLOTSTS			0x1A	/* Slot Status */
 #define	PCIE_ROOTCTL			0x1C	/* Root Control */
 #define	PCIE_ROOTSTS			0x20	/* Root Status */
+#define	PCIE_DEVCAP2			0x24	/* Device Capability 2 */
+#define	PCIE_DEVCTL2			0x28	/* Device Control 2 */
+#define	PCIE_DEVSTS2			0x2A	/* Device Status 2 */
+#define	PCIE_LINKCAP2			0x2C	/* Link Capability 2 */
+#define	PCIE_LINKCTL2			0x30	/* Link Control 2 */
+#define	PCIE_LINKSTS2			0x32	/* Link Status 2 */
+#define	PCIE_SLOTCAP2			0x34	/* Slot Capability 2 */
+#define	PCIE_SLOTCTL2			0x38	/* Slot Control 2 */
+#define	PCIE_SLOTSTS2			0x3A	/* Slot Status 2 */
 
 /*
  * PCI-Express Config Space size
@@ -60,6 +69,7 @@
  * PCI-Express Capabilities Register (2 bytes)
  */
 #define	PCIE_PCIECAP_VER_1_0		0x1	/* PCI-E spec 1.0 */
+#define	PCIE_PCIECAP_VER_2_0		0x2	/* PCI-E spec 2.0 */
 #define	PCIE_PCIECAP_VER_MASK		0xF	/* Version Mask */
 #define	PCIE_PCIECAP_DEV_TYPE_PCIE_DEV	0x00	/* PCI-E Endpont Device */
 #define	PCIE_PCIECAP_DEV_TYPE_PCI_DEV	0x10	/* "Leg PCI" Endpont Device */
@@ -303,6 +313,7 @@
 #define	PCIE_SLOTCTL_DLL_STATE_EN	0x1000	/* DLL State Changed En */
 #define	PCIE_SLOTCTL_ATTN_INDICATOR_MASK 0x00C0	/* Attn Indicator mask */
 #define	PCIE_SLOTCTL_PWR_INDICATOR_MASK	0x0300	/* Power Indicator mask */
+#define	PCIE_SLOTCTL_INTR_MASK		0x103f	/* Supported intr mask */
 
 /* State values for the Power and Attention Indicators */
 #define	PCIE_SLOTCTL_INDICATOR_STATE_ON		0x1	/* indicator ON */
@@ -334,6 +345,7 @@
 #define	PCIE_SLOTSTS_PRESENCE_DETECTED	0x40	/* Card Present in slot */
 #define	PCIE_SLOTSTS_EMI_LOCK_SET	0x0080	/* EMI Lock set */
 #define	PCIE_SLOTSTS_DLL_STATE_CHANGED	0x0100	/* DLL State Changed */
+#define	PCIE_SLOTSTS_STATUS_EVENTS	0x11f	/* Supported events */
 
 /*
  * Root Control Register (2 bytes)
@@ -352,6 +364,49 @@
 #define	PCIE_ROOTSTS_PME_STATUS		0x10000	/* PME Status */
 #define	PCIE_ROOTSTS_PME_PENDING	0x20000	/* PME Pending */
 
+/*
+ * Device Capabilities 2 Register (4 bytes)
+ */
+#define	PCIE_DEVCAP2_COM_TO_RANGE_MASK	0xF
+#define	PCIE_DEVCAP2_COM_TO_DISABLE	0x10
+#define	PCIE_DEVCAP2_ARI_FORWARD	0x20
+#define	PCIE_DEVCAP2_ATOMICOP_ROUTING	0x40
+#define	PCIE_DEVCAP2_32_ATOMICOP_COMPL  0x80
+#define	PCIE_DEVCAP2_64_ATOMICOP_COMPL  0x100
+#define	PCIE_DEVCAP2_128_CAS_COMPL	0x200
+#define	PCIE_DEVCAP2_NO_RO_PR_PR_PASS	0x400
+#define	PCIE_DEVCAP2_LTR_MECH		0x800
+#define	PCIE_DEVCAP2_TPH_COMP_SHIFT	12
+#define	PCIE_DEVCAP2_TPH_COMP_MASK	0x3
+#define	PCIE_DEVCAP2_EXT_FMT_FIELD	0x100000
+#define	PCIE_DEVCAP2_END_END_TLP_PREFIX	0x200000
+#define	PCIE_DEVCAP2_MAX_END_END_SHIFT	22
+#define	PCIE_DEVCAP2_MAX_END_END_MASK	0x3
+
+/*
+ * Device Control 2 Register (2 bytes)
+ */
+#define	PCIE_DEVCTL2_COM_TO_RANGE_0	0x0
+#define	PCIE_DEVCTL2_COM_TO_RANGE_1	0x1
+#define	PCIE_DEVCTL2_COM_TO_RANGE_2	0x2
+#define	PCIE_DEVCTL2_COM_TO_RANGE_3	0x5
+#define	PCIE_DEVCTL2_COM_TO_RANGE_4	0x6
+#define	PCIE_DEVCTL2_COM_TO_RANGE_5	0x9
+#define	PCIE_DEVCTL2_COM_TO_RANGE_6	0xa
+#define	PCIE_DEVCTL2_COM_TO_RANGE_7	0xd
+#define	PCIE_DEVCTL2_COM_TO_RANGE_8	0xe
+#define	PCIE_DEVCTL2_COM_TO_DISABLE	0x10
+#define	PCIE_DEVCTL2_ARI_FORWARD_EN	0x20
+#define	PCIE_DEVCTL2_ATOMICOP_REQ_EN	0x40
+#define	PCIE_DEVCTL2_ATOMICOP_EGRS_BLK	0x80
+#define	PCIE_DEVCTL2_IDO_REQ_EN		0x100
+#define	PCIE_DEVCTL2_IDO_COMPL_EN	0x200
+#define	PCIE_DEVCTL2_LTR_MECH_EN	0x400
+#define	PCIE_DEVCTL2_END_END_TLP_PREFIX	0x8000
+
+
+
+
 
 /*
  * PCI-Express Enhanced Capabilities Link Entry Bit Offsets
@@ -549,6 +604,25 @@
 #define	PCIE_SER_SID_UPPER_DW	0x8	/* Upper 32-bit Serial Number */
 
 /*
+ * ARI Capability Offsets
+ */
+#define	PCIE_ARI_HDR	0x0		/* Enhanced Capability Header */
+#define	PCIE_ARI_CAP	0x4		/* ARI Capability Register */
+#define	PCIE_ARI_CTL	0x6		/* ARI Control Register */
+
+#define	PCIE_ARI_CAP_MFVC_FUNC_GRP	0x01
+#define	PCIE_ARI_CAP_ASC_FUNC_GRP	0x02
+
+#define	PCIE_ARI_CAP_NEXT_FUNC_SHIFT	8
+#define	PCIE_ARI_CAP_NEXT_FUNC_MASK	0xffff
+
+#define	PCIE_ARI_CTRL_MFVC_FUNC_GRP	0x01
+#define	PCIE_ARI_CTRL_ASC_FUNC_GRP	0x02
+
+#define	PCIE_ARI_CTRL_FUNC_GRP_SHIFT	4
+#define	PCIE_ARI_CTRL_FUNC_GRP_MASK	0x7
+
+/*
  * PCI-E Common TLP Header Fields
  */
 #define	PCIE_TLP_FMT_3DW	0x00
@@ -595,6 +669,7 @@
 #define	PCIE_REQ_ID_DEV_MASK	0x00F8
 #define	PCIE_REQ_ID_FUNC_SHIFT	0
 #define	PCIE_REQ_ID_FUNC_MASK	0x0007
+#define	PCIE_REQ_ID_ARI_FUNC_MASK	0x00FF
 
 #define	PCIE_CPL_STS_SUCCESS	0
 #define	PCIE_CPL_STS_UR		1
--- a/usr/src/uts/common/sys/pcie_impl.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/sys/pcie_impl.h	Mon Nov 02 15:58:28 2009 +0800
@@ -65,6 +65,14 @@
 #define	PCIE_HAS_AER(bus_p) (bus_p->bus_aer_off)
 /* IS_ROOT = is RC or RP */
 #define	PCIE_IS_ROOT(bus_p) (PCIE_IS_RC(bus_p) || PCIE_IS_RP(bus_p))
+
+#define	PCIE_IS_HOTPLUG_CAPABLE(dip) \
+	(PCIE_DIP2BUS(dip)->bus_hp_sup_modes)
+
+#define	PCIE_IS_HOTPLUG_ENABLED(dip) \
+	((PCIE_DIP2BUS(dip)->bus_hp_curr_mode == PCIE_PCI_HP_MODE) || \
+	(PCIE_DIP2BUS(dip)->bus_hp_curr_mode == PCIE_NATIVE_HP_MODE))
+
 /*
  * This is a pseudo pcie "device type", but it's needed to explain describe
  * nodes such as PX and NPE, which aren't really PCI devices but do control or
@@ -154,6 +162,14 @@
 #define	PFD_IS_RC(pfd_p)	   PCIE_IS_RC(PCIE_PFD2BUS(pfd_p))
 #define	PFD_IS_RP(pfd_p)	   PCIE_IS_RP(PCIE_PFD2BUS(pfd_p))
 
+/* bus_hp_mode field */
+typedef enum {
+	PCIE_NONE_HP_MODE	= 0x0,
+	PCIE_ACPI_HP_MODE	= 0x1,
+	PCIE_PCI_HP_MODE	= 0x2,
+	PCIE_NATIVE_HP_MODE	= 0x4
+} pcie_hp_mode_t;
+
 typedef struct pf_pci_bdg_err_regs {
 	uint16_t pci_bdg_sec_stat;	/* PCI secondary status reg */
 	uint16_t pci_bdg_ctrl;		/* PCI bridge control reg */
@@ -244,8 +260,9 @@
 	/* Needed for PCI/PCIe fabric error handling */
 	dev_info_t	*bus_dip;
 	dev_info_t	*bus_rp_dip;
-	ddi_acc_handle_t bus_cfg_hdl;		/* error handling acc handle */
+	ddi_acc_handle_t bus_cfg_hdl;		/* error handling acc hdle */
 	uint_t		bus_fm_flags;
+	uint_t		bus_soft_state;
 
 	/* Static PCI/PCIe information */
 	pcie_req_id_t	bus_bdf;
@@ -258,6 +275,7 @@
 	uint16_t	bus_pcie_off;		/* PCIe Capability Offset */
 	uint16_t	bus_aer_off;		/* PCIe Advanced Error Offset */
 	uint16_t	bus_pcix_off;		/* PCIx Capability Offset */
+	uint16_t	bus_pci_hp_off;		/* PCI HP (SHPC) Cap Offset */
 	uint16_t	bus_ecc_ver;		/* PCIX ecc version */
 	pci_bus_range_t	bus_bus_range;		/* pci bus-range property */
 	ppb_ranges_t	*bus_addr_ranges;	/* pci range property */
@@ -271,6 +289,11 @@
 	int		bus_mps;		/* Maximum Payload Size */
 
 	void		*bus_plat_private;	/* Platform specific */
+	/* Hotplug specific fields */
+	pcie_hp_mode_t	bus_hp_sup_modes;	/* HP modes supported */
+	pcie_hp_mode_t	bus_hp_curr_mode;	/* HP mode used */
+	void		*bus_hp_ctrl;		/* HP bus ctrl data */
+	int		bus_ari;		/* ARI device */
 } pcie_bus_t;
 
 struct pf_data {
@@ -355,8 +378,28 @@
 	int		highest_common_mps;
 } pcie_max_supported_t;
 
+/*
+ * Default interrupt priority for all PCI and PCIe nexus drivers including
+ * hotplug interrupts.
+ */
+#define	PCIE_INTR_PRI		(LOCK_LEVEL - 1)
+
+/*
+ * XXX - PCIE_IS_PCIE check is required in order not to invoke these macros
+ * for non-standard PCI or PCI Express Hotplug Controllers.
+ */
+#define	PCIE_ENABLE_ERRORS(dip)	\
+	if (PCIE_IS_PCIE(PCIE_DIP2BUS(dip))) {	\
+		pcie_enable_errors(dip);	\
+		(void) pcie_enable_ce(dip);	\
+	}
+
+#define	PCIE_DISABLE_ERRORS(dip)		\
+	if (PCIE_IS_PCIE(PCIE_DIP2BUS(dip))) {	\
+		pcie_disable_errors(dip);	\
+	}
+
 #ifdef	DEBUG
-extern uint_t pcie_debug_flags;
 #define	PCIE_DBG pcie_dbg
 /* Common Debugging shortcuts */
 #define	PCIE_DBG_CFG(dip, bus_p, name, sz, off, org) \
@@ -372,18 +415,29 @@
 	    ddi_get_instance(dip), bus_p->bus_bdf, name, off, org, \
 	    PCIE_AER_GET(sz, bus_p, off))
 
-extern void pcie_dbg(char *fmt, ...);
-
 #else	/* DEBUG */
 
 #define	PCIE_DBG_CFG 0 &&
 #define	PCIE_DBG 0 &&
+#define	PCIE_ARI_DBG 0 &&
 #define	PCIE_DBG_CAP 0 &&
 #define	PCIE_DBG_AER 0 &&
 
 #endif	/* DEBUG */
 
 /* PCIe Friendly Functions */
+extern int pcie_init(dev_info_t *dip, caddr_t arg);
+extern int pcie_uninit(dev_info_t *dip);
+extern int pcie_intr(dev_info_t *dip);
+extern int pcie_open(dev_info_t *dip, dev_t *devp, int flags, int otyp,
+    cred_t *credp);
+extern int pcie_close(dev_info_t *dip, dev_t dev, int flags, int otyp,
+    cred_t *credp);
+extern int pcie_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
+    int mode, cred_t *credp, int *rvalp);
+extern int pcie_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
+    int flags, char *name, caddr_t valuep, int *lengthp);
+
 extern void pcie_init_root_port_mps(dev_info_t *dip);
 extern int pcie_initchild(dev_info_t *dip);
 extern void pcie_uninitchild(dev_info_t *dip);
@@ -422,6 +476,26 @@
 extern void pcie_set_serr_mask(uint32_t mask);
 extern void pcie_init_plat(dev_info_t *dip);
 extern void pcie_fini_plat(dev_info_t *dip);
+extern int pcie_read_only_probe(dev_info_t *, char *, dev_info_t **);
+extern dev_info_t *pcie_func_to_dip(dev_info_t *dip, pcie_req_id_t function);
+extern int pcie_ari_disable(dev_info_t *dip);
+extern int pcie_ari_enable(dev_info_t *dip);
+
+#define	PCIE_ARI_FORW_NOT_SUPPORTED	0
+#define	PCIE_ARI_FORW_SUPPORTED		1
+
+extern int pcie_ari_supported(dev_info_t *dip);
+
+#define	PCIE_ARI_FORW_DISABLED	0
+#define	PCIE_ARI_FORW_ENABLED	1
+
+extern int pcie_ari_is_enabled(dev_info_t *dip);
+
+#define	PCIE_NOT_ARI_DEVICE		0
+#define	PCIE_ARI_DEVICE			1
+
+extern int pcie_ari_device(dev_info_t *dip);
+extern int pcie_ari_get_next_function(dev_info_t *dip, int *func);
 
 /* PCIe error handling functions */
 extern int pf_scan_fabric(dev_info_t *rpdip, ddi_fm_error_t *derr,
@@ -432,6 +506,11 @@
     pcie_req_id_t);
 extern int pf_tlp_decode(pcie_bus_t *, pf_pcie_adv_err_regs_t *);
 
+#ifdef	DEBUG
+extern uint_t pcie_debug_flags;
+extern void pcie_dbg(char *fmt, ...);
+#endif	/* DEBUG */
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/uts/common/sys/sunndi.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/common/sys/sunndi.h	Mon Nov 02 15:58:28 2009 +0800
@@ -42,11 +42,15 @@
 
 #define	NDI_SUCCESS	DDI_SUCCESS	/* successful return */
 #define	NDI_FAILURE	DDI_FAILURE	/* unsuccessful return */
-#define	NDI_NOMEM	-2	/* failed to allocate resources */
-#define	NDI_BADHANDLE	-3	/* bad handle passed to in function */
-#define	NDI_FAULT	-4	/* fault during copyin/copyout */
-#define	NDI_BUSY	-5	/* device busy - could not offline */
-#define	NDI_UNBOUND	-6	/* device not bound to a driver */
+#define	NDI_NOMEM	-2		/* failed to allocate resources */
+#define	NDI_BADHANDLE	-3		/* bad handle passed to in function */
+#define	NDI_FAULT	-4		/* fault during copyin/copyout */
+#define	NDI_BUSY	-5		/* device busy - could not offline */
+#define	NDI_UNBOUND	-6		/* device not bound to a driver */
+#define	NDI_EINVAL	-7		/* invalid request or arguments */
+#define	NDI_ENOTSUP	-8		/* operation or event not supported */
+#define	NDI_CLAIMED	NDI_SUCCESS	/* event is claimed */
+#define	NDI_UNCLAIMED	-9		/* event is not claimed */
 
 /*
  * Property functions:   See also, ddipropdefs.h.
@@ -636,6 +640,23 @@
 ndi_busop_bus_unconfig(dev_info_t *dip, uint_t flags, ddi_bus_config_op_t op,
     void *arg);
 
+/*
+ * Called by the Nexus/HPC drivers to register, unregister and interact
+ * with the hotplug framework for the specified hotplug connection.
+ */
+int
+ndi_hp_register(dev_info_t *dip, ddi_hp_cn_info_t *info_p);
+
+int
+ndi_hp_unregister(dev_info_t *dip, char *cn_name);
+
+int
+ndi_hp_state_change_req(dev_info_t *dip, char *cn_name,
+    ddi_hp_cn_state_t state, uint_t flag);
+
+void
+ndi_hp_walk_cn(dev_info_t *dip, int (*f)(ddi_hp_cn_info_t *, void *),
+    void *arg);
 
 /*
  * Bus Resource allocation structures and function prototypes exported
@@ -705,12 +726,9 @@
 #define	NDI_RA_TYPE_PCI_PREFETCH_MEM	"pci_prefetchable_memory"
 #define	NDI_RA_TYPE_INTR		"interrupt"
 
-
-
 /* flag bit definition */
 #define	NDI_RA_PASS	0x0001		/* pass request up the dev tree */
 
-
 /*
  * Prototype definitions for functions exported
  */
@@ -729,7 +747,6 @@
 ndi_ra_free(dev_info_t *dip, uint64_t base, uint64_t len, char *type,
 	uint_t flag);
 
-
 /*
  * ndi_dev_is_prom_node: Return non-zero if the node is a prom node
  */
--- a/usr/src/uts/i86pc/Makefile.files	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/i86pc/Makefile.files	Mon Nov 02 15:58:28 2009 +0800
@@ -177,7 +177,7 @@
 FIPE_OBJS += fipe_drv.o fipe_pm.o
 IOAT_OBJS += ioat.o ioat_rs.o ioat_ioctl.o ioat_chan.o
 ISANEXUS_OBJS += isa.o dma_engine.o i8237A.o
-PCIE_MISC_OBJS += pcie_acpi.o pcie_x86.o
+PCIE_MISC_OBJS += pcie_acpi.o pciehpc_acpi.o pcie_x86.o
 PCI_E_NEXUS_OBJS += npe.o npe_misc.o
 PCI_E_NEXUS_OBJS += pci_common.o pci_kstats.o pci_tools.o
 PCINEXUS_OBJS += pci.o pci_common.o pci_kstats.o pci_tools.o
--- a/usr/src/uts/i86pc/Makefile.rules	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/i86pc/Makefile.rules	Mon Nov 02 15:58:28 2009 +0800
@@ -95,6 +95,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/intel/io/pciex/hotplug/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(UTSBASE)/i86pc/io/pcplusmp/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -311,6 +315,9 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/i86pc/io/pciex/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/intel/io/pciex/hotplug/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/i86pc/io/pcplusmp/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- a/usr/src/uts/i86pc/io/pci/pci.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/i86pc/io/pci/pci.c	Mon Nov 02 15:58:28 2009 +0800
@@ -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.
  */
 
@@ -163,9 +163,9 @@
  */
 
 static struct modldrv modldrv = {
-	&mod_driverops, /* Type of module */
-	"host to PCI nexus driver",
-	&pci_ops,	/* driver ops */
+	&mod_driverops, 			/* Type of module */
+	"x86 Host to PCI nexus driver",		/* Name of module */
+	&pci_ops,				/* driver ops */
 };
 
 static struct modlinkage modlinkage = {
@@ -247,6 +247,7 @@
 	}
 
 	pcip->pci_dip = devi;
+	pcip->pci_soft_state = PCI_SOFT_STATE_CLOSED;
 
 	/*
 	 * Initialize hotplug support on this bus. At minimum
@@ -267,6 +268,7 @@
 	pcip->pci_fmcap = DDI_FM_ERRCB_CAPABLE |
 	    DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
 	ddi_fm_init(devi, &pcip->pci_fmcap, &pcip->pci_fm_ibc);
+	mutex_init(&pcip->pci_mutex, NULL, MUTEX_DRIVER, NULL);
 	mutex_init(&pcip->pci_err_mutex, NULL, MUTEX_DRIVER,
 	    (void *)pcip->pci_fm_ibc);
 	mutex_init(&pcip->pci_peek_poke_mutex, NULL, MUTEX_DRIVER,
@@ -306,6 +308,7 @@
 		}
 		mutex_destroy(&pcip->pci_peek_poke_mutex);
 		mutex_destroy(&pcip->pci_err_mutex);
+		mutex_destroy(&pcip->pci_mutex);
 		ddi_fm_fini(devi);	/* Uninitialize pcitool support. */
 		pcitool_uninit(devi);
 
@@ -768,14 +771,28 @@
 pci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
 {
 	minor_t		minor = getminor(dev);
-	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
+	int		instance = PCI_MINOR_NUM_TO_INSTANCE(minor);
 	pci_state_t	*pci_p = ddi_get_soft_state(pci_statep, instance);
+	int		ret = ENOTTY;
 
 	if (pci_p == NULL)
 		return (ENXIO);
 
-	return (pci_common_ioctl(pci_p->pci_dip,
-	    dev, cmd, arg, mode, credp, rvalp));
+	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
+	case PCI_TOOL_REG_MINOR_NUM:
+	case PCI_TOOL_INTR_MINOR_NUM:
+		/* To handle pcitool related ioctls */
+		ret =  pci_common_ioctl(pci_p->pci_dip, dev, cmd, arg, mode,
+		    credp, rvalp);
+		break;
+	default:
+		/* To handle devctl and hotplug related ioctls */
+		ret = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode,
+		    credp, rvalp);
+		break;
+	}
+
+	return (ret);
 }
 
 
--- a/usr/src/uts/i86pc/io/pci/pci_common.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/i86pc/io/pci/pci_common.c	Mon Nov 02 15:58:28 2009 +0800
@@ -37,7 +37,6 @@
 #include <sys/pci.h>
 #include <sys/sunndi.h>
 #include <sys/mach_intr.h>
-#include <sys/hotplug/pci/pcihp.h>
 #include <sys/pci_intr_lib.h>
 #include <sys/psm.h>
 #include <sys/policy.h>
@@ -904,18 +903,18 @@
 
 
 /*
- * For pci_tools
+ * To handle PCI tool ioctls
  */
 
+/*ARGSUSED*/
 int
 pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
     int mode, cred_t *credp, int *rvalp)
 {
-	int rv = ENOTTY;
+	minor_t	minor = getminor(dev);
+	int	rv = ENOTTY;
 
-	minor_t minor = getminor(dev);
-
-	switch (PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
+	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
 	case PCI_TOOL_REG_MINOR_NUM:
 
 		switch (cmd) {
@@ -963,15 +962,7 @@
 		}
 		break;
 
-	/*
-	 * All non-PCItool ioctls go through here, including:
-	 *   devctl ioctls with minor number PCIHP_DEVCTL_MINOR and
-	 *   those for attachment points with where minor number is the
-	 *   device number.
-	 */
 	default:
-		rv = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode,
-		    credp, rvalp);
 		break;
 	}
 
--- a/usr/src/uts/i86pc/io/pci/pci_common.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/i86pc/io/pci/pci_common.h	Mon Nov 02 15:58:28 2009 +0800
@@ -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.
  */
 
@@ -40,7 +40,9 @@
 typedef struct pci_state {
 	dev_info_t *pci_dip;
 	int pci_fmcap;
+	uint_t pci_soft_state;
 	ddi_iblock_cookie_t pci_fm_ibc;
+	kmutex_t pci_mutex;
 	kmutex_t pci_peek_poke_mutex;
 	kmutex_t pci_err_mutex;
 } pci_state_t;
--- a/usr/src/uts/i86pc/io/pci/pci_tools.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/i86pc/io/pci/pci_tools.c	Mon Nov 02 15:58:28 2009 +0800
@@ -33,12 +33,12 @@
 #include <sys/ontrap.h>
 #include <sys/psm.h>
 #include <sys/pcie.h>
-#include <sys/hotplug/pci/pcihp.h>
 #include <sys/pci_cfgspace.h>
 #include <sys/pci_tools.h>
 #include <io/pci/pci_tools_ext.h>
 #include <sys/apic.h>
 #include <io/pci/pci_var.h>
+#include <sys/pci_impl.h>
 #include <sys/promif.h>
 #include <sys/x86_archext.h>
 #include <sys/cpuvar.h>
@@ -98,13 +98,13 @@
 	/* Create pcitool nodes for register access and interrupt routing. */
 
 	if (ddi_create_minor_node(dip, PCI_MINOR_REG, S_IFCHR,
-	    PCIHP_AP_MINOR_NUM(instance, PCI_TOOL_REG_MINOR_NUM),
+	    PCI_MINOR_NUM(instance, PCI_TOOL_REG_MINOR_NUM),
 	    DDI_NT_REGACC, 0) != DDI_SUCCESS) {
 		return (DDI_FAILURE);
 	}
 
 	if (ddi_create_minor_node(dip, PCI_MINOR_INTR, S_IFCHR,
-	    PCIHP_AP_MINOR_NUM(instance, PCI_TOOL_INTR_MINOR_NUM),
+	    PCI_MINOR_NUM(instance, PCI_TOOL_INTR_MINOR_NUM),
 	    DDI_NT_INTRCTL, 0) != DDI_SUCCESS) {
 		ddi_remove_minor_node(dip, PCI_MINOR_REG);
 		return (DDI_FAILURE);
--- a/usr/src/uts/i86pc/io/pci/pci_tools_ext.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/i86pc/io/pci/pci_tools_ext.h	Mon Nov 02 15:58:28 2009 +0800
@@ -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,15 +19,13 @@
  * 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.
  */
 
 #ifndef _PCI_TOOLS_EXT_H
 #define	_PCI_TOOLS_EXT_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -36,13 +33,6 @@
 /* This file contains pcitool defs exported to other modules of a PCI driver. */
 
 /*
- * Minor numbers for dedicated pcitool nodes.
- * Note that FF and FE minor numbers are used for other minor nodes.
- */
-#define	PCI_TOOL_REG_MINOR_NUM	0xFD
-#define	PCI_TOOL_INTR_MINOR_NUM	0xFC
-
-/*
  * Functions exported from the pci_tools.c module.
  */
 extern int pcitool_dev_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode);
--- a/usr/src/uts/i86pc/io/pciex/inc.flg	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/i86pc/io/pciex/inc.flg	Mon Nov 02 15:58:28 2009 +0800
@@ -57,7 +57,6 @@
 	usr/src/uts/i86xpv/npe			\
 	usr/src/uts/intel/pci_autoconfig	\
 	usr/src/uts/intel/pcieb			\
-	usr/src/uts/intel/pciehpc		\
 	usr/src/uts/intel/pcicfg
 
 # packaging files
--- a/usr/src/uts/i86pc/io/pciex/npe.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/i86pc/io/pciex/npe.c	Mon Nov 02 15:58:28 2009 +0800
@@ -30,6 +30,7 @@
 
 #include <sys/conf.h>
 #include <sys/modctl.h>
+#include <sys/file.h>
 #include <sys/pci_impl.h>
 #include <sys/pcie_impl.h>
 #include <sys/sysmacros.h>
@@ -39,7 +40,7 @@
 #include <sys/ddifm.h>
 #include <sys/ndifm.h>
 #include <sys/fm/util.h>
-#include <sys/hotplug/pci/pcihp.h>
+#include <sys/hotplug/pci/pcie_hp.h>
 #include <io/pci/pci_tools_ext.h>
 #include <io/pci/pci_common.h>
 #include <io/pciex/pcie_nvidia.h>
@@ -96,33 +97,25 @@
 	ddi_dma_mctl,
 	npe_ctlops,
 	ddi_bus_prop_op,
-	0,		/* (*bus_get_eventcookie)();	*/
-	0,		/* (*bus_add_eventcall)();	*/
-	0,		/* (*bus_remove_eventcall)();	*/
-	0,		/* (*bus_post_event)();		*/
-	0,		/* (*bus_intr_ctl)(); */
-	0,		/* (*bus_config)(); */
-	0,		/* (*bus_unconfig)(); */
-	npe_fm_init,	/* (*bus_fm_init)(); */
-	NULL,		/* (*bus_fm_fini)(); */
-	NULL,		/* (*bus_fm_access_enter)(); */
-	NULL,		/* (*bus_fm_access_exit)(); */
-	NULL,		/* (*bus_power)(); */
-	npe_intr_ops	/* (*bus_intr_op)(); */
+	0,			/* (*bus_get_eventcookie)();	*/
+	0,			/* (*bus_add_eventcall)();	*/
+	0,			/* (*bus_remove_eventcall)();	*/
+	0,			/* (*bus_post_event)();		*/
+	0,			/* (*bus_intr_ctl)(); */
+	0,			/* (*bus_config)(); */
+	0,			/* (*bus_unconfig)(); */
+	npe_fm_init,		/* (*bus_fm_init)(); */
+	NULL,			/* (*bus_fm_fini)(); */
+	NULL,			/* (*bus_fm_access_enter)(); */
+	NULL,			/* (*bus_fm_access_exit)(); */
+	NULL,			/* (*bus_power)(); */
+	npe_intr_ops,		/* (*bus_intr_op)(); */
+	pcie_hp_common_ops	/* (*bus_hp_op)(); */
 };
 
-/*
- * One goal here is to leverage off of the pcihp.c source without making
- * changes to it.  Call into it's cb_ops directly if needed, piggybacking
- * anything else needed by the pci_tools.c module.  Only pci_tools and pcihp
- * will be using the PCI devctl node.
- */
 static int	npe_open(dev_t *, int, int, cred_t *);
 static int	npe_close(dev_t, int, int, cred_t *);
 static int	npe_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
-static int	npe_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
-		    caddr_t, int *);
-static int	npe_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
 
 struct cb_ops npe_cb_ops = {
 	npe_open,			/* open */
@@ -137,7 +130,7 @@
 	nodev,				/* mmap */
 	nodev,				/* segmap */
 	nochpoll,			/* poll */
-	npe_prop_op,			/* cb_prop_op */
+	pcie_prop_op,			/* cb_prop_op */
 	NULL,				/* streamtab */
 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
 	CB_REV,				/* rev */
@@ -151,6 +144,7 @@
  */
 static int	npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
 static int	npe_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
+static int	npe_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
 
 struct dev_ops npe_ops = {
 	DEVO_REV,		/* devo_rev */
@@ -190,9 +184,9 @@
  * Module linkage information for the kernel.
  */
 static struct modldrv modldrv = {
-	&mod_driverops, /* Type of module */
-	"Host to PCIe nexus driver",
-	&npe_ops,	/* driver ops */
+	&mod_driverops,				/* Type of module */
+	"Host to PCIe nexus driver",		/* Name of module */
+	&npe_ops,				/* driver ops */
 };
 
 static struct modlinkage modlinkage = {
@@ -245,14 +239,39 @@
 
 /*ARGSUSED*/
 static int
+npe_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
+{
+	minor_t		minor = getminor((dev_t)arg);
+	int		instance = PCI_MINOR_NUM_TO_INSTANCE(minor);
+	pci_state_t	*pcip = ddi_get_soft_state(npe_statep, instance);
+	int		ret = DDI_SUCCESS;
+
+	switch (cmd) {
+	case DDI_INFO_DEVT2INSTANCE:
+		*result = (void *)(intptr_t)instance;
+		break;
+	case DDI_INFO_DEVT2DEVINFO:
+		if (pcip == NULL) {
+			ret = DDI_FAILURE;
+			break;
+		}
+
+		*result = (void *)pcip->pci_dip;
+		break;
+	default:
+		ret = DDI_FAILURE;
+		break;
+	}
+
+	return (ret);
+}
+
+/*ARGSUSED*/
+static int
 npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
 {
-	/*
-	 * Use the minor number as constructed by pcihp, as the index value to
-	 * ddi_soft_state_zalloc.
-	 */
-	int instance = ddi_get_instance(devi);
-	pci_state_t *pcip = NULL;
+	int		instance = ddi_get_instance(devi);
+	pci_state_t	*pcip = NULL;
 
 	if (cmd == DDI_RESUME) {
 		/*
@@ -287,27 +306,16 @@
 		return (DDI_FAILURE);
 
 	pcip->pci_dip = devi;
+	pcip->pci_soft_state = PCI_SOFT_STATE_CLOSED;
 
 	pcie_rc_init_bus(devi);
 
-	/*
-	 * Initialize hotplug support on this bus. At minimum
-	 * (for non hotplug bus) this would create ":devctl" minor
-	 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls
-	 * to this bus.
-	 */
-	if (pcihp_init(devi) != DDI_SUCCESS) {
-		cmn_err(CE_WARN, "npe: Failed to setup hotplug framework");
-		ddi_soft_state_free(npe_statep, instance);
-		return (DDI_FAILURE);
-	}
+	if (pcie_init(devi, NULL) != DDI_SUCCESS)
+		goto fail1;
 
 	/* Second arg: initialize for pci_express root nexus */
-	if (pcitool_init(devi, B_TRUE) != DDI_SUCCESS) {
-		(void) pcihp_uninit(devi);
-		ddi_soft_state_free(npe_statep, instance);
-		return (DDI_FAILURE);
-	}
+	if (pcitool_init(devi, B_TRUE) != DDI_SUCCESS)
+		goto fail2;
 
 	pcip->pci_fmcap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE |
 	    DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
@@ -322,8 +330,16 @@
 
 	npe_query_acpi_mcfg(devi);
 	ddi_report_dev(devi);
+
 	return (DDI_SUCCESS);
 
+fail2:
+	(void) pcie_uninit(devi);
+fail1:
+	pcie_rc_fini_bus(devi);
+	ddi_soft_state_free(npe_statep, instance);
+
+	return (DDI_FAILURE);
 }
 
 /*ARGSUSED*/
@@ -341,10 +357,8 @@
 		/* Uninitialize pcitool support. */
 		pcitool_uninit(devi);
 
-		/*
-		 * Uninitialize hotplug support on this bus.
-		 */
-		(void) pcihp_uninit(devi);
+		if (pcie_uninit(devi) != DDI_SUCCESS)
+			return (DDI_FAILURE);
 
 		if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE)
 			ddi_fm_handler_unregister(devi);
@@ -961,53 +975,112 @@
 	return (DDI_SUCCESS);
 }
 
-
-/*
- * When retrofitting this module for pci_tools, functions such as open, close,
- * and ioctl are now pulled into this module.  Before this, the functions in
- * the pcihp module were referenced directly.  Now they are called or
- * referenced through the pcihp cb_ops structure from functions in this module.
- */
 static int
 npe_open(dev_t *devp, int flags, int otyp, cred_t *credp)
 {
-	return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, credp));
+	minor_t		minor = getminor(*devp);
+	int		instance = PCI_MINOR_NUM_TO_INSTANCE(minor);
+	pci_state_t	*pci_p = ddi_get_soft_state(npe_statep, instance);
+	int	rv;
+
+	/*
+	 * Make sure the open is for the right file type.
+	 */
+	if (otyp != OTYP_CHR)
+		return (EINVAL);
+
+	if (pci_p == NULL)
+		return (ENXIO);
+
+	mutex_enter(&pci_p->pci_mutex);
+	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
+	case PCI_TOOL_REG_MINOR_NUM:
+	case PCI_TOOL_INTR_MINOR_NUM:
+		break;
+	default:
+		/* Handle devctl ioctls */
+		rv = pcie_open(pci_p->pci_dip, devp, flags, otyp, credp);
+		mutex_exit(&pci_p->pci_mutex);
+		return (rv);
+	}
+
+	/* Handle pcitool ioctls */
+	if (flags & FEXCL) {
+		if (pci_p->pci_soft_state != PCI_SOFT_STATE_CLOSED) {
+			mutex_exit(&pci_p->pci_mutex);
+			cmn_err(CE_NOTE, "npe_open: busy");
+			return (EBUSY);
+		}
+		pci_p->pci_soft_state = PCI_SOFT_STATE_OPEN_EXCL;
+	} else {
+		if (pci_p->pci_soft_state == PCI_SOFT_STATE_OPEN_EXCL) {
+			mutex_exit(&pci_p->pci_mutex);
+			cmn_err(CE_NOTE, "npe_open: busy");
+			return (EBUSY);
+		}
+		pci_p->pci_soft_state = PCI_SOFT_STATE_OPEN;
+	}
+	mutex_exit(&pci_p->pci_mutex);
+
+	return (0);
 }
 
 static int
 npe_close(dev_t dev, int flags, int otyp, cred_t *credp)
 {
-	return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, credp));
+	minor_t		minor = getminor(dev);
+	int		instance = PCI_MINOR_NUM_TO_INSTANCE(minor);
+	pci_state_t	*pci_p = ddi_get_soft_state(npe_statep, instance);
+	int	rv;
+
+	if (pci_p == NULL)
+		return (ENXIO);
+
+	mutex_enter(&pci_p->pci_mutex);
+
+	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
+	case PCI_TOOL_REG_MINOR_NUM:
+	case PCI_TOOL_INTR_MINOR_NUM:
+		break;
+	default:
+		/* Handle devctl ioctls */
+		rv = pcie_close(pci_p->pci_dip, dev, flags, otyp, credp);
+		mutex_exit(&pci_p->pci_mutex);
+		return (rv);
+	}
+
+	/* Handle pcitool ioctls */
+	pci_p->pci_soft_state = PCI_SOFT_STATE_CLOSED;
+	mutex_exit(&pci_p->pci_mutex);
+	return (0);
 }
 
 static int
 npe_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
 {
 	minor_t		minor = getminor(dev);
-	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
+	int		instance = PCI_MINOR_NUM_TO_INSTANCE(minor);
 	pci_state_t	*pci_p = ddi_get_soft_state(npe_statep, instance);
-	dev_info_t	*dip;
+	int		ret = ENOTTY;
 
 	if (pci_p == NULL)
 		return (ENXIO);
 
-	dip = pci_p->pci_dip;
-
-	return (pci_common_ioctl(dip, dev, cmd, arg, mode, credp, rvalp));
-}
+	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
+	case PCI_TOOL_REG_MINOR_NUM:
+	case PCI_TOOL_INTR_MINOR_NUM:
+		/* To handle pcitool related ioctls */
+		ret =  pci_common_ioctl(pci_p->pci_dip, dev, cmd, arg, mode,
+		    credp, rvalp);
+		break;
+	default:
+		/* To handle devctl and hotplug related ioctls */
+		ret = pcie_ioctl(pci_p->pci_dip, dev, cmd, arg, mode, credp,
+		    rvalp);
+		break;
+	}
 
-static int
-npe_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
-	int flags, char *name, caddr_t valuep, int *lengthp)
-{
-	return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags,
-	    name, valuep, lengthp));
-}
-
-static int
-npe_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
-{
-	return (pcihp_info(dip, cmd, arg, result));
+	return (ret);
 }
 
 /*ARGSUSED*/
--- a/usr/src/uts/i86pc/npe/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/i86pc/npe/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -21,11 +21,9 @@
 #
 # uts/i86pc/npe/Makefile
 #
-# 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 makefile drives the production of the PCI-E nexus driver
 #
 #	i86pc implementation architecture dependent
@@ -57,16 +55,13 @@
 INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
 
 #
-# depends on misc/pcihp, misc/acpica and misc/pcie
-#
-# For PCI Hotplug support, the misc/pcihp module provides devctl control
-# device and cb_ops functions to support hotplug operations.
+# depends on misc/acpica and misc/pcie
 #
 # acpica supplies ACPI access routines
 #
 # pcie supplies PCI Express fabric error support
 #
-LDFLAGS	+= -dy -Nmisc/pcihp -Nmisc/acpica -Nmisc/pcie
+LDFLAGS	+= -dy -Nmisc/acpica -Nmisc/pcie
 
 #
 # Name of the module is needed by the source, to distinguish from other
--- a/usr/src/uts/i86pc/pcie/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/i86pc/pcie/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -40,8 +40,10 @@
 #	Define the module and object file sets.
 #
 MODULE		= pcie
-OBJECTS		= $(PCIE_MISC_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(PCIE_MISC_OBJS:%.o=$(LINTS_DIR)/%.ln)
+OBJECTS		= $(PCIE_MISC_OBJS:%=$(OBJS_DIR)/%) \
+		  $(PCI_STRING_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(PCIE_MISC_OBJS:%.o=$(LINTS_DIR)/%.ln) \
+		  $(PCI_STRING_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_PSM_MISC_DIR)/$(MODULE)
 
 #
@@ -49,7 +51,10 @@
 #
 include $(UTSBASE)/i86pc/Makefile.i86pc
 
-LDFLAGS         += -dy -Nmisc/acpica
+#
+#	Dependency
+#
+LDFLAGS		+= -dy -Nmisc/acpica -Nmisc/busra
 
 #
 #	Define targets
--- a/usr/src/uts/i86xpv/Makefile.files	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/i86xpv/Makefile.files	Mon Nov 02 15:58:28 2009 +0800
@@ -190,7 +190,7 @@
 		    gfxp_devmap.o gfxp_vgatext.o gfxp_vm.o vgasubr.o
 IOAT_OBJS += ioat.o ioat_rs.o ioat_ioctl.o ioat_chan.o
 ISANEXUS_OBJS += isa.o dma_engine.o i8237A.o
-PCIE_MISC_OBJS += pcie_acpi.o pcie_x86.o
+PCIE_MISC_OBJS += pcie_acpi.o pciehpc_acpi.o pcie_x86.o
 PCI_E_NEXUS_OBJS += npe.o npe_misc.o
 PCI_E_NEXUS_OBJS += pci_common.o pci_kstats.o pci_tools.o
 PCINEXUS_OBJS += pci.o pci_common.o pci_kstats.o pci_tools.o
--- a/usr/src/uts/i86xpv/Makefile.rules	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/i86xpv/Makefile.rules	Mon Nov 02 15:58:28 2009 +0800
@@ -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.
 #
 
@@ -71,6 +71,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/intel/io/pciex/hotplug/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(UTSBASE)/i86xpv/io/psm/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -230,6 +234,9 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/i86pc/io/pciex/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/intel/io/pciex/hotplug/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/i86pc/io/gfx_private/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- a/usr/src/uts/i86xpv/npe/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/i86xpv/npe/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -20,11 +20,9 @@
 #
 
 #
-# 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"
-#
 #	This makefile drives the production of the PCI-E nexus driver
 #
 #	i86xpv implementation architecture dependent
@@ -56,14 +54,13 @@
 INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
 
 #
-# depends on misc/pcihp misc/acpica
-#
-# For PCI Hotplug support, the misc/pcihp module provides devctl control
-# device and cb_ops functions to support hotplug operations.
+# depends on misc/acpica and misc/pcie
 #
 # acpica supplies ACPI access routines
 #
-LDFLAGS	+= -dy -Nmisc/pcihp -Nmisc/acpica -Nmisc/pcie
+# pcie supplies PCI Express fabric error support
+#
+LDFLAGS	+= -dy -Nmisc/acpica -Nmisc/pcie
 
 #
 # Name of the module is needed by the source, to distinguish from other
--- a/usr/src/uts/i86xpv/pcie/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/i86xpv/pcie/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -39,8 +39,10 @@
 #	Define the module and object file sets.
 #
 MODULE		= pcie
-OBJECTS		= $(PCIE_MISC_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(PCIE_MISC_OBJS:%.o=$(LINTS_DIR)/%.ln)
+OBJECTS		= $(PCIE_MISC_OBJS:%=$(OBJS_DIR)/%) \
+		  $(PCI_STRING_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(PCIE_MISC_OBJS:%.o=$(LINTS_DIR)/%.ln) \
+		  $(PCI_STRING_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_PSM_MISC_DIR)/$(MODULE)
 
 #
@@ -48,7 +50,10 @@
 #
 include $(UTSBASE)/i86xpv/Makefile.i86xpv
 
-LDFLAGS         += -dy -Nmisc/acpica
+#
+#	Dependency
+#
+LDFLAGS		+= -dy -Nmisc/acpica -Nmisc/busra
 
 #
 #	Define targets
--- a/usr/src/uts/intel/Makefile.files	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/intel/Makefile.files	Mon Nov 02 15:58:28 2009 +0800
@@ -149,7 +149,6 @@
 NSKERN_OBJS += nsc_asm.o
 PCICFG_OBJS += pcicfg.o
 PCI_PCINEXUS_OBJS += pci_pci.o
-PCIEHPCNEXUS_OBJS += pciehpc_acpi.o
 PCIEB_OBJS += pcieb_x86.o
 PIT_BEEP_OBJS += pit_beep.o
 POWER_OBJS += power.o
--- a/usr/src/uts/intel/Makefile.intel.shared	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/intel/Makefile.intel.shared	Mon Nov 02 15:58:28 2009 +0800
@@ -621,7 +621,6 @@
 MISC_KMODS	+= neti
 MISC_KMODS	+= pci_autoconfig
 MISC_KMODS	+= pcicfg
-MISC_KMODS	+= pciehpc
 MISC_KMODS	+= pcihp
 MISC_KMODS	+= pcmcia
 MISC_KMODS	+= rpcsec
--- a/usr/src/uts/intel/Makefile.rules	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/intel/Makefile.rules	Mon Nov 02 15:58:28 2009 +0800
@@ -168,10 +168,6 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
-$(OBJS_DIR)/%.o:		$(UTSBASE)/intel/io/hotplug/pciehpc/%.c
-	$(COMPILE.c) -o $@ $<
-	$(CTFCONVERT_O)
-
 $(OBJS_DIR)/%.o:		$(UTSBASE)/intel/io/intel_nb5000/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -408,7 +404,7 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/intel/io/hotplug/pcicfg/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
-$(LINTS_DIR)/%.ln:		$(UTSBASE)/intel/io/hotplug/pciehpc/%.c
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/intel/io/hotplug/pci/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/intel/io/intel_nb5000/%.c
--- a/usr/src/uts/intel/ia32/ml/modstubs.s	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/intel/ia32/ml/modstubs.s	Mon Nov 02 15:58:28 2009 +0800
@@ -1041,14 +1041,12 @@
 #endif
 
 /*
- * Stubs for PCIEHPC (pci-ex hot plug support) module (misc/pciehpc).
+ * Stubs for pcieb nexus driver.
  */
-#ifndef	PCIEHPC_MODULE
-	MODULE(pciehpc,misc);
-	STUB(pciehpc, pciehpc_init, 0);
-	STUB(pciehpc, pciehpc_uninit, 0);
-	WSTUB(pciehpc, pciehpc_intr, nomod_zero);
-	END_MODULE(pciehpc);
+#ifndef PCIEB_MODULE
+	MODULE(pcieb,drv);
+	STUB(pcieb, pcieb_intel_error_workaround, 0);
+	END_MODULE(pcieb);
 #endif
 
 #ifndef IWSCN_MODULE
--- a/usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c	Mon Nov 02 15:58:28 2009 +0800
@@ -35,6 +35,7 @@
 #include <sys/autoconf.h>
 #include <sys/hwconf.h>
 #include <sys/pcie.h>
+#include <sys/pcie_impl.h>
 #include <sys/pci_cap.h>
 #include <sys/ddi.h>
 #include <sys/sunndi.h>
@@ -49,6 +50,8 @@
 
 static	int	pcicfg_start_devno = 0;	/* for Debug only */
 
+#define	PCICFG_MAX_ARI_FUNCTION 256
+
 #define	PCICFG_NODEVICE 42
 #define	PCICFG_NOMEMORY 43
 #define	PCICFG_NOMULTI	44
@@ -104,7 +107,7 @@
 	uint64_t	memory_len;
 
 	/* prefetchable memory space */
-	uint64_t	pf_memory_base;	/* PF Memory base for this AP */
+	uint64_t	pf_memory_base;	/* PF Memory base for this Connection */
 	uint64_t	pf_memory_last;
 	uint64_t	pf_memory_len;
 
@@ -214,9 +217,9 @@
  */
 
 static int pcicfg_add_config_reg(dev_info_t *,
-	uint_t, uint_t, uint_t);
+    uint_t, uint_t, uint_t);
 static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t,
-								uint_t *);
+    uint_t *, pcicfg_flags_t);
 static int pcicfg_match_dev(dev_info_t *, void *);
 static dev_info_t *pcicfg_devi_find(dev_info_t *, uint_t, uint_t);
 static pcicfg_phdl_t *pcicfg_find_phdl(dev_info_t *);
@@ -225,7 +228,8 @@
 static int pcicfg_sum_resources(dev_info_t *, void *);
 static int pcicfg_device_assign(dev_info_t *);
 static int pcicfg_bridge_assign(dev_info_t *, void *);
-static int pcicfg_free_resources(dev_info_t *);
+static int pcicfg_device_assign_readonly(dev_info_t *);
+static int pcicfg_free_resources(dev_info_t *, pcicfg_flags_t);
 static void pcicfg_setup_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
 static void pcicfg_update_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
 static int pcicfg_update_assigned_prop(dev_info_t *, pci_regspec_t *);
@@ -234,7 +238,7 @@
 static int pcicfg_set_busnode_props(dev_info_t *, uint8_t);
 static int pcicfg_free_bridge_resources(dev_info_t *);
 static int pcicfg_free_device_resources(dev_info_t *);
-static int pcicfg_teardown_device(dev_info_t *);
+static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t);
 static void pcicfg_reparent_node(dev_info_t *, dev_info_t *);
 static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *);
 static void pcicfg_config_teardown(ddi_acc_handle_t *);
@@ -245,7 +249,7 @@
 static int pcicfg_configure_ntbridge(dev_info_t *, uint_t, uint_t);
 static uint_t pcicfg_ntbridge_child(dev_info_t *);
 static uint_t pcicfg_get_ntbridge_child_range(dev_info_t *, uint64_t *,
-				uint64_t *, uint_t);
+    uint64_t *, uint_t);
 static int pcicfg_is_ntbridge(dev_info_t *);
 static int pcicfg_ntbridge_allocate_resources(dev_info_t *);
 static int pcicfg_ntbridge_configure_done(dev_info_t *);
@@ -262,9 +266,15 @@
 static int pcicfg_pcie_device_type(dev_info_t *, ddi_acc_handle_t);
 static int pcicfg_pcie_port_type(dev_info_t *, ddi_acc_handle_t);
 static int pcicfg_probe_bridge(dev_info_t *, ddi_acc_handle_t, uint_t,
-								uint_t *);
+    uint_t *);
 static int pcicfg_find_resource_end(dev_info_t *, void *);
 
+static int pcicfg_populate_reg_props(dev_info_t *, ddi_acc_handle_t);
+static int pcicfg_populate_props_from_bar(dev_info_t *, ddi_acc_handle_t);
+static int pcicfg_update_assigned_prop_value(dev_info_t *, uint32_t,
+    uint32_t, uint32_t, uint_t);
+static int pcicfg_ari_configure(dev_info_t *);
+
 #ifdef DEBUG
 static void pcicfg_dump_common_config(ddi_acc_handle_t config_handle);
 static void pcicfg_dump_device_config(ddi_acc_handle_t);
@@ -382,31 +392,31 @@
 	if ((pcicfg_debug & 1) == 0)
 		return;
 	prom_printf(" Vendor ID   = [0x%x]\n",
-		pci_config_get16(config_handle, PCI_CONF_VENID));
+	    pci_config_get16(config_handle, PCI_CONF_VENID));
 	prom_printf(" Device ID   = [0x%x]\n",
-		pci_config_get16(config_handle, PCI_CONF_DEVID));
+	    pci_config_get16(config_handle, PCI_CONF_DEVID));
 	prom_printf(" Command REG = [0x%x]\n",
-		pci_config_get16(config_handle, PCI_CONF_COMM));
+	    pci_config_get16(config_handle, PCI_CONF_COMM));
 	prom_printf(" Status  REG = [0x%x]\n",
-		pci_config_get16(config_handle, PCI_CONF_STAT));
+	    pci_config_get16(config_handle, PCI_CONF_STAT));
 	prom_printf(" Revision ID = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_CONF_REVID));
+	    pci_config_get8(config_handle, PCI_CONF_REVID));
 	prom_printf(" Prog Class  = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
+	    pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
 	prom_printf(" Dev Class   = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_CONF_SUBCLASS));
+	    pci_config_get8(config_handle, PCI_CONF_SUBCLASS));
 	prom_printf(" Base Class  = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_CONF_BASCLASS));
+	    pci_config_get8(config_handle, PCI_CONF_BASCLASS));
 	prom_printf(" Device ID   = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ));
+	    pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ));
 	prom_printf(" Header Type = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_CONF_HEADER));
+	    pci_config_get8(config_handle, PCI_CONF_HEADER));
 	prom_printf(" BIST        = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_CONF_BIST));
+	    pci_config_get8(config_handle, PCI_CONF_BIST));
 	prom_printf(" BASE 0      = [0x%x]\n",
-		pci_config_get32(config_handle, PCI_CONF_BASE0));
+	    pci_config_get32(config_handle, PCI_CONF_BASE0));
 	prom_printf(" BASE 1      = [0x%x]\n",
-		pci_config_get32(config_handle, PCI_CONF_BASE1));
+	    pci_config_get32(config_handle, PCI_CONF_BASE1));
 
 }
 
@@ -418,29 +428,29 @@
 	pcicfg_dump_common_config(config_handle);
 
 	prom_printf(" BASE 2      = [0x%x]\n",
-		pci_config_get32(config_handle, PCI_CONF_BASE2));
+	    pci_config_get32(config_handle, PCI_CONF_BASE2));
 	prom_printf(" BASE 3      = [0x%x]\n",
-		pci_config_get32(config_handle, PCI_CONF_BASE3));
+	    pci_config_get32(config_handle, PCI_CONF_BASE3));
 	prom_printf(" BASE 4      = [0x%x]\n",
-		pci_config_get32(config_handle, PCI_CONF_BASE4));
+	    pci_config_get32(config_handle, PCI_CONF_BASE4));
 	prom_printf(" BASE 5      = [0x%x]\n",
-		pci_config_get32(config_handle, PCI_CONF_BASE5));
+	    pci_config_get32(config_handle, PCI_CONF_BASE5));
 	prom_printf(" Cardbus CIS = [0x%x]\n",
-		pci_config_get32(config_handle, PCI_CONF_CIS));
+	    pci_config_get32(config_handle, PCI_CONF_CIS));
 	prom_printf(" Sub VID     = [0x%x]\n",
-		pci_config_get16(config_handle, PCI_CONF_SUBVENID));
+	    pci_config_get16(config_handle, PCI_CONF_SUBVENID));
 	prom_printf(" Sub SID     = [0x%x]\n",
-		pci_config_get16(config_handle, PCI_CONF_SUBSYSID));
+	    pci_config_get16(config_handle, PCI_CONF_SUBSYSID));
 	prom_printf(" ROM         = [0x%x]\n",
-		pci_config_get32(config_handle, PCI_CONF_ROM));
+	    pci_config_get32(config_handle, PCI_CONF_ROM));
 	prom_printf(" I Line      = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_CONF_ILINE));
+	    pci_config_get8(config_handle, PCI_CONF_ILINE));
 	prom_printf(" I Pin       = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_CONF_IPIN));
+	    pci_config_get8(config_handle, PCI_CONF_IPIN));
 	prom_printf(" Max Grant   = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_CONF_MIN_G));
+	    pci_config_get8(config_handle, PCI_CONF_MIN_G));
 	prom_printf(" Max Latent  = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_CONF_MAX_L));
+	    pci_config_get8(config_handle, PCI_CONF_MAX_L));
 }
 
 static void
@@ -453,43 +463,43 @@
 	prom_printf("........................................\n");
 
 	prom_printf(" Pri Bus     = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_BCNF_PRIBUS));
+	    pci_config_get8(config_handle, PCI_BCNF_PRIBUS));
 	prom_printf(" Sec Bus     = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_BCNF_SECBUS));
+	    pci_config_get8(config_handle, PCI_BCNF_SECBUS));
 	prom_printf(" Sub Bus     = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_BCNF_SUBBUS));
+	    pci_config_get8(config_handle, PCI_BCNF_SUBBUS));
 	prom_printf(" Latency     = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_BCNF_LATENCY_TIMER));
+	    pci_config_get8(config_handle, PCI_BCNF_LATENCY_TIMER));
 	prom_printf(" I/O Base LO = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW));
+	    pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW));
 	prom_printf(" I/O Lim LO  = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW));
+	    pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW));
 	prom_printf(" Sec. Status = [0x%x]\n",
-		pci_config_get16(config_handle, PCI_BCNF_SEC_STATUS));
+	    pci_config_get16(config_handle, PCI_BCNF_SEC_STATUS));
 	prom_printf(" Mem Base    = [0x%x]\n",
-		pci_config_get16(config_handle, PCI_BCNF_MEM_BASE));
+	    pci_config_get16(config_handle, PCI_BCNF_MEM_BASE));
 	prom_printf(" Mem Limit   = [0x%x]\n",
-		pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT));
+	    pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT));
 	prom_printf(" PF Mem Base = [0x%x]\n",
-		pci_config_get16(config_handle, PCI_BCNF_PF_BASE_LOW));
+	    pci_config_get16(config_handle, PCI_BCNF_PF_BASE_LOW));
 	prom_printf(" PF Mem Lim  = [0x%x]\n",
-		pci_config_get16(config_handle, PCI_BCNF_PF_LIMIT_LOW));
+	    pci_config_get16(config_handle, PCI_BCNF_PF_LIMIT_LOW));
 	prom_printf(" PF Base HI  = [0x%x]\n",
-		pci_config_get32(config_handle, PCI_BCNF_PF_BASE_HIGH));
+	    pci_config_get32(config_handle, PCI_BCNF_PF_BASE_HIGH));
 	prom_printf(" PF Lim  HI  = [0x%x]\n",
-		pci_config_get32(config_handle, PCI_BCNF_PF_LIMIT_HIGH));
+	    pci_config_get32(config_handle, PCI_BCNF_PF_LIMIT_HIGH));
 	prom_printf(" I/O Base HI = [0x%x]\n",
-		pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI));
+	    pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI));
 	prom_printf(" I/O Lim HI  = [0x%x]\n",
-		pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI));
+	    pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI));
 	prom_printf(" ROM addr    = [0x%x]\n",
-		pci_config_get32(config_handle, PCI_BCNF_ROM));
+	    pci_config_get32(config_handle, PCI_BCNF_ROM));
 	prom_printf(" Intr Line   = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_BCNF_ILINE));
+	    pci_config_get8(config_handle, PCI_BCNF_ILINE));
 	prom_printf(" Intr Pin    = [0x%x]\n",
-		pci_config_get8(config_handle, PCI_BCNF_IPIN));
+	    pci_config_get8(config_handle, PCI_BCNF_IPIN));
 	prom_printf(" Bridge Ctrl = [0x%x]\n",
-		pci_config_get16(config_handle, PCI_BCNF_BCNTRL));
+	    pci_config_get16(config_handle, PCI_BCNF_BCNTRL));
 }
 #endif
 
@@ -535,17 +545,24 @@
  * registers.
  */
 int
-pcicfg_configure(dev_info_t *devi, uint_t device)
+pcicfg_configure(dev_info_t *devi, uint_t device, uint_t function,
+    pcicfg_flags_t flags)
 {
 	uint_t bus;
 	int len;
 	int func;
-	dev_info_t *new_device;
 	dev_info_t *attach_point;
 	pci_bus_range_t pci_bus_range;
 	int rv;
 	int circ;
 	uint_t highest_bus;
+	int ari_mode = B_FALSE;
+	int max_function = PCI_MAX_FUNCTIONS;
+	int trans_device;
+	dev_info_t *new_device;
+
+	if (flags == PCICFG_FLAG_ENABLE_ARI)
+		return (pcicfg_ari_configure(devi));
 
 	/*
 	 * Start probing at the device specified in "device" on the
@@ -563,27 +580,35 @@
 	attach_point = devi;
 
 	ndi_devi_enter(devi, &circ);
-	for (func = 0; func < PCI_MAX_FUNCTIONS; func++) {
-
-		DEBUG3("Configuring [0x%x][0x%x][0x%x]\n", bus, device, func);
+	for (func = 0; func < max_function; ) {
+
+		if ((function != PCICFG_ALL_FUNC) && (function != func))
+			goto next;
+
+		if (ari_mode)
+			trans_device = func >> 3;
+		else
+			trans_device = device;
 
 		switch (rv = pcicfg_probe_children(attach_point,
-			bus, device, func, &highest_bus)) {
+		    bus, trans_device, func & 7, &highest_bus, flags)) {
 			case PCICFG_NORESRC:
 			case PCICFG_FAILURE:
-				DEBUG2("configure failed: "
-				"bus [0x%x] device [0x%x]\n",
-					bus, device);
+				DEBUG2("configure failed: bus [0x%x] device "
+				    "[0x%x]\n", bus, trans_device);
 				goto cleanup;
 			case PCICFG_NODEVICE:
 				DEBUG3("no device : bus "
-				"[0x%x] slot [0x%x] func [0x%x]\n",
-					bus, device, func);
-				continue;
+				    "[0x%x] slot [0x%x] func [0x%x]\n",
+				    bus, trans_device, func &7);
+
+				if (func)
+					goto next;
+				break;
 			default:
 				DEBUG3("configure: bus => [%d] "
-				"slot => [%d] func => [%d]\n",
-					bus, device, func);
+				    "slot => [%d] func => [%d]\n",
+				    bus, trans_device, func & 7);
 			break;
 		}
 
@@ -591,7 +616,7 @@
 			break;
 
 		if ((new_device = pcicfg_devi_find(attach_point,
-			device, func)) == NULL) {
+		    trans_device, func & 7)) == NULL) {
 			DEBUG0("Did'nt find device node just created\n");
 			goto cleanup;
 		}
@@ -623,10 +648,51 @@
 		if (pcicfg_is_ntbridge(new_device) != DDI_FAILURE) {
 			DEBUG0("pcicfg: Found nontransparent bridge.\n");
 
-			rv = pcicfg_configure_ntbridge(new_device, bus, device);
+			rv = pcicfg_configure_ntbridge(new_device, bus,
+			    trans_device);
 			if (rv != PCICFG_SUCCESS)
 				goto cleanup;
 		}
+
+next:
+		/*
+		 * Determine if ARI Forwarding should be enabled.
+		 */
+		if (func == 0) {
+			if ((pcie_ari_supported(devi)
+			    == PCIE_ARI_FORW_SUPPORTED) &&
+			    (pcie_ari_device(new_device) == PCIE_ARI_DEVICE)) {
+				if (pcie_ari_enable(devi) == DDI_SUCCESS) {
+					(void) ddi_prop_create(DDI_DEV_T_NONE,
+					    devi,  DDI_PROP_CANSLEEP,
+					    "ari-enabled", NULL, 0);
+
+					ari_mode = B_TRUE;
+					max_function = PCICFG_MAX_ARI_FUNCTION;
+				}
+			}
+		}
+		if (ari_mode == B_TRUE) {
+			int next_function;
+
+			DEBUG0("Next Function - ARI Device\n");
+			if (pcie_ari_get_next_function(new_device,
+			    &next_function) != DDI_SUCCESS)
+				goto cleanup;
+
+			/*
+			 * Check if there are more fucntions to probe.
+			 */
+			if (next_function == 0) {
+				DEBUG0("Next Function - "
+				    "No more ARI Functions\n");
+				break;
+			}
+			func = next_function;
+		} else {
+			func++;
+		}
+		DEBUG1("Next Function - %x\n", func);
 	}
 
 	ndi_devi_exit(devi, circ);
@@ -644,13 +710,16 @@
 	 */
 
 	for (func = 0; func < PCI_MAX_FUNCTIONS; func++) {
-		if ((new_device = pcicfg_devi_find(devi,
-			device, func)) == NULL) {
+		if ((function != PCICFG_ALL_FUNC) && (function != func))
+			continue;
+
+		if ((new_device = pcicfg_devi_find(devi, device, func))
+		    == NULL) {
 			continue;
 		}
 
 		DEBUG2("Cleaning up device [0x%x] function [0x%x]\n",
-			device, func);
+		    device, func);
 		/*
 		 * If this was a bridge device it will have a
 		 * probe handle - if not, no harm in calling this.
@@ -709,9 +778,7 @@
 	 * mapped directly under the host.
 	 */
 	if ((rc = ndi_prop_update_int(DDI_DEV_T_NONE, new_device,
-		PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS))
-						!= DDI_SUCCESS) {
-
+	    PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS)) != DDI_SUCCESS) {
 		DEBUG0("Cannot create indirect conf map property.\n");
 		return ((int)PCICFG_FAILURE);
 	}
@@ -726,7 +793,7 @@
 	pci_config_teardown(&config_handle);
 	/* create Bus node properties for ntbridge. */
 	if (pcicfg_set_busnode_props(new_device, pcie_device_type)
-			!= PCICFG_SUCCESS) {
+	    != PCICFG_SUCCESS) {
 		DEBUG0("Failed to set busnode props\n");
 		return (rc);
 	}
@@ -734,9 +801,8 @@
 	/* For now: Lets only support one layer of child */
 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
 	req.ra_len = 1;
-	if (ndi_ra_alloc(ddi_get_parent(new_device), &req,
-		&next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
-		NDI_RA_PASS) != NDI_SUCCESS) {
+	if (ndi_ra_alloc(ddi_get_parent(new_device), &req, &next_bus, &blen,
+	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
 		DEBUG0("ntbridge: Failed to get a bus number\n");
 		return (PCICFG_NORESRC);
 	}
@@ -750,8 +816,8 @@
 	bus_range[0] = (int)next_bus;
 	bus_range[1] = (int)next_bus;
 
-	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_device,
-		"bus-range", bus_range, 2) != DDI_SUCCESS) {
+	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_device, "bus-range",
+	    bus_range, 2) != DDI_SUCCESS) {
 		DEBUG0("Cannot set ntbridge bus-range property");
 		return (rc);
 	}
@@ -777,8 +843,7 @@
 	DEBUG0("pcicfg: Success loading nontransparent bridge nexus driver..");
 
 	/* Now set aside pci resource allocation requests for our children */
-	if (pcicfg_ntbridge_allocate_resources(new_device) !=
-				PCICFG_SUCCESS) {
+	if (pcicfg_ntbridge_allocate_resources(new_device) != PCICFG_SUCCESS) {
 		max_devs = 0;
 		rc = PCICFG_FAILURE;
 	} else
@@ -792,18 +857,18 @@
 		    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild);
 
 		if (pcicfg_add_config_reg(new_ntbridgechild, next_bus, devno, 0)
-					!= DDI_PROP_SUCCESS) {
+		    != DDI_PROP_SUCCESS) {
 			cmn_err(CE_WARN,
-				"Failed to add conf reg for ntbridge child.\n");
+			    "Failed to add conf reg for ntbridge child.\n");
 			(void) ndi_devi_free(new_ntbridgechild);
 			rc = PCICFG_FAILURE;
 			break;
 		}
 
 		if (pci_config_setup(new_ntbridgechild, &config_handle)
-					!= DDI_SUCCESS) {
+		    != DDI_SUCCESS) {
 			cmn_err(CE_WARN,
-				"Cannot map ntbridge child %x\n", devno);
+			    "Cannot map ntbridge child %x\n", devno);
 			(void) ndi_devi_free(new_ntbridgechild);
 			rc = PCICFG_FAILURE;
 			break;
@@ -822,20 +887,18 @@
 			continue;
 
 		/* Lets fake attachments points for each child, */
-		rc = pcicfg_configure(new_device, devno);
+		rc = pcicfg_configure(new_device, devno, PCICFG_ALL_FUNC, 0);
 		if (rc != PCICFG_SUCCESS) {
 			int old_dev = pcicfg_start_devno;
 
 			cmn_err(CE_WARN,
-			"Error configuring ntbridge child dev=%d\n", devno);
+			    "Error configuring ntbridge child dev=%d\n", devno);
 
 			while (old_dev != devno) {
 				if (pcicfg_ntbridge_unconfigure_child(
-					new_device, old_dev) == PCICFG_FAILURE)
-
-					cmn_err(CE_WARN,
-					"Unconfig Error ntbridge child "
-					"dev=%d\n", old_dev);
+				    new_device, old_dev) == PCICFG_FAILURE)
+					cmn_err(CE_WARN, "Unconfig Error "
+					    "ntbridge child dev=%d\n", old_dev);
 				old_dev++;
 			}
 			break;
@@ -851,19 +914,19 @@
 		int			k;
 
 		if (ddi_getlongprop(DDI_DEV_T_ANY, new_device,
-			DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
-			&k) != DDI_PROP_SUCCESS) {
+		    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus, &k)
+		    != DDI_PROP_SUCCESS) {
 			DEBUG0("Failed to read bus-range property\n");
 			rc = PCICFG_FAILURE;
 			return (rc);
 		}
 
 		DEBUG2("Need to free bus [%d] range [%d]\n",
-			bus[0], bus[1] - bus[0] + 1);
-
-		if (ndi_ra_free(ddi_get_parent(new_device),
-			(uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
-			NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
+		    bus[0], bus[1] - bus[0] + 1);
+
+		if (ndi_ra_free(ddi_get_parent(new_device), (uint64_t)bus[0],
+		    (uint64_t)(bus[1] - bus[0] + 1), NDI_RA_TYPE_PCI_BUSNUM,
+		    NDI_RA_PASS) != NDI_SUCCESS) {
 			DEBUG0("Failed to free a bus number\n");
 			rc = PCICFG_FAILURE;
 			kmem_free(bus, k);
@@ -920,9 +983,9 @@
 
 	/* Set Memory space handle for ntbridge */
 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
-			PCI_BASE_SPACE_MEM) != DDI_SUCCESS) {
+	    PCI_BASE_SPACE_MEM) != DDI_SUCCESS) {
 		cmn_err(CE_WARN,
-			"ntbridge: Mem resource information failure\n");
+		    "ntbridge: Mem resource information failure\n");
 		phdl->memory_len  = 0;
 		return (PCICFG_FAILURE);
 	}
@@ -930,7 +993,7 @@
 	mem_request->ra_boundlen = boundbase + boundlen;
 	mem_request->ra_len = boundlen;
 	mem_request->ra_align_mask =
-		PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
+	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
 	mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
 
 	/*
@@ -944,19 +1007,19 @@
 	phdl->mem_hole.len = mem_request->ra_len;
 	phdl->mem_hole.next = (hole_t *)NULL;
 
-	DEBUG2("AP requested [0x%llx], needs [0x%llx] bytes of memory\n",
-		boundlen, mem_request->ra_len);
+	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of memory\n",
+	    boundlen, mem_request->ra_len);
 
 	/* Set IO space handle for ntbridge */
 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
-			PCI_BASE_SPACE_IO) != DDI_SUCCESS) {
+	    PCI_BASE_SPACE_IO) != DDI_SUCCESS) {
 		cmn_err(CE_WARN, "ntbridge: IO resource information failure\n");
 		phdl->io_len  = 0;
 		return (PCICFG_FAILURE);
 	}
 	io_request->ra_len = boundlen;
 	io_request->ra_align_mask =
-		PCICFG_IOGRAN - 1;   /* 4K alignment on I/O space */
+	    PCICFG_IOGRAN - 1;   /* 4K alignment on I/O space */
 	io_request->ra_boundbase = boundbase;
 	io_request->ra_boundlen = boundbase + boundlen;
 	io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
@@ -972,14 +1035,14 @@
 	phdl->io_hole.len = io_request->ra_len;
 	phdl->io_hole.next = (hole_t *)NULL;
 
-	DEBUG2("AP requested [0x%llx], needs [0x%llx] bytes of IO\n",
-		boundlen, io_request->ra_len);
+	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of IO\n",
+	    boundlen, io_request->ra_len);
 
 	/* Set Prefetchable Memory space handle for ntbridge */
 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
-			PCI_BASE_SPACE_MEM | PCI_BASE_PREF_M) != DDI_SUCCESS) {
+	    PCI_BASE_SPACE_MEM | PCI_BASE_PREF_M) != DDI_SUCCESS) {
 		cmn_err(CE_WARN,
-			"ntbridge: PF Mem resource information failure\n");
+		    "ntbridge: PF Mem resource information failure\n");
 		phdl->pf_memory_len  = 0;
 		return (PCICFG_FAILURE);
 	}
@@ -987,7 +1050,7 @@
 	pf_mem_request->ra_boundlen = boundbase + boundlen;
 	pf_mem_request->ra_len = boundlen;
 	pf_mem_request->ra_align_mask =
-		PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
+	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
 	pf_mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
 
 	/*
@@ -1001,15 +1064,15 @@
 	phdl->pf_mem_hole.len = pf_mem_request->ra_len;
 	phdl->pf_mem_hole.next = (hole_t *)NULL;
 
-	DEBUG2("AP requested [0x%llx], needs [0x%llx] bytes of PF memory\n",
-		boundlen, pf_mem_request->ra_len);
+	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of PF "
+	    "memory\n", boundlen, pf_mem_request->ra_len);
 
 	DEBUG2("MEMORY BASE = [0x%lx] length [0x%lx]\n",
-		phdl->memory_base, phdl->memory_len);
+	    phdl->memory_base, phdl->memory_len);
 	DEBUG2("IO     BASE = [0x%x] length [0x%x]\n",
-		phdl->io_base, phdl->io_len);
+	    phdl->io_base, phdl->io_len);
 	DEBUG2("PF MEMORY BASE = [0x%lx] length [0x%lx]\n",
-		phdl->pf_memory_base, phdl->pf_memory_len);
+	    phdl->pf_memory_base, phdl->pf_memory_len);
 
 	return (PCICFG_SUCCESS);
 }
@@ -1028,24 +1091,23 @@
 	entry = pcicfg_find_phdl(dip);
 	ASSERT(entry);
 
-	bzero((caddr_t)range,
-		sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
+	bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
 	range[1].child_high = range[1].parent_high |=
-		(PCI_REG_REL_M | PCI_ADDR_MEM32);
+	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
 	range[1].child_low = range[1].parent_low = (uint32_t)entry->memory_base;
 
 	range[0].child_high = range[0].parent_high |=
-		(PCI_REG_REL_M | PCI_ADDR_IO);
+	    (PCI_REG_REL_M | PCI_ADDR_IO);
 	range[0].child_low = range[0].parent_low = (uint32_t)entry->io_base;
 
 	range[2].child_high = range[2].parent_high |=
-		(PCI_REG_REL_M | PCI_ADDR_MEM32 | PCI_REG_PF_M);
+	    (PCI_REG_REL_M | PCI_ADDR_MEM32 | PCI_REG_PF_M);
 	range[2].child_low = range[2].parent_low =
-		(uint32_t)entry->pf_memory_base;
+	    (uint32_t)entry->pf_memory_base;
 
 	len = sizeof (pci_bus_range_t);
 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
-		"bus-range", (caddr_t)&bus_range, (int *)&len) != DDI_SUCCESS) {
+	    "bus-range", (caddr_t)&bus_range, (int *)&len) != DDI_SUCCESS) {
 		DEBUG0("no bus-range property\n");
 		return (PCICFG_FAILURE);
 	}
@@ -1054,8 +1116,8 @@
 	if (entry->highest_bus) {	/* secondary bus number */
 		if (entry->highest_bus < bus_range.lo) {
 			cmn_err(CE_WARN,
-				"ntbridge bus range invalid !(%d,%d)\n",
-					bus_range.lo, entry->highest_bus);
+			    "ntbridge bus range invalid !(%d,%d)\n",
+			    bus_range.lo, entry->highest_bus);
 			new_bus_range[1] = bus_range.lo + entry->highest_bus;
 		}
 		else
@@ -1064,11 +1126,11 @@
 	else
 		new_bus_range[1] = bus_range.hi;
 
-	DEBUG2("ntbridge: bus range lo=%x, hi=%x\n",
-				new_bus_range[0], new_bus_range[1]);
-
-	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
-			"bus-range", new_bus_range, 2) != DDI_SUCCESS) {
+	DEBUG2("ntbridge: bus range lo=%x, hi=%x\n", new_bus_range[0],
+	    new_bus_range[1]);
+
+	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "bus-range",
+	    new_bus_range, 2) != DDI_SUCCESS) {
 		DEBUG0("Failed to set bus-range property");
 		entry->error = PCICFG_FAILURE;
 		return (PCICFG_FAILURE);
@@ -1079,7 +1141,7 @@
 		uint64_t	unused;
 		unused = pcicfg_unused_space(&entry->io_hole, &len);
 		DEBUG2("ntbridge: Unused IO space %llx bytes over %d holes\n",
-							unused, len);
+		    unused, len);
 	}
 #endif
 
@@ -1095,7 +1157,7 @@
 		uint64_t	unused;
 		unused = pcicfg_unused_space(&entry->mem_hole, &len);
 		DEBUG2("ntbridge: Unused Mem space %llx bytes over %d holes\n",
-							unused, len);
+		    unused, len);
 	}
 #endif
 
@@ -1111,7 +1173,7 @@
 		uint64_t	unused;
 		unused = pcicfg_unused_space(&entry->pf_mem_hole, &len);
 		DEBUG2("ntbridge: Unused PF Mem space %llx bytes over"
-			" %d holes\n", unused, len);
+		    " %d holes\n", unused, len);
 	}
 #endif
 
@@ -1128,13 +1190,13 @@
 static int
 pcicfg_ntbridge_program_child(dev_info_t *dip)
 {
-	pcicfg_phdl_t		*entry;
-	int			rc = PCICFG_SUCCESS;
+	pcicfg_phdl_t	*entry;
+	int		rc = PCICFG_SUCCESS;
 	dev_info_t	*anode = dip;
 
-	/* Find the attachment point node */
-	while ((anode != NULL) && (strcmp(ddi_binding_name(anode),
-		"hp_attachment") != 0)) {
+	/* Find the Hotplug Connection (CN) node */
+	while ((anode != NULL) &&
+	    (strcmp(ddi_binding_name(anode), "hp_attachment") != 0)) {
 		anode = ddi_get_parent(anode);
 	}
 
@@ -1147,8 +1209,8 @@
 
 	if (pcicfg_bridge_assign(dip, entry) == DDI_WALK_TERMINATE) {
 		cmn_err(CE_WARN,
-			"ntbridge: Error assigning range for child %s\n",
-				ddi_get_name(dip));
+		    "ntbridge: Error assigning range for child %s\n",
+		    ddi_get_name(dip));
 		rc = PCICFG_FAILURE;
 	}
 	return (rc);
@@ -1166,7 +1228,7 @@
 
 	len = sizeof (pci_bus_range_t);
 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, new_device, DDI_PROP_DONTPASS,
-		"bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
+	    "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
 		DEBUG0("no bus-range property\n");
 		return (PCICFG_FAILURE);
 	}
@@ -1177,18 +1239,17 @@
 	    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild);
 
 	if (pcicfg_add_config_reg(new_ntbridgechild, bus, devno, 0)
-				!= DDI_PROP_SUCCESS) {
-		cmn_err(CE_WARN,
-		"Unconfigure: Failed to add conf reg prop for ntbridge "
-			"child.\n");
+	    != DDI_PROP_SUCCESS) {
+		cmn_err(CE_WARN, "Unconfigure: Failed to add conf reg prop for "
+		    "ntbridge child.\n");
 		(void) ndi_devi_free(new_ntbridgechild);
 		return (PCICFG_FAILURE);
 	}
 
 	if (pci_config_setup(new_ntbridgechild, &config_handle)
-							!= DDI_SUCCESS) {
-		cmn_err(CE_WARN,
-			"pcicfg: Cannot map ntbridge child %x\n", devno);
+	    != DDI_SUCCESS) {
+		cmn_err(CE_WARN, "pcicfg: Cannot map ntbridge child %x\n",
+		    devno);
 		(void) ndi_devi_free(new_ntbridgechild);
 		return (PCICFG_FAILURE);
 	}
@@ -1205,7 +1266,7 @@
 	if (vid	== 0xffff)
 		return (PCICFG_NODEVICE);
 
-	return (pcicfg_unconfigure(new_device, devno));
+	return (pcicfg_unconfigure(new_device, devno, PCICFG_ALL_FUNC, 0));
 }
 
 static uint_t
@@ -1215,19 +1276,18 @@
 	uint_t			*bus;
 	int			k, rc = DDI_FAILURE;
 
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-			DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
-			&k) != DDI_PROP_SUCCESS) {
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "bus-range",
+	    (caddr_t)&bus, &k) != DDI_PROP_SUCCESS) {
 		DEBUG0("ntbridge: Failed to read bus-range property\n");
 		return (rc);
 	}
 
 	DEBUG2("ntbridge: Need to free bus [%d] range [%d]\n",
-		bus[0], bus[1] - bus[0] + 1);
-
-	if (ndi_ra_free(ddi_get_parent(dip),
-		(uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
-		NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
+	    bus[0], bus[1] - bus[0] + 1);
+
+	if (ndi_ra_free(ddi_get_parent(dip), (uint64_t)bus[0],
+	    (uint64_t)(bus[1] - bus[0] + 1),
+	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
 		DEBUG0("ntbridge: Failed to free a bus number\n");
 		kmem_free(bus, k);
 		return (rc);
@@ -1257,7 +1317,7 @@
 
 	if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) {
 		cmn_err(CE_WARN,
-			"pcicfg: cannot map config space, to get map type\n");
+		    "pcicfg: cannot map config space, to get map type\n");
 		return (DDI_FAILURE);
 	}
 	class = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
@@ -1268,9 +1328,9 @@
 		rc = DDI_FAILURE;
 
 	DEBUG3("pcicfg: checking device %x,%x for indirect map. rc=%d\n",
-			pci_config_get16(config_handle, PCI_CONF_VENID),
-			pci_config_get16(config_handle, PCI_CONF_DEVID),
-			rc);
+	    pci_config_get16(config_handle, PCI_CONF_VENID),
+	    pci_config_get16(config_handle, PCI_CONF_DEVID),
+	    rc);
 	pci_config_teardown(&config_handle);
 	return (rc);
 }
@@ -1282,10 +1342,10 @@
 	dev_info_t	*anode = dip;
 
 	/*
-	 * Find the attachment point node
+	 * Find the Hotplug Connection (CN) node
 	 */
 	while ((anode != NULL) && (strcmp(ddi_binding_name(anode),
-		"hp_attachment") != 0)) {
+	    "hp_attachment") != 0)) {
 		anode = ddi_get_parent(anode);
 	}
 
@@ -1295,11 +1355,11 @@
 	}
 	len = sizeof (int);
 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ddi_get_parent(anode),
-		DDI_PROP_DONTPASS, PCI_DEV_CONF_MAP_PROP, (caddr_t)&val,
-			&len) != DDI_SUCCESS) {
+	    DDI_PROP_DONTPASS, PCI_DEV_CONF_MAP_PROP, (caddr_t)&val, &len)
+	    != DDI_SUCCESS) {
 
 		DEBUG1("ntbridge child: no \"%s\" property\n",
-					PCI_DEV_CONF_MAP_PROP);
+		    PCI_DEV_CONF_MAP_PROP);
 		return (rc);
 	}
 	DEBUG0("ntbridge child: success\n");
@@ -1316,41 +1376,39 @@
 	if ((ibridge = pcicfg_is_ntbridge(dip)) == DDI_FAILURE)
 		return (found);
 
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-		DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
-			&length) != DDI_PROP_SUCCESS) {
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "assigned-addresses", (caddr_t)&assigned, &length)
+	    != DDI_PROP_SUCCESS) {
 		DEBUG1("Failed to get assigned-addresses property %llx\n", dip);
 		return (found);
 	}
 	DEBUG1("pcicfg: ntbridge child range: dip = %s\n",
-					ddi_driver_name(dip));
+	    ddi_driver_name(dip));
 
 	acount = length / sizeof (pci_regspec_t);
 
 	for (i = 0; i < acount; i++) {
-		if ((PCI_REG_REG_G(assigned[i].pci_phys_hi)
-		== pcicfg_indirect_map_devs[ibridge].mem_range_bar_offset) &&
-				(space_type == PCI_BASE_SPACE_MEM)) {
+		if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
+		    pcicfg_indirect_map_devs[ibridge].mem_range_bar_offset) &&
+		    (space_type == PCI_BASE_SPACE_MEM)) {
 			found = DDI_SUCCESS;
 			break;
-		} else if ((PCI_REG_REG_G(assigned[i].pci_phys_hi)
-		== pcicfg_indirect_map_devs[ibridge].io_range_bar_offset) &&
-					(space_type == PCI_BASE_SPACE_IO)) {
-				found = DDI_SUCCESS;
-				break;
-		} else {
-		    if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
-			pcicfg_indirect_map_devs[ibridge].
-			prefetch_mem_range_bar_offset) &&
-			(space_type == (PCI_BASE_SPACE_MEM |
-			PCI_BASE_PREF_M))) {
-				found = DDI_SUCCESS;
-				break;
-			}
+		} else if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
+		    pcicfg_indirect_map_devs[ibridge].io_range_bar_offset) &&
+		    (space_type == PCI_BASE_SPACE_IO)) {
+			found = DDI_SUCCESS;
+			break;
+		} else if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
+		    pcicfg_indirect_map_devs[ibridge].
+		    prefetch_mem_range_bar_offset) &&
+		    (space_type == (PCI_BASE_SPACE_MEM |
+		    PCI_BASE_PREF_M))) {
+			found = DDI_SUCCESS;
+			break;
 		}
 	}
 	DEBUG3("pcicfg: ntbridge child range: space=%x, base=%lx, len=%lx\n",
-		space_type, assigned[i].pci_phys_low, assigned[i].pci_size_low);
+	    space_type, assigned[i].pci_phys_low, assigned[i].pci_size_low);
 
 	if (found == DDI_SUCCESS)  {
 		*boundbase = assigned[i].pci_phys_low;
@@ -1363,91 +1421,134 @@
 
 /*
  * This will turn  resources allocated by pcicfg_configure()
- * and remove the device tree from the attachment point
+ * and remove the device tree from the Hotplug Connection (CN)
  * and below.  The routine assumes the devices have their
  * drivers detached.
  */
 int
-pcicfg_unconfigure(dev_info_t *devi, uint_t device)
+pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
+    pcicfg_flags_t flags)
 {
 	dev_info_t *child_dip;
 	int func;
 	int i;
+	int max_function, trans_device;
+
+	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
+		max_function = PCICFG_MAX_ARI_FUNCTION;
+	else
+		max_function = PCI_MAX_FUNCTIONS;
 
 	/*
 	 * Cycle through devices to make sure none are busy.
 	 * If a single device is busy fail the whole unconfigure.
 	 */
-	for (func = 0; func < PCI_MAX_FUNCTIONS; func++) {
-		if ((child_dip = pcicfg_devi_find(devi, device, func)) == NULL)
+	for (func = 0; func < max_function; func++) {
+		if ((function != PCICFG_ALL_FUNC) && (function != func))
+			continue;
+
+		if (max_function == PCICFG_MAX_ARI_FUNCTION)
+			trans_device = func >> 3; /* ARI Device */
+		else
+			trans_device = device;
+
+		if ((child_dip = pcicfg_devi_find(devi, trans_device,
+		    func & 7)) == NULL)
 			continue;
 
 		if (ndi_devi_offline(child_dip, NDI_UNCONFIG) == NDI_SUCCESS)
-				continue;
+			continue;
+
 		/*
 		 * Device function is busy. Before returning we have to
 		 * put all functions back online which were taken
 		 * offline during the process.
 		 */
-		DEBUG2("Device [0x%x] function [0x%x] is busy\n", device, func);
+		DEBUG2("Device [0x%x] function [0x%x] is busy\n",
+		    trans_device, func & 7);
+		/*
+		 * If we are only asked to offline one specific function,
+		 * and that fails, we just simply return.
+		 */
+		if (function != PCICFG_ALL_FUNC)
+			return (PCICFG_FAILURE);
+
 		for (i = 0; i < func; i++) {
-		    if ((child_dip = pcicfg_devi_find(devi, device, i))
-			== NULL) {
-			DEBUG0("No more devices to put back on line!!\n");
-			/*
-			 * Made it through all functions
-			 */
-			continue;
-		    }
-		    if (ndi_devi_online(child_dip, NDI_CONFIG) != NDI_SUCCESS) {
-			DEBUG0("Failed to put back devices state\n");
-			return (PCICFG_FAILURE);
-		    }
+			if (max_function == PCICFG_MAX_ARI_FUNCTION)
+				trans_device = i >> 3;
+
+			if ((child_dip = pcicfg_devi_find(devi, trans_device,
+			    i & 7)) == NULL) {
+				DEBUG0("No more devices to put back "
+				    "on line!!\n");
+				/*
+				 * Made it through all functions
+				 */
+				continue;
+			}
+			if (ndi_devi_online(child_dip, NDI_CONFIG)
+			    != NDI_SUCCESS) {
+				DEBUG0("Failed to put back devices state\n");
+				return (PCICFG_FAILURE);
+			}
 		}
 		return (PCICFG_FAILURE);
 	}
 
 	/*
-	 * Now, tear down all devinfo nodes for this AP.
+	 * Now, tear down all devinfo nodes for this Connector.
 	 */
-	for (func = 0; func < PCI_MAX_FUNCTIONS; func++) {
-		if ((child_dip = pcicfg_devi_find(devi,
-			device, func)) == NULL) {
-			DEBUG2("No device at %x,%x\n", device, func);
+	for (func = 0; func < max_function; func++) {
+		if ((function != PCICFG_ALL_FUNC) && (function != func))
+			continue;
+
+		if (max_function == PCICFG_MAX_ARI_FUNCTION)
+			trans_device = func >> 3; /* ARI Device */
+		else
+			trans_device = device;
+
+		if ((child_dip = pcicfg_devi_find(devi, trans_device, func & 7))
+		    == NULL) {
+			DEBUG2("No device at %x,%x\n", trans_device, func & 7);
 			continue;
 		}
 
 		DEBUG2("Tearing down device [0x%x] function [0x%x]\n",
-			device, func);
+		    trans_device, func & 7);
 
 		if (pcicfg_is_ntbridge(child_dip) != DDI_FAILURE)
 			if (pcicfg_ntbridge_unconfigure(child_dip) !=
-					PCICFG_SUCCESS) {
+			    PCICFG_SUCCESS) {
 				cmn_err(CE_WARN,
-					"ntbridge: unconfigure failed\n");
+				    "ntbridge: unconfigure failed\n");
 				return (PCICFG_FAILURE);
 			}
 
-		if (pcicfg_teardown_device(child_dip) != PCICFG_SUCCESS) {
+		if (pcicfg_teardown_device(child_dip, flags)
+		    != PCICFG_SUCCESS) {
 			DEBUG2("Failed to tear down device [0x%x]"
-			"function [0x%x]\n",
-				device, func);
+			    "function [0x%x]\n", trans_device, func & 7);
 			return (PCICFG_FAILURE);
 		}
 	}
+
+	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) {
+		(void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "ari-enabled");
+		(void) pcie_ari_disable(devi);
+	}
+
 	return (PCICFG_SUCCESS);
 }
 
 static int
-pcicfg_teardown_device(dev_info_t *dip)
+pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags)
 {
 	ddi_acc_handle_t	handle;
 
 	/*
 	 * Free up resources associated with 'dip'
 	 */
-
-	if (pcicfg_free_resources(dip) != PCICFG_SUCCESS) {
+	if (pcicfg_free_resources(dip, flags) != PCICFG_SUCCESS) {
 		DEBUG0("Failed to free resources\n");
 		return (PCICFG_FAILURE);
 	}
@@ -1499,8 +1600,7 @@
 {
 	pcicfg_phdl_t *new;
 
-	new = (pcicfg_phdl_t *)kmem_zalloc(sizeof (pcicfg_phdl_t),
-		KM_SLEEP);
+	new = (pcicfg_phdl_t *)kmem_zalloc(sizeof (pcicfg_phdl_t), KM_SLEEP);
 
 	new->dip = dip;
 	mutex_enter(&pcicfg_list_mutex);
@@ -1519,7 +1619,7 @@
 
 	mutex_enter(&pcicfg_list_mutex);
 	for (entry = pcicfg_phdl_list; entry != NULL; follow = entry,
-		entry = entry->next) {
+	    entry = entry->next) {
 		if (entry->dip == dip) {
 			if (entry == pcicfg_phdl_list) {
 				pcicfg_phdl_list = entry->next;
@@ -1533,26 +1633,22 @@
 			 */
 			if (entry->memory_len > 0) {
 				(void) ndi_ra_free(ddi_get_parent(dip),
-					entry->memory_base,
-					entry->memory_len,
-					NDI_RA_TYPE_MEM, NDI_RA_PASS);
+				    entry->memory_base, entry->memory_len,
+				    NDI_RA_TYPE_MEM, NDI_RA_PASS);
 			}
 			pcicfg_free_hole(&entry->mem_hole);
 
 			if (entry->io_len > 0) {
 				(void) ndi_ra_free(ddi_get_parent(dip),
-					entry->io_base,
-					entry->io_len,
-					NDI_RA_TYPE_IO, NDI_RA_PASS);
+				    entry->io_base, entry->io_len,
+				    NDI_RA_TYPE_IO, NDI_RA_PASS);
 			}
 			pcicfg_free_hole(&entry->io_hole);
 
 			if (entry->pf_memory_len > 0) {
 				(void) ndi_ra_free(ddi_get_parent(dip),
-					entry->pf_memory_base,
-					entry->pf_memory_len,
-					NDI_RA_TYPE_PCI_PREFETCH_MEM,
-					NDI_RA_PASS);
+				    entry->pf_memory_base, entry->pf_memory_len,
+				    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
 			}
 			pcicfg_free_hole(&entry->pf_mem_hole);
 
@@ -1592,8 +1688,7 @@
 
 	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
 
-	DEBUG1("bridge assign: assigning addresses to %s\n",
-					ddi_get_name(dip));
+	DEBUG1("bridge assign: assigning addresses to %s\n", ddi_get_name(dip));
 
 	entry->error = PCICFG_SUCCESS;
 
@@ -1603,8 +1698,7 @@
 		return (DDI_WALK_TERMINATE);
 	}
 
-	if (pcicfg_config_setup(dip, &handle)
-					!= DDI_SUCCESS) {
+	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
 		DEBUG0("Failed to map config space!\n");
 		entry->error = PCICFG_FAILURE;
 		return (DDI_WALK_TERMINATE);
@@ -1614,27 +1708,25 @@
 
 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
 
-		bzero((caddr_t)range,
-			sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
+		bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
 
 		(void) pcicfg_setup_bridge(entry, handle);
 
 		range[0].child_high = range[0].parent_high |=
-			(PCI_REG_REL_M | PCI_ADDR_IO);
-		range[0].child_low = range[0].parent_low =
-			entry->io_last;
+		    (PCI_REG_REL_M | PCI_ADDR_IO);
+		range[0].child_low = range[0].parent_low = entry->io_last;
 		range[1].child_high = range[1].parent_high |=
-			(PCI_REG_REL_M | PCI_ADDR_MEM32);
+		    (PCI_REG_REL_M | PCI_ADDR_MEM32);
 		range[1].child_low = range[1].parent_low =
-			entry->memory_last;
+		    entry->memory_last;
 		range[2].child_high = range[2].parent_high |=
-			(PCI_REG_REL_M | PCI_ADDR_MEM32 | PCI_REG_PF_M);
+		    (PCI_REG_REL_M | PCI_ADDR_MEM32 | PCI_REG_PF_M);
 		range[2].child_low = range[2].parent_low =
-			entry->pf_memory_last;
+		    entry->pf_memory_last;
 
 		ndi_devi_enter(dip, &count);
 		ddi_walk_devs(ddi_get_child(dip),
-			pcicfg_bridge_assign, (void *)entry);
+		    pcicfg_bridge_assign, (void *)entry);
 		ndi_devi_exit(dip, count);
 
 		(void) pcicfg_update_bridge(entry, handle);
@@ -1643,7 +1735,7 @@
 		bus_range[1] = pci_config_get8(handle, PCI_BCNF_SUBBUS);
 
 		if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
-				"bus-range", bus_range, 2) != DDI_SUCCESS) {
+		    "bus-range", bus_range, 2) != DDI_SUCCESS) {
 			DEBUG0("Failed to set bus-range property");
 			entry->error = PCICFG_FAILURE;
 			(void) pcicfg_config_teardown(&handle);
@@ -1655,30 +1747,25 @@
 		 * under the bridge.
 		 */
 		mem_residual = entry->memory_len -
-			(entry->memory_last - entry->memory_base);
+		    (entry->memory_last - entry->memory_base);
 		if (mem_residual > 0) {
 			(void) ndi_ra_free(ddi_get_parent(dip),
-				entry->memory_last,
-				mem_residual,
-				NDI_RA_TYPE_MEM, NDI_RA_PASS);
+			    entry->memory_last, mem_residual,
+			    NDI_RA_TYPE_MEM, NDI_RA_PASS);
 		}
 
-		io_residual = entry->io_len -
-			(entry->io_last - entry->io_base);
+		io_residual = entry->io_len - (entry->io_last - entry->io_base);
 		if (io_residual > 0) {
-			(void) ndi_ra_free(ddi_get_parent(dip),
-				entry->io_last,
-				io_residual,
-				NDI_RA_TYPE_IO, NDI_RA_PASS);
+			(void) ndi_ra_free(ddi_get_parent(dip), entry->io_last,
+			    io_residual, NDI_RA_TYPE_IO, NDI_RA_PASS);
 		}
 
 		pf_mem_residual = entry->pf_memory_len -
-			(entry->pf_memory_last - entry->pf_memory_base);
+		    (entry->pf_memory_last - entry->pf_memory_base);
 		if (pf_mem_residual > 0) {
 			(void) ndi_ra_free(ddi_get_parent(dip),
-				entry->pf_memory_last,
-				pf_mem_residual,
-				NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
+			    entry->pf_memory_last, pf_mem_residual,
+			    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
 		}
 
 		if (entry->io_len > 0) {
@@ -1692,7 +1779,7 @@
 		}
 		if (entry->memory_len > 0) {
 			range[1].size_low =
-				entry->memory_last - entry->memory_base;
+			    entry->memory_last - entry->memory_base;
 			if (pcicfg_update_ranges_prop(dip, &range[1])) {
 				DEBUG0("Failed to update ranges (memory)\n");
 				entry->error = PCICFG_FAILURE;
@@ -1702,7 +1789,7 @@
 		}
 		if (entry->pf_memory_len > 0) {
 			range[2].size_low =
-				entry->pf_memory_last - entry->pf_memory_base;
+			    entry->pf_memory_last - entry->pf_memory_base;
 			if (pcicfg_update_ranges_prop(dip, &range[2])) {
 				DEBUG0("Failed to update ranges (PF memory)\n");
 				entry->error = PCICFG_FAILURE;
@@ -1733,9 +1820,8 @@
 	 * For each "reg" property with a length, allocate memory
 	 * and program the base registers.
 	 */
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-		DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
-		&length) != DDI_PROP_SUCCESS) {
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
+	    (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
 		DEBUG0("Failed to read reg property\n");
 		entry->error = PCICFG_FAILURE;
 		(void) pcicfg_config_teardown(&handle);
@@ -1745,8 +1831,7 @@
 	rcount = length / sizeof (pci_regspec_t);
 	offset = PCI_CONF_BASE0;
 	for (i = 0; i < rcount; i++) {
-		if ((reg[i].pci_size_low != 0)||
-			(reg[i].pci_size_hi != 0)) {
+		if ((reg[i].pci_size_low != 0) || (reg[i].pci_size_hi != 0)) {
 
 			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
 
@@ -1759,20 +1844,18 @@
 					    reg[i].pci_size_low, &mem_answer);
 				} else { /* get non prefetchable memory */
 					pcicfg_get_mem(entry,
-					reg[i].pci_size_low, &mem_answer);
+					    reg[i].pci_size_low, &mem_answer);
 				}
 				pci_config_put64(handle, offset, mem_answer);
 				DEBUG2("REGISTER off %x (64)LO ----> [0x%x]\n",
-					offset,
-					pci_config_get32(handle, offset));
+				    offset, pci_config_get32(handle, offset));
 				DEBUG2("REGISTER off %x (64)HI ----> [0x%x]\n",
-					offset + 4,
-					pci_config_get32(handle, offset + 4));
+				    offset + 4,
+				    pci_config_get32(handle, offset + 4));
 
 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
 				reg[i].pci_phys_low = PCICFG_LOADDR(mem_answer);
-				reg[i].pci_phys_mid  =
-						PCICFG_HIADDR(mem_answer);
+				reg[i].pci_phys_mid = PCICFG_HIADDR(mem_answer);
 				break;
 
 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
@@ -1783,15 +1866,14 @@
 				} else {
 					/* get non prefetchable memory */
 					pcicfg_get_mem(entry,
-					reg[i].pci_size_low, &mem_answer);
+					    reg[i].pci_size_low, &mem_answer);
 				}
 
-				pci_config_put32(handle,
-					offset, (uint32_t)mem_answer);
+				pci_config_put32(handle, offset,
+				    (uint32_t)mem_answer);
 
 				DEBUG2("REGISTER off %x(32)LO ----> [0x%x]\n",
-					offset,
-					pci_config_get32(handle, offset));
+				    offset, pci_config_get32(handle, offset));
 
 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
 				reg[i].pci_phys_low = (uint32_t)mem_answer;
@@ -1800,13 +1882,12 @@
 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
 				/* allocate I/O space from the allocator */
 
-				(void) pcicfg_get_io(entry,
-					reg[i].pci_size_low, &io_answer);
+				(void) pcicfg_get_io(entry, reg[i].pci_size_low,
+				    &io_answer);
 				pci_config_put32(handle, offset, io_answer);
 
 				DEBUG2("REGISTER off %x (I/O)LO ----> [0x%x]\n",
-					offset,
-					pci_config_get32(handle, offset));
+				    offset, pci_config_get32(handle, offset));
 
 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
 				reg[i].pci_phys_low = io_answer;
@@ -1824,8 +1905,8 @@
 			 * Now that memory locations are assigned,
 			 * update the assigned address property.
 			 */
-			if (pcicfg_update_assigned_prop(dip,
-				&reg[i]) != PCICFG_SUCCESS) {
+			if (pcicfg_update_assigned_prop(dip, &reg[i])
+			    != PCICFG_SUCCESS) {
 				kmem_free(reg, length);
 				(void) pcicfg_config_teardown(&handle);
 				entry->error = PCICFG_FAILURE;
@@ -1855,7 +1936,6 @@
 	uint64_t		answer;
 	uint64_t		alen;
 
-
 	DEBUG1("%llx now under configuration\n", dip);
 
 	/* request.ra_len = PCICFG_ROUND_UP(request.ra_len, PCICFG_IOGRAN); */
@@ -1866,9 +1946,8 @@
 	/*
 	 * XXX Failure here should be noted
 	 */
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-		DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
-		&length) != DDI_PROP_SUCCESS) {
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
+	    (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
 		DEBUG0("Failed to read reg property\n");
 		return (PCICFG_FAILURE);
 	}
@@ -1911,8 +1990,7 @@
 	for (i = 0; i < rcount; i++) {
 		char	*mem_type;
 
-		if ((reg[i].pci_size_low != 0)||
-			(reg[i].pci_size_hi != 0)) {
+		if ((reg[i].pci_size_low != 0)|| (reg[i].pci_size_hi != 0)) {
 
 			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
 			request.ra_len = reg[i].pci_size_low;
@@ -1920,29 +1998,28 @@
 			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
 				if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
-				    mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
+					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
 				} else {
-				    mem_type = NDI_RA_TYPE_MEM;
+					mem_type = NDI_RA_TYPE_MEM;
 				}
 				/* allocate memory space from the allocator */
-				if (ndi_ra_alloc(ddi_get_parent(dip),
-					&request, &answer, &alen,
-					mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
+				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
+				    &answer, &alen, mem_type, NDI_RA_PASS)
+				    != NDI_SUCCESS) {
 					DEBUG0("Failed to allocate 64b mem\n");
 					kmem_free(reg, length);
 					(void) pcicfg_config_teardown(&handle);
 					return (PCICFG_NORESRC);
 				}
 				DEBUG3("64 addr = [0x%x.0x%x] len [0x%x]\n",
-					PCICFG_HIADDR(answer),
-					PCICFG_LOADDR(answer),
-					alen);
+				    PCICFG_HIADDR(answer),
+				    PCICFG_LOADDR(answer), alen);
 				/* program the low word */
-				pci_config_put32(handle,
-					offset, PCICFG_LOADDR(answer));
+				pci_config_put32(handle, offset,
+				    PCICFG_LOADDR(answer));
 				/* program the high word */
 				pci_config_put32(handle, offset + 4,
-					PCICFG_HIADDR(answer));
+				    PCICFG_HIADDR(answer));
 
 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
@@ -1951,8 +2028,8 @@
 				 * currently support 32b address space
 				 * assignments only.
 				 */
-				reg[i].pci_phys_hi ^= PCI_ADDR_MEM64 ^
-							PCI_ADDR_MEM32;
+				reg[i].pci_phys_hi ^=
+				    PCI_ADDR_MEM64 ^ PCI_ADDR_MEM32;
 
 				offset += 8;
 				break;
@@ -1963,21 +2040,21 @@
 				else
 					mem_type = NDI_RA_TYPE_MEM;
 				/* allocate memory space from the allocator */
-				if (ndi_ra_alloc(ddi_get_parent(dip),
-					&request, &answer, &alen,
-					mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
+				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
+				    &answer, &alen, mem_type, NDI_RA_PASS)
+				    != NDI_SUCCESS) {
 					DEBUG0("Failed to allocate 32b mem\n");
 					kmem_free(reg, length);
 					(void) pcicfg_config_teardown(&handle);
 					return (PCICFG_NORESRC);
 				}
 				DEBUG3("32 addr = [0x%x.0x%x] len [0x%x]\n",
-					PCICFG_HIADDR(answer),
-					PCICFG_LOADDR(answer),
-					alen);
+				    PCICFG_HIADDR(answer),
+				    PCICFG_LOADDR(answer),
+				    alen);
 				/* program the low word */
-				pci_config_put32(handle,
-					offset, PCICFG_LOADDR(answer));
+				pci_config_put32(handle, offset,
+				    PCICFG_LOADDR(answer));
 
 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
@@ -1987,21 +2064,19 @@
 				break;
 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
 				/* allocate I/O space from the allocator */
-				if (ndi_ra_alloc(ddi_get_parent(dip),
-					&request, &answer, &alen,
-					NDI_RA_TYPE_IO, NDI_RA_PASS)
-							!= NDI_SUCCESS) {
+				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
+				    &answer, &alen, NDI_RA_TYPE_IO, NDI_RA_PASS)
+				    != NDI_SUCCESS) {
 					DEBUG0("Failed to allocate I/O\n");
 					kmem_free(reg, length);
 					(void) pcicfg_config_teardown(&handle);
 					return (PCICFG_NORESRC);
 				}
 				DEBUG3("I/O addr = [0x%x.0x%x] len [0x%x]\n",
-					PCICFG_HIADDR(answer),
-					PCICFG_LOADDR(answer),
-					alen);
-				pci_config_put32(handle,
-					offset, PCICFG_LOADDR(answer));
+				    PCICFG_HIADDR(answer),
+				    PCICFG_LOADDR(answer), alen);
+				pci_config_put32(handle, offset,
+				    PCICFG_LOADDR(answer));
 
 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
@@ -2020,8 +2095,8 @@
 			 * update the assigned address property.
 			 */
 
-			if (pcicfg_update_assigned_prop(dip,
-				&reg[i]) != PCICFG_SUCCESS) {
+			if (pcicfg_update_assigned_prop(dip, &reg[i])
+			    != PCICFG_SUCCESS) {
 				kmem_free(reg, length);
 				(void) pcicfg_config_teardown(&handle);
 				return (PCICFG_FAILURE);
@@ -2038,6 +2113,138 @@
 	return (PCICFG_SUCCESS);
 }
 
+static int
+pcicfg_device_assign_readonly(dev_info_t *dip)
+{
+	ddi_acc_handle_t	handle;
+	pci_regspec_t		*assigned;
+	int			length;
+	int			acount;
+	int			i;
+	ndi_ra_request_t	request;
+	uint64_t		answer;
+	uint64_t		alen;
+
+	DEBUG1("%llx now under configuration\n", dip);
+
+	/*
+	 * we don't support ntbridges for readonly probe.
+	 */
+	if (pcicfg_ntbridge_child(dip) == DDI_SUCCESS) {
+		return (PCICFG_FAILURE);
+	}
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
+	    &length) != DDI_PROP_SUCCESS) {
+		DEBUG0("Failed to read assigned-addresses property\n");
+		return (PCICFG_FAILURE);
+	}
+
+	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
+		DEBUG0("Failed to map config space!\n");
+		kmem_free(assigned, length);
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * If there is an interrupt pin set program
+	 * interrupt line with default values.
+	 */
+	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
+		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
+	}
+	/*
+	 * Note: Both non-prefetchable and prefetchable memory space
+	 * allocations are made within 32bit space. Currently, BIOSs
+	 * allocate device memory for PCI devices within the 32bit space
+	 * so this will not be a problem.
+	 */
+	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
+
+	request.ra_flags = NDI_RA_ALLOC_SPECIFIED;  /* specified addr */
+	request.ra_boundbase = 0;
+	request.ra_boundlen = PCICFG_4GIG_LIMIT;
+
+	acount = length / sizeof (pci_regspec_t);
+	for (i = 0; i < acount; i++) {
+		char	*mem_type;
+
+		if ((assigned[i].pci_size_low != 0)||
+		    (assigned[i].pci_size_hi != 0)) {
+
+			request.ra_len = assigned[i].pci_size_low;
+
+			switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
+			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
+				request.ra_addr = (uint64_t)PCICFG_LADDR(
+				    assigned[i].pci_phys_low,
+				    assigned[i].pci_phys_mid);
+
+				if (assigned[i].pci_phys_hi & PCI_REG_PF_M) {
+					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
+				} else {
+					mem_type = NDI_RA_TYPE_MEM;
+				}
+				/* allocate memory space from the allocator */
+				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
+				    &answer, &alen, mem_type, NDI_RA_PASS)
+				    != NDI_SUCCESS) {
+					DEBUG0("Failed to allocate 64b mem\n");
+					kmem_free(assigned, length);
+					return (PCICFG_NORESRC);
+				}
+
+				break;
+			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
+				request.ra_addr = (uint64_t)
+				    assigned[i].pci_phys_low;
+
+				if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
+					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
+				else
+					mem_type = NDI_RA_TYPE_MEM;
+				/* allocate memory space from the allocator */
+				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
+				    &answer, &alen, mem_type, NDI_RA_PASS)
+				    != NDI_SUCCESS) {
+					DEBUG0("Failed to allocate 32b mem\n");
+					kmem_free(assigned, length);
+					return (PCICFG_NORESRC);
+				}
+
+				break;
+			case PCI_REG_ADDR_G(PCI_ADDR_IO):
+				request.ra_addr = (uint64_t)
+				    assigned[i].pci_phys_low;
+
+				/* allocate I/O space from the allocator */
+				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
+				    &answer, &alen, NDI_RA_TYPE_IO, NDI_RA_PASS)
+				    != NDI_SUCCESS) {
+					DEBUG0("Failed to allocate I/O\n");
+					kmem_free(assigned, length);
+					return (PCICFG_NORESRC);
+				}
+
+				break;
+			default:
+				DEBUG0("Unknown register type\n");
+				kmem_free(assigned, length);
+				return (PCICFG_FAILURE);
+			} /* switch */
+		}
+	}
+
+	(void) pcicfg_device_on(handle);
+	kmem_free(assigned, length);
+
+	PCICFG_DUMP_DEVICE_CONFIG(handle);
+
+	(void) pcicfg_config_teardown(&handle);
+	return (PCICFG_SUCCESS);
+}
+
 #ifdef	DEBUG
 /*
  * This function is useful in debug mode, where we can measure how
@@ -2086,7 +2293,7 @@
 		actual_hole_start = PCICFG_ROUND_UP(hole->start, length);
 		if (((actual_hole_start - hole->start) + length) <= hole->len) {
 			DEBUG3("hole found. start %llx, len %llx, req=0x%x\n",
-				hole->start, hole->len, length);
+			    hole->start, hole->len, length);
 			ostart = hole->start;
 			olen = hole->len;
 			/* current hole parameters adjust */
@@ -2098,7 +2305,7 @@
 			} else {
 				hole->len = actual_hole_start - hole->start;
 				nhole = (hole_t *)kmem_zalloc(sizeof (hole_t),
-								KM_SLEEP);
+				    KM_SLEEP);
 				nhole->start = actual_hole_start + length;
 				nhole->len = (ostart + olen) - nhole->start;
 				nhole->next = NULL;
@@ -2108,10 +2315,10 @@
 				if (nhole->start > *alast)
 					*alast = nhole->start;
 				DEBUG2("put new hole to %llx, %llx\n",
-					nhole->start, nhole->len);
+				    nhole->start, nhole->len);
 			}
 			DEBUG2("adjust current hole to %llx, %llx\n",
-					hole->start, hole->len);
+			    hole->start, hole->len);
 			break;
 		}
 		actual_hole_start = 0;
@@ -2123,20 +2330,19 @@
 }
 
 static void
-pcicfg_get_mem(pcicfg_phdl_t *entry,
-	uint32_t length, uint64_t *ans)
+pcicfg_get_mem(pcicfg_phdl_t *entry, uint32_t length, uint64_t *ans)
 {
 	uint64_t new_mem;
 
 	/* See if there is a hole, that can hold this request. */
 	new_mem = pcicfg_alloc_hole(&entry->mem_hole, &entry->memory_last,
-								length);
+	    length);
 	if (new_mem) {	/* if non-zero, found a hole. */
 		if (ans != NULL)
 			*ans = new_mem;
 	} else
 		cmn_err(CE_WARN, "No %u bytes memory window for %s\n",
-					length, ddi_get_name(entry->dip));
+		    length, ddi_get_name(entry->dip));
 }
 
 static void
@@ -2158,24 +2364,23 @@
 			*ans = new_io;
 	} else
 		cmn_err(CE_WARN, "No %u bytes IO space window for %s\n",
-					length, ddi_get_name(entry->dip));
+		    length, ddi_get_name(entry->dip));
 }
 
 static void
-pcicfg_get_pf_mem(pcicfg_phdl_t *entry,
-	uint32_t length, uint64_t *ans)
+pcicfg_get_pf_mem(pcicfg_phdl_t *entry, uint32_t length, uint64_t *ans)
 {
 	uint64_t new_mem;
 
 	/* See if there is a hole, that can hold this request. */
 	new_mem = pcicfg_alloc_hole(&entry->pf_mem_hole, &entry->pf_memory_last,
-								length);
+	    length);
 	if (new_mem) {	/* if non-zero, found a hole. */
 		if (ans != NULL)
 			*ans = new_mem;
 	} else
 		cmn_err(CE_WARN, "No %u bytes PF memory window for %s\n",
-					length, ddi_get_name(entry->dip));
+		    length, ddi_get_name(entry->dip));
 }
 
 static int
@@ -2212,17 +2417,16 @@
 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
 
 		if (entry->highest_bus < pci_config_get8(handle,
-			PCI_BCNF_SECBUS)) {
+		    PCI_BCNF_SECBUS)) {
 			entry->highest_bus =
-				pci_config_get8(handle, PCI_BCNF_SECBUS);
+			    pci_config_get8(handle, PCI_BCNF_SECBUS);
 		}
 		(void) pcicfg_config_teardown(&handle);
 		entry->error = PCICFG_FAILURE;
 		return (DDI_WALK_CONTINUE);
 	} else {
-		if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-			DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp,
-			&length) != DDI_PROP_SUCCESS) {
+		if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+		    "reg", (caddr_t)&pci_rp, &length) != DDI_PROP_SUCCESS) {
 			/*
 			 * If one node in (the subtree of nodes)
 			 * doesn't have a "reg" property fail the
@@ -2247,51 +2451,53 @@
 
 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
 				if (pci_rp[i].pci_phys_hi & PCI_REG_PF_M) {
-				    pf_mem_request->ra_len =
-				    pci_rp[i].pci_size_low +
-				    PCICFG_ROUND_UP(pf_mem_request->ra_len,
-				    pci_rp[i].pci_size_low);
-				    DEBUG1("ADDING 32 --->0x%x\n",
-					pci_rp[i].pci_size_low);
+					pf_mem_request->ra_len =
+					    pci_rp[i].pci_size_low +
+					    PCICFG_ROUND_UP(
+					    pf_mem_request->ra_len,
+					    pci_rp[i].pci_size_low);
+					DEBUG1("ADDING 32 --->0x%x\n",
+					    pci_rp[i].pci_size_low);
 				} else {
-				    mem_request->ra_len =
-				    pci_rp[i].pci_size_low +
-				    PCICFG_ROUND_UP(mem_request->ra_len,
-				    pci_rp[i].pci_size_low);
-				    DEBUG1("ADDING 32 --->0x%x\n",
-					pci_rp[i].pci_size_low);
+					mem_request->ra_len =
+					    pci_rp[i].pci_size_low +
+					    PCICFG_ROUND_UP(mem_request->ra_len,
+					    pci_rp[i].pci_size_low);
+					DEBUG1("ADDING 32 --->0x%x\n",
+					    pci_rp[i].pci_size_low);
 				}
 
-			break;
+				break;
 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
 				if (pci_rp[i].pci_phys_hi & PCI_REG_PF_M) {
-				    pf_mem_request->ra_len =
-				    pci_rp[i].pci_size_low +
-				    PCICFG_ROUND_UP(pf_mem_request->ra_len,
-				    pci_rp[i].pci_size_low);
-				    DEBUG1("ADDING 64 --->0x%x\n",
-					pci_rp[i].pci_size_low);
+					pf_mem_request->ra_len =
+					    pci_rp[i].pci_size_low +
+					    PCICFG_ROUND_UP(
+					    pf_mem_request->ra_len,
+					    pci_rp[i].pci_size_low);
+					DEBUG1("ADDING 64 --->0x%x\n",
+					    pci_rp[i].pci_size_low);
 				} else {
-				    mem_request->ra_len =
-				    pci_rp[i].pci_size_low +
-				    PCICFG_ROUND_UP(mem_request->ra_len,
-				    pci_rp[i].pci_size_low);
-				    DEBUG1("ADDING 64 --->0x%x\n",
-					pci_rp[i].pci_size_low);
+					mem_request->ra_len =
+					    pci_rp[i].pci_size_low +
+					    PCICFG_ROUND_UP(mem_request->ra_len,
+					    pci_rp[i].pci_size_low);
+					DEBUG1("ADDING 64 --->0x%x\n",
+					    pci_rp[i].pci_size_low);
 				}
 
-			break;
+				break;
 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
 				io_request->ra_len =
-				pci_rp[i].pci_size_low +
-				PCICFG_ROUND_UP(io_request->ra_len,
-				pci_rp[i].pci_size_low);
+				    pci_rp[i].pci_size_low +
+				    PCICFG_ROUND_UP(io_request->ra_len,
+				    pci_rp[i].pci_size_low);
 				DEBUG1("ADDING I/O --->0x%x\n",
-					pci_rp[i].pci_size_low);
-			break;
+				    pci_rp[i].pci_size_low);
+				break;
 			default:
-			    /* Config space register - not included */
-			break;
+				/* Config space register - not included */
+				break;
 			}
 		}
 
@@ -2320,13 +2526,12 @@
 	int			i;
 
 
-	if ((i = ddi_getlongprop(DDI_DEV_T_ANY, dip,
-		DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges,
-		&length)) != DDI_PROP_SUCCESS) {
+	if ((i = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "ranges", (caddr_t)&ranges, &length)) != DDI_PROP_SUCCESS) {
 		DEBUG0("Failed to read ranges property\n");
 		if (ddi_get_child(dip)) {
 			cmn_err(CE_WARN, "No ranges property found for %s",
-					ddi_get_name(dip));
+			    ddi_get_name(dip));
 			/*
 			 * strictly speaking, we can check for children with
 			 * assigned-addresses but for now it is better to
@@ -2342,57 +2547,53 @@
 	for (i = 0; i < length / sizeof (ppb_ranges_t); i++) {
 		char *mem_type;
 
-		if (ranges[i].size_low != 0 ||
-			ranges[i].size_high != 0) {
+		if (ranges[i].size_low != 0 || ranges[i].size_high != 0) {
 			switch (ranges[i].parent_high & PCI_REG_ADDR_M) {
-				case PCI_ADDR_IO:
-					DEBUG2("Free I/O    "
-					"base/length = [0x%x]/[0x%x]\n",
-						ranges[i].child_low,
-						ranges[i].size_low);
-					if (ndi_ra_free(ddi_get_parent(dip),
-						(uint64_t)ranges[i].child_low,
-						(uint64_t)ranges[i].size_low,
-						NDI_RA_TYPE_IO, NDI_RA_PASS)
-						!= NDI_SUCCESS) {
-						DEBUG0("Trouble freeing "
-						"PCI i/o space\n");
-						kmem_free(ranges, length);
-						return (PCICFG_FAILURE);
-					}
+			case PCI_ADDR_IO:
+				DEBUG2("Free I/O    base/length = "
+				    "[0x%x]/[0x%x]\n", ranges[i].child_low,
+				    ranges[i].size_low);
+				if (ndi_ra_free(ddi_get_parent(dip),
+				    (uint64_t)ranges[i].child_low,
+				    (uint64_t)ranges[i].size_low,
+				    NDI_RA_TYPE_IO, NDI_RA_PASS)
+				    != NDI_SUCCESS) {
+					DEBUG0("Trouble freeing "
+					    "PCI i/o space\n");
+					kmem_free(ranges, length);
+					return (PCICFG_FAILURE);
+				}
 				break;
-				case PCI_ADDR_MEM32:
-				case PCI_ADDR_MEM64:
-				    if (ranges[i].parent_high & PCI_REG_PF_M) {
-					DEBUG3("Free PF Memory base/length"
-					" = [0x%x.0x%x]/[0x%x]\n",
-					ranges[i].child_mid,
-					ranges[i].child_low,
-					ranges[i].size_low)
+			case PCI_ADDR_MEM32:
+			case PCI_ADDR_MEM64:
+				if (ranges[i].parent_high & PCI_REG_PF_M) {
+					DEBUG3("Free PF Memory base/length = "
+					    "[0x%x.0x%x]/[0x%x]\n",
+					    ranges[i].child_mid,
+					    ranges[i].child_low,
+					    ranges[i].size_low);
 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
-				    } else {
+				} else {
 					DEBUG3("Free Memory base/length"
-					" = [0x%x.0x%x]/[0x%x]\n",
-					ranges[i].child_mid,
-					ranges[i].child_low,
-					ranges[i].size_low)
+					    " = [0x%x.0x%x]/[0x%x]\n",
+					    ranges[i].child_mid,
+					    ranges[i].child_low,
+					    ranges[i].size_low)
 					mem_type = NDI_RA_TYPE_MEM;
-				    }
-				    if (ndi_ra_free(ddi_get_parent(dip),
-						PCICFG_LADDR(
-						ranges[i].child_low,
-						ranges[i].child_mid),
-						(uint64_t)ranges[i].size_low,
-						mem_type,
-						NDI_RA_PASS) != NDI_SUCCESS) {
-						DEBUG0("Trouble freeing "
-						    "PCI memory space\n");
-						kmem_free(ranges, length);
-						return (PCICFG_FAILURE);
-				    }
+				}
+				if (ndi_ra_free(ddi_get_parent(dip),
+				    PCICFG_LADDR(ranges[i].child_low,
+				    ranges[i].child_mid),
+				    (uint64_t)ranges[i].size_low,
+				    mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
+					DEBUG0("Trouble freeing "
+					    "PCI memory space\n");
+					kmem_free(ranges, length);
+					return (PCICFG_FAILURE);
+				}
 				break;
-				default:
-					DEBUG0("Unknown memory space\n");
+			default:
+				DEBUG0("Unknown memory space\n");
 				break;
 			}
 		}
@@ -2401,19 +2602,18 @@
 	if (length)
 		kmem_free(ranges, length);
 
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-		DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
-		&k) != DDI_PROP_SUCCESS) {
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "bus-range", (caddr_t)&bus, &k) != DDI_PROP_SUCCESS) {
 		DEBUG0("Failed to read bus-range property\n");
 		return (PCICFG_FAILURE);
 	}
 
 	DEBUG2("Need to free bus [%d] range [%d]\n",
-		bus[0], bus[1] - bus[0] + 1);
-
-	if (ndi_ra_free(ddi_get_parent(dip),
-		(uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
-		NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
+	    bus[0], bus[1] - bus[0] + 1);
+
+	if (ndi_ra_free(ddi_get_parent(dip), (uint64_t)bus[0],
+	    (uint64_t)(bus[1] - bus[0] + 1), NDI_RA_TYPE_PCI_BUSNUM,
+	    NDI_RA_PASS) != NDI_SUCCESS) {
 		DEBUG0("Failed to free a bus number\n");
 		kmem_free(bus, k);
 		return (PCICFG_FAILURE);
@@ -2432,9 +2632,9 @@
 	int acount;
 	int i;
 
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-		DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
-		&length) != DDI_PROP_SUCCESS) {
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "assigned-addresses", (caddr_t)&assigned, &length)
+	    != DDI_PROP_SUCCESS) {
 		DEBUG0("Failed to read assigned-addresses property\n");
 		return (PCICFG_FAILURE);
 	}
@@ -2452,7 +2652,7 @@
 		 * Free the resource if the size of it is not zero.
 		 */
 		if ((assigned[i].pci_size_low != 0)||
-			(assigned[i].pci_size_hi != 0)) {
+		    (assigned[i].pci_size_hi != 0)) {
 			switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
 				/*
@@ -2476,17 +2676,16 @@
 				    (uint64_t)assigned[i].pci_size_low,
 				    mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
 					DEBUG0("Trouble freeing "
-					"PCI memory space\n");
+					    "PCI memory space\n");
 					kmem_free(assigned, length);
 					return (PCICFG_FAILURE);
 				}
 
 				DEBUG4("Returned 0x%x of 32 bit %s space"
-				" @ 0x%x from register 0x%x\n",
-					assigned[i].pci_size_low,
-					mem_type,
-					assigned[i].pci_phys_low,
-					PCI_REG_REG_G(assigned[i].pci_phys_hi));
+				    " @ 0x%x from register 0x%x\n",
+				    assigned[i].pci_size_low, mem_type,
+				    assigned[i].pci_phys_low,
+				    PCI_REG_REG_G(assigned[i].pci_phys_hi));
 
 			break;
 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
@@ -2501,18 +2700,17 @@
 				    (uint64_t)assigned[i].pci_size_low,
 				    mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
 					DEBUG0("Trouble freeing "
-					"PCI memory space\n");
+					    "PCI memory space\n");
 					kmem_free(assigned, length);
 					return (PCICFG_FAILURE);
 				}
 
 				DEBUG5("Returned 0x%x of 64 bit %s space"
-				" @ 0x%x.0x%x from register 0x%x\n",
-					assigned[i].pci_size_low,
-					mem_type,
-					assigned[i].pci_phys_mid,
-					assigned[i].pci_phys_low,
-					PCI_REG_REG_G(assigned[i].pci_phys_hi));
+				    " @ 0x%x.0x%x from register 0x%x\n",
+				    assigned[i].pci_size_low,
+				    mem_type, assigned[i].pci_phys_mid,
+				    assigned[i].pci_phys_low,
+				    PCI_REG_REG_G(assigned[i].pci_phys_hi));
 
 			break;
 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
@@ -2522,15 +2720,14 @@
 				    NDI_RA_TYPE_IO, NDI_RA_PASS) !=
 				    NDI_SUCCESS) {
 					DEBUG0("Trouble freeing "
-					"PCI IO space\n");
+					    "PCI IO space\n");
 					kmem_free(assigned, length);
 					return (PCICFG_FAILURE);
 				}
-				DEBUG3("Returned 0x%x of IO space @ 0x%x"
-				" from register 0x%x\n",
-					assigned[i].pci_size_low,
-					assigned[i].pci_phys_low,
-					PCI_REG_REG_G(assigned[i].pci_phys_hi));
+				DEBUG3("Returned 0x%x of IO space @ 0x%x from "
+				    "register 0x%x\n", assigned[i].pci_size_low,
+				    assigned[i].pci_phys_low,
+				    PCI_REG_REG_G(assigned[i].pci_phys_hi));
 			break;
 			default:
 				DEBUG0("Unknown register type\n");
@@ -2544,7 +2741,7 @@
 }
 
 static int
-pcicfg_free_resources(dev_info_t *dip)
+pcicfg_free_resources(dev_info_t *dip, pcicfg_flags_t flags)
 {
 	ddi_acc_handle_t handle;
 	uint8_t header_type;
@@ -2562,6 +2759,12 @@
 	 * A different algorithm is used for bridges and leaf devices.
 	 */
 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
+		/*
+		 * We only support readonly probing for leaf devices.
+		 */
+		if (flags & PCICFG_FLAG_READ_ONLY)
+			return (PCICFG_FAILURE);
+
 		if (pcicfg_free_bridge_resources(dip) != PCICFG_SUCCESS) {
 			DEBUG0("Failed freeing up bridge resources\n");
 			return (PCICFG_FAILURE);
@@ -2617,9 +2820,8 @@
 	int pci_dev;
 	int pci_func;
 
-	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
-		DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
-		(uint_t *)&length) != DDI_PROP_SUCCESS) {
+	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
 		ctrl->dip = NULL;
 		return (DDI_WALK_TERMINATE);
 	}
@@ -2655,7 +2857,7 @@
 	uint_t		status;
 
 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
-		"assigned-addresses", (caddr_t)&assigned, &alen);
+	    "assigned-addresses", (caddr_t)&assigned, &alen);
 	switch (status) {
 		case DDI_PROP_SUCCESS:
 		break;
@@ -2664,8 +2866,8 @@
 			return (PCICFG_FAILURE);
 		default:
 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
-			"assigned-addresses", (int *)newone,
-				sizeof (*newone)/sizeof (int));
+			    "assigned-addresses", (int *)newone,
+			    sizeof (*newone)/sizeof (int));
 			return (PCICFG_SUCCESS);
 	}
 
@@ -2684,8 +2886,8 @@
 	 * Write out the new "assigned-addresses" spec
 	 */
 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
-		"assigned-addresses", (int *)newreg,
-		(alen + sizeof (*newone))/sizeof (int));
+	    "assigned-addresses", (int *)newreg,
+	    (alen + sizeof (*newone))/sizeof (int));
 
 	kmem_free((caddr_t)newreg, alen+sizeof (*newone));
 	kmem_free(assigned, alen);
@@ -2701,8 +2903,8 @@
 	caddr_t		newreg;
 	uint_t		status;
 
-	status = ddi_getlongprop(DDI_DEV_T_ANY,
-		dip, DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges, &rlen);
+	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "ranges", (caddr_t)&ranges, &rlen);
 
 
 	switch (status) {
@@ -2714,9 +2916,9 @@
 		default:
 			DEBUG0("no ranges property - creating one\n");
 			if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
-				dip, "ranges", (int *)addition,
-				sizeof (ppb_ranges_t)/sizeof (int))
-				!= DDI_SUCCESS) {
+			    dip, "ranges", (int *)addition,
+			    sizeof (ppb_ranges_t)/sizeof (int))
+			    != DDI_SUCCESS) {
 				DEBUG0("Did'nt create ranges property\n");
 				return (PCICFG_FAILURE);
 			}
@@ -2735,12 +2937,11 @@
 	/*
 	 * Write out the new "ranges" property
 	 */
-	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
-		dip, "ranges", (int *)newreg,
-		(rlen + sizeof (ppb_ranges_t))/sizeof (int));
+	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
+	    (int *)newreg, (rlen + sizeof (ppb_ranges_t))/sizeof (int));
 
 	DEBUG1("Updating ranges property for %d entries",
-			rlen / sizeof (ppb_ranges_t) + 1);
+	    rlen / sizeof (ppb_ranges_t) + 1);
 
 	kmem_free((caddr_t)newreg, rlen+sizeof (ppb_ranges_t));
 
@@ -2761,7 +2962,7 @@
 	uint_t		status;
 
 	status = ddi_getlongprop(DDI_DEV_T_ANY,
-		dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
+	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
 
 	switch (status) {
 		case DDI_PROP_SUCCESS:
@@ -2798,7 +2999,7 @@
 			if ((PCI_BASE_TYPE_M & regvalue) == PCI_BASE_TYPE_MEM) {
 				hiword |= PCI_ADDR_MEM32;
 			} else if ((PCI_BASE_TYPE_M & regvalue)
-				== PCI_BASE_TYPE_ALL) {
+			    == PCI_BASE_TYPE_ALL) {
 				hiword |= PCI_ADDR_MEM64;
 			}
 			if (regvalue & PCI_BASE_PREF_M)
@@ -2821,9 +3022,8 @@
 	/*
 	 * Write out the new "reg" property
 	 */
-	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
-		dip, "reg", (int *)newreg,
-		(rlen + sizeof (pci_regspec_t))/sizeof (int));
+	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg",
+	    (int *)newreg, (rlen + sizeof (pci_regspec_t))/sizeof (int));
 
 	kmem_free((caddr_t)newreg, rlen+sizeof (pci_regspec_t));
 	kmem_free((caddr_t)reg, rlen);
@@ -2831,6 +3031,82 @@
 	return (PCICFG_SUCCESS);
 }
 
+static int
+pcicfg_update_assigned_prop_value(dev_info_t *dip, uint32_t size,
+    uint32_t base, uint32_t base_hi, uint_t reg_offset)
+{
+	int		rlen;
+	pci_regspec_t	*reg;
+	uint32_t	hiword;
+	pci_regspec_t	addition;
+	uint_t		status;
+
+	status = ddi_getlongprop(DDI_DEV_T_ANY,
+	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
+
+	switch (status) {
+		case DDI_PROP_SUCCESS:
+		break;
+		case DDI_PROP_NO_MEMORY:
+			DEBUG0("reg present, but unable to get memory\n");
+			return (PCICFG_FAILURE);
+		default:
+			/*
+			 * Since the config space "reg" entry should have been
+			 * created, we expect a "reg" property already
+			 * present here.
+			 */
+			DEBUG0("no reg property\n");
+			return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * Build the regspec, then add it to the existing one(s)
+	 */
+
+	hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
+	    PCI_REG_DEV_G(reg->pci_phys_hi),
+	    PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
+
+	hiword |= PCI_REG_REL_M;
+
+	if (reg_offset == PCI_CONF_ROM) {
+		hiword |= PCI_ADDR_MEM32;
+
+		base = PCI_BASE_ROM_ADDR_M & base;
+	} else {
+		if ((PCI_BASE_SPACE_M & base) == PCI_BASE_SPACE_MEM) {
+			if ((PCI_BASE_TYPE_M & base) == PCI_BASE_TYPE_MEM) {
+				hiword |= PCI_ADDR_MEM32;
+			} else if ((PCI_BASE_TYPE_M & base)
+			    == PCI_BASE_TYPE_ALL) {
+				hiword |= PCI_ADDR_MEM64;
+			}
+			if (base & PCI_BASE_PREF_M)
+				hiword |= PCI_REG_PF_M;
+
+			base = PCI_BASE_M_ADDR_M & base;
+		} else {
+			hiword |= PCI_ADDR_IO;
+
+			base = PCI_BASE_IO_ADDR_M & base;
+			base_hi = 0;
+		}
+	}
+
+	addition.pci_phys_hi = hiword;
+	addition.pci_phys_mid = base_hi;
+	addition.pci_phys_low = base;
+	addition.pci_size_hi = 0;
+	addition.pci_size_low = size;
+
+	DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
+
+	kmem_free((caddr_t)reg, rlen);
+
+	return (pcicfg_update_assigned_prop(dip, &addition));
+}
+
 static void
 pcicfg_device_on(ddi_acc_handle_t config_handle)
 {
@@ -2840,7 +3116,7 @@
 	 * fast back-to-back, and addr. stepping?
 	 */
 	pci_config_put16(config_handle, PCI_CONF_COMM,
-		pci_config_get16(config_handle, PCI_CONF_COMM) | 0x7);
+	    pci_config_get16(config_handle, PCI_CONF_COMM) | 0x7);
 }
 
 static void
@@ -2866,17 +3142,17 @@
 	uint8_t byteval;
 
 	/* These two exists only for non-bridges */
-	if (((pci_config_get8(config_handle, PCI_CONF_HEADER)
-			& PCI_HEADER_TYPE_M) == PCI_HEADER_ZERO) && !pcie_dev) {
+	if (((pci_config_get8(config_handle, PCI_CONF_HEADER) &
+	    PCI_HEADER_TYPE_M) == PCI_HEADER_ZERO) && !pcie_dev) {
 		byteval = pci_config_get8(config_handle, PCI_CONF_MIN_G);
 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-			"min-grant", byteval)) != DDI_SUCCESS) {
+		    "min-grant", byteval)) != DDI_SUCCESS) {
 			return (ret);
 		}
 
 		byteval = pci_config_get8(config_handle, PCI_CONF_MAX_L);
 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-			"max-latency", byteval)) != DDI_SUCCESS) {
+		    "max-latency", byteval)) != DDI_SUCCESS) {
 			return (ret);
 		}
 	}
@@ -2887,32 +3163,32 @@
 	 */
 	val = pci_config_get16(config_handle, PCI_CONF_VENID);
 
-	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-				"vendor-id", val)) != DDI_SUCCESS) {
+	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "vendor-id", val))
+	    != DDI_SUCCESS) {
 		return (ret);
 	}
 	val = pci_config_get16(config_handle, PCI_CONF_DEVID);
-	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-				"device-id", val)) != DDI_SUCCESS) {
+	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "device-id", val))
+	    != DDI_SUCCESS) {
 		return (ret);
 	}
 	byteval = pci_config_get8(config_handle, PCI_CONF_REVID);
 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-				"revision-id", byteval)) != DDI_SUCCESS) {
+	    "revision-id", byteval)) != DDI_SUCCESS) {
 		return (ret);
 	}
 
 	wordval = (pci_config_get16(config_handle, PCI_CONF_SUBCLASS)<< 8) |
-		(pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
+	    (pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
 
 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-				"class-code", wordval)) != DDI_SUCCESS) {
+	    "class-code", wordval)) != DDI_SUCCESS) {
 		return (ret);
 	}
-	val = (pci_config_get16(config_handle,
-		PCI_CONF_STAT) & PCI_STAT_DEVSELT);
+	val = (pci_config_get16(config_handle, PCI_CONF_STAT) &
+	    PCI_STAT_DEVSELT);
 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-				"devsel-speed", val)) != DDI_SUCCESS) {
+	    "devsel-speed", val)) != DDI_SUCCESS) {
 		return (ret);
 	}
 
@@ -2922,24 +3198,22 @@
 	 * is set, non-existent otherwise
 	 */
 	if ((!pcie_dev) &&
-			(pci_config_get16(config_handle, PCI_CONF_STAT) &
-				PCI_STAT_FBBC)) {
+	    (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_FBBC)) {
 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-				"fast-back-to-back", 0)) != DDI_SUCCESS) {
+		    "fast-back-to-back", 0)) != DDI_SUCCESS) {
 			return (ret);
 		}
 	}
 	if ((!pcie_dev) &&
-			(pci_config_get16(config_handle, PCI_CONF_STAT) &
-				PCI_STAT_66MHZ)) {
+	    (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_66MHZ)) {
 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-				"66mhz-capable", 0)) != DDI_SUCCESS) {
+		    "66mhz-capable", 0)) != DDI_SUCCESS) {
 			return (ret);
 		}
 	}
 	if (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_UDF) {
 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-				"udf-supported", 0)) != DDI_SUCCESS) {
+		    "udf-supported", 0)) != DDI_SUCCESS) {
 			return (ret);
 		}
 	}
@@ -2950,24 +3224,22 @@
 	 * is non-zero then the property exists with the value
 	 * of the register.
 	 */
-	if ((val = pci_config_get16(config_handle,
-		PCI_CONF_SUBVENID)) != 0) {
+	if ((val = pci_config_get16(config_handle, PCI_CONF_SUBVENID)) != 0) {
 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-				"subsystem-vendor-id", val)) != DDI_SUCCESS) {
+		    "subsystem-vendor-id", val)) != DDI_SUCCESS) {
 			return (ret);
 		}
 	}
-	if ((val = pci_config_get16(config_handle,
-		PCI_CONF_SUBSYSID)) != 0) {
+	if ((val = pci_config_get16(config_handle, PCI_CONF_SUBSYSID)) != 0) {
 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-				"subsystem-id", val)) != DDI_SUCCESS) {
+		    "subsystem-id", val)) != DDI_SUCCESS) {
 			return (ret);
 		}
 	}
-	if ((val = pci_config_get16(config_handle,
-		PCI_CONF_CACHE_LINESZ)) != 0) {
+	if ((val = pci_config_get16(config_handle, PCI_CONF_CACHE_LINESZ))
+	    != 0) {
 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-				"cache-line-size", val)) != DDI_SUCCESS) {
+		    "cache-line-size", val)) != DDI_SUCCESS) {
 			return (ret);
 		}
 	}
@@ -2982,18 +3254,18 @@
 		 * record the interrupt line used
 		 */
 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-				"interrupts", byteval)) != DDI_SUCCESS) {
+		    "interrupts", byteval)) != DDI_SUCCESS) {
 			return (ret);
 		}
 	}
 	(void) PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_id_loc);
 	if (pcie_dev && cap_id_loc != PCI_CAP_NEXT_PTR_NULL) {
-		val = pci_config_get16(config_handle, cap_id_loc +
-				PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL;
+		val = pci_config_get16(config_handle, cap_id_loc + PCIE_PCIECAP)
+		    & PCIE_PCIECAP_SLOT_IMPL;
 		/* if slot implemented, get physical slot number */
 		if (val) {
 			wordval = pci_config_get32(config_handle, cap_id_loc +
-					PCIE_SLOTCAP);
+			    PCIE_SLOTCAP);
 			/* create the property only if slotnum set correctly? */
 			if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
 			    "physical-slot#", PCIE_SLOTCAP_PHY_SLOT_NUM(
@@ -3018,15 +3290,15 @@
 		(void) strcpy(device_type, "pci");
 
 	if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
-			"device_type", device_type)) != DDI_SUCCESS) {
+	    "device_type", device_type)) != DDI_SUCCESS) {
 		return (ret);
 	}
 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-				"#address-cells", 3)) != DDI_SUCCESS) {
+	    "#address-cells", 3)) != DDI_SUCCESS) {
 		return (ret);
 	}
-	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-				"#size-cells", 2)) != DDI_SUCCESS) {
+	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "#size-cells", 2))
+	    != DDI_SUCCESS) {
 		return (ret);
 	}
 	return (PCICFG_SUCCESS);
@@ -3059,9 +3331,9 @@
 	/*
 	 * NOTE: These are for both a child and PCI-PCI bridge node
 	 */
-	sub_vid = pci_config_get16(config_handle, PCI_CONF_SUBVENID),
+	sub_vid = pci_config_get16(config_handle, PCI_CONF_SUBVENID);
 	sub_sid = pci_config_get16(config_handle, PCI_CONF_SUBSYSID);
-	vid = pci_config_get16(config_handle, PCI_CONF_VENID),
+	vid = pci_config_get16(config_handle, PCI_CONF_VENID);
 	did = pci_config_get16(config_handle, PCI_CONF_DEVID);
 	revid = pci_config_get8(config_handle, PCI_CONF_REVID);
 	pif = pci_config_get8(config_handle, PCI_CONF_PROGCLASS);
@@ -3127,25 +3399,27 @@
 
 	do {
 		if (sub_vid) {
-		    /* pci[ex]VVVV,DDDD.SSSS.ssss.RR */
-		    (void) sprintf(buffer, "%s%x,%x.%x.%x.%x", pprefix,
-			vid, did, sub_vid, sub_sid, revid);
-		    compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
-		    (void) strcpy(compat[n++], buffer);
-
-		    /* pci[ex]VVVV,DDDD.SSSS.ssss */
-		    (void) sprintf(buffer, "%s%x,%x.%x.%x", pprefix,  vid, did,
-					sub_vid, sub_sid);
-		    compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
-		    (void) strcpy(compat[n++], buffer);
-
-		    /* pciSSSS.ssss  -> not created for PCIe as per PCIe */
-		    /* binding to IEEE 1275 spec.			 */
-		    if (!pcie_dev && pcicfg_do_legacy_props) {
-			(void) sprintf(buffer, "pci%x,%x", sub_vid, sub_sid);
+			/* pci[ex]VVVV,DDDD.SSSS.ssss.RR */
+			(void) sprintf(buffer, "%s%x,%x.%x.%x.%x", pprefix, vid,
+			    did, sub_vid, sub_sid, revid);
+			compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+			(void) strcpy(compat[n++], buffer);
+
+			/* pci[ex]VVVV,DDDD.SSSS.ssss */
+			(void) sprintf(buffer, "%s%x,%x.%x.%x", pprefix,  vid,
+			    did, sub_vid, sub_sid);
 			compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
 			(void) strcpy(compat[n++], buffer);
-		    }
+
+			/* pciSSSS.ssss  -> not created for PCIe as per PCIe */
+			/* binding to IEEE 1275 spec.			 */
+			if (!pcie_dev && pcicfg_do_legacy_props) {
+				(void) sprintf(buffer, "pci%x,%x", sub_vid,
+				    sub_sid);
+				compat[n] = kmem_alloc(strlen(buffer) + 1,
+				    KM_SLEEP);
+				(void) strcpy(compat[n++], buffer);
+			}
 		}
 
 		/* pci[ex]VVVV,DDDD.RR */
@@ -3159,8 +3433,8 @@
 		(void) strcpy(compat[n++], buffer);
 
 		/* pci[ex]class,CCSSPP */
-		(void) sprintf(buffer, "%sclass,%02x%02x%02x", pprefix,
-			pclass, psubclass, pif);
+		(void) sprintf(buffer, "%sclass,%02x%02x%02x", pprefix, pclass,
+		    psubclass, pif);
 		compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
 		(void) strcpy(compat[n++], buffer);
 
@@ -3178,8 +3452,8 @@
 
 	} while (pcicfg_do_legacy_props);
 
-	ret = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
-		"compatible", (char **)compat, n);
+	ret = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, "compatible",
+	    (char **)compat, n);
 
 	for (i = 0; i < n; i++) {
 		kmem_free(compat[i], strlen(compat[i]) + 1);
@@ -3196,7 +3470,7 @@
 uint_t primary, uint_t secondary, uint_t subordinate)
 {
 	DEBUG3("Setting bridge bus-range %d,%d,%d\n", primary, secondary,
-			subordinate);
+	    subordinate);
 	/*
 	 * Primary bus#
 	 */
@@ -3230,10 +3504,10 @@
 	 * Reset the secondary bus
 	 */
 	pci_config_put16(handle, PCI_BCNF_BCNTRL,
-		pci_config_get16(handle, PCI_BCNF_BCNTRL) | 0x40);
+	    pci_config_get16(handle, PCI_BCNF_BCNTRL) | 0x40);
 	drv_usecwait(1000);
 	pci_config_put16(handle, PCI_BCNF_BCNTRL,
-		pci_config_get16(handle, PCI_BCNF_BCNTRL) & ~0x40);
+	    pci_config_get16(handle, PCI_BCNF_BCNTRL) & ~0x40);
 	drv_usecwait(1000);
 
 	/*
@@ -3241,24 +3515,24 @@
 	 * start of the memory range
 	 */
 	pci_config_put16(handle, PCI_BCNF_MEM_BASE,
-		PCICFG_HIWORD(PCICFG_LOADDR(entry->memory_last)));
+	    PCICFG_HIWORD(PCICFG_LOADDR(entry->memory_last)));
 
 	/*
 	 * Program the I/O base register with the start of the I/O range
 	 */
 	pci_config_put8(handle, PCI_BCNF_IO_BASE_LOW,
-		PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(entry->io_last))));
+	    PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(entry->io_last))));
 	pci_config_put16(handle, PCI_BCNF_IO_BASE_HI,
-		PCICFG_HIWORD(PCICFG_LOADDR(entry->io_last)));
+	    PCICFG_HIWORD(PCICFG_LOADDR(entry->io_last)));
 
 	/*
 	 * Program the PF memory base register with the start of
 	 * PF memory range
 	 */
 	pci_config_put16(handle, PCI_BCNF_PF_BASE_LOW,
-		PCICFG_HIWORD(PCICFG_LOADDR(entry->pf_memory_last)));
+	    PCICFG_HIWORD(PCICFG_LOADDR(entry->pf_memory_last)));
 	pci_config_put32(handle, PCI_BCNF_PF_BASE_HIGH,
-		PCICFG_HIADDR(entry->pf_memory_last));
+	    PCICFG_HIADDR(entry->pf_memory_last));
 
 	/*
 	 * Clear status bits
@@ -3288,23 +3562,20 @@
 	 */
 
 	DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
-		PCICFG_ROUND_DOWN(entry->memory_last,
-		PCICFG_MEMGRAN));
+	    PCICFG_ROUND_DOWN(entry->memory_last, PCICFG_MEMGRAN));
 
 	pci_config_put16(handle, PCI_BCNF_MEM_LIMIT,
-		PCICFG_HIWORD(PCICFG_LOADDR(
-		PCICFG_ROUND_DOWN(entry->memory_last,
-			PCICFG_MEMGRAN))));
+	    PCICFG_HIWORD(PCICFG_LOADDR(
+	    PCICFG_ROUND_DOWN(entry->memory_last, PCICFG_MEMGRAN))));
 	/*
 	 * Since this is a bridge, the rest of this range will
 	 * be responded to by the bridge.  We have to round up
 	 * so no other device claims it.
 	 */
-	if ((length = (PCICFG_ROUND_UP(entry->memory_last,
-		PCICFG_MEMGRAN) - entry->memory_last)) > 0) {
+	if ((length = (PCICFG_ROUND_UP(entry->memory_last, PCICFG_MEMGRAN)
+	    - entry->memory_last)) > 0) {
 		(void) pcicfg_get_mem(entry, length, NULL);
-		DEBUG1("Added [0x%x]at the top of "
-		"the bridge (mem)\n", length);
+		DEBUG1("Added [0x%x]at the top of the bridge (mem)\n", length);
 	}
 
 	/*
@@ -3312,35 +3583,29 @@
 	 */
 
 	DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
-		PCICFG_ROUND_DOWN(entry->pf_memory_last,
-		PCICFG_MEMGRAN));
+	    PCICFG_ROUND_DOWN(entry->pf_memory_last, PCICFG_MEMGRAN));
 
 	pci_config_put16(handle, PCI_BCNF_PF_LIMIT_LOW,
-		PCICFG_HIWORD(PCICFG_LOADDR(
-		PCICFG_ROUND_DOWN(entry->pf_memory_last,
-			PCICFG_MEMGRAN))));
-	pci_config_put32(handle, PCI_BCNF_PF_LIMIT_HIGH,
-		PCICFG_HIADDR(
-		PCICFG_ROUND_DOWN(entry->pf_memory_last,
-		PCICFG_MEMGRAN)));
-	if ((length = (PCICFG_ROUND_UP(entry->pf_memory_last,
-		PCICFG_MEMGRAN) - entry->pf_memory_last)) > 0) {
+	    PCICFG_HIWORD(PCICFG_LOADDR(PCICFG_ROUND_DOWN(
+	    entry->pf_memory_last, PCICFG_MEMGRAN))));
+	pci_config_put32(handle, PCI_BCNF_PF_LIMIT_HIGH, PCICFG_HIADDR(
+	    PCICFG_ROUND_DOWN(entry->pf_memory_last, PCICFG_MEMGRAN)));
+	if ((length = (PCICFG_ROUND_UP(entry->pf_memory_last, PCICFG_MEMGRAN)
+	    - entry->pf_memory_last)) > 0) {
 		(void) pcicfg_get_pf_mem(entry, length, NULL);
-		DEBUG1("Added [0x%x]at the top of "
-		"the bridge (PF mem)\n", length);
+		DEBUG1("Added [0x%x]at the top of the bridge (PF mem)\n",
+		    length);
 	}
 
 	/*
 	 * Program the I/O limit register with the end of the I/O range
 	 */
 	pci_config_put8(handle, PCI_BCNF_IO_LIMIT_LOW,
-		PCICFG_HIBYTE(PCICFG_LOWORD(
-		PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last,
-			PCICFG_IOGRAN)))));
-
-	pci_config_put16(handle, PCI_BCNF_IO_LIMIT_HI,
-		PCICFG_HIWORD(PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last,
-		PCICFG_IOGRAN))));
+	    PCICFG_HIBYTE(PCICFG_LOWORD(
+	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, PCICFG_IOGRAN)))));
+
+	pci_config_put16(handle, PCI_BCNF_IO_LIMIT_HI, PCICFG_HIWORD(
+	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, PCICFG_IOGRAN))));
 
 	/*
 	 * Same as above for I/O space. Since this is a
@@ -3348,23 +3613,20 @@
 	 * to by the bridge.  We have to round up so no
 	 * other device claims it.
 	 */
-	if ((length = (PCICFG_ROUND_UP(entry->io_last,
-		PCICFG_IOGRAN) - entry->io_last)) > 0) {
+	if ((length = (PCICFG_ROUND_UP(entry->io_last, PCICFG_IOGRAN)
+	    - entry->io_last)) > 0) {
 		(void) pcicfg_get_io(entry, length, NULL);
-		DEBUG1("Added [0x%x]at the top of "
-		"the bridge (I/O)\n",  length);
+		DEBUG1("Added [0x%x]at the top of the bridge (I/O)\n", length);
 	}
 }
 
 static int
-pcicfg_probe_children(dev_info_t *parent, uint_t bus,
-	uint_t device, uint_t func, uint_t *highest_bus)
+pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
+    uint_t func, uint_t *highest_bus, pcicfg_flags_t flags)
 {
 	dev_info_t		*new_child;
 	ddi_acc_handle_t	config_handle;
 	uint8_t			header_type, pcie_dev = 0;
-	int			i;
-	uint32_t		request;
 	int			ret = PCICFG_FAILURE;
 
 	/*
@@ -3374,17 +3636,16 @@
 	 */
 
 	ndi_devi_alloc_sleep(parent, DEVI_PSEUDO_NEXNAME,
-		(pnode_t)DEVI_SID_NODEID, &new_child);
-
-	if (pcicfg_add_config_reg(new_child, bus,
-		device, func) != DDI_SUCCESS) {
-		DEBUG0("pcicfg_probe_children():"
-		"Failed to add candidate REG\n");
+	    (pnode_t)DEVI_SID_NODEID, &new_child);
+
+	if (pcicfg_add_config_reg(new_child, bus, device, func)
+	    != DDI_SUCCESS) {
+		DEBUG0("pcicfg_probe_children():Failed to add candidate REG\n");
 		goto failedconfig;
 	}
 
 	if ((ret = pcicfg_config_setup(new_child, &config_handle))
-		!= PCICFG_SUCCESS) {
+	    != PCICFG_SUCCESS) {
 		if (ret == PCICFG_NODEVICE) {
 			(void) ndi_devi_free(new_child);
 			return (ret);
@@ -3410,8 +3671,8 @@
 	/*
 	 * Set 1275 properties common to all devices
 	 */
-	if (pcicfg_set_standard_props(new_child, config_handle,
-			pcie_dev) != PCICFG_SUCCESS) {
+	if (pcicfg_set_standard_props(new_child, config_handle, pcie_dev)
+	    != PCICFG_SUCCESS) {
 		DEBUG0("Failed to set standard properties\n");
 		goto failedchild;
 	}
@@ -3419,8 +3680,8 @@
 	/*
 	 * Child node properties  NOTE: Both for PCI-PCI bridge and child node
 	 */
-	if (pcicfg_set_childnode_props(new_child, config_handle,
-			pcie_dev) != PCICFG_SUCCESS) {
+	if (pcicfg_set_childnode_props(new_child, config_handle, pcie_dev)
+	    != PCICFG_SUCCESS) {
 		goto failedchild;
 	}
 
@@ -3443,8 +3704,12 @@
 
 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
 
-		DEBUG3("--Bridge found bus [0x%x] device"
-			"[0x%x] func [0x%x]\n", bus, device, func);
+		DEBUG3("--Bridge found bus [0x%x] device[0x%x] func [0x%x]\n",
+		    bus, device, func);
+
+		/* Only support read-only probe for leaf device */
+		if (flags & PCICFG_FLAG_READ_ONLY)
+			goto failedchild;
 
 		ret = pcicfg_probe_bridge(new_child, config_handle, bus,
 		    highest_bus);
@@ -3456,83 +3721,45 @@
 	} else {
 
 		DEBUG3("--Leaf device found bus [0x%x] device"
-			"[0x%x] func [0x%x]\n",
-				bus, device, func);
-
-		i = PCI_CONF_BASE0;
-
-		while (i <= PCI_CONF_BASE5) {
-
-			pci_config_put32(config_handle, i, 0xffffffff);
-
-			request = pci_config_get32(config_handle, i);
+		    "[0x%x] func [0x%x]\n", bus, device, func);
+
+		if (flags & PCICFG_FLAG_READ_ONLY) {
 			/*
-			 * If its a zero length, don't do
-			 * any programming.
+			 * with read-only probe, don't do any resource
+			 * allocation, just read the BARs and update props.
 			 */
-			if (request != 0) {
-				/*
-				 * Add to the "reg" property
-				 */
-				if (pcicfg_update_reg_prop(new_child,
-					request, i) != PCICFG_SUCCESS) {
-					goto failedchild;
-				}
-			} else {
-				DEBUG1("BASE register [0x%x] asks for "
-				"[0x0]=[0x0](32)\n", i);
-				i += 4;
-				continue;
-			}
+			ret = pcicfg_populate_props_from_bar(new_child,
+			    config_handle);
+			if (ret != PCICFG_SUCCESS)
+				goto failedchild;
 
 			/*
-			 * Increment by eight if it is 64 bit address space
+			 * now allocate the resources, just remove the
+			 * resources from the parent busra pool.
 			 */
-			if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
-				DEBUG3("BASE register [0x%x] asks for "
-				"[0x%x]=[0x%x] (64)\n",
-					i, request,
-					(~(PCI_BASE_M_ADDR_M & request))+1)
-				i += 8;
-			} else {
-				DEBUG3("BASE register [0x%x] asks for "
-				"[0x%x]=[0x%x](32)\n",
-					i, request,
-					(~(PCI_BASE_M_ADDR_M & request))+1)
-				i += 4;
+			ret = pcicfg_device_assign_readonly(new_child);
+			if (ret != PCICFG_SUCCESS) {
+				(void) pcicfg_free_device_resources(new_child);
+				goto failedchild;
 			}
-		}
-
-		/*
-		 * Get the ROM size and create register for it
-		 */
-		pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
-
-		request = pci_config_get32(config_handle, PCI_CONF_ROM);
-		/*
-		 * If its a zero length, don't do
-		 * any programming.
-		 */
-
-		if (request != 0) {
-			DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
-				PCI_CONF_ROM, request,
-				(~(PCI_BASE_ROM_ADDR_M & request))+1);
+
+		} else {
 			/*
-			 * Add to the "reg" property
+			 * update "reg" property by sizing the BARs.
 			 */
-			if (pcicfg_update_reg_prop(new_child,
-				request, PCI_CONF_ROM) != PCICFG_SUCCESS) {
+			ret = pcicfg_populate_reg_props(new_child,
+			    config_handle);
+			if (ret != PCICFG_SUCCESS)
+				goto failedchild;
+
+			/* now allocate & program the resources */
+			ret = pcicfg_device_assign(new_child);
+			if (ret != PCICFG_SUCCESS) {
+				(void) pcicfg_free_device_resources(new_child);
 				goto failedchild;
 			}
 		}
 
-		/* now allocate & program the resources */
-		ret = pcicfg_device_assign(new_child);
-		if (ret != PCICFG_SUCCESS) {
-			(void) pcicfg_free_device_resources(new_child);
-			goto failedchild;
-		}
 		(void) ndi_devi_bind_driver(new_child, 0);
 	}
 
@@ -3552,9 +3779,200 @@
 	return (ret);
 }
 
+/*
+ * Sizing the BARs and update "reg" property
+ */
+static int
+pcicfg_populate_reg_props(dev_info_t *new_child,
+    ddi_acc_handle_t config_handle)
+{
+	int		i;
+	uint32_t 	request;
+
+	i = PCI_CONF_BASE0;
+
+	while (i <= PCI_CONF_BASE5) {
+
+		pci_config_put32(config_handle, i, 0xffffffff);
+
+		request = pci_config_get32(config_handle, i);
+		/*
+		 * If its a zero length, don't do
+		 * any programming.
+		 */
+		if (request != 0) {
+			/*
+			 * Add to the "reg" property
+			 */
+			if (pcicfg_update_reg_prop(new_child,
+			    request, i) != PCICFG_SUCCESS) {
+				goto failedchild;
+			}
+		} else {
+			DEBUG1("BASE register [0x%x] asks for "
+			    "[0x0]=[0x0](32)\n", i);
+			i += 4;
+			continue;
+		}
+
+		/*
+		 * Increment by eight if it is 64 bit address space
+		 */
+		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
+			DEBUG3("BASE register [0x%x] asks for "
+			    "[0x%x]=[0x%x] (64)\n",
+			    i, request, (~(PCI_BASE_M_ADDR_M & request))+1);
+			i += 8;
+		} else {
+			DEBUG3("BASE register [0x%x] asks for "
+			    "[0x%x]=[0x%x](32)\n",
+			    i, request, (~(PCI_BASE_M_ADDR_M & request))+1);
+			i += 4;
+		}
+	}
+
+	/*
+	 * Get the ROM size and create register for it
+	 */
+	pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
+
+	request = pci_config_get32(config_handle, PCI_CONF_ROM);
+	/*
+	 * If its a zero length, don't do
+	 * any programming.
+	 */
+
+	if (request != 0) {
+		DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
+		    PCI_CONF_ROM, request,
+		    (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
+		/*
+		 * Add to the "reg" property
+		 */
+		if (pcicfg_update_reg_prop(new_child, request, PCI_CONF_ROM)
+		    != PCICFG_SUCCESS) {
+			goto failedchild;
+		}
+	}
+
+	return (PCICFG_SUCCESS);
+
+failedchild:
+	return (PCICFG_FAILURE);
+}
+
+/*
+ * Read the BARs and update properties. Used in virtual hotplug.
+ */
+static int
+pcicfg_populate_props_from_bar(dev_info_t *new_child,
+    ddi_acc_handle_t config_handle)
+{
+	uint32_t request, base, base_hi, size;
+	int i;
+
+	i = PCI_CONF_BASE0;
+
+	while (i <= PCI_CONF_BASE5) {
+		/*
+		 * determine the size of the address space
+		 */
+		base = pci_config_get32(config_handle, i);
+		pci_config_put32(config_handle, i, 0xffffffff);
+		request = pci_config_get32(config_handle, i);
+		pci_config_put32(config_handle, i, base);
+
+		/*
+		 * If its a zero length, don't do any programming.
+		 */
+		if (request != 0) {
+			/*
+			 * Add to the "reg" property
+			 */
+			if (pcicfg_update_reg_prop(new_child,
+			    request, i) != PCICFG_SUCCESS) {
+				goto failedchild;
+			}
+
+			if ((PCI_BASE_SPACE_IO & request) == 0 &&
+			    (PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
+				base_hi = pci_config_get32(config_handle, i+4);
+			} else {
+				base_hi = 0;
+			}
+			/*
+			 * Add to "assigned-addresses" property
+			 */
+			size = (~(PCI_BASE_M_ADDR_M & request))+1;
+			if (pcicfg_update_assigned_prop_value(new_child,
+			    size, base, base_hi, i) != PCICFG_SUCCESS) {
+				goto failedchild;
+			}
+		} else {
+			DEBUG1("BASE register [0x%x] asks for [0x0]=[0x0]"
+			    "(32)\n", i);
+			i += 4;
+			continue;
+		}
+
+		/*
+		 * Increment by eight if it is 64 bit address space
+		 */
+		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
+			DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]"
+			    "(64)\n", i, request,
+			    (~(PCI_BASE_M_ADDR_M & request)) + 1);
+			i += 8;
+		} else {
+			DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]"
+			    "(32)\n", i, request,
+			    (~(PCI_BASE_M_ADDR_M & request)) + 1);
+			i += 4;
+		}
+	}
+
+	/*
+	 * Get the ROM size and create register for it
+	 */
+	base = pci_config_get32(config_handle, PCI_CONF_ROM);
+	pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
+	request = pci_config_get32(config_handle, PCI_CONF_ROM);
+	pci_config_put32(config_handle, PCI_CONF_ROM, base);
+
+	/*
+	 * If its a zero length, don't do
+	 * any programming.
+	 */
+	if (request != 0) {
+		DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
+		    PCI_CONF_ROM, request,
+		    (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
+		/*
+		 * Add to the "reg" property
+		 */
+		if (pcicfg_update_reg_prop(new_child, request, PCI_CONF_ROM)
+		    != PCICFG_SUCCESS) {
+			goto failedchild;
+		}
+		/*
+		 * Add to "assigned-addresses" property
+		 */
+		size = (~(PCI_BASE_ROM_ADDR_M & request))+1;
+		if (pcicfg_update_assigned_prop_value(new_child, size,
+		    base, 0, PCI_CONF_ROM) != PCICFG_SUCCESS) {
+			goto failedchild;
+		}
+	}
+
+	return (PCICFG_SUCCESS);
+
+failedchild:
+	return (PCICFG_FAILURE);
+}
+
 static int
 pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
-			uint_t *highest_bus)
+    uint_t *highest_bus)
 {
 	uint64_t next_bus;
 	uint_t new_bus, num_slots;
@@ -3573,15 +3991,37 @@
 	uint64_t max_bus;
 	uint8_t pcie_device_type = 0;
 	uint_t pf_mem_supported = 0;
+	dev_info_t *new_device;
+	int trans_device;
+	int ari_mode = B_FALSE;
+	int max_function = PCI_MAX_FUNCTIONS;
 
 	io_answer = io_base = io_alen = io_size = 0;
 	pf_mem_answer = pf_mem_base = pf_mem_size = pf_mem_alen = 0;
 
 	/*
+	 * Set "device_type" to "pci", the actual type will be set later
+	 * by pcicfg_set_busnode_props() below. This is needed as the
+	 * pcicfg_ra_free() below would update "available" property based
+	 * on "device_type".
+	 *
+	 * This code can be removed later after PCI configurator is changed
+	 * to use PCIRM, which automatically update properties upon allocation
+	 * and free, at that time we'll be able to remove the code inside
+	 * ndi_ra_alloc/free() which currently updates "available" property
+	 * for pci/pcie devices in pcie fabric.
+	 */
+	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
+	    "device_type", "pci") != DDI_SUCCESS) {
+		DEBUG0("Failed to set \"device_type\" props\n");
+		return (PCICFG_FAILURE);
+	}
+
+	/*
 	 * setup resource maps for the bridge node
 	 */
 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_BUSNUM)
-				== NDI_FAILURE) {
+	    == NDI_FAILURE) {
 		DEBUG0("Can not setup resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
 		rval = PCICFG_FAILURE;
 		goto cleanup;
@@ -3597,9 +4037,9 @@
 		goto cleanup;
 	}
 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_PREFETCH_MEM) ==
-		NDI_FAILURE) {
+	    NDI_FAILURE) {
 		DEBUG0("Can not setup resource map -"
-		" NDI_RA_TYPE_PCI_PREFETCH_MEM\n");
+		    " NDI_RA_TYPE_PCI_PREFETCH_MEM\n");
 		rval = PCICFG_FAILURE;
 		goto cleanup;
 	}
@@ -3629,7 +4069,7 @@
 	}
 
 	DEBUG2("Bus Range Allocated [base=%d] [len=%d]\n",
-			pcibus_base, pcibus_alen);
+	    pcibus_base, pcibus_alen);
 
 	/*
 	 * Put available bus range into the pool.
@@ -3637,7 +4077,7 @@
 	 * to child.
 	 */
 	(void) ndi_ra_free(new_child, pcibus_base+1, pcibus_alen-1,
-				NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
+	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
 
 	next_bus = pcibus_base;
 	max_bus = pcibus_base + pcibus_alen - 1;
@@ -3967,7 +4407,7 @@
 	 * Set bus properties
 	 */
 	if (pcicfg_set_busnode_props(new_child, pcie_device_type)
-				!= PCICFG_SUCCESS) {
+	    != PCICFG_SUCCESS) {
 		DEBUG0("Failed to set busnode props\n");
 		rval = PCICFG_FAILURE;
 		goto cleanup;
@@ -3996,24 +4436,78 @@
 	 */
 	DEBUG0("Bridge Programming Complete - probe children\n");
 	ndi_devi_enter(new_child, &count);
-	for (i = 0; i < PCI_MAX_DEVICES; i++) {
-		for (j = 0; j < PCI_MAX_FUNCTIONS; j++) {
+	for (i = 0; ((i < PCI_MAX_DEVICES) && (ari_mode == B_FALSE));
+	    i++) {
+		for (j = 0; j < max_function; ) {
+			if (ari_mode)
+				trans_device = j >> 3;
+			else
+				trans_device = i;
+
 			if ((rval = pcicfg_probe_children(new_child,
-					new_bus, i, j, highest_bus))
-							!= PCICFG_SUCCESS) {
+			    new_bus, trans_device, j & 7, highest_bus, 0))
+			    != PCICFG_SUCCESS) {
 				if (rval == PCICFG_NODEVICE) {
 					DEBUG3("No Device at bus [0x%x]"
-						"device [0x%x] "
-						"func [0x%x]\n", new_bus, i, j);
+					    "device [0x%x] "
+					    "func [0x%x]\n", new_bus,
+					    trans_device, j & 7);
+
 					if (j)
-						continue;
+						goto next;
 				} else
 					/*EMPTY*/
 					DEBUG3("Failed to configure bus "
-						"[0x%x] device [0x%x] "
-						"func [0x%x]\n", new_bus, i, j);
+					    "[0x%x] device [0x%x] "
+					    "func [0x%x]\n", new_bus,
+					    trans_device, j & 7);
 				break;
 			}
+next:
+			new_device = pcicfg_devi_find(new_child, trans_device,
+			    (j & 7));
+
+			/*
+			 * Determine if ARI Forwarding should be enabled.
+			 */
+			if (j == 0) {
+				if (new_device == NULL)
+					break;
+
+				if ((pcie_ari_supported(new_child) ==
+				    PCIE_ARI_FORW_SUPPORTED) &&
+				    (pcie_ari_device(new_device) ==
+				    PCIE_ARI_DEVICE)) {
+					if (pcie_ari_enable(new_child) ==
+					    DDI_SUCCESS) {
+						(void) ddi_prop_create(
+						    DDI_DEV_T_NONE,
+						    new_child,
+						    DDI_PROP_CANSLEEP,
+						    "ari-enabled", NULL, 0);
+						ari_mode = B_TRUE;
+						max_function =
+						    PCICFG_MAX_ARI_FUNCTION;
+					}
+				}
+			}
+			if (ari_mode == B_TRUE) {
+				int next_function;
+
+				if (new_device == NULL)
+					break;
+
+				if (pcie_ari_get_next_function(new_device,
+				    &next_function) != DDI_SUCCESS)
+					break;
+
+				j = next_function;
+
+				if (next_function == 0)
+					break;
+			} else
+				j++;
+
 		}
 		/* if any function fails to be configured, no need to proceed */
 		if (rval != PCICFG_NODEVICE)
@@ -4023,8 +4517,15 @@
 
 	/*
 	 * Offline the bridge to allow reprogramming of resources.
+	 *
+	 * This should always succeed since nobody else has started to
+	 * use it yet, failing to detach the driver would indicate a bug.
+	 * Also in that case it's better just panic than allowing the
+	 * configurator to proceed with BAR reprogramming without bridge
+	 * driver detached.
 	 */
-	(void) ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG);
+	VERIFY(ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG)
+	    == NDI_SUCCESS);
 
 	phdl.dip = new_child;
 	phdl.memory_base = mem_answer;
@@ -4041,24 +4542,34 @@
 	io_end = PCICFG_ROUND_UP(phdl.io_base, PCICFG_IOGRAN);
 	pf_mem_end = PCICFG_ROUND_UP(phdl.pf_memory_base, PCICFG_MEMGRAN);
 
-	DEBUG4("Start of Unallocated Bridge(%d slots) Resources "
-		"Mem=0x%lx I/O=0x%lx PF_mem=%x%lx\n", num_slots, mem_end,
-		io_end, pf_mem_end);
-
+	DEBUG4("Start of Unallocated Bridge(%d slots) Resources Mem=0x%lx "
+	    "I/O=0x%lx PF_mem=%x%lx\n", num_slots, mem_end, io_end, pf_mem_end);
+
+	/*
+	 * Before probing the children we've allocated maximum MEM/IO
+	 * resources from parent, and updated "available" property
+	 * accordingly. Later we'll be giving up unused resources to
+	 * the parent, thus we need to destroy "available" property
+	 * here otherwise it will be out-of-sync with the actual free
+	 * resources this bridge has. This property will be rebuilt below
+	 * with the actual free resources reserved for hotplug slots
+	 * (if any).
+	 */
+	(void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "available");
 	/*
 	 * if the bridge a slots, then preallocate. If not, assume static
 	 * configuration. Also check for preallocation limits and spit
 	 * warning messages appropriately (perhaps some can be in debug mode).
 	 */
 	if (num_slots) {
-		uint64_t mem_reqd = mem_answer + (num_slots *
-						pcicfg_slot_memsize);
-		uint64_t io_reqd = io_answer + (num_slots *
-						pcicfg_slot_iosize);
-		uint64_t pf_mem_reqd = pf_mem_answer + (num_slots *
-						pcicfg_slot_pf_memsize);
-		uint8_t highest_bus_reqd = new_bus + (num_slots *
-						pcicfg_slot_busnums);
+		uint64_t mem_reqd = mem_answer +
+		    (num_slots * pcicfg_slot_memsize);
+		uint64_t io_reqd = io_answer +
+		    (num_slots * pcicfg_slot_iosize);
+		uint64_t pf_mem_reqd = pf_mem_answer +
+		    (num_slots * pcicfg_slot_pf_memsize);
+		uint8_t highest_bus_reqd = new_bus +
+		    (num_slots * pcicfg_slot_busnums);
 #ifdef DEBUG
 		if (mem_end > mem_reqd)
 			DEBUG3("Memory space consumed by bridge more "
@@ -4095,23 +4606,22 @@
 			    num_slots, new_bus, *highest_bus);
 #endif
 		mem_end = MAX((MIN(mem_reqd, (mem_answer + mem_alen))),
-								mem_end);
+		    mem_end);
 		io_end = MAX((MIN(io_reqd, (io_answer + io_alen))), io_end);
 		pf_mem_end = MAX((MIN(pf_mem_reqd, (pf_mem_answer +
-				pf_mem_alen))), pf_mem_end);
+		    pf_mem_alen))), pf_mem_end);
 		*highest_bus = MAX((MIN(highest_bus_reqd, max_bus)),
-							*highest_bus);
+		    *highest_bus);
 		DEBUG4("mem_end %lx, io_end %lx, pf_mem_end %lx"
-				" highest_bus %x\n", mem_end, io_end,
-				pf_mem_end, *highest_bus);
+		    " highest_bus %x\n", mem_end, io_end, pf_mem_end,
+		    *highest_bus);
 	}
 
 	/*
 	 * Give back unused memory space to parent.
 	 */
-	(void) ndi_ra_free(ddi_get_parent(new_child),
-	    mem_end, (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM,
-		NDI_RA_PASS);
+	(void) ndi_ra_free(ddi_get_parent(new_child), mem_end,
+	    (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM, NDI_RA_PASS);
 
 	if (mem_end == mem_answer) {
 		DEBUG0("No memory resources used\n");
@@ -4172,33 +4682,33 @@
 	 * Give back unused PF memory space to parent.
 	 */
 	if (pf_mem_supported) {
-	    (void) ndi_ra_free(ddi_get_parent(new_child),
-		pf_mem_end, (pf_mem_answer + pf_mem_alen) - pf_mem_end,
-		NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
-
-	    if (pf_mem_end == pf_mem_answer) {
-		DEBUG0("No PF memory resources used\n");
-		/*
-		 * To prevent the bridge from forwarding any PF Memory
-		 * transactions, the PF Memory Limit will be programmed
-		 * with a smaller value than the Memory Base.
-		 */
-		pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0xfff0);
-		pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
-		pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW, 0);
-		pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH, 0);
-
-		pf_mem_size = 0;
-	    } else {
-		/*
-		 * Reprogram the end of the PF memory range.
-		 */
-		pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW,
-		    PCICFG_HIWORD(PCICFG_LOADDR(pf_mem_end - 1)));
-		pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH,
-		    PCICFG_HIADDR(pf_mem_end - 1));
-		pf_mem_size = pf_mem_end - pf_mem_base;
-	    }
+		(void) ndi_ra_free(ddi_get_parent(new_child),
+		    pf_mem_end, (pf_mem_answer + pf_mem_alen) - pf_mem_end,
+		    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
+
+		if (pf_mem_end == pf_mem_answer) {
+			DEBUG0("No PF memory resources used\n");
+			/*
+			 * To prevent the bridge from forwarding any PF Memory
+			 * transactions, the PF Memory Limit will be programmed
+			 * with a smaller value than the Memory Base.
+			 */
+			pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0xfff0);
+			pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
+			pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW, 0);
+			pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH, 0);
+
+			pf_mem_size = 0;
+		} else {
+			/*
+			 * Reprogram the end of the PF memory range.
+			 */
+			pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW,
+			    PCICFG_HIWORD(PCICFG_LOADDR(pf_mem_end - 1)));
+			pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH,
+			    PCICFG_HIADDR(pf_mem_end - 1));
+			pf_mem_size = pf_mem_end - pf_mem_base;
+		}
 	}
 
 	if ((max_bus - *highest_bus) > 0) {
@@ -4206,8 +4716,8 @@
 		 * Give back unused bus numbers
 		 */
 		(void) ndi_ra_free(ddi_get_parent(new_child),
-				*highest_bus+1, max_bus - *highest_bus,
-				NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
+		    *highest_bus+1, max_bus - *highest_bus,
+		    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
 	}
 
 	/*
@@ -4268,18 +4778,20 @@
 cleanup:
 	/* free up resources (for error return case only) */
 	if (rval != PCICFG_SUCCESS) {
-	    if (mem_alen)
-		(void) ndi_ra_free(ddi_get_parent(new_child), mem_base,
-		    mem_alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
-	    if (io_alen)
-		(void) ndi_ra_free(ddi_get_parent(new_child), io_base,
-		    io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
-	    if (pf_mem_alen)
-		(void) ndi_ra_free(ddi_get_parent(new_child), pf_mem_base,
-		    pf_mem_alen, NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
-	    if (pcibus_alen)
-		(void) ndi_ra_free(ddi_get_parent(new_child), pcibus_base,
-		    pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
+		if (mem_alen)
+			(void) ndi_ra_free(ddi_get_parent(new_child), mem_base,
+			    mem_alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
+		if (io_alen)
+			(void) ndi_ra_free(ddi_get_parent(new_child), io_base,
+			    io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
+		if (pf_mem_alen)
+			(void) ndi_ra_free(ddi_get_parent(new_child),
+			    pf_mem_base, pf_mem_alen,
+			    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
+		if (pcibus_alen)
+			(void) ndi_ra_free(ddi_get_parent(new_child),
+			    pcibus_base, pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM,
+			    NDI_RA_PASS);
 	}
 
 	/* free up any resource maps setup for the bridge node */
@@ -4320,47 +4832,51 @@
 			switch (PCI_REG_ADDR_G(pci_ap[i].pci_phys_hi)) {
 
 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
-			    if (pci_ap[i].pci_phys_hi & PCI_REG_PF_M) {
-				if ((pci_ap[i].pci_phys_low +
-				    pci_ap[i].pci_size_low) >
-				    entry->pf_memory_base) {
-					entry->pf_memory_base =
-					    pci_ap[i].pci_phys_low +
-					    pci_ap[i].pci_size_low;
+				if (pci_ap[i].pci_phys_hi & PCI_REG_PF_M) {
+					if ((pci_ap[i].pci_phys_low +
+					    pci_ap[i].pci_size_low) >
+					    entry->pf_memory_base) {
+						entry->pf_memory_base =
+						    pci_ap[i].pci_phys_low +
+						    pci_ap[i].pci_size_low;
+					}
+				} else {
+					if ((pci_ap[i].pci_phys_low +
+					    pci_ap[i].pci_size_low) >
+					    entry->memory_base) {
+						entry->memory_base =
+						    pci_ap[i].pci_phys_low +
+						    pci_ap[i].pci_size_low;
+					}
 				}
-			    } else {
-				if ((pci_ap[i].pci_phys_low +
-				    pci_ap[i].pci_size_low) >
-				    entry->memory_base) {
-					entry->memory_base =
-					    pci_ap[i].pci_phys_low +
-					    pci_ap[i].pci_size_low;
-				}
-			    }
-			break;
+				break;
 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
-			    if (pci_ap[i].pci_phys_hi & PCI_REG_PF_M) {
-				if ((PCICFG_LADDR(pci_ap[i].pci_phys_low,
-				    pci_ap[i].pci_phys_mid) +
-				    pci_ap[i].pci_size_low) >
-				    entry->pf_memory_base) {
-					entry->pf_memory_base = PCICFG_LADDR(
+				if (pci_ap[i].pci_phys_hi & PCI_REG_PF_M) {
+					if ((PCICFG_LADDR(
 					    pci_ap[i].pci_phys_low,
 					    pci_ap[i].pci_phys_mid) +
-					    pci_ap[i].pci_size_low;
-				}
-			    } else {
-				if ((PCICFG_LADDR(pci_ap[i].pci_phys_low,
-				    pci_ap[i].pci_phys_mid) +
-				    pci_ap[i].pci_size_low) >
-				    entry->memory_base) {
-					entry->memory_base = PCICFG_LADDR(
+					    pci_ap[i].pci_size_low) >
+					    entry->pf_memory_base) {
+						entry->pf_memory_base =
+						    PCICFG_LADDR(
+						    pci_ap[i].pci_phys_low,
+						    pci_ap[i].pci_phys_mid) +
+						    pci_ap[i].pci_size_low;
+					}
+				} else {
+					if ((PCICFG_LADDR(
 					    pci_ap[i].pci_phys_low,
 					    pci_ap[i].pci_phys_mid) +
-					    pci_ap[i].pci_size_low;
+					    pci_ap[i].pci_size_low) >
+					    entry->memory_base) {
+						entry->memory_base =
+						    PCICFG_LADDR(
+						    pci_ap[i].pci_phys_low,
+						    pci_ap[i].pci_phys_mid) +
+						    pci_ap[i].pci_size_low;
+					}
 				}
-			    }
-			break;
+				break;
 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
 				if ((pci_ap[i].pci_phys_low +
 				    pci_ap[i].pci_size_low) >
@@ -4369,7 +4885,7 @@
 					    pci_ap[i].pci_phys_low +
 					    pci_ap[i].pci_size_low;
 				}
-			break;
+				break;
 			}
 		}
 
@@ -4427,12 +4943,12 @@
 	/*
 	 * Get the pci register spec from the node
 	 */
-	status = ddi_getlongprop(DDI_DEV_T_ANY,
-		dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
+	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
+	    (caddr_t)&reg, &rlen);
 
 	switch (status) {
 		case DDI_PROP_SUCCESS:
-		break;
+			break;
 		case DDI_PROP_NO_MEMORY:
 			DEBUG0("reg present, but unable to get memory\n");
 			return (PCICFG_FAILURE);
@@ -4448,8 +4964,8 @@
 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
 
-	if (ddi_regs_map_setup(anode, 0, &cfgaddr,
-		0, 0, &attr, handle) != DDI_SUCCESS) {
+	if (ddi_regs_map_setup(anode, 0, &cfgaddr, 0, 0, &attr, handle)
+	    != DDI_SUCCESS) {
 		DEBUG0("Failed to setup registers\n");
 		kmem_free((caddr_t)reg, rlen);
 		return (PCICFG_FAILURE);
@@ -4495,10 +5011,23 @@
 
 	reg[0] = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
 
-	return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
-		"reg", reg, 5));
+	return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg", reg, 5));
 }
 
+static int
+pcicfg_ari_configure(dev_info_t *dip)
+{
+	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
+		return (DDI_FAILURE);
+
+	/*
+	 * Until we have resource balancing, dynamically configure
+	 * ARI functions without firmware assistamce.
+	 */
+	return (DDI_FAILURE);
+}
+
+
 #ifdef DEBUG
 static void
 debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
@@ -4522,9 +5051,8 @@
 	(void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_id_loc);
 	(void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &slot_id_loc);
 	if (cap_id_loc != PCI_CAP_NEXT_PTR_NULL) {
-		if (pci_config_get8(handle, cap_id_loc +
-					PCI_CAP_ID_REGS_OFF) &
-					PCIE_PCIECAP_SLOT_IMPL)
+		if (pci_config_get8(handle, cap_id_loc + PCI_CAP_ID_REGS_OFF) &
+		    PCIE_PCIECAP_SLOT_IMPL)
 			num_slots = 1;
 	} else /* not a PCIe switch/bridge. Must be a PCI-PCI[-X] bridge */
 	if (slot_id_loc != PCI_CAP_NEXT_PTR_NULL) {
@@ -4544,11 +5072,10 @@
 	int val;
 	dev_info_t *pdip = ddi_get_parent(dip);
 
-	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
-		DDI_PROP_DONTPASS, "device_type", &device_type)
-				!= DDI_PROP_SUCCESS) {
+	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
+	    "device_type", &device_type) != DDI_PROP_SUCCESS) {
 		DEBUG2("device_type property missing for %s#%d",
-			ddi_get_name(pdip), ddi_get_instance(pdip));
+		    ddi_get_name(pdip), ddi_get_instance(pdip));
 		return (DDI_FAILURE);
 	}
 	DEBUG1("device_type=<%s>\n", device_type);
@@ -4572,9 +5099,9 @@
 
 	/* check for all PCIe device_types */
 	if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) ||
-			(port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
-			(port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
-			(port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
+	    (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
+	    (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
+	    (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
 		return (DDI_SUCCESS);
 
 	return (DDI_FAILURE);
@@ -4592,7 +5119,7 @@
 	(void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_loc);
 	if (cap_loc != PCI_CAP_NEXT_PTR_NULL)
 		port_type = pci_config_get16(handle,
-			cap_loc + PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
+		    cap_loc + PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
 
 	return (port_type);
 }
--- a/usr/src/uts/intel/io/hotplug/pciehpc/pciehpc_acpi.c	Sun Nov 01 14:14:46 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,684 +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.
- */
-
-/*
- * ACPI interface related functions used in PCIEHPC driver module.
- */
-
-#include <sys/note.h>
-#include <sys/conf.h>
-#include <sys/kmem.h>
-#include <sys/debug.h>
-#include <sys/vtrace.h>
-#include <sys/varargs.h>
-#include <sys/ddi_impldefs.h>
-#include <sys/pci.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-#include <sys/pcie_acpi.h>
-#include "pciehpc_acpi.h"
-
-/* local static functions */
-static int pciehpc_acpi_hpc_init(pciehpc_t *ctrl_p);
-static int pciehpc_acpi_hpc_uninit(pciehpc_t *ctrl_p);
-static int pciehpc_acpi_slotinfo_init(pciehpc_t *ctrl_p);
-static int pciehpc_acpi_slotinfo_uninit(pciehpc_t *ctrl_p);
-static int pciehpc_acpi_enable_intr(pciehpc_t *ctrl_p);
-static int pciehpc_acpi_disable_intr(pciehpc_t *ctrl_p);
-static int pciehpc_acpi_slot_connect(caddr_t ops_arg, hpc_slot_t slot_hdl,
-	void *data, uint_t flags);
-static int pciehpc_acpi_slot_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl,
-	void *data, uint_t flags);
-static void pciehpc_acpi_setup_ops(pciehpc_t *ctrl_p);
-
-static ACPI_STATUS pciehpc_acpi_install_event_handler(pciehpc_t *ctrl_p);
-static void pciehpc_acpi_uninstall_event_handler(pciehpc_t *ctrl_p);
-static ACPI_STATUS pciehpc_acpi_power_on_slot(pciehpc_t *ctrl_p);
-static ACPI_STATUS pciehpc_acpi_power_off_slot(pciehpc_t *ctrl_p);
-static void pciehpc_acpi_notify_handler(ACPI_HANDLE device, uint32_t val,
-	void *context);
-static ACPI_STATUS pciehpc_acpi_ej0_present(ACPI_HANDLE pcibus_obj);
-static ACPI_STATUS pciehpc_acpi_get_dev_state(ACPI_HANDLE obj, int *statusp);
-
-/*
- * Update ops vector with platform specific (ACPI, CK8-04,...) functions.
- */
-void
-pciehpc_update_ops(pciehpc_t *ctrl_p)
-{
-	boolean_t hp_native_mode = B_FALSE;
-	uint32_t osc_flags = OSC_CONTROL_PCIE_NAT_HP;
-
-	/*
-	 * Call _OSC method to determine if hotplug mode is native or ACPI.
-	 * If _OSC method succeeds hp_native_mode below will be set according to
-	 * if native hotplug control was granted or not by BIOS.
-	 *
-	 * If _OSC method fails for any reason or if native hotplug control was
-	 * not granted assume it's ACPI mode and update platform specific
-	 * (ACPI, CK8-04,...) impl. ops
-	 */
-
-	if (pcie_acpi_osc(ctrl_p->dip, &osc_flags) == DDI_SUCCESS) {
-		hp_native_mode = (osc_flags & OSC_CONTROL_PCIE_NAT_HP) ?
-		    B_TRUE : B_FALSE;
-	}
-
-	if (!hp_native_mode) {
-		/* update ops vector for ACPI mode */
-		pciehpc_acpi_setup_ops(ctrl_p);
-		ctrl_p->hp_mode = PCIEHPC_ACPI_HP_MODE;
-	}
-}
-
-static void
-pciehpc_acpi_setup_ops(pciehpc_t *ctrl_p)
-{
-	ctrl_p->ops.init_hpc_hw = pciehpc_acpi_hpc_init;
-	ctrl_p->ops.init_hpc_slotinfo = pciehpc_acpi_slotinfo_init;
-	ctrl_p->ops.disable_hpc_intr = pciehpc_acpi_disable_intr;
-	ctrl_p->ops.enable_hpc_intr = pciehpc_acpi_enable_intr;
-	ctrl_p->ops.uninit_hpc_hw = pciehpc_acpi_hpc_uninit;
-	ctrl_p->ops.uninit_hpc_slotinfo = pciehpc_acpi_slotinfo_uninit;
-}
-
-/*
- * Intialize hot plug control for ACPI mode.
- */
-static int
-pciehpc_acpi_hpc_init(pciehpc_t *ctrl_p)
-{
-	ACPI_HANDLE pcibus_obj;
-	int status = AE_ERROR;
-	ACPI_HANDLE slot_dev_obj;
-	ACPI_HANDLE hdl;
-	pciehpc_acpi_t *acpi_p;
-	uint16_t bus_methods = 0;
-	uint16_t slot_methods = 0;
-
-	/* get the ACPI object for the bus node */
-	status = acpica_get_handle(ctrl_p->dip, &pcibus_obj);
-	if (status != AE_OK)
-		return (DDI_FAILURE);
-
-	/* get the ACPI object handle for the child node */
-	status = AcpiGetNextObject(ACPI_TYPE_DEVICE, pcibus_obj,
-	    NULL, &slot_dev_obj);
-	if (status != AE_OK)
-		return (DDI_FAILURE);
-
-	/*
-	 * gather the info about the ACPI methods present on the bus node
-	 * and the child nodes.
-	 */
-	if (AcpiGetHandle(pcibus_obj, "_OSC", &hdl) == AE_OK)
-		bus_methods |= PCIEHPC_ACPI_OSC_PRESENT;
-	if (AcpiGetHandle(pcibus_obj, "_OSHP", &hdl) == AE_OK)
-		bus_methods |= PCIEHPC_ACPI_OSHP_PRESENT;
-	if (AcpiGetHandle(pcibus_obj, "_HPX", &hdl) == AE_OK)
-		bus_methods |= PCIEHPC_ACPI_HPX_PRESENT;
-	if (AcpiGetHandle(pcibus_obj, "_HPP", &hdl) == AE_OK)
-		bus_methods |= PCIEHPC_ACPI_HPP_PRESENT;
-	if (AcpiGetHandle(pcibus_obj, "_DSM", &hdl) == AE_OK)
-		bus_methods |= PCIEHPC_ACPI_DSM_PRESENT;
-	if (AcpiGetHandle(slot_dev_obj, "_SUN", &hdl) == AE_OK)
-		slot_methods |= PCIEHPC_ACPI_SUN_PRESENT;
-	if (AcpiGetHandle(slot_dev_obj, "_PS0", &hdl) == AE_OK)
-		slot_methods |= PCIEHPC_ACPI_PS0_PRESENT;
-	if (AcpiGetHandle(slot_dev_obj, "_EJ0", &hdl) == AE_OK)
-		slot_methods |= PCIEHPC_ACPI_EJ0_PRESENT;
-	if (AcpiGetHandle(slot_dev_obj, "_STA", &hdl) == AE_OK)
-		slot_methods |= PCIEHPC_ACPI_STA_PRESENT;
-
-	/* save ACPI object handles, etc. */
-	acpi_p = kmem_zalloc(sizeof (pciehpc_acpi_t), KM_SLEEP);
-	acpi_p->bus_obj = pcibus_obj;
-	acpi_p->slot_dev_obj = slot_dev_obj;
-	acpi_p->bus_methods = bus_methods;
-	acpi_p->slot_methods = slot_methods;
-	ctrl_p->misc_data = acpi_p;
-	ctrl_p->hp_mode = PCIEHPC_ACPI_HP_MODE;
-
-	/* initialize the slot mutex */
-	mutex_init(&ctrl_p->pciehpc_mutex, NULL, MUTEX_DRIVER,
-	    (void *)PCIEHPC_INTR_PRI);
-
-	return (DDI_SUCCESS);
-}
-
-/*
- * Uninitialize HPC.
- */
-static int
-pciehpc_acpi_hpc_uninit(pciehpc_t *ctrl_p)
-{
-	/* free up buffer used for misc_data */
-	if (ctrl_p->misc_data) {
-		kmem_free(ctrl_p->misc_data, sizeof (pciehpc_acpi_t));
-		ctrl_p->misc_data = NULL;
-	}
-
-	/* destroy the mutex */
-	mutex_destroy(&ctrl_p->pciehpc_mutex);
-
-	return (DDI_SUCCESS);
-}
-
-/*
- * Enable interrupts. For ACPI hot plug this is a NOP.
- * Just return DDI_SUCCESS.
- */
-/*ARGSUSED*/
-static int
-pciehpc_acpi_enable_intr(pciehpc_t *ctrl_p)
-{
-	return (DDI_SUCCESS);
-}
-
-/*
- * Disable interrupts. For ACPI hot plug this is a NOP.
- * Just return DDI_SUCCESS.
- */
-/*ARGSUSED*/
-static int
-pciehpc_acpi_disable_intr(pciehpc_t *ctrl_p)
-{
-	return (DDI_SUCCESS);
-}
-
-/*
- * This function is similar to pciehpc_slotinfo_init() with some
- * changes:
- *	- no need for kernel thread to handle ATTN button events
- *	- function ops for connect/disconnect are different
- *
- * ASSUMPTION: No conflict in doing reads to HP registers directly.
- * Otherwise, there are no ACPI interfaces to do LED control or to get
- * the hot plug capabilities (ATTN button, MRL, etc.).
- */
-static int
-pciehpc_acpi_slotinfo_init(pciehpc_t *ctrl_p)
-{
-	uint32_t slot_capabilities;
-	pciehpc_slot_t *p = &ctrl_p->slot;
-
-	/*
-	 * setup HPS framework slot ops structure
-	 */
-	p->slot_ops.hpc_version = HPC_SLOT_OPS_VERSION;
-	p->slot_ops.hpc_op_connect = pciehpc_acpi_slot_connect;
-	p->slot_ops.hpc_op_disconnect = pciehpc_acpi_slot_disconnect;
-	p->slot_ops.hpc_op_insert = NULL;
-	p->slot_ops.hpc_op_remove = NULL;
-	p->slot_ops.hpc_op_control = pciehpc_slot_control;
-
-	/*
-	 * setup HPS framework slot information structure
-	 */
-	p->slot_info.version = HPC_SLOT_OPS_VERSION;
-	p->slot_info.slot_type = HPC_SLOT_TYPE_PCIE;
-	p->slot_info.slot_flags =
-	    HPC_SLOT_CREATE_DEVLINK | HPC_SLOT_NO_AUTO_ENABLE;
-	p->slot_info.pci_slot_capabilities = HPC_SLOT_64BITS;
-	/* the device number is fixed as 0 as per the spec  */
-	p->slot_info.pci_dev_num = 0;
-
-	/* read Slot Capabilities Register */
-	slot_capabilities = pciehpc_reg_get32(ctrl_p,
-	    ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCAP);
-
-	/* setup slot number/name */
-	pciehpc_set_slot_name(ctrl_p);
-
-	/* check if Attn Button present */
-	ctrl_p->has_attn = (slot_capabilities & PCIE_SLOTCAP_ATTN_BUTTON) ?
-	    B_TRUE : B_FALSE;
-
-	/* check if Manual Retention Latch sensor present */
-	ctrl_p->has_mrl = (slot_capabilities & PCIE_SLOTCAP_MRL_SENSOR) ?
-	    B_TRUE : B_FALSE;
-
-	/*
-	 * PCI-E (draft) version 1.1 defines EMI Lock Present bit
-	 * in Slot Capabilities register. Check for it.
-	 */
-	ctrl_p->has_emi_lock = (slot_capabilities &
-	    PCIE_SLOTCAP_EMI_LOCK_PRESENT) ? B_TRUE : B_FALSE;
-
-	/* initialize synchronization conditional variable */
-	cv_init(&ctrl_p->slot.cmd_comp_cv, NULL, CV_DRIVER, NULL);
-	ctrl_p->slot.command_pending = B_FALSE;
-
-	/* get current slot state from the hw */
-	pciehpc_get_slot_state(ctrl_p);
-
-	/* setup Notify() handler for hot plug events from ACPI BIOS */
-	if (pciehpc_acpi_install_event_handler(ctrl_p) != AE_OK)
-		return (DDI_FAILURE);
-
-	PCIEHPC_DEBUG((CE_NOTE, "ACPI hot plug is enabled for slot #%d\n",
-	    ctrl_p->slot.slotNum));
-
-	return (DDI_SUCCESS);
-}
-
-/*
- * This function is similar to pciehcp_slotinfo_uninit() but has ACPI
- * specific cleanup.
- */
-static int
-pciehpc_acpi_slotinfo_uninit(pciehpc_t *ctrl_p)
-{
-	/* uninstall Notify() event handler */
-	pciehpc_acpi_uninstall_event_handler(ctrl_p);
-
-	cv_destroy(&ctrl_p->slot.cmd_comp_cv);
-
-	return (DDI_SUCCESS);
-}
-
-/*
- * This function is same as pciehpc_slot_connect() except that it
- * uses ACPI method PS0 to enable power to the slot. If no PS0 method
- * is present then it returns HPC_ERR_FAILED.
- */
-/*ARGSUSED*/
-static int
-pciehpc_acpi_slot_connect(caddr_t ops_arg, hpc_slot_t slot_hdl,
-	void *data, uint_t flags)
-{
-	uint16_t status;
-	uint16_t control;
-
-	pciehpc_t *ctrl_p = (pciehpc_t *)ops_arg;
-
-	ASSERT(slot_hdl == ctrl_p->slot.slot_handle);
-
-	mutex_enter(&ctrl_p->pciehpc_mutex);
-
-	/* get the current state of the slot */
-	pciehpc_get_slot_state(ctrl_p);
-
-	/* check if the slot is already in the 'connected' state */
-	if (ctrl_p->slot.slot_state == HPC_SLOT_CONNECTED) {
-		/* slot is already in the 'connected' state */
-		PCIEHPC_DEBUG((CE_NOTE, "slot %d already connected\n",
-		    ctrl_p->slot.slotNum));
-		mutex_exit(&ctrl_p->pciehpc_mutex);
-		return (HPC_SUCCESS);
-	}
-
-	/* read the Slot Status Register */
-	status =  pciehpc_reg_get16(ctrl_p,
-	    ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS);
-
-	/* make sure the MRL switch is closed if present */
-	if ((ctrl_p->has_mrl) && (status & PCIE_SLOTSTS_MRL_SENSOR_OPEN)) {
-		/* MRL switch is open */
-		cmn_err(CE_WARN, "MRL switch is open on slot %d",
-		    ctrl_p->slot.slotNum);
-		goto cleanup;
-	}
-
-	/* make sure the slot has a device present */
-	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
-		/* slot is empty */
-		PCIEHPC_DEBUG((CE_NOTE, "slot %d is empty\n",
-		    ctrl_p->slot.slotNum));
-		goto cleanup;
-	}
-
-	/* get the current state of Slot Control Register */
-	control =  pciehpc_reg_get16(ctrl_p,
-	    ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL);
-
-	/* check if the slot's power state is ON */
-	if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
-		/* slot is already powered up */
-		PCIEHPC_DEBUG((CE_NOTE, "slot %d already connected\n",
-		    ctrl_p->slot.slotNum));
-		ctrl_p->slot.slot_state = HPC_SLOT_CONNECTED;
-		mutex_exit(&ctrl_p->pciehpc_mutex);
-		return (HPC_SUCCESS);
-	}
-
-	/* turn on power to the slot using ACPI method (PS0) */
-	if (pciehpc_acpi_power_on_slot(ctrl_p) != AE_OK)
-		goto cleanup;
-
-	ctrl_p->slot.slot_state = HPC_SLOT_CONNECTED;
-	mutex_exit(&ctrl_p->pciehpc_mutex);
-	return (HPC_SUCCESS);
-
-cleanup:
-	mutex_exit(&ctrl_p->pciehpc_mutex);
-	return (HPC_ERR_FAILED);
-}
-
-/*
- * This function is same as pciehpc_slot_disconnect() except that it
- * uses ACPI method EJ0 to disable power to the slot. If no EJ0 method
- * is present then it returns HPC_ERR_FAILED.
- */
-/*ARGSUSED*/
-static int
-pciehpc_acpi_slot_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl,
-	void *data, uint_t flags)
-{
-	uint16_t status;
-
-	pciehpc_t *ctrl_p = (pciehpc_t *)ops_arg;
-
-	ASSERT(slot_hdl == ctrl_p->slot.slot_handle);
-
-	mutex_enter(&ctrl_p->pciehpc_mutex);
-
-	/* get the current state of the slot */
-	pciehpc_get_slot_state(ctrl_p);
-
-	/* check if the slot is already in the 'disconnected' state */
-	if (ctrl_p->slot.slot_state == HPC_SLOT_DISCONNECTED) {
-		/* slot is in the 'disconnected' state */
-		PCIEHPC_DEBUG((CE_NOTE, "slot %d already disconnected\n",
-		    ctrl_p->slot.slotNum));
-		ASSERT(ctrl_p->slot.power_led_state == HPC_LED_OFF);
-		mutex_exit(&ctrl_p->pciehpc_mutex);
-		return (HPC_SUCCESS);
-	}
-
-	/* read the Slot Status Register */
-	status =  pciehpc_reg_get16(ctrl_p,
-	    ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS);
-
-	/* make sure the slot has a device present */
-	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
-		/* slot is empty */
-		PCIEHPC_DEBUG((CE_WARN, "slot %d is empty",
-		    ctrl_p->slot.slotNum));
-		goto cleanup;
-	}
-
-	/* turn off power to the slot using ACPI method (EJ0) */
-	if (pciehpc_acpi_power_off_slot(ctrl_p) != AE_OK)
-		goto cleanup;
-
-	ctrl_p->slot.slot_state = HPC_SLOT_DISCONNECTED;
-	mutex_exit(&ctrl_p->pciehpc_mutex);
-	return (HPC_SUCCESS);
-
-cleanup:
-	mutex_exit(&ctrl_p->pciehpc_mutex);
-	return (HPC_ERR_FAILED);
-}
-
-/*
- * Install event handler for the hot plug events on the bus node as well
- * as device function (dev=0,func=0).
- */
-static ACPI_STATUS
-pciehpc_acpi_install_event_handler(pciehpc_t *ctrl_p)
-{
-	int status = AE_OK;
-	pciehpc_acpi_t *acpi_p;
-
-	PCIEHPC_DEBUG3((CE_CONT, "install event handler for slot %d\n",
-	    ctrl_p->slot.slotNum));
-	acpi_p = ctrl_p->misc_data;
-	if (acpi_p->slot_dev_obj == NULL)
-		return (AE_NOT_FOUND);
-
-	/*
-	 * Install event hanlder for events on the bus object.
-	 * (Note: Insert event (hot-insert) is delivered on this object)
-	 */
-	status = AcpiInstallNotifyHandler(acpi_p->slot_dev_obj,
-	    ACPI_SYSTEM_NOTIFY, pciehpc_acpi_notify_handler, (void *)ctrl_p);
-	if (status != AE_OK)
-		goto cleanup;
-
-	/*
-	 * Install event hanlder for events on the device function object.
-	 * (Note: Eject device event (hot-remove) is delivered on this object)
-	 *
-	 * NOTE: Here the assumption is that Notify events are delivered
-	 * on all of the 8 possible device functions so, subscribing to
-	 * one of them is sufficient.
-	 */
-	status = AcpiInstallNotifyHandler(acpi_p->bus_obj, ACPI_SYSTEM_NOTIFY,
-	    pciehpc_acpi_notify_handler, (void *)ctrl_p);
-	return (status);
-
-cleanup:
-	(void) AcpiRemoveNotifyHandler(acpi_p->slot_dev_obj,
-	    ACPI_SYSTEM_NOTIFY, pciehpc_acpi_notify_handler);
-	return (status);
-}
-
-/*ARGSUSED*/
-static void
-pciehpc_acpi_notify_handler(ACPI_HANDLE device, uint32_t val, void *context)
-{
-	pciehpc_t *ctrl_p = context;
-	pciehpc_acpi_t *acpi_p;
-	int dev_state = 0;
-
-	PCIEHPC_DEBUG((CE_CONT, "received Notify(%d) event on slot #%d\n",
-	    val, ctrl_p->slot.slotNum));
-
-	mutex_enter(&ctrl_p->pciehpc_mutex);
-
-	/*
-	 * get the state of the device (from _STA method)
-	 */
-	acpi_p = ctrl_p->misc_data;
-	if (pciehpc_acpi_get_dev_state(acpi_p->slot_dev_obj,
-	    &dev_state) != AE_OK) {
-		cmn_err(CE_WARN, "failed to get device status on slot %d",
-		    ctrl_p->slot.slotNum);
-	}
-	PCIEHPC_DEBUG((CE_CONT, "(1)device state on slot #%d: 0x%x\n",
-	    ctrl_p->slot.slotNum, dev_state));
-
-	pciehpc_get_slot_state(ctrl_p);
-
-	switch (val) {
-	case 0: /* (re)enumerate the device */
-	case 3: /* Request Eject */
-		if (ctrl_p->slot.slot_state != HPC_SLOT_CONNECTED) {
-			/* unexpected slot state; surprise removal? */
-			cmn_err(CE_WARN, "Unexpected event on slot #%d"
-			    "(state 0x%x)", ctrl_p->slot.slotNum, dev_state);
-		}
-
-		/*
-		 * Ignore the event if ATTN button is not present (ACPI BIOS
-		 * problem).
-		 *
-		 * NOTE: This situation has been observed on some platforms
-		 * where the ACPI BIOS is generating the event for some other
-		 * (non hot-plug) operations (bug).
-		 */
-		if (ctrl_p->has_attn == B_FALSE) {
-			PCIEHPC_DEBUG((CE_CONT, "Ignore the unexpected event "
-			    "on slot #%d (state 0x%x)",
-			    ctrl_p->slot.slotNum, dev_state));
-			break;
-		}
-
-		/* send the ATTN button event to HPS framework */
-		(void) hpc_slot_event_notify(ctrl_p->slot.slot_handle,
-		    HPC_EVENT_SLOT_ATTN, HPC_EVENT_NORMAL);
-		break;
-	default:
-		cmn_err(CE_NOTE, "Unknown Notify() event %d on slot #%d\n",
-		    val, ctrl_p->slot.slotNum);
-		break;
-	}
-	mutex_exit(&ctrl_p->pciehpc_mutex);
-}
-
-static void
-pciehpc_acpi_uninstall_event_handler(pciehpc_t *ctrl_p)
-{
-	pciehpc_acpi_t *acpi_p = ctrl_p->misc_data;
-
-	PCIEHPC_DEBUG((CE_CONT, "Uninstall event handler for slot #%d\n",
-	    ctrl_p->slot.slotNum));
-	(void) AcpiRemoveNotifyHandler(acpi_p->slot_dev_obj,
-	    ACPI_SYSTEM_NOTIFY, pciehpc_acpi_notify_handler);
-	(void) AcpiRemoveNotifyHandler(acpi_p->bus_obj,
-	    ACPI_SYSTEM_NOTIFY, pciehpc_acpi_notify_handler);
-}
-
-/*
- * Run _PS0 method to turn on power to the slot.
- */
-static ACPI_STATUS
-pciehpc_acpi_power_on_slot(pciehpc_t *ctrl_p)
-{
-	int status = AE_OK;
-	pciehpc_acpi_t *acpi_p = ctrl_p->misc_data;
-	int dev_state = 0;
-
-	PCIEHPC_DEBUG((CE_CONT, "turn ON power to the slot #%d\n",
-	    ctrl_p->slot.slotNum));
-
-	status = AcpiEvaluateObject(acpi_p->slot_dev_obj, "_PS0", NULL, NULL);
-
-	/* get the state of the device (from _STA method) */
-	if (status == AE_OK) {
-		if (pciehpc_acpi_get_dev_state(acpi_p->slot_dev_obj,
-		    &dev_state) != AE_OK)
-		cmn_err(CE_WARN, "failed to get device status on slot #%d",
-		    ctrl_p->slot.slotNum);
-	}
-	PCIEHPC_DEBUG((CE_CONT, "(3)device state on slot #%d: 0x%x\n",
-	    ctrl_p->slot.slotNum, dev_state));
-
-	pciehpc_get_slot_state(ctrl_p);
-
-	if (ctrl_p->slot.slot_state != HPC_SLOT_CONNECTED) {
-		cmn_err(CE_WARN, "failed to power on the slot #%d"
-		    "(dev_state 0x%x, ACPI_STATUS 0x%x)",
-		    ctrl_p->slot.slotNum, dev_state, status);
-		return (AE_ERROR);
-	}
-
-	return (status);
-}
-
-/*
- * Run _EJ0 method to turn off power to the slot.
- */
-static ACPI_STATUS
-pciehpc_acpi_power_off_slot(pciehpc_t *ctrl_p)
-{
-	int status = AE_OK;
-	pciehpc_acpi_t *acpi_p = ctrl_p->misc_data;
-	int dev_state = 0;
-
-	PCIEHPC_DEBUG((CE_CONT, "turn OFF power to the slot #%d\n",
-	    ctrl_p->slot.slotNum));
-
-	status = AcpiEvaluateObject(acpi_p->slot_dev_obj, "_EJ0", NULL, NULL);
-
-	/* get the state of the device (from _STA method) */
-	if (status == AE_OK) {
-		if (pciehpc_acpi_get_dev_state(acpi_p->slot_dev_obj,
-		    &dev_state) != AE_OK)
-		cmn_err(CE_WARN, "failed to get device status on slot #%d",
-		    ctrl_p->slot.slotNum);
-	}
-	PCIEHPC_DEBUG((CE_CONT, "(2)device state on slot #%d: 0x%x\n",
-	    ctrl_p->slot.slotNum, dev_state));
-
-	pciehpc_get_slot_state(ctrl_p);
-
-	if (ctrl_p->slot.slot_state == HPC_SLOT_CONNECTED) {
-		cmn_err(CE_WARN, "failed to power OFF the slot #%d"
-		    "(dev_state 0x%x, ACPI_STATUS 0x%x)",
-		    ctrl_p->slot.slotNum, dev_state, status);
-		return (AE_ERROR);
-	}
-
-	return (status);
-}
-
-/*
- * Check if the child device node of the bus object has _EJ0 method
- * present.
- */
-static ACPI_STATUS
-pciehpc_acpi_ej0_present(ACPI_HANDLE pcibus_obj)
-{
-	int status = AE_OK;
-	ACPI_HANDLE d0f0_obj;
-	ACPI_HANDLE ej0_hdl;
-
-	if ((status = AcpiGetNextObject(ACPI_TYPE_DEVICE, pcibus_obj,
-	    NULL, &d0f0_obj)) == AE_OK) {
-		/* child device node(s) are present; check for _EJ0 method */
-		status = AcpiGetHandle(d0f0_obj, "_EJ0", &ej0_hdl);
-	}
-
-	return (status);
-}
-
-
-/*
- * Get the status info (as returned by _STA method) for the device.
- */
-static ACPI_STATUS
-pciehpc_acpi_get_dev_state(ACPI_HANDLE obj, int *statusp)
-{
-	ACPI_BUFFER	rb;
-	ACPI_DEVICE_INFO *info = NULL;
-	int ret = AE_OK;
-
-	/*
-	 * Get device info object
-	 */
-	rb.Length = ACPI_ALLOCATE_BUFFER;
-	rb.Pointer = NULL;
-	if ((ret = AcpiGetObjectInfo(obj, &rb)) != AE_OK)
-		return (ret);
-	info = (ACPI_DEVICE_INFO *)rb.Pointer;
-
-	if (info->Valid & ACPI_VALID_STA) {
-		*statusp = info->CurrentStatus;
-	} else {
-		/*
-		 * no _STA present; assume the device status is normal
-		 * (i.e present, enabled, shown in UI and functioning).
-		 * See section 6.3.7 of ACPI 3.0 spec.
-		 */
-		*statusp = STATUS_NORMAL;
-	}
-
-	AcpiOsFree(info);
-
-	return (ret);
-}
--- a/usr/src/uts/intel/io/hotplug/pciehpc/pciehpc_acpi.h	Sun Nov 01 14:14:46 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +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	_PCIEHPC_ACPI_H
-#define	_PCIEHPC_ACPI_H
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-#include <sys/acpi/acpi.h>
-#include <sys/acpica.h>
-#include <sys/hotplug/pci/pciehpc_impl.h>
-
-/* soft state data structure for ACPI hot plug mode */
-typedef struct pciehpc_acpi {
-	/* handle for the ACPI device for the bus node with HPC */
-	ACPI_HANDLE	bus_obj;
-
-	/* handle for the ACPI device for the slot (dev#0,func#0) */
-	ACPI_HANDLE	slot_dev_obj;
-
-	/* ACPI control methods present on the bus node */
-	uint16_t	bus_methods;
-
-	/* ACPI control methods on the slot device functions */
-	uint16_t	slot_methods;
-} pciehpc_acpi_t;
-
-/* bit definitions in acpi_bus_methods */
-#define	PCIEHPC_ACPI_OSC_PRESENT	0x0001
-#define	PCIEHPC_ACPI_OSHP_PRESENT	0x0002
-#define	PCIEHPC_ACPI_SUN_PRESENT	0x0004
-#define	PCIEHPC_ACPI_STA_PRESENT	0x0008
-#define	PCIEHPC_ACPI_EJ0_PRESENT	0x0010
-#define	PCIEHPC_ACPI_HPP_PRESENT	0x0020
-#define	PCIEHPC_ACPI_HPX_PRESENT	0x0040
-#define	PCIEHPC_ACPI_PS0_PRESENT	0x0080
-#define	PCIEHPC_ACPI_DSM_PRESENT	0x0080
-#define	PCIEHPC_ACPI_STR_PRESENT	0x0100
-
-/* Device status bit as returned by _STA method (see 6.3.7 of ACPI 3.0) */
-#define	DEV_STS_PRESENT		0x1	/* device is present */
-#define	DEV_STS_ENABLED		0x2	/* device is enabled */
-#define	DEV_STS_SHOWN_UI	0x4	/* device should be shown in UI */
-#define	DEV_STS_FUNC_OK		0x8	/* device functioning normally */
-#define	STATUS_NORMAL	\
-	(DEV_STS_PRESENT | DEV_STS_ENABLED | DEV_STS_SHOWN_UI | DEV_STS_FUNC_OK)
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif	/* _PCIEHPC_ACPI_H */
--- a/usr/src/uts/intel/io/pci/pci_boot.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/intel/io/pci/pci_boot.c	Mon Nov 02 15:58:28 2009 +0800
@@ -39,7 +39,7 @@
 #include "../../../../common/pci/pci_strings.h"
 #include <sys/apic.h>
 #include <io/pciex/pcie_nvidia.h>
-#include <io/hotplug/pciehpc/pciehpc_acpi.h>
+#include <sys/hotplug/pci/pciehpc_acpi.h>
 #include <sys/acpi/acpi.h>
 #include <sys/acpica.h>
 #include <sys/intel_iommu.h>
--- a/usr/src/uts/intel/io/pci/pci_pci.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/intel/io/pci/pci_pci.c	Mon Nov 02 15:58:28 2009 +0800
@@ -34,6 +34,7 @@
 #include <sys/autoconf.h>
 #include <sys/ddi_impldefs.h>
 #include <sys/pci.h>
+#include <sys/pci_impl.h>
 #include <sys/pcie_impl.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
@@ -41,6 +42,7 @@
 #include <sys/ddifm.h>
 #include <sys/ndifm.h>
 #include <sys/fm/protocol.h>
+#include <sys/hotplug/pci/pcie_hp.h>
 #include <sys/hotplug/pci/pcihp.h>
 #include <sys/pci_intr_lib.h>
 #include <sys/psm.h>
@@ -101,19 +103,20 @@
 	ddi_dma_mctl,
 	ppb_ctlops,
 	ddi_bus_prop_op,
-	0,		/* (*bus_get_eventcookie)();	*/
-	0,		/* (*bus_add_eventcall)();	*/
-	0,		/* (*bus_remove_eventcall)();	*/
-	0,		/* (*bus_post_event)();		*/
-	0,		/* (*bus_intr_ctl)();		*/
-	0,		/* (*bus_config)(); 		*/
-	0,		/* (*bus_unconfig)(); 		*/
-	ppb_fm_init,	/* (*bus_fm_init)(); 		*/
-	NULL,		/* (*bus_fm_fini)(); 		*/
-	NULL,		/* (*bus_fm_access_enter)(); 	*/
-	NULL,		/* (*bus_fm_access_exit)(); 	*/
-	NULL,		/* (*bus_power)(); 	*/
-	ppb_intr_ops	/* (*bus_intr_op)(); 		*/
+	0,			/* (*bus_get_eventcookie)();	*/
+	0,			/* (*bus_add_eventcall)();	*/
+	0,			/* (*bus_remove_eventcall)();	*/
+	0,			/* (*bus_post_event)();		*/
+	0,			/* (*bus_intr_ctl)();		*/
+	0,			/* (*bus_config)(); 		*/
+	0,			/* (*bus_unconfig)(); 		*/
+	ppb_fm_init,		/* (*bus_fm_init)(); 		*/
+	NULL,			/* (*bus_fm_fini)(); 		*/
+	NULL,			/* (*bus_fm_access_enter)(); 	*/
+	NULL,			/* (*bus_fm_access_exit)(); 	*/
+	NULL,			/* (*bus_power)(); 	*/
+	ppb_intr_ops,		/* (*bus_intr_op)(); 		*/
+	pcie_hp_common_ops	/* (*bus_hp_op)(); 		*/
 };
 
 /*
@@ -175,7 +178,7 @@
 
 static struct modldrv modldrv = {
 	&mod_driverops, /* Type of module */
-	"PCI to PCI bridge nexus driver",
+	"Standard PCI to PCI bridge nexus driver",
 	&ppb_ops,	/* driver ops */
 };
 
@@ -194,6 +197,7 @@
 	dev_info_t *dip;
 	int ppb_fmcap;
 	ddi_iblock_cookie_t ppb_fm_ibc;
+	kmutex_t ppb_mutex;
 	kmutex_t ppb_peek_poke_mutex;
 	kmutex_t ppb_err_mutex;
 
@@ -276,6 +280,7 @@
 	dev_info_t *pdip;
 	ddi_acc_handle_t config_handle;
 	char *bus;
+	int ret;
 
 	switch (cmd) {
 	case DDI_ATTACH:
@@ -307,6 +312,7 @@
 			    DDI_FM_DMACHK_CAPABLE;
 
 		ddi_fm_init(devi, &ppb->ppb_fmcap, &ppb->ppb_fm_ibc);
+		mutex_init(&ppb->ppb_mutex, NULL, MUTEX_DRIVER, NULL);
 		mutex_init(&ppb->ppb_err_mutex, NULL, MUTEX_DRIVER,
 		    (void *)ppb->ppb_fm_ibc);
 		mutex_init(&ppb->ppb_peek_poke_mutex, NULL, MUTEX_DRIVER,
@@ -355,14 +361,19 @@
 		pci_config_teardown(&config_handle);
 
 		/*
-		 * Initialize hotplug support on this bus. At minimum
-		 * (for non hotplug bus) this would create ":devctl" minor
-		 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls
-		 * to this bus.
+		 * Initialize hotplug support on this bus.
 		 */
-		if (pcihp_init(devi) != DDI_SUCCESS)
+		if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV)
+			ret = pcie_init(devi, NULL);
+		else
+			ret = pcihp_init(devi);
+
+		if (ret != DDI_SUCCESS) {
 			cmn_err(CE_WARN,
 			    "pci: Failed to setup hotplug framework");
+			(void) ppb_detach(devi, DDI_DETACH);
+			return (ret);
+		}
 
 		ddi_report_dev(devi);
 		return (DDI_SUCCESS);
@@ -387,6 +398,7 @@
 ppb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
 {
 	ppb_devstate_t *ppb;
+	int		ret;
 
 	switch (cmd) {
 	case DDI_DETACH:
@@ -398,8 +410,18 @@
 		if (ppb->ppb_fmcap & (DDI_FM_ERRCB_CAPABLE |
 		    DDI_FM_EREPORT_CAPABLE))
 			pci_ereport_teardown(devi);
+
+		/*
+		 * Uninitialize hotplug support on this bus.
+		 */
+		ret = (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) ?
+		    pcie_uninit(devi) : pcihp_uninit(devi);
+		if (ret != DDI_SUCCESS)
+			return (DDI_FAILURE);
+
 		mutex_destroy(&ppb->ppb_peek_poke_mutex);
 		mutex_destroy(&ppb->ppb_err_mutex);
+		mutex_destroy(&ppb->ppb_mutex);
 		ddi_fm_fini(devi);
 
 		/*
@@ -407,10 +429,6 @@
 		 */
 		ddi_soft_state_free(ppb_state, ddi_get_instance(devi));
 
-		/*
-		 * Uninitialize hotplug support on this bus.
-		 */
-		(void) pcihp_uninit(devi);
 		return (DDI_SUCCESS);
 
 	case DDI_SUSPEND:
@@ -886,29 +904,97 @@
 	return (rv);
 }
 
+/* ARGSUSED */
 static int
 ppb_open(dev_t *devp, int flags, int otyp, cred_t *credp)
 {
+	int		instance = PCI_MINOR_NUM_TO_INSTANCE(getminor(*devp));
+	ppb_devstate_t	*ppb_p = ddi_get_soft_state(ppb_state, instance);
+	int	rv;
+
+	if (ppb_p == NULL)
+		return (ENXIO);
+
+	/*
+	 * Ioctls will be handled by PCI Express framework for all
+	 * PCIe platforms
+	 */
+	if (ppb_p->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) {
+		mutex_enter(&ppb_p->ppb_mutex);
+		rv = pcie_open(ppb_p->dip, devp, flags, otyp, credp);
+		mutex_exit(&ppb_p->ppb_mutex);
+		return (rv);
+	}
+
 	return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, credp));
 }
 
+/* ARGSUSED */
 static int
 ppb_close(dev_t dev, int flags, int otyp, cred_t *credp)
 {
+	int		instance = PCI_MINOR_NUM_TO_INSTANCE(getminor(dev));
+	ppb_devstate_t	*ppb_p = ddi_get_soft_state(ppb_state, instance);
+	int	rv;
+
+	if (ppb_p == NULL)
+		return (ENXIO);
+
+	mutex_enter(&ppb_p->ppb_mutex);
+	/*
+	 * Ioctls will be handled by PCI Express framework for all
+	 * PCIe platforms
+	 */
+	if (ppb_p->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) {
+		rv = pcie_close(ppb_p->dip, dev, flags, otyp, credp);
+		mutex_exit(&ppb_p->ppb_mutex);
+		return (rv);
+	}
+
+	mutex_exit(&ppb_p->ppb_mutex);
 	return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, credp));
 }
 
+/*
+ * ppb_ioctl: devctl hotplug controls
+ */
+/* ARGSUSED */
 static int
-ppb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
+ppb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
+	int *rvalp)
 {
+	int		instance = PCI_MINOR_NUM_TO_INSTANCE(getminor(dev));
+	ppb_devstate_t	*ppb_p = ddi_get_soft_state(ppb_state, instance);
+
+	if (ppb_p == NULL)
+		return (ENXIO);
+
+	/*
+	 * Ioctls will be handled by PCI Express framework for all
+	 * PCIe platforms
+	 */
+	if (ppb_p->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV)
+		return (pcie_ioctl(ppb_p->dip, dev, cmd, arg, mode, credp,
+		    rvalp));
+
 	return ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode, credp,
 	    rvalp));
 }
 
 static int
-ppb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
-	int flags, char *name, caddr_t valuep, int *lengthp)
+ppb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int flags,
+    char *name, caddr_t valuep, int *lengthp)
 {
+	int		instance = PCI_MINOR_NUM_TO_INSTANCE(getminor(dev));
+	ppb_devstate_t	*ppb_p = ddi_get_soft_state(ppb_state, instance);
+
+	if (ppb_p == NULL)
+		return (ENXIO);
+
+	if (ppb_p->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV)
+		return (pcie_prop_op(dev, dip, prop_op, flags, name,
+		    valuep, lengthp));
+
 	return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags,
 	    name, valuep, lengthp));
 }
@@ -916,7 +1002,30 @@
 static int
 ppb_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
 {
-	return (pcihp_info(dip, cmd, arg, result));
+	minor_t		minor = getminor((dev_t)arg);
+	int		instance = PCI_MINOR_NUM_TO_INSTANCE(minor);
+	ppb_devstate_t	*ppb_p = ddi_get_soft_state(ppb_state, instance);
+
+	if (ppb_p == NULL)
+		return (DDI_FAILURE);
+
+	if (ppb_p->parent_bus != PCIE_PCIECAP_DEV_TYPE_PCIE_DEV)
+		return (pcihp_info(dip, cmd, arg, result));
+
+	switch (cmd) {
+	default:
+		return (DDI_FAILURE);
+
+	case DDI_INFO_DEVT2INSTANCE:
+		*result = (void *)(uintptr_t)instance;
+		return (DDI_SUCCESS);
+
+	case DDI_INFO_DEVT2DEVINFO:
+		if (ppb_p == NULL)
+			return (DDI_FAILURE);
+		*result = (void *)ppb_p->dip;
+		return (DDI_SUCCESS);
+	}
 }
 
 void ppb_peekpoke_cb(dev_info_t *dip, ddi_fm_error_t *derr) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/io/pciex/hotplug/pciehpc_acpi.c	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,677 @@
+/*
+ * 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.
+ */
+
+/*
+ * ACPI interface related functions used in PCIEHPC driver module.
+ *
+ * NOTE: This file is compiled and delivered through misc/pcie module.
+ */
+
+#include <sys/note.h>
+#include <sys/conf.h>
+#include <sys/kmem.h>
+#include <sys/debug.h>
+#include <sys/vtrace.h>
+#include <sys/varargs.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/pci.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/pci_impl.h>
+#include <sys/pcie_acpi.h>
+#include <sys/hotplug/pci/pcie_hp.h>
+#include <sys/hotplug/pci/pciehpc_acpi.h>
+
+/* local static functions */
+static int pciehpc_acpi_hpc_init(pcie_hp_ctrl_t *ctrl_p);
+static int pciehpc_acpi_hpc_uninit(pcie_hp_ctrl_t *ctrl_p);
+static int pciehpc_acpi_slotinfo_init(pcie_hp_ctrl_t *ctrl_p);
+static int pciehpc_acpi_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p);
+static int pciehpc_acpi_enable_intr(pcie_hp_ctrl_t *ctrl_p);
+static int pciehpc_acpi_disable_intr(pcie_hp_ctrl_t *ctrl_p);
+static int pciehpc_acpi_slot_poweron(pcie_hp_slot_t *slot_p,
+    ddi_hp_cn_state_t *result);
+static int pciehpc_acpi_slot_poweroff(pcie_hp_slot_t *slot_p,
+    ddi_hp_cn_state_t *result);
+static void pciehpc_acpi_setup_ops(pcie_hp_ctrl_t *ctrl_p);
+
+static ACPI_STATUS pciehpc_acpi_install_event_handler(pcie_hp_ctrl_t *ctrl_p);
+static void pciehpc_acpi_uninstall_event_handler(pcie_hp_ctrl_t *ctrl_p);
+static ACPI_STATUS pciehpc_acpi_power_on_slot(pcie_hp_ctrl_t *ctrl_p);
+static ACPI_STATUS pciehpc_acpi_power_off_slot(pcie_hp_ctrl_t *ctrl_p);
+static void pciehpc_acpi_notify_handler(ACPI_HANDLE device, uint32_t val,
+	void *context);
+static ACPI_STATUS pciehpc_acpi_get_dev_state(ACPI_HANDLE obj, int *statusp);
+
+/*
+ * Update ops vector with platform specific (ACPI, CK8-04,...) functions.
+ */
+void
+pciehpc_update_ops(pcie_hp_ctrl_t *ctrl_p)
+{
+	boolean_t hp_native_mode = B_FALSE;
+	uint32_t osc_flags = OSC_CONTROL_PCIE_NAT_HP;
+
+	/*
+	 * Call _OSC method to determine if hotplug mode is native or ACPI.
+	 * If _OSC method succeeds hp_native_mode below will be set according to
+	 * if native hotplug control was granted or not by BIOS.
+	 *
+	 * If _OSC method fails for any reason or if native hotplug control was
+	 * not granted assume it's ACPI mode and update platform specific
+	 * (ACPI, CK8-04,...) impl. ops
+	 */
+
+	if (pcie_acpi_osc(ctrl_p->hc_dip, &osc_flags) == DDI_SUCCESS) {
+		hp_native_mode = (osc_flags & OSC_CONTROL_PCIE_NAT_HP) ?
+		    B_TRUE : B_FALSE;
+	}
+
+	if (!hp_native_mode) {
+		pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+
+		/* update ops vector for ACPI mode */
+		pciehpc_acpi_setup_ops(ctrl_p);
+		bus_p->bus_hp_sup_modes |= PCIE_ACPI_HP_MODE;
+		bus_p->bus_hp_curr_mode = PCIE_ACPI_HP_MODE;
+	}
+}
+
+void
+pciehpc_acpi_setup_ops(pcie_hp_ctrl_t *ctrl_p)
+{
+	ctrl_p->hc_ops.init_hpc_hw = pciehpc_acpi_hpc_init;
+	ctrl_p->hc_ops.uninit_hpc_hw = pciehpc_acpi_hpc_uninit;
+	ctrl_p->hc_ops.init_hpc_slotinfo = pciehpc_acpi_slotinfo_init;
+	ctrl_p->hc_ops.uninit_hpc_slotinfo = pciehpc_acpi_slotinfo_uninit;
+	ctrl_p->hc_ops.poweron_hpc_slot = pciehpc_acpi_slot_poweron;
+	ctrl_p->hc_ops.poweroff_hpc_slot = pciehpc_acpi_slot_poweroff;
+	ctrl_p->hc_ops.disable_hpc_intr = pciehpc_acpi_disable_intr;
+	ctrl_p->hc_ops.enable_hpc_intr = pciehpc_acpi_enable_intr;
+}
+
+/*
+ * Intialize hot plug control for ACPI mode.
+ */
+static int
+pciehpc_acpi_hpc_init(pcie_hp_ctrl_t *ctrl_p)
+{
+	ACPI_HANDLE pcibus_obj;
+	int status = AE_ERROR;
+	ACPI_HANDLE slot_dev_obj;
+	ACPI_HANDLE hdl;
+	pciehpc_acpi_t *acpi_p;
+	uint16_t bus_methods = 0;
+	uint16_t slot_methods = 0;
+
+	/* get the ACPI object for the bus node */
+	status = acpica_get_handle(ctrl_p->hc_dip, &pcibus_obj);
+	if (status != AE_OK)
+		return (DDI_FAILURE);
+
+	/* get the ACPI object handle for the child node */
+	status = AcpiGetNextObject(ACPI_TYPE_DEVICE, pcibus_obj,
+	    NULL, &slot_dev_obj);
+	if (status != AE_OK)
+		return (DDI_FAILURE);
+
+	/*
+	 * gather the info about the ACPI methods present on the bus node
+	 * and the child nodes.
+	 */
+	if (AcpiGetHandle(pcibus_obj, "_OSC", &hdl) == AE_OK)
+		bus_methods |= PCIEHPC_ACPI_OSC_PRESENT;
+	if (AcpiGetHandle(pcibus_obj, "_OSHP", &hdl) == AE_OK)
+		bus_methods |= PCIEHPC_ACPI_OSHP_PRESENT;
+	if (AcpiGetHandle(pcibus_obj, "_HPX", &hdl) == AE_OK)
+		bus_methods |= PCIEHPC_ACPI_HPX_PRESENT;
+	if (AcpiGetHandle(pcibus_obj, "_HPP", &hdl) == AE_OK)
+		bus_methods |= PCIEHPC_ACPI_HPP_PRESENT;
+	if (AcpiGetHandle(pcibus_obj, "_DSM", &hdl) == AE_OK)
+		bus_methods |= PCIEHPC_ACPI_DSM_PRESENT;
+	if (AcpiGetHandle(slot_dev_obj, "_SUN", &hdl) == AE_OK)
+		slot_methods |= PCIEHPC_ACPI_SUN_PRESENT;
+	if (AcpiGetHandle(slot_dev_obj, "_PS0", &hdl) == AE_OK)
+		slot_methods |= PCIEHPC_ACPI_PS0_PRESENT;
+	if (AcpiGetHandle(slot_dev_obj, "_EJ0", &hdl) == AE_OK)
+		slot_methods |= PCIEHPC_ACPI_EJ0_PRESENT;
+	if (AcpiGetHandle(slot_dev_obj, "_STA", &hdl) == AE_OK)
+		slot_methods |= PCIEHPC_ACPI_STA_PRESENT;
+
+	/* save ACPI object handles, etc. */
+	acpi_p = kmem_zalloc(sizeof (pciehpc_acpi_t), KM_SLEEP);
+	acpi_p->bus_obj = pcibus_obj;
+	acpi_p->slot_dev_obj = slot_dev_obj;
+	acpi_p->bus_methods = bus_methods;
+	acpi_p->slot_methods = slot_methods;
+	ctrl_p->hc_misc_data = acpi_p;
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Uninitialize HPC.
+ */
+static int
+pciehpc_acpi_hpc_uninit(pcie_hp_ctrl_t *ctrl_p)
+{
+	/* free up buffer used for misc_data */
+	if (ctrl_p->hc_misc_data) {
+		kmem_free(ctrl_p->hc_misc_data, sizeof (pciehpc_acpi_t));
+		ctrl_p->hc_misc_data = NULL;
+	}
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Enable interrupts. For ACPI hot plug this is a NOP.
+ * Just return DDI_SUCCESS.
+ */
+/*ARGSUSED*/
+static int
+pciehpc_acpi_enable_intr(pcie_hp_ctrl_t *ctrl_p)
+{
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Disable interrupts. For ACPI hot plug this is a NOP.
+ * Just return DDI_SUCCESS.
+ */
+/*ARGSUSED*/
+static int
+pciehpc_acpi_disable_intr(pcie_hp_ctrl_t *ctrl_p)
+{
+	return (DDI_SUCCESS);
+}
+
+/*
+ * This function is similar to pciehpc_slotinfo_init() with some
+ * changes:
+ *	- no need for kernel thread to handle ATTN button events
+ *	- function ops for connect/disconnect are different
+ *
+ * ASSUMPTION: No conflict in doing reads to HP registers directly.
+ * Otherwise, there are no ACPI interfaces to do LED control or to get
+ * the hot plug capabilities (ATTN button, MRL, etc.).
+ */
+static int
+pciehpc_acpi_slotinfo_init(pcie_hp_ctrl_t *ctrl_p)
+{
+	uint32_t	slot_capabilities;
+	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+
+	mutex_enter(&ctrl_p->hc_mutex);
+	/*
+	 * setup DDI HP framework slot information structure
+	 */
+	slot_p->hs_device_num = 0;
+	slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCIE;
+	slot_p->hs_info.cn_type_str = PCIE_ACPI_HP_TYPE;
+	slot_p->hs_info.cn_child = NULL;
+
+	slot_p->hs_minor =
+	    PCI_MINOR_NUM(ddi_get_instance(ctrl_p->hc_dip),
+	    slot_p->hs_device_num);
+
+	/* read Slot Capabilities Register */
+	slot_capabilities = pciehpc_reg_get32(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCAP);
+
+	/* setup slot number/name */
+	pciehpc_set_slot_name(ctrl_p);
+
+	/* check if Attn Button present */
+	ctrl_p->hc_has_attn = (slot_capabilities &
+	    PCIE_SLOTCAP_ATTN_BUTTON) ? B_TRUE : B_FALSE;
+
+	/* check if Manual Retention Latch sensor present */
+	ctrl_p->hc_has_mrl = (slot_capabilities & PCIE_SLOTCAP_MRL_SENSOR) ?
+	    B_TRUE : B_FALSE;
+
+	/*
+	 * PCI-E (draft) version 1.1 defines EMI Lock Present bit
+	 * in Slot Capabilities register. Check for it.
+	 */
+	ctrl_p->hc_has_emi_lock = (slot_capabilities &
+	    PCIE_SLOTCAP_EMI_LOCK_PRESENT) ? B_TRUE : B_FALSE;
+
+	/* get current slot state from the hw */
+	pciehpc_get_slot_state(slot_p);
+	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED)
+		slot_p->hs_condition = AP_COND_OK;
+
+	mutex_exit(&ctrl_p->hc_mutex);
+
+	/* setup Notify() handler for hot plug events from ACPI BIOS */
+	if (pciehpc_acpi_install_event_handler(ctrl_p) != AE_OK)
+		return (DDI_FAILURE);
+
+	PCIE_DBG("ACPI hot plug is enabled for slot #%d\n",
+	    slot_p->hs_phy_slot_num);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * This function is similar to pciehcp_slotinfo_uninit() but has ACPI
+ * specific cleanup.
+ */
+static int
+pciehpc_acpi_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p)
+{
+	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
+
+	/* uninstall Notify() event handler */
+	pciehpc_acpi_uninstall_event_handler(ctrl_p);
+	if (slot_p->hs_info.cn_name)
+		kmem_free(slot_p->hs_info.cn_name,
+		    strlen(slot_p->hs_info.cn_name) + 1);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * This function is same as pciehpc_slot_poweron() except that it
+ * uses ACPI method PS0 to enable power to the slot. If no PS0 method
+ * is present then it returns DDI_FAILURE.
+ */
+/*ARGSUSED*/
+static int
+pciehpc_acpi_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
+{
+	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+	uint16_t	status, control;
+
+	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
+
+	/* get the current state of the slot */
+	pciehpc_get_slot_state(slot_p);
+
+	/* check if the slot is already in the 'ENABLED' state */
+	if (slot_p->hs_info.cn_state == DDI_HP_CN_STATE_ENABLED) {
+		/* slot is already in the 'connected' state */
+		PCIE_DBG("slot %d already connected\n",
+		    slot_p->hs_phy_slot_num);
+
+		*result = slot_p->hs_info.cn_state;
+		return (DDI_SUCCESS);
+	}
+
+	/* read the Slot Status Register */
+	status =  pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
+
+	/* make sure the MRL switch is closed if present */
+	if ((ctrl_p->hc_has_mrl) && (status & PCIE_SLOTSTS_MRL_SENSOR_OPEN)) {
+		/* MRL switch is open */
+		cmn_err(CE_WARN, "MRL switch is open on slot %d",
+		    slot_p->hs_phy_slot_num);
+		goto cleanup;
+	}
+
+	/* make sure the slot has a device present */
+	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
+		/* slot is empty */
+		PCIE_DBG("slot %d is empty\n", slot_p->hs_phy_slot_num);
+		goto cleanup;
+	}
+
+	/* get the current state of Slot Control Register */
+	control =  pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
+
+	/* check if the slot's power state is ON */
+	if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
+		/* slot is already powered up */
+		PCIE_DBG("slot %d already connected\n",
+		    slot_p->hs_phy_slot_num);
+
+		*result = slot_p->hs_info.cn_state;
+		return (DDI_SUCCESS);
+	}
+
+	/* turn on power to the slot using ACPI method (PS0) */
+	if (pciehpc_acpi_power_on_slot(ctrl_p) != AE_OK)
+		goto cleanup;
+
+	*result = slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED;
+	return (DDI_SUCCESS);
+
+cleanup:
+	return (DDI_FAILURE);
+}
+
+/*
+ * This function is same as pciehpc_slot_poweroff() except that it
+ * uses ACPI method EJ0 to disable power to the slot. If no EJ0 method
+ * is present then it returns DDI_FAILURE.
+ */
+/*ARGSUSED*/
+static int
+pciehpc_acpi_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
+{
+	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
+	uint16_t	status;
+
+	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
+
+	/* get the current state of the slot */
+	pciehpc_get_slot_state(slot_p);
+
+	/* check if the slot is already in the state less than 'powered' */
+	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
+		/* slot is in the 'disconnected' state */
+		PCIE_DBG("slot %d already disconnected\n",
+		    slot_p->hs_phy_slot_num);
+		ASSERT(slot_p->hs_power_led_state == PCIE_HP_LED_OFF);
+
+		*result = slot_p->hs_info.cn_state;
+		return (DDI_SUCCESS);
+	}
+
+	/* read the Slot Status Register */
+	status =  pciehpc_reg_get16(ctrl_p,
+	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
+
+	/* make sure the slot has a device present */
+	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
+		/* slot is empty */
+		PCIE_DBG("slot %d is empty", slot_p->hs_phy_slot_num);
+		goto cleanup;
+	}
+
+	/* turn off power to the slot using ACPI method (EJ0) */
+	if (pciehpc_acpi_power_off_slot(ctrl_p) != AE_OK)
+		goto cleanup;
+
+	/* get the current state of the slot */
+	pciehpc_get_slot_state(slot_p);
+
+	*result = slot_p->hs_info.cn_state;
+
+	return (DDI_SUCCESS);
+
+cleanup:
+	return (DDI_FAILURE);
+}
+
+/*
+ * Install event handler for the hot plug events on the bus node as well
+ * as device function (dev=0,func=0).
+ */
+static ACPI_STATUS
+pciehpc_acpi_install_event_handler(pcie_hp_ctrl_t *ctrl_p)
+{
+	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
+	int status = AE_OK;
+	pciehpc_acpi_t *acpi_p;
+
+	PCIE_DBG("install event handler for slot %d\n",
+	    slot_p->hs_phy_slot_num);
+	acpi_p = ctrl_p->hc_misc_data;
+	if (acpi_p->slot_dev_obj == NULL)
+		return (AE_NOT_FOUND);
+
+	/*
+	 * Install event hanlder for events on the bus object.
+	 * (Note: Insert event (hot-insert) is delivered on this object)
+	 */
+	status = AcpiInstallNotifyHandler(acpi_p->slot_dev_obj,
+	    ACPI_SYSTEM_NOTIFY, pciehpc_acpi_notify_handler, (void *)ctrl_p);
+	if (status != AE_OK)
+		goto cleanup;
+
+	/*
+	 * Install event hanlder for events on the device function object.
+	 * (Note: Eject device event (hot-remove) is delivered on this object)
+	 *
+	 * NOTE: Here the assumption is that Notify events are delivered
+	 * on all of the 8 possible device functions so, subscribing to
+	 * one of them is sufficient.
+	 */
+	status = AcpiInstallNotifyHandler(acpi_p->bus_obj,
+	    ACPI_SYSTEM_NOTIFY, pciehpc_acpi_notify_handler, (void *)ctrl_p);
+	return (status);
+
+cleanup:
+	(void) AcpiRemoveNotifyHandler(acpi_p->slot_dev_obj,
+	    ACPI_SYSTEM_NOTIFY, pciehpc_acpi_notify_handler);
+	return (status);
+}
+
+/*ARGSUSED*/
+static void
+pciehpc_acpi_notify_handler(ACPI_HANDLE device, uint32_t val, void *context)
+{
+	pcie_hp_ctrl_t *ctrl_p = context;
+	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
+	pciehpc_acpi_t *acpi_p;
+	ddi_hp_cn_state_t curr_state;
+	int dev_state = 0;
+
+	PCIE_DBG("received Notify(%d) event on slot #%d\n",
+	    val, slot_p->hs_phy_slot_num);
+
+	mutex_enter(&ctrl_p->hc_mutex);
+
+	/*
+	 * get the state of the device (from _STA method)
+	 */
+	acpi_p = ctrl_p->hc_misc_data;
+	if (pciehpc_acpi_get_dev_state(acpi_p->slot_dev_obj,
+	    &dev_state) != AE_OK) {
+		cmn_err(CE_WARN, "failed to get device status on slot %d",
+		    slot_p->hs_phy_slot_num);
+	}
+	PCIE_DBG("(1)device state on slot #%d: 0x%x\n",
+	    slot_p->hs_phy_slot_num, dev_state);
+
+	curr_state = slot_p->hs_info.cn_state;
+	pciehpc_get_slot_state(slot_p);
+
+	switch (val) {
+	case 0: /* (re)enumerate the device */
+	case 3: /* Request Eject */
+	{
+		ddi_hp_cn_state_t target_state;
+
+		/*
+		 * Ignore the event if ATTN button is not present (ACPI BIOS
+		 * problem).
+		 *
+		 * NOTE: This situation has been observed on some platforms
+		 * where the ACPI BIOS is generating the event for some other
+		 * (non hot-plug) operations (bug).
+		 */
+		if (ctrl_p->hc_has_attn == B_FALSE) {
+			PCIE_DBG("Ignore the unexpected event "
+			    "on slot #%d (state 0x%x)",
+			    slot_p->hs_phy_slot_num, dev_state);
+			break;
+		}
+
+		/* send the event to DDI Hotplug framework */
+		if (curr_state < DDI_HP_CN_STATE_POWERED) {
+			/* Insertion. Upgrade state to ENABLED */
+			target_state = DDI_HP_CN_STATE_ENABLED;
+
+			/*
+			 * When pressing ATTN button to enable a card, the slot
+			 * could be powered. Keep the slot state on PWOERED
+			 * other than ENABLED.
+			 */
+			if (slot_p->hs_info.cn_state == DDI_HP_CN_STATE_ENABLED)
+				slot_p->hs_info.cn_state =
+				    DDI_HP_CN_STATE_POWERED;
+		} else {
+			/* Want to remove; Power off Connection */
+			target_state = DDI_HP_CN_STATE_EMPTY;
+		}
+
+		(void) ndi_hp_state_change_req(slot_p->hs_ctrl->hc_dip,
+		    slot_p->hs_info.cn_name,
+		    target_state, DDI_HP_REQ_ASYNC);
+
+		break;
+	}
+	default:
+		cmn_err(CE_NOTE, "Unknown Notify() event %d on slot #%d\n",
+		    val, slot_p->hs_phy_slot_num);
+		break;
+	}
+	mutex_exit(&ctrl_p->hc_mutex);
+}
+
+static void
+pciehpc_acpi_uninstall_event_handler(pcie_hp_ctrl_t *ctrl_p)
+{
+	pciehpc_acpi_t *acpi_p = ctrl_p->hc_misc_data;
+	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
+
+	PCIE_DBG("Uninstall event handler for slot #%d\n",
+	    slot_p->hs_phy_slot_num);
+	(void) AcpiRemoveNotifyHandler(acpi_p->slot_dev_obj,
+	    ACPI_SYSTEM_NOTIFY, pciehpc_acpi_notify_handler);
+	(void) AcpiRemoveNotifyHandler(acpi_p->bus_obj,
+	    ACPI_SYSTEM_NOTIFY, pciehpc_acpi_notify_handler);
+}
+
+/*
+ * Run _PS0 method to turn on power to the slot.
+ */
+static ACPI_STATUS
+pciehpc_acpi_power_on_slot(pcie_hp_ctrl_t *ctrl_p)
+{
+	int status = AE_OK;
+	pciehpc_acpi_t *acpi_p = ctrl_p->hc_misc_data;
+	int dev_state = 0;
+	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
+
+	PCIE_DBG("turn ON power to the slot #%d\n", slot_p->hs_phy_slot_num);
+
+	status = AcpiEvaluateObject(acpi_p->slot_dev_obj, "_PS0", NULL, NULL);
+
+	/* get the state of the device (from _STA method) */
+	if (status == AE_OK) {
+		if (pciehpc_acpi_get_dev_state(acpi_p->slot_dev_obj,
+		    &dev_state) != AE_OK)
+			cmn_err(CE_WARN, "failed to get device status "
+			    "on slot #%d", slot_p->hs_phy_slot_num);
+	}
+
+	PCIE_DBG("(3)device state on slot #%d: 0x%x\n",
+	    slot_p->hs_phy_slot_num, dev_state);
+
+	pciehpc_get_slot_state(slot_p);
+
+	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
+		cmn_err(CE_WARN, "failed to power on the slot #%d"
+		    "(dev_state 0x%x, ACPI_STATUS 0x%x)",
+		    slot_p->hs_phy_slot_num, dev_state, status);
+		return (AE_ERROR);
+	}
+
+	return (status);
+}
+
+/*
+ * Run _EJ0 method to turn off power to the slot.
+ */
+static ACPI_STATUS
+pciehpc_acpi_power_off_slot(pcie_hp_ctrl_t *ctrl_p)
+{
+	int status = AE_OK;
+	pciehpc_acpi_t *acpi_p = ctrl_p->hc_misc_data;
+	int dev_state = 0;
+	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
+
+	PCIE_DBG("turn OFF power to the slot #%d\n", slot_p->hs_phy_slot_num);
+
+	status = AcpiEvaluateObject(acpi_p->slot_dev_obj, "_EJ0", NULL, NULL);
+
+	/* get the state of the device (from _STA method) */
+	if (status == AE_OK) {
+		if (pciehpc_acpi_get_dev_state(acpi_p->slot_dev_obj,
+		    &dev_state) != AE_OK)
+			cmn_err(CE_WARN, "failed to get device status "
+			    "on slot #%d", slot_p->hs_phy_slot_num);
+	}
+
+	PCIE_DBG("(2)device state on slot #%d: 0x%x\n",
+	    slot_p->hs_phy_slot_num, dev_state);
+
+	pciehpc_get_slot_state(slot_p);
+
+	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
+		cmn_err(CE_WARN, "failed to power OFF the slot #%d"
+		    "(dev_state 0x%x, ACPI_STATUS 0x%x)",
+		    slot_p->hs_phy_slot_num, dev_state, status);
+		return (AE_ERROR);
+	}
+
+	return (status);
+}
+
+/*
+ * Get the status info (as returned by _STA method) for the device.
+ */
+static ACPI_STATUS
+pciehpc_acpi_get_dev_state(ACPI_HANDLE obj, int *statusp)
+{
+	ACPI_BUFFER	rb;
+	ACPI_DEVICE_INFO *info = NULL;
+	int ret = AE_OK;
+
+	/*
+	 * Get device info object
+	 */
+	rb.Length = ACPI_ALLOCATE_BUFFER;
+	rb.Pointer = NULL;
+	if ((ret = AcpiGetObjectInfo(obj, &rb)) != AE_OK)
+		return (ret);
+	info = (ACPI_DEVICE_INFO *)rb.Pointer;
+
+	if (info->Valid & ACPI_VALID_STA) {
+		*statusp = info->CurrentStatus;
+	} else {
+		/*
+		 * no _STA present; assume the device status is normal
+		 * (i.e present, enabled, shown in UI and functioning).
+		 * See section 6.3.7 of ACPI 3.0 spec.
+		 */
+		*statusp = STATUS_NORMAL;
+	}
+
+	AcpiOsFree(info);
+
+	return (ret);
+}
--- a/usr/src/uts/intel/io/pciex/pcieb_x86.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/intel/io/pciex/pcieb_x86.c	Mon Nov 02 15:58:28 2009 +0800
@@ -667,15 +667,3 @@
 
 	return (DDI_SUCCESS);
 }
-
-void
-pcieb_plat_ioctl_hotplug(dev_info_t *dip, int rv, int cmd)
-{
-	/*
-	 * like in attach, since hotplugging can change error registers,
-	 * we need to ensure that the proper bits are set on this port
-	 * after a configure operation
-	 */
-	if ((rv == HPC_SUCCESS) && (cmd == DEVCTL_AP_CONFIGURE))
-		pcieb_intel_error_workaround(dip);
-}
--- a/usr/src/uts/intel/pci_autoconfig/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/intel/pci_autoconfig/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -20,11 +20,9 @@
 #
 #
 # uts/intel/pci_autoconfig/Makefile
-# 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"
-#
 #	This makefile drives the production of the PCI autoconfiguration
 #	kernel module.
 #
@@ -40,10 +38,8 @@
 #	Define the module and object file sets.
 #
 MODULE		= pci_autoconfig
-OBJECTS		= $(PCI_AUTOCONFIG_OBJS:%=$(OBJS_DIR)/%) \
-		  $(PCI_STRING_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(PCI_AUTOCONFIG_OBJS:%.o=$(LINTS_DIR)/%.ln) \
-		  $(PCI_STRING_OBJS:%.o=$(LINTS_DIR)/%.ln)
+OBJECTS		= $(PCI_AUTOCONFIG_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(PCI_AUTOCONFIG_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_MISC_DIR)/$(MODULE)
 INC_PATH	+= -I$(UTSBASE)/i86pc
 
@@ -62,7 +58,7 @@
 #
 # Depends on acpica ACPI CA interpreter
 #
-LDFLAGS		+= -dy -N misc/acpica
+LDFLAGS		+= -dy -Nmisc/acpica -Nmisc/pcie
 
 #
 # For now, disable these lint checks; maintainers should endeavor
--- a/usr/src/uts/intel/pci_pci/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/intel/pci_pci/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -21,11 +21,9 @@
 #
 # uts/intel/pci_pci/Makefile
 #
-# 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"
-#
 #	This makefile drives the production of the pci_pci driver kernel module.
 #
 
@@ -57,9 +55,9 @@
 INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
 
 #
-# depends on misc/pcihp
+# depends on misc/pcie and misc/pcihp
 #
-LDFLAGS		+= -dy -Nmisc/pcihp -Nmisc/pcie
+LDFLAGS		+= -dy -Nmisc/pcie -Nmisc/pcihp
 
 #
 #	Override defaults to build a unique, local modstubs.o.
--- a/usr/src/uts/intel/pcicfg/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/intel/pcicfg/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -20,11 +20,9 @@
 #
 #
 # uts/intel/pcicfg/Makefile
-# 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 makefile drives the production of the kernel/misc/pcicfg module
 #	(PCI configurator module) for PCI hotplug support in PCI nexus
 #	drivers.
@@ -67,7 +65,7 @@
 #
 #	Dependency
 #
-LDFLAGS		+= -dy -Nmisc/busra
+LDFLAGS		+= -dy -Nmisc/busra -Nmisc/pcie
 
 #
 # For now, disable these lint checks; maintainers should endeavor
--- a/usr/src/uts/intel/pcieb/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/intel/pcieb/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -55,14 +55,9 @@
 INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
 
 #
-# depends on misc/pcihp and misc/pcie
+# depends on misc/pcie
 #
-# For PCI Hotplug support, the misc/pcihp module provides devctl control
-# device and cb_ops functions to support hotplug operations.
-#
-# pcie supplies PCI Express fabric error support
-#
-LDFLAGS		+= -dy -Nmisc/pcihp -Nmisc/pcie
+LDFLAGS		+= -dy -Nmisc/pcie
 
 #
 #	Override defaults to build a unique, local modstubs.o.
--- a/usr/src/uts/intel/pciehpc/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +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 2007 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
-#	This makefile drives the production of the kernel/misc/pciehpc module
-#	for PCI-E hotplug controller support in PCI-E nexus drivers.
-#
-#	intel architecture dependent
-#
-
-#
-#	Path to the base of the uts directory tree (usually /usr/src/uts).
-#
-UTSBASE	= ../..
-
-#
-#	Define the module and object file sets.
-#
-MODULE		= pciehpc
-OBJECTS		= $(PCIEHPCNEXUS_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(PCIEHPCNEXUS_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_MISC_DIR)/$(MODULE)
-
-#
-#	Include common rules.
-#
-include $(UTSBASE)/intel/Makefile.intel
-
-#
-#	Define targets
-#
-ALL_TARGET	= $(BINARY)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
-
-#
-# depends on misc/hpcsvc, misc/acpica and misc/pcie
-#
-# For Hotplug support, the misc/hpcsvc module provides various hooks
-# to support hotplug operations.
-#
-# acpica supplies ACPI access routines
-#
-# pcie supplies PCI Express fabric error support
-#
-
-#
-LDFLAGS		+= -dy -Nmisc/hpcsvc -Nmisc/acpica -Nmisc/pcie
-
-#
-# 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_STATIC_UNUSED
-
-#
-#	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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/sys/hotplug/pci/pciehpc_acpi.h	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,78 @@
+/*
+ * 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	_PCIEHPC_ACPI_H
+#define	_PCIEHPC_ACPI_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/acpi/acpi.h>
+#include <sys/acpica.h>
+#include <sys/hotplug/pci/pcie_hp.h>
+#include <sys/hotplug/pci/pciehpc.h>
+
+/* soft state data structure for ACPI hot plug mode */
+typedef struct pciehpc_acpi {
+	/* handle for the ACPI device for the bus node with HPC */
+	ACPI_HANDLE	bus_obj;
+
+	/* handle for the ACPI device for the slot (dev#0,func#0) */
+	ACPI_HANDLE	slot_dev_obj;
+
+	/* ACPI control methods present on the bus node */
+	uint16_t	bus_methods;
+
+	/* ACPI control methods on the slot device functions */
+	uint16_t	slot_methods;
+} pciehpc_acpi_t;
+
+/* bit definitions in acpi_bus_methods */
+#define	PCIEHPC_ACPI_OSC_PRESENT	0x0001
+#define	PCIEHPC_ACPI_OSHP_PRESENT	0x0002
+#define	PCIEHPC_ACPI_SUN_PRESENT	0x0004
+#define	PCIEHPC_ACPI_STA_PRESENT	0x0008
+#define	PCIEHPC_ACPI_EJ0_PRESENT	0x0010
+#define	PCIEHPC_ACPI_HPP_PRESENT	0x0020
+#define	PCIEHPC_ACPI_HPX_PRESENT	0x0040
+#define	PCIEHPC_ACPI_PS0_PRESENT	0x0080
+#define	PCIEHPC_ACPI_DSM_PRESENT	0x0080
+#define	PCIEHPC_ACPI_STR_PRESENT	0x0100
+
+/* Device status bit as returned by _STA method (see 6.3.7 of ACPI 3.0) */
+#define	DEV_STS_PRESENT		0x1	/* device is present */
+#define	DEV_STS_ENABLED		0x2	/* device is enabled */
+#define	DEV_STS_SHOWN_UI	0x4	/* device should be shown in UI */
+#define	DEV_STS_FUNC_OK		0x8	/* device functioning normally */
+#define	STATUS_NORMAL	\
+	(DEV_STS_PRESENT | DEV_STS_ENABLED | DEV_STS_SHOWN_UI | DEV_STS_FUNC_OK)
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _PCIEHPC_ACPI_H */
--- a/usr/src/uts/sparc/Makefile.files	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sparc/Makefile.files	Mon Nov 02 15:58:28 2009 +0800
@@ -90,7 +90,7 @@
 	kobj_reloc.o
 
 SWAPGENERIC_OBJS += swapgeneric.o
-PCICFG_E_OBJS	+= pcicfg.e.o
+PCICFG_OBJS	+= pcicfg.o
 FCPCI_OBJS	+= fcpci.o
 FCODEM_OBJS	+= fc_ddi.o fc_physio.o fc_ops.o fc_subr.o
 
--- a/usr/src/uts/sparc/Makefile.sparc.shared	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sparc/Makefile.sparc.shared	Mon Nov 02 15:58:28 2009 +0800
@@ -399,7 +399,7 @@
 MISC_KMODS	+= fssnap_if
 MISC_KMODS	+= hidparser kbtrans usba usba10 usbs49_fw
 MISC_KMODS	+= s1394
-MISC_KMODS	+= hpcsvc pcihp pciehpc pcishpc
+MISC_KMODS	+= hpcsvc pcihp
 MISC_KMODS	+= rsmops
 MISC_KMODS	+= kcf
 MISC_KMODS	+= ksocket
@@ -416,7 +416,7 @@
 MISC_KMODS	+= mac dls
 MISC_KMODS	+= cmlb
 MISC_KMODS	+= tem
-MISC_KMODS	+= pcicfg.e fcodem fcpci
+MISC_KMODS	+= pcicfg fcodem fcpci
 MISC_KMODS	+= scsi_vhci_f_sym scsi_vhci_f_tpgs scsi_vhci_f_asym_sun
 MISC_KMODS	+= scsi_vhci_f_sym_hds
 MISC_KMODS	+= scsi_vhci_f_tape scsi_vhci_f_tpgs_tape
--- a/usr/src/uts/sparc/io/pciex/pcieb_sparc.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sparc/io/pciex/pcieb_sparc.c	Mon Nov 02 15:58:28 2009 +0800
@@ -95,8 +95,10 @@
 
 	intr = hdlp->ih_vector;
 
+	d = (pcie_ari_is_enabled(dip) == PCIE_ARI_FORW_ENABLED) ? 0 :
+	    PCI_REG_DEV_G(pci_rp[0].pci_phys_hi);
+
 	/* spin the interrupt */
-	d = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi);
 	if ((intr >= PCI_INTA) && (intr <= PCI_INTD))
 		hdlp->ih_vector = ((intr - 1 + (d % 4)) % 4 + 1);
 	else
@@ -156,12 +158,6 @@
 	return (DDI_SUCCESS);
 }
 
-/*ARGSUSED*/
-void
-pcieb_plat_ioctl_hotplug(dev_info_t *dip, int rv, int cmd)
-{
-}
-
 void
 pcieb_plat_initchild(dev_info_t *child)
 {
@@ -201,11 +197,17 @@
 	uint_t		bus_num, primary, secondary;
 	uint8_t		dev_type = bus_p->bus_dev_type;
 	uint16_t	vendor_id = bus_p->bus_dev_ven_id & 0xFFFF;
+	uint16_t	device_id = bus_p->bus_dev_ven_id >> 16;
 	int 		ce_mask = 0;
 
 	if (!IS_PLX_VENDORID(vendor_id))
 		return;
 
+	if ((device_id == PXB_DEVICE_PLX_8532) &&
+	    (bus_p->bus_rev_id <= PXB_DEVICE_PLX_AA_REV))
+		/* Clear hotplug capability */
+		bus_p->bus_hp_sup_modes = PCIE_NONE_HP_MODE;
+
 	/*
 	 * Due to a PLX HW bug we need to disable the receiver error CE on all
 	 * ports. To this end we create a property "pcie_ce_mask" with value
--- a/usr/src/uts/sparc/ml/modstubs.s	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sparc/ml/modstubs.s	Mon Nov 02 15:58:28 2009 +0800
@@ -1028,35 +1028,13 @@
 #endif
 
 /*
- * Stubs for PCI configurator module (misc/pcicfg.e).
- */
-#ifndef	PCICFG_E_MODULE
-	MODULE(pcicfg.e,misc);
-	STUB(pcicfg.e, pcicfg_configure, 0);
-	STUB(pcicfg.e, pcicfg_unconfigure, 0);
-	END_MODULE(pcicfg.e);
-#endif
-
-/*
- * Stubs for PCIEHPC (pci-ex hot plug support) module (misc/pciehpc).
+ * Stubs for PCI configurator module (misc/pcicfg).
  */
-#ifndef	PCIEHPC_MODULE
-	MODULE(pciehpc,misc);
-	STUB(pciehpc, pciehpc_init, 0);
-	STUB(pciehpc, pciehpc_uninit, 0);
-	WSTUB(pciehpc, pciehpc_intr, 0);
-	END_MODULE(pciehpc);
-#endif
-
-/*
- * Stubs for PCISHPC (pci/pci-x shpc hot plug support) module (misc/pcishpc).
- */
-#ifndef	PCISHPC_MODULE
-	MODULE(pcishpc,misc);
-	STUB(pcishpc, pcishpc_init, 0);
-	STUB(pcishpc, pcishpc_uninit, 0);
-	WSTUB(pcishpc, pcishpc_intr, 0);
-	END_MODULE(pcishpc);
+#ifndef	PCICFG_MODULE
+	MODULE(pcicfg,misc);
+	STUB(pcicfg, pcicfg_configure, 0);
+	STUB(pcicfg, pcicfg_unconfigure, 0);
+	END_MODULE(pcicfg);
 #endif
 
 #ifndef PCIHP_MODULE
--- a/usr/src/uts/sparc/pci_pci/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sparc/pci_pci/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -19,11 +19,9 @@
 # CDDL HEADER END
 #
 # uts/sparc/pci_pci/Makefile
-# 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 makefile drives the production of the pci driver kernel module
 #
 #	sparc implementation architecture dependent
@@ -83,7 +81,7 @@
 #
 #	Dependency
 #
-LDFLAGS += -dy -Nmisc/pcie
+LDFLAGS += -dy -Nmisc/pcie -Nmisc/pcihp
 
 #
 #	Default build targets.
--- a/usr/src/uts/sparc/pcicfg.e/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +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/pcicfg.e/Makefile
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
-#	This makefile drives the production of the EFCode Enabled
-#	PCI Configurator.
-#
-#	sun4 implementation architecture dependent
-#
-
-#
-#	Path to the base of the uts directory tree (usually /usr/src/uts).
-#
-UTSBASE	= ../..
-
-#
-#	Define the module and object file sets.
-#
-MODULE		= pcicfg.e
-OBJECTS		= $(PCICFG_E_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(PCICFG_E_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_MISC_DIR)/$(MODULE)
-
-#
-#	Include common rules.
-#
-include $(UTSBASE)/sparc/Makefile.sparc
-
-#
-#	Define targets
-#
-ALL_TARGET	= $(BINARY)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
-
-#
-#       Include sun4 specific headers files
-#
-INC_PATH	+= -I$(UTSBASE)/sun4
-
-
-# Turn this on once compiler understands v9 in it's backend
-#INLINES		+= $(UTSBASE)/sun4u/io/pcicfg.il
-
-#
-# lint pass one enforcement
-#
-CFLAGS += $(CCVERBOSE)
-
-#
-# Turn on doubleword alignment for 64 bit registers
-#
-CFLAGS += -dalign -DPCICFG_INTERPRET_FCODE
-
-#
-#	Dependency
-LDFLAGS += -dy -Nmisc/busra -Nmisc/fcpci -Nmisc/fcodem -Nmisc/pcie
-
-#
-# 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_ASSIGN_NARROW_CONV
-LINTTAGS	+= -erroff=E_STATIC_UNUSED
-
-#
-#	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)/sparc/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/pcicfg/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,113 @@
+#
+# 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/pcicfg/Makefile
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#	This makefile drives the production of the EFCode Enabled
+#	PCI Configurator.
+#
+#	sun4 implementation architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= pcicfg
+OBJECTS		= $(PCICFG_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(PCICFG_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_MISC_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sparc/Makefile.sparc
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+#       Include sun4 specific headers files
+#
+INC_PATH	+= -I$(UTSBASE)/sun4
+
+
+# Turn this on once compiler understands v9 in it's backend
+#INLINES		+= $(UTSBASE)/sun4u/io/pcicfg.il
+
+#
+# lint pass one enforcement
+#
+CFLAGS += $(CCVERBOSE)
+
+#
+# Turn on doubleword alignment for 64 bit registers
+#
+CFLAGS += -dalign -DPCICFG_INTERPRET_FCODE
+
+#
+#	Dependency
+LDFLAGS += -dy -Nmisc/busra -Nmisc/fcpci -Nmisc/fcodem -Nmisc/pcie
+
+#
+# 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_ASSIGN_NARROW_CONV
+LINTTAGS	+= -erroff=E_STATIC_UNUSED
+
+#
+#	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)/sparc/Makefile.targ
--- a/usr/src/uts/sparc/pcie/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sparc/pcie/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -23,7 +23,6 @@
 # Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#
 #	This makefile drives the production of the PCIE driver kernel module.
 #
 #	sparc architecture dependent
@@ -38,8 +37,10 @@
 #	Define the module and object file sets.
 #
 MODULE		= pcie
-OBJECTS		= $(PCIE_MISC_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(PCIE_MISC_OBJS:%.o=$(LINTS_DIR)/%.ln)
+OBJECTS		= $(PCIE_MISC_OBJS:%=$(OBJS_DIR)/%) \
+		  $(PCI_STRING_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(PCIE_MISC_OBJS:%.o=$(LINTS_DIR)/%.ln) \
+		  $(PCI_STRING_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_MISC_DIR)/$(MODULE)
 
 #
@@ -60,6 +61,11 @@
 CFLAGS += $(CCVERBOSE)
 
 #
+#	Dependency
+#
+LDFLAGS += -dy -Nmisc/busra
+
+#
 # Overrides
 #
 MODSTUBS_DIR	= $(OBJS_DIR)
--- a/usr/src/uts/sparc/pcieb/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sparc/pcieb/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -74,7 +74,7 @@
 #
 #	Dependency
 #
-LDFLAGS += -dy -Nmisc/pcie -Nmisc/pcishpc -Nmisc/pcihp -Nmisc/pciehpc
+LDFLAGS += -dy -Nmisc/pcie
 
 #
 # For now, disable these lint checks; maintainers should endeavor
--- a/usr/src/uts/sparc/pcieb_bcm/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sparc/pcieb_bcm/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -69,12 +69,12 @@
 # Enable Broadcom 5714/5715 workaround code and lint duplicate symbol
 # avoidance hack
 #
-CPPFLAGS += -DBCM_SW_WORKAROUNDS -DPX_MOD_NAME=pcieb_bcm
+CPPFLAGS += -DPCIEB_BCM -DPX_MOD_NAME=pcieb_bcm
 
 #
 #	Dependency
 #
-LDFLAGS += -dy -Nmisc/pcie -Nmisc/pcishpc -Nmisc/pcihp -Nmisc/pciehpc
+LDFLAGS += -dy -Nmisc/pcie
 
 #
 # For now, disable these lint checks; maintainers should endeavor
--- a/usr/src/uts/sparc/pciehpc/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +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/pciehpc/Makefile
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
-#	This makefile drives the production of the kernel/misc/pciehpc module
-#	(PCIe hotplug controller module) for PCIe hotplug support in PCIe nexus
-#	drivers.
-#
-
-#
-#	Path to the base of the uts directory tree (usually /usr/src/uts).
-#
-UTSBASE	= ../..
-
-#
-#	Define the module and object file sets.
-#
-MODULE		= pciehpc
-OBJECTS		= $(PCIEHPCNEXUS_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(PCIEHPCNEXUS_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_MISC_DIR)/$(MODULE)
-
-#
-#	Include common rules.
-
-include $(UTSBASE)/sparc/Makefile.sparc
-
-#
-#	Define targets
-#
-ALL_TARGET	= $(BINARY)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
-
-#
-#	Dependency
-LDFLAGS		+= -dy -Nmisc/hpcsvc -Nmisc/pcie
-
-#
-# 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
-
-#
-#	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)/sparc/Makefile.targ
--- a/usr/src/uts/sparc/pcihp/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sparc/pcihp/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -20,11 +20,9 @@
 #
 #
 # uts/sparc/pcihp/Makefile
-# 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 makefile drives the production of the kernel/misc/pcihp module
 #	for PCI hotplug support in PCI nexus drivers.
 #
@@ -70,7 +68,7 @@
 
 #
 #	Dependency
-LDFLAGS		+= -dy -Nmisc/busra -Nmisc/hpcsvc -Nmisc/pcicfg.e
+LDFLAGS		+= -dy -Nmisc/busra -Nmisc/hpcsvc -Nmisc/pcicfg
 
 #
 # For now, disable these lint checks; maintainers should endeavor
--- a/usr/src/uts/sparc/pcishpc/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +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/pcishpc/Makefile
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
-#	This makefile drives the production of the kernel/misc/pcishpc module
-#	(PCI SHPC hotplug controller module) for PCI hotplug support in PCI
-#	nexus drivers.
-#
-
-#
-#	Path to the base of the uts directory tree (usually /usr/src/uts).
-#
-UTSBASE	= ../..
-
-#
-#	Define the module and object file sets.
-#
-MODULE		= pcishpc
-OBJECTS		= $(PCISHPC_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(PCISHPC_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_MISC_DIR)/$(MODULE)
-
-#
-#	Include common rules.
-
-include $(UTSBASE)/sparc/Makefile.sparc
-
-#
-#	Define targets
-#
-ALL_TARGET	= $(BINARY)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
-
-#
-#	Dependency
-LDFLAGS		+= -dy -Nmisc/hpcsvc
-
-#
-# 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_STATIC_UNUSED
-
-#
-#	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)/sparc/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4/io/pcicfg.c	Mon Nov 02 15:58:28 2009 +0800
@@ -0,0 +1,6755 @@
+/*
+ * 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.
+ */
+
+/*
+ *     PCI configurator (pcicfg)
+ */
+
+#include <sys/isa_defs.h>
+
+#include <sys/conf.h>
+#include <sys/kmem.h>
+#include <sys/debug.h>
+#include <sys/modctl.h>
+#include <sys/autoconf.h>
+#include <sys/hwconf.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/fcode.h>
+#include <sys/pci.h>
+#include <sys/pcie.h>
+#include <sys/pcie_impl.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/pci_cap.h>
+#include <sys/hotplug/pci/pcicfg.h>
+#include <sys/ndi_impldefs.h>
+
+#define	PCICFG_DEVICE_TYPE_PCI	1
+#define	PCICFG_DEVICE_TYPE_PCIE	2
+
+#define	EFCODE21554	/* changes for supporting 21554 */
+
+static int pcicfg_alloc_resource(dev_info_t *, pci_regspec_t);
+static int pcicfg_free_resource(dev_info_t *, pci_regspec_t, pcicfg_flags_t);
+static int pcicfg_remove_assigned_prop(dev_info_t *, pci_regspec_t *);
+
+#ifdef	PCICFG_INTERPRET_FCODE
+static int pcicfg_fcode_assign_bars(ddi_acc_handle_t, dev_info_t *,
+    uint_t, uint_t, uint_t, int32_t, pci_regspec_t *);
+#endif	/* PCICFG_INTERPRET_FCODE */
+
+/*
+ * ************************************************************************
+ * *** Implementation specific local data structures/definitions.	***
+ * ************************************************************************
+ */
+
+static	int	pcicfg_start_devno = 0;	/* for Debug only */
+
+#define	PCICFG_MAX_DEVICE 32
+#define	PCICFG_MAX_FUNCTION 8
+#define	PCICFG_MAX_ARI_FUNCTION 256
+#define	PCICFG_MAX_REGISTER 64
+#define	PCICFG_MAX_BUS_DEPTH 255
+
+#define	PCICFG_NODEVICE 42
+#define	PCICFG_NOMEMORY 43
+#define	PCICFG_NOMULTI	44
+
+#define	PCICFG_HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32))
+#define	PCICFG_LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
+#define	PCICFG_LADDR(lo, hi)	(((uint64_t)(hi) << 32) | (uint32_t)(lo))
+
+#define	PCICFG_HIWORD(n) ((uint16_t)(((uint32_t)(n) & 0xFFFF0000)>> 16))
+#define	PCICFG_LOWORD(n) ((uint16_t)((uint32_t)(n) & 0x0000FFFF))
+#define	PCICFG_HIBYTE(n) ((uint8_t)(((uint16_t)(n) & 0xFF00)>> 8))
+#define	PCICFG_LOBYTE(n) ((uint8_t)((uint16_t)(n) & 0x00FF))
+
+#define	PCICFG_ROUND_UP(addr, gran) ((uintptr_t)((gran+addr-1)&(~(gran-1))))
+#define	PCICFG_ROUND_DOWN(addr, gran) ((uintptr_t)((addr) & ~(gran-1)))
+
+#define	PCICFG_MEMGRAN 0x100000
+#define	PCICFG_IOGRAN 0x1000
+#define	PCICFG_4GIG_LIMIT 0xFFFFFFFFUL
+
+#define	PCICFG_MEM_MULT 4
+#define	PCICFG_IO_MULT 4
+#define	PCICFG_RANGE_LEN 2 /* Number of range entries */
+
+static int pcicfg_slot_busnums = 8;
+static int pcicfg_slot_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
+static int pcicfg_slot_iosize = 16 * PCICFG_IOGRAN; /* 64K per slot */
+static int pcicfg_chassis_per_tree = 1;
+static int pcicfg_sec_reset_delay = 1000000;
+
+/*
+ * The following typedef is used to represent a
+ * 1275 "bus-range" property of a PCI Bus node.
+ * DAF - should be in generic include file...
+ */
+
+typedef struct pcicfg_bus_range {
+	uint32_t lo;
+	uint32_t hi;
+} pcicfg_bus_range_t;
+
+typedef struct pcicfg_range {
+
+	uint32_t child_hi;
+	uint32_t child_mid;
+	uint32_t child_lo;
+	uint32_t parent_hi;
+	uint32_t parent_mid;
+	uint32_t parent_lo;
+	uint32_t size_hi;
+	uint32_t size_lo;
+
+} pcicfg_range_t;
+
+typedef struct hole hole_t;
+
+struct hole {
+	uint64_t	start;
+	uint64_t	len;
+	hole_t		*next;
+};
+
+typedef struct pcicfg_phdl pcicfg_phdl_t;
+
+struct pcicfg_phdl {
+
+	dev_info_t	*dip;		/* Associated with the attach point */
+	pcicfg_phdl_t	*next;
+
+	uint64_t	memory_base;	/* Memory base for this attach point */
+	uint64_t	memory_last;
+	uint64_t	memory_len;
+	uint32_t	io_base;	/* I/O base for this attach point */
+	uint32_t	io_last;
+	uint32_t	io_len;
+
+	int		error;
+	uint_t		highest_bus;	/* Highest bus seen on the probe */
+
+	hole_t		mem_hole;	/* Memory hole linked list. */
+	hole_t		io_hole;	/* IO hole linked list */
+
+	ndi_ra_request_t mem_req;	/* allocator request for memory */
+	ndi_ra_request_t io_req;	/* allocator request for I/O */
+};
+
+struct pcicfg_standard_prop_entry {
+    uchar_t *name;
+    uint_t  config_offset;
+    uint_t  size;
+};
+
+
+struct pcicfg_name_entry {
+    uint32_t class_code;
+    char  *name;
+};
+
+struct pcicfg_find_ctrl {
+	uint_t		device;
+	uint_t		function;
+	dev_info_t	*dip;
+};
+
+typedef struct pcicfg_err_regs {
+	uint16_t cmd;
+	uint16_t bcntl;
+	uint16_t pcie_dev;
+	uint16_t devctl;
+	uint16_t pcie_cap_off;
+} pcicfg_err_regs_t;
+
+/*
+ * List of Indirect Config Map Devices. At least the intent of the
+ * design is to look for a device in this list during the configure
+ * operation, and if the device is listed here, then it is a nontransparent
+ * bridge, hence load the driver and avail the config map services from
+ * the driver. Class and Subclass should be as defined in the PCI specs
+ * ie. class is 0x6, and subclass is 0x9.
+ */
+static struct {
+	uint8_t		mem_range_bar_offset;
+	uint8_t		io_range_bar_offset;
+	uint8_t		prefetch_mem_range_bar_offset;
+} pcicfg_indirect_map_devs[] = {
+	PCI_CONF_BASE3, PCI_CONF_BASE2, PCI_CONF_BASE3,
+	0,	0,	0,
+};
+
+#define	PCICFG_MAKE_REG_HIGH(busnum, devnum, funcnum, register)\
+	(\
+	((ulong_t)(busnum & 0xff) << 16)    |\
+	((ulong_t)(devnum & 0x1f) << 11)    |\
+	((ulong_t)(funcnum & 0x7) <<  8)    |\
+	((ulong_t)(register & 0x3f)))
+
+/*
+ * debug macros:
+ */
+#if	defined(DEBUG)
+extern void prom_printf(const char *, ...);
+
+/*
+ * Following values are defined for this debug flag.
+ *
+ * 1 = dump configuration header only.
+ * 2 = dump generic debug data only (no config header dumped)
+ * 3 = dump everything (both 1 and 2)
+ */
+int pcicfg_debug = 0;
+int pcicfg_dump_fcode = 0;
+
+static void debug(char *, uintptr_t, uintptr_t,
+	uintptr_t, uintptr_t, uintptr_t);
+
+#define	DEBUG0(fmt)\
+	debug(fmt, 0, 0, 0, 0, 0);
+#define	DEBUG1(fmt, a1)\
+	debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
+#define	DEBUG2(fmt, a1, a2)\
+	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
+#define	DEBUG3(fmt, a1, a2, a3)\
+	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
+		(uintptr_t)(a3), 0, 0);
+#define	DEBUG4(fmt, a1, a2, a3, a4)\
+	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
+		(uintptr_t)(a3), (uintptr_t)(a4), 0);
+#else
+#define	DEBUG0(fmt)
+#define	DEBUG1(fmt, a1)
+#define	DEBUG2(fmt, a1, a2)
+#define	DEBUG3(fmt, a1, a2, a3)
+#define	DEBUG4(fmt, a1, a2, a3, a4)
+#endif
+
+#ifdef PCICFG_INTERPRET_FCODE
+int pcicfg_dont_interpret = 0;
+#else
+int pcicfg_dont_interpret = 1;
+#endif
+
+/*
+ * forward declarations for routines defined in this module (called here)
+ */
+
+static int pcicfg_add_config_reg(dev_info_t *,
+    uint_t, uint_t, uint_t);
+static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t,
+    uint_t *, pcicfg_flags_t);
+
+#ifdef PCICFG_INTERPRET_FCODE
+static int pcicfg_load_fcode(dev_info_t *, uint_t, uint_t, uint_t,
+	uint16_t, uint16_t, uchar_t **, int *, int, int);
+#endif
+
+static int pcicfg_fcode_probe(dev_info_t *, uint_t, uint_t, uint_t,
+    uint_t *, pcicfg_flags_t);
+static int pcicfg_probe_bridge(dev_info_t *, ddi_acc_handle_t, uint_t,
+    uint_t *);
+static int pcicfg_free_all_resources(dev_info_t *);
+static int pcicfg_alloc_new_resources(dev_info_t *);
+static int pcicfg_match_dev(dev_info_t *, void *);
+static dev_info_t *pcicfg_devi_find(dev_info_t *, uint_t, uint_t);
+static pcicfg_phdl_t *pcicfg_find_phdl(dev_info_t *);
+static pcicfg_phdl_t *pcicfg_create_phdl(dev_info_t *);
+static int pcicfg_destroy_phdl(dev_info_t *);
+static int pcicfg_sum_resources(dev_info_t *, void *);
+static int pcicfg_find_resource_end(dev_info_t *, void *);
+static int pcicfg_allocate_chunk(dev_info_t *);
+static int pcicfg_program_ap(dev_info_t *);
+static int pcicfg_device_assign(dev_info_t *);
+static int pcicfg_bridge_assign(dev_info_t *, void *);
+static int pcicfg_device_assign_readonly(dev_info_t *);
+static int pcicfg_free_resources(dev_info_t *, pcicfg_flags_t);
+static void pcicfg_setup_bridge(pcicfg_phdl_t *, ddi_acc_handle_t,
+    dev_info_t *);
+static void pcicfg_update_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
+static void pcicfg_enable_bridge_probe_err(dev_info_t *dip,
+				ddi_acc_handle_t h, pcicfg_err_regs_t *regs);
+static void pcicfg_disable_bridge_probe_err(dev_info_t *dip,
+				ddi_acc_handle_t h, pcicfg_err_regs_t *regs);
+static int pcicfg_update_assigned_prop(dev_info_t *, pci_regspec_t *);
+static void pcicfg_device_on(ddi_acc_handle_t);
+static void pcicfg_device_off(ddi_acc_handle_t);
+static int pcicfg_set_busnode_props(dev_info_t *, uint8_t, int, int);
+static int pcicfg_free_bridge_resources(dev_info_t *);
+static int pcicfg_free_device_resources(dev_info_t *, pcicfg_flags_t);
+static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t);
+static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *);
+static void pcicfg_config_teardown(ddi_acc_handle_t *);
+static void pcicfg_get_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
+static void pcicfg_get_io(pcicfg_phdl_t *, uint32_t, uint32_t *);
+static int pcicfg_update_ranges_prop(dev_info_t *, pcicfg_range_t *);
+static int pcicfg_map_phys(dev_info_t *, pci_regspec_t *, caddr_t *,
+    ddi_device_acc_attr_t *, ddi_acc_handle_t *);
+static void pcicfg_unmap_phys(ddi_acc_handle_t *, pci_regspec_t *);
+static int pcicfg_dump_assigned(dev_info_t *);
+static uint_t pcicfg_configure_ntbridge(dev_info_t *, uint_t, uint_t);
+static int pcicfg_indirect_map(dev_info_t *dip);
+static uint_t pcicfg_get_ntbridge_child_range(dev_info_t *, uint64_t *,
+				uint64_t *, uint_t);
+static int pcicfg_is_ntbridge(dev_info_t *);
+static int pcicfg_ntbridge_allocate_resources(dev_info_t *);
+static int pcicfg_ntbridge_configure_done(dev_info_t *);
+static int pcicfg_ntbridge_unconfigure(dev_info_t *);
+static int pcicfg_ntbridge_unconfigure_child(dev_info_t *, uint_t);
+static void pcicfg_free_hole(hole_t *);
+static uint64_t pcicfg_alloc_hole(hole_t *, uint64_t *, uint32_t);
+static int pcicfg_update_available_prop(dev_info_t *, pci_regspec_t *);
+static int pcicfg_ari_configure(dev_info_t *);
+static int pcicfg_populate_reg_props(dev_info_t *, ddi_acc_handle_t);
+static int pcicfg_populate_props_from_bar(dev_info_t *, ddi_acc_handle_t);
+static int pcicfg_update_assigned_prop_value(dev_info_t *, uint32_t,
+    uint32_t, uint32_t, uint_t);
+
+#ifdef DEBUG
+static void pcicfg_dump_common_config(ddi_acc_handle_t config_handle);
+static void pcicfg_dump_device_config(ddi_acc_handle_t);
+
+static void pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle);
+static uint64_t pcicfg_unused_space(hole_t *, uint32_t *);
+
+#define	PCICFG_DUMP_COMMON_CONFIG(hdl) (void)pcicfg_dump_common_config(hdl)
+#define	PCICFG_DUMP_DEVICE_CONFIG(hdl) (void)pcicfg_dump_device_config(hdl)
+#define	PCICFG_DUMP_BRIDGE_CONFIG(hdl) (void)pcicfg_dump_bridge_config(hdl)
+#else
+#define	PCICFG_DUMP_COMMON_CONFIG(handle)
+#define	PCICFG_DUMP_DEVICE_CONFIG(handle)
+#define	PCICFG_DUMP_BRIDGE_CONFIG(handle)
+#endif
+
+static kmutex_t pcicfg_list_mutex; /* Protects the probe handle list */
+static pcicfg_phdl_t *pcicfg_phdl_list = NULL;
+
+#ifndef _DONT_USE_1275_GENERIC_NAMES
+/*
+ * Class code table
+ */
+static struct pcicfg_name_entry pcicfg_class_lookup [] = {
+
+	{ 0x001, "display" },
+	{ 0x100, "scsi" },
+	{ 0x101, "ide" },
+	{ 0x102, "fdc" },
+	{ 0x103, "ipi" },
+	{ 0x104, "raid" },
+	{ 0x200, "ethernet" },
+	{ 0x201, "token-ring" },
+	{ 0x202, "fddi" },
+	{ 0x203, "atm" },
+	{ 0x300, "display" },
+	{ 0x400, "video" },
+	{ 0x401, "sound" },
+	{ 0x500, "memory" },
+	{ 0x501, "flash" },
+	{ 0x600, "host" },
+	{ 0x601, "isa" },
+	{ 0x602, "eisa" },
+	{ 0x603, "mca" },
+	{ 0x604, "pci" },
+	{ 0x605, "pcmcia" },
+	{ 0x606, "nubus" },
+	{ 0x607, "cardbus" },
+	{ 0x609, "pci" },
+	{ 0x700, "serial" },
+	{ 0x701, "parallel" },
+	{ 0x800, "interrupt-controller" },
+	{ 0x801, "dma-controller" },
+	{ 0x802, "timer" },
+	{ 0x803, "rtc" },
+	{ 0x900, "keyboard" },
+	{ 0x901, "pen" },
+	{ 0x902, "mouse" },
+	{ 0xa00, "dock" },
+	{ 0xb00, "cpu" },
+	{ 0xc00, "firewire" },
+	{ 0xc01, "access-bus" },
+	{ 0xc02, "ssa" },
+	{ 0xc03, "usb" },
+	{ 0xc04, "fibre-channel" },
+	{ 0, 0 }
+};
+#endif /* _DONT_USE_1275_GENERIC_NAMES */
+
+/*
+ * Module control operations
+ */
+
+extern struct mod_ops mod_miscops;
+
+static struct modlmisc modlmisc = {
+	&mod_miscops, /* Type of module */
+	"PCIe/PCI Config (EFCode Enabled)"
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1, (void *)&modlmisc, NULL
+};
+
+#ifdef DEBUG
+
+static void
+pcicfg_dump_common_config(ddi_acc_handle_t config_handle)
+{
+	if ((pcicfg_debug & 1) == 0)
+		return;
+	cmn_err(CE_CONT, " Vendor ID   = [0x%x]\n",
+	    pci_config_get16(config_handle, PCI_CONF_VENID));
+	cmn_err(CE_CONT, " Device ID   = [0x%x]\n",
+	    pci_config_get16(config_handle, PCI_CONF_DEVID));
+	cmn_err(CE_CONT, " Command REG = [0x%x]\n",
+	    pci_config_get16(config_handle, PCI_CONF_COMM));
+	cmn_err(CE_CONT, " Status  REG = [0x%x]\n",
+	    pci_config_get16(config_handle, PCI_CONF_STAT));
+	cmn_err(CE_CONT, " Revision ID = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_REVID));
+	cmn_err(CE_CONT, " Prog Class  = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
+	cmn_err(CE_CONT, " Dev Class   = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_SUBCLASS));
+	cmn_err(CE_CONT, " Base Class  = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_BASCLASS));
+	cmn_err(CE_CONT, " Device ID   = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ));
+	cmn_err(CE_CONT, " Header Type = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_HEADER));
+	cmn_err(CE_CONT, " BIST        = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_BIST));
+	cmn_err(CE_CONT, " BASE 0      = [0x%x]\n",
+	    pci_config_get32(config_handle, PCI_CONF_BASE0));
+	cmn_err(CE_CONT, " BASE 1      = [0x%x]\n",
+	    pci_config_get32(config_handle, PCI_CONF_BASE1));
+
+}
+
+static void
+pcicfg_dump_device_config(ddi_acc_handle_t config_handle)
+{
+	if ((pcicfg_debug & 1) == 0)
+		return;
+	pcicfg_dump_common_config(config_handle);
+
+	cmn_err(CE_CONT, " BASE 2      = [0x%x]\n",
+	    pci_config_get32(config_handle, PCI_CONF_BASE2));
+	cmn_err(CE_CONT, " BASE 3      = [0x%x]\n",
+	    pci_config_get32(config_handle, PCI_CONF_BASE3));
+	cmn_err(CE_CONT, " BASE 4      = [0x%x]\n",
+	    pci_config_get32(config_handle, PCI_CONF_BASE4));
+	cmn_err(CE_CONT, " BASE 5      = [0x%x]\n",
+	    pci_config_get32(config_handle, PCI_CONF_BASE5));
+	cmn_err(CE_CONT, " Cardbus CIS = [0x%x]\n",
+	    pci_config_get32(config_handle, PCI_CONF_CIS));
+	cmn_err(CE_CONT, " Sub VID     = [0x%x]\n",
+	    pci_config_get16(config_handle, PCI_CONF_SUBVENID));
+	cmn_err(CE_CONT, " Sub SID     = [0x%x]\n",
+	    pci_config_get16(config_handle, PCI_CONF_SUBSYSID));
+	cmn_err(CE_CONT, " ROM         = [0x%x]\n",
+	    pci_config_get32(config_handle, PCI_CONF_ROM));
+	cmn_err(CE_CONT, " I Line      = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_ILINE));
+	cmn_err(CE_CONT, " I Pin       = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_IPIN));
+	cmn_err(CE_CONT, " Max Grant   = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_MIN_G));
+	cmn_err(CE_CONT, " Max Latent  = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_MAX_L));
+}
+
+static void
+pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle)
+{
+	if ((pcicfg_debug & 1) == 0)
+		return;
+
+	pcicfg_dump_common_config(config_handle);
+
+	cmn_err(CE_CONT, "........................................\n");
+
+	cmn_err(CE_CONT, " Pri Bus     = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_BCNF_PRIBUS));
+	cmn_err(CE_CONT, " Sec Bus     = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_BCNF_SECBUS));
+	cmn_err(CE_CONT, " Sub Bus     = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_BCNF_SUBBUS));
+	cmn_err(CE_CONT, " Latency     = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_BCNF_LATENCY_TIMER));
+	cmn_err(CE_CONT, " I/O Base LO = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW));
+	cmn_err(CE_CONT, " I/O Lim LO  = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW));
+	cmn_err(CE_CONT, " Sec. Status = [0x%x]\n",
+	    pci_config_get16(config_handle, PCI_BCNF_SEC_STATUS));
+	cmn_err(CE_CONT, " Mem Base    = [0x%x]\n",
+	    pci_config_get16(config_handle, PCI_BCNF_MEM_BASE));
+	cmn_err(CE_CONT, " Mem Limit   = [0x%x]\n",
+	    pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT));
+	cmn_err(CE_CONT, " PF Mem Base = [0x%x]\n",
+	    pci_config_get16(config_handle, PCI_BCNF_PF_BASE_LOW));
+	cmn_err(CE_CONT, " PF Mem Lim  = [0x%x]\n",
+	    pci_config_get16(config_handle, PCI_BCNF_PF_LIMIT_LOW));
+	cmn_err(CE_CONT, " PF Base HI  = [0x%x]\n",
+	    pci_config_get32(config_handle, PCI_BCNF_PF_BASE_HIGH));
+	cmn_err(CE_CONT, " PF Lim  HI  = [0x%x]\n",
+	    pci_config_get32(config_handle, PCI_BCNF_PF_LIMIT_HIGH));
+	cmn_err(CE_CONT, " I/O Base HI = [0x%x]\n",
+	    pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI));
+	cmn_err(CE_CONT, " I/O Lim HI  = [0x%x]\n",
+	    pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI));
+	cmn_err(CE_CONT, " ROM addr    = [0x%x]\n",
+	    pci_config_get32(config_handle, PCI_BCNF_ROM));
+	cmn_err(CE_CONT, " Intr Line   = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_BCNF_ILINE));
+	cmn_err(CE_CONT, " Intr Pin    = [0x%x]\n",
+	    pci_config_get8(config_handle, PCI_BCNF_IPIN));
+	cmn_err(CE_CONT, " Bridge Ctrl = [0x%x]\n",
+	    pci_config_get16(config_handle, PCI_BCNF_BCNTRL));
+}
+
+#endif
+
+
+int
+_init()
+{
+	DEBUG0("PCI configurator installed - Fcode Interpretation/21554\n");
+
+	mutex_init(&pcicfg_list_mutex, NULL, MUTEX_DRIVER, NULL);
+	return (mod_install(&modlinkage));
+}
+
+int
+_fini(void)
+{
+	int error;
+
+	error = mod_remove(&modlinkage);
+	if (error != 0) {
+		return (error);
+	}
+	mutex_destroy(&pcicfg_list_mutex);
+	return (0);
+}
+
+int
+_info(modinfop)
+struct modinfo *modinfop;
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+/*ARGSUSED*/
+static uint8_t
+pcicfg_get_nslots(dev_info_t *dip, ddi_acc_handle_t handle)
+{
+	uint8_t num_slots = 0;
+	uint16_t cap_ptr;
+
+	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_HOTPLUG,
+	    &cap_ptr)) == DDI_SUCCESS) {
+		uint32_t config;
+
+		PCI_CAP_PUT8(handle, NULL, cap_ptr, PCI_HP_DWORD_SELECT_OFF,
+		    PCI_HP_SLOT_CONFIGURATION_REG);
+		config = PCI_CAP_GET32(handle, NULL, cap_ptr,
+		    PCI_HP_DWORD_DATA_OFF);
+		num_slots = config & 0x1F;
+	} else if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &cap_ptr))
+	    == DDI_SUCCESS) {
+		uint8_t esr_reg = PCI_CAP_GET8(handle, NULL,
+		    cap_ptr, PCI_CAP_ID_REGS_OFF);
+
+		num_slots = PCI_CAPSLOT_NSLOTS(esr_reg);
+	} else if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr))
+	    == DDI_SUCCESS) {
+		int port_type = PCI_CAP_GET16(handle, NULL, cap_ptr,
+		    PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
+
+		if ((port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) &&
+		    (PCI_CAP_GET16(handle, NULL, cap_ptr, PCIE_PCIECAP)
+		    & PCIE_PCIECAP_SLOT_IMPL))
+				num_slots = 1;
+	}
+
+	DEBUG3("%s#%d has %d slots",
+	    ddi_get_name(dip), ddi_get_instance(dip), num_slots);
+
+	return (num_slots);
+}
+
+/*ARGSUSED*/
+static uint8_t
+pcicfg_is_chassis(dev_info_t *dip, ddi_acc_handle_t handle)
+{
+	uint16_t cap_ptr;
+
+	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &cap_ptr)) !=
+	    DDI_FAILURE) {
+
+		uint8_t esr_reg = PCI_CAP_GET8(handle, NULL, cap_ptr, 2);
+		if (PCI_CAPSLOT_FIC(esr_reg))
+			return (B_TRUE);
+	}
+	return (B_FALSE);
+}
+
+/*ARGSUSED*/
+static int
+pcicfg_pcie_dev(dev_info_t *dip, int bus_type, pcicfg_err_regs_t *regs)
+{
+	/* get parent device's device_type property */
+	char *device_type;
+	int rc = DDI_FAILURE;
+	dev_info_t *pdip = ddi_get_parent(dip);
+
+	regs->pcie_dev = 0;
+	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
+	    DDI_PROP_DONTPASS, "device_type", &device_type)
+	    != DDI_PROP_SUCCESS) {
+		DEBUG2("device_type property missing for %s#%d",
+		    ddi_get_name(pdip), ddi_get_instance(pdip));
+		return (DDI_FAILURE);
+	}
+	switch (bus_type) {
+		case PCICFG_DEVICE_TYPE_PCIE:
+			if (strcmp(device_type, "pciex") == 0) {
+				rc = DDI_SUCCESS;
+				regs->pcie_dev = 1;
+			}
+			break;
+		case PCICFG_DEVICE_TYPE_PCI:
+			if (strcmp(device_type, "pci") == 0)
+				rc = DDI_SUCCESS;
+			break;
+		default:
+			break;
+	}
+	ddi_prop_free(device_type);
+	return (rc);
+}
+
+/*ARGSUSED*/
+static int
+pcicfg_pcie_port_type(dev_info_t *dip, ddi_acc_handle_t handle)
+{
+	int port_type = -1;
+	uint16_t cap_ptr;
+
+	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr)) !=
+	    DDI_FAILURE)
+		port_type = PCI_CAP_GET16(handle, NULL,
+		    cap_ptr, PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
+
+	return (port_type);
+}
+
+static int
+pcicfg_pcie_device_type(dev_info_t *dip, ddi_acc_handle_t handle)
+{
+	int port_type = pcicfg_pcie_port_type(dip, handle);
+
+	DEBUG1("device port_type = %x\n", port_type);
+	/* No PCIe CAP regs, we are not PCIe device_type */
+	if (port_type < 0)
+		return (DDI_FAILURE);
+
+	/* check for all PCIe device_types */
+	if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) ||
+	    (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
+	    (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
+	    (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
+		return (DDI_SUCCESS);
+
+	return (DDI_FAILURE);
+
+}
+
+/*
+ * In the following functions ndi_devi_enter() without holding the
+ * parent dip is sufficient. This is because  pci dr is driven through
+ * opens on the nexus which is in the device tree path above the node
+ * being operated on, and implicitly held due to the open.
+ */
+
+/*
+ * This entry point is called to configure a device (and
+ * all its children) on the given bus. It is called when
+ * a new device is added to the PCI domain.  This routine
+ * will create the device tree and program the devices
+ * registers.
+ */
+
+int
+pcicfg_configure(dev_info_t *devi, uint_t device, uint_t function,
+    pcicfg_flags_t flags)
+{
+	uint_t bus;
+	int len;
+	int func;
+	int trans_device;
+	dev_info_t *new_device;
+	pcicfg_bus_range_t pci_bus_range;
+	int rv;
+	int circ;
+	uint_t highest_bus = 0;
+	int ari_mode = B_FALSE;
+	int max_function = PCICFG_MAX_FUNCTION;
+
+	if (flags == PCICFG_FLAG_ENABLE_ARI)
+		return (pcicfg_ari_configure(devi));
+
+	/*
+	 * Start probing at the device specified in "device" on the
+	 * "bus" specified.
+	 */
+	len = sizeof (pcicfg_bus_range_t);
+	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
+	    "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
+		DEBUG0("no bus-range property\n");
+		return (PCICFG_FAILURE);
+	}
+
+	bus = pci_bus_range.lo; /* primary bus number of this bus node */
+
+	ndi_devi_enter(devi, &circ);
+	for (func = 0; func < max_function; ) {
+		if ((function != PCICFG_ALL_FUNC) && (function != func))
+			goto next;
+
+		if (ari_mode)
+			trans_device = func >> 3;
+		else
+			trans_device = device;
+
+		DEBUG3("Configuring [0x%x][0x%x][0x%x]\n",
+		    bus, trans_device, func & 7);
+
+		/*
+		 * Try executing fcode if available.
+		 */
+		switch (rv = pcicfg_fcode_probe(devi, bus, trans_device,
+		    func & 7, &highest_bus, flags)) {
+			case PCICFG_FAILURE:
+				DEBUG2("configure failed: "
+				    "bus [0x%x] device [0x%x]\n",
+				    bus, trans_device);
+				break;
+			case PCICFG_NODEVICE:
+				DEBUG3("no device : bus "
+				    "[0x%x] slot [0x%x] func [0x%x]\n",
+				    bus, trans_device, func & 7);
+				if (func)
+					goto next;
+				break;
+			default:
+				DEBUG3("configure: bus => [%d] "
+				    "slot => [%d] func => [%d]\n",
+				    bus, trans_device, func & 7);
+				break;
+		}
+
+		if (rv != PCICFG_SUCCESS)
+			break;
+
+		if ((new_device = pcicfg_devi_find(devi,
+		    trans_device, (func & 7))) == NULL) {
+			DEBUG0("Did'nt find device node just created\n");
+			goto cleanup;
+		}
+
+next:
+		/*
+		 * Determine if ARI Forwarding should be enabled.
+		 */
+		if (func == 0) {
+			if ((pcie_ari_supported(devi)
+			    == PCIE_ARI_FORW_SUPPORTED) &&
+			    (pcie_ari_device(new_device) == PCIE_ARI_DEVICE)) {
+				if (pcie_ari_enable(devi) == DDI_SUCCESS) {
+					(void) ddi_prop_create(DDI_DEV_T_NONE,
+					    devi,  DDI_PROP_CANSLEEP,
+					    "ari-enabled", NULL, 0);
+
+					ari_mode = B_TRUE;
+					max_function = PCICFG_MAX_ARI_FUNCTION;
+				}
+			}
+		}
+
+		if (ari_mode == B_TRUE) {
+			int next_function;
+
+			DEBUG0("Next Function - ARI Device\n");
+			if (pcie_ari_get_next_function(new_device,
+			    &next_function) != DDI_SUCCESS)
+				goto cleanup;
+
+			/*
+			 * Check if there are more fucntions to probe.
+			 */
+			if (next_function == 0) {
+				DEBUG0("Next Function - "
+				    "No more ARI Functions\n");
+				break;
+			}
+			func = next_function;
+		} else {
+			func++;
+		}
+
+		DEBUG1("Next Function - %x\n", func);
+	}
+
+	ndi_devi_exit(devi, circ);
+
+	if (func == 0)
+		return (PCICFG_FAILURE);	/* probe failed */
+	else
+		return (PCICFG_SUCCESS);
+
+cleanup:
+	/*
+	 * Clean up a partially created "probe state" tree.
+	 * There are no resources allocated to the in the
+	 * probe state.
+	 */
+	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
+		max_function = PCICFG_MAX_ARI_FUNCTION;
+	else
+		max_function = PCICFG_MAX_FUNCTION;
+
+	for (func = 0; func < max_function; func++) {
+
+		if (max_function == PCICFG_MAX_ARI_FUNCTION)
+			trans_device = func >> 3; /* ARI Device */
+		else
+			trans_device = device;
+
+		if ((new_device = pcicfg_devi_find(devi,
+		    trans_device, (func & 0x7))) == NULL) {
+			DEBUG0("No more devices to clean up\n");
+			continue;
+		}
+
+		DEBUG2("Cleaning up device [0x%x] function [0x%x]\n",
+		    trans_device, func & 7);
+		/*
+		 * If this was a bridge device it will have a
+		 * probe handle - if not, no harm in calling this.
+		 */
+		(void) pcicfg_destroy_phdl(new_device);
+		/*
+		 * This will free up the node
+		 */
+		(void) ndi_devi_offline(new_device, NDI_DEVI_REMOVE);
+	}
+	ndi_devi_exit(devi, circ);
+
+	return (PCICFG_FAILURE);
+}
+
+/*
+ * configure the child nodes of ntbridge. new_device points to ntbridge itself
+ */
+/*ARGSUSED*/
+static uint_t
+pcicfg_configure_ntbridge(dev_info_t *new_device, uint_t bus, uint_t device)
+{
+	int bus_range[2], rc = PCICFG_FAILURE, rc1, max_devs = 0;
+	int			devno;
+	dev_info_t		*new_ntbridgechild;
+	ddi_acc_handle_t	config_handle;
+	uint16_t		vid;
+	uint64_t		next_bus;
+	uint64_t		blen;
+	ndi_ra_request_t	req;
+	uint8_t			pcie_device_type = 0;
+
+	/*
+	 * If we need to do indirect config, lets create a property here
+	 * to let the child conf map routine know that it has to
+	 * go through the DDI calls, and not assume the devices are
+	 * mapped directly under the host.
+	 */
+	if ((rc = ndi_prop_update_int(DDI_DEV_T_NONE, new_device,
+	    PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS))
+	    != DDI_SUCCESS) {
+
+		DEBUG0("Cannot create indirect conf map property.\n");
+		return ((uint_t)PCICFG_FAILURE);
+	}
+	if (pci_config_setup(new_device, &config_handle) != DDI_SUCCESS)
+		return ((uint_t)PCICFG_FAILURE);
+	/* check if we are PCIe device */
+	if (pcicfg_pcie_device_type(new_device, config_handle) == DDI_SUCCESS)
+		pcie_device_type = 1;
+	pci_config_teardown(&config_handle);
+
+	/* create Bus node properties for ntbridge. */
+	if (pcicfg_set_busnode_props(new_device, pcie_device_type, -1, -1) !=
+	    PCICFG_SUCCESS) {
+		DEBUG0("Failed to set busnode props\n");
+		return (rc);
+	}
+
+	/* For now: Lets only support one layer of child */
+	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
+	req.ra_len = 1;
+	if (ndi_ra_alloc(ddi_get_parent(new_device), &req,
+	    &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
+	    NDI_RA_PASS) != NDI_SUCCESS) {
+		DEBUG0("ntbridge: Failed to get a bus number\n");
+		return (rc);
+	}
+
+	DEBUG1("ntbridge bus range start  ->[%d]\n", next_bus);
+
+	/*
+	 * Following will change, as we detect more bridges
+	 * on the way.
+	 */
+	bus_range[0] = (int)next_bus;
+	bus_range[1] = (int)next_bus;
+
+	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_device,
+	    "bus-range", bus_range, 2) != DDI_SUCCESS) {
+		DEBUG0("Cannot set ntbridge bus-range property");
+		return (rc);
+	}
+
+	/*
+	 * The other interface (away from the host) will be
+	 * initialized by the nexus driver when it loads.
+	 * We just have to set the registers and the nexus driver
+	 * figures out the rest.
+	 */
+
+	/*
+	 * finally, lets load and attach the driver
+	 * before configuring children of ntbridge.
+	 */
+	rc = ndi_devi_online(new_device, NDI_NO_EVENT|NDI_CONFIG);
+	if (rc != NDI_SUCCESS) {
+		cmn_err(CE_WARN,
+		    "pcicfg: Fail: can\'t load non-transparent bridge \
+		    driver.\n");
+		rc = PCICFG_FAILURE;
+		return (rc);
+	}
+	DEBUG0("pcicfg: Success loading nontransparent bridge nexus driver..");
+
+	/* Now set aside pci resources for our children. */
+	if (pcicfg_ntbridge_allocate_resources(new_device) !=
+	    PCICFG_SUCCESS) {
+		max_devs = 0;
+		rc = PCICFG_FAILURE;
+	} else
+		max_devs = PCICFG_MAX_DEVICE;
+
+	/* Probe devices on 2nd bus */
+	for (devno = pcicfg_start_devno; devno < max_devs; devno++) {
+
+		if (ndi_devi_alloc(new_device, DEVI_PSEUDO_NEXNAME,
+		    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild)
+		    != NDI_SUCCESS) {
+
+			DEBUG0("pcicfg: Failed to alloc test node\n");
+			rc = PCICFG_FAILURE;
+			break;
+		}
+
+		if (pcicfg_add_config_reg(new_ntbridgechild, next_bus, devno, 0)
+		    != DDI_PROP_SUCCESS) {
+			cmn_err(CE_WARN,
+			    "Failed to add conf reg for ntbridge child.\n");
+			(void) ndi_devi_free(new_ntbridgechild);
+			rc = PCICFG_FAILURE;
+			break;
+		}
+
+		if ((rc = pci_config_setup(new_ntbridgechild,
+		    &config_handle)) != PCICFG_SUCCESS) {
+			cmn_err(CE_WARN,
+			    "Cannot map ntbridge child %x\n", devno);
+			(void) ndi_devi_free(new_ntbridgechild);
+			rc = PCICFG_FAILURE;
+			break;
+		}
+
+		/*
+		 * See if there is any PCI HW at this location
+		 * by reading the Vendor ID.  If it returns with 0xffff
+		 * then there is no hardware at this location.
+		 */
+		vid = pci_config_get16(config_handle, PCI_CONF_VENID);
+
+		pci_config_teardown(&config_handle);
+		(void) ndi_devi_free(new_ntbridgechild);
+		if (vid	== 0xffff)
+			continue;
+
+		/* Lets fake attachments points for each child, */
+		if (pcicfg_configure(new_device, devno, PCICFG_ALL_FUNC, 0)
+		    != PCICFG_SUCCESS) {
+			int old_dev = pcicfg_start_devno;
+
+			cmn_err(CE_WARN,
+			"Error configuring ntbridge child dev=%d\n", devno);
+
+			rc = PCICFG_FAILURE;
+			while (old_dev != devno) {
+				if (pcicfg_ntbridge_unconfigure_child(
+				    new_device, old_dev) == PCICFG_FAILURE)
+
+					cmn_err(CE_WARN,
+					    "Unconfig Error ntbridge child "
+					    "dev=%d\n", old_dev);
+				old_dev++;
+			}
+			break;
+		}
+	} /* devno loop */
+	DEBUG1("ntbridge: finish probing 2nd bus, rc=%d\n", rc);
+
+	if (rc != PCICFG_FAILURE)
+		rc = pcicfg_ntbridge_configure_done(new_device);
+	else {
+		pcicfg_phdl_t *entry = pcicfg_find_phdl(new_device);
+		uint_t			*bus;
+		int			k;
+
+		if (ddi_getlongprop(DDI_DEV_T_ANY, new_device,
+		    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
+		    &k) != DDI_PROP_SUCCESS) {
+			DEBUG0("Failed to read bus-range property\n");
+			rc = PCICFG_FAILURE;
+			return (rc);
+		}
+
+		DEBUG2("Need to free bus [%d] range [%d]\n",
+		    bus[0], bus[1] - bus[0] + 1);
+
+		if (ndi_ra_free(ddi_get_parent(new_device),
+		    (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
+		    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
+			DEBUG0("Failed to free a bus number\n");
+			rc = PCICFG_FAILURE;
+			/*
+			 * Don't forget to free up memory from ddi_getlongprop
+			 */
+			kmem_free((caddr_t)bus, k);
+
+			return (rc);
+		}
+
+		/*
+		 * Since no memory allocations are done for non transparent
+		 * bridges (but instead we just set the handle with the
+		 * already allocated memory, we just need to reset the
+		 * following values before calling the destroy_phdl()
+		 * function next, otherwise the it will try to free
+		 * memory allocated as in case of a transparent bridge.
+		 */
+		entry->memory_len = 0;
+		entry->io_len = 0;
+		/* the following will free hole data. */
+		(void) pcicfg_destroy_phdl(new_device);
+		/*
+		 * Don't forget to free up memory from ddi_getlongprop
+		 */
+		kmem_free((caddr_t)bus, k);
+	}
+
+	/*
+	 * Unload driver just in case child configure failed!
+	 */
+	rc1 = ndi_devi_offline(new_device, NDI_NO_EVENT);
+	DEBUG1("pcicfg: now unloading the ntbridge driver. rc1=%d\n", rc1);
+	if (rc1 != NDI_SUCCESS) {
+		cmn_err(CE_WARN,
+		    "pcicfg: can\'t unload ntbridge driver children.\n");
+		rc = PCICFG_FAILURE;
+	}
+
+	return (rc);
+}
+
+static int
+pcicfg_ntbridge_allocate_resources(dev_info_t *dip)
+{
+	pcicfg_phdl_t		*phdl;
+	ndi_ra_request_t	*mem_request;
+	ndi_ra_request_t	*io_request;
+	uint64_t		boundbase, boundlen;
+
+	phdl = pcicfg_find_phdl(dip);
+	ASSERT(phdl);
+
+	mem_request = &phdl->mem_req;
+	io_request  = &phdl->io_req;
+
+	phdl->error = PCICFG_SUCCESS;
+
+	/* Set Memory space handle for ntbridge */
+	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
+	    PCI_BASE_SPACE_MEM) != DDI_SUCCESS) {
+		cmn_err(CE_WARN,
+		    "ntbridge: Mem resource information failure\n");
+		phdl->memory_len  = 0;
+		return (PCICFG_FAILURE);
+	}
+	mem_request->ra_boundbase = boundbase;
+	mem_request->ra_boundlen = boundbase + boundlen;
+	mem_request->ra_len = boundlen;
+	mem_request->ra_align_mask =
+	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
+	mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
+
+	/*
+	 * mem_request->ra_len =
+	 * PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
+	 */
+
+	phdl->memory_base = phdl->memory_last = boundbase;
+	phdl->memory_len  = boundlen;
+	phdl->mem_hole.start = phdl->memory_base;
+	phdl->mem_hole.len = mem_request->ra_len;
+	phdl->mem_hole.next = (hole_t *)NULL;
+
+	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of memory\n",
+	    boundlen, mem_request->ra_len);
+
+	/* set up a memory resource map for NT bridge */
+	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
+		DEBUG0("Can not setup ntbridge memory resource map\n");
+		return (PCICFG_FAILURE);
+	}
+	/* initialize the memory map */
+	if (ndi_ra_free(dip, boundbase, boundlen, NDI_RA_TYPE_MEM,
+	    NDI_RA_PASS) != NDI_SUCCESS) {
+		DEBUG0("Can not initalize ntbridge memory resource map\n");
+		return (PCICFG_FAILURE);
+	}
+	/* Set IO space handle for ntbridge */
+	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
+	    PCI_BASE_SPACE_IO) != DDI_SUCCESS) {
+		cmn_err(CE_WARN, "ntbridge: IO resource information failure\n");
+		phdl->io_len  = 0;
+		return (PCICFG_FAILURE);
+	}
+	io_request->ra_len = boundlen;
+	io_request->ra_align_mask =
+	    PCICFG_IOGRAN - 1;   /* 4K alignment on I/O space */
+	io_request->ra_boundbase = boundbase;
+	io_request->ra_boundlen = boundbase + boundlen;
+	io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
+
+	/*
+	 * io_request->ra_len =
+	 * PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
+	 */
+
+	phdl->io_base = phdl->io_last = (uint32_t)boundbase;
+	phdl->io_len  = (uint32_t)boundlen;
+	phdl->io_hole.start = phdl->io_base;
+	phdl->io_hole.len = io_request->ra_len;
+	phdl->io_hole.next = (hole_t *)NULL;
+
+	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of IO\n",
+	    boundlen, io_request->ra_len);
+
+	DEBUG2("MEMORY BASE = [0x%x] length [0x%x]\n",
+	    phdl->memory_base, phdl->memory_len);
+	DEBUG2("IO     BASE = [0x%x] length [0x%x]\n",
+	    phdl->io_base, phdl->io_len);
+
+	/* set up a IO resource map for NT bridge */
+	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
+		DEBUG0("Can not setup ntbridge memory resource map\n");
+		return (PCICFG_FAILURE);
+	}
+	/* initialize the IO map */
+	if (ndi_ra_free(dip, boundbase, boundlen, NDI_RA_TYPE_IO,
+	    NDI_RA_PASS) != NDI_SUCCESS) {
+		DEBUG0("Can not initalize ntbridge memory resource map\n");
+		return (PCICFG_FAILURE);
+	}
+
+	return (PCICFG_SUCCESS);
+}
+
+static int
+pcicfg_ntbridge_configure_done(dev_info_t *dip)
+{
+	pcicfg_range_t range[PCICFG_RANGE_LEN];
+	pcicfg_phdl_t		*entry;
+	uint_t			len;
+	pcicfg_bus_range_t	bus_range;
+	int			new_bus_range[2];
+
+	DEBUG1("Configuring children for %llx\n", dip);
+
+	entry = pcicfg_find_phdl(dip);
+	ASSERT(entry);
+
+	bzero((caddr_t)range,
+	    sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
+	range[1].child_hi = range[1].parent_hi |=
+	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
+	range[1].child_lo = range[1].parent_lo = (uint32_t)entry->memory_base;
+
+	range[0].child_hi = range[0].parent_hi |=
+	    (PCI_REG_REL_M | PCI_ADDR_IO);
+	range[0].child_lo = range[0].parent_lo = (uint32_t)entry->io_base;
+
+	len = sizeof (pcicfg_bus_range_t);
+	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "bus-range", (caddr_t)&bus_range, (int *)&len) != DDI_SUCCESS) {
+		DEBUG0("no bus-range property\n");
+		return (PCICFG_FAILURE);
+	}
+
+	new_bus_range[0] = bus_range.lo;	/* primary bus number */
+	if (entry->highest_bus) {	/* secondary bus number */
+		if (entry->highest_bus < bus_range.lo) {
+			cmn_err(CE_WARN,
+			    "ntbridge bus range invalid !(%d,%d)\n",
+			    bus_range.lo, entry->highest_bus);
+			new_bus_range[1] = bus_range.lo + entry->highest_bus;
+		}
+		else
+			new_bus_range[1] = entry->highest_bus;
+	}
+	else
+		new_bus_range[1] = bus_range.hi;
+
+	DEBUG2("ntbridge: bus range lo=%x, hi=%x\n",
+	    new_bus_range[0], new_bus_range[1]);
+
+	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
+	    "bus-range", new_bus_range, 2) != DDI_SUCCESS) {
+		DEBUG0("Failed to set bus-range property");
+		entry->error = PCICFG_FAILURE;
+		return (PCICFG_FAILURE);
+	}
+
+#ifdef DEBUG
+	{
+		uint64_t	unused;
+		unused = pcicfg_unused_space(&entry->io_hole, &len);
+		DEBUG2("ntbridge: Unused IO space %llx bytes over %d holes\n",
+		    unused, len);
+	}
+#endif
+
+	range[0].size_lo = entry->io_len;
+	if (pcicfg_update_ranges_prop(dip, &range[0])) {
+		DEBUG0("Failed to update ranges (i/o)\n");
+		entry->error = PCICFG_FAILURE;
+		return (PCICFG_FAILURE);
+	}
+
+#ifdef DEBUG
+	{
+		uint64_t	unused;
+		unused = pcicfg_unused_space(&entry->mem_hole, &len);
+		DEBUG2("ntbridge: Unused Mem space %llx bytes over %d holes\n",
+		    unused, len);
+	}
+#endif
+
+	range[1].size_lo = entry->memory_len;
+	if (pcicfg_update_ranges_prop(dip, &range[1])) {
+		DEBUG0("Failed to update ranges (memory)\n");
+		entry->error = PCICFG_FAILURE;
+		return (PCICFG_FAILURE);
+	}
+
+	return (PCICFG_SUCCESS);
+}
+
+static int
+pcicfg_ntbridge_unconfigure_child(dev_info_t *new_device, uint_t devno)
+{
+
+	dev_info_t	*new_ntbridgechild;
+	int 		len, bus;
+	uint16_t	vid;
+	ddi_acc_handle_t	config_handle;
+	pcicfg_bus_range_t pci_bus_range;
+
+	len = sizeof (pcicfg_bus_range_t);
+	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, new_device, DDI_PROP_DONTPASS,
+	    "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
+		DEBUG0("no bus-range property\n");
+		return (PCICFG_FAILURE);
+	}
+
+	bus = pci_bus_range.lo; /* primary bus number of this bus node */
+
+	if (ndi_devi_alloc(new_device, DEVI_PSEUDO_NEXNAME,
+	    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild) != NDI_SUCCESS) {
+
+		DEBUG0("pcicfg: Failed to alloc test node\n");
+		return (PCICFG_FAILURE);
+	}
+
+	if (pcicfg_add_config_reg(new_ntbridgechild, bus, devno, 0)
+	    != DDI_PROP_SUCCESS) {
+		cmn_err(CE_WARN,
+		"Unconfigure: Failed to add conf reg prop for ntbridge "
+		    "child.\n");
+		(void) ndi_devi_free(new_ntbridgechild);
+		return (PCICFG_FAILURE);
+	}
+
+	if (pcicfg_config_setup(new_ntbridgechild, &config_handle)
+	    != DDI_SUCCESS) {
+		cmn_err(CE_WARN,
+		    "pcicfg: Cannot map ntbridge child %x\n", devno);
+		(void) ndi_devi_free(new_ntbridgechild);
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * See if there is any PCI HW at this location
+	 * by reading the Vendor ID.  If it returns with 0xffff
+	 * then there is no hardware at this location.
+	 */
+	vid = pci_config_get16(config_handle, PCI_CONF_VENID);
+
+	pci_config_teardown(&config_handle);
+	(void) ndi_devi_free(new_ntbridgechild);
+	if (vid	== 0xffff)
+		return (PCICFG_NODEVICE);
+
+	return (pcicfg_unconfigure(new_device, devno, PCICFG_ALL_FUNC, 0));
+}
+
+static int
+pcicfg_ntbridge_unconfigure(dev_info_t *dip)
+{
+	pcicfg_phdl_t *entry = pcicfg_find_phdl(dip);
+	uint_t			*bus;
+	int			k, rc = PCICFG_FAILURE;
+
+	if (entry->memory_len)
+		if (ndi_ra_map_destroy(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
+			DEBUG1("cannot destroy ntbridge memory map size=%x\n",
+			    entry->memory_len);
+			return (PCICFG_FAILURE);
+		}
+	if (entry->io_len)
+		if (ndi_ra_map_destroy(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
+			DEBUG1("cannot destroy ntbridge io map size=%x\n",
+			    entry->io_len);
+			return (PCICFG_FAILURE);
+		}
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
+	    &k) != DDI_PROP_SUCCESS) {
+		DEBUG0("ntbridge: Failed to read bus-range property\n");
+		return (rc);
+	}
+
+	DEBUG2("ntbridge: Need to free bus [%d] range [%d]\n",
+	    bus[0], bus[1] - bus[0] + 1);
+
+	if (ndi_ra_free(ddi_get_parent(dip),
+	    (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
+	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
+		DEBUG0("ntbridge: Failed to free a bus number\n");
+		/*
+		 * Don't forget to free up memory from ddi_getlongprop
+		 */
+		kmem_free((caddr_t)bus, k);
+
+		return (rc);
+	}
+
+	/*
+	 * Don't forget to free up memory from ddi_getlongprop
+	 */
+	kmem_free((caddr_t)bus, k);
+
+	/*
+	 * Since our resources will be freed at the parent level,
+	 * just reset these values.
+	 */
+	entry->memory_len = 0;
+	entry->io_len = 0;
+	/* the following will also free hole data. */
+	return (pcicfg_destroy_phdl(dip));
+
+}
+
+static int
+pcicfg_is_ntbridge(dev_info_t *dip)
+{
+	ddi_acc_handle_t	config_handle;
+	uint8_t		class, subclass;
+	int		rc = DDI_SUCCESS;
+
+	if (pcicfg_config_setup(dip, &config_handle) != DDI_SUCCESS) {
+		cmn_err(CE_WARN,
+		    "pcicfg: cannot map config space, to get map type\n");
+		return (DDI_FAILURE);
+	}
+	class = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
+	subclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
+
+	/* check for class=6, subclass=9, for non transparent bridges.  */
+	if ((class != PCI_CLASS_BRIDGE) || (subclass != PCI_BRIDGE_STBRIDGE))
+		rc = DDI_FAILURE;
+
+	DEBUG3("pcicfg: checking device %x,%x for indirect map. rc=%d\n",
+	    pci_config_get16(config_handle, PCI_CONF_VENID),
+	    pci_config_get16(config_handle, PCI_CONF_DEVID),
+	    rc);
+	pci_config_teardown(&config_handle);
+	return (rc);
+}
+
+/*
+ * this function is called only for SPARC platforms, where we may have
+ * a mix n' match of direct vs indirectly mapped configuration space.
+ * On x86, this function does not get called. We always return TRUE
+ * via a macro for x86.
+ */
+/*ARGSUSED*/
+static int
+pcicfg_indirect_map(dev_info_t *dip)
+{
+#if defined(__sparc)
+	int rc = DDI_FAILURE;
+
+	if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip), 0,
+	    PCI_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
+		rc = DDI_SUCCESS;
+	else
+		if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip),
+		    0, PCI_BUS_CONF_MAP_PROP,
+		    DDI_FAILURE) != DDI_FAILURE)
+			rc = DDI_SUCCESS;
+	DEBUG1("pci conf map = %d", rc);
+	return (rc);
+#else
+	return (DDI_SUCCESS);
+#endif
+}
+
+static uint_t
+pcicfg_get_ntbridge_child_range(dev_info_t *dip, uint64_t *boundbase,
+				uint64_t *boundlen, uint_t space_type)
+{
+	int		length, found = DDI_FAILURE, acount, i, ibridge;
+	pci_regspec_t	*assigned;
+
+	if ((ibridge = pcicfg_is_ntbridge(dip)) == DDI_FAILURE)
+		return (found);
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
+	    &length) != DDI_PROP_SUCCESS) {
+		DEBUG1("Failed to get assigned-addresses property %llx\n", dip);
+		return (found);
+	}
+	DEBUG1("pcicfg: ntbridge child range: dip = %s\n",
+	    ddi_driver_name(dip));
+
+	acount = length / sizeof (pci_regspec_t);
+
+	for (i = 0; i < acount; i++) {
+		if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
+		    pcicfg_indirect_map_devs[ibridge].mem_range_bar_offset) &&
+		    (space_type == PCI_BASE_SPACE_MEM)) {
+			found = DDI_SUCCESS;
+			break;
+		} else {
+			if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
+			    pcicfg_indirect_map_devs[ibridge].\
+			    io_range_bar_offset) &&
+			    (space_type == PCI_BASE_SPACE_IO)) {
+				found = DDI_SUCCESS;
+				break;
+			}
+		}
+	}
+	DEBUG3("pcicfg: ntbridge child range: space=%x, base=%lx, len=%lx\n",
+	    space_type, assigned[i].pci_phys_low, assigned[i].pci_size_low);
+
+	if (found == DDI_SUCCESS)  {
+		*boundbase = assigned[i].pci_phys_low;
+		*boundlen = assigned[i].pci_size_low;
+	}
+
+	kmem_free(assigned, length);
+	return (found);
+}
+
+/*
+ * This will turn  resources allocated by pcicfg_configure()
+ * and remove the device tree from the Hotplug Connection (CN)
+ * and below.  The routine assumes the devices have their
+ * drivers detached.
+ */
+int
+pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
+    pcicfg_flags_t flags)
+{
+	dev_info_t *child_dip;
+	int func;
+	int i;
+	int max_function;
+	int trans_device;
+
+	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
+		max_function = PCICFG_MAX_ARI_FUNCTION;
+	else
+		max_function = PCICFG_MAX_FUNCTION;
+
+	/*
+	 * Cycle through devices to make sure none are busy.
+	 * If a single device is busy fail the whole unconfigure.
+	 */
+	for (func = 0; func < max_function; func++) {
+
+		if (max_function == PCICFG_MAX_ARI_FUNCTION)
+			trans_device = func >> 3; /* ARI Device */
+		else
+			trans_device = device;
+
+		if ((child_dip = pcicfg_devi_find(devi, trans_device,
+		    (func & 0x7))) == NULL)
+			continue;
+
+		if (ndi_devi_offline(child_dip, NDI_UNCONFIG) == NDI_SUCCESS)
+			continue;
+		/*
+		 * Device function is busy. Before returning we have to
+		 * put all functions back online which were taken
+		 * offline during the process.
+		 */
+		DEBUG2("Device [0x%x] function [%x] is busy\n", device, func);
+		/*
+		 * If we are only asked to offline one specific function,
+		 * and that fails, we just simply return.
+		 */
+		if (function != PCICFG_ALL_FUNC)
+			return (PCICFG_FAILURE);
+
+		for (i = 0; i < func; i++) {
+
+			if (max_function == PCICFG_MAX_ARI_FUNCTION)
+				trans_device = i >> 3;
+
+			if ((child_dip =
+			    pcicfg_devi_find(devi, trans_device, (i & 7)))
+			    == NULL) {
+				DEBUG0(
+				    "No more devices to put back on line!!\n");
+				/*
+				 * Made it through all functions
+				 */
+				continue;
+			}
+			if (ndi_devi_online(child_dip, NDI_CONFIG)
+			    != NDI_SUCCESS) {
+				DEBUG0("Failed to put back devices state\n");
+				return (PCICFG_FAILURE);
+			}
+		}
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * Now, tear down all devinfo nodes for this Connector.
+	 */
+	for (func = 0; func < max_function; func++) {
+
+		if (max_function == PCICFG_MAX_ARI_FUNCTION)
+			trans_device = func >> 3; /* ARI Device */
+		else
+			trans_device = device;
+
+		if ((child_dip = pcicfg_devi_find(devi,
+		    trans_device, (func & 7))) == NULL) {
+			DEBUG0("No more devices to tear down!\n");
+			continue;
+		}
+
+		DEBUG2("Tearing down device [0x%x] function [0x%x]\n",
+		    trans_device, (func & 7));
+
+		if (pcicfg_is_ntbridge(child_dip) != DDI_FAILURE)
+			if (pcicfg_ntbridge_unconfigure(child_dip) !=
+			    PCICFG_SUCCESS) {
+				cmn_err(CE_WARN,
+				    "ntbridge: unconfigure failed\n");
+				return (PCICFG_FAILURE);
+			}
+
+		if (pcicfg_teardown_device(child_dip, flags)
+		    != PCICFG_SUCCESS) {
+			DEBUG2("Failed to tear down device [0x%x]"
+			    "function [0x%x]\n",
+			    trans_device, func & 7);
+			return (PCICFG_FAILURE);
+		}
+	}
+
+	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) {
+		(void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "ari-enabled");
+		(void) pcie_ari_disable(devi);
+	}
+
+	return (PCICFG_SUCCESS);
+}
+
+static int
+pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags)
+{
+	ddi_acc_handle_t	config_handle;
+
+	/*
+	 * Free up resources associated with 'dip'
+	 */
+	if (pcicfg_free_resources(dip, flags) != PCICFG_SUCCESS) {
+		DEBUG0("Failed to free resources\n");
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * This will disable the device
+	 */
+	if (pci_config_setup(dip, &config_handle) != PCICFG_SUCCESS) {
+		return (PCICFG_FAILURE);
+	}
+
+	pcicfg_device_off(config_handle);
+	pci_config_teardown(&config_handle);
+
+	/*
+	 * The framework provides this routine which can
+	 * tear down a sub-tree.
+	 */
+	if (ndi_devi_offline(dip, NDI_DEVI_REMOVE) != NDI_SUCCESS) {
+		DEBUG0("Failed to offline and remove node\n");
+		return (PCICFG_FAILURE);
+	}
+
+	return (PCICFG_SUCCESS);
+}
+
+/*
+ * BEGIN GENERIC SUPPORT ROUTINES
+ */
+static pcicfg_phdl_t *
+pcicfg_find_phdl(dev_info_t *dip)
+{
+	pcicfg_phdl_t *entry;
+	mutex_enter(&pcicfg_list_mutex);
+	for (entry = pcicfg_phdl_list; entry != NULL; entry = entry->next) {
+		if (entry->dip == dip) {
+			mutex_exit(&pcicfg_list_mutex);
+			return (entry);
+		}
+	}
+	mutex_exit(&pcicfg_list_mutex);
+
+	/*
+	 * Did'nt find entry - create one
+	 */
+	return (pcicfg_create_phdl(dip));
+}
+
+static pcicfg_phdl_t *
+pcicfg_create_phdl(dev_info_t *dip)
+{
+	pcicfg_phdl_t *new;
+
+	new = (pcicfg_phdl_t *)kmem_zalloc(sizeof (pcicfg_phdl_t),
+	    KM_SLEEP);
+
+	new->dip = dip;
+	mutex_enter(&pcicfg_list_mutex);
+	new->next = pcicfg_phdl_list;
+	pcicfg_phdl_list = new;
+	mutex_exit(&pcicfg_list_mutex);
+
+	return (new);
+}
+
+static int
+pcicfg_destroy_phdl(dev_info_t *dip)
+{
+	pcicfg_phdl_t *entry;
+	pcicfg_phdl_t *follow = NULL;
+
+	mutex_enter(&pcicfg_list_mutex);
+	for (entry = pcicfg_phdl_list; entry != NULL; follow = entry,
+	    entry = entry->next) {
+		if (entry->dip == dip) {
+			if (entry == pcicfg_phdl_list) {
+				pcicfg_phdl_list = entry->next;
+			} else {
+				follow->next = entry->next;
+			}
+			/*
+			 * If this entry has any allocated memory
+			 * or IO space associated with it, that
+			 * must be freed up.
+			 */
+			if (entry->memory_len > 0) {
+				(void) ndi_ra_free(ddi_get_parent(dip),
+				    entry->memory_base,
+				    entry->memory_len,
+				    NDI_RA_TYPE_MEM, NDI_RA_PASS);
+			}
+			pcicfg_free_hole(&entry->mem_hole);
+
+			if (entry->io_len > 0) {
+				(void) ndi_ra_free(ddi_get_parent(dip),
+				    entry->io_base,
+				    entry->io_len,
+				    NDI_RA_TYPE_IO, NDI_RA_PASS);
+			}
+			pcicfg_free_hole(&entry->io_hole);
+
+			/*
+			 * Destroy this entry
+			 */
+			kmem_free((caddr_t)entry, sizeof (pcicfg_phdl_t));
+			mutex_exit(&pcicfg_list_mutex);
+			return (PCICFG_SUCCESS);
+		}
+	}
+	mutex_exit(&pcicfg_list_mutex);
+	/*
+	 * Did'nt find the entry
+	 */
+	return (PCICFG_FAILURE);
+}
+
+static int
+pcicfg_program_ap(dev_info_t *dip)
+{
+	pcicfg_phdl_t *phdl;
+	uint8_t header_type;
+	ddi_acc_handle_t handle;
+	pcicfg_phdl_t *entry;
+
+	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
+		DEBUG0("Failed to map config space!\n");
+		return (PCICFG_FAILURE);
+
+	}
+
+	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
+
+	(void) pcicfg_config_teardown(&handle);
+
+	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
+
+		if (pcicfg_allocate_chunk(dip) != PCICFG_SUCCESS) {
+			DEBUG0("Not enough memory to hotplug\n");
+			(void) pcicfg_destroy_phdl(dip);
+			return (PCICFG_FAILURE);
+		}
+
+		phdl = pcicfg_find_phdl(dip);
+		ASSERT(phdl);
+
+		(void) pcicfg_bridge_assign(dip, (void *)phdl);
+
+		if (phdl->error != PCICFG_SUCCESS) {
+			DEBUG0("Problem assigning bridge\n");
+			(void) pcicfg_destroy_phdl(dip);
+			return (phdl->error);
+		}
+
+		/*
+		 * Successfully allocated and assigned
+		 * memory.  Set the memory and IO length
+		 * to zero so when the handle is freed up
+		 * it will not de-allocate assigned resources.
+		 */
+		entry = (pcicfg_phdl_t *)phdl;
+
+		entry->memory_len = entry->io_len = 0;
+
+		/*
+		 * Free up the "entry" structure.
+		 */
+		(void) pcicfg_destroy_phdl(dip);
+	} else {
+		if (pcicfg_device_assign(dip) != PCICFG_SUCCESS) {
+			return (PCICFG_FAILURE);
+		}
+	}
+	return (PCICFG_SUCCESS);
+}
+
+static int
+pcicfg_bridge_assign(dev_info_t *dip, void *hdl)
+{
+	ddi_acc_handle_t handle;
+	pci_regspec_t *reg;
+	int length;
+	int rcount;
+	int i;
+	int offset;
+	uint64_t mem_answer;
+	uint32_t io_answer;
+	int count;
+	uint8_t header_type;
+	pcicfg_range_t range[PCICFG_RANGE_LEN];
+	int bus_range[2];
+
+	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
+
+	DEBUG1("bridge assign: assigning addresses to %s\n", ddi_get_name(dip));
+
+	if (entry == NULL) {
+		DEBUG0("Failed to get entry\n");
+		return (DDI_WALK_TERMINATE);
+	}
+
+	entry->error = PCICFG_SUCCESS;
+
+	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
+		DEBUG0("Failed to map config space!\n");
+		entry->error = PCICFG_FAILURE;
+		return (DDI_WALK_TERMINATE);
+	}
+
+	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
+
+	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
+
+		bzero((caddr_t)range,
+		    sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
+
+		(void) pcicfg_setup_bridge(entry, handle, dip);
+
+		range[0].child_hi = range[0].parent_hi |=
+		    (PCI_REG_REL_M | PCI_ADDR_IO);
+		range[0].child_lo = range[0].parent_lo =
+		    entry->io_last;
+		range[1].child_hi = range[1].parent_hi |=
+		    (PCI_REG_REL_M | PCI_ADDR_MEM32);
+		range[1].child_lo = range[1].parent_lo =
+		    entry->memory_last;
+
+		ndi_devi_enter(dip, &count);
+		ddi_walk_devs(ddi_get_child(dip),
+		    pcicfg_bridge_assign, (void *)entry);
+		ndi_devi_exit(dip, count);
+
+		(void) pcicfg_update_bridge(entry, handle);
+
+		bus_range[0] = pci_config_get8(handle, PCI_BCNF_SECBUS);
+		bus_range[1] = pci_config_get8(handle, PCI_BCNF_SUBBUS);
+
+		if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
+		    "bus-range", bus_range, 2) != DDI_SUCCESS) {
+			DEBUG0("Failed to set bus-range property");
+			entry->error = PCICFG_FAILURE;
+			return (DDI_WALK_TERMINATE);
+		}
+
+		if (entry->io_len > 0) {
+			range[0].size_lo = entry->io_last - entry->io_base;
+			if (pcicfg_update_ranges_prop(dip, &range[0])) {
+				DEBUG0("Failed to update ranges (i/o)\n");
+				entry->error = PCICFG_FAILURE;
+				return (DDI_WALK_TERMINATE);
+			}
+		}
+		if (entry->memory_len > 0) {
+			range[1].size_lo =
+			    entry->memory_last - entry->memory_base;
+			if (pcicfg_update_ranges_prop(dip, &range[1])) {
+				DEBUG0("Failed to update ranges (memory)\n");
+				entry->error = PCICFG_FAILURE;
+				return (DDI_WALK_TERMINATE);
+			}
+		}
+
+		(void) pcicfg_device_on(handle);
+
+		PCICFG_DUMP_BRIDGE_CONFIG(handle);
+
+		return (DDI_WALK_PRUNECHILD);
+	}
+
+	/*
+	 * If there is an interrupt pin set program
+	 * interrupt line with default values.
+	 */
+	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
+		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
+	}
+
+	/*
+	 * A single device (under a bridge).
+	 * For each "reg" property with a length, allocate memory
+	 * and program the base registers.
+	 */
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
+	    &length) != DDI_PROP_SUCCESS) {
+		DEBUG0("Failed to read reg property\n");
+		entry->error = PCICFG_FAILURE;
+		return (DDI_WALK_TERMINATE);
+	}
+
+	rcount = length / sizeof (pci_regspec_t);
+	offset = PCI_CONF_BASE0;
+	for (i = 0; i < rcount; i++) {
+		if ((reg[i].pci_size_low != 0)||
+		    (reg[i].pci_size_hi != 0)) {
+
+			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
+
+			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
+			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
+
+				(void) pcicfg_get_mem(entry,
+				    reg[i].pci_size_low, &mem_answer);
+				pci_config_put64(handle, offset, mem_answer);
+				DEBUG2("REGISTER off %x (64)LO ----> [0x%x]\n",
+				    offset,
+				    pci_config_get32(handle, offset));
+				DEBUG2("REGISTER off %x (64)HI ----> [0x%x]\n",
+				    offset + 4,
+				    pci_config_get32(handle, offset + 4));
+
+				reg[i].pci_phys_low = PCICFG_HIADDR(mem_answer);
+				reg[i].pci_phys_mid  =
+				    PCICFG_LOADDR(mem_answer);
+
+				break;
+
+			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
+				/* allocate memory space from the allocator */
+
+				(void) pcicfg_get_mem(entry,
+				    reg[i].pci_size_low, &mem_answer);
+				pci_config_put32(handle,
+				    offset, (uint32_t)mem_answer);
+
+				DEBUG2("REGISTER off %x(32)LO ----> [0x%x]\n",
+				    offset,
+				    pci_config_get32(handle, offset));
+
+				reg[i].pci_phys_low = (uint32_t)mem_answer;
+
+				break;
+			case PCI_REG_ADDR_G(PCI_ADDR_IO):
+				/* allocate I/O space from the allocator */
+
+				(void) pcicfg_get_io(entry,
+				    reg[i].pci_size_low, &io_answer);
+				pci_config_put32(handle, offset, io_answer);
+
+				DEBUG2("REGISTER off %x (I/O)LO ----> [0x%x]\n",
+				    offset,
+				    pci_config_get32(handle, offset));
+
+				reg[i].pci_phys_low = io_answer;
+
+				break;
+			default:
+				DEBUG0("Unknown register type\n");
+				kmem_free(reg, length);
+				(void) pcicfg_config_teardown(&handle);
+				entry->error = PCICFG_FAILURE;
+				return (DDI_WALK_TERMINATE);
+			} /* switch */
+
+			/*
+			 * Now that memory locations are assigned,
+			 * update the assigned address property.
+			 */
+			if (pcicfg_update_assigned_prop(dip,
+			    &reg[i]) != PCICFG_SUCCESS) {
+				kmem_free(reg, length);
+				(void) pcicfg_config_teardown(&handle);
+				entry->error = PCICFG_FAILURE;
+				return (DDI_WALK_TERMINATE);
+			}
+		}
+	}
+	(void) pcicfg_device_on(handle);
+
+	PCICFG_DUMP_DEVICE_CONFIG(handle);
+
+	(void) pcicfg_config_teardown(&handle);
+	/*
+	 * Don't forget to free up memory from ddi_getlongprop
+	 */
+	kmem_free((caddr_t)reg, length);
+
+	return (DDI_WALK_CONTINUE);
+}
+
+static int
+pcicfg_device_assign(dev_info_t *dip)
+{
+	ddi_acc_handle_t	handle;
+	pci_regspec_t		*reg;
+	int			length;
+	int			rcount;
+	int			i;
+	int			offset;
+	ndi_ra_request_t	request;
+	uint64_t		answer;
+	uint64_t		alen;
+
+	DEBUG1("%llx now under configuration\n", dip);
+
+	/*
+	 * XXX Failure here should be noted
+	 */
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
+	    &length) != DDI_PROP_SUCCESS) {
+		DEBUG0("Failed to read reg property\n");
+		return (PCICFG_FAILURE);
+	}
+
+	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
+		DEBUG0("Failed to map config space!\n");
+		/*
+		 * Don't forget to free up memory from ddi_getlongprop
+		 */
+		kmem_free((caddr_t)reg, length);
+
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * A single device
+	 *
+	 * For each "reg" property with a length, allocate memory
+	 * and program the base registers.
+	 */
+
+	/*
+	 * If there is an interrupt pin set program
+	 * interrupt line with default values.
+	 */
+	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
+		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
+	}
+
+	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
+
+	request.ra_flags |= NDI_RA_ALIGN_SIZE;
+	request.ra_boundbase = 0;
+	request.ra_boundlen = PCICFG_4GIG_LIMIT;
+
+	rcount = length / sizeof (pci_regspec_t);
+	offset = PCI_CONF_BASE0;
+	for (i = 0; i < rcount; i++) {
+		if ((reg[i].pci_size_low != 0)||
+		    (reg[i].pci_size_hi != 0)) {
+
+			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
+			request.ra_len = reg[i].pci_size_low;
+
+			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
+			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
+				request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
+				/* allocate memory space from the allocator */
+				if (ndi_ra_alloc(ddi_get_parent(dip),
+				    &request, &answer, &alen,
+				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
+				    != NDI_SUCCESS) {
+					DEBUG0("Failed to allocate 64b mem\n");
+					kmem_free(reg, length);
+					(void) pcicfg_config_teardown(&handle);
+					return (PCICFG_FAILURE);
+				}
+				DEBUG3("64 addr = [0x%x.%x] len [0x%x]\n",
+				    PCICFG_HIADDR(answer),
+				    PCICFG_LOADDR(answer),
+				    alen);
+				/* program the low word */
+				pci_config_put32(handle,
+				    offset, PCICFG_LOADDR(answer));
+
+				/* program the high word with value zero */
+				pci_config_put32(handle, offset + 4,
+				    PCICFG_HIADDR(answer));
+
+				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
+				reg[i].pci_phys_mid = PCICFG_HIADDR(answer);
+				/*
+				 * currently support 32b address space
+				 * assignments only.
+				 */
+				reg[i].pci_phys_hi ^= PCI_ADDR_MEM64 ^
+				    PCI_ADDR_MEM32;
+
+				offset += 8;
+				break;
+
+			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
+				request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
+				/* allocate memory space from the allocator */
+				if (ndi_ra_alloc(ddi_get_parent(dip),
+				    &request, &answer, &alen,
+				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
+				    != NDI_SUCCESS) {
+					DEBUG0("Failed to allocate 32b mem\n");
+					kmem_free(reg, length);
+					(void) pcicfg_config_teardown(&handle);
+					return (PCICFG_FAILURE);
+				}
+				DEBUG3("32 addr = [0x%x.%x] len [0x%x]\n",
+				    PCICFG_HIADDR(answer),
+				    PCICFG_LOADDR(answer),
+				    alen);
+				/* program the low word */
+				pci_config_put32(handle,
+				    offset, PCICFG_LOADDR(answer));
+
+				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
+
+				offset += 4;
+				break;
+			case PCI_REG_ADDR_G(PCI_ADDR_IO):
+				/* allocate I/O space from the allocator */
+				request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
+				if (ndi_ra_alloc(ddi_get_parent(dip),
+				    &request, &answer, &alen,
+				    NDI_RA_TYPE_IO, NDI_RA_PASS)
+				    != NDI_SUCCESS) {
+					DEBUG0("Failed to allocate I/O\n");
+					kmem_free(reg, length);
+					(void) pcicfg_config_teardown(&handle);
+					return (PCICFG_FAILURE);
+				}
+				DEBUG3("I/O addr = [0x%x.%x] len [0x%x]\n",
+				    PCICFG_HIADDR(answer),
+				    PCICFG_LOADDR(answer),
+				    alen);
+				pci_config_put32(handle,
+				    offset, PCICFG_LOADDR(answer));
+
+				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
+
+				offset += 4;
+				break;
+			default:
+				DEBUG0("Unknown register type\n");
+				kmem_free(reg, length);
+				(void) pcicfg_config_teardown(&handle);
+				return (PCICFG_FAILURE);
+			} /* switch */
+
+			/*
+			 * Now that memory locations are assigned,
+			 * update the assigned address property.
+			 */
+
+			if (pcicfg_update_assigned_prop(dip,
+			    &reg[i]) != PCICFG_SUCCESS) {
+				kmem_free(reg, length);
+				(void) pcicfg_config_teardown(&handle);
+				return (PCICFG_FAILURE);
+			}
+		}
+	}
+
+	(void) pcicfg_device_on(handle);
+	kmem_free(reg, length);
+
+	PCICFG_DUMP_DEVICE_CONFIG(handle);
+
+	(void) pcicfg_config_teardown(&handle);
+	return (PCICFG_SUCCESS);
+}
+
+static int
+pcicfg_device_assign_readonly(dev_info_t *dip)
+{
+	ddi_acc_handle_t	handle;
+	pci_regspec_t		*assigned;
+	int			length;
+	int			acount;
+	int			i;
+	ndi_ra_request_t	request;
+	uint64_t		answer;
+	uint64_t		alen;
+
+
+	DEBUG1("%llx now under configuration\n", dip);
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
+	    &length) != DDI_PROP_SUCCESS) {
+		DEBUG0("Failed to read assigned-addresses property\n");
+		return (PCICFG_FAILURE);
+	}
+
+	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
+		DEBUG0("Failed to map config space!\n");
+		/*
+		 * Don't forget to free up memory from ddi_getlongprop
+		 */
+		kmem_free((caddr_t)assigned, length);
+
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * For each "assigned-addresses" property entry with a length,
+	 * call the memory allocation routines to return the
+	 * resource.
+	 */
+	/*
+	 * If there is an interrupt pin set program
+	 * interrupt line with default values.
+	 */
+	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
+		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
+	}
+
+	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
+
+	request.ra_flags = NDI_RA_ALLOC_SPECIFIED; /* specified addr */
+	request.ra_boundbase = 0;
+	request.ra_boundlen = PCICFG_4GIG_LIMIT;
+
+	acount = length / sizeof (pci_regspec_t);
+	for (i = 0; i < acount; i++) {
+		if ((assigned[i].pci_size_low != 0)||
+		    (assigned[i].pci_size_hi != 0)) {
+
+			request.ra_len = assigned[i].pci_size_low;
+
+			switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
+			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
+				request.ra_addr = (uint64_t)PCICFG_LADDR(
+				    assigned[i].pci_phys_low,
+				    assigned[i].pci_phys_mid);
+
+				/* allocate memory space from the allocator */
+				if (ndi_ra_alloc(ddi_get_parent(dip),
+				    &request, &answer, &alen,
+				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
+				    != NDI_SUCCESS) {
+					DEBUG0("Failed to allocate 64b mem\n");
+					kmem_free(assigned, length);
+					return (PCICFG_FAILURE);
+				}
+
+				break;
+			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
+				request.ra_addr = (uint64_t)
+				    assigned[i].pci_phys_low;
+
+				/* allocate memory space from the allocator */
+				if (ndi_ra_alloc(ddi_get_parent(dip),
+				    &request, &answer, &alen,
+				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
+				    != NDI_SUCCESS) {
+					DEBUG0("Failed to allocate 32b mem\n");
+					kmem_free(assigned, length);
+					return (PCICFG_FAILURE);
+				}
+
+				break;
+			case PCI_REG_ADDR_G(PCI_ADDR_IO):
+				request.ra_addr = (uint64_t)
+				    assigned[i].pci_phys_low;
+
+				/* allocate I/O space from the allocator */
+				if (ndi_ra_alloc(ddi_get_parent(dip),
+				    &request, &answer, &alen,
+				    NDI_RA_TYPE_IO, NDI_RA_PASS)
+				    != NDI_SUCCESS) {
+					DEBUG0("Failed to allocate I/O\n");
+					kmem_free(assigned, length);
+					return (PCICFG_FAILURE);
+				}
+
+				break;
+			default:
+				DEBUG0("Unknown register type\n");
+				kmem_free(assigned, length);
+				return (PCICFG_FAILURE);
+			} /* switch */
+		}
+	}
+
+	(void) pcicfg_device_on(handle);
+	kmem_free(assigned, length);
+
+	PCICFG_DUMP_DEVICE_CONFIG(handle);
+
+	(void) pcicfg_config_teardown(&handle);
+	return (PCICFG_SUCCESS);
+}
+
+/*
+ * The "dip" passed to this routine is assumed to be
+ * the device at the Hotplug Connection (CN). Currently it is
+ * assumed to be a bridge.
+ */
+static int
+pcicfg_allocate_chunk(dev_info_t *dip)
+{
+	pcicfg_phdl_t		*phdl;
+	ndi_ra_request_t	*mem_request;
+	ndi_ra_request_t	*io_request;
+	uint64_t		mem_answer;
+	uint64_t		io_answer;
+	int			count;
+	uint64_t		alen;
+
+	/*
+	 * This should not find an existing entry - so
+	 * it will create a new one.
+	 */
+	phdl = pcicfg_find_phdl(dip);
+	ASSERT(phdl);
+
+	mem_request = &phdl->mem_req;
+	io_request  = &phdl->io_req;
+
+	/*
+	 * From this point in the tree - walk the devices,
+	 * The function passed in will read and "sum" up
+	 * the memory and I/O requirements and put them in
+	 * structure "phdl".
+	 */
+	ndi_devi_enter(ddi_get_parent(dip), &count);
+	ddi_walk_devs(dip, pcicfg_sum_resources, (void *)phdl);
+	ndi_devi_exit(ddi_get_parent(dip), count);
+
+	if (phdl->error != PCICFG_SUCCESS) {
+		DEBUG0("Failure summing resources\n");
+		return (phdl->error);
+	}
+
+	/*
+	 * Call into the memory allocator with the request.
+	 * Record the addresses returned in the phdl
+	 */
+	DEBUG1("Connector requires [0x%x] bytes of memory space\n",
+	    mem_request->ra_len);
+	DEBUG1("Connector requires [0x%x] bytes of I/O space\n",
+	    io_request->ra_len);
+
+	mem_request->ra_align_mask =
+	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
+	io_request->ra_align_mask =
+	    PCICFG_IOGRAN - 1;   /* 4K alignment on I/O space */
+	io_request->ra_boundbase = 0;
+	io_request->ra_boundlen = PCICFG_4GIG_LIMIT;
+	io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
+
+	mem_request->ra_len =
+	    PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
+
+	io_request->ra_len =
+	    PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
+
+	if (ndi_ra_alloc(ddi_get_parent(dip),
+	    mem_request, &mem_answer, &alen,
+	    NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
+		DEBUG0("Failed to allocate memory\n");
+		return (PCICFG_FAILURE);
+	}
+
+	phdl->memory_base = phdl->memory_last = mem_answer;
+	phdl->memory_len  = alen;
+
+	phdl->mem_hole.start = phdl->memory_base;
+	phdl->mem_hole.len = phdl->memory_len;
+	phdl->mem_hole.next = (hole_t *)NULL;
+
+	if (ndi_ra_alloc(ddi_get_parent(dip), io_request, &io_answer,
+	    &alen, NDI_RA_TYPE_IO, NDI_RA_PASS) != NDI_SUCCESS) {
+
+		DEBUG0("Failed to allocate I/O space\n");
+		(void) ndi_ra_free(ddi_get_parent(dip), mem_answer,
+		    alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
+		phdl->memory_len = phdl->io_len = 0;
+		return (PCICFG_FAILURE);
+	}
+
+	phdl->io_base = phdl->io_last = (uint32_t)io_answer;
+	phdl->io_len  = (uint32_t)alen;
+
+	phdl->io_hole.start = phdl->io_base;
+	phdl->io_hole.len = phdl->io_len;
+	phdl->io_hole.next = (hole_t *)NULL;
+
+	DEBUG2("MEMORY BASE = [0x%x] length [0x%x]\n",
+	    phdl->memory_base, phdl->memory_len);
+	DEBUG2("IO     BASE = [0x%x] length [0x%x]\n",
+	    phdl->io_base, phdl->io_len);
+
+	return (PCICFG_SUCCESS);
+}
+
+#ifdef	DEBUG
+/*
+ * This function is useful in debug mode, where we can measure how
+ * much memory was wasted/unallocated in bridge device's domain.
+ */
+static uint64_t
+pcicfg_unused_space(hole_t *hole, uint32_t *hole_count)
+{
+	uint64_t len = 0;
+	uint32_t count = 0;
+
+	do {
+		len += hole->len;
+		hole = hole->next;
+		count++;
+	} while (hole);
+	*hole_count = count;
+	return (len);
+}
+#endif
+
+/*
+ * This function frees data structures that hold the hole information
+ * which are allocated in pcicfg_alloc_hole(). This is not freeing
+ * any memory allocated through NDI calls.
+ */
+static void
+pcicfg_free_hole(hole_t *addr_hole)
+{
+	hole_t *nhole, *hole = addr_hole->next;
+
+	while (hole) {
+		nhole = hole->next;
+		kmem_free(hole, sizeof (hole_t));
+		hole = nhole;
+	}
+}
+
+static uint64_t
+pcicfg_alloc_hole(hole_t *addr_hole, uint64_t *alast, uint32_t length)
+{
+	uint64_t actual_hole_start, ostart, olen;
+	hole_t	*hole = addr_hole, *thole, *nhole;
+
+	do {
+		actual_hole_start = PCICFG_ROUND_UP(hole->start, length);
+		if (((actual_hole_start - hole->start) + length) <= hole->len) {
+			DEBUG3("hole found. start %llx, len %llx, req=%x\n",
+			    hole->start, hole->len, length);
+			ostart = hole->start;
+			olen = hole->len;
+			/* current hole parameters adjust */
+			if ((actual_hole_start - hole->start) == 0) {
+				hole->start += length;
+				hole->len -= length;
+				if (hole->start > *alast)
+					*alast = hole->start;
+			} else {
+				hole->len = actual_hole_start - hole->start;
+				nhole = (hole_t *)kmem_zalloc(sizeof (hole_t),
+				    KM_SLEEP);
+				nhole->start = actual_hole_start + length;
+				nhole->len = (ostart + olen) - nhole->start;
+				nhole->next = NULL;
+				thole = hole->next;
+				hole->next = nhole;
+				nhole->next = thole;
+				if (nhole->start > *alast)
+					*alast = nhole->start;
+				DEBUG2("put new hole to %llx, %llx\n",
+				    nhole->start, nhole->len);
+			}
+			DEBUG2("adjust current hole to %llx, %llx\n",
+			    hole->start, hole->len);
+			break;
+		}
+		actual_hole_start = 0;
+		hole = hole->next;
+	} while (hole);
+
+	DEBUG1("return hole at %llx\n", actual_hole_start);
+	return (actual_hole_start);
+}
+
+static void
+pcicfg_get_mem(pcicfg_phdl_t *entry,
+	uint32_t length, uint64_t *ans)
+{
+	uint64_t new_mem;
+
+	/* See if there is a hole, that can hold this request. */
+	new_mem = pcicfg_alloc_hole(&entry->mem_hole, &entry->memory_last,
+	    length);
+	if (new_mem) {	/* if non-zero, found a hole. */
+		if (ans != NULL)
+			*ans = new_mem;
+	} else
+		cmn_err(CE_WARN, "No %u bytes memory window for %s\n",
+		    length, ddi_get_name(entry->dip));
+}
+
+static void
+pcicfg_get_io(pcicfg_phdl_t *entry,
+	uint32_t length, uint32_t *ans)
+{
+	uint32_t new_io;
+	uint64_t io_last;
+
+	/*
+	 * See if there is a hole, that can hold this request.
+	 * Pass 64 bit parameters and then truncate to 32 bit.
+	 */
+	io_last = entry->io_last;
+	new_io = (uint32_t)pcicfg_alloc_hole(&entry->io_hole, &io_last, length);
+	if (new_io) {	/* if non-zero, found a hole. */
+		entry->io_last = (uint32_t)io_last;
+		if (ans != NULL)
+			*ans = new_io;
+	} else
+		cmn_err(CE_WARN, "No %u bytes IO space window for %s\n",
+		    length, ddi_get_name(entry->dip));
+}
+
+static int
+pcicfg_sum_resources(dev_info_t *dip, void *hdl)
+{
+	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
+	pci_regspec_t *pci_rp;
+	int length;
+	int rcount;
+	int i;
+	ndi_ra_request_t *mem_request;
+	ndi_ra_request_t *io_request;
+	uint8_t header_type;
+	ddi_acc_handle_t handle;
+
+	entry->error = PCICFG_SUCCESS;
+
+	mem_request = &entry->mem_req;
+	io_request =  &entry->io_req;
+
+	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
+		DEBUG0("Failed to map config space!\n");
+		entry->error = PCICFG_FAILURE;
+		return (DDI_WALK_TERMINATE);
+	}
+
+	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
+
+	/*
+	 * If its a bridge - just record the highest bus seen
+	 */
+	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
+
+		if (entry->highest_bus < pci_config_get8(handle,
+		    PCI_BCNF_SECBUS)) {
+			entry->highest_bus =
+			    pci_config_get8(handle, PCI_BCNF_SECBUS);
+		}
+
+		(void) pcicfg_config_teardown(&handle);
+		entry->error = PCICFG_FAILURE;
+		return (DDI_WALK_CONTINUE);
+	} else {
+		if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+		    DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp,
+		    &length) != DDI_PROP_SUCCESS) {
+			/*
+			 * If one node in (the subtree of nodes)
+			 * does'nt have a "reg" property fail the
+			 * allocation.
+			 */
+			entry->memory_len = 0;
+			entry->io_len = 0;
+			entry->error = PCICFG_FAILURE;
+			return (DDI_WALK_TERMINATE);
+		}
+		/*
+		 * For each "reg" property with a length, add that to the
+		 * total memory (or I/O) to allocate.
+		 */
+		rcount = length / sizeof (pci_regspec_t);
+
+		for (i = 0; i < rcount; i++) {
+
+			switch (PCI_REG_ADDR_G(pci_rp[i].pci_phys_hi)) {
+
+			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
+				mem_request->ra_len =
+				    pci_rp[i].pci_size_low +
+				    PCICFG_ROUND_UP(mem_request->ra_len,
+				    pci_rp[i].pci_size_low);
+				DEBUG1("ADDING 32 --->0x%x\n",
+				    pci_rp[i].pci_size_low);
+
+			break;
+			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
+				mem_request->ra_len =
+				    pci_rp[i].pci_size_low +
+				    PCICFG_ROUND_UP(mem_request->ra_len,
+				    pci_rp[i].pci_size_low);
+				DEBUG1("ADDING 64 --->0x%x\n",
+				    pci_rp[i].pci_size_low);
+
+			break;
+			case PCI_REG_ADDR_G(PCI_ADDR_IO):
+				io_request->ra_len =
+				    pci_rp[i].pci_size_low +
+				    PCICFG_ROUND_UP(io_request->ra_len,
+				    pci_rp[i].pci_size_low);
+				DEBUG1("ADDING I/O --->0x%x\n",
+				    pci_rp[i].pci_size_low);
+			break;
+			default:
+			    /* Config space register - not included */
+			break;
+			}
+		}
+
+		/*
+		 * free the memory allocated by ddi_getlongprop
+		 */
+		kmem_free(pci_rp, length);
+
+		/*
+		 * continue the walk to the next sibling to sum memory
+		 */
+
+		(void) pcicfg_config_teardown(&handle);
+
+		return (DDI_WALK_CONTINUE);
+	}
+}
+
+static int
+pcicfg_find_resource_end(dev_info_t *dip, void *hdl)
+{
+	pcicfg_phdl_t *entry_p = (pcicfg_phdl_t *)hdl;
+	pci_regspec_t *pci_ap;
+	pcicfg_range_t *ranges;
+	int length;
+	int rcount;
+	int i;
+
+	entry_p->error = PCICFG_SUCCESS;
+
+	if (dip == entry_p->dip) {
+		DEBUG0("Don't include parent bridge node\n");
+		return (DDI_WALK_CONTINUE);
+	}
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "ranges",
+	    (caddr_t)&ranges,  &length) != DDI_PROP_SUCCESS) {
+		DEBUG0("Node doesn't have ranges\n");
+		goto ap;
+	}
+
+	rcount = length / sizeof (pcicfg_range_t);
+
+	for (i = 0; i < rcount; i++) {
+		uint64_t base;
+		uint64_t mid = ranges[i].child_mid;
+		uint64_t lo = ranges[i].child_lo;
+		uint64_t size = ranges[i].size_lo;
+
+		switch (PCI_REG_ADDR_G(ranges[i].child_hi)) {
+
+		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
+			base = entry_p->memory_base;
+			entry_p->memory_base = MAX(base, lo + size);
+			break;
+		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
+			base = entry_p->memory_base;
+			entry_p->memory_base = MAX(base,
+			    PCICFG_LADDR(lo, mid) + size);
+			break;
+		case PCI_REG_ADDR_G(PCI_ADDR_IO):
+			base = entry_p->io_base;
+			entry_p->io_base = MAX(base, lo + size);
+			break;
+		}
+	}
+
+	kmem_free(ranges, length);
+	return (DDI_WALK_CONTINUE);
+
+ap:	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "assigned-addresses",
+	    (caddr_t)&pci_ap,  &length) != DDI_PROP_SUCCESS) {
+		DEBUG0("Node doesn't have assigned-addresses\n");
+		return (DDI_WALK_CONTINUE);
+	}
+
+	rcount = length / sizeof (pci_regspec_t);
+
+	for (i = 0; i < rcount; i++) {
+
+		switch (PCI_REG_ADDR_G(pci_ap[i].pci_phys_hi)) {
+
+		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
+			if ((pci_ap[i].pci_phys_low +
+			    pci_ap[i].pci_size_low) >
+			    entry_p->memory_base) {
+				entry_p->memory_base =
+				    pci_ap[i].pci_phys_low +
+				    pci_ap[i].pci_size_low;
+			}
+		break;
+		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
+			if ((PCICFG_LADDR(pci_ap[i].pci_phys_low,
+			    pci_ap[i].pci_phys_mid) +
+			    pci_ap[i].pci_size_low) >
+			    entry_p->memory_base) {
+				entry_p->memory_base = PCICFG_LADDR(
+				    pci_ap[i].pci_phys_low,
+				    pci_ap[i].pci_phys_mid) +
+				    pci_ap[i].pci_size_low;
+			}
+		break;
+		case PCI_REG_ADDR_G(PCI_ADDR_IO):
+			if ((pci_ap[i].pci_phys_low +
+			    pci_ap[i].pci_size_low) >
+			    entry_p->io_base) {
+				entry_p->io_base =
+				    pci_ap[i].pci_phys_low +
+				    pci_ap[i].pci_size_low;
+			}
+		break;
+		}
+	}
+
+	/*
+	 * free the memory allocated by ddi_getlongprop
+	 */
+	kmem_free(pci_ap, length);
+
+	/*
+	 * continue the walk to the next sibling to sum memory
+	 */
+	return (DDI_WALK_CONTINUE);
+}
+
+static int
+pcicfg_free_bridge_resources(dev_info_t *dip)
+{
+	pcicfg_range_t		*ranges;
+	uint_t			*bus;
+	int			k;
+	int			length;
+	int			i;
+
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges,
+	    &length) != DDI_PROP_SUCCESS) {
+		DEBUG0("Failed to read ranges property\n");
+		if (ddi_get_child(dip)) {
+			cmn_err(CE_WARN, "No ranges property found for %s",
+			    ddi_get_name(dip));
+			/*
+			 * strictly speaking, we can check for children with
+			 * assigned-addresses but for now it is better to
+			 * be conservative and assume that if there are child
+			 * nodes, then they do consume PCI memory or IO
+			 * resources, Hence return failure.
+			 */
+			return (PCICFG_FAILURE);
+		}
+		length = 0;
+
+	}
+
+	for (i = 0; i < length / sizeof (pcicfg_range_t); i++) {
+		if (ranges[i].size_lo != 0 ||
+		    ranges[i].size_hi != 0) {
+			switch (ranges[i].parent_hi & PCI_REG_ADDR_M) {
+				case PCI_ADDR_IO:
+					DEBUG2("Free I/O    "
+					    "base/length = [0x%x]/[0x%x]\n",
+					    ranges[i].child_lo,
+					    ranges[i].size_lo);
+					if (ndi_ra_free(ddi_get_parent(dip),
+					    (uint64_t)ranges[i].child_lo,
+					    (uint64_t)ranges[i].size_lo,
+					    NDI_RA_TYPE_IO, NDI_RA_PASS)
+					    != NDI_SUCCESS) {
+						DEBUG0("Trouble freeing "
+						    "PCI i/o space\n");
+						kmem_free(ranges, length);
+						return (PCICFG_FAILURE);
+					}
+				break;
+				case PCI_ADDR_MEM32:
+				case PCI_ADDR_MEM64:
+					DEBUG3("Free Memory base/length = "
+					    "[0x%x.%x]/[0x%x]\n",
+					    ranges[i].child_mid,
+					    ranges[i].child_lo,
+					    ranges[i].size_lo)
+					if (ndi_ra_free(ddi_get_parent(dip),
+					    PCICFG_LADDR(ranges[i].child_lo,
+					    ranges[i].child_mid),
+					    (uint64_t)ranges[i].size_lo,
+					    NDI_RA_TYPE_MEM, NDI_RA_PASS)
+					    != NDI_SUCCESS) {
+						DEBUG0("Trouble freeing "
+						    "PCI memory space\n");
+						kmem_free(ranges, length);
+						return (PCICFG_FAILURE);
+					}
+				break;
+				default:
+					DEBUG0("Unknown memory space\n");
+				break;
+			}
+		}
+	}
+
+	if (length)
+		kmem_free(ranges, length);
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
+	    &k) != DDI_PROP_SUCCESS) {
+		DEBUG0("Failed to read bus-range property\n");
+		return (PCICFG_FAILURE);
+	}
+
+	DEBUG2("Need to free bus [%d] range [%d]\n",
+	    bus[0], bus[1] - bus[0] + 1);
+
+	if (ndi_ra_free(ddi_get_parent(dip),
+	    (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
+	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
+		/*EMPTY*/
+		DEBUG0("Failed to free a bus number\n");
+	}
+	/*
+	 * Don't forget to free up memory from ddi_getlongprop
+	 */
+	kmem_free((caddr_t)bus, k);
+
+	return (PCICFG_SUCCESS);
+}
+
+static int
+pcicfg_free_device_resources(dev_info_t *dip, pcicfg_flags_t flags)
+{
+	pci_regspec_t *assigned;
+
+	int length;
+	int acount;
+	int i;
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
+	    &length) != DDI_PROP_SUCCESS) {
+		DEBUG0("Failed to read assigned-addresses property\n");
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * For each "assigned-addresses" property entry with a length,
+	 * call the memory allocation routines to return the
+	 * resource.
+	 */
+	acount = length / sizeof (pci_regspec_t);
+	for (i = 0; i < acount; i++) {
+		/*
+		 * Workaround for Devconf (x86) bug to skip extra entries
+		 * beyond the PCI_CONF_BASE5 offset. But we want to free up
+		 * any memory for expansion roms if allocated.
+		 */
+		if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) > PCI_CONF_BASE5) &&
+		    (PCI_REG_REG_G(assigned[i].pci_phys_hi) != PCI_CONF_ROM))
+			break;
+
+		if (pcicfg_free_resource(dip, assigned[i], flags)) {
+			DEBUG1("pcicfg_free_device_resources - Trouble freeing "
+			    "%x\n", assigned[i].pci_phys_hi);
+			/*
+			 * Don't forget to free up memory from ddi_getlongprop
+			 */
+			kmem_free((caddr_t)assigned, length);
+
+			return (PCICFG_FAILURE);
+		}
+	}
+	kmem_free(assigned, length);
+	return (PCICFG_SUCCESS);
+}
+
+static int
+pcicfg_free_resources(dev_info_t *dip, pcicfg_flags_t flags)
+{
+	ddi_acc_handle_t handle;
+	uint8_t header_type;
+
+	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
+		DEBUG0("Failed to map config space!\n");
+		return (PCICFG_FAILURE);
+	}
+
+	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
+
+	(void) pci_config_teardown(&handle);
+
+	/*
+	 * A different algorithm is used for bridges and leaf devices.
+	 */
+	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
+		/*
+		 * We only support readonly probing for leaf devices.
+		 */
+		if (flags & PCICFG_FLAG_READ_ONLY)
+			return (PCICFG_FAILURE);
+
+		if (pcicfg_free_bridge_resources(dip) != PCICFG_SUCCESS) {
+			DEBUG0("Failed freeing up bridge resources\n");
+			return (PCICFG_FAILURE);
+		}
+	} else {
+		if (pcicfg_free_device_resources(dip, flags)
+		    != PCICFG_SUCCESS) {
+			DEBUG0("Failed freeing up device resources\n");
+			return (PCICFG_FAILURE);
+		}
+	}
+	return (PCICFG_SUCCESS);
+}
+
+#ifndef _DONT_USE_1275_GENERIC_NAMES
+static char *
+pcicfg_get_class_name(uint32_t classcode)
+{
+	struct pcicfg_name_entry *ptr;
+
+	for (ptr = &pcicfg_class_lookup[0]; ptr->name != NULL; ptr++) {
+		if (ptr->class_code == classcode) {
+			return (ptr->name);
+		}
+	}
+	return (NULL);
+}
+#endif /* _DONT_USE_1275_GENERIC_NAMES */
+
+static dev_info_t *
+pcicfg_devi_find(dev_info_t *dip, uint_t device, uint_t function)
+{
+	struct pcicfg_find_ctrl ctrl;
+	int count;
+
+	ctrl.device = device;
+	ctrl.function = function;
+	ctrl.dip = NULL;
+
+	ndi_devi_enter(dip, &count);
+	ddi_walk_devs(ddi_get_child(dip), pcicfg_match_dev, (void *)&ctrl);
+	ndi_devi_exit(dip, count);
+
+	return (ctrl.dip);
+}
+
+static int
+pcicfg_match_dev(dev_info_t *dip, void *hdl)
+{
+	struct pcicfg_find_ctrl *ctrl = (struct pcicfg_find_ctrl *)hdl;
+	pci_regspec_t *pci_rp;
+	int length;
+	int pci_dev;
+	int pci_func;
+
+	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
+	    (uint_t *)&length) != DDI_PROP_SUCCESS) {
+		ctrl->dip = NULL;
+		return (DDI_WALK_TERMINATE);
+	}
+
+	/* get the PCI device address info */
+	pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
+	pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
+
+	/*
+	 * free the memory allocated by ddi_prop_lookup_int_array
+	 */
+	ddi_prop_free(pci_rp);
+
+
+	if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
+		/* found the match for the specified device address */
+		ctrl->dip = dip;
+		return (DDI_WALK_TERMINATE);
+	}
+
+	/*
+	 * continue the walk to the next sibling to look for a match.
+	 */
+	return (DDI_WALK_PRUNECHILD);
+}
+
+static int
+pcicfg_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone)
+{
+	int		alen;
+	pci_regspec_t	*assigned;
+	caddr_t		newreg;
+	uint_t		status;
+
+	DEBUG0("pcicfg_update_assigned_prop()\n");
+	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "assigned-addresses", (caddr_t)&assigned, &alen);
+	switch (status) {
+		case DDI_PROP_SUCCESS:
+		break;
+		case DDI_PROP_NO_MEMORY:
+			DEBUG0("no memory for assigned-addresses property\n");
+			return (PCICFG_FAILURE);
+		default:
+			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
+			    "assigned-addresses", (int *)newone,
+			    sizeof (*newone)/sizeof (int));
+
+			(void) pcicfg_dump_assigned(dip);
+
+			return (PCICFG_SUCCESS);
+	}
+
+	/*
+	 * Allocate memory for the existing
+	 * assigned-addresses(s) plus one and then
+	 * build it.
+	 */
+
+	newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
+
+	bcopy(assigned, newreg, alen);
+	bcopy(newone, newreg + alen, sizeof (*newone));
+
+	/*
+	 * Write out the new "assigned-addresses" spec
+	 */
+	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
+	    "assigned-addresses", (int *)newreg,
+	    (alen + sizeof (*newone))/sizeof (int));
+
+	kmem_free((caddr_t)newreg, alen+sizeof (*newone));
+
+	/*
+	 * Don't forget to free up memory from ddi_getlongprop
+	 */
+	kmem_free((caddr_t)assigned, alen);
+
+	(void) pcicfg_dump_assigned(dip);
+
+	return (PCICFG_SUCCESS);
+}
+static int
+pcicfg_update_ranges_prop(dev_info_t *dip, pcicfg_range_t *addition)
+{
+	int		rlen;
+	pcicfg_range_t	*ranges;
+	caddr_t		newreg;
+	uint_t		status;
+
+	status = ddi_getlongprop(DDI_DEV_T_ANY,
+	    dip, DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges, &rlen);
+
+
+	switch (status) {
+		case DDI_PROP_SUCCESS:
+		break;
+		case DDI_PROP_NO_MEMORY:
+			DEBUG0("ranges present, but unable to get memory\n");
+			return (PCICFG_FAILURE);
+		default:
+			DEBUG0("no ranges property - creating one\n");
+			if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
+			    dip, "ranges", (int *)addition,
+			    sizeof (pcicfg_range_t)/sizeof (int))
+			    != DDI_SUCCESS) {
+				DEBUG0("Did'nt create ranges property\n");
+				return (PCICFG_FAILURE);
+			}
+			return (PCICFG_SUCCESS);
+	}
+
+	/*
+	 * Allocate memory for the existing reg(s) plus one and then
+	 * build it.
+	 */
+	newreg = kmem_zalloc(rlen + sizeof (pcicfg_range_t), KM_SLEEP);
+
+	bcopy(ranges, newreg, rlen);
+	bcopy(addition, newreg + rlen, sizeof (pcicfg_range_t));
+
+	/*
+	 * Write out the new "ranges" property
+	 */
+	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
+	    dip, "ranges", (int *)newreg,
+	    (rlen + sizeof (pcicfg_range_t))/sizeof (int));
+
+	kmem_free((caddr_t)newreg, rlen+sizeof (pcicfg_range_t));
+
+	kmem_free((caddr_t)ranges, rlen);
+
+	return (PCICFG_SUCCESS);
+}
+
+static int
+pcicfg_update_reg_prop(dev_info_t *dip, uint32_t regvalue, uint_t reg_offset)
+{
+	int		rlen;
+	pci_regspec_t	*reg;
+	caddr_t		newreg;
+	uint32_t	hiword;
+	pci_regspec_t	addition;
+	uint32_t	size;
+	uint_t		status;
+
+	status = ddi_getlongprop(DDI_DEV_T_ANY,
+	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
+
+	switch (status) {
+		case DDI_PROP_SUCCESS:
+		break;
+		case DDI_PROP_NO_MEMORY:
+			DEBUG0("reg present, but unable to get memory\n");
+			return (PCICFG_FAILURE);
+		default:
+			DEBUG0("no reg property\n");
+			return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * Allocate memory for the existing reg(s) plus one and then
+	 * build it.
+	 */
+	newreg = kmem_zalloc(rlen+sizeof (pci_regspec_t), KM_SLEEP);
+
+	/*
+	 * Build the regspec, then add it to the existing one(s)
+	 */
+
+	hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
+	    PCI_REG_DEV_G(reg->pci_phys_hi),
+	    PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
+
+	if (reg_offset == PCI_CONF_ROM) {
+		size = (~(PCI_BASE_ROM_ADDR_M & regvalue))+1;
+		hiword |= PCI_ADDR_MEM32;
+	} else {
+		size = (~(PCI_BASE_M_ADDR_M & regvalue))+1;
+
+		if ((PCI_BASE_SPACE_M & regvalue) == PCI_BASE_SPACE_MEM) {
+			if ((PCI_BASE_TYPE_M & regvalue) == PCI_BASE_TYPE_MEM) {
+				hiword |= PCI_ADDR_MEM32;
+			} else if ((PCI_BASE_TYPE_M & regvalue)
+			    == PCI_BASE_TYPE_ALL) {
+				hiword |= PCI_ADDR_MEM64;
+			}
+		} else {
+			hiword |= PCI_ADDR_IO;
+		}
+	}
+
+	addition.pci_phys_hi = hiword;
+	addition.pci_phys_mid = 0;
+	addition.pci_phys_low = 0;
+	addition.pci_size_hi = 0;
+	addition.pci_size_low = size;
+
+	bcopy(reg, newreg, rlen);
+	bcopy(&addition, newreg + rlen, sizeof (pci_regspec_t));
+
+	/*
+	 * Write out the new "reg" property
+	 */
+	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
+	    dip, "reg", (int *)newreg,
+	    (rlen + sizeof (pci_regspec_t))/sizeof (int));
+
+	kmem_free((caddr_t)newreg, rlen+sizeof (pci_regspec_t));
+	kmem_free((caddr_t)reg, rlen);
+
+	return (PCICFG_SUCCESS);
+}
+static int
+pcicfg_update_available_prop(dev_info_t *dip, pci_regspec_t *newone)
+{
+	int		alen;
+	pci_regspec_t	*avail_p;
+	caddr_t		new_avail;
+	uint_t		status;
+
+	DEBUG2("pcicfg_update_available_prop() - Address %lx Size %x\n",
+	    newone->pci_phys_low, newone->pci_size_low);
+	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "available", (caddr_t)&avail_p, &alen);
+	switch (status) {
+		case DDI_PROP_SUCCESS:
+			break;
+		case DDI_PROP_NO_MEMORY:
+			DEBUG0("no memory for available property\n");
+			return (PCICFG_FAILURE);
+		default:
+			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
+			    "available", (int *)newone,
+			    sizeof (*newone)/sizeof (int));
+
+			return (PCICFG_SUCCESS);
+	}
+
+	/*
+	 * Allocate memory for the existing available plus one and then
+	 * build it.
+	 */
+	new_avail = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
+
+	bcopy(avail_p, new_avail, alen);
+	bcopy(newone, new_avail + alen, sizeof (*newone));
+
+	/* Write out the new "available" spec */
+	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
+	    "available", (int *)new_avail,
+	    (alen + sizeof (*newone))/sizeof (int));
+
+	kmem_free((caddr_t)new_avail, alen+sizeof (*newone));
+
+	/* Don't forget to free up memory from ddi_getlongprop */
+	kmem_free((caddr_t)avail_p, alen);
+
+	return (PCICFG_SUCCESS);
+}
+
+static int
+pcicfg_update_assigned_prop_value(dev_info_t *dip, uint32_t size,
+    uint32_t base, uint32_t base_hi, uint_t reg_offset)
+{
+	int		rlen;
+	pci_regspec_t	*reg;
+	uint32_t	hiword;
+	pci_regspec_t	addition;
+	uint_t		status;
+
+	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "reg", (caddr_t)&reg, &rlen);
+
+	switch (status) {
+		case DDI_PROP_SUCCESS:
+		break;
+		case DDI_PROP_NO_MEMORY:
+			DEBUG0("reg present, but unable to get memory\n");
+			return (PCICFG_FAILURE);
+		default:
+			/*
+			 * Since the config space "reg" entry should have been
+			 * created, we expect a "reg" property already
+			 * present here.
+			 */
+			DEBUG0("no reg property\n");
+			return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * Build the regspec, then add it to the existing one(s)
+	 */
+
+	hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
+	    PCI_REG_DEV_G(reg->pci_phys_hi),
+	    PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
+
+	hiword |= PCI_REG_REL_M;
+
+	if (reg_offset == PCI_CONF_ROM) {
+		hiword |= PCI_ADDR_MEM32;
+
+		base = PCI_BASE_ROM_ADDR_M & base;
+	} else {
+		if ((PCI_BASE_SPACE_M & base) == PCI_BASE_SPACE_MEM) {
+			if ((PCI_BASE_TYPE_M & base) == PCI_BASE_TYPE_MEM) {
+				hiword |= PCI_ADDR_MEM32;
+			} else if ((PCI_BASE_TYPE_M & base)
+			    == PCI_BASE_TYPE_ALL) {
+				hiword |= PCI_ADDR_MEM64;
+			}
+
+			if (base & PCI_BASE_PREF_M)
+				hiword |= PCI_REG_PF_M;
+
+			base = PCI_BASE_M_ADDR_M & base;
+		} else {
+			hiword |= PCI_ADDR_IO;
+
+			base = PCI_BASE_IO_ADDR_M & base;
+			base_hi = 0;
+		}
+	}
+
+	addition.pci_phys_hi = hiword;
+	addition.pci_phys_mid = base_hi;
+	addition.pci_phys_low = base;
+	addition.pci_size_hi = 0;
+	addition.pci_size_low = size;
+
+	DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
+
+	kmem_free((caddr_t)reg, rlen);
+
+	return (pcicfg_update_assigned_prop(dip, &addition));
+}
+
+static void
+pcicfg_device_on(ddi_acc_handle_t config_handle)
+{
+	/*
+	 * Enable memory, IO, and bus mastership
+	 * XXX should we enable parity, SERR#,
+	 * fast back-to-back, and addr. stepping?
+	 */
+	pci_config_put16(config_handle, PCI_CONF_COMM,
+	    pci_config_get16(config_handle, PCI_CONF_COMM) | 0x7);
+}
+
+static void
+pcicfg_device_off(ddi_acc_handle_t config_handle)
+{
+	/*
+	 * Disable I/O and memory traffic through the bridge
+	 */
+	pci_config_put16(config_handle, PCI_CONF_COMM, 0x0);
+}
+
+/*
+ * Setup the basic 1275 properties based on information found in the config
+ * header of the PCI device
+ */
+static int
+pcicfg_set_standard_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
+	uint8_t pcie_dev)
+{
+	int ret;
+	uint16_t val, cap_ptr;
+	uint32_t wordval;
+	uint8_t byteval;
+
+	/* These two exists only for non-bridges */
+	if (((pci_config_get8(config_handle, PCI_CONF_HEADER)
+	    & PCI_HEADER_TYPE_M) == PCI_HEADER_ZERO) && !pcie_dev) {
+		byteval = pci_config_get8(config_handle, PCI_CONF_MIN_G);
+		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+		    "min-grant", byteval)) != DDI_SUCCESS) {
+			return (ret);
+		}
+
+		byteval = pci_config_get8(config_handle, PCI_CONF_MAX_L);
+		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+		    "max-latency", byteval)) != DDI_SUCCESS) {
+			return (ret);
+		}
+	}
+
+	/*
+	 * These should always exist and have the value of the
+	 * corresponding register value
+	 */
+	val = pci_config_get16(config_handle, PCI_CONF_VENID);
+
+	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    "vendor-id", val)) != DDI_SUCCESS) {
+		return (ret);
+	}
+	val = pci_config_get16(config_handle, PCI_CONF_DEVID);
+	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    "device-id", val)) != DDI_SUCCESS) {
+		return (ret);
+	}
+	byteval = pci_config_get8(config_handle, PCI_CONF_REVID);
+	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    "revision-id", byteval)) != DDI_SUCCESS) {
+		return (ret);
+	}
+
+	wordval = (pci_config_get16(config_handle, PCI_CONF_SUBCLASS)<< 8) |
+	    (pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
+
+	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    "class-code", wordval)) != DDI_SUCCESS) {
+		return (ret);
+	}
+	/* devsel-speed starts at the 9th bit */
+	val = (pci_config_get16(config_handle,
+	    PCI_CONF_STAT) & PCI_STAT_DEVSELT) >> 9;
+	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    "devsel-speed", val)) != DDI_SUCCESS) {
+		return (ret);
+	}
+
+	/*
+	 * The next three are bits set in the status register.  The property is
+	 * present (but with no value other than its own existence) if the bit
+	 * is set, non-existent otherwise
+	 */
+	if ((!pcie_dev) &&
+	    (pci_config_get16(config_handle, PCI_CONF_STAT) &
+	    PCI_STAT_FBBC)) {
+		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+		    "fast-back-to-back", 0)) != DDI_SUCCESS) {
+			return (ret);
+		}
+	}
+	if ((!pcie_dev) &&
+	    (pci_config_get16(config_handle, PCI_CONF_STAT) &
+	    PCI_STAT_66MHZ)) {
+		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+		    "66mhz-capable", 0)) != DDI_SUCCESS) {
+			return (ret);
+		}
+	}
+	if (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_UDF) {
+		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+		    "udf-supported", 0)) != DDI_SUCCESS) {
+			return (ret);
+		}
+	}
+
+	/*
+	 * These next three are optional and are not present
+	 * if the corresponding register is zero.  If the value
+	 * is non-zero then the property exists with the value
+	 * of the register.
+	 */
+	if ((val = pci_config_get16(config_handle,
+	    PCI_CONF_SUBVENID)) != 0) {
+		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+		    "subsystem-vendor-id", val)) != DDI_SUCCESS) {
+			return (ret);
+		}
+	}
+	if ((val = pci_config_get16(config_handle,
+	    PCI_CONF_SUBSYSID)) != 0) {
+		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+		    "subsystem-id", val)) != DDI_SUCCESS) {
+			return (ret);
+		}
+	}
+	if ((val = pci_config_get16(config_handle,
+	    PCI_CONF_CACHE_LINESZ)) != 0) {
+		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+		    "cache-line-size", val)) != DDI_SUCCESS) {
+			return (ret);
+		}
+	}
+
+	/*
+	 * If the Interrupt Pin register is non-zero then the
+	 * interrupts property exists
+	 */
+	if ((byteval = pci_config_get8(config_handle, PCI_CONF_IPIN)) != 0) {
+		/*
+		 * If interrupt pin is non-zero,
+		 * record the interrupt line used
+		 */
+		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+		    "interrupts", byteval)) != DDI_SUCCESS) {
+			return (ret);
+		}
+	}
+
+	ret = PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr);
+
+	if (pcie_dev && (ret == DDI_SUCCESS)) {
+		val = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
+		    PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL;
+		/* if slot implemented, get physical slot number */
+		if (val) {
+			wordval = (PCI_CAP_GET32(config_handle, NULL,
+			    cap_ptr, PCIE_SLOTCAP) >>
+			    PCIE_SLOTCAP_PHY_SLOT_NUM_SHIFT) &
+			    PCIE_SLOTCAP_PHY_SLOT_NUM_MASK;
+			if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE,
+			    dip, "physical-slot#", wordval))
+			    != DDI_SUCCESS) {
+				return (ret);
+			}
+		}
+	}
+	return (PCICFG_SUCCESS);
+}
+static int
+pcicfg_set_busnode_props(dev_info_t *dip, uint8_t pcie_device_type,
+    int pbus, int sbus)
+{
+	int ret;
+	char device_type[8];
+
+	if (pcie_device_type)
+		(void) strcpy(device_type, "pciex");
+	else
+		(void) strcpy(device_type, "pci");
+
+	if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
+	    "device_type", device_type)) != DDI_SUCCESS) {
+		return (ret);
+	}
+	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    "#address-cells", 3)) != DDI_SUCCESS) {
+		return (ret);
+	}
+	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    "#size-cells", 2)) != DDI_SUCCESS) {
+		return (ret);
+	}
+
+	/*
+	 * Create primary-bus and secondary-bus properties to be used
+	 * to restore bus numbers in the pcicfg_setup_bridge() routine.
+	 */
+	if (pbus != -1 && sbus != -1) {
+		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+		    "primary-bus", pbus)) != DDI_SUCCESS) {
+				return (ret);
+		}
+		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+		    "secondary-bus", sbus)) != DDI_SUCCESS) {
+				return (ret);
+		}
+	}
+	return (PCICFG_SUCCESS);
+}
+
+static int
+pcicfg_set_childnode_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
+	uint8_t pcie_dev)
+{
+
+	int		ret;
+	char		*name;
+	char		buffer[64], pprefix[8];
+	uint16_t	classcode;
+	uint8_t		revid, pif, pclass, psubclass;
+	char		*compat[24];
+	int		i;
+	int		n;
+	uint16_t		sub_vid, sub_sid, vid, did;
+
+	/* set the property prefix based on the device type */
+	if (pcie_dev)
+		(void) sprintf(pprefix, "pciex");
+	else
+		(void) sprintf(pprefix, "pci");
+	sub_vid = pci_config_get16(config_handle, PCI_CONF_SUBVENID);
+	sub_sid = pci_config_get16(config_handle, PCI_CONF_SUBSYSID);
+	vid = pci_config_get16(config_handle, PCI_CONF_VENID);
+	did = pci_config_get16(config_handle, PCI_CONF_DEVID);
+	revid = pci_config_get8(config_handle, PCI_CONF_REVID);
+	pif = pci_config_get8(config_handle, PCI_CONF_PROGCLASS);
+	classcode = pci_config_get16(config_handle, PCI_CONF_SUBCLASS);
+	pclass = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
+	psubclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
+
+	/*
+	 * NOTE: These are for both a child and PCI-PCI bridge node
+	 */
+
+	/*
+	 *	"name" property rule
+	 *	--------------------
+	 *
+	 *
+	 * |	  \svid |
+	 * |	   \    |
+	 * |	    \   |
+	 * |	ssid \  |	=0		|	!= 0		|
+	 * |------------|-----------------------|-----------------------|
+	 * |		|			|			|
+	 * |	=0	|	vid,did		|	svid,ssid	|
+	 * |		|			|			|
+	 * |------------|-----------------------|-----------------------|
+	 * |		|			|			|
+	 * |	!=0	|	svid,ssid	|	svid,ssid	|
+	 * |		|			|			|
+	 * |------------|-----------------------|-----------------------|
+	 *
+	 * where:
+	 *    vid = vendor id
+	 *    did = device id
+	 *   svid = subsystem vendor id
+	 *   ssid = subsystem id
+	 */
+
+	if ((sub_sid != 0) || (sub_vid != 0)) {
+		(void) sprintf(buffer, "%s%x,%x", pprefix, sub_vid, sub_sid);
+	} else {
+		(void) sprintf(buffer, "%s%x,%x", pprefix, vid, did);
+	}
+
+	/*
+	 * In some environments, trying to use "generic" 1275 names is
+	 * not the convention.  In those cases use the name as created
+	 * above.  In all the rest of the cases, check to see if there
+	 * is a generic name first.
+	 */
+#ifdef _DONT_USE_1275_GENERIC_NAMES
+	name = buffer;
+#else
+	if ((name = pcicfg_get_class_name(classcode)) == NULL) {
+		/*
+		 * Set name to the above fabricated name
+		 */
+		name = buffer;
+	}
+#endif
+
+	/*
+	 * The node name field needs to be filled in with the name
+	 */
+	if (ndi_devi_set_nodename(dip, name, 0) != NDI_SUCCESS) {
+		DEBUG0("Failed to set nodename for node\n");
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * Create the compatible property as an array of pointers
+	 * to strings.  Start with the buffer created above.
+	 */
+	n = 0;
+	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+	(void) strcpy(compat[n++], buffer);
+
+	/*
+	 * Setup 'compatible' as per the PCI2.1 bindings document.
+	 *	pci[ex]VVVV,DDDD.SSSS.ssss.RR
+	 *	pci[ex]VVVV,DDDD.SSSS.ssss
+	 *	pciSSSS.ssss  -> not created for PCIe as per PCIe bindings
+	 *	pci[ex]VVVV,DDDD.RR
+	 *	pci[ex]VVVV,DDDD
+	 *	pci[ex]class,CCSSPP
+	 *	pci[ex]class,CCSS
+	 */
+
+	/* pci[ex]VVVV,DDDD.SSSS.ssss.RR */
+	(void) sprintf(buffer, "%s%x,%x.%x.%x.%x", pprefix,  vid, did,
+	    sub_vid, sub_sid, revid);
+	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+	(void) strcpy(compat[n++], buffer);
+
+	/* pci[ex]VVVV,DDDD.SSSS.ssss */
+	(void) sprintf(buffer, "%s%x,%x.%x.%x", pprefix,  vid, did,
+	    sub_vid, sub_sid);
+	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+	(void) strcpy(compat[n++], buffer);
+
+	/* pciSSSS.ssss  -> not created for PCIe as per PCIe bindings */
+	if (!pcie_dev) {
+		(void) sprintf(buffer, "pci%x,%x", sub_vid, sub_sid);
+		compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+		(void) strcpy(compat[n++], buffer);
+	}
+
+	/* pci[ex]VVVV,DDDD.RR */
+	(void) sprintf(buffer, "%s%x,%x.%x", pprefix,  vid, did, revid);
+	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+	(void) strcpy(compat[n++], buffer);
+
+	/* pci[ex]VVVV,DDDD */
+	(void) sprintf(buffer, "%s%x,%x", pprefix, vid, did);
+	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+	(void) strcpy(compat[n++], buffer);
+
+	/* pci[ex]class,CCSSPP */
+	(void) sprintf(buffer, "%sclass,%02x%02x%02x", pprefix,
+	    pclass, psubclass, pif);
+	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+	(void) strcpy(compat[n++], buffer);
+
+	/* pci[ex]class,CCSS */
+	(void) sprintf(buffer, "%sclass,%04x", pprefix, classcode);
+	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+	(void) strcpy(compat[n++], buffer);
+
+	if ((ret = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
+	    "compatible", (char **)compat, n)) != DDI_SUCCESS) {
+		return (ret);
+	}
+
+	for (i = 0; i < n; i++) {
+		kmem_free(compat[i], strlen(compat[i]) + 1);
+	}
+
+	DEBUG1("pcicfg_set_childnode_props - creating name=%s\n", name);
+	if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
+	    "name", name)) != DDI_SUCCESS) {
+
+		DEBUG0("pcicfg_set_childnode_props - Unable to create name "
+		    "property\n");
+
+		return (ret);
+	}
+
+	return (PCICFG_SUCCESS);
+}
+
+/*
+ * Program the bus numbers into the bridge
+ */
+
+static void
+pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle,
+uint_t primary, uint_t secondary, uint_t subordinate)
+{
+	DEBUG3("Setting bridge bus-range %d,%d,%d\n", primary, secondary,
+	    subordinate);
+	/*
+	 * Primary bus#
+	 */
+	pci_config_put8(config_handle, PCI_BCNF_PRIBUS, primary);
+
+	/*
+	 * Secondary bus#
+	 */
+	pci_config_put8(config_handle, PCI_BCNF_SECBUS, secondary);
+
+	/*
+	 * Subordinate bus#
+	 */
+	pci_config_put8(config_handle, PCI_BCNF_SUBBUS, subordinate);
+}
+
+/*
+ * Put bridge registers into initial state
+ */
+static void
+pcicfg_setup_bridge(pcicfg_phdl_t *entry,
+    ddi_acc_handle_t handle, dev_info_t *dip)
+{
+	int pbus, sbus;
+
+	/*
+	 * The highest bus seen during probing is the max-subordinate bus
+	 */
+	pci_config_put8(handle, PCI_BCNF_SUBBUS, entry->highest_bus);
+
+
+	/*
+	 * If there exists more than 1 downstream bridge, it
+	 * will be reset by the below secondary bus reset which
+	 * will clear the bus numbers assumed to be programmed in
+	 * the pcicfg_probe_children() routine.  We therefore restore
+	 * them here.
+	 */
+	if (pci_config_get8(handle, PCI_BCNF_SECBUS) == 0) {
+		pbus = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+		    DDI_PROP_DONTPASS, "primary-bus", -1);
+		sbus = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+		    DDI_PROP_DONTPASS, "secondary-bus", -1);
+		if (pbus != -1 && sbus != -1) {
+			pci_config_put8(handle, PCI_BCNF_PRIBUS, (uint_t)pbus);
+			pci_config_put8(handle, PCI_BCNF_SECBUS, (uint_t)sbus);
+		} else {
+			cmn_err(CE_WARN, "Invalid Bridge number detected: \
+			    %s%d: pbus = 0x%x, sbus = 0x%x",
+			    ddi_get_name(dip), ddi_get_instance(dip), pbus,
+			    sbus);
+		}
+	}
+
+	/*
+	 * Reset the secondary bus
+	 */
+	pci_config_put16(handle, PCI_BCNF_BCNTRL,
+	    pci_config_get16(handle, PCI_BCNF_BCNTRL) | 0x40);
+
+	drv_usecwait(100);
+
+	pci_config_put16(handle, PCI_BCNF_BCNTRL,
+	    pci_config_get16(handle, PCI_BCNF_BCNTRL) & ~0x40);
+
+	/*
+	 * Program the memory base register with the
+	 * start of the memory range
+	 */
+	pci_config_put16(handle, PCI_BCNF_MEM_BASE,
+	    PCICFG_HIWORD(PCICFG_LOADDR(entry->memory_last)));
+
+	/*
+	 * Program the I/O base register with the start of the I/O range
+	 */
+	pci_config_put8(handle, PCI_BCNF_IO_BASE_LOW,
+	    PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(entry->io_last))));
+	pci_config_put16(handle, PCI_BCNF_IO_BASE_HI,
+	    PCICFG_HIWORD(PCICFG_LOADDR(entry->io_last)));
+
+	/*
+	 * Clear status bits
+	 */
+	pci_config_put16(handle, PCI_BCNF_SEC_STATUS, 0xffff);
+
+	/*
+	 * Turn off prefetchable range
+	 */
+	pci_config_put32(handle, PCI_BCNF_PF_BASE_LOW, 0x0000ffff);
+	pci_config_put32(handle, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
+	pci_config_put32(handle, PCI_BCNF_PF_LIMIT_HIGH, 0x0);
+
+	/*
+	 * Needs to be set to this value
+	 */
+	pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
+
+	/*
+	 * After a Reset, we need to wait 2^25 clock cycles before the
+	 * first Configuration access.  The worst case is 33MHz, which
+	 * is a 1 second wait.
+	 */
+	drv_usecwait(pcicfg_sec_reset_delay);
+
+}
+
+static void
+pcicfg_update_bridge(pcicfg_phdl_t *entry,
+	ddi_acc_handle_t handle)
+{
+	uint_t length;
+
+	/*
+	 * Program the memory limit register with the end of the memory range
+	 */
+
+	DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
+	    PCICFG_ROUND_DOWN(entry->memory_last,
+	    PCICFG_MEMGRAN));
+
+	pci_config_put16(handle, PCI_BCNF_MEM_LIMIT,
+	    PCICFG_HIWORD(PCICFG_LOADDR(
+	    PCICFG_ROUND_DOWN(entry->memory_last,
+	    PCICFG_MEMGRAN))));
+	/*
+	 * Since this is a bridge, the rest of this range will
+	 * be responded to by the bridge.  We have to round up
+	 * so no other device claims it.
+	 */
+	if ((length = (PCICFG_ROUND_UP(entry->memory_last,
+	    PCICFG_MEMGRAN) - entry->memory_last)) > 0) {
+		(void) pcicfg_get_mem(entry, length, NULL);
+		DEBUG1("Added [0x%x]at the top of "
+		    "the bridge (mem)\n", length);
+	}
+
+	/*
+	 * Program the I/O limit register with the end of the I/O range
+	 */
+	pci_config_put8(handle, PCI_BCNF_IO_LIMIT_LOW,
+	    PCICFG_HIBYTE(PCICFG_LOWORD(
+	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last,
+	    PCICFG_IOGRAN)))));
+
+	pci_config_put16(handle, PCI_BCNF_IO_LIMIT_HI,
+	    PCICFG_HIWORD(PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last,
+	    PCICFG_IOGRAN))));
+
+	/*
+	 * Same as above for I/O space. Since this is a
+	 * bridge, the rest of this range will be responded
+	 * to by the bridge.  We have to round up so no
+	 * other device claims it.
+	 */
+	if ((length = (PCICFG_ROUND_UP(entry->io_last,
+	    PCICFG_IOGRAN) - entry->io_last)) > 0) {
+		(void) pcicfg_get_io(entry, length, NULL);
+		DEBUG1("Added [0x%x]at the top of "
+		    "the bridge (I/O)\n",  length);
+	}
+}
+
+/*ARGSUSED*/
+static void
+pcicfg_disable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h,
+	pcicfg_err_regs_t *regs)
+{
+	uint16_t val;
+
+	/* disable SERR generated in the context of Master Aborts. */
+	regs->cmd = val = pci_config_get16(h, PCI_CONF_COMM);
+	val &= ~PCI_COMM_SERR_ENABLE;
+	pci_config_put16(h, PCI_CONF_COMM, val);
+	regs->bcntl = val = pci_config_get16(h, PCI_BCNF_BCNTRL);
+	val &= ~PCI_BCNF_BCNTRL_SERR_ENABLE;
+	pci_config_put16(h, PCI_BCNF_BCNTRL, val);
+	/* clear any current pending errors */
+	pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB|
+	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
+	pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB|
+	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
+	/* if we are a PCIe device, disable the generation of UR, CE and NFE */
+	if (regs->pcie_dev) {
+		uint16_t devctl;
+		uint16_t cap_ptr;
+
+		if ((PCI_CAP_LOCATE(h, PCI_CAP_ID_PCI_E, &cap_ptr)) ==
+		    DDI_FAILURE)
+			return;
+
+		regs->pcie_cap_off = cap_ptr;
+		regs->devctl = devctl = PCI_CAP_GET16(h, NULL, cap_ptr,
+		    PCIE_DEVCTL);
+		devctl &= ~(PCIE_DEVCTL_UR_REPORTING_EN |
+		    PCIE_DEVCTL_CE_REPORTING_EN |
+		    PCIE_DEVCTL_NFE_REPORTING_EN |
+		    PCIE_DEVCTL_FE_REPORTING_EN);
+		PCI_CAP_PUT16(h, NULL, cap_ptr, PCIE_DEVCTL, devctl);
+	}
+}
+
+/*ARGSUSED*/
+static void
+pcicfg_enable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h,
+	pcicfg_err_regs_t *regs)
+{
+	/* clear any pending errors */
+	pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB|
+	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
+	pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB|
+	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
+
+	/* restore original settings */
+	if (regs->pcie_dev) {
+		pcie_clear_errors(dip);
+		pci_config_put16(h, regs->pcie_cap_off + PCIE_DEVCTL,
+		    regs->devctl);
+	}
+
+	pci_config_put16(h, PCI_BCNF_BCNTRL, regs->bcntl);
+	pci_config_put16(h, PCI_CONF_COMM, regs->cmd);
+
+}
+
+static int
+pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
+    uint_t func, uint_t *highest_bus, pcicfg_flags_t flags)
+{
+	dev_info_t		*new_child;
+	ddi_acc_handle_t	config_handle;
+	uint8_t			header_type, pcie_dev = 0;
+	int			ret;
+	pcicfg_err_regs_t	regs;
+
+	/*
+	 * This node will be put immediately below
+	 * "parent". Allocate a blank device node.  It will either
+	 * be filled in or freed up based on further probing.
+	 */
+	/*
+	 * Note: in usr/src/uts/common/io/hotplug/pcicfg/pcicfg.c
+	 * ndi_devi_alloc() is called as ndi_devi_alloc_sleep()
+	 */
+	if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME,
+	    (pnode_t)DEVI_SID_NODEID, &new_child)
+	    != NDI_SUCCESS) {
+		DEBUG0("pcicfg_probe_children(): Failed to alloc child node\n");
+		return (PCICFG_FAILURE);
+	}
+
+	if (pcicfg_add_config_reg(new_child, bus,
+	    device, func) != DDI_SUCCESS) {
+		DEBUG0("pcicfg_probe_children():"
+		    "Failed to add candidate REG\n");
+		goto failedconfig;
+	}
+
+	if ((ret = pcicfg_config_setup(new_child, &config_handle))
+	    != PCICFG_SUCCESS) {
+		if (ret == PCICFG_NODEVICE) {
+			(void) ndi_devi_free(new_child);
+			return (ret);
+		}
+		DEBUG0("pcicfg_probe_children():"
+		    "Failed to setup config space\n");
+		goto failedconfig;
+	}
+
+	/*
+	 * As soon as we have access to config space,
+	 * turn off device. It will get turned on
+	 * later (after memory is assigned).
+	 */
+	(void) pcicfg_device_off(config_handle);
+
+	/* check if we are PCIe device */
+	if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, &regs)
+	    == DDI_SUCCESS) {
+		DEBUG0("PCIe device detected\n");
+		pcie_dev = 1;
+	}
+
+	/*
+	 * Set 1275 properties common to all devices
+	 */
+	if (pcicfg_set_standard_props(new_child, config_handle,
+	    pcie_dev) != PCICFG_SUCCESS) {
+		DEBUG0("Failed to set standard properties\n");
+		goto failedchild;
+	}
+
+	/*
+	 * Child node properties  NOTE: Both for PCI-PCI bridge and child node
+	 */
+	if (pcicfg_set_childnode_props(new_child, config_handle,
+	    pcie_dev) != PCICFG_SUCCESS) {
+		goto failedchild;
+	}
+
+	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
+
+	/*
+	 * If this is not a multi-function card only probe function zero.
+	 */
+	if ((!(header_type & PCI_HEADER_MULTI)) && (func != 0)) {
+
+		(void) pcicfg_config_teardown(&config_handle);
+		(void) ndi_devi_free(new_child);
+		return (PCICFG_NODEVICE);
+	}
+
+	DEBUG1("---Vendor ID = [0x%x]\n",
+	    pci_config_get16(config_handle, PCI_CONF_VENID));
+	DEBUG1("---Device ID = [0x%x]\n",
+	    pci_config_get16(config_handle, PCI_CONF_DEVID));
+
+	/*
+	 * Attach the child to its parent
+	 */
+	(void) i_ndi_config_node(new_child, DS_LINKED, 0);
+
+	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
+
+		DEBUG3("--Bridge found bus [0x%x] device"
+		    "[0x%x] func [0x%x]\n", bus, device, func);
+
+		/* Only support read-only probe for leaf device */
+		if (flags & PCICFG_FLAG_READ_ONLY)
+			goto failedchild;
+
+		if (pcicfg_probe_bridge(new_child, config_handle,
+		    bus, highest_bus) != PCICFG_SUCCESS) {
+			(void) pcicfg_free_bridge_resources(new_child);
+			goto failedchild;
+		}
+
+	} else {
+
+		DEBUG3("--Leaf device found bus [0x%x] device"
+		    "[0x%x] func [0x%x]\n",
+		    bus, device, func);
+
+		if (flags & PCICFG_FLAG_READ_ONLY) {
+			/*
+			 * with read-only probe, don't do any resource
+			 * allocation, just read the BARs and update props.
+			 */
+			ret = pcicfg_populate_props_from_bar(new_child,
+			    config_handle);
+			if (ret != PCICFG_SUCCESS)
+				goto failedchild;
+
+			/*
+			 * for readonly probe "assigned-addresses" property
+			 * has already been setup by reading the BAR, here
+			 * just substract the resource from its parent here.
+			 */
+			ret = pcicfg_device_assign_readonly(new_child);
+			if (ret != PCICFG_SUCCESS) {
+				(void) pcicfg_free_device_resources(new_child,
+				    flags);
+				goto failedchild;
+			}
+		} else {
+			/*
+			 * update "reg" property by sizing the BARs.
+			 */
+			ret = pcicfg_populate_reg_props(new_child,
+			    config_handle);
+			if (ret != PCICFG_SUCCESS)
+				goto failedchild;
+
+			/* now allocate & program the resources */
+			ret = pcicfg_device_assign(new_child);
+			if (ret != PCICFG_SUCCESS) {
+				(void) pcicfg_free_device_resources(new_child,
+				    flags);
+				goto failedchild;
+			}
+		}
+
+		(void) ndi_devi_bind_driver(new_child, 0);
+	}
+
+	(void) pcicfg_config_teardown(&config_handle);
+	return (PCICFG_SUCCESS);
+
+failedchild:
+
+	(void) pcicfg_config_teardown(&config_handle);
+
+failedconfig:
+
+	(void) ndi_devi_free(new_child);
+	return (PCICFG_FAILURE);
+}
+
+/*
+ * Sizing the BARs and update "reg" property
+ */
+static int
+pcicfg_populate_reg_props(dev_info_t *new_child,
+    ddi_acc_handle_t config_handle)
+{
+	int		i;
+	uint32_t	request;
+
+	i = PCI_CONF_BASE0;
+
+	while (i <= PCI_CONF_BASE5) {
+
+		pci_config_put32(config_handle, i, 0xffffffff);
+
+		request = pci_config_get32(config_handle, i);
+		/*
+		 * If its a zero length, don't do
+		 * any programming.
+		 */
+		if (request != 0) {
+			/*
+			 * Add to the "reg" property
+			 */
+			if (pcicfg_update_reg_prop(new_child,
+			    request, i) != PCICFG_SUCCESS) {
+				goto failedchild;
+			}
+		} else {
+			DEBUG1("BASE register [0x%x] asks for "
+			    "[0x0]=[0x0](32)\n", i);
+			i += 4;
+			continue;
+		}
+
+		/*
+		 * Increment by eight if it is 64 bit address space
+		 */
+		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
+			DEBUG3("BASE register [0x%x] asks for "
+			    "[0x%x]=[0x%x] (64)\n",
+			    i, request,
+			    (~(PCI_BASE_M_ADDR_M & request))+1)
+			i += 8;
+		} else {
+			DEBUG3("BASE register [0x%x] asks for "
+			    "[0x%x]=[0x%x](32)\n",
+			    i, request,
+			    (~(PCI_BASE_M_ADDR_M & request))+1)
+			i += 4;
+		}
+	}
+
+	/*
+	 * Get the ROM size and create register for it
+	 */
+	pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
+
+	request = pci_config_get32(config_handle, PCI_CONF_ROM);
+	/*
+	 * If its a zero length, don't do
+	 * any programming.
+	 */
+
+	if (request != 0) {
+		DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
+		    PCI_CONF_ROM, request,
+		    (~(PCI_BASE_ROM_ADDR_M & request))+1);
+		/*
+		 * Add to the "reg" property
+		 */
+		if (pcicfg_update_reg_prop(new_child,
+		    request, PCI_CONF_ROM) != PCICFG_SUCCESS) {
+			goto failedchild;
+		}
+	}
+
+
+	return (PCICFG_SUCCESS);
+
+failedchild:
+	return (PCICFG_FAILURE);
+}
+
+static int
+pcicfg_fcode_probe(dev_info_t *parent, uint_t bus, uint_t device,
+    uint_t func, uint_t *highest_bus, pcicfg_flags_t flags)
+{
+	dev_info_t		*new_child;
+	int8_t			header_type;
+	int			ret;
+	ddi_acc_handle_t	h, ph;
+	int			error = 0;
+	extern int		pcicfg_dont_interpret;
+	pcicfg_err_regs_t	parent_regs, regs;
+	char			*status_prop = NULL;
+#ifdef PCICFG_INTERPRET_FCODE
+	struct pci_ops_bus_args	po;
+	fco_handle_t		c;
+	char			unit_address[64];
+	int			fcode_size = 0;
+	uchar_t			*fcode_addr;
+	uint64_t		mem_answer, mem_alen;
+	pci_regspec_t		p;
+	int32_t			request;
+	ndi_ra_request_t	req;
+	int16_t			vendor_id, device_id;
+#endif
+
+	/*
+	 * check if our parent is of type pciex.
+	 * if so, program config space to disable error msgs during probe.
+	 */
+	if (pcicfg_pcie_dev(parent, PCICFG_DEVICE_TYPE_PCIE, &parent_regs)
+	    == DDI_SUCCESS) {
+		DEBUG0("PCI/PCIe parent detected. Disable errors.\n");
+		/*
+		 * disable parent generating URs or SERR#s during probing
+		 * alone.
+		 */
+		if (pci_config_setup(parent, &ph) != DDI_SUCCESS)
+			return (DDI_FAILURE);
+
+		if ((flags & PCICFG_FLAG_READ_ONLY) == 0) {
+			pcicfg_disable_bridge_probe_err(parent,
+			    ph, &parent_regs);
+		}
+	}
+
+	/*
+	 * This node will be put immediately below
+	 * "parent". Allocate a blank device node.  It will either
+	 * be filled in or freed up based on further probing.
+	 */
+
+	if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME,
+	    (pnode_t)DEVI_SID_NODEID, &new_child)
+	    != NDI_SUCCESS) {
+		DEBUG0("pcicfg_fcode_probe(): Failed to alloc child node\n");
+		/* return (PCICFG_FAILURE); */
+		ret = PCICFG_FAILURE;
+		goto failed2;
+	}
+
+	/*
+	 * Create a dummy reg property.  This will be replaced with
+	 * a real reg property when fcode completes or if we need to
+	 * produce one by hand.
+	 */
+	if (pcicfg_add_config_reg(new_child, bus,
+	    device, func) != DDI_SUCCESS) {
+		ret = PCICFG_FAILURE;
+		goto failed3;
+	}
+#ifdef	EFCODE21554
+	if ((ret = pcicfg_config_setup(new_child, &h))
+	    != PCICFG_SUCCESS) {
+		DEBUG0("pcicfg_fcode_probe():"
+		    "Failed to setup config space\n");
+		ret = PCICFG_NODEVICE;
+		goto failed3;
+	}
+
+#else
+	p.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
+	p.pci_phys_mid = p.pci_phys_low = 0;
+	p.pci_size_hi = p.pci_size_low = 0;
+
+	/*
+	 * Map in configuration space (temporarily)
+	 */
+	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
+	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+
+	if (pcicfg_map_phys(new_child, &p, &virt, &acc, &h)) {
+		DEBUG0("pcicfg_fcode_probe():"
+		    "Failed to setup config space\n");
+		ret = PCICFG_NODEVICE;
+		goto failed3;
+	}
+
+	/*
+	 * First use ddi_peek16 so that if there is not a device there,
+	 * a bus error will not cause a panic.
+	 */
+	v = virt + PCI_CONF_VENID;
+	if (ddi_peek16(new_child, (int16_t *)v, &vendor_id)) {
+		DEBUG0("Can not read Vendor ID");
+		pcicfg_unmap_phys(&h, &p);
+		ret = PCICFG_NODEVICE;
+		goto failed3;
+	}
+#endif
+	DEBUG0("fcode_probe: conf space mapped.\n");
+	/*
+	 * As soon as we have access to config space,
+	 * turn off device. It will get turned on
+	 * later (after memory is assigned).
+	 */
+	(void) pcicfg_device_off(h);
+
+	/* check if we are PCIe device */
+	if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, &regs)
+	    == DDI_SUCCESS) {
+		/*EMPTY*/
+		DEBUG0("PCI/PCIe device detected\n");
+	}
+
+	/*
+	 * Set 1275 properties common to all devices
+	 */
+	if (pcicfg_set_standard_props(new_child,
+	    h, regs.pcie_dev) != PCICFG_SUCCESS) {
+		DEBUG0("Failed to set standard properties\n");
+		goto failed;
+	}
+
+	/*
+	 * Child node properties  NOTE: Both for PCI-PCI bridge and child node
+	 */
+	if (pcicfg_set_childnode_props(new_child,
+	    h, regs.pcie_dev) != PCICFG_SUCCESS) {
+		ret = PCICFG_FAILURE;
+		goto failed;
+	}
+
+	header_type = pci_config_get8(h, PCI_CONF_HEADER);
+
+	/*
+	 * If this is not a multi-function card only probe function zero.
+	 */
+	if (!(header_type & PCI_HEADER_MULTI) && (func > 0)) {
+
+		ret = PCICFG_NODEVICE;
+		goto failed;
+	}
+
+	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
+
+		/*
+		 * XXX - Transparent bridges are handled differently
+		 * than other devices with regards to fcode.  Since
+		 * no transparent bridge currently ships with fcode,
+		 * there is no reason to try to extract it from its rom
+		 * or call the fcode interpreter to try to load a drop-in.
+		 * If fcode is developed to handle transparent bridges,
+		 * this code will have to change.
+		 */
+
+		DEBUG3("--Bridge found bus [0x%x] device"
+		    "[0x%x] func [0x%x]\n", bus, device, func);
+
+		/* Only support read-only probe for leaf device */
+		if (flags & PCICFG_FLAG_READ_ONLY)
+			goto failed;
+
+		if ((ret = pcicfg_probe_bridge(new_child, h,
+		    bus, highest_bus)) != PCICFG_SUCCESS)
+			(void) pcicfg_free_bridge_resources(new_child);
+		goto done;
+	} else {
+
+		DEBUG3("--Leaf device found bus [0x%x] device"
+		    "[0x%x] func [0x%x]\n",
+		    bus, device, func);
+
+		/*
+		 * link in tree, but don't bind driver
+		 * We don't have compatible property yet
+		 */
+		(void) i_ndi_config_node(new_child, DS_LINKED, 0);
+
+		/* XXX for now, don't run Fcode in read-only probe. */
+		if (flags & PCICFG_FLAG_READ_ONLY)
+			goto no_fcode;
+
+		if (pci_config_get8(h, PCI_CONF_IPIN)) {
+			pci_config_put8(h, PCI_CONF_ILINE, 0xf);
+		}
+
+#ifdef PCICFG_INTERPRET_FCODE
+		/*
+		 * Some platforms (x86) don't run fcode, so don't interpret
+		 * fcode that might be in the ROM.
+		 */
+		if (pcicfg_dont_interpret == 0) {
+
+			/* This platform supports fcode */
+
+			vendor_id = pci_config_get16(h, PCI_CONF_VENID);
+			device_id = pci_config_get16(h, PCI_CONF_DEVID);
+
+			/*
+			 * Get the ROM size and create register for it
+			 */
+			pci_config_put32(h, PCI_CONF_ROM, 0xfffffffe);
+
+			request = pci_config_get32(h, PCI_CONF_ROM);
+
+			/*
+			 * If its a zero length, don't do
+			 * any programming.
+			 */
+
+			if (request != 0) {
+				/*
+				 * Add resource to assigned-addresses.
+				 */
+				if (pcicfg_fcode_assign_bars(h, new_child,
+				    bus, device, func, request, &p)
+				    != PCICFG_SUCCESS) {
+					DEBUG0("Failed to assign addresses to "
+					    "implemented BARs");
+					ret = PCICFG_FAILURE;
+					goto failed;
+				}
+
+				/* Turn device on */
+				(void) pcicfg_device_on(h);
+
+				/*
+				 * Attempt to load fcode.
+				 */
+				(void) pcicfg_load_fcode(new_child, bus, device,
+				    func, vendor_id, device_id, &fcode_addr,
+				    &fcode_size, PCICFG_LOADDR(mem_answer),
+				    (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
+
+				/* Turn device off */
+				(void) pcicfg_device_off(h);
+
+				/*
+				 * Free the ROM resources.
+				 */
+				(void) pcicfg_free_resource(new_child, p, 0);
+
+				DEBUG2("configure: fcode addr %lx size %x\n",
+				    fcode_addr, fcode_size);
+
+				/*
+				 * Create the fcode-rom-offset property.  The
+				 * buffer containing the fcode always starts
+				 * with 0xF1, so the fcode offset is zero.
+				 */
+				if (ndi_prop_update_int(DDI_DEV_T_NONE,
+				    new_child, "fcode-rom-offset", 0)
+				    != DDI_SUCCESS) {
+					DEBUG0("Failed to create "
+					    "fcode-rom-offset property\n");
+					ret = PCICFG_FAILURE;
+					goto failed;
+				}
+			} else {
+				DEBUG0("There is no Expansion ROM\n");
+				fcode_addr = NULL;
+				fcode_size = 0;
+			}
+
+			/*
+			 * Fill in the bus specific arguments. For
+			 * PCI, it is the config address.
+			 */
+			po.config_address =
+			    PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
+
+			DEBUG1("config_address=%x\n", po.config_address);
+
+			/*
+			 * Build unit address.
+			 */
+			(void) sprintf(unit_address, "%x,%x", device, func);
+
+			DEBUG3("pci_fc_ops_alloc_handle ap=%lx "
+			    "new device=%lx unit address=%s\n",
+			    parent, new_child, unit_address);
+
+			c = pci_fc_ops_alloc_handle(parent, new_child,
+			    fcode_addr, fcode_size, unit_address, &po);
+
+			DEBUG0("calling fcode_interpreter()\n");
+
+			DEBUG3("Before int DIP=%lx binding name %s major %d\n",
+			    new_child, ddi_binding_name(new_child),
+			    ddi_driver_major(new_child));
+
+			error = fcode_interpreter(parent, &pci_fc_ops, c);
+
+			DEBUG1("returned from fcode_interpreter() - "
+			    "returned %x\n", error);
+
+			pci_fc_ops_free_handle(c);
+
+			DEBUG1("fcode size = %x\n", fcode_size);
+			/*
+			 * We don't need the fcode anymore. While allocating
+			 * we had rounded up to a page size.
+			 */
+			if (fcode_size) {
+				kmem_free(fcode_addr, ptob(btopr(fcode_size)));
+			}
+		} else {
+			/* This platform does not support fcode */
+
+			DEBUG0("NOT calling fcode_interpreter()\n");
+		}
+
+#endif /* PCICFG_INTERPRET_FCODE */
+
+		if ((error == 0) && (pcicfg_dont_interpret == 0)) {
+			/*
+			 * The interpreter completed successfully.
+			 * We need to redo the resources based on the new reg
+			 * property.
+			 */
+			DEBUG3("DIP=%lx binding name %s major %d\n", new_child,
+			    ddi_binding_name(new_child),
+			    ddi_driver_major(new_child));
+
+			/*
+			 * Readjust resources specified by reg property.
+			 */
+			if (pcicfg_alloc_new_resources(new_child) ==
+			    PCICFG_FAILURE) {
+				ret = PCICFG_FAILURE;
+				goto failed;
+			}
+
+			/*
+			 * At this stage, there should be enough info to pull
+			 * the status property if it exists.
+			 */
+			if (ddi_prop_lookup_string(DDI_DEV_T_ANY,
+			    new_child, NULL, "status", &status_prop) ==
+			    DDI_PROP_SUCCESS) {
+				if ((strncmp("disabled", status_prop, 8) ==
+				    0) || (strncmp("fail", status_prop, 4) ==
+				    0)) {
+					ret = PCICFG_FAILURE;
+					ddi_prop_free(status_prop);
+					goto failed;
+				} else {
+					ddi_prop_free(status_prop);
+				}
+			}
+
+			ret = PCICFG_SUCCESS;
+			/* no fcode, bind driver now */
+			(void) ndi_devi_bind_driver(new_child, 0);
+
+			goto done;
+		} else if ((error != FC_NO_FCODE) &&
+		    (pcicfg_dont_interpret == 0))  {
+			/*
+			 * The interpreter located fcode, but had an error in
+			 * processing. Cleanup and fail the operation.
+			 */
+			DEBUG0("Interpreter detected fcode failure\n");
+			(void) pcicfg_free_resources(new_child, flags);
+			ret = PCICFG_FAILURE;
+			goto failed;
+		} else {
+no_fcode:
+			/*
+			 * Either the interpreter failed with FC_NO_FCODE or we
+			 * chose not to run the interpreter
+			 * (pcicfg_dont_interpret).
+			 *
+			 * If the interpreter failed because there was no
+			 * dropin, then we need to probe the device ourself.
+			 */
+
+			/*
+			 * Free any resources that may have been assigned
+			 * during fcode loading/execution since we need
+			 * to start over.
+			 */
+			(void) pcicfg_free_resources(new_child, flags);
+
+#ifdef	EFCODE21554
+			pcicfg_config_teardown(&h);
+#else
+			pcicfg_unmap_phys(&h, &p);
+#endif
+			(void) ndi_devi_free(new_child);
+
+			DEBUG0("No Drop-in Probe device ourself\n");
+
+			ret = pcicfg_probe_children(parent, bus, device, func,
+			    highest_bus, flags);
+
+			if (ret != PCICFG_SUCCESS) {
+				DEBUG0("Could not self probe child\n");
+				goto failed2;
+			}
+
+			/*
+			 * We successfully self probed the device.
+			 */
+			if ((new_child = pcicfg_devi_find(
+			    parent, device, func)) == NULL) {
+				DEBUG0("Did'nt find device node "
+				    "just created\n");
+				ret = PCICFG_FAILURE;
+				goto failed2;
+			}
+#ifdef	EFCODE21554
+			/*
+			 * Till now, we have detected a non transparent bridge
+			 * (ntbridge) as a part of the generic probe code and
+			 * configured only one configuration
+			 * header which is the side facing the host bus.
+			 * Now, configure the other side and create children.
+			 *
+			 * To make the process simpler, lets load the device
+			 * driver for the non transparent bridge as this is a
+			 * Solaris bundled driver, and use its configuration map
+			 * services rather than programming it here.
+			 * If the driver is not bundled into Solaris, it must be
+			 * first loaded and configured before performing any
+			 * hotplug operations.
+			 *
+			 * This not only makes the code simpler but also more
+			 * generic.
+			 *
+			 * So here we go.
+			 */
+			if (pcicfg_is_ntbridge(new_child) != DDI_FAILURE) {
+
+				DEBUG0("Found nontransparent bridge.\n");
+
+				ret = pcicfg_configure_ntbridge(new_child,
+				    bus, device);
+			}
+			if (ret != PCICFG_SUCCESS) {
+				/*
+				 * Bridge configure failed. Free up the self
+				 * probed entry. The bus resource allocation
+				 * maps need to be cleaned up to prevent
+				 * warnings on retries of the failed configure.
+				 */
+				(void) pcicfg_ntbridge_unconfigure(new_child);
+				(void) pcicfg_teardown_device(new_child, flags);
+			}
+#endif
+			goto done2;
+		}
+	}
+done:
+failed:
+#ifdef	EFCODE21554
+	pcicfg_config_teardown(&h);
+#else
+	pcicfg_unmap_phys(&h, &p);
+#endif
+failed3:
+	if (ret != PCICFG_SUCCESS)
+		(void) ndi_devi_free(new_child);
+done2:
+failed2:
+	if (parent_regs.pcie_dev) {
+		if ((flags & PCICFG_FLAG_READ_ONLY) == 0) {
+			pcicfg_enable_bridge_probe_err(parent,
+			    ph, &parent_regs);
+		}
+		pci_config_teardown(&ph);
+	}
+	return (ret);
+}
+
+/*
+ * Read the BARs and update properties. Used in virtual hotplug.
+ */
+static int
+pcicfg_populate_props_from_bar(dev_info_t *new_child,
+    ddi_acc_handle_t config_handle)
+{
+	uint32_t request, base, base_hi, size;
+	int i;
+
+	i = PCI_CONF_BASE0;
+
+	while (i <= PCI_CONF_BASE5) {
+		/*
+		 * determine the size of the address space
+		 */
+		base = pci_config_get32(config_handle, i);
+		pci_config_put32(config_handle, i, 0xffffffff);
+		request = pci_config_get32(config_handle, i);
+		pci_config_put32(config_handle, i, base);
+
+		/*
+		 * If its a zero length, don't do any programming.
+		 */
+		if (request != 0) {
+			/*
+			 * Add to the "reg" property
+			 */
+			if (pcicfg_update_reg_prop(new_child,
+			    request, i) != PCICFG_SUCCESS) {
+				goto failedchild;
+			}
+
+			if ((PCI_BASE_SPACE_IO & request) == 0 &&
+			    (PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
+				base_hi = pci_config_get32(config_handle, i+4);
+			} else {
+				base_hi = 0;
+			}
+			/*
+			 * Add to "assigned-addresses" property
+			 */
+			size = (~(PCI_BASE_M_ADDR_M & request))+1;
+			if (pcicfg_update_assigned_prop_value(new_child,
+			    size, base, base_hi, i) != PCICFG_SUCCESS) {
+				goto failedchild;
+			}
+		} else {
+			DEBUG1("BASE register [0x%x] asks for "
+			"[0x0]=[0x0](32)\n", i);
+			i += 4;
+			continue;
+		}
+
+		/*
+		 * Increment by eight if it is 64 bit address space
+		 */
+		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
+			DEBUG3("BASE register [0x%x] asks for "
+			"[0x%x]=[0x%x] (64)\n",
+			    i, request,
+			    (~(PCI_BASE_M_ADDR_M & request))+1)
+			i += 8;
+		} else {
+			DEBUG3("BASE register [0x%x] asks for "
+			"[0x%x]=[0x%x](32)\n",
+			    i, request,
+			    (~(PCI_BASE_M_ADDR_M & request))+1)
+			i += 4;
+		}
+	}
+
+	/*
+	 * Get the ROM size and create register for it
+	 */
+	base = pci_config_get32(config_handle, PCI_CONF_ROM);
+	pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
+	request = pci_config_get32(config_handle, PCI_CONF_ROM);
+	pci_config_put32(config_handle, PCI_CONF_ROM, base);
+
+	/*
+	 * If its a zero length, don't do
+	 * any programming.
+	 */
+	if (request != 0) {
+		DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
+		    PCI_CONF_ROM, request,
+		    (~(PCI_BASE_ROM_ADDR_M & request))+1);
+		/*
+		 * Add to the "reg" property
+		 */
+		if (pcicfg_update_reg_prop(new_child,
+		    request, PCI_CONF_ROM) != PCICFG_SUCCESS) {
+			goto failedchild;
+		}
+		/*
+		 * Add to "assigned-addresses" property
+		 */
+		size = (~(PCI_BASE_ROM_ADDR_M & request))+1;
+		if (pcicfg_update_assigned_prop_value(new_child, size,
+		    base, 0, PCI_CONF_ROM) != PCICFG_SUCCESS) {
+			goto failedchild;
+		}
+	}
+
+	return (PCICFG_SUCCESS);
+
+failedchild:
+	return (PCICFG_FAILURE);
+}
+
+static int
+pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
+    uint_t *highest_bus)
+{
+	uint64_t next_bus;
+	uint_t new_bus, num_slots;
+	ndi_ra_request_t req;
+	int rval, i, j;
+	uint64_t mem_answer, mem_base, mem_alen, mem_size, mem_end;
+	uint64_t io_answer, io_base, io_alen, io_size, io_end;
+	uint64_t round_answer, round_len;
+	pcicfg_range_t range[PCICFG_RANGE_LEN];
+	int bus_range[2];
+	pcicfg_phdl_t phdl;
+	int count;
+	uint64_t pcibus_base, pcibus_alen;
+	uint64_t max_bus;
+	uint8_t pcie_device_type = 0;
+	dev_info_t *new_device;
+	int trans_device;
+	int ari_mode = B_FALSE;
+	int max_function = PCICFG_MAX_FUNCTION;
+
+	/*
+	 * Set "device_type" to "pci", the actual type will be set later
+	 * by pcicfg_set_busnode_props() below. This is needed as the
+	 * pcicfg_ra_free() below would update "available" property based
+	 * on "device_type".
+	 *
+	 * This code can be removed later after PCI configurator is changed
+	 * to use PCIRM, which automatically update properties upon allocation
+	 * and free, at that time we'll be able to remove the code inside
+	 * ndi_ra_alloc/free() which currently updates "available" property
+	 * for pci/pcie devices in pcie fabric.
+	 */
+	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
+	    "device_type", "pci") != DDI_SUCCESS) {
+		DEBUG0("Failed to set \"device_type\" props\n");
+		return (PCICFG_FAILURE);
+	}
+
+	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
+	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
+	req.ra_boundbase = 0;
+	req.ra_boundlen = PCICFG_MAX_BUS_DEPTH;
+	req.ra_len = PCICFG_MAX_BUS_DEPTH;
+	req.ra_align_mask = 0;  /* no alignment needed */
+
+	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
+	    &pcibus_base, &pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
+
+	if (rval != NDI_SUCCESS) {
+		if (rval == NDI_RA_PARTIAL_REQ) {
+			/*EMPTY*/
+			DEBUG0("NDI_RA_PARTIAL_REQ returned for bus range\n");
+		} else {
+			DEBUG0(
+			    "Failed to allocate bus range for bridge\n");
+			return (PCICFG_FAILURE);
+		}
+	}
+
+	DEBUG2("Bus Range Allocated [base=%d] [len=%d]\n",
+	    pcibus_base, pcibus_alen);
+
+	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_BUSNUM)
+	    == NDI_FAILURE) {
+		DEBUG0("Can not setup resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * Put available bus range into the pool.
+	 * Take the first one for this bridge to use and don't give
+	 * to child.
+	 */
+	(void) ndi_ra_free(new_child, pcibus_base+1, pcibus_alen-1,
+	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
+
+	next_bus = pcibus_base;
+	max_bus = pcibus_base + pcibus_alen - 1;
+
+	new_bus = next_bus;
+
+	DEBUG1("NEW bus found  ->[%d]\n", new_bus);
+
+	/* Keep track of highest bus for subordinate bus programming */
+	*highest_bus = new_bus;
+
+	/*
+	 * Allocate Memory Space for Bridge
+	 */
+	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
+	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
+	req.ra_boundbase = 0;
+	/*
+	 * Note: To support a 32b system, boundlen and len need to be
+	 * 32b quantities
+	 */
+	req.ra_boundlen = PCICFG_4GIG_LIMIT + 1;
+	req.ra_len = PCICFG_4GIG_LIMIT + 1; /* Get as big as possible */
+	req.ra_align_mask =
+	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
+
+	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
+	    &mem_answer, &mem_alen,  NDI_RA_TYPE_MEM, NDI_RA_PASS);
+
+	if (rval != NDI_SUCCESS) {
+		if (rval == NDI_RA_PARTIAL_REQ) {
+			/*EMPTY*/
+			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
+		} else {
+			DEBUG0(
+			    "Failed to allocate memory for bridge\n");
+			return (PCICFG_FAILURE);
+		}
+	}
+
+	DEBUG3("Bridge Memory Allocated [0x%x.%x] len [0x%x]\n",
+	    PCICFG_HIADDR(mem_answer),
+	    PCICFG_LOADDR(mem_answer),
+	    mem_alen);
+
+	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
+		DEBUG0("Can not setup resource map - NDI_RA_TYPE_MEM\n");
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * Put available memory into the pool.
+	 */
+	(void) ndi_ra_free(new_child, mem_answer, mem_alen, NDI_RA_TYPE_MEM,
+	    NDI_RA_PASS);
+
+	mem_base = mem_answer;
+
+	/*
+	 * Allocate I/O Space for Bridge
+	 */
+	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
+	req.ra_align_mask = PCICFG_IOGRAN - 1; /* 4k alignment */
+	req.ra_boundbase = 0;
+	req.ra_boundlen = PCICFG_4GIG_LIMIT;
+	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
+	req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
+
+	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, &io_answer,
+	    &io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
+
+	if (rval != NDI_SUCCESS) {
+		if (rval == NDI_RA_PARTIAL_REQ) {
+			/*EMPTY*/
+			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
+		} else {
+			DEBUG0("Failed to allocate io space for bridge\n");
+			io_base = io_answer = io_alen = 0;
+			/* return (PCICFG_FAILURE); */
+		}
+	}
+
+	if (io_alen) {
+		DEBUG3("Bridge IO Space Allocated [0x%x.%x] len [0x%x]\n",
+		    PCICFG_HIADDR(io_answer), PCICFG_LOADDR(io_answer),
+		    io_alen);
+
+		if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_IO) ==
+		    NDI_FAILURE) {
+			DEBUG0("Can not setup resource map - NDI_RA_TYPE_IO\n");
+			return (PCICFG_FAILURE);
+		}
+
+		/*
+		 * Put available I/O into the pool.
+		 */
+		(void) ndi_ra_free(new_child, io_answer, io_alen,
+		    NDI_RA_TYPE_IO, NDI_RA_PASS);
+		io_base = io_answer;
+	}
+
+	pcicfg_set_bus_numbers(h, bus, new_bus, max_bus);
+
+	/*
+	 * Setup "bus-range" property before onlining the bridge.
+	 */
+	bus_range[0] = new_bus;
+	bus_range[1] = max_bus;
+
+	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
+	    "bus-range", bus_range, 2) != DDI_SUCCESS) {
+		DEBUG0("Failed to set bus-range property");
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * Reset the secondary bus
+	 */
+	pci_config_put16(h, PCI_BCNF_BCNTRL,
+	    pci_config_get16(h, PCI_BCNF_BCNTRL) | 0x40);
+
+	drv_usecwait(100);
+
+	pci_config_put16(h, PCI_BCNF_BCNTRL,
+	    pci_config_get16(h, PCI_BCNF_BCNTRL) & ~0x40);
+
+	/*
+	 * Program the memory base register with the
+	 * start of the memory range
+	 */
+	pci_config_put16(h, PCI_BCNF_MEM_BASE,
+	    PCICFG_HIWORD(PCICFG_LOADDR(mem_answer)));
+
+	/*
+	 * Program the memory limit register with the
+	 * end of the memory range.
+	 */
+
+	pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
+	    PCICFG_HIWORD(PCICFG_LOADDR(
+	    PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN) - 1)));
+
+	/*
+	 * Allocate the chunk of memory (if any) not programmed into the
+	 * bridge because of the round down.
+	 */
+	if (PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN)
+	    != (mem_answer + mem_alen)) {
+		DEBUG0("Need to allocate Memory round off chunk\n");
+		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
+		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
+		req.ra_addr = PCICFG_ROUND_DOWN((mem_answer + mem_alen),
+		    PCICFG_MEMGRAN);
+		req.ra_len =  (mem_answer + mem_alen) -
+		    (PCICFG_ROUND_DOWN((mem_answer + mem_alen),
+		    PCICFG_MEMGRAN));
+
+		(void) ndi_ra_alloc(new_child, &req,
+		    &round_answer, &round_len,  NDI_RA_TYPE_MEM, NDI_RA_PASS);
+	}
+
+	/*
+	 * Program the I/O Space Base
+	 */
+	pci_config_put8(h, PCI_BCNF_IO_BASE_LOW,
+	    PCICFG_HIBYTE(PCICFG_LOWORD(
+	    PCICFG_LOADDR(io_answer))));
+
+	pci_config_put16(h, PCI_BCNF_IO_BASE_HI,
+	    PCICFG_HIWORD(PCICFG_LOADDR(io_answer)));
+
+	/*
+	 * Program the I/O Space Limit
+	 */
+	pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
+	    PCICFG_HIBYTE(PCICFG_LOWORD(
+	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(io_answer + io_alen,
+	    PCICFG_IOGRAN)))) - 1);
+
+	pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
+	    PCICFG_HIWORD(PCICFG_LOADDR(
+	    PCICFG_ROUND_DOWN(io_answer + io_alen, PCICFG_IOGRAN)))
+	    - 1);
+
+	/*
+	 * Allocate the chunk of I/O (if any) not programmed into the
+	 * bridge because of the round down.
+	 */
+	if (PCICFG_ROUND_DOWN((io_answer + io_alen), PCICFG_IOGRAN)
+	    != (io_answer + io_alen)) {
+		DEBUG0("Need to allocate I/O round off chunk\n");
+		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
+		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
+		req.ra_addr = PCICFG_ROUND_DOWN((io_answer + io_alen),
+		    PCICFG_IOGRAN);
+		req.ra_len =  (io_answer + io_alen) -
+		    (PCICFG_ROUND_DOWN((io_answer + io_alen),
+		    PCICFG_IOGRAN));
+
+		(void) ndi_ra_alloc(new_child, &req,
+		    &round_answer, &round_len,  NDI_RA_TYPE_IO, NDI_RA_PASS);
+	}
+
+	/*
+	 * Setup "ranges" property before onlining the bridge.
+	 */
+	bzero((caddr_t)range, sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
+
+	range[0].child_hi = range[0].parent_hi |= (PCI_REG_REL_M | PCI_ADDR_IO);
+	range[0].child_lo = range[0].parent_lo = io_base;
+	range[1].child_hi = range[1].parent_hi |=
+	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
+	range[1].child_lo = range[1].parent_lo = mem_base;
+
+	range[0].size_lo = io_alen;
+	if (pcicfg_update_ranges_prop(new_child, &range[0])) {
+		DEBUG0("Failed to update ranges (io)\n");
+		return (PCICFG_FAILURE);
+	}
+	range[1].size_lo = mem_alen;
+	if (pcicfg_update_ranges_prop(new_child, &range[1])) {
+		DEBUG0("Failed to update ranges (memory)\n");
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * Clear status bits
+	 */
+	pci_config_put16(h, PCI_BCNF_SEC_STATUS, 0xffff);
+
+	/*
+	 * Turn off prefetchable range
+	 */
+	pci_config_put32(h, PCI_BCNF_PF_BASE_LOW, 0x0000ffff);
+	pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
+	pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH, 0x0);
+
+	/*
+	 * Needs to be set to this value
+	 */
+	pci_config_put8(h, PCI_CONF_ILINE, 0xf);
+
+	/* check our device_type as defined by Open Firmware */
+	if (pcicfg_pcie_device_type(new_child, h) == DDI_SUCCESS)
+		pcie_device_type = 1;
+
+	/*
+	 * Set bus properties
+	 */
+	if (pcicfg_set_busnode_props(new_child, pcie_device_type,
+	    (int)bus, (int)new_bus) != PCICFG_SUCCESS) {
+		DEBUG0("Failed to set busnode props\n");
+		return (PCICFG_FAILURE);
+	}
+
+	(void) pcicfg_device_on(h);
+
+	if (ndi_devi_online(new_child, NDI_NO_EVENT|NDI_CONFIG)
+	    != NDI_SUCCESS) {
+		DEBUG0("Unable to online bridge\n");
+		return (PCICFG_FAILURE);
+	}
+
+	DEBUG0("Bridge is ONLINE\n");
+
+	/*
+	 * After a Reset, we need to wait 2^25 clock cycles before the
+	 * first Configuration access.  The worst case is 33MHz, which
+	 * is a 1 second wait.
+	 */
+	drv_usecwait(pcicfg_sec_reset_delay);
+
+	/*
+	 * Probe all children devices
+	 */
+	DEBUG0("Bridge Programming Complete - probe children\n");
+	ndi_devi_enter(new_child, &count);
+	for (i = 0; ((i < PCICFG_MAX_DEVICE) && (ari_mode == B_FALSE));
+	    i++) {
+		for (j = 0; j < max_function; ) {
+			if (ari_mode)
+				trans_device = j >> 3;
+			else
+				trans_device = i;
+
+			if ((rval = pcicfg_fcode_probe(new_child,
+			    new_bus, trans_device, (j & 7), highest_bus, 0))
+			    != PCICFG_SUCCESS) {
+				if (rval == PCICFG_NODEVICE) {
+					DEBUG3("No Device at bus [0x%x]"
+					    "device [0x%x] "
+					    "func [0x%x]\n", new_bus,
+					    trans_device, j & 7);
+
+					if (j)
+						goto next;
+				} else {
+					DEBUG3("Failed to configure bus "
+					    "[0x%x] device [0x%x] "
+					    "func [0x%x]\n", new_bus,
+					    trans_device, j & 7);
+
+					rval = PCICFG_FAILURE;
+				}
+				break;
+			}
+next:
+			new_device = pcicfg_devi_find(new_child,
+			    trans_device, (j & 7));
+
+			/*
+			 * Determine if ARI Forwarding should be enabled.
+			 */
+			if (j == 0) {
+				if (new_device == NULL)
+					break;
+
+				if ((pcie_ari_supported(new_child) ==
+				    PCIE_ARI_FORW_ENABLED) &&
+				    (pcie_ari_device(new_device) ==
+				    PCIE_ARI_DEVICE)) {
+					if (pcie_ari_enable(new_child) ==
+					    DDI_SUCCESS) {
+						(void) ddi_prop_create(
+						    DDI_DEV_T_NONE,
+						    new_child,
+						    DDI_PROP_CANSLEEP,
+						    "ari-enabled", NULL, 0);
+						ari_mode = B_TRUE;
+						max_function =
+						    PCICFG_MAX_ARI_FUNCTION;
+					}
+				}
+			}
+
+			if (ari_mode == B_TRUE) {
+				int next_function;
+
+				if (new_device == NULL)
+					break;
+
+				if (pcie_ari_get_next_function(new_device,
+				    &next_function) != DDI_SUCCESS)
+					break;
+
+				j = next_function;
+
+				if (next_function == 0)
+					break;
+			} else
+				j++;
+		}
+	}
+
+	ndi_devi_exit(new_child, count);
+
+	/* if empty topology underneath, it is still a success. */
+	if (rval != PCICFG_FAILURE)
+		rval = PCICFG_SUCCESS;
+
+	/*
+	 * Offline the bridge to allow reprogramming of resources.
+	 *
+	 * This should always succeed since nobody else has started to
+	 * use it yet, failing to detach the driver would indicate a bug.
+	 * Also in that case it's better just panic than allowing the
+	 * configurator to proceed with BAR reprogramming without bridge
+	 * driver detached.
+	 */
+	VERIFY(ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG)
+	    == NDI_SUCCESS);
+
+	phdl.dip = new_child;
+	phdl.memory_base = mem_answer;
+	phdl.io_base = (uint32_t)io_answer;
+	phdl.error = PCICFG_SUCCESS;    /* in case of empty child tree */
+
+	ndi_devi_enter(ddi_get_parent(new_child), &count);
+	ddi_walk_devs(new_child, pcicfg_find_resource_end, (void *)&phdl);
+	ndi_devi_exit(ddi_get_parent(new_child), count);
+
+	if (phdl.error != PCICFG_SUCCESS) {
+		DEBUG0("Failure summing resources\n");
+		return (PCICFG_FAILURE);
+	}
+
+	num_slots = pcicfg_get_nslots(new_child, h);
+	mem_end = PCICFG_ROUND_UP(phdl.memory_base, PCICFG_MEMGRAN);
+	io_end = PCICFG_ROUND_UP(phdl.io_base, PCICFG_IOGRAN);
+
+	DEBUG3("Start of Unallocated Bridge(%d slots) Resources "
+	    "Mem=0x%lx I/O=0x%lx\n", num_slots, mem_end, io_end);
+
+	/*
+	 * Before probing the children we've allocated maximum MEM/IO
+	 * resources from parent, and updated "available" property
+	 * accordingly. Later we'll be giving up unused resources to
+	 * the parent, thus we need to destroy "available" property
+	 * here otherwise it will be out-of-sync with the actual free
+	 * resources this bridge has. This property will be rebuilt below
+	 * with the actual free resources reserved for hotplug slots
+	 * (if any).
+	 */
+	(void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "available");
+	/*
+	 * if the bridge a slots, then preallocate. If not, assume static
+	 * configuration. Also check for preallocation limits and spit
+	 * warning messages appropriately (perhaps some can be in debug mode).
+	 */
+	if (num_slots) {
+		pci_regspec_t reg;
+		uint64_t mem_assigned = mem_end;
+		uint64_t io_assigned = io_end;
+		uint64_t mem_reqd = mem_answer + (num_slots *
+		    pcicfg_slot_memsize);
+		uint64_t io_reqd = io_answer + (num_slots *
+		    pcicfg_slot_iosize);
+		uint8_t highest_bus_reqd = new_bus + (num_slots *
+		    pcicfg_slot_busnums);
+#ifdef DEBUG
+		if (mem_end > mem_reqd)
+			DEBUG3("Memory space consumed by bridge"
+			    " more than planned for %d slot(s)(%lx, %lx)",
+			    num_slots, mem_answer, mem_end);
+		if (io_end > io_reqd)
+			DEBUG3("IO space consumed by bridge"
+			    " more than planned for %d slot(s)(%lx, %lx)",
+			    num_slots, io_answer, io_end);
+		if (*highest_bus > highest_bus_reqd)
+			DEBUG3("Buses consumed by bridge"
+			    " more than planned for %d slot(s)(%x, %x)",
+			    num_slots, new_bus, *highest_bus);
+
+		if (mem_reqd > (mem_answer + mem_alen))
+			DEBUG3("Memory space required by bridge"
+			    " more than available for %d slot(s)(%lx, %lx)",
+			    num_slots, mem_answer, mem_end);
+
+		if (io_reqd > (io_answer + io_alen))
+			DEBUG3("IO space required by bridge"
+			    " more than available for %d slot(s)(%lx, %lx)",
+			    num_slots, io_answer, io_end);
+		if (highest_bus_reqd > max_bus)
+			DEBUG3("Bus numbers required by bridge"
+			    " more than available for %d slot(s)(%x, %x)",
+			    num_slots, new_bus, *highest_bus);
+#endif
+		mem_end = MAX((MIN(mem_reqd, (mem_answer + mem_alen))),
+		    mem_end);
+		io_end = MAX((MIN(io_reqd, (io_answer + io_alen))), io_end);
+		*highest_bus = MAX((MIN(highest_bus_reqd, max_bus)),
+		    *highest_bus);
+		DEBUG3("mem_end %lx, io_end %lx, highest_bus %x\n",
+		    mem_end, io_end, *highest_bus);
+
+		mem_size = mem_end - mem_assigned;
+		io_size = io_end - io_assigned;
+
+		reg.pci_phys_mid = reg.pci_size_hi = 0;
+		if (io_size > 0) {
+			reg.pci_phys_hi = (PCI_REG_REL_M | PCI_ADDR_IO);
+			reg.pci_phys_low = io_assigned;
+			reg.pci_size_low = io_size;
+			if (pcicfg_update_available_prop(new_child, &reg)) {
+				DEBUG0("Failed to update available prop "
+				    "(io)\n");
+				return (PCICFG_FAILURE);
+			}
+		}
+		if (mem_size > 0) {
+			reg.pci_phys_hi = (PCI_REG_REL_M | PCI_ADDR_MEM32);
+			reg.pci_phys_low = mem_assigned;
+			reg.pci_size_low = mem_size;
+			if (pcicfg_update_available_prop(new_child, &reg)) {
+				DEBUG0("Failed to update available prop "
+				    "(memory)\n");
+				return (PCICFG_FAILURE);
+			}
+		}
+	}
+
+	/*
+	 * Give back unused memory space to parent.
+	 */
+	(void) ndi_ra_free(ddi_get_parent(new_child),
+	    mem_end, (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM,
+	    NDI_RA_PASS);
+
+	if (mem_end == mem_answer) {
+		DEBUG0("No memory resources used\n");
+		/*
+		 * To prevent the bridge from forwarding any Memory
+		 * transactions, the Memory Limit will be programmed
+		 * with a smaller value than the Memory Base.
+		 */
+		pci_config_put16(h, PCI_BCNF_MEM_BASE, 0xffff);
+		pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 0);
+
+		mem_size = 0;
+	} else {
+		/*
+		 * Reprogram the end of the memory.
+		 */
+		pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
+		    PCICFG_HIWORD(mem_end) - 1);
+		mem_size = mem_end - mem_base;
+	}
+
+	/*
+	 * Give back unused io space to parent.
+	 */
+	(void) ndi_ra_free(ddi_get_parent(new_child),
+	    io_end, (io_answer + io_alen) - io_end,
+	    NDI_RA_TYPE_IO, NDI_RA_PASS);
+
+	if (io_end == io_answer) {
+		DEBUG0("No IO Space resources used\n");
+
+		/*
+		 * To prevent the bridge from forwarding any I/O
+		 * transactions, the I/O Limit will be programmed
+		 * with a smaller value than the I/O Base.
+		 */
+		pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 0);
+		pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 0);
+		pci_config_put8(h, PCI_BCNF_IO_BASE_LOW, 0xff);
+		pci_config_put16(h, PCI_BCNF_IO_BASE_HI, 0);
+
+		io_size = 0;
+	} else {
+		/*
+		 * Reprogram the end of the io space.
+		 */
+		pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
+		    PCICFG_HIBYTE(PCICFG_LOWORD(
+		    PCICFG_LOADDR(io_end) - 1)));
+
+		pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
+		    PCICFG_HIWORD(PCICFG_LOADDR(io_end - 1)));
+
+		io_size = io_end - io_base;
+	}
+
+	if ((max_bus - *highest_bus) > 0) {
+		/*
+		 * Give back unused bus numbers
+		 */
+		(void) ndi_ra_free(ddi_get_parent(new_child),
+		    *highest_bus+1, max_bus - *highest_bus,
+		    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
+	}
+
+	/*
+	 * Set bus numbers to ranges encountered during scan
+	 */
+	pcicfg_set_bus_numbers(h, bus, new_bus, *highest_bus);
+
+	bus_range[0] = pci_config_get8(h, PCI_BCNF_SECBUS);
+	bus_range[1] = pci_config_get8(h, PCI_BCNF_SUBBUS);
+	DEBUG1("End of bridge probe: bus_range[0] =  %d\n", bus_range[0]);
+	DEBUG1("End of bridge probe: bus_range[1] =  %d\n", bus_range[1]);
+
+	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
+	    "bus-range", bus_range, 2) != DDI_SUCCESS) {
+		DEBUG0("Failed to set bus-range property");
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * Remove the ranges property if it exists since we will create
+	 * a new one.
+	 */
+	(void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "ranges");
+
+	DEBUG2("Creating Ranges property - Mem Address %lx Mem Size %x\n",
+	    mem_base, mem_size);
+	DEBUG2("                         - I/O Address %lx I/O Size %x\n",
+	    io_base, io_size);
+
+	bzero((caddr_t)range, sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
+
+	range[0].child_hi = range[0].parent_hi |= (PCI_REG_REL_M | PCI_ADDR_IO);
+	range[0].child_lo = range[0].parent_lo = io_base;
+	range[1].child_hi = range[1].parent_hi |=
+	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
+	range[1].child_lo = range[1].parent_lo = mem_base;
+
+	if (io_size > 0) {
+		range[0].size_lo = io_size;
+		if (pcicfg_update_ranges_prop(new_child, &range[0])) {
+			DEBUG0("Failed to update ranges (io)\n");
+			return (PCICFG_FAILURE);
+		}
+	}
+	if (mem_size > 0) {
+		range[1].size_lo = mem_size;
+		if (pcicfg_update_ranges_prop(new_child, &range[1])) {
+			DEBUG0("Failed to update ranges (memory)\n");
+			return (PCICFG_FAILURE);
+		}
+	}
+
+	/*
+	 * Remove the resource maps for the bridge since we no longer
+	 * need them.  Note that the failure is ignored since the
+	 * ndi_devi_offline above may have already taken care of it via
+	 * driver detach.
+	 * It has been checked that there are no other reasons for
+	 * failure other than map itself being non-existent. So we are Ok.
+	 */
+	if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
+		/*EMPTY*/
+		DEBUG0("Can not destroy resource map - NDI_RA_TYPE_MEM\n");
+	}
+
+	if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_IO) == NDI_FAILURE) {
+		/*EMPTY*/
+		DEBUG0("Can not destroy resource map - NDI_RA_TYPE_IO\n");
+	}
+
+	if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_BUSNUM)
+	    == NDI_FAILURE) {
+		/*EMPTY*/
+		DEBUG0("Can't destroy resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
+	}
+
+	return (rval);
+}
+
+/*
+ * Return PCICFG_SUCCESS if device exists at the specified address.
+ * Return PCICFG_NODEVICE is no device exists at the specified address.
+ *
+ */
+int
+pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
+{
+	caddr_t			virt;
+	ddi_device_acc_attr_t	attr;
+	int			status;
+	int			rlen;
+	pci_regspec_t		*reg;
+	int			ret = DDI_SUCCESS;
+	int16_t			tmp;
+	/*
+	 * flags = PCICFG_CONF_INDIRECT_MAP if configuration space is indirectly
+	 * mapped, otherwise it is 0. "flags" is introduced in support of any
+	 * non transparent bridges, where configuration space is indirectly
+	 * mapped.
+	 * Indirect mapping is always true on sun4v systems.
+	 */
+	int			flags = 0;
+
+
+	/*
+	 * Get the pci register spec from the node
+	 */
+	status = ddi_getlongprop(DDI_DEV_T_ANY,
+	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
+
+	switch (status) {
+		case DDI_PROP_SUCCESS:
+		break;
+		case DDI_PROP_NO_MEMORY:
+			DEBUG0("reg present, but unable to get memory\n");
+			return (PCICFG_FAILURE);
+		default:
+			DEBUG0("no reg property\n");
+			return (PCICFG_FAILURE);
+	}
+
+	if (pcicfg_indirect_map(dip) == DDI_SUCCESS)
+		flags |= PCICFG_CONF_INDIRECT_MAP;
+
+	/*
+	 * Map in configuration space (temporarily)
+	 */
+	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
+	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+	attr.devacc_attr_access = DDI_CAUTIOUS_ACC;
+
+#ifdef	EFCODE21554
+	if (ddi_regs_map_setup(dip, 0, &virt,
+	    0, 0, &attr, handle) != DDI_SUCCESS)
+#else
+	if (pcicfg_map_phys(dip, reg, &virt, &attr, handle)
+	    != DDI_SUCCESS)
+#endif
+	{
+		DEBUG0("pcicfg_config_setup():"
+		"Failed to setup config space\n");
+
+		kmem_free((caddr_t)reg, rlen);
+		return (PCICFG_FAILURE);
+	}
+
+	if (flags & PCICFG_CONF_INDIRECT_MAP) {
+		/*
+		 * need to use DDI interfaces as the conf space is
+		 * cannot be directly accessed by the host.
+		 */
+		tmp = (int16_t)ddi_get16(*handle, (uint16_t *)virt);
+	} else {
+		ret = ddi_peek16(dip, (int16_t *)virt, &tmp);
+	}
+
+	if (ret == DDI_SUCCESS) {
+		if (tmp == -1) {
+			DEBUG1("NO DEVICEFOUND, read %x\n", tmp);
+			ret = PCICFG_NODEVICE;
+		} else {
+			/* XXX - Need to check why HV is returning 0 */
+			if (tmp == 0) {
+				DEBUG0("Device Not Ready yet ?");
+				ret = PCICFG_NODEVICE;
+			} else {
+				DEBUG1("DEVICEFOUND, read %x\n", tmp);
+				ret = PCICFG_SUCCESS;
+			}
+		}
+	} else {
+		DEBUG0("ddi_peek failed, must be NODEVICE\n");
+		ret = PCICFG_NODEVICE;
+	}
+
+	/*
+	 * A bug in XMITS 3.0 causes us to miss the Master Abort Split
+	 * Completion message.  The result is the error message being
+	 * sent back as part of the config data.  If the first two words
+	 * of the config space happen to be the same as the Master Abort
+	 * message, then report back that there is no device there.
+	 */
+	if ((ret == PCICFG_SUCCESS) && !(flags & PCICFG_CONF_INDIRECT_MAP)) {
+		int32_t	pcix_scm;
+
+#define		PCICFG_PCIX_SCM	0x10000004
+
+		pcix_scm = 0;
+		(void) ddi_peek32(dip, (int32_t *)virt, &pcix_scm);
+		if (pcix_scm == PCICFG_PCIX_SCM) {
+			pcix_scm = 0;
+			(void) ddi_peek32(dip,
+			    (int32_t *)(virt + 4), &pcix_scm);
+			if (pcix_scm == PCICFG_PCIX_SCM)
+				ret = PCICFG_NODEVICE;
+		}
+	}
+
+	if (ret == PCICFG_NODEVICE)
+#ifdef	EFCODE21554
+		ddi_regs_map_free(handle);
+#else
+		pcicfg_unmap_phys(handle, reg);
+#endif
+
+	kmem_free((caddr_t)reg, rlen);
+
+	return (ret);
+
+}
+
+static void
+pcicfg_config_teardown(ddi_acc_handle_t *handle)
+{
+	(void) ddi_regs_map_free(handle);
+}
+
+static int
+pcicfg_add_config_reg(dev_info_t *dip,
+	uint_t bus, uint_t device, uint_t func)
+{
+	int reg[10] = { PCI_ADDR_CONFIG, 0, 0, 0, 0};
+
+	reg[0] = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
+
+	return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
+	    "reg", reg, 5));
+}
+
+static int
+pcicfg_dump_assigned(dev_info_t *dip)
+{
+	pci_regspec_t		*reg;
+	int			length;
+	int			rcount;
+	int			i;
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&reg,
+	    &length) != DDI_PROP_SUCCESS) {
+		DEBUG0("Failed to read assigned-addresses property\n");
+		return (PCICFG_FAILURE);
+	}
+
+	rcount = length / sizeof (pci_regspec_t);
+	for (i = 0; i < rcount; i++) {
+		DEBUG4("pcicfg_dump_assigned - size=%x low=%x mid=%x high=%x\n",
+		    reg[i].pci_size_low, reg[i].pci_phys_low,
+		    reg[i].pci_phys_mid, reg[i].pci_phys_hi);
+	}
+	/*
+	 * Don't forget to free up memory from ddi_getlongprop
+	 */
+	kmem_free((caddr_t)reg, length);
+
+	return (PCICFG_SUCCESS);
+}
+
+#ifdef PCICFG_INTERPRET_FCODE
+static int
+pcicfg_load_fcode(dev_info_t *dip, uint_t bus, uint_t device, uint_t func,
+    uint16_t vendor_id, uint16_t device_id, uchar_t **fcode_addr,
+    int *fcode_size, int rom_paddr, int rom_size)
+{
+	pci_regspec_t		p;
+	int			pci_data;
+	int			start_of_fcode;
+	int			image_length;
+	int			code_type;
+	ddi_acc_handle_t	h;
+	ddi_device_acc_attr_t	acc;
+	uint8_t			*addr;
+	int8_t			image_not_found, indicator;
+	uint16_t		vendor_id_img, device_id_img;
+	int16_t			rom_sig;
+#ifdef DEBUG
+	int i;
+#endif
+
+	DEBUG4("pcicfg_load_fcode() - "
+	    "bus %x device =%x func=%x rom_paddr=%lx\n",
+	    bus, device, func, rom_paddr);
+	DEBUG2("pcicfg_load_fcode() - vendor_id=%x device_id=%x\n",
+	    vendor_id, device_id);
+
+	*fcode_size = 0;
+	*fcode_addr = NULL;
+
+	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
+	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+
+	p.pci_phys_hi = PCI_ADDR_MEM32 | PCICFG_MAKE_REG_HIGH(bus, device,
+	    func, PCI_CONF_ROM);
+
+	p.pci_phys_mid = 0;
+	p.pci_phys_low = 0;
+
+	p.pci_size_low = rom_size;
+	p.pci_size_hi = 0;
+
+	if (pcicfg_map_phys(dip, &p, (caddr_t *)&addr, &acc, &h)) {
+		DEBUG1("Can Not map in ROM %x\n", p.pci_phys_low);
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * Walk the ROM to find the proper image for this device.
+	 */
+	image_not_found = 1;
+	while (image_not_found) {
+		DEBUG1("Expansion ROM maps to %lx\n", addr);
+
+#ifdef DEBUG
+		if (pcicfg_dump_fcode) {
+			for (i = 0; i < 100; i++)
+				DEBUG2("ROM 0x%x --> 0x%x\n", i,
+				    ddi_get8(h, (uint8_t *)(addr + i)));
+		}
+#endif
+
+		/*
+		 * Some device say they have an Expansion ROM, but do not, so
+		 * for non-21554 devices use peek so we don't panic due to
+		 * accessing non existent memory.
+		 */
+		if (pcicfg_indirect_map(dip) == DDI_SUCCESS) {
+			rom_sig = ddi_get16(h,
+			    (uint16_t *)(addr + PCI_ROM_SIGNATURE));
+		} else {
+			if (ddi_peek16(dip,
+			    (int16_t *)(addr + PCI_ROM_SIGNATURE), &rom_sig)) {
+				cmn_err(CE_WARN,
+				    "PCI Expansion ROM is not accessible");
+				pcicfg_unmap_phys(&h, &p);
+				return (PCICFG_FAILURE);
+			}
+		}
+
+		/*
+		 * Validate the ROM Signature.
+		 */
+		if ((uint16_t)rom_sig != 0xaa55) {
+			DEBUG1("Invalid ROM Signature %x\n", (uint16_t)rom_sig);
+			pcicfg_unmap_phys(&h, &p);
+			return (PCICFG_FAILURE);
+		}
+
+		DEBUG0("Valid ROM Signature Found\n");
+
+		start_of_fcode = ddi_get16(h, (uint16_t *)(addr + 2));
+
+		pci_data =  ddi_get16(h,
+		    (uint16_t *)(addr + PCI_ROM_PCI_DATA_STRUCT_PTR));
+
+		DEBUG2("Pointer To PCI Data Structure %x %x\n", pci_data,
+		    addr);
+
+		/*
+		 * Validate the PCI Data Structure Signature.
+		 * 0x52494350 = "PCIR"
+		 */
+
+		if (ddi_get8(h, (uint8_t *)(addr + pci_data)) != 0x50) {
+			DEBUG0("Invalid PCI Data Structure Signature\n");
+			pcicfg_unmap_phys(&h, &p);
+			return (PCICFG_FAILURE);
+		}
+
+		if (ddi_get8(h, (uint8_t *)(addr + pci_data + 1)) != 0x43) {
+			DEBUG0("Invalid PCI Data Structure Signature\n");
+			pcicfg_unmap_phys(&h, &p);
+			return (PCICFG_FAILURE);
+		}
+		if (ddi_get8(h, (uint8_t *)(addr + pci_data + 2)) != 0x49) {
+			DEBUG0("Invalid PCI Data Structure Signature\n");
+			pcicfg_unmap_phys(&h, &p);
+			return (PCICFG_FAILURE);
+		}
+		if (ddi_get8(h, (uint8_t *)(addr + pci_data + 3)) != 0x52) {
+			DEBUG0("Invalid PCI Data Structure Signature\n");
+			pcicfg_unmap_phys(&h, &p);
+			return (PCICFG_FAILURE);
+		}
+
+		/*
+		 * Is this image for this device?
+		 */
+		vendor_id_img = ddi_get16(h,
+		    (uint16_t *)(addr + pci_data + PCI_PDS_VENDOR_ID));
+		device_id_img = ddi_get16(h,
+		    (uint16_t *)(addr + pci_data + PCI_PDS_DEVICE_ID));
+
+		DEBUG2("This image is for vendor_id=%x device_id=%x\n",
+		    vendor_id_img, device_id_img);
+
+		code_type = ddi_get8(h, addr + pci_data + PCI_PDS_CODE_TYPE);
+
+		switch (code_type) {
+		case PCI_PDS_CODE_TYPE_PCAT:
+			DEBUG0("ROM is of x86/PC-AT Type\n");
+			break;
+		case PCI_PDS_CODE_TYPE_OPEN_FW:
+			DEBUG0("ROM is of Open Firmware Type\n");
+			break;
+		default:
+			DEBUG1("ROM is of Unknown Type 0x%x\n", code_type);
+			break;
+		}
+
+		if ((vendor_id_img != vendor_id) ||
+		    (device_id_img != device_id) ||
+		    (code_type != PCI_PDS_CODE_TYPE_OPEN_FW)) {
+			DEBUG0("Firmware Image is not for this device..."
+			    "goto next image\n");
+			/*
+			 * Read indicator byte to see if there is another
+			 * image in the ROM
+			 */
+			indicator = ddi_get8(h,
+			    (uint8_t *)(addr + pci_data + PCI_PDS_INDICATOR));
+
+			if (indicator != 1) {
+				/*
+				 * There is another image in the ROM.
+				 */
+				image_length = ddi_get16(h,  (uint16_t *)(addr +
+				    pci_data + PCI_PDS_IMAGE_LENGTH)) * 512;
+
+				addr += image_length;
+			} else {
+				/*
+				 * There are no more images.
+				 */
+				DEBUG0("There are no more images in the ROM\n");
+				pcicfg_unmap_phys(&h, &p);
+
+				return (PCICFG_FAILURE);
+			}
+		} else {
+			DEBUG0("Correct image was found\n");
+			image_not_found = 0;  /* Image was found */
+		}
+	}
+
+	*fcode_size =  (ddi_get8(h, addr + start_of_fcode + 4) << 24) |
+	    (ddi_get8(h, addr + start_of_fcode + 5) << 16) |
+	    (ddi_get8(h, addr + start_of_fcode + 6) << 8) |
+	    (ddi_get8(h, addr + start_of_fcode + 7));
+
+	DEBUG1("Fcode Size %x\n", *fcode_size);
+
+	/*
+	 * Allocate page aligned buffer space
+	 */
+	*fcode_addr = kmem_zalloc(ptob(btopr(*fcode_size)), KM_SLEEP);
+
+	if (*fcode_addr == NULL) {
+		DEBUG0("kmem_zalloc returned NULL\n");
+		pcicfg_unmap_phys(&h, &p);
+		return (PCICFG_FAILURE);
+	}
+
+	DEBUG1("Fcode Addr %lx\n", *fcode_addr);
+
+	ddi_rep_get8(h, *fcode_addr, addr + start_of_fcode, *fcode_size,
+	    DDI_DEV_AUTOINCR);
+
+	pcicfg_unmap_phys(&h, &p);
+
+	return (PCICFG_SUCCESS);
+}
+
+static int
+pcicfg_fcode_assign_bars(ddi_acc_handle_t h, dev_info_t *dip, uint_t bus,
+    uint_t device, uint_t func, int32_t fc_request, pci_regspec_t *rom_regspec)
+{
+	/*
+	 * Assign values to all BARs so that it is safe to turn on the
+	 * device for accessing the fcode on the PROM. On successful
+	 * exit from this function, "assigned-addresses" are created
+	 * for all BARs and ROM BAR is enabled. Also, rom_regspec is
+	 * filled with the values that can be used to free up this
+	 * resource later.
+	 */
+	uint32_t request, hiword, size;
+	pci_regspec_t phys_spec;
+	ndi_ra_request_t req;
+	uint64_t mem_answer, mem_alen;
+	int i;
+
+	DEBUG1("pcicfg_fcode_assign_bars :%s\n", DEVI(dip)->devi_name);
+
+	/*
+	 * Process the BARs.
+	 */
+	for (i = PCI_CONF_BASE0; i <= PCI_CONF_BASE5; ) {
+		pci_config_put32(h, i, 0xffffffff);
+		request = pci_config_get32(h, i);
+		/*
+		 * Check if implemented
+		 */
+		if (request == 0) {
+			DEBUG1("pcicfg_fcode_assign_bars :"
+			    "BASE register [0x%x] asks for 0(32)\n", i);
+			i += 4;
+			continue;
+		}
+		/*
+		 * Build the phys_spec for this BAR
+		 */
+		hiword = PCICFG_MAKE_REG_HIGH(bus, device, func, i);
+		size = (~(PCI_BASE_M_ADDR_M & request)) + 1;
+
+		DEBUG3("pcicfg_fcode_assign_bars :"
+		    "BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
+		    i, request, size);
+
+		if ((PCI_BASE_SPACE_M & request) == PCI_BASE_SPACE_MEM) {
+			if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_MEM) {
+				hiword |= PCI_ADDR_MEM32;
+			} else if ((PCI_BASE_TYPE_M & request)
+			    == PCI_BASE_TYPE_ALL) {
+				hiword |= PCI_ADDR_MEM64;
+			}
+			if (request & PCI_BASE_PREF_M)
+				hiword |= PCI_REG_PF_M;
+		} else {
+			hiword |= PCI_ADDR_IO;
+		}
+		phys_spec.pci_phys_hi = hiword;
+		phys_spec.pci_phys_mid = 0;
+		phys_spec.pci_phys_low = 0;
+		phys_spec.pci_size_hi = 0;
+		phys_spec.pci_size_low = size;
+
+		/*
+		 * The following function
+		 * - allocates address space
+		 * - programs the BAR
+		 * - adds an "assigned-addresses" property
+		 */
+		if (pcicfg_alloc_resource(dip, phys_spec)) {
+			cmn_err(CE_WARN, "failed to allocate %d bytes"
+			    " for dev %s BASE register [0x%x]\n",
+			    size, DEVI(dip)->devi_name, i);
+			goto failure;
+		}
+		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
+			/*
+			 * 64 bit, should be in memory space.
+			 */
+			i += 8;
+		} else {
+			/*
+			 * 32 bit, either memory or I/O space.
+			 */
+			i += 4;
+		}
+	}
+
+	/*
+	 * Handle ROM BAR. We do not use the common
+	 * resource allocator function because we need to
+	 * return reg spec to the caller.
+	 */
+	size = (~(PCI_BASE_ROM_ADDR_M & fc_request)) + 1;
+
+	DEBUG3("BASE register [0x%x] asks for "
+	    "[0x%x]=[0x%x]\n", PCI_CONF_ROM, fc_request, size);
+
+	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
+
+	req.ra_boundbase = 0;
+	req.ra_boundlen = PCICFG_4GIG_LIMIT;
+	req.ra_len = size;
+	req.ra_flags |= NDI_RA_ALIGN_SIZE;
+	req.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
+
+	if (ndi_ra_alloc(ddi_get_parent(dip),
+	    &req, &mem_answer, &mem_alen,
+	    NDI_RA_TYPE_MEM, NDI_RA_PASS)) {
+		cmn_err(CE_WARN, "failed to allocate %d bytes"
+		    " for dev %s ROM BASE register\n",
+		    size, DEVI(dip)->devi_name);
+		goto failure;
+	}
+
+	DEBUG3("ROM addr = [0x%x.%x] len [0x%x]\n",
+	    PCICFG_HIADDR(mem_answer),
+	    PCICFG_LOADDR(mem_answer), mem_alen);
+
+	/*
+	 * Assign address space and enable ROM.
+	 */
+	pci_config_put32(h, PCI_CONF_ROM,
+	    PCICFG_LOADDR(mem_answer) | PCI_BASE_ROM_ENABLE);
+
+	/*
+	 * Add resource to assigned-addresses.
+	 */
+	phys_spec.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, \
+	    PCI_CONF_ROM) | PCI_ADDR_MEM32;
+	if (fc_request & PCI_BASE_PREF_M)
+		phys_spec.pci_phys_hi |= PCI_REG_PF_M;
+	phys_spec.pci_phys_mid = 0;
+	phys_spec.pci_phys_low = PCICFG_LOADDR(mem_answer);
+	phys_spec.pci_size_hi = 0;
+	phys_spec.pci_size_low = size;
+
+	if (pcicfg_update_assigned_prop(dip, &phys_spec)
+	    != PCICFG_SUCCESS) {
+		cmn_err(CE_WARN, "failed to update"
+		    " assigned-address property for dev %s\n",
+		    DEVI(dip)->devi_name);
+		goto failure;
+	}
+	/*
+	 * Copy out the reg spec.
+	 */
+	*rom_regspec = phys_spec;
+
+	return (PCICFG_SUCCESS);
+
+failure:
+	/*
+	 * We came in with no "assigned-addresses".
+	 * Free up the resources we may have allocated.
+	 */
+	(void) pcicfg_free_device_resources(dip, 0);
+
+	return (PCICFG_FAILURE);
+}
+
+#endif /* PCICFG_INTERPRET_FCODE */
+
+static int
+pcicfg_free_all_resources(dev_info_t *dip)
+{
+	pci_regspec_t		*assigned;
+	int			assigned_len;
+	int			acount;
+	int			i;
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
+	    &assigned_len) != DDI_PROP_SUCCESS) {
+		DEBUG0("Failed to read assigned-addresses property\n");
+		return (PCICFG_FAILURE);
+	}
+
+	acount = assigned_len / sizeof (pci_regspec_t);
+
+	for (i = 0; i < acount; i++) {
+		if (pcicfg_free_resource(dip, assigned[i], 0)) {
+			/*
+			 * Dont forget to free mem from ddi_getlongprop
+			 */
+			kmem_free((caddr_t)assigned, assigned_len);
+			return (PCICFG_FAILURE);
+		}
+	}
+
+	/*
+	 * Don't forget to free up memory from ddi_getlongprop
+	 */
+	if (assigned_len)
+		kmem_free((caddr_t)assigned, assigned_len);
+
+	return (PCICFG_SUCCESS);
+}
+static int
+pcicfg_alloc_new_resources(dev_info_t *dip)
+{
+	pci_regspec_t		*assigned, *reg;
+	int			assigned_len, reg_len;
+	int			acount, rcount;
+	int			i, j, alloc_size;
+	boolean_t		alloc;
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
+	    &reg_len) != DDI_PROP_SUCCESS) {
+		DEBUG0("Failed to read reg property\n");
+		return (PCICFG_FAILURE);
+	}
+	rcount = reg_len / sizeof (pci_regspec_t);
+
+	DEBUG2("pcicfg_alloc_new_resources() reg size=%x entries=%x\n",
+	    reg_len, rcount);
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
+	    &assigned_len) != DDI_PROP_SUCCESS) {
+		acount = 0;
+	} else {
+		acount = assigned_len / sizeof (pci_regspec_t);
+	}
+
+	DEBUG1("assigned-addresses property len=%x\n", acount);
+
+	/*
+	 * For each address described by reg, search for it in the
+	 * assigned-addresses property. If it does not exist, allocate
+	 * resources for it. If it does exist, check the size in both.
+	 * The size needs to be bigger of the two.
+	 */
+	for (i = 1; i < rcount; i++) {
+		alloc = B_TRUE;
+		alloc_size = reg[i].pci_size_low;
+		for (j = 0; j < acount; j++) {
+			if (assigned[j].pci_phys_hi == reg[i].pci_phys_hi) {
+				/*
+				 * There is an exact match. Check size.
+				 */
+				DEBUG1("pcicfg_alloc_new_resources "
+				    "- %x - MATCH\n",
+				    reg[i].pci_phys_hi);
+
+				if (reg[i].pci_size_low >
+				    assigned[j].pci_size_low) {
+					/*
+					 * Fcode wants more.
+					 */
+					DEBUG3("pcicfg_alloc_new_resources"
+					    " - %x - RESIZE"
+					    " assigned 0x%x reg 0x%x\n",
+					    assigned[j].pci_phys_hi,
+					    assigned[j].pci_size_low,
+					    reg[i].pci_size_low);
+
+					/*
+					 * Free the old resource.
+					 */
+					(void) pcicfg_free_resource(dip,
+					    assigned[j], 0);
+				} else {
+					DEBUG3("pcicfg_alloc_new_resources"
+					    " - %x - ENOUGH"
+					    " assigned 0x%x reg 0x%x\n",
+					    assigned[j].pci_phys_hi,
+					    assigned[j].pci_size_low,
+					    reg[i].pci_size_low);
+
+					alloc = B_FALSE;
+				}
+				break;
+			}
+			/*
+			 * Fcode may have set one or more of the
+			 * NPT bits in phys.hi.
+			 */
+			if (PCI_REG_BDFR_G(assigned[j].pci_phys_hi) ==
+			    PCI_REG_BDFR_G(reg[i].pci_phys_hi)) {
+
+				DEBUG2("pcicfg_alloc_new_resources "
+				    "- PARTIAL MATCH assigned 0x%x "
+				    "reg 0x%x\n", assigned[j].pci_phys_hi,
+				    reg[i].pci_phys_hi);
+				/*
+				 * Changing the SS bits is an error
+				 */
+				if (PCI_REG_ADDR_G(
+				    assigned[j].pci_phys_hi) !=
+				    PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
+
+					DEBUG2("Fcode changing"
+					    " SS bits of - 0x%x -"
+					    " on %s\n", reg[i].pci_phys_hi,
+					    DEVI(dip)->devi_name);
+
+				}
+
+
+				/*
+				 * We are going to allocate new resource.
+				 * Free the old resource. Again, adjust
+				 * the size to be safe.
+				 */
+				(void) pcicfg_free_resource(dip,
+				    assigned[j], 0);
+
+				alloc_size = MAX(reg[i].pci_size_low,
+				    assigned[j].pci_size_low);
+
+				break;
+			}
+		}
+		/*
+		 * We are allocating resources for one of three reasons -
+		 * - Fcode wants a larger address space
+		 * - Fcode has set changed/set n, p, t bits.
+		 * - It is a new "reg", it should be only ROM bar, but
+		 *   we don't do the checking.
+		 */
+		if (alloc == B_TRUE) {
+			DEBUG1("pcicfg_alloc_new_resources : creating 0x%x\n",
+			    reg[i].pci_phys_hi);
+
+			reg[i].pci_size_low = alloc_size;
+			if (pcicfg_alloc_resource(dip, reg[i])) {
+				/*
+				 * Dont forget to free mem from
+				 * ddi_getlongprop
+				 */
+				if (acount != 0)
+					kmem_free((caddr_t)assigned,
+					    assigned_len);
+				kmem_free((caddr_t)reg, reg_len);
+				return (PCICFG_FAILURE);
+			}
+		}
+	}
+
+	/*
+	 * Don't forget to free up memory from ddi_getlongprop
+	 */
+	if (acount != 0)
+		kmem_free((caddr_t)assigned, assigned_len);
+	kmem_free((caddr_t)reg, reg_len);
+
+	return (PCICFG_SUCCESS);
+}
+
+static int
+pcicfg_alloc_resource(dev_info_t *dip, pci_regspec_t phys_spec)
+{
+	uint64_t answer;
+	uint64_t alen;
+	int offset;
+	pci_regspec_t config;
+	caddr_t virt, v;
+	ddi_device_acc_attr_t acc;
+	ddi_acc_handle_t h;
+	ndi_ra_request_t request;
+	pci_regspec_t *assigned;
+	int assigned_len, entries, i;
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
+	    &assigned_len) == DDI_PROP_SUCCESS) {
+		DEBUG0("pcicfg_alloc_resource - "
+		    "searching assigned-addresses\n");
+
+		entries = assigned_len / (sizeof (pci_regspec_t));
+
+		/*
+		 * Walk through the assigned-addresses entries. If there is
+		 * a match, there is no need to allocate the resource.
+		 */
+		for (i = 0; i < entries; i++) {
+			if (assigned[i].pci_phys_hi == phys_spec.pci_phys_hi) {
+				DEBUG1("pcicfg_alloc_resource - MATCH %x\n",
+				    assigned[i].pci_phys_hi);
+				kmem_free(assigned, assigned_len);
+				return (0);
+			}
+		}
+		kmem_free(assigned, assigned_len);
+	}
+
+	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
+
+	config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
+	config.pci_phys_hi &= ~PCI_REG_REG_M;
+	config.pci_phys_mid = config.pci_phys_low = 0;
+	config.pci_size_hi = config.pci_size_low = 0;
+
+	/*
+	 * Map in configuration space (temporarily)
+	 */
+	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
+	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+
+	if (pcicfg_map_phys(dip, &config, &virt, &acc, &h)) {
+		DEBUG0("Can not map in config space\n");
+		return (1);
+	}
+
+	request.ra_flags |= NDI_RA_ALIGN_SIZE;
+	request.ra_boundbase = 0;
+	request.ra_boundlen = PCICFG_4GIG_LIMIT;
+	/*
+	 * Use size stored in phys_spec parameter.
+	 */
+	request.ra_len = phys_spec.pci_size_low;
+
+	offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
+
+	v = virt + offset;
+
+	if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
+
+		request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
+
+		/* allocate memory space from the allocator */
+
+		if (ndi_ra_alloc(ddi_get_parent(dip),
+		    &request, &answer, &alen,
+		    NDI_RA_TYPE_MEM, NDI_RA_PASS)
+		    != NDI_SUCCESS) {
+			DEBUG0("(ROM)Failed to allocate 32b mem");
+			pcicfg_unmap_phys(&h, &config);
+			return (1);
+		}
+		DEBUG3("ROM addr = [0x%x.%x] len [0x%x]\n",
+		    PCICFG_HIADDR(answer),
+		    PCICFG_LOADDR(answer),
+		    alen);
+
+		/* program the low word */
+
+		ddi_put32(h, (uint32_t *)v, (uint32_t)PCICFG_LOADDR(answer));
+
+		phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
+		phys_spec.pci_phys_mid = PCICFG_HIADDR(answer);
+	} else {
+
+		switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
+		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
+			request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
+			/* allocate memory space from the allocator */
+			if (ndi_ra_alloc(ddi_get_parent(dip),
+			    &request, &answer, &alen,
+			    NDI_RA_TYPE_MEM, NDI_RA_PASS)
+			    != NDI_SUCCESS) {
+				DEBUG0("Failed to allocate 64b mem\n");
+				pcicfg_unmap_phys(&h, &config);
+				return (1);
+			}
+			DEBUG3("64 addr = [0x%x.%x] len [0x%x]\n",
+			    PCICFG_HIADDR(answer),
+			    PCICFG_LOADDR(answer),
+			    alen);
+
+			/* program the low word */
+
+			ddi_put32(h, (uint32_t *)v,
+			    (uint32_t)PCICFG_LOADDR(answer));
+
+			/* program the high word with value zero */
+			v += 4;
+			ddi_put32(h, (uint32_t *)v,
+			    (uint32_t)PCICFG_HIADDR(answer));
+
+			phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
+			phys_spec.pci_phys_mid = PCICFG_HIADDR(answer);
+			/*
+			 * currently support 32b address space
+			 * assignments only.
+			 */
+			phys_spec.pci_phys_hi ^= PCI_ADDR_MEM64 ^
+			    PCI_ADDR_MEM32;
+
+			break;
+
+		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
+			request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
+			/* allocate memory space from the allocator */
+			if (ndi_ra_alloc(ddi_get_parent(dip),
+			    &request, &answer, &alen,
+			    NDI_RA_TYPE_MEM, NDI_RA_PASS)
+			    != NDI_SUCCESS) {
+				DEBUG0("Failed to allocate 32b mem\n");
+				pcicfg_unmap_phys(&h, &config);
+				return (1);
+			}
+
+			DEBUG3("32 addr = [0x%x.%x] len [0x%x]\n",
+			    PCICFG_HIADDR(answer),
+			    PCICFG_LOADDR(answer),
+			    alen);
+
+			/* program the low word */
+
+			ddi_put32(h, (uint32_t *)v,
+			    (uint32_t)PCICFG_LOADDR(answer));
+
+			phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
+
+			break;
+		case PCI_REG_ADDR_G(PCI_ADDR_IO):
+			/* allocate I/O space from the allocator */
+			request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
+			if (ndi_ra_alloc(ddi_get_parent(dip),
+			    &request, &answer, &alen,
+			    NDI_RA_TYPE_IO, NDI_RA_PASS)
+			    != NDI_SUCCESS) {
+				DEBUG0("Failed to allocate I/O\n");
+				pcicfg_unmap_phys(&h, &config);
+				return (1);
+			}
+			DEBUG3("I/O addr = [0x%x.%x] len [0x%x]\n",
+			    PCICFG_HIADDR(answer),
+			    PCICFG_LOADDR(answer),
+			    alen);
+
+			ddi_put32(h, (uint32_t *)v,
+			    (uint32_t)PCICFG_LOADDR(answer));
+
+			phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
+
+			break;
+		default:
+			DEBUG0("Unknown register type\n");
+			pcicfg_unmap_phys(&h, &config);
+			return (1);
+		} /* switch */
+	}
+
+	/*
+	 * Now that memory locations are assigned,
+	 * update the assigned address property.
+	 */
+
+	DEBUG1("updating assigned-addresss for %x\n",  phys_spec.pci_phys_hi);
+
+	if (pcicfg_update_assigned_prop(dip, &phys_spec)) {
+		pcicfg_unmap_phys(&h, &config);
+		return (1);
+	}
+
+	pcicfg_unmap_phys(&h, &config);
+
+	return (0);
+}
+
+static int
+pcicfg_free_resource(dev_info_t *dip, pci_regspec_t phys_spec,
+    pcicfg_flags_t flags)
+{
+	int offset;
+	pci_regspec_t config;
+	caddr_t virt, v;
+	ddi_device_acc_attr_t acc;
+	ddi_acc_handle_t h;
+	ndi_ra_request_t request;
+	int l;
+
+	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
+
+	config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
+	config.pci_phys_hi &= ~PCI_REG_REG_M;
+	config.pci_phys_mid = config.pci_phys_low = 0;
+	config.pci_size_hi = config.pci_size_low = 0;
+
+	/*
+	 * Map in configuration space (temporarily)
+	 */
+	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
+	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+
+	if (pcicfg_map_phys(dip, &config, &virt, &acc, &h)) {
+		DEBUG0("Can not map in config space\n");
+		return (1);
+	}
+
+	offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
+
+	v = virt + offset;
+
+	/*
+	 * Use size stored in phys_spec parameter.
+	 */
+	l = phys_spec.pci_size_low;
+
+	if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
+
+		/* free memory back to the allocator */
+		if (ndi_ra_free(ddi_get_parent(dip), phys_spec.pci_phys_low,
+		    l, NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
+			DEBUG0("(ROM)Can not free 32b mem");
+			pcicfg_unmap_phys(&h, &config);
+			return (1);
+		}
+
+		/* Unmap the BAR by writing a zero */
+
+		if ((flags & PCICFG_FLAG_READ_ONLY) == 0)
+			ddi_put32(h, (uint32_t *)v, (uint32_t)0);
+	} else {
+
+		switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
+		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
+			/* free memory back to the allocator */
+			if (ndi_ra_free(ddi_get_parent(dip),
+			    PCICFG_LADDR(phys_spec.pci_phys_low,
+			    phys_spec.pci_phys_mid),
+			    l, NDI_RA_TYPE_MEM,
+			    NDI_RA_PASS) != NDI_SUCCESS) {
+				DEBUG0("Can not free 64b mem");
+				pcicfg_unmap_phys(&h, &config);
+				return (1);
+			}
+
+			break;
+
+		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
+			/* free memory back to the allocator */
+			if (ndi_ra_free(ddi_get_parent(dip),
+			    phys_spec.pci_phys_low,
+			    l, NDI_RA_TYPE_MEM,
+			    NDI_RA_PASS) != NDI_SUCCESS) {
+				DEBUG0("Can not free 32b mem");
+				pcicfg_unmap_phys(&h, &config);
+				return (1);
+			}
+
+			break;
+		case PCI_REG_ADDR_G(PCI_ADDR_IO):
+			/* free I/O space back to the allocator */
+			if (ndi_ra_free(ddi_get_parent(dip),
+			    phys_spec.pci_phys_low,
+			    l, NDI_RA_TYPE_IO,
+			    NDI_RA_PASS) != NDI_SUCCESS) {
+				DEBUG0("Can not free I/O space");
+				pcicfg_unmap_phys(&h, &config);
+				return (1);
+			}
+
+			break;
+		default:
+			DEBUG0("Unknown register type\n");
+			pcicfg_unmap_phys(&h, &config);
+			return (1);
+		} /* switch */
+	}
+
+	/*
+	 * Now that memory locations are assigned,
+	 * update the assigned address property.
+	 */
+
+	DEBUG1("updating assigned-addresss for %x\n", phys_spec.pci_phys_hi);
+
+	if (pcicfg_remove_assigned_prop(dip, &phys_spec)) {
+		pcicfg_unmap_phys(&h, &config);
+		return (1);
+	}
+
+	pcicfg_unmap_phys(&h, &config);
+
+	return (0);
+}
+
+static int
+pcicfg_remove_assigned_prop(dev_info_t *dip, pci_regspec_t *oldone)
+{
+	int		alen, num_entries, i;
+	pci_regspec_t	*assigned, *assigned_copy;
+	uint_t		status;
+
+	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "assigned-addresses", (caddr_t)&assigned, &alen);
+	switch (status) {
+		case DDI_PROP_SUCCESS:
+		break;
+		case DDI_PROP_NO_MEMORY:
+			DEBUG0("no memory for assigned-addresses property\n");
+			return (1);
+		default:
+			DEBUG0("assigned-addresses property does not exist\n");
+			return (0);
+	}
+
+	/*
+	 * Make a copy of old assigned-addresses property.
+	 */
+	assigned_copy = kmem_alloc(alen, KM_SLEEP);
+	bcopy(assigned, assigned_copy, alen);
+
+	status = ndi_prop_remove(DDI_DEV_T_NONE, dip, "assigned-addresses");
+
+	if (status != DDI_PROP_SUCCESS) {
+		/*
+		 * If "assigned-addresses" is retrieved from PROM, the
+		 * ndi_prop_remove() will fail.
+		 */
+		DEBUG1("pcicfg_remove_assigned_prop: 0x%x not removed\n",
+		    oldone->pci_phys_hi);
+
+		/*
+		 * Free up allocated memory
+		 */
+		kmem_free(assigned_copy, alen);
+		kmem_free((caddr_t)assigned, alen);
+
+		return (0);
+	}
+
+	num_entries = alen / sizeof (pci_regspec_t);
+
+	/*
+	 * Rebuild the assigned-addresses property.
+	 */
+	for (i = 0; i < num_entries; i++) {
+		if (assigned_copy[i].pci_phys_hi != oldone->pci_phys_hi) {
+			(void) pcicfg_update_assigned_prop(dip,
+			    &assigned_copy[i]);
+		}
+	}
+
+	/*
+	 * Free the copy of the original assigned-addresses.
+	 */
+	kmem_free(assigned_copy, alen);
+
+	/*
+	 * Don't forget to free up memory from ddi_getlongprop
+	 */
+	kmem_free((caddr_t)assigned, alen);
+
+	return (0);
+}
+
+static int
+pcicfg_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
+	caddr_t *addrp, ddi_device_acc_attr_t *accattrp,
+	ddi_acc_handle_t *handlep)
+{
+	ddi_map_req_t mr;
+	ddi_acc_hdl_t *hp;
+	int result;
+
+	*handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
+	hp = impl_acc_hdl_get(*handlep);
+	hp->ah_vers = VERS_ACCHDL;
+	hp->ah_dip = dip;
+	hp->ah_rnumber = 0;
+	hp->ah_offset = 0;
+	hp->ah_len = 0;
+	hp->ah_acc = *accattrp;
+
+	mr.map_op = DDI_MO_MAP_LOCKED;
+	mr.map_type = DDI_MT_REGSPEC;
+	mr.map_obj.rp = (struct regspec *)phys_spec;
+	mr.map_prot = PROT_READ | PROT_WRITE;
+	mr.map_flags = DDI_MF_KERNEL_MAPPING;
+	mr.map_handlep = hp;
+	mr.map_vers = DDI_MAP_VERSION;
+
+	result = ddi_map(dip, &mr, 0, 0, addrp);
+
+	if (result != DDI_SUCCESS) {
+		impl_acc_hdl_free(*handlep);
+		*handlep = (ddi_acc_handle_t)NULL;
+	} else {
+		hp->ah_addr = *addrp;
+	}
+
+	return (result);
+}
+
+void
+pcicfg_unmap_phys(ddi_acc_handle_t *handlep,  pci_regspec_t *ph)
+{
+	ddi_map_req_t mr;
+	ddi_acc_hdl_t *hp;
+
+	hp = impl_acc_hdl_get(*handlep);
+	ASSERT(hp);
+
+	mr.map_op = DDI_MO_UNMAP;
+	mr.map_type = DDI_MT_REGSPEC;
+	mr.map_obj.rp = (struct regspec *)ph;
+	mr.map_prot = PROT_READ | PROT_WRITE;
+	mr.map_flags = DDI_MF_KERNEL_MAPPING;
+	mr.map_handlep = hp;
+	mr.map_vers = DDI_MAP_VERSION;
+
+	(void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
+	    hp->ah_len, &hp->ah_addr);
+
+	impl_acc_hdl_free(*handlep);
+	*handlep = (ddi_acc_handle_t)NULL;
+}
+
+static int
+pcicfg_ari_configure(dev_info_t *dip)
+{
+	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
+		return (DDI_FAILURE);
+
+	/*
+	 * Until we have resource balancing, dynamically configure
+	 * ARI functions without firmware assistamce.
+	 */
+	return (DDI_FAILURE);
+}
+
+#ifdef DEBUG
+static void
+debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
+	uintptr_t a4, uintptr_t a5)
+{
+	if (pcicfg_debug == 1) {
+		prom_printf("pcicfg: ");
+		prom_printf(fmt, a1, a2, a3, a4, a5);
+	} else
+		if (pcicfg_debug)
+			cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
+}
+#endif
--- a/usr/src/uts/sun4/io/pcicfg.e.c	Sun Nov 01 14:14:46 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6145 +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.
- */
-
-/*
- *     PCI configurator (pcicfg)
- */
-
-#include <sys/isa_defs.h>
-
-#include <sys/conf.h>
-#include <sys/kmem.h>
-#include <sys/debug.h>
-#include <sys/modctl.h>
-#include <sys/autoconf.h>
-#include <sys/hwconf.h>
-#include <sys/ddi_impldefs.h>
-#include <sys/fcode.h>
-#include <sys/pcie.h>
-#include <sys/pcie_impl.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-#include <sys/sunndi.h>
-#include <sys/pci_cap.h>
-#include <sys/hotplug/pci/pcicfg.h>
-#include <sys/hotplug/pci/pcishpc_regs.h>
-#include <sys/ndi_impldefs.h>
-
-#define	PCICFG_DEVICE_TYPE_PCI	1
-#define	PCICFG_DEVICE_TYPE_PCIE	2
-
-#define	EFCODE21554	/* changes for supporting 21554 */
-
-static int pcicfg_alloc_resource(dev_info_t *, pci_regspec_t);
-static int pcicfg_free_resource(dev_info_t *, pci_regspec_t);
-static int pcicfg_remove_assigned_prop(dev_info_t *, pci_regspec_t *);
-
-#ifdef	PCICFG_INTERPRET_FCODE
-static int pcicfg_fcode_assign_bars(ddi_acc_handle_t, dev_info_t *,
-    uint_t, uint_t, uint_t, int32_t, pci_regspec_t *);
-#endif	/* PCICFG_INTERPRET_FCODE */
-
-/*
- * ************************************************************************
- * *** Implementation specific local data structures/definitions.	***
- * ************************************************************************
- */
-
-static	int	pcicfg_start_devno = 0;	/* for Debug only */
-
-#define	PCICFG_MAX_DEVICE 32
-#define	PCICFG_MAX_FUNCTION 8
-#define	PCICFG_MAX_REGISTER 64
-#define	PCICFG_MAX_BUS_DEPTH 255
-
-#define	PCICFG_NODEVICE 42
-#define	PCICFG_NOMEMORY 43
-#define	PCICFG_NOMULTI	44
-
-#define	PCICFG_HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32))
-#define	PCICFG_LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
-#define	PCICFG_LADDR(lo, hi)	(((uint64_t)(hi) << 32) | (uint32_t)(lo))
-
-#define	PCICFG_HIWORD(n) ((uint16_t)(((uint32_t)(n) & 0xFFFF0000)>> 16))
-#define	PCICFG_LOWORD(n) ((uint16_t)((uint32_t)(n) & 0x0000FFFF))
-#define	PCICFG_HIBYTE(n) ((uint8_t)(((uint16_t)(n) & 0xFF00)>> 8))
-#define	PCICFG_LOBYTE(n) ((uint8_t)((uint16_t)(n) & 0x00FF))
-
-#define	PCICFG_ROUND_UP(addr, gran) ((uintptr_t)((gran+addr-1)&(~(gran-1))))
-#define	PCICFG_ROUND_DOWN(addr, gran) ((uintptr_t)((addr) & ~(gran-1)))
-
-#define	PCICFG_MEMGRAN 0x100000
-#define	PCICFG_IOGRAN 0x1000
-#define	PCICFG_4GIG_LIMIT 0xFFFFFFFFUL
-
-#define	PCICFG_MEM_MULT 4
-#define	PCICFG_IO_MULT 4
-#define	PCICFG_RANGE_LEN 2 /* Number of range entries */
-
-static int pcicfg_slot_busnums = 8;
-static int pcicfg_slot_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
-static int pcicfg_slot_iosize = 16 * PCICFG_IOGRAN; /* 64K per slot */
-static int pcicfg_chassis_per_tree = 1;
-static int pcicfg_sec_reset_delay = 1000000;
-
-/*
- * The following typedef is used to represent a
- * 1275 "bus-range" property of a PCI Bus node.
- * DAF - should be in generic include file...
- */
-
-typedef struct pcicfg_bus_range {
-	uint32_t lo;
-	uint32_t hi;
-} pcicfg_bus_range_t;
-
-typedef struct pcicfg_range {
-
-	uint32_t child_hi;
-	uint32_t child_mid;
-	uint32_t child_lo;
-	uint32_t parent_hi;
-	uint32_t parent_mid;
-	uint32_t parent_lo;
-	uint32_t size_hi;
-	uint32_t size_lo;
-
-} pcicfg_range_t;
-
-typedef struct hole hole_t;
-
-struct hole {
-	uint64_t	start;
-	uint64_t	len;
-	hole_t		*next;
-};
-
-typedef struct pcicfg_phdl pcicfg_phdl_t;
-
-struct pcicfg_phdl {
-
-	dev_info_t	*dip;		/* Associated with the attach point */
-	pcicfg_phdl_t	*next;
-
-	uint64_t	memory_base;	/* Memory base for this attach point */
-	uint64_t	memory_last;
-	uint64_t	memory_len;
-	uint32_t	io_base;	/* I/O base for this attach point */
-	uint32_t	io_last;
-	uint32_t	io_len;
-
-	int		error;
-	uint_t		highest_bus;	/* Highest bus seen on the probe */
-
-	hole_t		mem_hole;	/* Memory hole linked list. */
-	hole_t		io_hole;	/* IO hole linked list */
-
-	ndi_ra_request_t mem_req;	/* allocator request for memory */
-	ndi_ra_request_t io_req;	/* allocator request for I/O */
-};
-
-struct pcicfg_standard_prop_entry {
-    uchar_t *name;
-    uint_t  config_offset;
-    uint_t  size;
-};
-
-
-struct pcicfg_name_entry {
-    uint32_t class_code;
-    char  *name;
-};
-
-struct pcicfg_find_ctrl {
-	uint_t		device;
-	uint_t		function;
-	dev_info_t	*dip;
-};
-
-typedef struct pcicfg_err_regs {
-	uint16_t cmd;
-	uint16_t bcntl;
-	uint16_t pcie_dev;
-	uint16_t devctl;
-	uint16_t pcie_cap_off;
-} pcicfg_err_regs_t;
-
-/*
- * List of Indirect Config Map Devices. At least the intent of the
- * design is to look for a device in this list during the configure
- * operation, and if the device is listed here, then it is a nontransparent
- * bridge, hence load the driver and avail the config map services from
- * the driver. Class and Subclass should be as defined in the PCI specs
- * ie. class is 0x6, and subclass is 0x9.
- */
-static struct {
-	uint8_t		mem_range_bar_offset;
-	uint8_t		io_range_bar_offset;
-	uint8_t		prefetch_mem_range_bar_offset;
-} pcicfg_indirect_map_devs[] = {
-	PCI_CONF_BASE3, PCI_CONF_BASE2, PCI_CONF_BASE3,
-	0,	0,	0,
-};
-
-#define	PCICFG_MAKE_REG_HIGH(busnum, devnum, funcnum, register)\
-	(\
-	((ulong_t)(busnum & 0xff) << 16)    |\
-	((ulong_t)(devnum & 0x1f) << 11)    |\
-	((ulong_t)(funcnum & 0x7) <<  8)    |\
-	((ulong_t)(register & 0x3f)))
-
-/*
- * debug macros:
- */
-#if	defined(DEBUG)
-extern void prom_printf(const char *, ...);
-
-/*
- * Following values are defined for this debug flag.
- *
- * 1 = dump configuration header only.
- * 2 = dump generic debug data only (no config header dumped)
- * 3 = dump everything (both 1 and 2)
- */
-int pcicfg_debug = 0;
-int pcicfg_dump_fcode = 0;
-
-static void debug(char *, uintptr_t, uintptr_t,
-	uintptr_t, uintptr_t, uintptr_t);
-
-#define	DEBUG0(fmt)\
-	debug(fmt, 0, 0, 0, 0, 0);
-#define	DEBUG1(fmt, a1)\
-	debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
-#define	DEBUG2(fmt, a1, a2)\
-	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
-#define	DEBUG3(fmt, a1, a2, a3)\
-	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
-		(uintptr_t)(a3), 0, 0);
-#define	DEBUG4(fmt, a1, a2, a3, a4)\
-	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
-		(uintptr_t)(a3), (uintptr_t)(a4), 0);
-#else
-#define	DEBUG0(fmt)
-#define	DEBUG1(fmt, a1)
-#define	DEBUG2(fmt, a1, a2)
-#define	DEBUG3(fmt, a1, a2, a3)
-#define	DEBUG4(fmt, a1, a2, a3, a4)
-#endif
-
-#ifdef PCICFG_INTERPRET_FCODE
-int pcicfg_dont_interpret = 0;
-#else
-int pcicfg_dont_interpret = 1;
-#endif
-
-/*
- * forward declarations for routines defined in this module (called here)
- */
-
-static int pcicfg_add_config_reg(dev_info_t *,
-	uint_t, uint_t, uint_t);
-static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t,
-								uint_t *);
-
-#ifdef PCICFG_INTERPRET_FCODE
-static int pcicfg_load_fcode(dev_info_t *, uint_t, uint_t, uint_t,
-	uint16_t, uint16_t, uchar_t **, int *, int, int);
-#endif
-
-static int pcicfg_fcode_probe(dev_info_t *, uint_t, uint_t, uint_t, uint_t *);
-static int pcicfg_probe_bridge(dev_info_t *, ddi_acc_handle_t, uint_t,
-				uint_t *);
-static int pcicfg_free_all_resources(dev_info_t *);
-static int pcicfg_alloc_new_resources(dev_info_t *);
-static int pcicfg_match_dev(dev_info_t *, void *);
-static dev_info_t *pcicfg_devi_find(dev_info_t *, uint_t, uint_t);
-static pcicfg_phdl_t *pcicfg_find_phdl(dev_info_t *);
-static pcicfg_phdl_t *pcicfg_create_phdl(dev_info_t *);
-static int pcicfg_destroy_phdl(dev_info_t *);
-static int pcicfg_sum_resources(dev_info_t *, void *);
-static int pcicfg_find_resource_end(dev_info_t *, void *);
-static int pcicfg_allocate_chunk(dev_info_t *);
-static int pcicfg_program_ap(dev_info_t *);
-static int pcicfg_device_assign(dev_info_t *);
-static int pcicfg_bridge_assign(dev_info_t *, void *);
-static int pcicfg_free_resources(dev_info_t *);
-static void pcicfg_setup_bridge(pcicfg_phdl_t *, ddi_acc_handle_t,
-    dev_info_t *);
-static void pcicfg_update_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
-static void pcicfg_enable_bridge_probe_err(dev_info_t *dip,
-				ddi_acc_handle_t h, pcicfg_err_regs_t *regs);
-static void pcicfg_disable_bridge_probe_err(dev_info_t *dip,
-				ddi_acc_handle_t h, pcicfg_err_regs_t *regs);
-static int pcicfg_update_assigned_prop(dev_info_t *, pci_regspec_t *);
-static void pcicfg_device_on(ddi_acc_handle_t);
-static void pcicfg_device_off(ddi_acc_handle_t);
-static int pcicfg_set_busnode_props(dev_info_t *, uint8_t, int, int);
-static int pcicfg_free_bridge_resources(dev_info_t *);
-static int pcicfg_free_device_resources(dev_info_t *);
-static int pcicfg_teardown_device(dev_info_t *);
-static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *);
-static void pcicfg_config_teardown(ddi_acc_handle_t *);
-static void pcicfg_get_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
-static void pcicfg_get_io(pcicfg_phdl_t *, uint32_t, uint32_t *);
-static int pcicfg_update_ranges_prop(dev_info_t *, pcicfg_range_t *);
-static int pcicfg_map_phys(dev_info_t *, pci_regspec_t *, caddr_t *,
-    ddi_device_acc_attr_t *, ddi_acc_handle_t *);
-static void pcicfg_unmap_phys(ddi_acc_handle_t *, pci_regspec_t *);
-static int pcicfg_dump_assigned(dev_info_t *);
-static uint_t pcicfg_configure_ntbridge(dev_info_t *, uint_t, uint_t);
-static int pcicfg_indirect_map(dev_info_t *dip);
-static uint_t pcicfg_get_ntbridge_child_range(dev_info_t *, uint64_t *,
-				uint64_t *, uint_t);
-static int pcicfg_is_ntbridge(dev_info_t *);
-static int pcicfg_ntbridge_allocate_resources(dev_info_t *);
-static int pcicfg_ntbridge_configure_done(dev_info_t *);
-static int pcicfg_ntbridge_unconfigure(dev_info_t *);
-static int pcicfg_ntbridge_unconfigure_child(dev_info_t *, uint_t);
-static void pcicfg_free_hole(hole_t *);
-static uint64_t pcicfg_alloc_hole(hole_t *, uint64_t *, uint32_t);
-static int pcicfg_update_available_prop(dev_info_t *, pci_regspec_t *);
-
-#ifdef DEBUG
-static void pcicfg_dump_common_config(ddi_acc_handle_t config_handle);
-static void pcicfg_dump_device_config(ddi_acc_handle_t);
-
-static void pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle);
-static uint64_t pcicfg_unused_space(hole_t *, uint32_t *);
-
-#define	PCICFG_DUMP_COMMON_CONFIG(hdl) (void)pcicfg_dump_common_config(hdl)
-#define	PCICFG_DUMP_DEVICE_CONFIG(hdl) (void)pcicfg_dump_device_config(hdl)
-#define	PCICFG_DUMP_BRIDGE_CONFIG(hdl) (void)pcicfg_dump_bridge_config(hdl)
-#else
-#define	PCICFG_DUMP_COMMON_CONFIG(handle)
-#define	PCICFG_DUMP_DEVICE_CONFIG(handle)
-#define	PCICFG_DUMP_BRIDGE_CONFIG(handle)
-#endif
-
-static kmutex_t pcicfg_list_mutex; /* Protects the probe handle list */
-static pcicfg_phdl_t *pcicfg_phdl_list = NULL;
-
-#ifndef _DONT_USE_1275_GENERIC_NAMES
-/*
- * Class code table
- */
-static struct pcicfg_name_entry pcicfg_class_lookup [] = {
-
-	{ 0x001, "display" },
-	{ 0x100, "scsi" },
-	{ 0x101, "ide" },
-	{ 0x102, "fdc" },
-	{ 0x103, "ipi" },
-	{ 0x104, "raid" },
-	{ 0x200, "ethernet" },
-	{ 0x201, "token-ring" },
-	{ 0x202, "fddi" },
-	{ 0x203, "atm" },
-	{ 0x300, "display" },
-	{ 0x400, "video" },
-	{ 0x401, "sound" },
-	{ 0x500, "memory" },
-	{ 0x501, "flash" },
-	{ 0x600, "host" },
-	{ 0x601, "isa" },
-	{ 0x602, "eisa" },
-	{ 0x603, "mca" },
-	{ 0x604, "pci" },
-	{ 0x605, "pcmcia" },
-	{ 0x606, "nubus" },
-	{ 0x607, "cardbus" },
-	{ 0x609, "pci" },
-	{ 0x700, "serial" },
-	{ 0x701, "parallel" },
-	{ 0x800, "interrupt-controller" },
-	{ 0x801, "dma-controller" },
-	{ 0x802, "timer" },
-	{ 0x803, "rtc" },
-	{ 0x900, "keyboard" },
-	{ 0x901, "pen" },
-	{ 0x902, "mouse" },
-	{ 0xa00, "dock" },
-	{ 0xb00, "cpu" },
-	{ 0xc00, "firewire" },
-	{ 0xc01, "access-bus" },
-	{ 0xc02, "ssa" },
-	{ 0xc03, "usb" },
-	{ 0xc04, "fibre-channel" },
-	{ 0, 0 }
-};
-#endif /* _DONT_USE_1275_GENERIC_NAMES */
-
-/*
- * Module control operations
- */
-
-extern struct mod_ops mod_miscops;
-
-static struct modlmisc modlmisc = {
-	&mod_miscops, /* Type of module */
-	"PCIe/PCI Config (EFCode Enabled)"
-};
-
-static struct modlinkage modlinkage = {
-	MODREV_1, (void *)&modlmisc, NULL
-};
-
-#ifdef DEBUG
-
-static void
-pcicfg_dump_common_config(ddi_acc_handle_t config_handle)
-{
-	if ((pcicfg_debug & 1) == 0)
-		return;
-	cmn_err(CE_CONT, " Vendor ID   = [0x%x]\n",
-	    pci_config_get16(config_handle, PCI_CONF_VENID));
-	cmn_err(CE_CONT, " Device ID   = [0x%x]\n",
-	    pci_config_get16(config_handle, PCI_CONF_DEVID));
-	cmn_err(CE_CONT, " Command REG = [0x%x]\n",
-	    pci_config_get16(config_handle, PCI_CONF_COMM));
-	cmn_err(CE_CONT, " Status  REG = [0x%x]\n",
-	    pci_config_get16(config_handle, PCI_CONF_STAT));
-	cmn_err(CE_CONT, " Revision ID = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_CONF_REVID));
-	cmn_err(CE_CONT, " Prog Class  = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
-	cmn_err(CE_CONT, " Dev Class   = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_CONF_SUBCLASS));
-	cmn_err(CE_CONT, " Base Class  = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_CONF_BASCLASS));
-	cmn_err(CE_CONT, " Device ID   = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ));
-	cmn_err(CE_CONT, " Header Type = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_CONF_HEADER));
-	cmn_err(CE_CONT, " BIST        = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_CONF_BIST));
-	cmn_err(CE_CONT, " BASE 0      = [0x%x]\n",
-	    pci_config_get32(config_handle, PCI_CONF_BASE0));
-	cmn_err(CE_CONT, " BASE 1      = [0x%x]\n",
-	    pci_config_get32(config_handle, PCI_CONF_BASE1));
-
-}
-
-static void
-pcicfg_dump_device_config(ddi_acc_handle_t config_handle)
-{
-	if ((pcicfg_debug & 1) == 0)
-		return;
-	pcicfg_dump_common_config(config_handle);
-
-	cmn_err(CE_CONT, " BASE 2      = [0x%x]\n",
-	    pci_config_get32(config_handle, PCI_CONF_BASE2));
-	cmn_err(CE_CONT, " BASE 3      = [0x%x]\n",
-	    pci_config_get32(config_handle, PCI_CONF_BASE3));
-	cmn_err(CE_CONT, " BASE 4      = [0x%x]\n",
-	    pci_config_get32(config_handle, PCI_CONF_BASE4));
-	cmn_err(CE_CONT, " BASE 5      = [0x%x]\n",
-	    pci_config_get32(config_handle, PCI_CONF_BASE5));
-	cmn_err(CE_CONT, " Cardbus CIS = [0x%x]\n",
-	    pci_config_get32(config_handle, PCI_CONF_CIS));
-	cmn_err(CE_CONT, " Sub VID     = [0x%x]\n",
-	    pci_config_get16(config_handle, PCI_CONF_SUBVENID));
-	cmn_err(CE_CONT, " Sub SID     = [0x%x]\n",
-	    pci_config_get16(config_handle, PCI_CONF_SUBSYSID));
-	cmn_err(CE_CONT, " ROM         = [0x%x]\n",
-	    pci_config_get32(config_handle, PCI_CONF_ROM));
-	cmn_err(CE_CONT, " I Line      = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_CONF_ILINE));
-	cmn_err(CE_CONT, " I Pin       = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_CONF_IPIN));
-	cmn_err(CE_CONT, " Max Grant   = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_CONF_MIN_G));
-	cmn_err(CE_CONT, " Max Latent  = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_CONF_MAX_L));
-}
-
-static void
-pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle)
-{
-	if ((pcicfg_debug & 1) == 0)
-		return;
-
-	pcicfg_dump_common_config(config_handle);
-
-	cmn_err(CE_CONT, "........................................\n");
-
-	cmn_err(CE_CONT, " Pri Bus     = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_BCNF_PRIBUS));
-	cmn_err(CE_CONT, " Sec Bus     = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_BCNF_SECBUS));
-	cmn_err(CE_CONT, " Sub Bus     = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_BCNF_SUBBUS));
-	cmn_err(CE_CONT, " Latency     = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_BCNF_LATENCY_TIMER));
-	cmn_err(CE_CONT, " I/O Base LO = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW));
-	cmn_err(CE_CONT, " I/O Lim LO  = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW));
-	cmn_err(CE_CONT, " Sec. Status = [0x%x]\n",
-	    pci_config_get16(config_handle, PCI_BCNF_SEC_STATUS));
-	cmn_err(CE_CONT, " Mem Base    = [0x%x]\n",
-	    pci_config_get16(config_handle, PCI_BCNF_MEM_BASE));
-	cmn_err(CE_CONT, " Mem Limit   = [0x%x]\n",
-	    pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT));
-	cmn_err(CE_CONT, " PF Mem Base = [0x%x]\n",
-	    pci_config_get16(config_handle, PCI_BCNF_PF_BASE_LOW));
-	cmn_err(CE_CONT, " PF Mem Lim  = [0x%x]\n",
-	    pci_config_get16(config_handle, PCI_BCNF_PF_LIMIT_LOW));
-	cmn_err(CE_CONT, " PF Base HI  = [0x%x]\n",
-	    pci_config_get32(config_handle, PCI_BCNF_PF_BASE_HIGH));
-	cmn_err(CE_CONT, " PF Lim  HI  = [0x%x]\n",
-	    pci_config_get32(config_handle, PCI_BCNF_PF_LIMIT_HIGH));
-	cmn_err(CE_CONT, " I/O Base HI = [0x%x]\n",
-	    pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI));
-	cmn_err(CE_CONT, " I/O Lim HI  = [0x%x]\n",
-	    pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI));
-	cmn_err(CE_CONT, " ROM addr    = [0x%x]\n",
-	    pci_config_get32(config_handle, PCI_BCNF_ROM));
-	cmn_err(CE_CONT, " Intr Line   = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_BCNF_ILINE));
-	cmn_err(CE_CONT, " Intr Pin    = [0x%x]\n",
-	    pci_config_get8(config_handle, PCI_BCNF_IPIN));
-	cmn_err(CE_CONT, " Bridge Ctrl = [0x%x]\n",
-	    pci_config_get16(config_handle, PCI_BCNF_BCNTRL));
-}
-
-#endif
-
-
-int
-_init()
-{
-	DEBUG0("PCI configurator installed - Fcode Interpretation/21554\n");
-
-	mutex_init(&pcicfg_list_mutex, NULL, MUTEX_DRIVER, NULL);
-	return (mod_install(&modlinkage));
-}
-
-int
-_fini(void)
-{
-	int error;
-
-	error = mod_remove(&modlinkage);
-	if (error != 0) {
-		return (error);
-	}
-	mutex_destroy(&pcicfg_list_mutex);
-	return (0);
-}
-
-int
-_info(modinfop)
-struct modinfo *modinfop;
-{
-	return (mod_info(&modlinkage, modinfop));
-}
-
-/*ARGSUSED*/
-static uint8_t
-pcicfg_get_nslots(dev_info_t *dip, ddi_acc_handle_t handle)
-{
-	uint8_t num_slots = 0;
-	uint16_t cap_ptr;
-
-	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_HOTPLUG,
-	    &cap_ptr)) == DDI_SUCCESS) {
-		uint32_t config;
-
-		PCI_CAP_PUT8(handle, NULL, cap_ptr, SHPC_DWORD_SELECT_OFF,
-		    SHPC_SLOT_CONFIGURATION_REG);
-		config = PCI_CAP_GET32(handle, NULL, cap_ptr,
-		    SHPC_DWORD_DATA_OFF);
-		num_slots = config & 0x1F;
-	} else if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &cap_ptr))
-	    == DDI_SUCCESS) {
-		uint8_t esr_reg = PCI_CAP_GET8(handle, NULL,
-		    cap_ptr, PCI_CAP_ID_REGS_OFF);
-
-		num_slots = PCI_CAPSLOT_NSLOTS(esr_reg);
-	} else if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr))
-	    == DDI_SUCCESS) {
-		int port_type = PCI_CAP_GET16(handle, NULL, cap_ptr,
-		    PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
-
-		if ((port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) &&
-		    (PCI_CAP_GET16(handle, NULL, cap_ptr, PCIE_PCIECAP)
-		    & PCIE_PCIECAP_SLOT_IMPL))
-				num_slots = 1;
-	}
-
-	DEBUG3("%s#%d has %d slots",
-	    ddi_get_name(dip), ddi_get_instance(dip), num_slots);
-
-	return (num_slots);
-}
-
-/*ARGSUSED*/
-static uint8_t
-pcicfg_is_chassis(dev_info_t *dip, ddi_acc_handle_t handle)
-{
-	uint16_t cap_ptr;
-
-	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &cap_ptr)) !=
-	    DDI_FAILURE) {
-
-		uint8_t esr_reg = PCI_CAP_GET8(handle, NULL, cap_ptr, 2);
-		if (PCI_CAPSLOT_FIC(esr_reg))
-			return (B_TRUE);
-	}
-	return (B_FALSE);
-}
-
-/*ARGSUSED*/
-static int
-pcicfg_pcie_dev(dev_info_t *dip, int bus_type, pcicfg_err_regs_t *regs)
-{
-	/* get parent device's device_type property */
-	char *device_type;
-	int rc = DDI_FAILURE;
-	dev_info_t *pdip = ddi_get_parent(dip);
-
-	regs->pcie_dev = 0;
-	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
-	    DDI_PROP_DONTPASS, "device_type", &device_type)
-	    != DDI_PROP_SUCCESS) {
-		DEBUG2("device_type property missing for %s#%d",
-		    ddi_get_name(pdip), ddi_get_instance(pdip));
-		return (DDI_FAILURE);
-	}
-	switch (bus_type) {
-		case PCICFG_DEVICE_TYPE_PCIE:
-			if (strcmp(device_type, "pciex") == 0) {
-				rc = DDI_SUCCESS;
-				regs->pcie_dev = 1;
-			}
-			break;
-		case PCICFG_DEVICE_TYPE_PCI:
-			if (strcmp(device_type, "pci") == 0)
-				rc = DDI_SUCCESS;
-			break;
-		default:
-			break;
-	}
-	ddi_prop_free(device_type);
-	return (rc);
-}
-
-/*ARGSUSED*/
-static int
-pcicfg_pcie_port_type(dev_info_t *dip, ddi_acc_handle_t handle)
-{
-	int port_type = -1;
-	uint16_t cap_ptr;
-
-	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr)) !=
-	    DDI_FAILURE)
-		port_type = PCI_CAP_GET16(handle, NULL,
-		    cap_ptr, PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
-
-	return (port_type);
-}
-
-static int
-pcicfg_pcie_device_type(dev_info_t *dip, ddi_acc_handle_t handle)
-{
-	int port_type = pcicfg_pcie_port_type(dip, handle);
-
-	DEBUG1("device port_type = %x\n", port_type);
-	/* No PCIe CAP regs, we are not PCIe device_type */
-	if (port_type < 0)
-		return (DDI_FAILURE);
-
-	/* check for all PCIe device_types */
-	if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) ||
-	    (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
-	    (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
-	    (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
-		return (DDI_SUCCESS);
-
-	return (DDI_FAILURE);
-
-}
-
-/*
- * In the following functions ndi_devi_enter() without holding the
- * parent dip is sufficient. This is because  pci dr is driven through
- * opens on the nexus which is in the device tree path above the node
- * being operated on, and implicitly held due to the open.
- */
-
-/*
- * This entry point is called to configure a device (and
- * all its children) on the given bus. It is called when
- * a new device is added to the PCI domain.  This routine
- * will create the device tree and program the devices
- * registers.
- */
-
-int
-pcicfg_configure(dev_info_t *devi, uint_t device)
-{
-	uint_t bus;
-	int len;
-	int func;
-	dev_info_t *new_device;
-	pcicfg_bus_range_t pci_bus_range;
-	int rv;
-	int circ;
-	uint_t highest_bus = 0;
-
-	/*
-	 * Start probing at the device specified in "device" on the
-	 * "bus" specified.
-	 */
-	len = sizeof (pcicfg_bus_range_t);
-	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
-	    "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
-		DEBUG0("no bus-range property\n");
-		return (PCICFG_FAILURE);
-	}
-
-	bus = pci_bus_range.lo; /* primary bus number of this bus node */
-
-	ndi_devi_enter(devi, &circ);
-	for (func = 0; func < PCICFG_MAX_FUNCTION; func++) {
-
-		DEBUG3("Configuring [0x%x][0x%x][0x%x]\n", bus, device, func);
-
-		/*
-		 * Try executing fcode if available.
-		 */
-		switch (rv = pcicfg_fcode_probe(devi, bus, device, func,
-		    &highest_bus)) {
-			case PCICFG_FAILURE:
-				DEBUG2("configure failed: "
-				    "bus [0x%x] device [0x%x]\n",
-				    bus, device);
-				break;
-			case PCICFG_NODEVICE:
-				DEBUG3("no device : bus "
-				    "[0x%x] slot [0x%x] func [0x%x]\n",
-				    bus, device, func);
-				if (func)
-					continue;
-				break;
-			default:
-				DEBUG3("configure: bus => [%d] "
-				    "slot => [%d] func => [%d]\n",
-				    bus, device, func);
-				break;
-		}
-
-		if (rv != PCICFG_SUCCESS)
-			break;
-
-		if ((new_device = pcicfg_devi_find(devi,
-		    device, func)) == NULL) {
-			DEBUG0("Did'nt find device node just created\n");
-			goto cleanup;
-		}
-	}
-	ndi_devi_exit(devi, circ);
-
-	if (func == 0)
-		return (PCICFG_FAILURE);	/* probe failed */
-	else
-		return (PCICFG_SUCCESS);
-
-cleanup:
-	/*
-	 * Clean up a partially created "probe state" tree.
-	 * There are no resources allocated to the in the
-	 * probe state.
-	 */
-
-	for (func = 0; func < PCICFG_MAX_FUNCTION; func++) {
-		if ((new_device = pcicfg_devi_find(devi,
-		    device, func)) == NULL) {
-			DEBUG0("No more devices to clean up\n");
-			continue;
-		}
-
-		DEBUG2("Cleaning up device [0x%x] function [0x%x]\n",
-		    device, func);
-		/*
-		 * If this was a bridge device it will have a
-		 * probe handle - if not, no harm in calling this.
-		 */
-		(void) pcicfg_destroy_phdl(new_device);
-		/*
-		 * This will free up the node
-		 */
-		(void) ndi_devi_offline(new_device, NDI_DEVI_REMOVE);
-	}
-	ndi_devi_exit(devi, circ);
-
-	return (PCICFG_FAILURE);
-}
-
-/*
- * configure the child nodes of ntbridge. new_device points to ntbridge itself
- */
-/*ARGSUSED*/
-static uint_t
-pcicfg_configure_ntbridge(dev_info_t *new_device, uint_t bus, uint_t device)
-{
-	int bus_range[2], rc = PCICFG_FAILURE, rc1, max_devs = 0;
-	int			devno;
-	dev_info_t		*new_ntbridgechild;
-	ddi_acc_handle_t	config_handle;
-	uint16_t		vid;
-	uint64_t		next_bus;
-	uint64_t		blen;
-	ndi_ra_request_t	req;
-	uint8_t			pcie_device_type = 0;
-
-	/*
-	 * If we need to do indirect config, lets create a property here
-	 * to let the child conf map routine know that it has to
-	 * go through the DDI calls, and not assume the devices are
-	 * mapped directly under the host.
-	 */
-	if ((rc = ndi_prop_update_int(DDI_DEV_T_NONE, new_device,
-	    PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS))
-	    != DDI_SUCCESS) {
-
-		DEBUG0("Cannot create indirect conf map property.\n");
-		return ((uint_t)PCICFG_FAILURE);
-	}
-	if (pci_config_setup(new_device, &config_handle) != DDI_SUCCESS)
-		return ((uint_t)PCICFG_FAILURE);
-	/* check if we are PCIe device */
-	if (pcicfg_pcie_device_type(new_device, config_handle) == DDI_SUCCESS)
-		pcie_device_type = 1;
-	pci_config_teardown(&config_handle);
-
-	/* create Bus node properties for ntbridge. */
-	if (pcicfg_set_busnode_props(new_device, pcie_device_type, -1, -1) !=
-	    PCICFG_SUCCESS) {
-		DEBUG0("Failed to set busnode props\n");
-		return (rc);
-	}
-
-	/* For now: Lets only support one layer of child */
-	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
-	req.ra_len = 1;
-	if (ndi_ra_alloc(ddi_get_parent(new_device), &req,
-	    &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
-	    NDI_RA_PASS) != NDI_SUCCESS) {
-		DEBUG0("ntbridge: Failed to get a bus number\n");
-		return (rc);
-	}
-
-	DEBUG1("ntbridge bus range start  ->[%d]\n", next_bus);
-
-	/*
-	 * Following will change, as we detect more bridges
-	 * on the way.
-	 */
-	bus_range[0] = (int)next_bus;
-	bus_range[1] = (int)next_bus;
-
-	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_device,
-	    "bus-range", bus_range, 2) != DDI_SUCCESS) {
-		DEBUG0("Cannot set ntbridge bus-range property");
-		return (rc);
-	}
-
-	/*
-	 * The other interface (away from the host) will be
-	 * initialized by the nexus driver when it loads.
-	 * We just have to set the registers and the nexus driver
-	 * figures out the rest.
-	 */
-
-	/*
-	 * finally, lets load and attach the driver
-	 * before configuring children of ntbridge.
-	 */
-	rc = ndi_devi_online(new_device, NDI_NO_EVENT|NDI_CONFIG);
-	if (rc != NDI_SUCCESS) {
-		cmn_err(CE_WARN,
-		    "pcicfg: Fail: can\'t load non-transparent bridge \
-		    driver.\n");
-		rc = PCICFG_FAILURE;
-		return (rc);
-	}
-	DEBUG0("pcicfg: Success loading nontransparent bridge nexus driver..");
-
-	/* Now set aside pci resources for our children. */
-	if (pcicfg_ntbridge_allocate_resources(new_device) !=
-	    PCICFG_SUCCESS) {
-		max_devs = 0;
-		rc = PCICFG_FAILURE;
-	} else
-		max_devs = PCICFG_MAX_DEVICE;
-
-	/* Probe devices on 2nd bus */
-	for (devno = pcicfg_start_devno; devno < max_devs; devno++) {
-
-		if (ndi_devi_alloc(new_device, DEVI_PSEUDO_NEXNAME,
-		    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild)
-		    != NDI_SUCCESS) {
-
-			DEBUG0("pcicfg: Failed to alloc test node\n");
-			rc = PCICFG_FAILURE;
-			break;
-		}
-
-		if (pcicfg_add_config_reg(new_ntbridgechild, next_bus, devno, 0)
-		    != DDI_PROP_SUCCESS) {
-			cmn_err(CE_WARN,
-			    "Failed to add conf reg for ntbridge child.\n");
-			(void) ndi_devi_free(new_ntbridgechild);
-			rc = PCICFG_FAILURE;
-			break;
-		}
-
-		if ((rc = pci_config_setup(new_ntbridgechild,
-		    &config_handle)) != PCICFG_SUCCESS) {
-			cmn_err(CE_WARN,
-			    "Cannot map ntbridge child %x\n", devno);
-			(void) ndi_devi_free(new_ntbridgechild);
-			rc = PCICFG_FAILURE;
-			break;
-		}
-
-		/*
-		 * See if there is any PCI HW at this location
-		 * by reading the Vendor ID.  If it returns with 0xffff
-		 * then there is no hardware at this location.
-		 */
-		vid = pci_config_get16(config_handle, PCI_CONF_VENID);
-
-		pci_config_teardown(&config_handle);
-		(void) ndi_devi_free(new_ntbridgechild);
-		if (vid	== 0xffff)
-			continue;
-
-		/* Lets fake attachments points for each child, */
-		if (pcicfg_configure(new_device, devno) != PCICFG_SUCCESS) {
-			int old_dev = pcicfg_start_devno;
-
-			cmn_err(CE_WARN,
-			"Error configuring ntbridge child dev=%d\n", devno);
-
-			rc = PCICFG_FAILURE;
-			while (old_dev != devno) {
-				if (pcicfg_ntbridge_unconfigure_child(
-				    new_device, old_dev) == PCICFG_FAILURE)
-
-					cmn_err(CE_WARN,
-					    "Unconfig Error ntbridge child "
-					    "dev=%d\n", old_dev);
-				old_dev++;
-			}
-			break;
-		}
-	} /* devno loop */
-	DEBUG1("ntbridge: finish probing 2nd bus, rc=%d\n", rc);
-
-	if (rc != PCICFG_FAILURE)
-		rc = pcicfg_ntbridge_configure_done(new_device);
-	else {
-		pcicfg_phdl_t *entry = pcicfg_find_phdl(new_device);
-		uint_t			*bus;
-		int			k;
-
-		if (ddi_getlongprop(DDI_DEV_T_ANY, new_device,
-		    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
-		    &k) != DDI_PROP_SUCCESS) {
-			DEBUG0("Failed to read bus-range property\n");
-			rc = PCICFG_FAILURE;
-			return (rc);
-		}
-
-		DEBUG2("Need to free bus [%d] range [%d]\n",
-		    bus[0], bus[1] - bus[0] + 1);
-
-		if (ndi_ra_free(ddi_get_parent(new_device),
-		    (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
-		    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
-			DEBUG0("Failed to free a bus number\n");
-			rc = PCICFG_FAILURE;
-			/*
-			 * Don't forget to free up memory from ddi_getlongprop
-			 */
-			kmem_free((caddr_t)bus, k);
-
-			return (rc);
-		}
-
-		/*
-		 * Since no memory allocations are done for non transparent
-		 * bridges (but instead we just set the handle with the
-		 * already allocated memory, we just need to reset the
-		 * following values before calling the destroy_phdl()
-		 * function next, otherwise the it will try to free
-		 * memory allocated as in case of a transparent bridge.
-		 */
-		entry->memory_len = 0;
-		entry->io_len = 0;
-		/* the following will free hole data. */
-		(void) pcicfg_destroy_phdl(new_device);
-		/*
-		 * Don't forget to free up memory from ddi_getlongprop
-		 */
-		kmem_free((caddr_t)bus, k);
-	}
-
-	/*
-	 * Unload driver just in case child configure failed!
-	 */
-	rc1 = ndi_devi_offline(new_device, NDI_NO_EVENT);
-	DEBUG1("pcicfg: now unloading the ntbridge driver. rc1=%d\n", rc1);
-	if (rc1 != NDI_SUCCESS) {
-		cmn_err(CE_WARN,
-		    "pcicfg: can\'t unload ntbridge driver children.\n");
-		rc = PCICFG_FAILURE;
-	}
-
-	return (rc);
-}
-
-static int
-pcicfg_ntbridge_allocate_resources(dev_info_t *dip)
-{
-	pcicfg_phdl_t		*phdl;
-	ndi_ra_request_t	*mem_request;
-	ndi_ra_request_t	*io_request;
-	uint64_t		boundbase, boundlen;
-
-	phdl = pcicfg_find_phdl(dip);
-	ASSERT(phdl);
-
-	mem_request = &phdl->mem_req;
-	io_request  = &phdl->io_req;
-
-	phdl->error = PCICFG_SUCCESS;
-
-	/* Set Memory space handle for ntbridge */
-	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
-	    PCI_BASE_SPACE_MEM) != DDI_SUCCESS) {
-		cmn_err(CE_WARN,
-		    "ntbridge: Mem resource information failure\n");
-		phdl->memory_len  = 0;
-		return (PCICFG_FAILURE);
-	}
-	mem_request->ra_boundbase = boundbase;
-	mem_request->ra_boundlen = boundbase + boundlen;
-	mem_request->ra_len = boundlen;
-	mem_request->ra_align_mask =
-	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
-	mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
-
-	/*
-	 * mem_request->ra_len =
-	 * PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
-	 */
-
-	phdl->memory_base = phdl->memory_last = boundbase;
-	phdl->memory_len  = boundlen;
-	phdl->mem_hole.start = phdl->memory_base;
-	phdl->mem_hole.len = mem_request->ra_len;
-	phdl->mem_hole.next = (hole_t *)NULL;
-
-	DEBUG2("AP requested [0x%llx], needs [0x%llx] bytes of memory\n",
-	    boundlen, mem_request->ra_len);
-
-	/* set up a memory resource map for NT bridge */
-	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
-		DEBUG0("Can not setup ntbridge memory resource map\n");
-		return (PCICFG_FAILURE);
-	}
-	/* initialize the memory map */
-	if (ndi_ra_free(dip, boundbase, boundlen, NDI_RA_TYPE_MEM,
-	    NDI_RA_PASS) != NDI_SUCCESS) {
-		DEBUG0("Can not initalize ntbridge memory resource map\n");
-		return (PCICFG_FAILURE);
-	}
-	/* Set IO space handle for ntbridge */
-	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
-	    PCI_BASE_SPACE_IO) != DDI_SUCCESS) {
-		cmn_err(CE_WARN, "ntbridge: IO resource information failure\n");
-		phdl->io_len  = 0;
-		return (PCICFG_FAILURE);
-	}
-	io_request->ra_len = boundlen;
-	io_request->ra_align_mask =
-	    PCICFG_IOGRAN - 1;   /* 4K alignment on I/O space */
-	io_request->ra_boundbase = boundbase;
-	io_request->ra_boundlen = boundbase + boundlen;
-	io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
-
-	/*
-	 * io_request->ra_len =
-	 * PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
-	 */
-
-	phdl->io_base = phdl->io_last = (uint32_t)boundbase;
-	phdl->io_len  = (uint32_t)boundlen;
-	phdl->io_hole.start = phdl->io_base;
-	phdl->io_hole.len = io_request->ra_len;
-	phdl->io_hole.next = (hole_t *)NULL;
-
-	DEBUG2("AP requested [0x%llx], needs [0x%llx] bytes of IO\n",
-	    boundlen, io_request->ra_len);
-
-	DEBUG2("MEMORY BASE = [0x%x] length [0x%x]\n",
-	    phdl->memory_base, phdl->memory_len);
-	DEBUG2("IO     BASE = [0x%x] length [0x%x]\n",
-	    phdl->io_base, phdl->io_len);
-
-	/* set up a IO resource map for NT bridge */
-	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
-		DEBUG0("Can not setup ntbridge memory resource map\n");
-		return (PCICFG_FAILURE);
-	}
-	/* initialize the IO map */
-	if (ndi_ra_free(dip, boundbase, boundlen, NDI_RA_TYPE_IO,
-	    NDI_RA_PASS) != NDI_SUCCESS) {
-		DEBUG0("Can not initalize ntbridge memory resource map\n");
-		return (PCICFG_FAILURE);
-	}
-
-	return (PCICFG_SUCCESS);
-}
-
-static int
-pcicfg_ntbridge_configure_done(dev_info_t *dip)
-{
-	pcicfg_range_t range[PCICFG_RANGE_LEN];
-	pcicfg_phdl_t		*entry;
-	uint_t			len;
-	pcicfg_bus_range_t	bus_range;
-	int			new_bus_range[2];
-
-	DEBUG1("Configuring children for %llx\n", dip);
-
-	entry = pcicfg_find_phdl(dip);
-	ASSERT(entry);
-
-	bzero((caddr_t)range,
-	    sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
-	range[1].child_hi = range[1].parent_hi |=
-	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
-	range[1].child_lo = range[1].parent_lo = (uint32_t)entry->memory_base;
-
-	range[0].child_hi = range[0].parent_hi |=
-	    (PCI_REG_REL_M | PCI_ADDR_IO);
-	range[0].child_lo = range[0].parent_lo = (uint32_t)entry->io_base;
-
-	len = sizeof (pcicfg_bus_range_t);
-	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
-	    "bus-range", (caddr_t)&bus_range, (int *)&len) != DDI_SUCCESS) {
-		DEBUG0("no bus-range property\n");
-		return (PCICFG_FAILURE);
-	}
-
-	new_bus_range[0] = bus_range.lo;	/* primary bus number */
-	if (entry->highest_bus) {	/* secondary bus number */
-		if (entry->highest_bus < bus_range.lo) {
-			cmn_err(CE_WARN,
-			    "ntbridge bus range invalid !(%d,%d)\n",
-			    bus_range.lo, entry->highest_bus);
-			new_bus_range[1] = bus_range.lo + entry->highest_bus;
-		}
-		else
-			new_bus_range[1] = entry->highest_bus;
-	}
-	else
-		new_bus_range[1] = bus_range.hi;
-
-	DEBUG2("ntbridge: bus range lo=%x, hi=%x\n",
-	    new_bus_range[0], new_bus_range[1]);
-
-	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
-	    "bus-range", new_bus_range, 2) != DDI_SUCCESS) {
-		DEBUG0("Failed to set bus-range property");
-		entry->error = PCICFG_FAILURE;
-		return (PCICFG_FAILURE);
-	}
-
-#ifdef DEBUG
-	{
-		uint64_t	unused;
-		unused = pcicfg_unused_space(&entry->io_hole, &len);
-		DEBUG2("ntbridge: Unused IO space %llx bytes over %d holes\n",
-		    unused, len);
-	}
-#endif
-
-	range[0].size_lo = entry->io_len;
-	if (pcicfg_update_ranges_prop(dip, &range[0])) {
-		DEBUG0("Failed to update ranges (i/o)\n");
-		entry->error = PCICFG_FAILURE;
-		return (PCICFG_FAILURE);
-	}
-
-#ifdef DEBUG
-	{
-		uint64_t	unused;
-		unused = pcicfg_unused_space(&entry->mem_hole, &len);
-		DEBUG2("ntbridge: Unused Mem space %llx bytes over %d holes\n",
-		    unused, len);
-	}
-#endif
-
-	range[1].size_lo = entry->memory_len;
-	if (pcicfg_update_ranges_prop(dip, &range[1])) {
-		DEBUG0("Failed to update ranges (memory)\n");
-		entry->error = PCICFG_FAILURE;
-		return (PCICFG_FAILURE);
-	}
-
-	return (PCICFG_SUCCESS);
-}
-
-static int
-pcicfg_ntbridge_unconfigure_child(dev_info_t *new_device, uint_t devno)
-{
-
-	dev_info_t	*new_ntbridgechild;
-	int 		len, bus;
-	uint16_t	vid;
-	ddi_acc_handle_t	config_handle;
-	pcicfg_bus_range_t pci_bus_range;
-
-	len = sizeof (pcicfg_bus_range_t);
-	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, new_device, DDI_PROP_DONTPASS,
-	    "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
-		DEBUG0("no bus-range property\n");
-		return (PCICFG_FAILURE);
-	}
-
-	bus = pci_bus_range.lo; /* primary bus number of this bus node */
-
-	if (ndi_devi_alloc(new_device, DEVI_PSEUDO_NEXNAME,
-	    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild) != NDI_SUCCESS) {
-
-		DEBUG0("pcicfg: Failed to alloc test node\n");
-		return (PCICFG_FAILURE);
-	}
-
-	if (pcicfg_add_config_reg(new_ntbridgechild, bus, devno, 0)
-	    != DDI_PROP_SUCCESS) {
-		cmn_err(CE_WARN,
-		"Unconfigure: Failed to add conf reg prop for ntbridge "
-		    "child.\n");
-		(void) ndi_devi_free(new_ntbridgechild);
-		return (PCICFG_FAILURE);
-	}
-
-	if (pcicfg_config_setup(new_ntbridgechild, &config_handle)
-	    != DDI_SUCCESS) {
-		cmn_err(CE_WARN,
-		    "pcicfg: Cannot map ntbridge child %x\n", devno);
-		(void) ndi_devi_free(new_ntbridgechild);
-		return (PCICFG_FAILURE);
-	}
-
-	/*
-	 * See if there is any PCI HW at this location
-	 * by reading the Vendor ID.  If it returns with 0xffff
-	 * then there is no hardware at this location.
-	 */
-	vid = pci_config_get16(config_handle, PCI_CONF_VENID);
-
-	pci_config_teardown(&config_handle);
-	(void) ndi_devi_free(new_ntbridgechild);
-	if (vid	== 0xffff)
-		return (PCICFG_NODEVICE);
-
-	return (pcicfg_unconfigure(new_device, devno));
-}
-
-static int
-pcicfg_ntbridge_unconfigure(dev_info_t *dip)
-{
-	pcicfg_phdl_t *entry = pcicfg_find_phdl(dip);
-	uint_t			*bus;
-	int			k, rc = PCICFG_FAILURE;
-
-	if (entry->memory_len)
-		if (ndi_ra_map_destroy(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
-			DEBUG1("cannot destroy ntbridge memory map size=%x\n",
-			    entry->memory_len);
-			return (PCICFG_FAILURE);
-		}
-	if (entry->io_len)
-		if (ndi_ra_map_destroy(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
-			DEBUG1("cannot destroy ntbridge io map size=%x\n",
-			    entry->io_len);
-			return (PCICFG_FAILURE);
-		}
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
-	    &k) != DDI_PROP_SUCCESS) {
-		DEBUG0("ntbridge: Failed to read bus-range property\n");
-		return (rc);
-	}
-
-	DEBUG2("ntbridge: Need to free bus [%d] range [%d]\n",
-	    bus[0], bus[1] - bus[0] + 1);
-
-	if (ndi_ra_free(ddi_get_parent(dip),
-	    (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
-	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
-		DEBUG0("ntbridge: Failed to free a bus number\n");
-		/*
-		 * Don't forget to free up memory from ddi_getlongprop
-		 */
-		kmem_free((caddr_t)bus, k);
-
-		return (rc);
-	}
-
-	/*
-	 * Don't forget to free up memory from ddi_getlongprop
-	 */
-	kmem_free((caddr_t)bus, k);
-
-	/*
-	 * Since our resources will be freed at the parent level,
-	 * just reset these values.
-	 */
-	entry->memory_len = 0;
-	entry->io_len = 0;
-	/* the following will also free hole data. */
-	return (pcicfg_destroy_phdl(dip));
-
-}
-
-static int
-pcicfg_is_ntbridge(dev_info_t *dip)
-{
-	ddi_acc_handle_t	config_handle;
-	uint8_t		class, subclass;
-	int		rc = DDI_SUCCESS;
-
-	if (pcicfg_config_setup(dip, &config_handle) != DDI_SUCCESS) {
-		cmn_err(CE_WARN,
-		    "pcicfg: cannot map config space, to get map type\n");
-		return (DDI_FAILURE);
-	}
-	class = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
-	subclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
-
-	/* check for class=6, subclass=9, for non transparent bridges.  */
-	if ((class != PCI_CLASS_BRIDGE) || (subclass != PCI_BRIDGE_STBRIDGE))
-		rc = DDI_FAILURE;
-
-	DEBUG3("pcicfg: checking device %x,%x for indirect map. rc=%d\n",
-	    pci_config_get16(config_handle, PCI_CONF_VENID),
-	    pci_config_get16(config_handle, PCI_CONF_DEVID),
-	    rc);
-	pci_config_teardown(&config_handle);
-	return (rc);
-}
-
-/*
- * this function is called only for SPARC platforms, where we may have
- * a mix n' match of direct vs indirectly mapped configuration space.
- * On x86, this function does not get called. We always return TRUE
- * via a macro for x86.
- */
-/*ARGSUSED*/
-static int
-pcicfg_indirect_map(dev_info_t *dip)
-{
-#if defined(__sparc)
-	int rc = DDI_FAILURE;
-
-	if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip), 0,
-	    PCI_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
-		rc = DDI_SUCCESS;
-	else
-		if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip),
-		    0, PCI_BUS_CONF_MAP_PROP,
-		    DDI_FAILURE) != DDI_FAILURE)
-			rc = DDI_SUCCESS;
-	DEBUG1("pci conf map = %d", rc);
-	return (rc);
-#else
-	return (DDI_SUCCESS);
-#endif
-}
-
-static uint_t
-pcicfg_get_ntbridge_child_range(dev_info_t *dip, uint64_t *boundbase,
-				uint64_t *boundlen, uint_t space_type)
-{
-	int		length, found = DDI_FAILURE, acount, i, ibridge;
-	pci_regspec_t	*assigned;
-
-	if ((ibridge = pcicfg_is_ntbridge(dip)) == DDI_FAILURE)
-		return (found);
-
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
-	    &length) != DDI_PROP_SUCCESS) {
-		DEBUG1("Failed to get assigned-addresses property %llx\n", dip);
-		return (found);
-	}
-	DEBUG1("pcicfg: ntbridge child range: dip = %s\n",
-	    ddi_driver_name(dip));
-
-	acount = length / sizeof (pci_regspec_t);
-
-	for (i = 0; i < acount; i++) {
-		if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
-		    pcicfg_indirect_map_devs[ibridge].mem_range_bar_offset) &&
-		    (space_type == PCI_BASE_SPACE_MEM)) {
-			found = DDI_SUCCESS;
-			break;
-		} else {
-			if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
-			    pcicfg_indirect_map_devs[ibridge].\
-			    io_range_bar_offset) &&
-			    (space_type == PCI_BASE_SPACE_IO)) {
-				found = DDI_SUCCESS;
-				break;
-			}
-		}
-	}
-	DEBUG3("pcicfg: ntbridge child range: space=%x, base=%lx, len=%lx\n",
-	    space_type, assigned[i].pci_phys_low, assigned[i].pci_size_low);
-
-	if (found == DDI_SUCCESS)  {
-		*boundbase = assigned[i].pci_phys_low;
-		*boundlen = assigned[i].pci_size_low;
-	}
-
-	kmem_free(assigned, length);
-	return (found);
-}
-
-/*
- * This will turn  resources allocated by pcicfg_configure()
- * and remove the device tree from the attachment point
- * and below.  The routine assumes the devices have their
- * drivers detached.
- */
-int
-pcicfg_unconfigure(dev_info_t *devi, uint_t device)
-{
-	dev_info_t *child_dip;
-	int func;
-	int i;
-
-	/*
-	 * Cycle through devices to make sure none are busy.
-	 * If a single device is busy fail the whole unconfigure.
-	 */
-	for (func = 0; func < PCICFG_MAX_FUNCTION; func++) {
-		if ((child_dip = pcicfg_devi_find(devi, device, func)) == NULL)
-			continue;
-
-		if (ndi_devi_offline(child_dip, NDI_UNCONFIG) == NDI_SUCCESS)
-			continue;
-		/*
-		 * Device function is busy. Before returning we have to
-		 * put all functions back online which were taken
-		 * offline during the process.
-		 */
-		DEBUG2("Device [0x%x] function [%x] is busy\n", device, func);
-		for (i = 0; i < func; i++) {
-			if ((child_dip = pcicfg_devi_find(devi, device, i))
-			    == NULL) {
-				DEBUG0(
-				    "No more devices to put back on line!!\n");
-				/*
-				 * Made it through all functions
-				 */
-				continue;
-			}
-			if (ndi_devi_online(child_dip, NDI_CONFIG)
-			    != NDI_SUCCESS) {
-				DEBUG0("Failed to put back devices state\n");
-				return (PCICFG_FAILURE);
-			}
-		}
-		return (PCICFG_FAILURE);
-	}
-
-	/*
-	 * Now, tear down all devinfo nodes for this AP.
-	 */
-	for (func = 0; func < PCICFG_MAX_FUNCTION; func++) {
-		if ((child_dip = pcicfg_devi_find(devi,
-		    device, func)) == NULL) {
-			DEBUG0("No more devices to tear down!\n");
-			continue;
-		}
-
-		DEBUG2("Tearing down device [0x%x] function [0x%x]\n",
-		    device, func);
-
-		if (pcicfg_is_ntbridge(child_dip) != DDI_FAILURE)
-			if (pcicfg_ntbridge_unconfigure(child_dip) !=
-			    PCICFG_SUCCESS) {
-				cmn_err(CE_WARN,
-				    "ntbridge: unconfigure failed\n");
-				return (PCICFG_FAILURE);
-			}
-
-		if (pcicfg_teardown_device(child_dip) != PCICFG_SUCCESS) {
-			DEBUG2("Failed to tear down device [0x%x]"
-			    "function [0x%x]\n",
-			    device, func);
-			return (PCICFG_FAILURE);
-		}
-	}
-
-	return (PCICFG_SUCCESS);
-}
-
-static int
-pcicfg_teardown_device(dev_info_t *dip)
-{
-	ddi_acc_handle_t	config_handle;
-
-	/*
-	 * Free up resources associated with 'dip'
-	 */
-
-	if (pcicfg_free_resources(dip) != PCICFG_SUCCESS) {
-		DEBUG0("Failed to free resources\n");
-		return (PCICFG_FAILURE);
-	}
-
-	/*
-	 * This will disable the device
-	 */
-	if (pci_config_setup(dip, &config_handle) != PCICFG_SUCCESS) {
-		return (PCICFG_FAILURE);
-	}
-
-	pcicfg_device_off(config_handle);
-	pci_config_teardown(&config_handle);
-
-	/*
-	 * The framework provides this routine which can
-	 * tear down a sub-tree.
-	 */
-	if (ndi_devi_offline(dip, NDI_DEVI_REMOVE) != NDI_SUCCESS) {
-		DEBUG0("Failed to offline and remove node\n");
-		return (PCICFG_FAILURE);
-	}
-
-	return (PCICFG_SUCCESS);
-}
-
-/*
- * BEGIN GENERIC SUPPORT ROUTINES
- */
-static pcicfg_phdl_t *
-pcicfg_find_phdl(dev_info_t *dip)
-{
-	pcicfg_phdl_t *entry;
-	mutex_enter(&pcicfg_list_mutex);
-	for (entry = pcicfg_phdl_list; entry != NULL; entry = entry->next) {
-		if (entry->dip == dip) {
-			mutex_exit(&pcicfg_list_mutex);
-			return (entry);
-		}
-	}
-	mutex_exit(&pcicfg_list_mutex);
-
-	/*
-	 * Did'nt find entry - create one
-	 */
-	return (pcicfg_create_phdl(dip));
-}
-
-static pcicfg_phdl_t *
-pcicfg_create_phdl(dev_info_t *dip)
-{
-	pcicfg_phdl_t *new;
-
-	new = (pcicfg_phdl_t *)kmem_zalloc(sizeof (pcicfg_phdl_t),
-	    KM_SLEEP);
-
-	new->dip = dip;
-	mutex_enter(&pcicfg_list_mutex);
-	new->next = pcicfg_phdl_list;
-	pcicfg_phdl_list = new;
-	mutex_exit(&pcicfg_list_mutex);
-
-	return (new);
-}
-
-static int
-pcicfg_destroy_phdl(dev_info_t *dip)
-{
-	pcicfg_phdl_t *entry;
-	pcicfg_phdl_t *follow = NULL;
-
-	mutex_enter(&pcicfg_list_mutex);
-	for (entry = pcicfg_phdl_list; entry != NULL; follow = entry,
-	    entry = entry->next) {
-		if (entry->dip == dip) {
-			if (entry == pcicfg_phdl_list) {
-				pcicfg_phdl_list = entry->next;
-			} else {
-				follow->next = entry->next;
-			}
-			/*
-			 * If this entry has any allocated memory
-			 * or IO space associated with it, that
-			 * must be freed up.
-			 */
-			if (entry->memory_len > 0) {
-				(void) ndi_ra_free(ddi_get_parent(dip),
-				    entry->memory_base,
-				    entry->memory_len,
-				    NDI_RA_TYPE_MEM, NDI_RA_PASS);
-			}
-			pcicfg_free_hole(&entry->mem_hole);
-
-			if (entry->io_len > 0) {
-				(void) ndi_ra_free(ddi_get_parent(dip),
-				    entry->io_base,
-				    entry->io_len,
-				    NDI_RA_TYPE_IO, NDI_RA_PASS);
-			}
-			pcicfg_free_hole(&entry->io_hole);
-
-			/*
-			 * Destroy this entry
-			 */
-			kmem_free((caddr_t)entry, sizeof (pcicfg_phdl_t));
-			mutex_exit(&pcicfg_list_mutex);
-			return (PCICFG_SUCCESS);
-		}
-	}
-	mutex_exit(&pcicfg_list_mutex);
-	/*
-	 * Did'nt find the entry
-	 */
-	return (PCICFG_FAILURE);
-}
-
-static int
-pcicfg_program_ap(dev_info_t *dip)
-{
-	pcicfg_phdl_t *phdl;
-	uint8_t header_type;
-	ddi_acc_handle_t handle;
-	pcicfg_phdl_t *entry;
-
-	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
-		DEBUG0("Failed to map config space!\n");
-		return (PCICFG_FAILURE);
-
-	}
-
-	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
-
-	(void) pcicfg_config_teardown(&handle);
-
-	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
-
-		if (pcicfg_allocate_chunk(dip) != PCICFG_SUCCESS) {
-			DEBUG0("Not enough memory to hotplug\n");
-			(void) pcicfg_destroy_phdl(dip);
-			return (PCICFG_FAILURE);
-		}
-
-		phdl = pcicfg_find_phdl(dip);
-		ASSERT(phdl);
-
-		(void) pcicfg_bridge_assign(dip, (void *)phdl);
-
-		if (phdl->error != PCICFG_SUCCESS) {
-			DEBUG0("Problem assigning bridge\n");
-			(void) pcicfg_destroy_phdl(dip);
-			return (phdl->error);
-		}
-
-		/*
-		 * Successfully allocated and assigned
-		 * memory.  Set the memory and IO length
-		 * to zero so when the handle is freed up
-		 * it will not de-allocate assigned resources.
-		 */
-		entry = (pcicfg_phdl_t *)phdl;
-
-		entry->memory_len = entry->io_len = 0;
-
-		/*
-		 * Free up the "entry" structure.
-		 */
-		(void) pcicfg_destroy_phdl(dip);
-	} else {
-		if (pcicfg_device_assign(dip) != PCICFG_SUCCESS) {
-			return (PCICFG_FAILURE);
-		}
-	}
-	return (PCICFG_SUCCESS);
-}
-
-static int
-pcicfg_bridge_assign(dev_info_t *dip, void *hdl)
-{
-	ddi_acc_handle_t handle;
-	pci_regspec_t *reg;
-	int length;
-	int rcount;
-	int i;
-	int offset;
-	uint64_t mem_answer;
-	uint32_t io_answer;
-	int count;
-	uint8_t header_type;
-	pcicfg_range_t range[PCICFG_RANGE_LEN];
-	int bus_range[2];
-
-	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
-
-	DEBUG1("bridge assign: assigning addresses to %s\n", ddi_get_name(dip));
-
-	if (entry == NULL) {
-		DEBUG0("Failed to get entry\n");
-		return (DDI_WALK_TERMINATE);
-	}
-
-	entry->error = PCICFG_SUCCESS;
-
-	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
-		DEBUG0("Failed to map config space!\n");
-		entry->error = PCICFG_FAILURE;
-		return (DDI_WALK_TERMINATE);
-	}
-
-	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
-
-	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
-
-		bzero((caddr_t)range,
-		    sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
-
-		(void) pcicfg_setup_bridge(entry, handle, dip);
-
-		range[0].child_hi = range[0].parent_hi |=
-		    (PCI_REG_REL_M | PCI_ADDR_IO);
-		range[0].child_lo = range[0].parent_lo =
-		    entry->io_last;
-		range[1].child_hi = range[1].parent_hi |=
-		    (PCI_REG_REL_M | PCI_ADDR_MEM32);
-		range[1].child_lo = range[1].parent_lo =
-		    entry->memory_last;
-
-		ndi_devi_enter(dip, &count);
-		ddi_walk_devs(ddi_get_child(dip),
-		    pcicfg_bridge_assign, (void *)entry);
-		ndi_devi_exit(dip, count);
-
-		(void) pcicfg_update_bridge(entry, handle);
-
-		bus_range[0] = pci_config_get8(handle, PCI_BCNF_SECBUS);
-		bus_range[1] = pci_config_get8(handle, PCI_BCNF_SUBBUS);
-
-		if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
-		    "bus-range", bus_range, 2) != DDI_SUCCESS) {
-			DEBUG0("Failed to set bus-range property");
-			entry->error = PCICFG_FAILURE;
-			return (DDI_WALK_TERMINATE);
-		}
-
-		if (entry->io_len > 0) {
-			range[0].size_lo = entry->io_last - entry->io_base;
-			if (pcicfg_update_ranges_prop(dip, &range[0])) {
-				DEBUG0("Failed to update ranges (i/o)\n");
-				entry->error = PCICFG_FAILURE;
-				return (DDI_WALK_TERMINATE);
-			}
-		}
-		if (entry->memory_len > 0) {
-			range[1].size_lo =
-			    entry->memory_last - entry->memory_base;
-			if (pcicfg_update_ranges_prop(dip, &range[1])) {
-				DEBUG0("Failed to update ranges (memory)\n");
-				entry->error = PCICFG_FAILURE;
-				return (DDI_WALK_TERMINATE);
-			}
-		}
-
-		(void) pcicfg_device_on(handle);
-
-		PCICFG_DUMP_BRIDGE_CONFIG(handle);
-
-		return (DDI_WALK_PRUNECHILD);
-	}
-
-	/*
-	 * If there is an interrupt pin set program
-	 * interrupt line with default values.
-	 */
-	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
-		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
-	}
-
-	/*
-	 * A single device (under a bridge).
-	 * For each "reg" property with a length, allocate memory
-	 * and program the base registers.
-	 */
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
-	    &length) != DDI_PROP_SUCCESS) {
-		DEBUG0("Failed to read reg property\n");
-		entry->error = PCICFG_FAILURE;
-		return (DDI_WALK_TERMINATE);
-	}
-
-	rcount = length / sizeof (pci_regspec_t);
-	offset = PCI_CONF_BASE0;
-	for (i = 0; i < rcount; i++) {
-		if ((reg[i].pci_size_low != 0)||
-		    (reg[i].pci_size_hi != 0)) {
-
-			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
-
-			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
-			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
-
-				(void) pcicfg_get_mem(entry,
-				    reg[i].pci_size_low, &mem_answer);
-				pci_config_put64(handle, offset, mem_answer);
-				DEBUG2("REGISTER off %x (64)LO ----> [0x%x]\n",
-				    offset,
-				    pci_config_get32(handle, offset));
-				DEBUG2("REGISTER off %x (64)HI ----> [0x%x]\n",
-				    offset + 4,
-				    pci_config_get32(handle, offset + 4));
-
-				reg[i].pci_phys_low = PCICFG_HIADDR(mem_answer);
-				reg[i].pci_phys_mid  =
-				    PCICFG_LOADDR(mem_answer);
-
-				break;
-
-			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
-				/* allocate memory space from the allocator */
-
-				(void) pcicfg_get_mem(entry,
-				    reg[i].pci_size_low, &mem_answer);
-				pci_config_put32(handle,
-				    offset, (uint32_t)mem_answer);
-
-				DEBUG2("REGISTER off %x(32)LO ----> [0x%x]\n",
-				    offset,
-				    pci_config_get32(handle, offset));
-
-				reg[i].pci_phys_low = (uint32_t)mem_answer;
-
-				break;
-			case PCI_REG_ADDR_G(PCI_ADDR_IO):
-				/* allocate I/O space from the allocator */
-
-				(void) pcicfg_get_io(entry,
-				    reg[i].pci_size_low, &io_answer);
-				pci_config_put32(handle, offset, io_answer);
-
-				DEBUG2("REGISTER off %x (I/O)LO ----> [0x%x]\n",
-				    offset,
-				    pci_config_get32(handle, offset));
-
-				reg[i].pci_phys_low = io_answer;
-
-				break;
-			default:
-				DEBUG0("Unknown register type\n");
-				kmem_free(reg, length);
-				(void) pcicfg_config_teardown(&handle);
-				entry->error = PCICFG_FAILURE;
-				return (DDI_WALK_TERMINATE);
-			} /* switch */
-
-			/*
-			 * Now that memory locations are assigned,
-			 * update the assigned address property.
-			 */
-			if (pcicfg_update_assigned_prop(dip,
-			    &reg[i]) != PCICFG_SUCCESS) {
-				kmem_free(reg, length);
-				(void) pcicfg_config_teardown(&handle);
-				entry->error = PCICFG_FAILURE;
-				return (DDI_WALK_TERMINATE);
-			}
-		}
-	}
-	(void) pcicfg_device_on(handle);
-
-	PCICFG_DUMP_DEVICE_CONFIG(handle);
-
-	(void) pcicfg_config_teardown(&handle);
-	/*
-	 * Don't forget to free up memory from ddi_getlongprop
-	 */
-	kmem_free((caddr_t)reg, length);
-
-	return (DDI_WALK_CONTINUE);
-}
-static int
-pcicfg_device_assign(dev_info_t *dip)
-{
-	ddi_acc_handle_t	handle;
-	pci_regspec_t		*reg;
-	int			length;
-	int			rcount;
-	int			i;
-	int			offset;
-	ndi_ra_request_t	request;
-	uint64_t		answer;
-	uint64_t		alen;
-
-
-	DEBUG1("%llx now under configuration\n", dip);
-
-	/*
-	 * XXX Failure here should be noted
-	 */
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
-	    &length) != DDI_PROP_SUCCESS) {
-		DEBUG0("Failed to read reg property\n");
-		return (PCICFG_FAILURE);
-	}
-
-	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
-		DEBUG0("Failed to map config space!\n");
-		/*
-		 * Don't forget to free up memory from ddi_getlongprop
-		 */
-		kmem_free((caddr_t)reg, length);
-
-		return (PCICFG_FAILURE);
-	}
-
-	/*
-	 * A single device
-	 *
-	 * For each "reg" property with a length, allocate memory
-	 * and program the base registers.
-	 */
-
-	/*
-	 * If there is an interrupt pin set program
-	 * interrupt line with default values.
-	 */
-	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
-		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
-	}
-
-	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
-
-	request.ra_flags |= NDI_RA_ALIGN_SIZE;
-	request.ra_boundbase = 0;
-	request.ra_boundlen = PCICFG_4GIG_LIMIT;
-
-	rcount = length / sizeof (pci_regspec_t);
-	offset = PCI_CONF_BASE0;
-	for (i = 0; i < rcount; i++) {
-		if ((reg[i].pci_size_low != 0)||
-		    (reg[i].pci_size_hi != 0)) {
-
-			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
-			request.ra_len = reg[i].pci_size_low;
-
-			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
-			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
-				request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
-				/* allocate memory space from the allocator */
-				if (ndi_ra_alloc(ddi_get_parent(dip),
-				    &request, &answer, &alen,
-				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
-				    != NDI_SUCCESS) {
-					DEBUG0("Failed to allocate 64b mem\n");
-					kmem_free(reg, length);
-					(void) pcicfg_config_teardown(&handle);
-					return (PCICFG_FAILURE);
-				}
-				DEBUG3("64 addr = [0x%x.%x] len [0x%x]\n",
-				    PCICFG_HIADDR(answer),
-				    PCICFG_LOADDR(answer),
-				    alen);
-				/* program the low word */
-				pci_config_put32(handle,
-				    offset, PCICFG_LOADDR(answer));
-
-				/* program the high word with value zero */
-				pci_config_put32(handle, offset + 4,
-				    PCICFG_HIADDR(answer));
-
-				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
-				reg[i].pci_phys_mid = PCICFG_HIADDR(answer);
-				/*
-				 * currently support 32b address space
-				 * assignments only.
-				 */
-				reg[i].pci_phys_hi ^= PCI_ADDR_MEM64 ^
-				    PCI_ADDR_MEM32;
-
-				offset += 8;
-				break;
-
-			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
-				request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
-				/* allocate memory space from the allocator */
-				if (ndi_ra_alloc(ddi_get_parent(dip),
-				    &request, &answer, &alen,
-				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
-				    != NDI_SUCCESS) {
-					DEBUG0("Failed to allocate 32b mem\n");
-					kmem_free(reg, length);
-					(void) pcicfg_config_teardown(&handle);
-					return (PCICFG_FAILURE);
-				}
-				DEBUG3("32 addr = [0x%x.%x] len [0x%x]\n",
-				    PCICFG_HIADDR(answer),
-				    PCICFG_LOADDR(answer),
-				    alen);
-				/* program the low word */
-				pci_config_put32(handle,
-				    offset, PCICFG_LOADDR(answer));
-
-				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
-
-				offset += 4;
-				break;
-			case PCI_REG_ADDR_G(PCI_ADDR_IO):
-				/* allocate I/O space from the allocator */
-				request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
-				if (ndi_ra_alloc(ddi_get_parent(dip),
-				    &request, &answer, &alen,
-				    NDI_RA_TYPE_IO, NDI_RA_PASS)
-				    != NDI_SUCCESS) {
-					DEBUG0("Failed to allocate I/O\n");
-					kmem_free(reg, length);
-					(void) pcicfg_config_teardown(&handle);
-					return (PCICFG_FAILURE);
-				}
-				DEBUG3("I/O addr = [0x%x.%x] len [0x%x]\n",
-				    PCICFG_HIADDR(answer),
-				    PCICFG_LOADDR(answer),
-				    alen);
-				pci_config_put32(handle,
-				    offset, PCICFG_LOADDR(answer));
-
-				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
-
-				offset += 4;
-				break;
-			default:
-				DEBUG0("Unknown register type\n");
-				kmem_free(reg, length);
-				(void) pcicfg_config_teardown(&handle);
-				return (PCICFG_FAILURE);
-			} /* switch */
-
-			/*
-			 * Now that memory locations are assigned,
-			 * update the assigned address property.
-			 */
-
-			if (pcicfg_update_assigned_prop(dip,
-			    &reg[i]) != PCICFG_SUCCESS) {
-				kmem_free(reg, length);
-				(void) pcicfg_config_teardown(&handle);
-				return (PCICFG_FAILURE);
-			}
-		}
-	}
-
-	(void) pcicfg_device_on(handle);
-	kmem_free(reg, length);
-
-	PCICFG_DUMP_DEVICE_CONFIG(handle);
-
-	(void) pcicfg_config_teardown(&handle);
-	return (PCICFG_SUCCESS);
-}
-
-/*
- * The "dip" passed to this routine is assumed to be
- * the device at the attachment point. Currently it is
- * assumed to be a bridge.
- */
-static int
-pcicfg_allocate_chunk(dev_info_t *dip)
-{
-	pcicfg_phdl_t		*phdl;
-	ndi_ra_request_t	*mem_request;
-	ndi_ra_request_t	*io_request;
-	uint64_t		mem_answer;
-	uint64_t		io_answer;
-	int			count;
-	uint64_t		alen;
-
-	/*
-	 * This should not find an existing entry - so
-	 * it will create a new one.
-	 */
-	phdl = pcicfg_find_phdl(dip);
-	ASSERT(phdl);
-
-	mem_request = &phdl->mem_req;
-	io_request  = &phdl->io_req;
-
-	/*
-	 * From this point in the tree - walk the devices,
-	 * The function passed in will read and "sum" up
-	 * the memory and I/O requirements and put them in
-	 * structure "phdl".
-	 */
-	ndi_devi_enter(ddi_get_parent(dip), &count);
-	ddi_walk_devs(dip, pcicfg_sum_resources, (void *)phdl);
-	ndi_devi_exit(ddi_get_parent(dip), count);
-
-	if (phdl->error != PCICFG_SUCCESS) {
-		DEBUG0("Failure summing resources\n");
-		return (phdl->error);
-	}
-
-	/*
-	 * Call into the memory allocator with the request.
-	 * Record the addresses returned in the phdl
-	 */
-	DEBUG1("AP requires [0x%x] bytes of memory space\n",
-	    mem_request->ra_len);
-	DEBUG1("AP requires [0x%x] bytes of I/O    space\n",
-	    io_request->ra_len);
-
-	mem_request->ra_align_mask =
-	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
-	io_request->ra_align_mask =
-	    PCICFG_IOGRAN - 1;   /* 4K alignment on I/O space */
-	io_request->ra_boundbase = 0;
-	io_request->ra_boundlen = PCICFG_4GIG_LIMIT;
-	io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
-
-	mem_request->ra_len =
-	    PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
-
-	io_request->ra_len =
-	    PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
-
-	if (ndi_ra_alloc(ddi_get_parent(dip),
-	    mem_request, &mem_answer, &alen,
-	    NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
-		DEBUG0("Failed to allocate memory\n");
-		return (PCICFG_FAILURE);
-	}
-
-	phdl->memory_base = phdl->memory_last = mem_answer;
-	phdl->memory_len  = alen;
-
-	phdl->mem_hole.start = phdl->memory_base;
-	phdl->mem_hole.len = phdl->memory_len;
-	phdl->mem_hole.next = (hole_t *)NULL;
-
-	if (ndi_ra_alloc(ddi_get_parent(dip), io_request, &io_answer,
-	    &alen, NDI_RA_TYPE_IO, NDI_RA_PASS) != NDI_SUCCESS) {
-
-		DEBUG0("Failed to allocate I/O space\n");
-		(void) ndi_ra_free(ddi_get_parent(dip), mem_answer,
-		    alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
-		phdl->memory_len = phdl->io_len = 0;
-		return (PCICFG_FAILURE);
-	}
-
-	phdl->io_base = phdl->io_last = (uint32_t)io_answer;
-	phdl->io_len  = (uint32_t)alen;
-
-	phdl->io_hole.start = phdl->io_base;
-	phdl->io_hole.len = phdl->io_len;
-	phdl->io_hole.next = (hole_t *)NULL;
-
-	DEBUG2("MEMORY BASE = [0x%x] length [0x%x]\n",
-	    phdl->memory_base, phdl->memory_len);
-	DEBUG2("IO     BASE = [0x%x] length [0x%x]\n",
-	    phdl->io_base, phdl->io_len);
-
-	return (PCICFG_SUCCESS);
-}
-
-#ifdef	DEBUG
-/*
- * This function is useful in debug mode, where we can measure how
- * much memory was wasted/unallocated in bridge device's domain.
- */
-static uint64_t
-pcicfg_unused_space(hole_t *hole, uint32_t *hole_count)
-{
-	uint64_t len = 0;
-	uint32_t count = 0;
-
-	do {
-		len += hole->len;
-		hole = hole->next;
-		count++;
-	} while (hole);
-	*hole_count = count;
-	return (len);
-}
-#endif
-
-/*
- * This function frees data structures that hold the hole information
- * which are allocated in pcicfg_alloc_hole(). This is not freeing
- * any memory allocated through NDI calls.
- */
-static void
-pcicfg_free_hole(hole_t *addr_hole)
-{
-	hole_t *nhole, *hole = addr_hole->next;
-
-	while (hole) {
-		nhole = hole->next;
-		kmem_free(hole, sizeof (hole_t));
-		hole = nhole;
-	}
-}
-
-static uint64_t
-pcicfg_alloc_hole(hole_t *addr_hole, uint64_t *alast, uint32_t length)
-{
-	uint64_t actual_hole_start, ostart, olen;
-	hole_t	*hole = addr_hole, *thole, *nhole;
-
-	do {
-		actual_hole_start = PCICFG_ROUND_UP(hole->start, length);
-		if (((actual_hole_start - hole->start) + length) <= hole->len) {
-			DEBUG3("hole found. start %llx, len %llx, req=%x\n",
-			    hole->start, hole->len, length);
-			ostart = hole->start;
-			olen = hole->len;
-			/* current hole parameters adjust */
-			if ((actual_hole_start - hole->start) == 0) {
-				hole->start += length;
-				hole->len -= length;
-				if (hole->start > *alast)
-					*alast = hole->start;
-			} else {
-				hole->len = actual_hole_start - hole->start;
-				nhole = (hole_t *)kmem_zalloc(sizeof (hole_t),
-				    KM_SLEEP);
-				nhole->start = actual_hole_start + length;
-				nhole->len = (ostart + olen) - nhole->start;
-				nhole->next = NULL;
-				thole = hole->next;
-				hole->next = nhole;
-				nhole->next = thole;
-				if (nhole->start > *alast)
-					*alast = nhole->start;
-				DEBUG2("put new hole to %llx, %llx\n",
-				    nhole->start, nhole->len);
-			}
-			DEBUG2("adjust current hole to %llx, %llx\n",
-			    hole->start, hole->len);
-			break;
-		}
-		actual_hole_start = 0;
-		hole = hole->next;
-	} while (hole);
-
-	DEBUG1("return hole at %llx\n", actual_hole_start);
-	return (actual_hole_start);
-}
-
-static void
-pcicfg_get_mem(pcicfg_phdl_t *entry,
-	uint32_t length, uint64_t *ans)
-{
-	uint64_t new_mem;
-
-	/* See if there is a hole, that can hold this request. */
-	new_mem = pcicfg_alloc_hole(&entry->mem_hole, &entry->memory_last,
-	    length);
-	if (new_mem) {	/* if non-zero, found a hole. */
-		if (ans != NULL)
-			*ans = new_mem;
-	} else
-		cmn_err(CE_WARN, "No %u bytes memory window for %s\n",
-		    length, ddi_get_name(entry->dip));
-}
-
-static void
-pcicfg_get_io(pcicfg_phdl_t *entry,
-	uint32_t length, uint32_t *ans)
-{
-	uint32_t new_io;
-	uint64_t io_last;
-
-	/*
-	 * See if there is a hole, that can hold this request.
-	 * Pass 64 bit parameters and then truncate to 32 bit.
-	 */
-	io_last = entry->io_last;
-	new_io = (uint32_t)pcicfg_alloc_hole(&entry->io_hole, &io_last, length);
-	if (new_io) {	/* if non-zero, found a hole. */
-		entry->io_last = (uint32_t)io_last;
-		if (ans != NULL)
-			*ans = new_io;
-	} else
-		cmn_err(CE_WARN, "No %u bytes IO space window for %s\n",
-		    length, ddi_get_name(entry->dip));
-}
-
-static int
-pcicfg_sum_resources(dev_info_t *dip, void *hdl)
-{
-	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
-	pci_regspec_t *pci_rp;
-	int length;
-	int rcount;
-	int i;
-	ndi_ra_request_t *mem_request;
-	ndi_ra_request_t *io_request;
-	uint8_t header_type;
-	ddi_acc_handle_t handle;
-
-	entry->error = PCICFG_SUCCESS;
-
-	mem_request = &entry->mem_req;
-	io_request =  &entry->io_req;
-
-	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
-		DEBUG0("Failed to map config space!\n");
-		entry->error = PCICFG_FAILURE;
-		return (DDI_WALK_TERMINATE);
-	}
-
-	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
-
-	/*
-	 * If its a bridge - just record the highest bus seen
-	 */
-	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
-
-		if (entry->highest_bus < pci_config_get8(handle,
-		    PCI_BCNF_SECBUS)) {
-			entry->highest_bus =
-			    pci_config_get8(handle, PCI_BCNF_SECBUS);
-		}
-
-		(void) pcicfg_config_teardown(&handle);
-		entry->error = PCICFG_FAILURE;
-		return (DDI_WALK_CONTINUE);
-	} else {
-		if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-		    DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp,
-		    &length) != DDI_PROP_SUCCESS) {
-			/*
-			 * If one node in (the subtree of nodes)
-			 * does'nt have a "reg" property fail the
-			 * allocation.
-			 */
-			entry->memory_len = 0;
-			entry->io_len = 0;
-			entry->error = PCICFG_FAILURE;
-			return (DDI_WALK_TERMINATE);
-		}
-		/*
-		 * For each "reg" property with a length, add that to the
-		 * total memory (or I/O) to allocate.
-		 */
-		rcount = length / sizeof (pci_regspec_t);
-
-		for (i = 0; i < rcount; i++) {
-
-			switch (PCI_REG_ADDR_G(pci_rp[i].pci_phys_hi)) {
-
-			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
-				mem_request->ra_len =
-				    pci_rp[i].pci_size_low +
-				    PCICFG_ROUND_UP(mem_request->ra_len,
-				    pci_rp[i].pci_size_low);
-				DEBUG1("ADDING 32 --->0x%x\n",
-				    pci_rp[i].pci_size_low);
-
-			break;
-			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
-				mem_request->ra_len =
-				    pci_rp[i].pci_size_low +
-				    PCICFG_ROUND_UP(mem_request->ra_len,
-				    pci_rp[i].pci_size_low);
-				DEBUG1("ADDING 64 --->0x%x\n",
-				    pci_rp[i].pci_size_low);
-
-			break;
-			case PCI_REG_ADDR_G(PCI_ADDR_IO):
-				io_request->ra_len =
-				    pci_rp[i].pci_size_low +
-				    PCICFG_ROUND_UP(io_request->ra_len,
-				    pci_rp[i].pci_size_low);
-				DEBUG1("ADDING I/O --->0x%x\n",
-				    pci_rp[i].pci_size_low);
-			break;
-			default:
-			    /* Config space register - not included */
-			break;
-			}
-		}
-
-		/*
-		 * free the memory allocated by ddi_getlongprop
-		 */
-		kmem_free(pci_rp, length);
-
-		/*
-		 * continue the walk to the next sibling to sum memory
-		 */
-
-		(void) pcicfg_config_teardown(&handle);
-
-		return (DDI_WALK_CONTINUE);
-	}
-}
-
-static int
-pcicfg_find_resource_end(dev_info_t *dip, void *hdl)
-{
-	pcicfg_phdl_t *entry_p = (pcicfg_phdl_t *)hdl;
-	pci_regspec_t *pci_ap;
-	pcicfg_range_t *ranges;
-	int length;
-	int rcount;
-	int i;
-
-	entry_p->error = PCICFG_SUCCESS;
-
-	if (dip == entry_p->dip) {
-		DEBUG0("Don't include parent bridge node\n");
-		return (DDI_WALK_CONTINUE);
-	}
-
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "ranges",
-	    (caddr_t)&ranges,  &length) != DDI_PROP_SUCCESS) {
-		DEBUG0("Node doesn't have ranges\n");
-		goto ap;
-	}
-
-	rcount = length / sizeof (pcicfg_range_t);
-
-	for (i = 0; i < rcount; i++) {
-		uint64_t base;
-		uint64_t mid = ranges[i].child_mid;
-		uint64_t lo = ranges[i].child_lo;
-		uint64_t size = ranges[i].size_lo;
-
-		switch (PCI_REG_ADDR_G(ranges[i].child_hi)) {
-
-		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
-			base = entry_p->memory_base;
-			entry_p->memory_base = MAX(base, lo + size);
-			break;
-		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
-			base = entry_p->memory_base;
-			entry_p->memory_base = MAX(base,
-			    PCICFG_LADDR(lo, mid) + size);
-			break;
-		case PCI_REG_ADDR_G(PCI_ADDR_IO):
-			base = entry_p->io_base;
-			entry_p->io_base = MAX(base, lo + size);
-			break;
-		}
-	}
-
-	kmem_free(ranges, length);
-	return (DDI_WALK_CONTINUE);
-
-ap:	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "assigned-addresses",
-	    (caddr_t)&pci_ap,  &length) != DDI_PROP_SUCCESS) {
-		DEBUG0("Node doesn't have assigned-addresses\n");
-		return (DDI_WALK_CONTINUE);
-	}
-
-	rcount = length / sizeof (pci_regspec_t);
-
-	for (i = 0; i < rcount; i++) {
-
-		switch (PCI_REG_ADDR_G(pci_ap[i].pci_phys_hi)) {
-
-		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
-			if ((pci_ap[i].pci_phys_low +
-			    pci_ap[i].pci_size_low) >
-			    entry_p->memory_base) {
-				entry_p->memory_base =
-				    pci_ap[i].pci_phys_low +
-				    pci_ap[i].pci_size_low;
-			}
-		break;
-		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
-			if ((PCICFG_LADDR(pci_ap[i].pci_phys_low,
-			    pci_ap[i].pci_phys_mid) +
-			    pci_ap[i].pci_size_low) >
-			    entry_p->memory_base) {
-				entry_p->memory_base = PCICFG_LADDR(
-				    pci_ap[i].pci_phys_low,
-				    pci_ap[i].pci_phys_mid) +
-				    pci_ap[i].pci_size_low;
-			}
-		break;
-		case PCI_REG_ADDR_G(PCI_ADDR_IO):
-			if ((pci_ap[i].pci_phys_low +
-			    pci_ap[i].pci_size_low) >
-			    entry_p->io_base) {
-				entry_p->io_base =
-				    pci_ap[i].pci_phys_low +
-				    pci_ap[i].pci_size_low;
-			}
-		break;
-		}
-	}
-
-	/*
-	 * free the memory allocated by ddi_getlongprop
-	 */
-	kmem_free(pci_ap, length);
-
-	/*
-	 * continue the walk to the next sibling to sum memory
-	 */
-	return (DDI_WALK_CONTINUE);
-}
-
-static int
-pcicfg_free_bridge_resources(dev_info_t *dip)
-{
-	pcicfg_range_t		*ranges;
-	uint_t			*bus;
-	int			k;
-	int			length;
-	int			i;
-
-
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges,
-	    &length) != DDI_PROP_SUCCESS) {
-		DEBUG0("Failed to read ranges property\n");
-		if (ddi_get_child(dip)) {
-			cmn_err(CE_WARN, "No ranges property found for %s",
-			    ddi_get_name(dip));
-			/*
-			 * strictly speaking, we can check for children with
-			 * assigned-addresses but for now it is better to
-			 * be conservative and assume that if there are child
-			 * nodes, then they do consume PCI memory or IO
-			 * resources, Hence return failure.
-			 */
-			return (PCICFG_FAILURE);
-		}
-		length = 0;
-
-	}
-
-	for (i = 0; i < length / sizeof (pcicfg_range_t); i++) {
-		if (ranges[i].size_lo != 0 ||
-		    ranges[i].size_hi != 0) {
-			switch (ranges[i].parent_hi & PCI_REG_ADDR_M) {
-				case PCI_ADDR_IO:
-					DEBUG2("Free I/O    "
-					    "base/length = [0x%x]/[0x%x]\n",
-					    ranges[i].child_lo,
-					    ranges[i].size_lo);
-					if (ndi_ra_free(ddi_get_parent(dip),
-					    (uint64_t)ranges[i].child_lo,
-					    (uint64_t)ranges[i].size_lo,
-					    NDI_RA_TYPE_IO, NDI_RA_PASS)
-					    != NDI_SUCCESS) {
-						DEBUG0("Trouble freeing "
-						    "PCI i/o space\n");
-						kmem_free(ranges, length);
-						return (PCICFG_FAILURE);
-					}
-				break;
-				case PCI_ADDR_MEM32:
-				case PCI_ADDR_MEM64:
-					DEBUG3("Free Memory base/length = "
-					    "[0x%x.%x]/[0x%x]\n",
-					    ranges[i].child_mid,
-					    ranges[i].child_lo,
-					    ranges[i].size_lo)
-					if (ndi_ra_free(ddi_get_parent(dip),
-					    PCICFG_LADDR(ranges[i].child_lo,
-					    ranges[i].child_mid),
-					    (uint64_t)ranges[i].size_lo,
-					    NDI_RA_TYPE_MEM, NDI_RA_PASS)
-					    != NDI_SUCCESS) {
-						DEBUG0("Trouble freeing "
-						    "PCI memory space\n");
-						kmem_free(ranges, length);
-						return (PCICFG_FAILURE);
-					}
-				break;
-				default:
-					DEBUG0("Unknown memory space\n");
-				break;
-			}
-		}
-	}
-
-	if (length)
-		kmem_free(ranges, length);
-
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
-	    &k) != DDI_PROP_SUCCESS) {
-		DEBUG0("Failed to read bus-range property\n");
-		return (PCICFG_FAILURE);
-	}
-
-	DEBUG2("Need to free bus [%d] range [%d]\n",
-	    bus[0], bus[1] - bus[0] + 1);
-
-	if (ndi_ra_free(ddi_get_parent(dip),
-	    (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
-	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
-		/*EMPTY*/
-		DEBUG0("Failed to free a bus number\n");
-	}
-	/*
-	 * Don't forget to free up memory from ddi_getlongprop
-	 */
-	kmem_free((caddr_t)bus, k);
-
-	return (PCICFG_SUCCESS);
-}
-
-static int
-pcicfg_free_device_resources(dev_info_t *dip)
-{
-	pci_regspec_t *assigned;
-
-	int length;
-	int acount;
-	int i;
-
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
-	    &length) != DDI_PROP_SUCCESS) {
-		DEBUG0("Failed to read assigned-addresses property\n");
-		return (PCICFG_FAILURE);
-	}
-
-	/*
-	 * For each "assigned-addresses" property entry with a length,
-	 * call the memory allocation routines to return the
-	 * resource.
-	 */
-	acount = length / sizeof (pci_regspec_t);
-	for (i = 0; i < acount; i++) {
-		/*
-		 * Workaround for Devconf (x86) bug to skip extra entries
-		 * beyond the PCI_CONF_BASE5 offset. But we want to free up
-		 * any memory for expansion roms if allocated.
-		 */
-		if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) > PCI_CONF_BASE5) &&
-		    (PCI_REG_REG_G(assigned[i].pci_phys_hi) != PCI_CONF_ROM))
-			break;
-
-		if (pcicfg_free_resource(dip, assigned[i])) {
-			DEBUG1("pcicfg_free_device_resources - Trouble freeing "
-			    "%x\n", assigned[i].pci_phys_hi);
-			/*
-			 * Don't forget to free up memory from ddi_getlongprop
-			 */
-			kmem_free((caddr_t)assigned, length);
-
-			return (PCICFG_FAILURE);
-		}
-	}
-	kmem_free(assigned, length);
-	return (PCICFG_SUCCESS);
-}
-
-static int
-pcicfg_free_resources(dev_info_t *dip)
-{
-	ddi_acc_handle_t handle;
-	uint8_t header_type;
-
-	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
-		DEBUG0("Failed to map config space!\n");
-		return (PCICFG_FAILURE);
-	}
-
-	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
-
-	(void) pci_config_teardown(&handle);
-
-	/*
-	 * A different algorithm is used for bridges and leaf devices.
-	 */
-	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
-		if (pcicfg_free_bridge_resources(dip) != PCICFG_SUCCESS) {
-			DEBUG0("Failed freeing up bridge resources\n");
-			return (PCICFG_FAILURE);
-		}
-	} else {
-		if (pcicfg_free_device_resources(dip) != PCICFG_SUCCESS) {
-			DEBUG0("Failed freeing up device resources\n");
-			return (PCICFG_FAILURE);
-		}
-	}
-	return (PCICFG_SUCCESS);
-}
-
-#ifndef _DONT_USE_1275_GENERIC_NAMES
-static char *
-pcicfg_get_class_name(uint32_t classcode)
-{
-	struct pcicfg_name_entry *ptr;
-
-	for (ptr = &pcicfg_class_lookup[0]; ptr->name != NULL; ptr++) {
-		if (ptr->class_code == classcode) {
-			return (ptr->name);
-		}
-	}
-	return (NULL);
-}
-#endif /* _DONT_USE_1275_GENERIC_NAMES */
-
-static dev_info_t *
-pcicfg_devi_find(dev_info_t *dip, uint_t device, uint_t function)
-{
-	struct pcicfg_find_ctrl ctrl;
-	int count;
-
-	ctrl.device = device;
-	ctrl.function = function;
-	ctrl.dip = NULL;
-
-	ndi_devi_enter(dip, &count);
-	ddi_walk_devs(ddi_get_child(dip), pcicfg_match_dev, (void *)&ctrl);
-	ndi_devi_exit(dip, count);
-
-	return (ctrl.dip);
-}
-
-static int
-pcicfg_match_dev(dev_info_t *dip, void *hdl)
-{
-	struct pcicfg_find_ctrl *ctrl = (struct pcicfg_find_ctrl *)hdl;
-	pci_regspec_t *pci_rp;
-	int length;
-	int pci_dev;
-	int pci_func;
-
-	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
-	    (uint_t *)&length) != DDI_PROP_SUCCESS) {
-		ctrl->dip = NULL;
-		return (DDI_WALK_TERMINATE);
-	}
-
-	/* get the PCI device address info */
-	pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
-	pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
-
-	/*
-	 * free the memory allocated by ddi_prop_lookup_int_array
-	 */
-	ddi_prop_free(pci_rp);
-
-
-	if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
-		/* found the match for the specified device address */
-		ctrl->dip = dip;
-		return (DDI_WALK_TERMINATE);
-	}
-
-	/*
-	 * continue the walk to the next sibling to look for a match.
-	 */
-	return (DDI_WALK_PRUNECHILD);
-}
-
-static int
-pcicfg_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone)
-{
-	int		alen;
-	pci_regspec_t	*assigned;
-	caddr_t		newreg;
-	uint_t		status;
-
-	DEBUG0("pcicfg_update_assigned_prop()\n");
-	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
-	    "assigned-addresses", (caddr_t)&assigned, &alen);
-	switch (status) {
-		case DDI_PROP_SUCCESS:
-		break;
-		case DDI_PROP_NO_MEMORY:
-			DEBUG0("no memory for assigned-addresses property\n");
-			return (PCICFG_FAILURE);
-		default:
-			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
-			    "assigned-addresses", (int *)newone,
-			    sizeof (*newone)/sizeof (int));
-
-			(void) pcicfg_dump_assigned(dip);
-
-			return (PCICFG_SUCCESS);
-	}
-
-	/*
-	 * Allocate memory for the existing
-	 * assigned-addresses(s) plus one and then
-	 * build it.
-	 */
-
-	newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
-
-	bcopy(assigned, newreg, alen);
-	bcopy(newone, newreg + alen, sizeof (*newone));
-
-	/*
-	 * Write out the new "assigned-addresses" spec
-	 */
-	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
-	    "assigned-addresses", (int *)newreg,
-	    (alen + sizeof (*newone))/sizeof (int));
-
-	kmem_free((caddr_t)newreg, alen+sizeof (*newone));
-
-	/*
-	 * Don't forget to free up memory from ddi_getlongprop
-	 */
-	kmem_free((caddr_t)assigned, alen);
-
-	(void) pcicfg_dump_assigned(dip);
-
-	return (PCICFG_SUCCESS);
-}
-static int
-pcicfg_update_ranges_prop(dev_info_t *dip, pcicfg_range_t *addition)
-{
-	int		rlen;
-	pcicfg_range_t	*ranges;
-	caddr_t		newreg;
-	uint_t		status;
-
-	status = ddi_getlongprop(DDI_DEV_T_ANY,
-	    dip, DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges, &rlen);
-
-
-	switch (status) {
-		case DDI_PROP_SUCCESS:
-		break;
-		case DDI_PROP_NO_MEMORY:
-			DEBUG0("ranges present, but unable to get memory\n");
-			return (PCICFG_FAILURE);
-		default:
-			DEBUG0("no ranges property - creating one\n");
-			if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
-			    dip, "ranges", (int *)addition,
-			    sizeof (pcicfg_range_t)/sizeof (int))
-			    != DDI_SUCCESS) {
-				DEBUG0("Did'nt create ranges property\n");
-				return (PCICFG_FAILURE);
-			}
-			return (PCICFG_SUCCESS);
-	}
-
-	/*
-	 * Allocate memory for the existing reg(s) plus one and then
-	 * build it.
-	 */
-	newreg = kmem_zalloc(rlen+sizeof (pcicfg_range_t), KM_SLEEP);
-
-	bcopy(ranges, newreg, rlen);
-	bcopy(addition, newreg + rlen, sizeof (pcicfg_range_t));
-
-	/*
-	 * Write out the new "ranges" property
-	 */
-	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
-	    dip, "ranges", (int *)newreg,
-	    (rlen + sizeof (pcicfg_range_t))/sizeof (int));
-
-	kmem_free((caddr_t)newreg, rlen+sizeof (pcicfg_range_t));
-
-	kmem_free((caddr_t)ranges, rlen);
-
-	return (PCICFG_SUCCESS);
-}
-
-static int
-pcicfg_update_reg_prop(dev_info_t *dip, uint32_t regvalue, uint_t reg_offset)
-{
-	int		rlen;
-	pci_regspec_t	*reg;
-	caddr_t		newreg;
-	uint32_t	hiword;
-	pci_regspec_t	addition;
-	uint32_t	size;
-	uint_t		status;
-
-	status = ddi_getlongprop(DDI_DEV_T_ANY,
-	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
-
-	switch (status) {
-		case DDI_PROP_SUCCESS:
-		break;
-		case DDI_PROP_NO_MEMORY:
-			DEBUG0("reg present, but unable to get memory\n");
-			return (PCICFG_FAILURE);
-		default:
-			DEBUG0("no reg property\n");
-			return (PCICFG_FAILURE);
-	}
-
-	/*
-	 * Allocate memory for the existing reg(s) plus one and then
-	 * build it.
-	 */
-	newreg = kmem_zalloc(rlen+sizeof (pci_regspec_t), KM_SLEEP);
-
-	/*
-	 * Build the regspec, then add it to the existing one(s)
-	 */
-
-	hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
-	    PCI_REG_DEV_G(reg->pci_phys_hi),
-	    PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
-
-	if (reg_offset == PCI_CONF_ROM) {
-		size = (~(PCI_BASE_ROM_ADDR_M & regvalue))+1;
-		hiword |= PCI_ADDR_MEM32;
-	} else {
-		size = (~(PCI_BASE_M_ADDR_M & regvalue))+1;
-
-		if ((PCI_BASE_SPACE_M & regvalue) == PCI_BASE_SPACE_MEM) {
-			if ((PCI_BASE_TYPE_M & regvalue) == PCI_BASE_TYPE_MEM) {
-				hiword |= PCI_ADDR_MEM32;
-			} else if ((PCI_BASE_TYPE_M & regvalue)
-			    == PCI_BASE_TYPE_ALL) {
-				hiword |= PCI_ADDR_MEM64;
-			}
-		} else {
-			hiword |= PCI_ADDR_IO;
-		}
-	}
-
-	addition.pci_phys_hi = hiword;
-	addition.pci_phys_mid = 0;
-	addition.pci_phys_low = 0;
-	addition.pci_size_hi = 0;
-	addition.pci_size_low = size;
-
-	bcopy(reg, newreg, rlen);
-	bcopy(&addition, newreg + rlen, sizeof (pci_regspec_t));
-
-	/*
-	 * Write out the new "reg" property
-	 */
-	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
-	    dip, "reg", (int *)newreg,
-	    (rlen + sizeof (pci_regspec_t))/sizeof (int));
-
-	kmem_free((caddr_t)newreg, rlen+sizeof (pci_regspec_t));
-	kmem_free((caddr_t)reg, rlen);
-
-	return (PCICFG_SUCCESS);
-}
-static int
-pcicfg_update_available_prop(dev_info_t *dip, pci_regspec_t *newone)
-{
-	int		alen;
-	pci_regspec_t	*avail_p;
-	caddr_t		new_avail;
-	uint_t		status;
-
-	DEBUG2("pcicfg_update_available_prop() - Address %lx Size %x\n",
-	    newone->pci_phys_low, newone->pci_size_low);
-	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
-	    "available", (caddr_t)&avail_p, &alen);
-	switch (status) {
-		case DDI_PROP_SUCCESS:
-			break;
-		case DDI_PROP_NO_MEMORY:
-			DEBUG0("no memory for available property\n");
-			return (PCICFG_FAILURE);
-		default:
-			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
-			    "available", (int *)newone,
-			    sizeof (*newone)/sizeof (int));
-
-			return (PCICFG_SUCCESS);
-	}
-
-	/*
-	 * Allocate memory for the existing available plus one and then
-	 * build it.
-	 */
-	new_avail = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
-
-	bcopy(avail_p, new_avail, alen);
-	bcopy(newone, new_avail + alen, sizeof (*newone));
-
-	/* Write out the new "available" spec */
-	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
-	    "available", (int *)new_avail,
-	    (alen + sizeof (*newone))/sizeof (int));
-
-	kmem_free((caddr_t)new_avail, alen+sizeof (*newone));
-
-	/* Don't forget to free up memory from ddi_getlongprop */
-	kmem_free((caddr_t)avail_p, alen);
-
-	return (PCICFG_SUCCESS);
-}
-
-static void
-pcicfg_device_on(ddi_acc_handle_t config_handle)
-{
-	/*
-	 * Enable memory, IO, and bus mastership
-	 * XXX should we enable parity, SERR#,
-	 * fast back-to-back, and addr. stepping?
-	 */
-	pci_config_put16(config_handle, PCI_CONF_COMM,
-	    pci_config_get16(config_handle, PCI_CONF_COMM) | 0x7);
-}
-
-static void
-pcicfg_device_off(ddi_acc_handle_t config_handle)
-{
-	/*
-	 * Disable I/O and memory traffic through the bridge
-	 */
-	pci_config_put16(config_handle, PCI_CONF_COMM, 0x0);
-}
-
-/*
- * Setup the basic 1275 properties based on information found in the config
- * header of the PCI device
- */
-static int
-pcicfg_set_standard_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
-	uint8_t pcie_dev)
-{
-	int ret;
-	uint16_t val, cap_ptr;
-	uint32_t wordval;
-	uint8_t byteval;
-
-	/* These two exists only for non-bridges */
-	if (((pci_config_get8(config_handle, PCI_CONF_HEADER)
-	    & PCI_HEADER_TYPE_M) == PCI_HEADER_ZERO) && !pcie_dev) {
-		byteval = pci_config_get8(config_handle, PCI_CONF_MIN_G);
-		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-		    "min-grant", byteval)) != DDI_SUCCESS) {
-			return (ret);
-		}
-
-		byteval = pci_config_get8(config_handle, PCI_CONF_MAX_L);
-		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-		    "max-latency", byteval)) != DDI_SUCCESS) {
-			return (ret);
-		}
-	}
-
-	/*
-	 * These should always exist and have the value of the
-	 * corresponding register value
-	 */
-	val = pci_config_get16(config_handle, PCI_CONF_VENID);
-
-	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-	    "vendor-id", val)) != DDI_SUCCESS) {
-		return (ret);
-	}
-	val = pci_config_get16(config_handle, PCI_CONF_DEVID);
-	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-	    "device-id", val)) != DDI_SUCCESS) {
-		return (ret);
-	}
-	byteval = pci_config_get8(config_handle, PCI_CONF_REVID);
-	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-	    "revision-id", byteval)) != DDI_SUCCESS) {
-		return (ret);
-	}
-
-	wordval = (pci_config_get16(config_handle, PCI_CONF_SUBCLASS)<< 8) |
-	    (pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
-
-	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-	    "class-code", wordval)) != DDI_SUCCESS) {
-		return (ret);
-	}
-	/* devsel-speed starts at the 9th bit */
-	val = (pci_config_get16(config_handle,
-	    PCI_CONF_STAT) & PCI_STAT_DEVSELT) >> 9;
-	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-	    "devsel-speed", val)) != DDI_SUCCESS) {
-		return (ret);
-	}
-
-	/*
-	 * The next three are bits set in the status register.  The property is
-	 * present (but with no value other than its own existence) if the bit
-	 * is set, non-existent otherwise
-	 */
-	if ((!pcie_dev) &&
-	    (pci_config_get16(config_handle, PCI_CONF_STAT) &
-	    PCI_STAT_FBBC)) {
-		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-		    "fast-back-to-back", 0)) != DDI_SUCCESS) {
-			return (ret);
-		}
-	}
-	if ((!pcie_dev) &&
-	    (pci_config_get16(config_handle, PCI_CONF_STAT) &
-	    PCI_STAT_66MHZ)) {
-		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-		    "66mhz-capable", 0)) != DDI_SUCCESS) {
-			return (ret);
-		}
-	}
-	if (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_UDF) {
-		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-		    "udf-supported", 0)) != DDI_SUCCESS) {
-			return (ret);
-		}
-	}
-
-	/*
-	 * These next three are optional and are not present
-	 * if the corresponding register is zero.  If the value
-	 * is non-zero then the property exists with the value
-	 * of the register.
-	 */
-	if ((val = pci_config_get16(config_handle,
-	    PCI_CONF_SUBVENID)) != 0) {
-		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-		    "subsystem-vendor-id", val)) != DDI_SUCCESS) {
-			return (ret);
-		}
-	}
-	if ((val = pci_config_get16(config_handle,
-	    PCI_CONF_SUBSYSID)) != 0) {
-		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-		    "subsystem-id", val)) != DDI_SUCCESS) {
-			return (ret);
-		}
-	}
-	if ((val = pci_config_get16(config_handle,
-	    PCI_CONF_CACHE_LINESZ)) != 0) {
-		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-		    "cache-line-size", val)) != DDI_SUCCESS) {
-			return (ret);
-		}
-	}
-
-	/*
-	 * If the Interrupt Pin register is non-zero then the
-	 * interrupts property exists
-	 */
-	if ((byteval = pci_config_get8(config_handle, PCI_CONF_IPIN)) != 0) {
-		/*
-		 * If interrupt pin is non-zero,
-		 * record the interrupt line used
-		 */
-		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-		    "interrupts", byteval)) != DDI_SUCCESS) {
-			return (ret);
-		}
-	}
-
-	ret = PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr);
-
-	if (pcie_dev && (ret == DDI_SUCCESS)) {
-		val = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
-		    PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL;
-		/* if slot implemented, get physical slot number */
-		if (val) {
-			wordval = (PCI_CAP_GET32(config_handle, NULL,
-			    cap_ptr, PCIE_SLOTCAP) >>
-			    PCIE_SLOTCAP_PHY_SLOT_NUM_SHIFT) &
-			    PCIE_SLOTCAP_PHY_SLOT_NUM_MASK;
-			if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE,
-			    dip, "physical-slot#", wordval))
-			    != DDI_SUCCESS) {
-				return (ret);
-			}
-		}
-	}
-	return (PCICFG_SUCCESS);
-}
-static int
-pcicfg_set_busnode_props(dev_info_t *dip, uint8_t pcie_device_type,
-    int pbus, int sbus)
-{
-	int ret;
-	char device_type[8];
-
-	if (pcie_device_type)
-		(void) strcpy(device_type, "pciex");
-	else
-		(void) strcpy(device_type, "pci");
-
-	if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
-	    "device_type", device_type)) != DDI_SUCCESS) {
-		return (ret);
-	}
-	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-	    "#address-cells", 3)) != DDI_SUCCESS) {
-		return (ret);
-	}
-	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-	    "#size-cells", 2)) != DDI_SUCCESS) {
-		return (ret);
-	}
-
-	/*
-	 * Create primary-bus and secondary-bus properties to be used
-	 * to restore bus numbers in the pcicfg_setup_bridge() routine.
-	 */
-	if (pbus != -1 && sbus != -1) {
-		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-		    "primary-bus", pbus)) != DDI_SUCCESS) {
-				return (ret);
-		}
-		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
-		    "secondary-bus", sbus)) != DDI_SUCCESS) {
-				return (ret);
-		}
-	}
-	return (PCICFG_SUCCESS);
-}
-
-static int
-pcicfg_set_childnode_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
-	uint8_t pcie_dev)
-{
-
-	int		ret;
-	char		*name;
-	char		buffer[64], pprefix[8];
-	uint16_t	classcode;
-	uint8_t		revid, pif, pclass, psubclass;
-	char		*compat[24];
-	int		i;
-	int		n;
-	uint16_t		sub_vid, sub_sid, vid, did;
-
-	/* set the property prefix based on the device type */
-	if (pcie_dev)
-		(void) sprintf(pprefix, "pciex");
-	else
-		(void) sprintf(pprefix, "pci");
-	sub_vid = pci_config_get16(config_handle, PCI_CONF_SUBVENID);
-	sub_sid = pci_config_get16(config_handle, PCI_CONF_SUBSYSID);
-	vid = pci_config_get16(config_handle, PCI_CONF_VENID);
-	did = pci_config_get16(config_handle, PCI_CONF_DEVID);
-	revid = pci_config_get8(config_handle, PCI_CONF_REVID);
-	pif = pci_config_get8(config_handle, PCI_CONF_PROGCLASS);
-	classcode = pci_config_get16(config_handle, PCI_CONF_SUBCLASS);
-	pclass = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
-	psubclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
-
-	/*
-	 * NOTE: These are for both a child and PCI-PCI bridge node
-	 */
-
-	/*
-	 *	"name" property rule
-	 *	--------------------
-	 *
-	 *
-	 * |	  \svid |
-	 * |	   \    |
-	 * |	    \   |
-	 * |	ssid \  |	=0		|	!= 0		|
-	 * |------------|-----------------------|-----------------------|
-	 * |		|			|			|
-	 * |	=0	|	vid,did		|	svid,ssid	|
-	 * |		|			|			|
-	 * |------------|-----------------------|-----------------------|
-	 * |		|			|			|
-	 * |	!=0	|	svid,ssid	|	svid,ssid	|
-	 * |		|			|			|
-	 * |------------|-----------------------|-----------------------|
-	 *
-	 * where:
-	 *    vid = vendor id
-	 *    did = device id
-	 *   svid = subsystem vendor id
-	 *   ssid = subsystem id
-	 */
-
-	if ((sub_sid != 0) || (sub_vid != 0)) {
-		(void) sprintf(buffer, "%s%x,%x", pprefix, sub_vid, sub_sid);
-	} else {
-		(void) sprintf(buffer, "%s%x,%x", pprefix, vid, did);
-	}
-
-	/*
-	 * In some environments, trying to use "generic" 1275 names is
-	 * not the convention.  In those cases use the name as created
-	 * above.  In all the rest of the cases, check to see if there
-	 * is a generic name first.
-	 */
-#ifdef _DONT_USE_1275_GENERIC_NAMES
-	name = buffer;
-#else
-	if ((name = pcicfg_get_class_name(classcode)) == NULL) {
-		/*
-		 * Set name to the above fabricated name
-		 */
-		name = buffer;
-	}
-#endif
-
-	/*
-	 * The node name field needs to be filled in with the name
-	 */
-	if (ndi_devi_set_nodename(dip, name, 0) != NDI_SUCCESS) {
-		DEBUG0("Failed to set nodename for node\n");
-		return (PCICFG_FAILURE);
-	}
-
-	/*
-	 * Create the compatible property as an array of pointers
-	 * to strings.  Start with the buffer created above.
-	 */
-	n = 0;
-	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
-	(void) strcpy(compat[n++], buffer);
-
-	/*
-	 * Setup 'compatible' as per the PCI2.1 bindings document.
-	 *	pci[ex]VVVV,DDDD.SSSS.ssss.RR
-	 *	pci[ex]VVVV,DDDD.SSSS.ssss
-	 *	pciSSSS.ssss  -> not created for PCIe as per PCIe bindings
-	 *	pci[ex]VVVV,DDDD.RR
-	 *	pci[ex]VVVV,DDDD
-	 *	pci[ex]class,CCSSPP
-	 *	pci[ex]class,CCSS
-	 */
-
-	/* pci[ex]VVVV,DDDD.SSSS.ssss.RR */
-	(void) sprintf(buffer, "%s%x,%x.%x.%x.%x", pprefix,  vid, did,
-	    sub_vid, sub_sid, revid);
-	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
-	(void) strcpy(compat[n++], buffer);
-
-	/* pci[ex]VVVV,DDDD.SSSS.ssss */
-	(void) sprintf(buffer, "%s%x,%x.%x.%x", pprefix,  vid, did,
-	    sub_vid, sub_sid);
-	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
-	(void) strcpy(compat[n++], buffer);
-
-	/* pciSSSS.ssss  -> not created for PCIe as per PCIe bindings */
-	if (!pcie_dev) {
-		(void) sprintf(buffer, "pci%x,%x", sub_vid, sub_sid);
-		compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
-		(void) strcpy(compat[n++], buffer);
-	}
-
-	/* pci[ex]VVVV,DDDD.RR */
-	(void) sprintf(buffer, "%s%x,%x.%x", pprefix,  vid, did, revid);
-	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
-	(void) strcpy(compat[n++], buffer);
-
-	/* pci[ex]VVVV,DDDD */
-	(void) sprintf(buffer, "%s%x,%x", pprefix, vid, did);
-	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
-	(void) strcpy(compat[n++], buffer);
-
-	/* pci[ex]class,CCSSPP */
-	(void) sprintf(buffer, "%sclass,%02x%02x%02x", pprefix,
-	    pclass, psubclass, pif);
-	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
-	(void) strcpy(compat[n++], buffer);
-
-	/* pci[ex]class,CCSS */
-	(void) sprintf(buffer, "%sclass,%04x", pprefix, classcode);
-	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
-	(void) strcpy(compat[n++], buffer);
-
-	if ((ret = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
-	    "compatible", (char **)compat, n)) != DDI_SUCCESS) {
-		return (ret);
-	}
-
-	for (i = 0; i < n; i++) {
-		kmem_free(compat[i], strlen(compat[i]) + 1);
-	}
-
-	DEBUG1("pcicfg_set_childnode_props - creating name=%s\n", name);
-	if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
-	    "name", name)) != DDI_SUCCESS) {
-
-		DEBUG0("pcicfg_set_childnode_props - Unable to create name "
-		    "property\n");
-
-		return (ret);
-	}
-
-	return (PCICFG_SUCCESS);
-}
-
-/*
- * Program the bus numbers into the bridge
- */
-
-static void
-pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle,
-uint_t primary, uint_t secondary, uint_t subordinate)
-{
-	DEBUG3("Setting bridge bus-range %d,%d,%d\n", primary, secondary,
-	    subordinate);
-	/*
-	 * Primary bus#
-	 */
-	pci_config_put8(config_handle, PCI_BCNF_PRIBUS, primary);
-
-	/*
-	 * Secondary bus#
-	 */
-	pci_config_put8(config_handle, PCI_BCNF_SECBUS, secondary);
-
-	/*
-	 * Subordinate bus#
-	 */
-	pci_config_put8(config_handle, PCI_BCNF_SUBBUS, subordinate);
-}
-
-/*
- * Put bridge registers into initial state
- */
-static void
-pcicfg_setup_bridge(pcicfg_phdl_t *entry,
-    ddi_acc_handle_t handle, dev_info_t *dip)
-{
-	int pbus, sbus;
-
-	/*
-	 * The highest bus seen during probing is the max-subordinate bus
-	 */
-	pci_config_put8(handle, PCI_BCNF_SUBBUS, entry->highest_bus);
-
-
-	/*
-	 * If there exists more than 1 downstream bridge, it
-	 * will be reset by the below secondary bus reset which
-	 * will clear the bus numbers assumed to be programmed in
-	 * the pcicfg_probe_children() routine.  We therefore restore
-	 * them here.
-	 */
-	if (pci_config_get8(handle, PCI_BCNF_SECBUS) == 0) {
-		pbus = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
-		    DDI_PROP_DONTPASS, "primary-bus", -1);
-		sbus = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
-		    DDI_PROP_DONTPASS, "secondary-bus", -1);
-		if (pbus != -1 && sbus != -1) {
-			pci_config_put8(handle, PCI_BCNF_PRIBUS, (uint_t)pbus);
-			pci_config_put8(handle, PCI_BCNF_SECBUS, (uint_t)sbus);
-		} else {
-			cmn_err(CE_WARN, "Invalid Bridge number detected: \
-			    %s%d: pbus = 0x%x, sbus = 0x%x",
-			    ddi_get_name(dip), ddi_get_instance(dip), pbus,
-			    sbus);
-		}
-	}
-
-	/*
-	 * Reset the secondary bus
-	 */
-	pci_config_put16(handle, PCI_BCNF_BCNTRL,
-	    pci_config_get16(handle, PCI_BCNF_BCNTRL) | 0x40);
-
-	drv_usecwait(100);
-
-	pci_config_put16(handle, PCI_BCNF_BCNTRL,
-	    pci_config_get16(handle, PCI_BCNF_BCNTRL) & ~0x40);
-
-	/*
-	 * Program the memory base register with the
-	 * start of the memory range
-	 */
-	pci_config_put16(handle, PCI_BCNF_MEM_BASE,
-	    PCICFG_HIWORD(PCICFG_LOADDR(entry->memory_last)));
-
-	/*
-	 * Program the I/O base register with the start of the I/O range
-	 */
-	pci_config_put8(handle, PCI_BCNF_IO_BASE_LOW,
-	    PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(entry->io_last))));
-	pci_config_put16(handle, PCI_BCNF_IO_BASE_HI,
-	    PCICFG_HIWORD(PCICFG_LOADDR(entry->io_last)));
-
-	/*
-	 * Clear status bits
-	 */
-	pci_config_put16(handle, PCI_BCNF_SEC_STATUS, 0xffff);
-
-	/*
-	 * Turn off prefetchable range
-	 */
-	pci_config_put32(handle, PCI_BCNF_PF_BASE_LOW, 0x0000ffff);
-	pci_config_put32(handle, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
-	pci_config_put32(handle, PCI_BCNF_PF_LIMIT_HIGH, 0x0);
-
-	/*
-	 * Needs to be set to this value
-	 */
-	pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
-
-	/*
-	 * After a Reset, we need to wait 2^25 clock cycles before the
-	 * first Configuration access.  The worst case is 33MHz, which
-	 * is a 1 second wait.
-	 */
-	drv_usecwait(pcicfg_sec_reset_delay);
-
-}
-
-static void
-pcicfg_update_bridge(pcicfg_phdl_t *entry,
-	ddi_acc_handle_t handle)
-{
-	uint_t length;
-
-	/*
-	 * Program the memory limit register with the end of the memory range
-	 */
-
-	DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
-	    PCICFG_ROUND_DOWN(entry->memory_last,
-	    PCICFG_MEMGRAN));
-
-	pci_config_put16(handle, PCI_BCNF_MEM_LIMIT,
-	    PCICFG_HIWORD(PCICFG_LOADDR(
-	    PCICFG_ROUND_DOWN(entry->memory_last,
-	    PCICFG_MEMGRAN))));
-	/*
-	 * Since this is a bridge, the rest of this range will
-	 * be responded to by the bridge.  We have to round up
-	 * so no other device claims it.
-	 */
-	if ((length = (PCICFG_ROUND_UP(entry->memory_last,
-	    PCICFG_MEMGRAN) - entry->memory_last)) > 0) {
-		(void) pcicfg_get_mem(entry, length, NULL);
-		DEBUG1("Added [0x%x]at the top of "
-		    "the bridge (mem)\n", length);
-	}
-
-	/*
-	 * Program the I/O limit register with the end of the I/O range
-	 */
-	pci_config_put8(handle, PCI_BCNF_IO_LIMIT_LOW,
-	    PCICFG_HIBYTE(PCICFG_LOWORD(
-	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last,
-	    PCICFG_IOGRAN)))));
-
-	pci_config_put16(handle, PCI_BCNF_IO_LIMIT_HI,
-	    PCICFG_HIWORD(PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last,
-	    PCICFG_IOGRAN))));
-
-	/*
-	 * Same as above for I/O space. Since this is a
-	 * bridge, the rest of this range will be responded
-	 * to by the bridge.  We have to round up so no
-	 * other device claims it.
-	 */
-	if ((length = (PCICFG_ROUND_UP(entry->io_last,
-	    PCICFG_IOGRAN) - entry->io_last)) > 0) {
-		(void) pcicfg_get_io(entry, length, NULL);
-		DEBUG1("Added [0x%x]at the top of "
-		    "the bridge (I/O)\n",  length);
-	}
-}
-
-/*ARGSUSED*/
-static void
-pcicfg_disable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h,
-	pcicfg_err_regs_t *regs)
-{
-	uint16_t val;
-
-	/* disable SERR generated in the context of Master Aborts. */
-	regs->cmd = val = pci_config_get16(h, PCI_CONF_COMM);
-	val &= ~PCI_COMM_SERR_ENABLE;
-	pci_config_put16(h, PCI_CONF_COMM, val);
-	regs->bcntl = val = pci_config_get16(h, PCI_BCNF_BCNTRL);
-	val &= ~PCI_BCNF_BCNTRL_SERR_ENABLE;
-	pci_config_put16(h, PCI_BCNF_BCNTRL, val);
-	/* clear any current pending errors */
-	pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB|
-	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
-	pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB|
-	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
-	/* if we are a PCIe device, disable the generation of UR, CE and NFE */
-	if (regs->pcie_dev) {
-		uint16_t devctl;
-		uint16_t cap_ptr;
-
-		if ((PCI_CAP_LOCATE(h, PCI_CAP_ID_PCI_E, &cap_ptr)) ==
-		    DDI_FAILURE)
-			return;
-
-		regs->pcie_cap_off = cap_ptr;
-		regs->devctl = devctl = PCI_CAP_GET16(h, NULL, cap_ptr,
-		    PCIE_DEVCTL);
-		devctl &= ~(PCIE_DEVCTL_UR_REPORTING_EN |
-		    PCIE_DEVCTL_CE_REPORTING_EN |
-		    PCIE_DEVCTL_NFE_REPORTING_EN |
-		    PCIE_DEVCTL_FE_REPORTING_EN);
-		PCI_CAP_PUT16(h, NULL, cap_ptr, PCIE_DEVCTL, devctl);
-	}
-}
-
-/*ARGSUSED*/
-static void
-pcicfg_enable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h,
-	pcicfg_err_regs_t *regs)
-{
-	/* clear any pending errors */
-	pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB|
-	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
-	pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB|
-	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
-
-	/* restore original settings */
-	if (regs->pcie_dev) {
-		pcie_clear_errors(dip);
-		pci_config_put16(h, regs->pcie_cap_off + PCIE_DEVCTL,
-		    regs->devctl);
-	}
-
-	pci_config_put16(h, PCI_BCNF_BCNTRL, regs->bcntl);
-	pci_config_put16(h, PCI_CONF_COMM, regs->cmd);
-
-}
-
-static int
-pcicfg_probe_children(dev_info_t *parent, uint_t bus,
-	uint_t device, uint_t func, uint_t *highest_bus)
-{
-	dev_info_t		*new_child;
-	ddi_acc_handle_t	config_handle;
-	uint8_t			header_type, pcie_dev = 0;
-
-	int			i;
-	uint32_t		request;
-	int			ret;
-	pcicfg_err_regs_t	regs;
-	/*
-	 * This node will be put immediately below
-	 * "parent". Allocate a blank device node.  It will either
-	 * be filled in or freed up based on further probing.
-	 */
-	/*
-	 * Note: in usr/src/uts/common/io/hotplug/pcicfg/pcicfg.c
-	 * ndi_devi_alloc() is called as ndi_devi_alloc_sleep()
-	 */
-	if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME,
-	    (pnode_t)DEVI_SID_NODEID, &new_child)
-	    != NDI_SUCCESS) {
-		DEBUG0("pcicfg_probe_children(): Failed to alloc child node\n");
-		return (PCICFG_FAILURE);
-	}
-
-	if (pcicfg_add_config_reg(new_child, bus,
-	    device, func) != DDI_SUCCESS) {
-		DEBUG0("pcicfg_probe_children():"
-		    "Failed to add candidate REG\n");
-		goto failedconfig;
-	}
-
-	if ((ret = pcicfg_config_setup(new_child, &config_handle))
-	    != PCICFG_SUCCESS) {
-		if (ret == PCICFG_NODEVICE) {
-			(void) ndi_devi_free(new_child);
-			return (ret);
-		}
-		DEBUG0("pcicfg_probe_children():"
-		    "Failed to setup config space\n");
-		goto failedconfig;
-	}
-
-	/*
-	 * As soon as we have access to config space,
-	 * turn off device. It will get turned on
-	 * later (after memory is assigned).
-	 */
-	(void) pcicfg_device_off(config_handle);
-
-	/* check if we are PCIe device */
-	if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, &regs)
-	    == DDI_SUCCESS) {
-		DEBUG0("PCIe device detected\n");
-		pcie_dev = 1;
-	}
-
-	/*
-	 * Set 1275 properties common to all devices
-	 */
-	if (pcicfg_set_standard_props(new_child, config_handle,
-	    pcie_dev) != PCICFG_SUCCESS) {
-		DEBUG0("Failed to set standard properties\n");
-		goto failedchild;
-	}
-
-	/*
-	 * Child node properties  NOTE: Both for PCI-PCI bridge and child node
-	 */
-	if (pcicfg_set_childnode_props(new_child, config_handle,
-	    pcie_dev) != PCICFG_SUCCESS) {
-		goto failedchild;
-	}
-
-	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
-
-	/*
-	 * If this is not a multi-function card only probe function zero.
-	 */
-	if ((!(header_type & PCI_HEADER_MULTI)) && (func != 0)) {
-
-		(void) pcicfg_config_teardown(&config_handle);
-		(void) ndi_devi_free(new_child);
-		return (PCICFG_NODEVICE);
-	}
-
-	DEBUG1("---Vendor ID = [0x%x]\n",
-	    pci_config_get16(config_handle, PCI_CONF_VENID));
-	DEBUG1("---Device ID = [0x%x]\n",
-	    pci_config_get16(config_handle, PCI_CONF_DEVID));
-
-	/*
-	 * Attach the child to its parent
-	 */
-	(void) i_ndi_config_node(new_child, DS_LINKED, 0);
-
-	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
-
-		DEBUG3("--Bridge found bus [0x%x] device"
-		    "[0x%x] func [0x%x]\n", bus, device, func);
-
-		if (pcicfg_probe_bridge(new_child, config_handle,
-		    bus, highest_bus) != PCICFG_SUCCESS) {
-			(void) pcicfg_free_bridge_resources(new_child);
-			goto failedchild;
-		}
-
-	} else {
-
-		DEBUG3("--Leaf device found bus [0x%x] device"
-		    "[0x%x] func [0x%x]\n",
-		    bus, device, func);
-
-		i = PCI_CONF_BASE0;
-
-		while (i <= PCI_CONF_BASE5) {
-
-			pci_config_put32(config_handle, i, 0xffffffff);
-
-			request = pci_config_get32(config_handle, i);
-			/*
-			 * If its a zero length, don't do
-			 * any programming.
-			 */
-			if (request != 0) {
-				/*
-				 * Add to the "reg" property
-				 */
-				if (pcicfg_update_reg_prop(new_child,
-				    request, i) != PCICFG_SUCCESS) {
-					goto failedchild;
-				}
-			} else {
-				DEBUG1("BASE register [0x%x] asks for "
-				    "[0x0]=[0x0](32)\n", i);
-				i += 4;
-				continue;
-			}
-
-			/*
-			 * Increment by eight if it is 64 bit address space
-			 */
-			if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
-				DEBUG3("BASE register [0x%x] asks for "
-				    "[0x%x]=[0x%x] (64)\n",
-				    i, request,
-				    (~(PCI_BASE_M_ADDR_M & request))+1)
-				i += 8;
-			} else {
-				DEBUG3("BASE register [0x%x] asks for "
-				    "[0x%x]=[0x%x](32)\n",
-				    i, request,
-				    (~(PCI_BASE_M_ADDR_M & request))+1)
-				i += 4;
-			}
-		}
-
-		/*
-		 * Get the ROM size and create register for it
-		 */
-		pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
-
-		request = pci_config_get32(config_handle, PCI_CONF_ROM);
-		/*
-		 * If its a zero length, don't do
-		 * any programming.
-		 */
-
-		if (request != 0) {
-			DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
-			    PCI_CONF_ROM, request,
-			    (~(PCI_BASE_ROM_ADDR_M & request))+1);
-			/*
-			 * Add to the "reg" property
-			 */
-			if (pcicfg_update_reg_prop(new_child,
-			    request, PCI_CONF_ROM) != PCICFG_SUCCESS) {
-				goto failedchild;
-			}
-		}
-
-		/* now allocate & program the resources */
-		if (pcicfg_device_assign(new_child) != PCICFG_SUCCESS) {
-			(void) pcicfg_free_device_resources(new_child);
-			goto failedchild;
-		}
-		(void) ndi_devi_bind_driver(new_child, 0);
-	}
-
-	(void) pcicfg_config_teardown(&config_handle);
-	return (PCICFG_SUCCESS);
-
-failedchild:
-
-	(void) pcicfg_config_teardown(&config_handle);
-
-failedconfig:
-
-	(void) ndi_devi_free(new_child);
-	return (PCICFG_FAILURE);
-}
-
-static int
-pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
-	uint_t device, uint_t func, uint_t *highest_bus)
-{
-	dev_info_t		*new_child;
-	int8_t			header_type;
-	int			ret;
-	ddi_acc_handle_t	h, ph;
-	int			error = 0;
-	extern int		pcicfg_dont_interpret;
-	pcicfg_err_regs_t	parent_regs, regs;
-	char			*status_prop = NULL;
-#ifdef PCICFG_INTERPRET_FCODE
-	struct pci_ops_bus_args	po;
-	fco_handle_t		c;
-	char			unit_address[64];
-	int			fcode_size = 0;
-	uchar_t			*fcode_addr;
-	uint64_t		mem_answer, mem_alen;
-	pci_regspec_t		p;
-	int32_t			request;
-	ndi_ra_request_t	req;
-	int16_t			vendor_id, device_id;
-#endif
-
-	/*
-	 * check if our parent is of type pciex.
-	 * if so, program config space to disable error msgs during probe.
-	 */
-	if (pcicfg_pcie_dev(parent, PCICFG_DEVICE_TYPE_PCIE, &parent_regs)
-	    == DDI_SUCCESS) {
-		DEBUG0("PCI/PCIe parent detected. Disable errors.\n");
-		/*
-		 * disable parent generating URs or SERR#s during probing
-		 * alone.
-		 */
-		if (pci_config_setup(parent, &ph) != DDI_SUCCESS)
-			return (DDI_FAILURE);
-		pcicfg_disable_bridge_probe_err(parent, ph, &parent_regs);
-	}
-
-	/*
-	 * This node will be put immediately below
-	 * "parent". Allocate a blank device node.  It will either
-	 * be filled in or freed up based on further probing.
-	 */
-
-	if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME,
-	    (pnode_t)DEVI_SID_NODEID, &new_child)
-	    != NDI_SUCCESS) {
-		DEBUG0("pcicfg_fcode_probe(): Failed to alloc child node\n");
-		/* return (PCICFG_FAILURE); */
-		ret = PCICFG_FAILURE;
-		goto failed2;
-	}
-
-	/*
-	 * Create a dummy reg property.  This will be replaced with
-	 * a real reg property when fcode completes or if we need to
-	 * produce one by hand.
-	 */
-	if (pcicfg_add_config_reg(new_child, bus,
-	    device, func) != DDI_SUCCESS) {
-		ret = PCICFG_FAILURE;
-		goto failed3;
-	}
-#ifdef	EFCODE21554
-	if ((ret = pcicfg_config_setup(new_child, &h))
-	    != PCICFG_SUCCESS) {
-		DEBUG0("pcicfg_fcode_probe():"
-		    "Failed to setup config space\n");
-		ret = PCICFG_NODEVICE;
-		goto failed3;
-	}
-
-#else
-	p.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
-	p.pci_phys_mid = p.pci_phys_low = 0;
-	p.pci_size_hi = p.pci_size_low = 0;
-
-	/*
-	 * Map in configuration space (temporarily)
-	 */
-	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
-	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
-	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
-
-	if (pcicfg_map_phys(new_child, &p, &virt, &acc, &h)) {
-		DEBUG0("pcicfg_fcode_probe():"
-		    "Failed to setup config space\n");
-		ret = PCICFG_NODEVICE;
-		goto failed3;
-	}
-
-	/*
-	 * First use ddi_peek16 so that if there is not a device there,
-	 * a bus error will not cause a panic.
-	 */
-	v = virt + PCI_CONF_VENID;
-	if (ddi_peek16(new_child, (int16_t *)v, &vendor_id)) {
-		DEBUG0("Can not read Vendor ID");
-		pcicfg_unmap_phys(&h, &p);
-		ret = PCICFG_NODEVICE;
-		goto failed3;
-	}
-#endif
-	DEBUG0("fcode_probe: conf space mapped.\n");
-	/*
-	 * As soon as we have access to config space,
-	 * turn off device. It will get turned on
-	 * later (after memory is assigned).
-	 */
-	(void) pcicfg_device_off(h);
-
-	/* check if we are PCIe device */
-	if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, &regs)
-	    == DDI_SUCCESS) {
-		/*EMPTY*/
-		DEBUG0("PCI/PCIe device detected\n");
-	}
-
-	/*
-	 * Set 1275 properties common to all devices
-	 */
-	if (pcicfg_set_standard_props(new_child,
-	    h, regs.pcie_dev) != PCICFG_SUCCESS) {
-		DEBUG0("Failed to set standard properties\n");
-		goto failed;
-	}
-
-	/*
-	 * Child node properties  NOTE: Both for PCI-PCI bridge and child node
-	 */
-	if (pcicfg_set_childnode_props(new_child,
-	    h, regs.pcie_dev) != PCICFG_SUCCESS) {
-		ret = PCICFG_FAILURE;
-		goto failed;
-	}
-
-	header_type = pci_config_get8(h, PCI_CONF_HEADER);
-
-	/*
-	 * If this is not a multi-function card only probe function zero.
-	 */
-	if (!(header_type & PCI_HEADER_MULTI) && (func > 0)) {
-
-		ret = PCICFG_NODEVICE;
-		goto failed;
-	}
-
-	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
-
-		/*
-		 * XXX - Transparent bridges are handled differently
-		 * than other devices with regards to fcode.  Since
-		 * no transparent bridge currently ships with fcode,
-		 * there is no reason to try to extract it from its rom
-		 * or call the fcode interpreter to try to load a drop-in.
-		 * If fcode is developed to handle transparent bridges,
-		 * this code will have to change.
-		 */
-
-		DEBUG3("--Bridge found bus [0x%x] device"
-		    "[0x%x] func [0x%x]\n", bus, device, func);
-
-		if ((ret = pcicfg_probe_bridge(new_child, h,
-		    bus, highest_bus)) != PCICFG_SUCCESS)
-			(void) pcicfg_free_bridge_resources(new_child);
-		goto done;
-	} else {
-
-		DEBUG3("--Leaf device found bus [0x%x] device"
-		    "[0x%x] func [0x%x]\n",
-		    bus, device, func);
-
-		/*
-		 * link in tree, but don't bind driver
-		 * We don't have compatible property yet
-		 */
-		(void) i_ndi_config_node(new_child, DS_LINKED, 0);
-
-		if (pci_config_get8(h, PCI_CONF_IPIN)) {
-			pci_config_put8(h, PCI_CONF_ILINE, 0xf);
-		}
-
-#ifdef PCICFG_INTERPRET_FCODE
-		/*
-		 * Some platforms (x86) don't run fcode, so don't interpret
-		 * fcode that might be in the ROM.
-		 */
-		if (pcicfg_dont_interpret == 0) {
-
-			/* This platform supports fcode */
-
-			vendor_id = pci_config_get16(h, PCI_CONF_VENID);
-			device_id = pci_config_get16(h, PCI_CONF_DEVID);
-
-			/*
-			 * Get the ROM size and create register for it
-			 */
-			pci_config_put32(h, PCI_CONF_ROM, 0xfffffffe);
-
-			request = pci_config_get32(h, PCI_CONF_ROM);
-
-			/*
-			 * If its a zero length, don't do
-			 * any programming.
-			 */
-
-			if (request != 0) {
-				/*
-				 * Add resource to assigned-addresses.
-				 */
-				if (pcicfg_fcode_assign_bars(h, new_child,
-				    bus, device, func, request, &p)
-				    != PCICFG_SUCCESS) {
-					DEBUG0("Failed to assign addresses to "
-					    "implemented BARs");
-					ret = PCICFG_FAILURE;
-					goto failed;
-				}
-
-				/* Turn device on */
-				(void) pcicfg_device_on(h);
-
-				/*
-				 * Attempt to load fcode.
-				 */
-				(void) pcicfg_load_fcode(new_child, bus, device,
-				    func, vendor_id, device_id, &fcode_addr,
-				    &fcode_size, PCICFG_LOADDR(mem_answer),
-				    (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
-
-				/* Turn device off */
-				(void) pcicfg_device_off(h);
-
-				/*
-				 * Free the ROM resources.
-				 */
-				(void) pcicfg_free_resource(new_child, p);
-
-				DEBUG2("configure: fcode addr %lx size %x\n",
-				    fcode_addr, fcode_size);
-
-				/*
-				 * Create the fcode-rom-offset property.  The
-				 * buffer containing the fcode always starts
-				 * with 0xF1, so the fcode offset is zero.
-				 */
-				if (ndi_prop_update_int(DDI_DEV_T_NONE,
-				    new_child, "fcode-rom-offset", 0)
-				    != DDI_SUCCESS) {
-					DEBUG0("Failed to create "
-					    "fcode-rom-offset property\n");
-					ret = PCICFG_FAILURE;
-					goto failed;
-				}
-			} else {
-				DEBUG0("There is no Expansion ROM\n");
-				fcode_addr = NULL;
-				fcode_size = 0;
-			}
-
-			/*
-			 * Fill in the bus specific arguments. For
-			 * PCI, it is the config address.
-			 */
-			po.config_address =
-			    PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
-
-			DEBUG1("config_address=%x\n", po.config_address);
-
-			/*
-			 * Build unit address.
-			 */
-			(void) sprintf(unit_address, "%x,%x", device, func);
-
-			DEBUG3("pci_fc_ops_alloc_handle ap=%lx "
-			    "new device=%lx unit address=%s\n",
-			    parent, new_child, unit_address);
-
-			c = pci_fc_ops_alloc_handle(parent, new_child,
-			    fcode_addr, fcode_size, unit_address, &po);
-
-			DEBUG0("calling fcode_interpreter()\n");
-
-			DEBUG3("Before int DIP=%lx binding name %s major %d\n",
-			    new_child, ddi_binding_name(new_child),
-			    ddi_driver_major(new_child));
-
-			error = fcode_interpreter(parent, &pci_fc_ops, c);
-
-			DEBUG1("returned from fcode_interpreter() - "
-			    "returned %x\n", error);
-
-			pci_fc_ops_free_handle(c);
-
-			DEBUG1("fcode size = %x\n", fcode_size);
-			/*
-			 * We don't need the fcode anymore. While allocating
-			 * we had rounded up to a page size.
-			 */
-			if (fcode_size) {
-				kmem_free(fcode_addr, ptob(btopr(fcode_size)));
-			}
-		} else {
-			/* This platform does not support fcode */
-
-			DEBUG0("NOT calling fcode_interpreter()\n");
-		}
-
-#endif /* PCICFG_INTERPRET_FCODE */
-
-		if ((error == 0) && (pcicfg_dont_interpret == 0)) {
-			/*
-			 * The interpreter completed successfully.
-			 * We need to redo the resources based on the new reg
-			 * property.
-			 */
-			DEBUG3("DIP=%lx binding name %s major %d\n", new_child,
-			    ddi_binding_name(new_child),
-			    ddi_driver_major(new_child));
-
-			/*
-			 * Readjust resources specified by reg property.
-			 */
-			if (pcicfg_alloc_new_resources(new_child) ==
-			    PCICFG_FAILURE) {
-				ret = PCICFG_FAILURE;
-				goto failed;
-			}
-
-			/*
-			 * At this stage, there should be enough info to pull
-			 * the status property if it exists.
-			 */
-			if (ddi_prop_lookup_string(DDI_DEV_T_ANY,
-			    new_child, NULL, "status", &status_prop) ==
-			    DDI_PROP_SUCCESS) {
-				if ((strncmp("disabled", status_prop, 8) ==
-				    0) || (strncmp("fail", status_prop, 4) ==
-				    0)) {
-					ret = PCICFG_FAILURE;
-					ddi_prop_free(status_prop);
-					goto failed;
-				} else {
-					ddi_prop_free(status_prop);
-				}
-			}
-
-			ret = PCICFG_SUCCESS;
-			/* no fcode, bind driver now */
-			(void) ndi_devi_bind_driver(new_child, 0);
-
-			goto done;
-		} else if ((error != FC_NO_FCODE) &&
-		    (pcicfg_dont_interpret == 0))  {
-			/*
-			 * The interpreter located fcode, but had an error in
-			 * processing. Cleanup and fail the operation.
-			 */
-			DEBUG0("Interpreter detected fcode failure\n");
-			(void) pcicfg_free_resources(new_child);
-			ret = PCICFG_FAILURE;
-			goto failed;
-		} else {
-			/*
-			 * Either the interpreter failed with FC_NO_FCODE or we
-			 * chose not to run the interpreter
-			 * (pcicfg_dont_interpret).
-			 *
-			 * If the interpreter failed because there was no
-			 * dropin, then we need to probe the device ourself.
-			 */
-
-			/*
-			 * Free any resources that may have been assigned
-			 * during fcode loading/execution since we need
-			 * to start over.
-			 */
-			(void) pcicfg_free_resources(new_child);
-
-#ifdef	EFCODE21554
-			pcicfg_config_teardown(&h);
-#else
-			pcicfg_unmap_phys(&h, &p);
-#endif
-			(void) ndi_devi_free(new_child);
-
-			DEBUG0("No Drop-in Probe device ourself\n");
-
-			ret = pcicfg_probe_children(parent, bus, device, func,
-			    highest_bus);
-
-			if (ret != PCICFG_SUCCESS) {
-				DEBUG0("Could not self probe child\n");
-				goto failed2;
-			}
-
-			/*
-			 * We successfully self probed the device.
-			 */
-			if ((new_child = pcicfg_devi_find(
-			    parent, device, func)) == NULL) {
-				DEBUG0("Did'nt find device node "
-				    "just created\n");
-				ret = PCICFG_FAILURE;
-				goto failed2;
-			}
-#ifdef	EFCODE21554
-			/*
-			 * Till now, we have detected a non transparent bridge
-			 * (ntbridge) as a part of the generic probe code and
-			 * configured only one configuration
-			 * header which is the side facing the host bus.
-			 * Now, configure the other side and create children.
-			 *
-			 * To make the process simpler, lets load the device
-			 * driver for the non transparent bridge as this is a
-			 * Solaris bundled driver, and use its configuration map
-			 * services rather than programming it here.
-			 * If the driver is not bundled into Solaris, it must be
-			 * first loaded and configured before performing any
-			 * hotplug operations.
-			 *
-			 * This not only makes the code simpler but also more
-			 * generic.
-			 *
-			 * So here we go.
-			 */
-			if (pcicfg_is_ntbridge(new_child) != DDI_FAILURE) {
-
-				DEBUG0("Found nontransparent bridge.\n");
-
-				ret = pcicfg_configure_ntbridge(new_child,
-				    bus, device);
-			}
-			if (ret != PCICFG_SUCCESS) {
-				/*
-				 * Bridge configure failed. Free up the self
-				 * probed entry. The bus resource allocation
-				 * maps need to be cleaned up to prevent
-				 * warnings on retries of the failed configure.
-				 */
-				(void) pcicfg_ntbridge_unconfigure(new_child);
-				(void) pcicfg_teardown_device(new_child);
-			}
-#endif
-			goto done2;
-		}
-	}
-done:
-failed:
-#ifdef	EFCODE21554
-	pcicfg_config_teardown(&h);
-#else
-	pcicfg_unmap_phys(&h, &p);
-#endif
-failed3:
-	if (ret != PCICFG_SUCCESS)
-		(void) ndi_devi_free(new_child);
-done2:
-failed2:
-	if (parent_regs.pcie_dev) {
-		pcicfg_enable_bridge_probe_err(parent, ph, &parent_regs);
-		pci_config_teardown(&ph);
-	}
-	return (ret);
-}
-
-static int
-pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
-			uint_t *highest_bus)
-{
-	uint64_t next_bus;
-	uint_t new_bus, num_slots;
-	ndi_ra_request_t req;
-	int rval, i, j;
-	uint64_t mem_answer, mem_base, mem_alen, mem_size, mem_end;
-	uint64_t io_answer, io_base, io_alen, io_size, io_end;
-	uint64_t round_answer, round_len;
-	pcicfg_range_t range[PCICFG_RANGE_LEN];
-	int bus_range[2];
-	pcicfg_phdl_t phdl;
-	int count;
-	uint64_t pcibus_base, pcibus_alen;
-	uint64_t max_bus;
-	uint8_t pcie_device_type = 0;
-
-	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
-	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
-	req.ra_boundbase = 0;
-	req.ra_boundlen = PCICFG_MAX_BUS_DEPTH;
-	req.ra_len = PCICFG_MAX_BUS_DEPTH;
-	req.ra_align_mask = 0;  /* no alignment needed */
-
-	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
-	    &pcibus_base, &pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
-
-	if (rval != NDI_SUCCESS) {
-		if (rval == NDI_RA_PARTIAL_REQ) {
-			/*EMPTY*/
-			DEBUG0("NDI_RA_PARTIAL_REQ returned for bus range\n");
-		} else {
-			DEBUG0(
-			    "Failed to allocate bus range for bridge\n");
-			return (PCICFG_FAILURE);
-		}
-	}
-
-	DEBUG2("Bus Range Allocated [base=%d] [len=%d]\n",
-	    pcibus_base, pcibus_alen);
-
-	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_BUSNUM)
-	    == NDI_FAILURE) {
-		DEBUG0("Can not setup resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
-		return (PCICFG_FAILURE);
-	}
-
-	/*
-	 * Put available bus range into the pool.
-	 * Take the first one for this bridge to use and don't give
-	 * to child.
-	 */
-	(void) ndi_ra_free(new_child, pcibus_base+1, pcibus_alen-1,
-	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
-
-	next_bus = pcibus_base;
-	max_bus = pcibus_base + pcibus_alen - 1;
-
-	new_bus = next_bus;
-
-	DEBUG1("NEW bus found  ->[%d]\n", new_bus);
-
-	/* Keep track of highest bus for subordinate bus programming */
-	*highest_bus = new_bus;
-
-	/*
-	 * Allocate Memory Space for Bridge
-	 */
-	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
-	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
-	req.ra_boundbase = 0;
-	/*
-	 * Note: To support a 32b system, boundlen and len need to be
-	 * 32b quantities
-	 */
-	req.ra_boundlen = PCICFG_4GIG_LIMIT + 1;
-	req.ra_len = PCICFG_4GIG_LIMIT + 1; /* Get as big as possible */
-	req.ra_align_mask =
-	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
-
-	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
-	    &mem_answer, &mem_alen,  NDI_RA_TYPE_MEM, NDI_RA_PASS);
-
-	if (rval != NDI_SUCCESS) {
-		if (rval == NDI_RA_PARTIAL_REQ) {
-			/*EMPTY*/
-			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
-		} else {
-			DEBUG0(
-			    "Failed to allocate memory for bridge\n");
-			return (PCICFG_FAILURE);
-		}
-	}
-
-	DEBUG3("Bridge Memory Allocated [0x%x.%x] len [0x%x]\n",
-	    PCICFG_HIADDR(mem_answer),
-	    PCICFG_LOADDR(mem_answer),
-	    mem_alen);
-
-	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
-		DEBUG0("Can not setup resource map - NDI_RA_TYPE_MEM\n");
-		return (PCICFG_FAILURE);
-	}
-
-	/*
-	 * Put available memory into the pool.
-	 */
-	(void) ndi_ra_free(new_child, mem_answer, mem_alen, NDI_RA_TYPE_MEM,
-	    NDI_RA_PASS);
-
-	mem_base = mem_answer;
-
-	/*
-	 * Allocate I/O Space for Bridge
-	 */
-	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
-	req.ra_align_mask = PCICFG_IOGRAN - 1; /* 4k alignment */
-	req.ra_boundbase = 0;
-	req.ra_boundlen = PCICFG_4GIG_LIMIT;
-	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
-	req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
-
-	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, &io_answer,
-	    &io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
-
-	if (rval != NDI_SUCCESS) {
-		if (rval == NDI_RA_PARTIAL_REQ) {
-			/*EMPTY*/
-			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
-		} else {
-			DEBUG0("Failed to allocate io space for bridge\n");
-			io_base = io_answer = io_alen = 0;
-			/* return (PCICFG_FAILURE); */
-		}
-	}
-
-	if (io_alen) {
-		DEBUG3("Bridge IO Space Allocated [0x%x.%x] len [0x%x]\n",
-		    PCICFG_HIADDR(io_answer), PCICFG_LOADDR(io_answer),
-		    io_alen);
-
-		if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_IO) ==
-		    NDI_FAILURE) {
-			DEBUG0("Can not setup resource map - NDI_RA_TYPE_IO\n");
-			return (PCICFG_FAILURE);
-		}
-
-		/*
-		 * Put available I/O into the pool.
-		 */
-		(void) ndi_ra_free(new_child, io_answer, io_alen,
-		    NDI_RA_TYPE_IO, NDI_RA_PASS);
-		io_base = io_answer;
-	}
-
-	pcicfg_set_bus_numbers(h, bus, new_bus, max_bus);
-
-	/*
-	 * Setup "bus-range" property before onlining the bridge.
-	 */
-	bus_range[0] = new_bus;
-	bus_range[1] = max_bus;
-
-	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
-	    "bus-range", bus_range, 2) != DDI_SUCCESS) {
-		DEBUG0("Failed to set bus-range property");
-		return (PCICFG_FAILURE);
-	}
-
-	/*
-	 * Reset the secondary bus
-	 */
-	pci_config_put16(h, PCI_BCNF_BCNTRL,
-	    pci_config_get16(h, PCI_BCNF_BCNTRL) | 0x40);
-
-	drv_usecwait(100);
-
-	pci_config_put16(h, PCI_BCNF_BCNTRL,
-	    pci_config_get16(h, PCI_BCNF_BCNTRL) & ~0x40);
-
-	/*
-	 * Program the memory base register with the
-	 * start of the memory range
-	 */
-	pci_config_put16(h, PCI_BCNF_MEM_BASE,
-	    PCICFG_HIWORD(PCICFG_LOADDR(mem_answer)));
-
-	/*
-	 * Program the memory limit register with the
-	 * end of the memory range.
-	 */
-
-	pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
-	    PCICFG_HIWORD(PCICFG_LOADDR(
-	    PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN) - 1)));
-
-	/*
-	 * Allocate the chunk of memory (if any) not programmed into the
-	 * bridge because of the round down.
-	 */
-	if (PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN)
-	    != (mem_answer + mem_alen)) {
-		DEBUG0("Need to allocate Memory round off chunk\n");
-		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
-		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
-		req.ra_addr = PCICFG_ROUND_DOWN((mem_answer + mem_alen),
-		    PCICFG_MEMGRAN);
-		req.ra_len =  (mem_answer + mem_alen) -
-		    (PCICFG_ROUND_DOWN((mem_answer + mem_alen),
-		    PCICFG_MEMGRAN));
-
-		(void) ndi_ra_alloc(new_child, &req,
-		    &round_answer, &round_len,  NDI_RA_TYPE_MEM, NDI_RA_PASS);
-	}
-
-	/*
-	 * Program the I/O Space Base
-	 */
-	pci_config_put8(h, PCI_BCNF_IO_BASE_LOW,
-	    PCICFG_HIBYTE(PCICFG_LOWORD(
-	    PCICFG_LOADDR(io_answer))));
-
-	pci_config_put16(h, PCI_BCNF_IO_BASE_HI,
-	    PCICFG_HIWORD(PCICFG_LOADDR(io_answer)));
-
-	/*
-	 * Program the I/O Space Limit
-	 */
-	pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
-	    PCICFG_HIBYTE(PCICFG_LOWORD(
-	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(io_answer + io_alen,
-	    PCICFG_IOGRAN)))) - 1);
-
-	pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
-	    PCICFG_HIWORD(PCICFG_LOADDR(
-	    PCICFG_ROUND_DOWN(io_answer + io_alen, PCICFG_IOGRAN)))
-	    - 1);
-
-	/*
-	 * Allocate the chunk of I/O (if any) not programmed into the
-	 * bridge because of the round down.
-	 */
-	if (PCICFG_ROUND_DOWN((io_answer + io_alen), PCICFG_IOGRAN)
-	    != (io_answer + io_alen)) {
-		DEBUG0("Need to allocate I/O round off chunk\n");
-		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
-		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
-		req.ra_addr = PCICFG_ROUND_DOWN((io_answer + io_alen),
-		    PCICFG_IOGRAN);
-		req.ra_len =  (io_answer + io_alen) -
-		    (PCICFG_ROUND_DOWN((io_answer + io_alen),
-		    PCICFG_IOGRAN));
-
-		(void) ndi_ra_alloc(new_child, &req,
-		    &round_answer, &round_len,  NDI_RA_TYPE_IO, NDI_RA_PASS);
-	}
-
-	/*
-	 * Setup "ranges" property before onlining the bridge.
-	 */
-	bzero((caddr_t)range, sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
-
-	range[0].child_hi = range[0].parent_hi |= (PCI_REG_REL_M | PCI_ADDR_IO);
-	range[0].child_lo = range[0].parent_lo = io_base;
-	range[1].child_hi = range[1].parent_hi |=
-	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
-	range[1].child_lo = range[1].parent_lo = mem_base;
-
-	range[0].size_lo = io_alen;
-	if (pcicfg_update_ranges_prop(new_child, &range[0])) {
-		DEBUG0("Failed to update ranges (io)\n");
-		return (PCICFG_FAILURE);
-	}
-	range[1].size_lo = mem_alen;
-	if (pcicfg_update_ranges_prop(new_child, &range[1])) {
-		DEBUG0("Failed to update ranges (memory)\n");
-		return (PCICFG_FAILURE);
-	}
-
-	/*
-	 * Clear status bits
-	 */
-	pci_config_put16(h, PCI_BCNF_SEC_STATUS, 0xffff);
-
-	/*
-	 * Turn off prefetchable range
-	 */
-	pci_config_put32(h, PCI_BCNF_PF_BASE_LOW, 0x0000ffff);
-	pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
-	pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH, 0x0);
-
-	/*
-	 * Needs to be set to this value
-	 */
-	pci_config_put8(h, PCI_CONF_ILINE, 0xf);
-
-	/* check our device_type as defined by Open Firmware */
-	if (pcicfg_pcie_device_type(new_child, h) == DDI_SUCCESS)
-		pcie_device_type = 1;
-
-	/*
-	 * Set bus properties
-	 */
-	if (pcicfg_set_busnode_props(new_child, pcie_device_type,
-	    (int)bus, (int)new_bus) != PCICFG_SUCCESS) {
-		DEBUG0("Failed to set busnode props\n");
-		return (PCICFG_FAILURE);
-	}
-
-	(void) pcicfg_device_on(h);
-
-	if (ndi_devi_online(new_child, NDI_NO_EVENT|NDI_CONFIG)
-	    != NDI_SUCCESS) {
-		DEBUG0("Unable to online bridge\n");
-		return (PCICFG_FAILURE);
-	}
-
-	DEBUG0("Bridge is ONLINE\n");
-
-	/*
-	 * After a Reset, we need to wait 2^25 clock cycles before the
-	 * first Configuration access.  The worst case is 33MHz, which
-	 * is a 1 second wait.
-	 */
-	drv_usecwait(pcicfg_sec_reset_delay);
-
-	/*
-	 * Probe all children devices
-	 */
-	DEBUG0("Bridge Programming Complete - probe children\n");
-	ndi_devi_enter(new_child, &count);
-	for (i = 0; i < PCICFG_MAX_DEVICE; i++) {
-		for (j = 0; j < PCICFG_MAX_FUNCTION; j++) {
-			if ((rval = pcicfg_fcode_probe(new_child,
-			    new_bus, i, j, highest_bus))
-			    != PCICFG_SUCCESS) {
-				if (rval == PCICFG_NODEVICE) {
-					DEBUG3("No Device at bus [0x%x]"
-					    "device [0x%x] "
-					    "func [0x%x]\n", new_bus, i, j);
-					if (j)
-						continue;
-				} else {
-					DEBUG3("Failed to configure bus "
-					    "[0x%x] device [0x%x] "
-					    "func [0x%x]\n", new_bus, i, j);
-					rval = PCICFG_FAILURE;
-				}
-
-				break;
-			}
-		}
-		/* if any function fails to be configured, no need to proceed */
-		if (rval != PCICFG_NODEVICE) {
-			break;
-		}
-	}
-	ndi_devi_exit(new_child, count);
-
-	/* if empty topology underneath, it is still a success. */
-	if (rval != PCICFG_FAILURE)
-		rval = PCICFG_SUCCESS;
-
-	/*
-	 * Offline the bridge to allow reprogramming of resources.
-	 */
-	(void) ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG);
-
-	phdl.dip = new_child;
-	phdl.memory_base = mem_answer;
-	phdl.io_base = (uint32_t)io_answer;
-	phdl.error = PCICFG_SUCCESS;    /* in case of empty child tree */
-
-	ndi_devi_enter(ddi_get_parent(new_child), &count);
-	ddi_walk_devs(new_child, pcicfg_find_resource_end, (void *)&phdl);
-	ndi_devi_exit(ddi_get_parent(new_child), count);
-
-	if (phdl.error != PCICFG_SUCCESS) {
-		DEBUG0("Failure summing resources\n");
-		return (PCICFG_FAILURE);
-	}
-
-	num_slots = pcicfg_get_nslots(new_child, h);
-	mem_end = PCICFG_ROUND_UP(phdl.memory_base, PCICFG_MEMGRAN);
-	io_end = PCICFG_ROUND_UP(phdl.io_base, PCICFG_IOGRAN);
-
-	DEBUG3("Start of Unallocated Bridge(%d slots) Resources "
-	    "Mem=0x%lx I/O=0x%lx\n", num_slots, mem_end, io_end);
-
-	/*
-	 * if the bridge a slots, then preallocate. If not, assume static
-	 * configuration. Also check for preallocation limits and spit
-	 * warning messages appropriately (perhaps some can be in debug mode).
-	 */
-	if (num_slots) {
-		pci_regspec_t reg;
-		uint64_t mem_assigned = mem_end;
-		uint64_t io_assigned = io_end;
-		uint64_t mem_reqd = mem_answer + (num_slots *
-		    pcicfg_slot_memsize);
-		uint64_t io_reqd = io_answer + (num_slots *
-		    pcicfg_slot_iosize);
-		uint8_t highest_bus_reqd = new_bus + (num_slots *
-		    pcicfg_slot_busnums);
-#ifdef DEBUG
-		if (mem_end > mem_reqd)
-			DEBUG3("Memory space consumed by bridge"
-			    " more than planned for %d slot(s)(%lx, %lx)",
-			    num_slots, mem_answer, mem_end);
-		if (io_end > io_reqd)
-			DEBUG3("IO space consumed by bridge"
-			    " more than planned for %d slot(s)(%lx, %lx)",
-			    num_slots, io_answer, io_end);
-		if (*highest_bus > highest_bus_reqd)
-			DEBUG3("Buses consumed by bridge"
-			    " more than planned for %d slot(s)(%x, %x)",
-			    num_slots, new_bus, *highest_bus);
-
-		if (mem_reqd > (mem_answer + mem_alen))
-			DEBUG3("Memory space required by bridge"
-			    " more than available for %d slot(s)(%lx, %lx)",
-			    num_slots, mem_answer, mem_end);
-
-		if (io_reqd > (io_answer + io_alen))
-			DEBUG3("IO space required by bridge"
-			    " more than available for %d slot(s)(%lx, %lx)",
-			    num_slots, io_answer, io_end);
-		if (highest_bus_reqd > max_bus)
-			DEBUG3("Bus numbers required by bridge"
-			    " more than available for %d slot(s)(%x, %x)",
-			    num_slots, new_bus, *highest_bus);
-#endif
-		mem_end = MAX((MIN(mem_reqd, (mem_answer + mem_alen))),
-		    mem_end);
-		io_end = MAX((MIN(io_reqd, (io_answer + io_alen))), io_end);
-		*highest_bus = MAX((MIN(highest_bus_reqd, max_bus)),
-		    *highest_bus);
-		DEBUG3("mem_end %lx, io_end %lx, highest_bus %x\n",
-		    mem_end, io_end, *highest_bus);
-
-		mem_size = mem_end - mem_assigned;
-		io_size = io_end - io_assigned;
-
-		reg.pci_phys_mid = reg.pci_size_hi = 0;
-		if (io_size > 0) {
-			reg.pci_phys_hi = (PCI_REG_REL_M | PCI_ADDR_IO);
-			reg.pci_phys_low = io_assigned;
-			reg.pci_size_low = io_size;
-			if (pcicfg_update_available_prop(new_child, &reg)) {
-				DEBUG0("Failed to update available prop "
-				    "(io)\n");
-				return (PCICFG_FAILURE);
-			}
-		}
-		if (mem_size > 0) {
-			reg.pci_phys_hi = (PCI_REG_REL_M | PCI_ADDR_MEM32);
-			reg.pci_phys_low = mem_assigned;
-			reg.pci_size_low = mem_size;
-			if (pcicfg_update_available_prop(new_child, &reg)) {
-				DEBUG0("Failed to update available prop "
-				    "(memory)\n");
-				return (PCICFG_FAILURE);
-			}
-		}
-	}
-
-	/*
-	 * Give back unused memory space to parent.
-	 */
-	(void) ndi_ra_free(ddi_get_parent(new_child),
-	    mem_end, (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM,
-	    NDI_RA_PASS);
-
-	if (mem_end == mem_answer) {
-		DEBUG0("No memory resources used\n");
-		/*
-		 * To prevent the bridge from forwarding any Memory
-		 * transactions, the Memory Limit will be programmed
-		 * with a smaller value than the Memory Base.
-		 */
-		pci_config_put16(h, PCI_BCNF_MEM_BASE, 0xffff);
-		pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 0);
-
-		mem_size = 0;
-	} else {
-		/*
-		 * Reprogram the end of the memory.
-		 */
-		pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
-		    PCICFG_HIWORD(mem_end) - 1);
-		mem_size = mem_end - mem_base;
-	}
-
-	/*
-	 * Give back unused io space to parent.
-	 */
-	(void) ndi_ra_free(ddi_get_parent(new_child),
-	    io_end, (io_answer + io_alen) - io_end,
-	    NDI_RA_TYPE_IO, NDI_RA_PASS);
-
-	if (io_end == io_answer) {
-		DEBUG0("No IO Space resources used\n");
-
-		/*
-		 * To prevent the bridge from forwarding any I/O
-		 * transactions, the I/O Limit will be programmed
-		 * with a smaller value than the I/O Base.
-		 */
-		pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 0);
-		pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 0);
-		pci_config_put8(h, PCI_BCNF_IO_BASE_LOW, 0xff);
-		pci_config_put16(h, PCI_BCNF_IO_BASE_HI, 0);
-
-		io_size = 0;
-	} else {
-		/*
-		 * Reprogram the end of the io space.
-		 */
-		pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
-		    PCICFG_HIBYTE(PCICFG_LOWORD(
-		    PCICFG_LOADDR(io_end) - 1)));
-
-		pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
-		    PCICFG_HIWORD(PCICFG_LOADDR(io_end - 1)));
-
-		io_size = io_end - io_base;
-	}
-
-	if ((max_bus - *highest_bus) > 0) {
-		/*
-		 * Give back unused bus numbers
-		 */
-		(void) ndi_ra_free(ddi_get_parent(new_child),
-		    *highest_bus+1, max_bus - *highest_bus,
-		    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
-	}
-
-	/*
-	 * Set bus numbers to ranges encountered during scan
-	 */
-	pcicfg_set_bus_numbers(h, bus, new_bus, *highest_bus);
-
-	bus_range[0] = pci_config_get8(h, PCI_BCNF_SECBUS);
-	bus_range[1] = pci_config_get8(h, PCI_BCNF_SUBBUS);
-	DEBUG1("End of bridge probe: bus_range[0] =  %d\n", bus_range[0]);
-	DEBUG1("End of bridge probe: bus_range[1] =  %d\n", bus_range[1]);
-
-	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
-	    "bus-range", bus_range, 2) != DDI_SUCCESS) {
-		DEBUG0("Failed to set bus-range property");
-		return (PCICFG_FAILURE);
-	}
-
-	/*
-	 * Remove the ranges property if it exists since we will create
-	 * a new one.
-	 */
-	(void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "ranges");
-
-	DEBUG2("Creating Ranges property - Mem Address %lx Mem Size %x\n",
-	    mem_base, mem_size);
-	DEBUG2("                         - I/O Address %lx I/O Size %x\n",
-	    io_base, io_size);
-
-	bzero((caddr_t)range, sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
-
-	range[0].child_hi = range[0].parent_hi |= (PCI_REG_REL_M | PCI_ADDR_IO);
-	range[0].child_lo = range[0].parent_lo = io_base;
-	range[1].child_hi = range[1].parent_hi |=
-	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
-	range[1].child_lo = range[1].parent_lo = mem_base;
-
-	if (io_size > 0) {
-		range[0].size_lo = io_size;
-		if (pcicfg_update_ranges_prop(new_child, &range[0])) {
-			DEBUG0("Failed to update ranges (io)\n");
-			return (PCICFG_FAILURE);
-		}
-	}
-	if (mem_size > 0) {
-		range[1].size_lo = mem_size;
-		if (pcicfg_update_ranges_prop(new_child, &range[1])) {
-			DEBUG0("Failed to update ranges (memory)\n");
-			return (PCICFG_FAILURE);
-		}
-	}
-
-	/*
-	 * Remove the resource maps for the bridge since we no longer
-	 * need them.  Note that the failure is ignored since the
-	 * ndi_devi_offline above may have already taken care of it via
-	 * driver detach.
-	 * It has been checked that there are no other reasons for
-	 * failure other than map itself being non-existent. So we are Ok.
-	 */
-	if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
-		/*EMPTY*/
-		DEBUG0("Can not destroy resource map - NDI_RA_TYPE_MEM\n");
-	}
-
-	if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_IO) == NDI_FAILURE) {
-		/*EMPTY*/
-		DEBUG0("Can not destroy resource map - NDI_RA_TYPE_IO\n");
-	}
-
-	if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_BUSNUM)
-	    == NDI_FAILURE) {
-		/*EMPTY*/
-		DEBUG0("Can't destroy resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
-	}
-
-	return (rval);
-}
-
-/*
- * Return PCICFG_SUCCESS if device exists at the specified address.
- * Return PCICFG_NODEVICE is no device exists at the specified address.
- *
- */
-int
-pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
-{
-	caddr_t			virt;
-	ddi_device_acc_attr_t	attr;
-	int			status;
-	int			rlen;
-	pci_regspec_t		*reg;
-	int			ret = DDI_SUCCESS;
-	int16_t			tmp;
-	/*
-	 * flags = PCICFG_CONF_INDIRECT_MAP if configuration space is indirectly
-	 * mapped, otherwise it is 0. "flags" is introduced in support of any
-	 * non transparent bridges, where configuration space is indirectly
-	 * mapped.
-	 * Indirect mapping is always true on sun4v systems.
-	 */
-	int			flags = 0;
-
-
-	/*
-	 * Get the pci register spec from the node
-	 */
-	status = ddi_getlongprop(DDI_DEV_T_ANY,
-	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
-
-	switch (status) {
-		case DDI_PROP_SUCCESS:
-		break;
-		case DDI_PROP_NO_MEMORY:
-			DEBUG0("reg present, but unable to get memory\n");
-			return (PCICFG_FAILURE);
-		default:
-			DEBUG0("no reg property\n");
-			return (PCICFG_FAILURE);
-	}
-
-	if (pcicfg_indirect_map(dip) == DDI_SUCCESS)
-		flags |= PCICFG_CONF_INDIRECT_MAP;
-
-	/*
-	 * Map in configuration space (temporarily)
-	 */
-	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
-	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
-	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
-	attr.devacc_attr_access = DDI_CAUTIOUS_ACC;
-
-#ifdef	EFCODE21554
-	if (ddi_regs_map_setup(dip, 0, &virt,
-	    0, 0, &attr, handle) != DDI_SUCCESS)
-#else
-	if (pcicfg_map_phys(dip, reg, &virt, &attr, handle)
-	    != DDI_SUCCESS)
-#endif
-	{
-		DEBUG0("pcicfg_config_setup():"
-		"Failed to setup config space\n");
-
-		kmem_free((caddr_t)reg, rlen);
-		return (PCICFG_FAILURE);
-	}
-
-	if (flags & PCICFG_CONF_INDIRECT_MAP) {
-		/*
-		 * need to use DDI interfaces as the conf space is
-		 * cannot be directly accessed by the host.
-		 */
-		tmp = (int16_t)ddi_get16(*handle, (uint16_t *)virt);
-	} else {
-		ret = ddi_peek16(dip, (int16_t *)virt, &tmp);
-	}
-
-	if (ret == DDI_SUCCESS) {
-		if (tmp == -1) {
-			DEBUG1("NO DEVICEFOUND, read %x\n", tmp);
-			ret = PCICFG_NODEVICE;
-		} else {
-			/* XXX - Need to check why HV is returning 0 */
-			if (tmp == 0) {
-				DEBUG0("Device Not Ready yet ?");
-				ret = PCICFG_NODEVICE;
-			} else {
-				DEBUG1("DEVICEFOUND, read %x\n", tmp);
-				ret = PCICFG_SUCCESS;
-			}
-		}
-	} else {
-		DEBUG0("ddi_peek failed, must be NODEVICE\n");
-		ret = PCICFG_NODEVICE;
-	}
-
-	/*
-	 * A bug in XMITS 3.0 causes us to miss the Master Abort Split
-	 * Completion message.  The result is the error message being
-	 * sent back as part of the config data.  If the first two words
-	 * of the config space happen to be the same as the Master Abort
-	 * message, then report back that there is no device there.
-	 */
-	if ((ret == PCICFG_SUCCESS) && !(flags & PCICFG_CONF_INDIRECT_MAP)) {
-		int32_t	pcix_scm;
-
-#define		PCICFG_PCIX_SCM	0x10000004
-
-		pcix_scm = 0;
-		(void) ddi_peek32(dip, (int32_t *)virt, &pcix_scm);
-		if (pcix_scm == PCICFG_PCIX_SCM) {
-			pcix_scm = 0;
-			(void) ddi_peek32(dip,
-			    (int32_t *)(virt + 4), &pcix_scm);
-			if (pcix_scm == PCICFG_PCIX_SCM)
-				ret = PCICFG_NODEVICE;
-		}
-	}
-
-	if (ret == PCICFG_NODEVICE)
-#ifdef	EFCODE21554
-		ddi_regs_map_free(handle);
-#else
-		pcicfg_unmap_phys(handle, reg);
-#endif
-
-	kmem_free((caddr_t)reg, rlen);
-
-	return (ret);
-
-}
-
-static void
-pcicfg_config_teardown(ddi_acc_handle_t *handle)
-{
-	(void) ddi_regs_map_free(handle);
-}
-
-static int
-pcicfg_add_config_reg(dev_info_t *dip,
-	uint_t bus, uint_t device, uint_t func)
-{
-	int reg[10] = { PCI_ADDR_CONFIG, 0, 0, 0, 0};
-
-	reg[0] = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
-
-	return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
-	    "reg", reg, 5));
-}
-
-static int
-pcicfg_dump_assigned(dev_info_t *dip)
-{
-	pci_regspec_t		*reg;
-	int			length;
-	int			rcount;
-	int			i;
-
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&reg,
-	    &length) != DDI_PROP_SUCCESS) {
-		DEBUG0("Failed to read assigned-addresses property\n");
-		return (PCICFG_FAILURE);
-	}
-
-	rcount = length / sizeof (pci_regspec_t);
-	for (i = 0; i < rcount; i++) {
-		DEBUG4("pcicfg_dump_assigned - size=%x low=%x mid=%x high=%x\n",
-		    reg[i].pci_size_low, reg[i].pci_phys_low,
-		    reg[i].pci_phys_mid, reg[i].pci_phys_hi);
-	}
-	/*
-	 * Don't forget to free up memory from ddi_getlongprop
-	 */
-	kmem_free((caddr_t)reg, length);
-
-	return (PCICFG_SUCCESS);
-}
-
-#ifdef PCICFG_INTERPRET_FCODE
-static int
-pcicfg_load_fcode(dev_info_t *dip, uint_t bus, uint_t device, uint_t func,
-    uint16_t vendor_id, uint16_t device_id, uchar_t **fcode_addr,
-    int *fcode_size, int rom_paddr, int rom_size)
-{
-	pci_regspec_t		p;
-	int			pci_data;
-	int			start_of_fcode;
-	int			image_length;
-	int			code_type;
-	ddi_acc_handle_t	h;
-	ddi_device_acc_attr_t	acc;
-	uint8_t			*addr;
-	int8_t			image_not_found, indicator;
-	uint16_t		vendor_id_img, device_id_img;
-	int16_t			rom_sig;
-#ifdef DEBUG
-	int i;
-#endif
-
-	DEBUG4("pcicfg_load_fcode() - "
-	    "bus %x device =%x func=%x rom_paddr=%lx\n",
-	    bus, device, func, rom_paddr);
-	DEBUG2("pcicfg_load_fcode() - vendor_id=%x device_id=%x\n",
-	    vendor_id, device_id);
-
-	*fcode_size = 0;
-	*fcode_addr = NULL;
-
-	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
-	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
-	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
-
-	p.pci_phys_hi = PCI_ADDR_MEM32 | PCICFG_MAKE_REG_HIGH(bus, device,
-	    func, PCI_CONF_ROM);
-
-	p.pci_phys_mid = 0;
-	p.pci_phys_low = 0;
-
-	p.pci_size_low = rom_size;
-	p.pci_size_hi = 0;
-
-	if (pcicfg_map_phys(dip, &p, (caddr_t *)&addr, &acc, &h)) {
-		DEBUG1("Can Not map in ROM %x\n", p.pci_phys_low);
-		return (PCICFG_FAILURE);
-	}
-
-	/*
-	 * Walk the ROM to find the proper image for this device.
-	 */
-	image_not_found = 1;
-	while (image_not_found) {
-		DEBUG1("Expansion ROM maps to %lx\n", addr);
-
-#ifdef DEBUG
-		if (pcicfg_dump_fcode) {
-			for (i = 0; i < 100; i++)
-				DEBUG2("ROM 0x%x --> 0x%x\n", i,
-				    ddi_get8(h, (uint8_t *)(addr + i)));
-		}
-#endif
-
-		/*
-		 * Some device say they have an Expansion ROM, but do not, so
-		 * for non-21554 devices use peek so we don't panic due to
-		 * accessing non existent memory.
-		 */
-		if (pcicfg_indirect_map(dip) == DDI_SUCCESS) {
-			rom_sig = ddi_get16(h,
-			    (uint16_t *)(addr + PCI_ROM_SIGNATURE));
-		} else {
-			if (ddi_peek16(dip,
-			    (int16_t *)(addr + PCI_ROM_SIGNATURE), &rom_sig)) {
-				cmn_err(CE_WARN,
-				    "PCI Expansion ROM is not accessible");
-				pcicfg_unmap_phys(&h, &p);
-				return (PCICFG_FAILURE);
-			}
-		}
-
-		/*
-		 * Validate the ROM Signature.
-		 */
-		if ((uint16_t)rom_sig != 0xaa55) {
-			DEBUG1("Invalid ROM Signature %x\n", (uint16_t)rom_sig);
-			pcicfg_unmap_phys(&h, &p);
-			return (PCICFG_FAILURE);
-		}
-
-		DEBUG0("Valid ROM Signature Found\n");
-
-		start_of_fcode = ddi_get16(h, (uint16_t *)(addr + 2));
-
-		pci_data =  ddi_get16(h,
-		    (uint16_t *)(addr + PCI_ROM_PCI_DATA_STRUCT_PTR));
-
-		DEBUG2("Pointer To PCI Data Structure %x %x\n", pci_data,
-		    addr);
-
-		/*
-		 * Validate the PCI Data Structure Signature.
-		 * 0x52494350 = "PCIR"
-		 */
-
-		if (ddi_get8(h, (uint8_t *)(addr + pci_data)) != 0x50) {
-			DEBUG0("Invalid PCI Data Structure Signature\n");
-			pcicfg_unmap_phys(&h, &p);
-			return (PCICFG_FAILURE);
-		}
-
-		if (ddi_get8(h, (uint8_t *)(addr + pci_data + 1)) != 0x43) {
-			DEBUG0("Invalid PCI Data Structure Signature\n");
-			pcicfg_unmap_phys(&h, &p);
-			return (PCICFG_FAILURE);
-		}
-		if (ddi_get8(h, (uint8_t *)(addr + pci_data + 2)) != 0x49) {
-			DEBUG0("Invalid PCI Data Structure Signature\n");
-			pcicfg_unmap_phys(&h, &p);
-			return (PCICFG_FAILURE);
-		}
-		if (ddi_get8(h, (uint8_t *)(addr + pci_data + 3)) != 0x52) {
-			DEBUG0("Invalid PCI Data Structure Signature\n");
-			pcicfg_unmap_phys(&h, &p);
-			return (PCICFG_FAILURE);
-		}
-
-		/*
-		 * Is this image for this device?
-		 */
-		vendor_id_img = ddi_get16(h,
-		    (uint16_t *)(addr + pci_data + PCI_PDS_VENDOR_ID));
-		device_id_img = ddi_get16(h,
-		    (uint16_t *)(addr + pci_data + PCI_PDS_DEVICE_ID));
-
-		DEBUG2("This image is for vendor_id=%x device_id=%x\n",
-		    vendor_id_img, device_id_img);
-
-		code_type = ddi_get8(h, addr + pci_data + PCI_PDS_CODE_TYPE);
-
-		switch (code_type) {
-		case PCI_PDS_CODE_TYPE_PCAT:
-			DEBUG0("ROM is of x86/PC-AT Type\n");
-			break;
-		case PCI_PDS_CODE_TYPE_OPEN_FW:
-			DEBUG0("ROM is of Open Firmware Type\n");
-			break;
-		default:
-			DEBUG1("ROM is of Unknown Type 0x%x\n", code_type);
-			break;
-		}
-
-		if ((vendor_id_img != vendor_id) ||
-		    (device_id_img != device_id) ||
-		    (code_type != PCI_PDS_CODE_TYPE_OPEN_FW)) {
-			DEBUG0("Firmware Image is not for this device..."
-			    "goto next image\n");
-			/*
-			 * Read indicator byte to see if there is another
-			 * image in the ROM
-			 */
-			indicator = ddi_get8(h,
-			    (uint8_t *)(addr + pci_data + PCI_PDS_INDICATOR));
-
-			if (indicator != 1) {
-				/*
-				 * There is another image in the ROM.
-				 */
-				image_length = ddi_get16(h,  (uint16_t *)(addr +
-				    pci_data + PCI_PDS_IMAGE_LENGTH)) * 512;
-
-				addr += image_length;
-			} else {
-				/*
-				 * There are no more images.
-				 */
-				DEBUG0("There are no more images in the ROM\n");
-				pcicfg_unmap_phys(&h, &p);
-
-				return (PCICFG_FAILURE);
-			}
-		} else {
-			DEBUG0("Correct image was found\n");
-			image_not_found = 0;  /* Image was found */
-		}
-	}
-
-	*fcode_size =  (ddi_get8(h, addr + start_of_fcode + 4) << 24) |
-	    (ddi_get8(h, addr + start_of_fcode + 5) << 16) |
-	    (ddi_get8(h, addr + start_of_fcode + 6) << 8) |
-	    (ddi_get8(h, addr + start_of_fcode + 7));
-
-	DEBUG1("Fcode Size %x\n", *fcode_size);
-
-	/*
-	 * Allocate page aligned buffer space
-	 */
-	*fcode_addr = kmem_zalloc(ptob(btopr(*fcode_size)), KM_SLEEP);
-
-	if (*fcode_addr == NULL) {
-		DEBUG0("kmem_zalloc returned NULL\n");
-		pcicfg_unmap_phys(&h, &p);
-		return (PCICFG_FAILURE);
-	}
-
-	DEBUG1("Fcode Addr %lx\n", *fcode_addr);
-
-	ddi_rep_get8(h, *fcode_addr, addr + start_of_fcode, *fcode_size,
-	    DDI_DEV_AUTOINCR);
-
-	pcicfg_unmap_phys(&h, &p);
-
-	return (PCICFG_SUCCESS);
-}
-
-static int
-pcicfg_fcode_assign_bars(ddi_acc_handle_t h, dev_info_t *dip, uint_t bus,
-    uint_t device, uint_t func, int32_t fc_request, pci_regspec_t *rom_regspec)
-{
-	/*
-	 * Assign values to all BARs so that it is safe to turn on the
-	 * device for accessing the fcode on the PROM. On successful
-	 * exit from this function, "assigned-addresses" are created
-	 * for all BARs and ROM BAR is enabled. Also, rom_regspec is
-	 * filled with the values that can be used to free up this
-	 * resource later.
-	 */
-	uint32_t request, hiword, size;
-	pci_regspec_t phys_spec;
-	ndi_ra_request_t req;
-	uint64_t mem_answer, mem_alen;
-	int i;
-
-	DEBUG1("pcicfg_fcode_assign_bars :%s\n", DEVI(dip)->devi_name);
-
-	/*
-	 * Process the BARs.
-	 */
-	for (i = PCI_CONF_BASE0; i <= PCI_CONF_BASE5; ) {
-		pci_config_put32(h, i, 0xffffffff);
-		request = pci_config_get32(h, i);
-		/*
-		 * Check if implemented
-		 */
-		if (request == 0) {
-			DEBUG1("pcicfg_fcode_assign_bars :"
-			    "BASE register [0x%x] asks for 0(32)\n", i);
-			i += 4;
-			continue;
-		}
-		/*
-		 * Build the phys_spec for this BAR
-		 */
-		hiword = PCICFG_MAKE_REG_HIGH(bus, device, func, i);
-		size = (~(PCI_BASE_M_ADDR_M & request)) + 1;
-
-		DEBUG3("pcicfg_fcode_assign_bars :"
-		    "BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
-		    i, request, size);
-
-		if ((PCI_BASE_SPACE_M & request) == PCI_BASE_SPACE_MEM) {
-			if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_MEM) {
-				hiword |= PCI_ADDR_MEM32;
-			} else if ((PCI_BASE_TYPE_M & request)
-			    == PCI_BASE_TYPE_ALL) {
-				hiword |= PCI_ADDR_MEM64;
-			}
-			if (request & PCI_BASE_PREF_M)
-				hiword |= PCI_REG_PF_M;
-		} else {
-			hiword |= PCI_ADDR_IO;
-		}
-		phys_spec.pci_phys_hi = hiword;
-		phys_spec.pci_phys_mid = 0;
-		phys_spec.pci_phys_low = 0;
-		phys_spec.pci_size_hi = 0;
-		phys_spec.pci_size_low = size;
-
-		/*
-		 * The following function
-		 * - allocates address space
-		 * - programs the BAR
-		 * - adds an "assigned-addresses" property
-		 */
-		if (pcicfg_alloc_resource(dip, phys_spec)) {
-			cmn_err(CE_WARN, "failed to allocate %d bytes"
-			    " for dev %s BASE register [0x%x]\n",
-			    size, DEVI(dip)->devi_name, i);
-			goto failure;
-		}
-		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
-			/*
-			 * 64 bit, should be in memory space.
-			 */
-			i += 8;
-		} else {
-			/*
-			 * 32 bit, either memory or I/O space.
-			 */
-			i += 4;
-		}
-	}
-
-	/*
-	 * Handle ROM BAR. We do not use the common
-	 * resource allocator function because we need to
-	 * return reg spec to the caller.
-	 */
-	size = (~(PCI_BASE_ROM_ADDR_M & fc_request)) + 1;
-
-	DEBUG3("BASE register [0x%x] asks for "
-	    "[0x%x]=[0x%x]\n", PCI_CONF_ROM, fc_request, size);
-
-	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
-
-	req.ra_boundbase = 0;
-	req.ra_boundlen = PCICFG_4GIG_LIMIT;
-	req.ra_len = size;
-	req.ra_flags |= NDI_RA_ALIGN_SIZE;
-	req.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
-
-	if (ndi_ra_alloc(ddi_get_parent(dip),
-	    &req, &mem_answer, &mem_alen,
-	    NDI_RA_TYPE_MEM, NDI_RA_PASS)) {
-		cmn_err(CE_WARN, "failed to allocate %d bytes"
-		    " for dev %s ROM BASE register\n",
-		    size, DEVI(dip)->devi_name);
-		goto failure;
-	}
-
-	DEBUG3("ROM addr = [0x%x.%x] len [0x%x]\n",
-	    PCICFG_HIADDR(mem_answer),
-	    PCICFG_LOADDR(mem_answer), mem_alen);
-
-	/*
-	 * Assign address space and enable ROM.
-	 */
-	pci_config_put32(h, PCI_CONF_ROM,
-	    PCICFG_LOADDR(mem_answer) | PCI_BASE_ROM_ENABLE);
-
-	/*
-	 * Add resource to assigned-addresses.
-	 */
-	phys_spec.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, \
-	    PCI_CONF_ROM) | PCI_ADDR_MEM32;
-	if (fc_request & PCI_BASE_PREF_M)
-		phys_spec.pci_phys_hi |= PCI_REG_PF_M;
-	phys_spec.pci_phys_mid = 0;
-	phys_spec.pci_phys_low = PCICFG_LOADDR(mem_answer);
-	phys_spec.pci_size_hi = 0;
-	phys_spec.pci_size_low = size;
-
-	if (pcicfg_update_assigned_prop(dip, &phys_spec)
-	    != PCICFG_SUCCESS) {
-		cmn_err(CE_WARN, "failed to update"
-		    " assigned-address property for dev %s\n",
-		    DEVI(dip)->devi_name);
-		goto failure;
-	}
-	/*
-	 * Copy out the reg spec.
-	 */
-	*rom_regspec = phys_spec;
-
-	return (PCICFG_SUCCESS);
-
-failure:
-	/*
-	 * We came in with no "assigned-addresses".
-	 * Free up the resources we may have allocated.
-	 */
-	(void) pcicfg_free_device_resources(dip);
-
-	return (PCICFG_FAILURE);
-}
-
-#endif /* PCICFG_INTERPRET_FCODE */
-
-static int
-pcicfg_free_all_resources(dev_info_t *dip)
-{
-	pci_regspec_t		*assigned;
-	int			assigned_len;
-	int			acount;
-	int			i;
-
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
-	    &assigned_len) != DDI_PROP_SUCCESS) {
-		DEBUG0("Failed to read assigned-addresses property\n");
-		return (PCICFG_FAILURE);
-	}
-
-	acount = assigned_len / sizeof (pci_regspec_t);
-
-	for (i = 0; i < acount; i++) {
-		if (pcicfg_free_resource(dip, assigned[i])) {
-			/*
-			 * Dont forget to free mem from ddi_getlongprop
-			 */
-			kmem_free((caddr_t)assigned, assigned_len);
-			return (PCICFG_FAILURE);
-		}
-	}
-
-	/*
-	 * Don't forget to free up memory from ddi_getlongprop
-	 */
-	if (assigned_len)
-		kmem_free((caddr_t)assigned, assigned_len);
-
-	return (PCICFG_SUCCESS);
-}
-static int
-pcicfg_alloc_new_resources(dev_info_t *dip)
-{
-	pci_regspec_t		*assigned, *reg;
-	int			assigned_len, reg_len;
-	int			acount, rcount;
-	int			i, j, alloc_size;
-	boolean_t		alloc;
-
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
-	    &reg_len) != DDI_PROP_SUCCESS) {
-		DEBUG0("Failed to read reg property\n");
-		return (PCICFG_FAILURE);
-	}
-	rcount = reg_len / sizeof (pci_regspec_t);
-
-	DEBUG2("pcicfg_alloc_new_resources() reg size=%x entries=%x\n",
-	    reg_len, rcount);
-
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
-	    &assigned_len) != DDI_PROP_SUCCESS) {
-		acount = 0;
-	} else {
-		acount = assigned_len / sizeof (pci_regspec_t);
-	}
-
-	DEBUG1("assigned-addresses property len=%x\n", acount);
-
-	/*
-	 * For each address described by reg, search for it in the
-	 * assigned-addresses property. If it does not exist, allocate
-	 * resources for it. If it does exist, check the size in both.
-	 * The size needs to be bigger of the two.
-	 */
-	for (i = 1; i < rcount; i++) {
-		alloc = B_TRUE;
-		alloc_size = reg[i].pci_size_low;
-		for (j = 0; j < acount; j++) {
-			if (assigned[j].pci_phys_hi == reg[i].pci_phys_hi) {
-				/*
-				 * There is an exact match. Check size.
-				 */
-				DEBUG1("pcicfg_alloc_new_resources "
-				    "- %x - MATCH\n",
-				    reg[i].pci_phys_hi);
-
-				if (reg[i].pci_size_low >
-				    assigned[j].pci_size_low) {
-					/*
-					 * Fcode wants more.
-					 */
-					DEBUG3("pcicfg_alloc_new_resources"
-					    " - %x - RESIZE"
-					    " assigned 0x%x reg 0x%x\n",
-					    assigned[j].pci_phys_hi,
-					    assigned[j].pci_size_low,
-					    reg[i].pci_size_low);
-
-					/*
-					 * Free the old resource.
-					 */
-					(void) pcicfg_free_resource(dip,
-					    assigned[j]);
-				} else {
-					DEBUG3("pcicfg_alloc_new_resources"
-					    " - %x - ENOUGH"
-					    " assigned 0x%x reg 0x%x\n",
-					    assigned[j].pci_phys_hi,
-					    assigned[j].pci_size_low,
-					    reg[i].pci_size_low);
-
-					alloc = B_FALSE;
-				}
-				break;
-			}
-			/*
-			 * Fcode may have set one or more of the
-			 * NPT bits in phys.hi.
-			 */
-			if (PCI_REG_BDFR_G(assigned[j].pci_phys_hi) ==
-			    PCI_REG_BDFR_G(reg[i].pci_phys_hi)) {
-
-				DEBUG2("pcicfg_alloc_new_resources "
-				    "- PARTIAL MATCH assigned 0x%x "
-				    "reg 0x%x\n", assigned[j].pci_phys_hi,
-				    reg[i].pci_phys_hi);
-				/*
-				 * Changing the SS bits is an error
-				 */
-				if (PCI_REG_ADDR_G(
-				    assigned[j].pci_phys_hi) !=
-				    PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
-
-					DEBUG2("Fcode changing"
-					    " SS bits of - 0x%x -"
-					    " on %s\n", reg[i].pci_phys_hi,
-					    DEVI(dip)->devi_name);
-
-				}
-
-
-				/*
-				 * We are going to allocate new resource.
-				 * Free the old resource. Again, adjust
-				 * the size to be safe.
-				 */
-				(void) pcicfg_free_resource(dip, assigned[j]);
-
-				alloc_size = MAX(reg[i].pci_size_low,
-				    assigned[j].pci_size_low);
-
-				break;
-			}
-		}
-		/*
-		 * We are allocating resources for one of three reasons -
-		 * - Fcode wants a larger address space
-		 * - Fcode has set changed/set n, p, t bits.
-		 * - It is a new "reg", it should be only ROM bar, but
-		 *   we don't do the checking.
-		 */
-		if (alloc == B_TRUE) {
-			DEBUG1("pcicfg_alloc_new_resources : creating 0x%x\n",
-			    reg[i].pci_phys_hi);
-
-			reg[i].pci_size_low = alloc_size;
-			if (pcicfg_alloc_resource(dip, reg[i])) {
-				/*
-				 * Dont forget to free mem from
-				 * ddi_getlongprop
-				 */
-				if (acount != 0)
-					kmem_free((caddr_t)assigned,
-					    assigned_len);
-				kmem_free((caddr_t)reg, reg_len);
-				return (PCICFG_FAILURE);
-			}
-		}
-	}
-
-	/*
-	 * Don't forget to free up memory from ddi_getlongprop
-	 */
-	if (acount != 0)
-		kmem_free((caddr_t)assigned, assigned_len);
-	kmem_free((caddr_t)reg, reg_len);
-
-	return (PCICFG_SUCCESS);
-}
-static int
-pcicfg_alloc_resource(dev_info_t *dip, pci_regspec_t phys_spec)
-{
-	uint64_t answer;
-	uint64_t alen;
-	int offset;
-	pci_regspec_t config;
-	caddr_t virt, v;
-	ddi_device_acc_attr_t acc;
-	ddi_acc_handle_t h;
-	ndi_ra_request_t request;
-	pci_regspec_t *assigned;
-	int assigned_len, entries, i;
-
-	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
-	    &assigned_len) == DDI_PROP_SUCCESS) {
-		DEBUG0("pcicfg_alloc_resource - "
-		    "searching assigned-addresses\n");
-
-		entries = assigned_len / (sizeof (pci_regspec_t));
-
-		/*
-		 * Walk through the assigned-addresses entries. If there is
-		 * a match, there is no need to allocate the resource.
-		 */
-		for (i = 0; i < entries; i++) {
-			if (assigned[i].pci_phys_hi == phys_spec.pci_phys_hi) {
-				DEBUG1("pcicfg_alloc_resource - MATCH %x\n",
-				    assigned[i].pci_phys_hi);
-				kmem_free(assigned, assigned_len);
-				return (0);
-			}
-		}
-		kmem_free(assigned, assigned_len);
-	}
-
-	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
-
-	config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
-	config.pci_phys_hi &= ~PCI_REG_REG_M;
-	config.pci_phys_mid = config.pci_phys_low = 0;
-	config.pci_size_hi = config.pci_size_low = 0;
-
-	/*
-	 * Map in configuration space (temporarily)
-	 */
-	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
-	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
-	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
-
-	if (pcicfg_map_phys(dip, &config, &virt, &acc, &h)) {
-		DEBUG0("Can not map in config space\n");
-		return (1);
-	}
-
-	request.ra_flags |= NDI_RA_ALIGN_SIZE;
-	request.ra_boundbase = 0;
-	request.ra_boundlen = PCICFG_4GIG_LIMIT;
-	/*
-	 * Use size stored in phys_spec parameter.
-	 */
-	request.ra_len = phys_spec.pci_size_low;
-
-	offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
-
-	v = virt + offset;
-
-	if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
-
-		request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
-
-		/* allocate memory space from the allocator */
-
-		if (ndi_ra_alloc(ddi_get_parent(dip),
-		    &request, &answer, &alen,
-		    NDI_RA_TYPE_MEM, NDI_RA_PASS)
-		    != NDI_SUCCESS) {
-			DEBUG0("(ROM)Failed to allocate 32b mem");
-			pcicfg_unmap_phys(&h, &config);
-			return (1);
-		}
-		DEBUG3("ROM addr = [0x%x.%x] len [0x%x]\n",
-		    PCICFG_HIADDR(answer),
-		    PCICFG_LOADDR(answer),
-		    alen);
-
-		/* program the low word */
-
-		ddi_put32(h, (uint32_t *)v, (uint32_t)PCICFG_LOADDR(answer));
-
-		phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
-		phys_spec.pci_phys_mid = PCICFG_HIADDR(answer);
-	} else {
-
-		switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
-		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
-			request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
-			/* allocate memory space from the allocator */
-			if (ndi_ra_alloc(ddi_get_parent(dip),
-			    &request, &answer, &alen,
-			    NDI_RA_TYPE_MEM, NDI_RA_PASS)
-			    != NDI_SUCCESS) {
-				DEBUG0("Failed to allocate 64b mem\n");
-				pcicfg_unmap_phys(&h, &config);
-				return (1);
-			}
-			DEBUG3("64 addr = [0x%x.%x] len [0x%x]\n",
-			    PCICFG_HIADDR(answer),
-			    PCICFG_LOADDR(answer),
-			    alen);
-
-			/* program the low word */
-
-			ddi_put32(h, (uint32_t *)v,
-			    (uint32_t)PCICFG_LOADDR(answer));
-
-			/* program the high word with value zero */
-			v += 4;
-			ddi_put32(h, (uint32_t *)v,
-			    (uint32_t)PCICFG_HIADDR(answer));
-
-			phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
-			phys_spec.pci_phys_mid = PCICFG_HIADDR(answer);
-			/*
-			 * currently support 32b address space
-			 * assignments only.
-			 */
-			phys_spec.pci_phys_hi ^= PCI_ADDR_MEM64 ^
-			    PCI_ADDR_MEM32;
-
-			break;
-
-		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
-			request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
-			/* allocate memory space from the allocator */
-			if (ndi_ra_alloc(ddi_get_parent(dip),
-			    &request, &answer, &alen,
-			    NDI_RA_TYPE_MEM, NDI_RA_PASS)
-			    != NDI_SUCCESS) {
-				DEBUG0("Failed to allocate 32b mem\n");
-				pcicfg_unmap_phys(&h, &config);
-				return (1);
-			}
-
-			DEBUG3("32 addr = [0x%x.%x] len [0x%x]\n",
-			    PCICFG_HIADDR(answer),
-			    PCICFG_LOADDR(answer),
-			    alen);
-
-			/* program the low word */
-
-			ddi_put32(h, (uint32_t *)v,
-			    (uint32_t)PCICFG_LOADDR(answer));
-
-			phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
-
-			break;
-		case PCI_REG_ADDR_G(PCI_ADDR_IO):
-			/* allocate I/O space from the allocator */
-			request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
-			if (ndi_ra_alloc(ddi_get_parent(dip),
-			    &request, &answer, &alen,
-			    NDI_RA_TYPE_IO, NDI_RA_PASS)
-			    != NDI_SUCCESS) {
-				DEBUG0("Failed to allocate I/O\n");
-				pcicfg_unmap_phys(&h, &config);
-				return (1);
-			}
-			DEBUG3("I/O addr = [0x%x.%x] len [0x%x]\n",
-			    PCICFG_HIADDR(answer),
-			    PCICFG_LOADDR(answer),
-			    alen);
-
-			ddi_put32(h, (uint32_t *)v,
-			    (uint32_t)PCICFG_LOADDR(answer));
-
-			phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
-
-			break;
-		default:
-			DEBUG0("Unknown register type\n");
-			pcicfg_unmap_phys(&h, &config);
-			return (1);
-		} /* switch */
-	}
-
-	/*
-	 * Now that memory locations are assigned,
-	 * update the assigned address property.
-	 */
-
-	DEBUG1("updating assigned-addresss for %x\n",  phys_spec.pci_phys_hi);
-
-	if (pcicfg_update_assigned_prop(dip, &phys_spec)) {
-		pcicfg_unmap_phys(&h, &config);
-		return (1);
-	}
-
-	pcicfg_unmap_phys(&h, &config);
-
-	return (0);
-}
-
-static int
-pcicfg_free_resource(dev_info_t *dip, pci_regspec_t phys_spec)
-{
-	int offset;
-	pci_regspec_t config;
-	caddr_t virt, v;
-	ddi_device_acc_attr_t acc;
-	ddi_acc_handle_t h;
-	ndi_ra_request_t request;
-	int l;
-
-	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
-
-	config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
-	config.pci_phys_hi &= ~PCI_REG_REG_M;
-	config.pci_phys_mid = config.pci_phys_low = 0;
-	config.pci_size_hi = config.pci_size_low = 0;
-
-	/*
-	 * Map in configuration space (temporarily)
-	 */
-	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
-	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
-	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
-
-	if (pcicfg_map_phys(dip, &config, &virt, &acc, &h)) {
-		DEBUG0("Can not map in config space\n");
-		return (1);
-	}
-
-	offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
-
-	v = virt + offset;
-
-	/*
-	 * Use size stored in phys_spec parameter.
-	 */
-	l = phys_spec.pci_size_low;
-
-	if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
-
-		/* free memory back to the allocator */
-		if (ndi_ra_free(ddi_get_parent(dip), phys_spec.pci_phys_low,
-		    l, NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
-			DEBUG0("(ROM)Can not free 32b mem");
-			pcicfg_unmap_phys(&h, &config);
-			return (1);
-		}
-
-		/* Unmap the BAR by writing a zero */
-
-		ddi_put32(h, (uint32_t *)v, (uint32_t)0);
-	} else {
-
-		switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
-		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
-			/* free memory back to the allocator */
-			if (ndi_ra_free(ddi_get_parent(dip),
-			    PCICFG_LADDR(phys_spec.pci_phys_low,
-			    phys_spec.pci_phys_mid),
-			    l, NDI_RA_TYPE_MEM,
-			    NDI_RA_PASS) != NDI_SUCCESS) {
-				DEBUG0("Can not free 64b mem");
-				pcicfg_unmap_phys(&h, &config);
-				return (1);
-			}
-
-			break;
-
-		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
-			/* free memory back to the allocator */
-			if (ndi_ra_free(ddi_get_parent(dip),
-			    phys_spec.pci_phys_low,
-			    l, NDI_RA_TYPE_MEM,
-			    NDI_RA_PASS) != NDI_SUCCESS) {
-				DEBUG0("Can not free 32b mem");
-				pcicfg_unmap_phys(&h, &config);
-				return (1);
-			}
-
-			break;
-		case PCI_REG_ADDR_G(PCI_ADDR_IO):
-			/* free I/O space back to the allocator */
-			if (ndi_ra_free(ddi_get_parent(dip),
-			    phys_spec.pci_phys_low,
-			    l, NDI_RA_TYPE_IO,
-			    NDI_RA_PASS) != NDI_SUCCESS) {
-				DEBUG0("Can not free I/O space");
-				pcicfg_unmap_phys(&h, &config);
-				return (1);
-			}
-
-			break;
-		default:
-			DEBUG0("Unknown register type\n");
-			pcicfg_unmap_phys(&h, &config);
-			return (1);
-		} /* switch */
-	}
-
-	/*
-	 * Now that memory locations are assigned,
-	 * update the assigned address property.
-	 */
-
-	DEBUG1("updating assigned-addresss for %x\n", phys_spec.pci_phys_hi);
-
-	if (pcicfg_remove_assigned_prop(dip, &phys_spec)) {
-		pcicfg_unmap_phys(&h, &config);
-		return (1);
-	}
-
-	pcicfg_unmap_phys(&h, &config);
-
-	return (0);
-}
-
-static int
-pcicfg_remove_assigned_prop(dev_info_t *dip, pci_regspec_t *oldone)
-{
-	int		alen, num_entries, i;
-	pci_regspec_t	*assigned, *assigned_copy;
-	uint_t		status;
-
-	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
-	    "assigned-addresses", (caddr_t)&assigned, &alen);
-	switch (status) {
-		case DDI_PROP_SUCCESS:
-		break;
-		case DDI_PROP_NO_MEMORY:
-			DEBUG0("no memory for assigned-addresses property\n");
-			return (1);
-		default:
-			DEBUG0("assigned-addresses property does not exist\n");
-			return (0);
-	}
-
-	/*
-	 * Make a copy of old assigned-addresses property.
-	 */
-	assigned_copy = kmem_alloc(alen, KM_SLEEP);
-	bcopy(assigned, assigned_copy, alen);
-
-	status = ndi_prop_remove(DDI_DEV_T_NONE, dip, "assigned-addresses");
-
-	if (status != DDI_PROP_SUCCESS) {
-		/*
-		 * If "assigned-addresses" is retrieved from PROM, the
-		 * ndi_prop_remove() will fail.
-		 */
-		DEBUG1("pcicfg_remove_assigned_prop: 0x%x not removed\n",
-		    oldone->pci_phys_hi);
-
-		/*
-		 * Free up allocated memory
-		 */
-		kmem_free(assigned_copy, alen);
-		kmem_free((caddr_t)assigned, alen);
-
-		return (0);
-	}
-
-	num_entries = alen / sizeof (pci_regspec_t);
-
-	/*
-	 * Rebuild the assigned-addresses property.
-	 */
-	for (i = 0; i < num_entries; i++) {
-		if (assigned_copy[i].pci_phys_hi != oldone->pci_phys_hi) {
-			(void) pcicfg_update_assigned_prop(dip,
-			    &assigned_copy[i]);
-		}
-	}
-
-	/*
-	 * Free the copy of the original assigned-addresses.
-	 */
-	kmem_free(assigned_copy, alen);
-
-	/*
-	 * Don't forget to free up memory from ddi_getlongprop
-	 */
-	kmem_free((caddr_t)assigned, alen);
-
-	return (0);
-}
-
-static int
-pcicfg_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
-	caddr_t *addrp, ddi_device_acc_attr_t *accattrp,
-	ddi_acc_handle_t *handlep)
-{
-	ddi_map_req_t mr;
-	ddi_acc_hdl_t *hp;
-	int result;
-
-	*handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
-	hp = impl_acc_hdl_get(*handlep);
-	hp->ah_vers = VERS_ACCHDL;
-	hp->ah_dip = dip;
-	hp->ah_rnumber = 0;
-	hp->ah_offset = 0;
-	hp->ah_len = 0;
-	hp->ah_acc = *accattrp;
-
-	mr.map_op = DDI_MO_MAP_LOCKED;
-	mr.map_type = DDI_MT_REGSPEC;
-	mr.map_obj.rp = (struct regspec *)phys_spec;
-	mr.map_prot = PROT_READ | PROT_WRITE;
-	mr.map_flags = DDI_MF_KERNEL_MAPPING;
-	mr.map_handlep = hp;
-	mr.map_vers = DDI_MAP_VERSION;
-
-	result = ddi_map(dip, &mr, 0, 0, addrp);
-
-	if (result != DDI_SUCCESS) {
-		impl_acc_hdl_free(*handlep);
-		*handlep = (ddi_acc_handle_t)NULL;
-	} else {
-		hp->ah_addr = *addrp;
-	}
-
-	return (result);
-}
-
-void
-pcicfg_unmap_phys(ddi_acc_handle_t *handlep,  pci_regspec_t *ph)
-{
-	ddi_map_req_t mr;
-	ddi_acc_hdl_t *hp;
-
-	hp = impl_acc_hdl_get(*handlep);
-	ASSERT(hp);
-
-	mr.map_op = DDI_MO_UNMAP;
-	mr.map_type = DDI_MT_REGSPEC;
-	mr.map_obj.rp = (struct regspec *)ph;
-	mr.map_prot = PROT_READ | PROT_WRITE;
-	mr.map_flags = DDI_MF_KERNEL_MAPPING;
-	mr.map_handlep = hp;
-	mr.map_vers = DDI_MAP_VERSION;
-
-	(void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
-	    hp->ah_len, &hp->ah_addr);
-
-	impl_acc_hdl_free(*handlep);
-	*handlep = (ddi_acc_handle_t)NULL;
-}
-#ifdef DEBUG
-static void
-debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
-	uintptr_t a4, uintptr_t a5)
-{
-	if (pcicfg_debug == 1) {
-		prom_printf("pcicfg: ");
-		prom_printf(fmt, a1, a2, a3, a4, a5);
-	} else
-		if (pcicfg_debug)
-			cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
-}
-#endif
--- a/usr/src/uts/sun4/io/px/px.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px.c	Mon Nov 02 15:58:28 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * PCI Express nexus driver interface
+ * SPARC Host to PCI Express nexus driver
  */
 
 #include <sys/types.h>
@@ -33,14 +33,12 @@
 #include <sys/kmem.h>
 #include <sys/sunddi.h>
 #include <sys/sunndi.h>
-#include <sys/ddi_impldefs.h>
 #include <sys/ddi_subrdefs.h>
 #include <sys/spl.h>
 #include <sys/epm.h>
 #include <sys/iommutsb.h>
-#include <sys/hotplug/pci/pcihp.h>
-#include <sys/hotplug/pci/pciehpc.h>
 #include "px_obj.h"
+#include <sys/hotplug/pci/pcie_hp.h>
 #include <sys/pci_tools.h>
 #include "px_tools_ext.h"
 #include <sys/pcie_pwr.h>
@@ -64,12 +62,6 @@
 extern int pcie_max_mps;
 
 /*
- * function prototypes for hotplug routines:
- */
-static int px_init_hotplug(px_t *px_p);
-static int px_uninit_hotplug(dev_info_t *dip);
-
-/*
  * bus ops and dev ops structures:
  */
 static struct bus_ops px_bus_ops = {
@@ -101,7 +93,8 @@
 	px_bus_enter,		/* (*bus_fm_access_enter)(); */
 	px_bus_exit,		/* (*bus_fm_access_fini)(); */
 	pcie_bus_power,		/* (*bus_power)(); */
-	px_intr_ops		/* (*bus_intr_op)(); */
+	px_intr_ops,		/* (*bus_intr_op)(); */
+	pcie_hp_common_ops	/* (*bus_hp_op)(); */
 };
 
 extern struct cb_ops px_cb_ops;
@@ -128,9 +121,13 @@
 extern struct mod_ops mod_driverops;
 
 static struct modldrv modldrv = {
-	&mod_driverops, 		/* Type of module - driver */
-	"PCI Express nexus driver",	/* Name of module. */
-	&px_ops,			/* driver ops */
+	&mod_driverops, 			/* Type of module - driver */
+#if defined(sun4u)
+	"Sun4u Host to PCIe nexus driver",	/* Name of module. */
+#elif defined(sun4v)
+	"Sun4v Host to PCIe nexus driver",	/* Name of module. */
+#endif
+	&px_ops,				/* driver ops */
 };
 
 static struct modlinkage modlinkage = {
@@ -189,31 +186,29 @@
 static int
 px_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
 {
-	int	instance = getminor((dev_t)arg);
+	minor_t	minor = getminor((dev_t)arg);
+	int	instance = PCI_MINOR_NUM_TO_INSTANCE(minor);
 	px_t	*px_p = INST_TO_STATE(instance);
+	int	ret = DDI_SUCCESS;
 
-	/*
-	 * Allow hotplug to deal with ones it manages
-	 * Hot Plug will be done later.
-	 */
-	if (px_p && (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE))
-		return (pcihp_info(dip, infocmd, arg, result));
-
-	/* non-hotplug or not attached */
 	switch (infocmd) {
 	case DDI_INFO_DEVT2INSTANCE:
 		*result = (void *)(intptr_t)instance;
-		return (DDI_SUCCESS);
-
+		break;
 	case DDI_INFO_DEVT2DEVINFO:
-		if (px_p == NULL)
-			return (DDI_FAILURE);
+		if (px_p == NULL) {
+			ret = DDI_FAILURE;
+			break;
+		}
+
 		*result = (void *)px_p->px_dip;
-		return (DDI_SUCCESS);
-
+		break;
 	default:
-		return (DDI_FAILURE);
+		ret = DDI_FAILURE;
+		break;
 	}
+
+	return (ret);
 }
 
 /* device driver entry points */
@@ -228,6 +223,7 @@
 	int		instance = DIP_TO_INST(dip);
 	int		ret = DDI_SUCCESS;
 	devhandle_t	dev_hdl = NULL;
+	pcie_hp_regops_t regops;
 
 	switch (cmd) {
 	case DDI_ATTACH:
@@ -245,14 +241,14 @@
 		px_p = INST_TO_STATE(instance);
 		px_p->px_dip = dip;
 		mutex_init(&px_p->px_mutex, NULL, MUTEX_DRIVER, NULL);
-		px_p->px_soft_state = PX_SOFT_STATE_CLOSED;
-		px_p->px_open_count = 0;
+		px_p->px_soft_state = PCI_SOFT_STATE_CLOSED;
 
 		(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
 		    "device_type", "pciex");
 
 		/* Initialize px_dbg for high pil printing */
 		px_dbg_attach(dip, &px_p->px_dbg_hdl);
+		pcie_rc_init_bus(dip);
 
 		/*
 		 * Get key properties of the pci bridge node and
@@ -311,20 +307,16 @@
 		if ((ret = px_err_add_intr(&px_p->px_fault)) != DDI_SUCCESS)
 			goto err_bad_intr;
 
-		(void) px_init_hotplug(px_p);
+		if (px_lib_hotplug_init(dip, (void *)&regops) == DDI_SUCCESS) {
+			pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
+
+			bus_p->bus_hp_sup_modes |= PCIE_NATIVE_HP_MODE;
+		}
 
 		(void) px_set_mps(px_p);
 
-		/*
-		 * Create the "devctl" node for hotplug and pcitool support.
-		 * For non-hotplug bus, we still need ":devctl" to
-		 * support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls.
-		 */
-		if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
-		    PCIHP_AP_MINOR_NUM(instance, PCIHP_DEVCTL_MINOR),
-		    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
-			goto err_bad_devctl_node;
-		}
+		if (pcie_init(dip, (caddr_t)&regops) != DDI_SUCCESS)
+			goto err_bad_hotplug;
 
 		if (pxtool_init(dip) != DDI_SUCCESS)
 			goto err_bad_pcitool_node;
@@ -353,8 +345,9 @@
 		break;
 
 err_bad_pcitool_node:
-		ddi_remove_minor_node(dip, "devctl");
-err_bad_devctl_node:
+		(void) pcie_uninit(dip);
+err_bad_hotplug:
+		(void) px_lib_hotplug_uninit(dip);
 		px_err_rem_intr(&px_p->px_fault);
 err_bad_intr:
 		px_fm_detach(px_p);
@@ -377,6 +370,7 @@
 err_bad_dev_init:
 		px_free_props(px_p);
 err_bad_px_prop:
+		pcie_rc_fini_bus(dip);
 		px_dbg_detach(dip, &px_p->px_dbg_hdl);
 		mutex_destroy(&px_p->px_mutex);
 		ddi_soft_state_free(px_state_p, instance);
@@ -423,9 +417,10 @@
 static int
 px_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 {
-	int instance = ddi_get_instance(dip);
-	px_t *px_p = INST_TO_STATE(instance);
-	int ret;
+	int		instance = ddi_get_instance(dip);
+	px_t		*px_p = INST_TO_STATE(instance);
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
+	int		ret;
 
 	/*
 	 * Make sure we are currently attached
@@ -446,11 +441,13 @@
 		 */
 		px_cpr_rem_callb(px_p);
 
-		if (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE)
-			if (px_uninit_hotplug(dip) != DDI_SUCCESS) {
-				mutex_exit(&px_p->px_mutex);
-				return (DDI_FAILURE);
-			}
+		if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p))
+			(void) px_lib_hotplug_uninit(dip);
+
+		if (pcie_uninit(dip) != DDI_SUCCESS) {
+			mutex_exit(&px_p->px_mutex);
+			return (DDI_FAILURE);
+		}
 
 		/*
 		 * things which used to be done in obj_destroy
@@ -461,7 +458,6 @@
 
 		pxtool_uninit(dip);
 
-		ddi_remove_minor_node(dip, "devctl");
 		px_err_rem_intr(&px_p->px_fault);
 		px_fm_detach(px_p);
 		px_pec_detach(px_p);
@@ -481,21 +477,11 @@
 		 * resources it's using.
 		 */
 		px_free_props(px_p);
+		pcie_rc_fini_bus(dip);
 		px_dbg_detach(dip, &px_p->px_dbg_hdl);
 		mutex_exit(&px_p->px_mutex);
 		mutex_destroy(&px_p->px_mutex);
 
-		/* Free the interrupt-priorities prop if we created it. */
-		{
-			int len;
-
-			if (ddi_getproplen(DDI_DEV_T_ANY, dip,
-			    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
-			    "interrupt-priorities", &len) == DDI_PROP_SUCCESS)
-				(void) ddi_prop_remove(DDI_DEV_T_NONE, dip,
-				    "interrupt-priorities");
-		}
-
 		px_p->px_dev_hdl = NULL;
 		ddi_soft_state_free(px_state_p, instance);
 
@@ -1370,81 +1356,6 @@
 	return (ret);
 }
 
-static int
-px_init_hotplug(px_t *px_p)
-{
-	px_bus_range_t bus_range;
-	dev_info_t *dip;
-	pciehpc_regops_t regops;
-
-	dip = px_p->px_dip;
-
-	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
-	    "hotplug-capable") == 0)
-		return (DDI_FAILURE);
-
-	/*
-	 * Before initializing hotplug - open up bus range.  The busra
-	 * module will initialize its pool of bus numbers from this.
-	 * "busra" will be the agent that keeps track of them during
-	 * hotplug.  Also, note, that busra will remove any bus numbers
-	 * already in use from boot time.
-	 */
-	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
-	    "bus-range") == 0) {
-		cmn_err(CE_WARN, "%s%d: bus-range not found\n",
-		    ddi_driver_name(dip), ddi_get_instance(dip));
-#ifdef	DEBUG
-		bus_range.lo = 0x0;
-		bus_range.hi = 0xff;
-
-		if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
-		    dip, "bus-range", (int *)&bus_range, 2)
-		    != DDI_PROP_SUCCESS) {
-			return (DDI_FAILURE);
-		}
-#else
-		return (DDI_FAILURE);
-#endif
-	}
-
-	if (px_lib_hotplug_init(dip, (void *)&regops) != DDI_SUCCESS)
-		return (DDI_FAILURE);
-
-	if (pciehpc_init(dip, &regops) != DDI_SUCCESS) {
-		px_lib_hotplug_uninit(dip);
-		return (DDI_FAILURE);
-	}
-
-	if (pcihp_init(dip) != DDI_SUCCESS) {
-		(void) pciehpc_uninit(dip);
-		px_lib_hotplug_uninit(dip);
-		return (DDI_FAILURE);
-	}
-
-	if (pcihp_get_cb_ops() != NULL) {
-		DBG(DBG_ATTACH, dip, "%s%d hotplug enabled",
-		    ddi_driver_name(dip), ddi_get_instance(dip));
-		px_p->px_dev_caps |= PX_HOTPLUG_CAPABLE;
-	}
-
-	return (DDI_SUCCESS);
-}
-
-static int
-px_uninit_hotplug(dev_info_t *dip)
-{
-	if (pcihp_uninit(dip) != DDI_SUCCESS)
-		return (DDI_FAILURE);
-
-	if (pciehpc_uninit(dip) != DDI_SUCCESS)
-		return (DDI_FAILURE);
-
-	px_lib_hotplug_uninit(dip);
-
-	return (DDI_SUCCESS);
-}
-
 static void
 px_set_mps(px_t *px_p)
 {
--- a/usr/src/uts/sun4/io/px/px_devctl.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_devctl.c	Mon Nov 02 15:58:28 2009 +0800
@@ -38,7 +38,6 @@
 #include <sys/errno.h>
 #include <sys/file.h>
 #include <sys/policy.h>
-#include <sys/hotplug/pci/pcihp.h>
 #include "px_obj.h"
 #include <sys/pci_tools.h>
 #include "px_tools_ext.h"
@@ -50,8 +49,6 @@
 static int px_close(dev_t dev, int flags, int otyp, cred_t *credp);
 static int px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
 						cred_t *credp, int *rvalp);
-static int px_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
-    int flags, char *name, caddr_t valuep, int *lengthp);
 
 struct cb_ops px_cb_ops = {
 	px_open,			/* open */
@@ -66,7 +63,7 @@
 	nodev,				/* mmap */
 	nodev,				/* segmap */
 	nochpoll,			/* poll */
-	px_prop_op,			/* cb_prop_op */
+	pcie_prop_op,			/* cb_prop_op */
 	NULL,				/* streamtab */
 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
 	CB_REV,				/* rev */
@@ -78,9 +75,9 @@
 static int
 px_open(dev_t *devp, int flags, int otyp, cred_t *credp)
 {
-	px_t *px_p;
-	int rval;
-	uint_t orig_px_soft_state;
+	px_t		*px_p = PX_DEV_TO_SOFTSTATE(*devp);
+	int		minor = getminor(*devp);
+	int		rval;
 
 	/*
 	 * Make sure the open is for the right file type.
@@ -91,41 +88,44 @@
 	/*
 	 * Get the soft state structure for the device.
 	 */
-	px_p = PX_DEV_TO_SOFTSTATE(*devp);
 	if (px_p == NULL)
 		return (ENXIO);
 
+	DBG(DBG_OPEN, px_p->px_dip, "devp=%x: flags=%x\n", devp, flags);
+
 	/*
 	 * Handle the open by tracking the device state.
 	 */
-	DBG(DBG_OPEN, px_p->px_dip, "devp=%x: flags=%x\n", devp, flags);
 	mutex_enter(&px_p->px_mutex);
-	orig_px_soft_state = px_p->px_soft_state;
+
+	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
+	case PCI_TOOL_REG_MINOR_NUM:
+	case PCI_TOOL_INTR_MINOR_NUM:
+		break;
+	default:
+		/* To handle devctl and hotplug related ioctls */
+		if (rval = pcie_open(px_p->px_dip, devp, flags, otyp, credp)) {
+			mutex_exit(&px_p->px_mutex);
+			return (rval);
+		}
+	}
+
 	if (flags & FEXCL) {
-		if (px_p->px_soft_state != PX_SOFT_STATE_CLOSED) {
+		if (px_p->px_soft_state != PCI_SOFT_STATE_CLOSED) {
 			mutex_exit(&px_p->px_mutex);
 			DBG(DBG_OPEN, px_p->px_dip, "busy\n");
 			return (EBUSY);
 		}
-		px_p->px_soft_state = PX_SOFT_STATE_OPEN_EXCL;
+		px_p->px_soft_state = PCI_SOFT_STATE_OPEN_EXCL;
 	} else {
-		if (px_p->px_soft_state == PX_SOFT_STATE_OPEN_EXCL) {
+		if (px_p->px_soft_state == PCI_SOFT_STATE_OPEN_EXCL) {
 			mutex_exit(&px_p->px_mutex);
 			DBG(DBG_OPEN, px_p->px_dip, "busy\n");
 			return (EBUSY);
 		}
-		px_p->px_soft_state = PX_SOFT_STATE_OPEN;
+		px_p->px_soft_state = PCI_SOFT_STATE_OPEN;
 	}
 
-	if (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE)
-		if (rval = (pcihp_get_cb_ops())->cb_open(devp, flags,
-		    otyp, credp)) {
-			px_p->px_soft_state = orig_px_soft_state;
-			mutex_exit(&px_p->px_mutex);
-			return (rval);
-		}
-
-	px_p->px_open_count++;
 	mutex_exit(&px_p->px_mutex);
 	return (0);
 }
@@ -135,28 +135,32 @@
 static int
 px_close(dev_t dev, int flags, int otyp, cred_t *credp)
 {
-	px_t *px_p;
-	int rval;
+	px_t		*px_p = PX_DEV_TO_SOFTSTATE(dev);
+	int		minor = getminor(dev);
+	int		rval;
 
 	if (otyp != OTYP_CHR)
 		return (EINVAL);
 
-	px_p = PX_DEV_TO_SOFTSTATE(dev);
 	if (px_p == NULL)
 		return (ENXIO);
 
 	DBG(DBG_CLOSE, px_p->px_dip, "dev=%x: flags=%x\n", dev, flags);
 	mutex_enter(&px_p->px_mutex);
 
-	if (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE)
-		if (rval = (pcihp_get_cb_ops())->cb_close(dev, flags,
-		    otyp, credp)) {
+	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
+	case PCI_TOOL_REG_MINOR_NUM:
+	case PCI_TOOL_INTR_MINOR_NUM:
+		break;
+	default:
+		/* To handle devctl and hotplug related ioctls */
+		if (rval = pcie_close(px_p->px_dip, dev, flags, otyp, credp)) {
 			mutex_exit(&px_p->px_mutex);
 			return (rval);
 		}
+	}
 
-	px_p->px_soft_state = PX_SOFT_STATE_CLOSED;
-	px_p->px_open_count = 0;
+	px_p->px_soft_state = PCI_SOFT_STATE_CLOSED;
 	mutex_exit(&px_p->px_mutex);
 	return (0);
 }
@@ -165,14 +169,11 @@
 static int
 px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
 {
-	px_t *px_p;
-	dev_info_t *dip;
-	struct devctl_iocdata *dcp;
-	uint_t bus_state;
-	int rv = DDI_SUCCESS;
-	int minor = getminor(dev);
+	px_t		*px_p = PX_DEV_TO_SOFTSTATE(dev);
+	int		minor = getminor(dev);
+	dev_info_t	*dip;
+	int		rv = ENOTTY;
 
-	px_p = PX_DEV_TO_SOFTSTATE(dev);
 	if (px_p == NULL)
 		return (ENXIO);
 
@@ -186,13 +187,11 @@
 	}
 #endif	/* PX_DMA_TEST */
 
-	switch (PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
-
+	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
 	/*
 	 * PCI tools.
 	 */
 	case PCI_TOOL_REG_MINOR_NUM:
-
 		switch (cmd) {
 		case PCITOOL_DEVICE_SET_REG:
 		case PCITOOL_DEVICE_GET_REG:
@@ -220,9 +219,7 @@
 			rv = ENOTTY;
 		}
 		return (rv);
-
 	case PCI_TOOL_INTR_MINOR_NUM:
-
 		switch (cmd) {
 		case PCITOOL_DEVICE_SET_INTR:
 
@@ -243,11 +240,9 @@
 			rv = ENOTTY;
 		}
 		return (rv);
-
 	default:
-		if (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE)
-			return ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd,
-			    arg, mode, credp, rvalp));
+		/* To handle devctl and hotplug related ioctls */
+		rv = pcie_ioctl(dip, dev, cmd, arg, mode, credp, rvalp);
 		break;
 	}
 
@@ -263,72 +258,5 @@
 		return (px_lib_pmctl(cmd, px_p));
 	}
 
-	/*
-	 * We can use the generic implementation for these ioctls
-	 */
-	switch (cmd) {
-	case DEVCTL_DEVICE_GETSTATE:
-	case DEVCTL_DEVICE_ONLINE:
-	case DEVCTL_DEVICE_OFFLINE:
-	case DEVCTL_BUS_GETSTATE:
-		return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0));
-	}
-
-	/*
-	 * read devctl ioctl data
-	 */
-	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
-		return (EFAULT);
-
-	switch (cmd) {
-
-	case DEVCTL_DEVICE_RESET:
-		DBG(DBG_IOCTL, dip, "DEVCTL_DEVICE_RESET\n");
-		rv = ENOTSUP;
-		break;
-
-
-	case DEVCTL_BUS_QUIESCE:
-		DBG(DBG_IOCTL, dip, "DEVCTL_BUS_QUIESCE\n");
-		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
-			if (bus_state == BUS_QUIESCED)
-				break;
-		(void) ndi_set_bus_state(dip, BUS_QUIESCED);
-		break;
-
-	case DEVCTL_BUS_UNQUIESCE:
-		DBG(DBG_IOCTL, dip, "DEVCTL_BUS_UNQUIESCE\n");
-		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
-			if (bus_state == BUS_ACTIVE)
-				break;
-		(void) ndi_set_bus_state(dip, BUS_ACTIVE);
-		break;
-
-	case DEVCTL_BUS_RESET:
-		DBG(DBG_IOCTL, dip, "DEVCTL_BUS_RESET\n");
-		rv = ENOTSUP;
-		break;
-
-	case DEVCTL_BUS_RESETALL:
-		DBG(DBG_IOCTL, dip, "DEVCTL_BUS_RESETALL\n");
-		rv = ENOTSUP;
-		break;
-
-	default:
-		rv = ENOTTY;
-	}
-
-	ndi_dc_freehdl(dcp);
 	return (rv);
 }
-
-static int px_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
-    int flags, char *name, caddr_t valuep, int *lengthp)
-{
-	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
-	    "hotplug-capable"))
-		return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip,
-		    prop_op, flags, name, valuep, lengthp));
-
-	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
-}
--- a/usr/src/uts/sun4/io/px/px_fm.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_fm.c	Mon Nov 02 15:58:28 2009 +0800
@@ -93,9 +93,6 @@
 	mutex_init(&px_p->px_fm_mutex, NULL, MUTEX_DRIVER,
 	    (void *)px_p->px_fm_ibc);
 
-
-	pcie_rc_init_bus(dip);
-
 	px_p->px_pfd_idx = 0;
 	for (i = 0; i < 5; i++)
 		pcie_rc_init_pfd(dip, &px_p->px_pfd_arr[i]);
@@ -126,7 +123,6 @@
 	ddi_fm_fini(px_p->px_dip);
 	for (i = 0; i < 5; i++)
 		pcie_rc_fini_pfd(&px_p->px_pfd_arr[i]);
-	pcie_rc_fini_bus(px_p->px_dip);
 }
 
 /*
@@ -260,7 +256,7 @@
 }
 
 static uint64_t
-px_in_addr_range(dev_info_t *dip, px_ranges_t *ranges_p, uint64_t addr)
+px_in_addr_range(dev_info_t *dip, pci_ranges_t *ranges_p, uint64_t addr)
 {
 	uint64_t	addr_low, addr_high;
 
@@ -294,7 +290,7 @@
 	uint64_t	addr, base_addr;
 	uint64_t	fault_addr = (uint64_t)derr->fme_bus_specific;
 	pcie_req_id_t	bdf = PCIE_INVALID_BDF;
-	px_ranges_t	*ranges_p;
+	pci_ranges_t	*ranges_p;
 	int		range_len;
 
 	/*
@@ -316,7 +312,7 @@
 	 * Make sure this failed load came from this PCIe port.	 Check by
 	 * matching the upper 32 bits of the address with the ranges property.
 	 */
-	range_len = px_p->px_ranges_length / sizeof (px_ranges_t);
+	range_len = px_p->px_ranges_length / sizeof (pci_ranges_t);
 	i = 0;
 	for (ranges_p = px_p->px_ranges_p; i < range_len; i++, ranges_p++) {
 		base_addr = px_in_addr_range(dip, ranges_p, fault_addr);
@@ -797,7 +793,7 @@
 {
 	dev_info_t		*px_dip = PCIE_DIP2BUS(dip)->bus_rp_dip;
 	px_t			*px_p = INST_TO_STATE(ddi_get_instance(px_dip));
-	px_ranges_t		*ranges_p;
+	pci_ranges_t		*ranges_p;
 	int			range_len;
 	ddi_acc_handle_t	ap = (ddi_acc_handle_t)handle;
 	ddi_acc_hdl_t		*hp = impl_acc_hdl_get(ap);
@@ -812,7 +808,7 @@
 
 	/* Normalize the base addr to the addr and strip off the HB info. */
 	base_addr = (hp->ah_pfn << MMU_PAGESHIFT) + hp->ah_offset;
-	range_len = px_p->px_ranges_length / sizeof (px_ranges_t);
+	range_len = px_p->px_ranges_length / sizeof (pci_ranges_t);
 	i = 0;
 	for (ranges_p = px_p->px_ranges_p; i < range_len; i++, ranges_p++) {
 		range_addr = px_in_addr_range(dip, ranges_p, base_addr);
--- a/usr/src/uts/sun4/io/px/px_msi.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_msi.c	Mon Nov 02 15:58:28 2009 +0800
@@ -107,23 +107,8 @@
 
 	DBG(DBG_MSIQ, dip, "px_msi_detach\n");
 
-	if (msi_state_p->msi_pool_p) {
+	if (msi_state_p->msi_pool_p)
 		(void) ndi_irm_destroy(msi_state_p->msi_pool_p);
-	}
-
-	if (msi_state_p->msi_addr64 && msi_state_p->msi_mem_flg) {
-		ndi_ra_free(dip, msi_state_p->msi_addr64,
-		    msi_state_p->msi_addr64_len,
-		    NDI_RA_TYPE_MEM, NDI_RA_PASS);
-	}
-
-	if (msi_state_p->msi_addr32 && msi_state_p->msi_mem_flg) {
-		ndi_ra_free(dip, msi_state_p->msi_addr32,
-		    msi_state_p->msi_addr32_len,
-		    NDI_RA_TYPE_MEM, NDI_RA_PASS);
-
-		pci_resource_destroy(dip);
-	}
 
 	if (msi_state_p->msi_p) {
 		kmem_free(msi_state_p->msi_p,
@@ -336,50 +321,45 @@
 static int
 px_msi_get_props(px_t *px_p)
 {
-	dev_info_t		*dip = px_p->px_dip;
-	px_msi_state_t		*msi_state_p = &px_p->px_ib_p->ib_msi_state;
-	int			ret = DDI_SUCCESS;
-	int			length = sizeof (int);
-	int			*valuep = NULL;
-	uint64_t		msi_addr_hi, msi_addr_lo;
-	uint64_t		mem_answer, mem_alen;
-	ndi_ra_request_t	request;
+	dev_info_t	*dip = px_p->px_dip;
+	px_msi_state_t	*msi_state_p = &px_p->px_ib_p->ib_msi_state;
+	int		length = sizeof (int);
+	int		*valuep = NULL;
+	uint64_t	msi_addr_hi, msi_addr_lo;
 
 	DBG(DBG_MSIQ, dip, "px_msi_get_props\n");
 
 	/* #msi */
 	msi_state_p->msi_cnt = ddi_getprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "#msi", PX_DEFAULT_MSI_CNT);
+	    DDI_PROP_DONTPASS, "#msi", 0);
 
-	DBG(DBG_MSIQ, dip, "obp: #msi=%d\n",
-	    msi_state_p->msi_cnt);
+	DBG(DBG_MSIQ, dip, "#msi=%d\n", msi_state_p->msi_cnt);
+	if (msi_state_p->msi_cnt == 0)
+		return (DDI_FAILURE);
 
 	/* msi-ranges: msi# field */
-	ret = ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_ALLOC,
-	    DDI_PROP_DONTPASS, "msi-ranges", (caddr_t)&valuep, &length);
+	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_ALLOC,
+	    DDI_PROP_DONTPASS, "msi-ranges", (caddr_t)&valuep, &length)
+	    != DDI_PROP_SUCCESS)
+		return (DDI_FAILURE);
 
-	if (ret == DDI_PROP_SUCCESS) {
-		msi_state_p->msi_1st_msinum =
-		    ((px_msi_ranges_t *)valuep)->msi_no;
-		kmem_free(valuep, (size_t)length);
-	} else
-		msi_state_p->msi_1st_msinum = PX_DEFAULT_MSI_1ST_MSINUM;
+	msi_state_p->msi_1st_msinum = ((px_msi_ranges_t *)valuep)->msi_no;
+	kmem_free(valuep, (size_t)length);
 
-	DBG(DBG_MSIQ, dip, "obp: msi_1st_msinum=%d\n",
-	    msi_state_p->msi_1st_msinum);
+	DBG(DBG_MSIQ, dip, "msi_1st_msinum=%d\n", msi_state_p->msi_1st_msinum);
 
 	/* msi-data-mask */
 	msi_state_p->msi_data_mask = ddi_getprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "msi-data-mask", PX_DEFAULT_MSI_DATA_MASK);
+	    DDI_PROP_DONTPASS, "msi-data-mask", 0);
 
-	DBG(DBG_MSIQ, dip, "obp: msi-data-mask=0x%x\n",
+	DBG(DBG_MSIQ, dip, "msi-data-mask=0x%x\n",
 	    msi_state_p->msi_data_mask);
 
 	/* msi-data-width */
 	msi_state_p->msi_data_width = ddi_getprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "msix-data-width", PX_DEFAULT_MSI_DATA_WIDTH);
+	    DDI_PROP_DONTPASS, "msix-data-width", 0);
 
-	DBG(DBG_MSIQ, dip, "obp: msix-data-width=%d\n",
+	DBG(DBG_MSIQ, dip, "msix-data-width=%d\n",
 	    msi_state_p->msi_data_width);
 
 	/*
@@ -389,127 +369,31 @@
 		msi_state_p->msi_type = DDI_INTR_TYPE_MSI;
 		if (msi_state_p->msi_data_width == PX_MSIX_WIDTH)
 			msi_state_p->msi_type |= DDI_INTR_TYPE_MSIX;
+	} else {
+		return (DDI_FAILURE);
 	}
 
 	/* msi-address-ranges */
-	ret = ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_ALLOC,
-	    DDI_PROP_DONTPASS, "msi-address-ranges", (caddr_t)&valuep,
-	    &length);
-
-	if (ret == DDI_PROP_SUCCESS) {
-		msi_addr_hi =
-		    ((px_msi_address_ranges_t *)valuep)->msi_addr32_hi;
-		msi_addr_lo =
-		    ((px_msi_address_ranges_t *)valuep)->msi_addr32_lo;
-		msi_state_p->msi_addr32 =
-		    (msi_addr_hi << 32) | msi_addr_lo;
-
-		msi_state_p->msi_addr32_len =
-		    ((px_msi_address_ranges_t *)valuep)->msi_addr32_len;
-
-		msi_addr_hi =
-		    ((px_msi_address_ranges_t *)valuep)->msi_addr64_hi;
-		msi_addr_lo =
-		    ((px_msi_address_ranges_t *)valuep)->msi_addr64_lo;
-		msi_state_p->msi_addr64 =
-		    (msi_addr_hi << 32) | msi_addr_lo;
-
-		msi_state_p->msi_addr64_len =
-		    ((px_msi_address_ranges_t *)valuep)->msi_addr64_len;
-
-		kmem_free(valuep, (size_t)length);
-
-		msi_state_p->msi_mem_flg = B_FALSE;
+	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_ALLOC,
+	    DDI_PROP_DONTPASS, "msi-address-ranges", (caddr_t)&valuep, &length)
+	    != DDI_PROP_SUCCESS)
+		return (DDI_FAILURE);
 
-		DBG(DBG_MSIQ, dip, "obp: msi_addr32=0x%llx\n",
-		    msi_state_p->msi_addr32);
-
-		DBG(DBG_MSIQ, dip, "obp: msi_addr64=0x%llx\n",
-		    msi_state_p->msi_addr64);
-
-		return (ret);
-	}
-
-	/*
-	 * If msi-address-ranges property does not exist in OBP, Fire
-	 * driver will need to allocate memory.
-	 *
-	 * Allocate 64KB of memory from unused PCI-E address space for the MSI
-	 * transactions and program MSI 32-bit address register.
-	 *
-	 * This register is used by the Fire hardware to compare against the
-	 * address of incoming PCI-E 32-bit addressed memory write commands.
-	 * If the address matches bits 31:16 then PCI-E command is considered
-	 * to be MSI transaction.
-	 *
-	 * pci_resource_setup() is called in context of PCI hotplug
-	 * initialization.
-	 *
-	 * Setup resource maps for this bus node.
-	 */
-	if (pci_resource_setup(dip) != NDI_SUCCESS) {
-		DBG(DBG_MSIQ, dip, "px_msi_getprops: dip=%s%d"
-		    "pci_resource_setup failed\n",
-		    ddi_driver_name(dip), ddi_get_instance(dip));
+	msi_addr_hi = ((px_msi_address_ranges_t *)valuep)->msi_addr32_hi;
+	msi_addr_lo = ((px_msi_address_ranges_t *)valuep)->msi_addr32_lo;
+	msi_state_p->msi_addr32 = (msi_addr_hi << 32) | msi_addr_lo;
+	msi_state_p->msi_addr32_len =
+	    ((px_msi_address_ranges_t *)valuep)->msi_addr32_len;
 
-		return (DDI_FAILURE);
-	}
-
-	msi_state_p->msi_mem_flg = B_TRUE;
-
-	/*
-	 * Reserve PCI MEM 32 resources to perform 32 bit MSI transactions.
-	 */
-	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
-	request.ra_flags = NDI_RA_ALLOC_BOUNDED;
-	request.ra_boundbase = 0;
-	request.ra_boundlen = PX_MSI_4GIG_LIMIT;
-	request.ra_len = PX_MSI_ADDR_LEN;
-	request.ra_align_mask = 0;
-
-	if (ndi_ra_alloc(dip, &request, &mem_answer, &mem_alen,
-	    NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
-		DBG(DBG_MSIQ, dip, "px_msi_getprops: Failed to allocate "
-		    "64KB mem\n");
-
-		return (DDI_FAILURE);
-	}
-
-	msi_state_p->msi_addr32 = mem_answer;
-	msi_state_p->msi_addr32_len = mem_alen;
-
-	DBG(DBG_MSIQ, dip, "px_msi_getprops: 32 Addr 0x%llx\n",
-	    msi_state_p->msi_addr32);
+	msi_addr_hi = ((px_msi_address_ranges_t *)valuep)->msi_addr64_hi;
+	msi_addr_lo = ((px_msi_address_ranges_t *)valuep)->msi_addr64_lo;
+	msi_state_p->msi_addr64 = (msi_addr_hi << 32) | msi_addr_lo;
+	msi_state_p->msi_addr64_len =
+	    ((px_msi_address_ranges_t *)valuep)->msi_addr64_len;
 
-	/*
-	 * Reserve PCI MEM 64 resources to perform 64 bit MSI transactions.
-	 *
-	 * NOTE:
-	 *
-	 * Currently OBP do not export any "available" property or range in
-	 * the MEM64 space. Hence ndi_ra_alloc() request will return failure.
-	 * So, for time being ignore this failure.
-	 */
-	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
-	request.ra_flags = NDI_RA_ALLOC_BOUNDED;
-	request.ra_boundbase = PX_MSI_4GIG_LIMIT + 1;
-	request.ra_boundlen = PX_MSI_4GIG_LIMIT;
-	request.ra_len = PX_MSI_ADDR_LEN;
-	request.ra_align_mask = 0;
+	DBG(DBG_MSIQ, dip, "msi_addr32=0x%llx\n", msi_state_p->msi_addr32);
+	DBG(DBG_MSIQ, dip, "msi_addr64=0x%llx\n", msi_state_p->msi_addr64);
 
-	if (ndi_ra_alloc(dip, &request, &mem_answer, &mem_alen,
-	    NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
-		DBG(DBG_MSIQ, dip, "px_msi_getprops: Failed to allocate "
-		    "64KB mem\n");
-
-		return (DDI_SUCCESS);
-	}
-
-	msi_state_p->msi_addr64 = mem_answer;
-	msi_state_p->msi_addr64_len = mem_alen;
-
-	DBG(DBG_MSIQ, dip, "px_msi_getprops: 64 Addr 0x%llx\n",
-	    msi_state_p->msi_addr64);
-
+	kmem_free(valuep, (size_t)length);
 	return (DDI_SUCCESS);
 }
--- a/usr/src/uts/sun4/io/px/px_msi.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_msi.h	Mon Nov 02 15:58:28 2009 +0800
@@ -88,17 +88,6 @@
 #define	PX_MSI_WIDTH			16
 #define	PX_MSIX_WIDTH			32
 
-/*
- * Default MSI configurations
- */
-#define	PX_DEFAULT_MSI_CNT		256
-#define	PX_DEFAULT_MSI_1ST_MSINUM	0
-#define	PX_DEFAULT_MSI_DATA_MASK	0xff
-#define	PX_DEFAULT_MSI_DATA_WIDTH	PX_MSIX_WIDTH
-
-#define	PX_MSI_4GIG_LIMIT		0xFFFFFFFFUL
-#define	PX_MSI_ADDR_LEN			0x10000	/* 64K bytes */
-
 extern	int	px_msi_attach(px_t *px_p);
 extern	void	px_msi_detach(px_t *px_p);
 
--- a/usr/src/uts/sun4/io/px/px_msiq.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_msiq.c	Mon Nov 02 15:58:28 2009 +0800
@@ -40,7 +40,7 @@
 #include <sys/ddi_impldefs.h>
 #include "px_obj.h"
 
-static void px_msiq_get_props(px_t *px_p);
+static int px_msiq_get_props(px_t *px_p);
 
 /*
  * px_msiq_attach()
@@ -60,7 +60,8 @@
 	 *
 	 * Avaialble MSIQs and its properties.
 	 */
-	px_msiq_get_props(px_p);
+	if (px_msiq_get_props(px_p) != DDI_SUCCESS)
+		return (DDI_FAILURE);
 
 	/*
 	 * 10% of available MSIQs are reserved for the PCIe messages.
@@ -406,49 +407,63 @@
 /*
  * px_msiq_get_props()
  */
-static void
+static int
 px_msiq_get_props(px_t *px_p)
 {
-	px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
-	int	ret = DDI_SUCCESS;
-	int	length = sizeof (int);
-	char	*valuep = NULL;
+	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
+	int		length = sizeof (int);
+	char		*valuep = NULL;
+	int		ret;
 
 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_get_props\n");
 
 	/* #msi-eqs */
 	msiq_state_p->msiq_cnt = ddi_getprop(DDI_DEV_T_ANY, px_p->px_dip,
-	    DDI_PROP_DONTPASS, "#msi-eqs", PX_DEFAULT_MSIQ_CNT);
+	    DDI_PROP_DONTPASS, "#msi-eqs", 0);
 
-	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_cnt=%d\n",
-	    msiq_state_p->msiq_cnt);
+	DBG(DBG_MSIQ, px_p->px_dip, "msiq_cnt=%d\n", msiq_state_p->msiq_cnt);
 
 	/* msi-eq-size */
 	msiq_state_p->msiq_rec_cnt = ddi_getprop(DDI_DEV_T_ANY, px_p->px_dip,
-	    DDI_PROP_DONTPASS, "msi-eq-size", PX_DEFAULT_MSIQ_REC_CNT);
+	    DDI_PROP_DONTPASS, "msi-eq-size", 0);
 
-	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_rec_cnt=%d\n",
+	DBG(DBG_MSIQ, px_p->px_dip, "msiq_rec_cnt=%d\n",
 	    msiq_state_p->msiq_rec_cnt);
 
+	if ((msiq_state_p->msiq_cnt == 0) || (msiq_state_p->msiq_rec_cnt == 0))
+		return (DDI_FAILURE);
+
 	/* msi-eq-to-devino: msi-eq#, devino# fields */
 	ret = ddi_prop_op(DDI_DEV_T_ANY, px_p->px_dip, PROP_LEN_AND_VAL_ALLOC,
-	    DDI_PROP_DONTPASS, "msi-eq-to-devino", (caddr_t)&valuep,
-	    &length);
+	    DDI_PROP_DONTPASS, "msi-eq-to-devino", (caddr_t)&valuep, &length);
 
-	if (ret == DDI_PROP_SUCCESS) {
-		msiq_state_p->msiq_1st_msiq_id =
-		    ((px_msi_eq_to_devino_t *)valuep)->msi_eq_no;
-		msiq_state_p->msiq_1st_devino =
-		    ((px_msi_eq_to_devino_t *)valuep)->devino_no;
-		kmem_free(valuep, (size_t)length);
-	} else {
-		msiq_state_p->msiq_1st_msiq_id = PX_DEFAULT_MSIQ_1ST_MSIQ_ID;
-		msiq_state_p->msiq_1st_devino = PX_DEFAULT_MSIQ_1ST_DEVINO;
+	/*
+	 * NOTE:
+	 * On sun4u PCIe systems, the msi-eq-to-devino property is broken and
+	 * these systems defines this property as msi-eq-devino.
+	 */
+	if (ret == DDI_PROP_NOT_FOUND) {
+		DBG(DBG_MSIQ, px_p->px_dip, "msi-eq-to-devino is not found\n");
+		ret = ddi_prop_op(DDI_DEV_T_ANY, px_p->px_dip,
+		    PROP_LEN_AND_VAL_ALLOC, DDI_PROP_DONTPASS, "msi-eq-devino",
+		    (caddr_t)&valuep, &length);
 	}
 
-	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_1st_msiq_id=%d\n",
+	if (ret != DDI_PROP_SUCCESS) {
+		return (DDI_FAILURE);
+	}
+
+	msiq_state_p->msiq_1st_msiq_id =
+	    ((px_msi_eq_to_devino_t *)valuep)->msi_eq_no;
+	msiq_state_p->msiq_1st_devino =
+	    ((px_msi_eq_to_devino_t *)valuep)->devino_no;
+
+	DBG(DBG_MSIQ, px_p->px_dip, "msiq_1st_msiq_id=%d\n",
 	    msiq_state_p->msiq_1st_msiq_id);
 
-	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_1st_devino=%d\n",
+	DBG(DBG_MSIQ, px_p->px_dip, "msiq_1st_devino=%d\n",
 	    msiq_state_p->msiq_1st_devino);
+
+	kmem_free(valuep, (size_t)length);
+	return (DDI_SUCCESS);
 }
--- a/usr/src/uts/sun4/io/px/px_msiq.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_msiq.h	Mon Nov 02 15:58:28 2009 +0800
@@ -81,14 +81,6 @@
 	int	devino_no;
 } px_msi_eq_to_devino_t;
 
-/*
- * Default MSIQ Configurations
- */
-#define	PX_DEFAULT_MSIQ_CNT		36
-#define	PX_DEFAULT_MSIQ_REC_CNT		128
-#define	PX_DEFAULT_MSIQ_1ST_MSIQ_ID	0
-#define	PX_DEFAULT_MSIQ_1ST_DEVINO	24
-
 extern	int	px_msiq_attach(px_t *px_p);
 extern	void	px_msiq_detach(px_t *px_p);
 extern	void	px_msiq_resume(px_t *px_p);
--- a/usr/src/uts/sun4/io/px/px_obj.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_obj.h	Mon Nov 02 15:58:28 2009 +0800
@@ -19,20 +19,17 @@
  * 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_PX_OBJ_H
 #define	_SYS_PX_OBJ_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
-#include <sys/pcie.h>
 #include <sys/pcie_impl.h>
 #include <sys/pci_impl.h>
 #include <sys/fm/io/sun4_fire.h>
--- a/usr/src/uts/sun4/io/px/px_pec.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_pec.c	Mon Nov 02 15:58:28 2009 +0800
@@ -54,9 +54,9 @@
 {
 	px_pec_t *pec_p;
 	int i, len;
-	int nrange = px_p->px_ranges_length / sizeof (px_ranges_t);
+	int nrange = px_p->px_ranges_length / sizeof (pci_ranges_t);
 	dev_info_t *dip = px_p->px_dip;
-	px_ranges_t *rangep = px_p->px_ranges_p;
+	pci_ranges_t *rangep = px_p->px_ranges_p;
 	int ret;
 
 	/*
--- a/usr/src/uts/sun4/io/px/px_space.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_space.c	Mon Nov 02 15:58:28 2009 +0800
@@ -32,7 +32,6 @@
 #include <sys/sunddi.h>
 #include <sys/cmn_err.h>
 #include <sys/time.h>
-#include <sys/pcie.h>
 #include "px_obj.h"
 
 /*LINTLIBRARY*/
--- a/usr/src/uts/sun4/io/px/px_tools.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_tools.c	Mon Nov 02 15:58:28 2009 +0800
@@ -28,7 +28,6 @@
 #include <sys/cpuvar.h>
 #include <sys/kmem.h>
 #include <sys/sunddi.h>
-#include <sys/hotplug/pci/pcihp.h>
 #include "px_obj.h"
 #include <sys/pci_tools.h>
 #include "px_tools_ext.h"
@@ -774,13 +773,13 @@
 	int instance = ddi_get_instance(dip);
 
 	if (ddi_create_minor_node(dip, PCI_MINOR_REG, S_IFCHR,
-	    PCIHP_AP_MINOR_NUM(instance, PCI_TOOL_REG_MINOR_NUM),
+	    PCI_MINOR_NUM(instance, PCI_TOOL_REG_MINOR_NUM),
 	    DDI_NT_REGACC, 0) != DDI_SUCCESS) {
 		return (DDI_FAILURE);
 	}
 
 	if (ddi_create_minor_node(dip, PCI_MINOR_INTR, S_IFCHR,
-	    PCIHP_AP_MINOR_NUM(instance, PCI_TOOL_INTR_MINOR_NUM),
+	    PCI_MINOR_NUM(instance, PCI_TOOL_INTR_MINOR_NUM),
 	    DDI_NT_INTRCTL, 0) != DDI_SUCCESS) {
 		ddi_remove_minor_node(dip, PCI_MINOR_REG);
 		return (DDI_FAILURE);
--- a/usr/src/uts/sun4/io/px/px_tools_ext.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_tools_ext.h	Mon Nov 02 15:58:28 2009 +0800
@@ -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,28 +19,18 @@
  * 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.
  */
 
 #ifndef	_SYS_PX_TOOLS_EXT_H
 #define	_SYS_PX_TOOLS_EXT_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
-/*
- * Minor numbers for dedicated pcitool nodes.
- * Note that FF and FE minor numbers are used for other minor nodes.
- */
-#define	PCI_TOOL_REG_MINOR_NUM  0xFD
-#define	PCI_TOOL_INTR_MINOR_NUM 0xFC
-
 /* Stuff exported by px_tools.c and px_tools_4[u/v].c */
-
 int pxtool_dev_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode);
 int pxtool_bus_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode);
 int pxtool_intr(dev_info_t *dip, void *arg, int cmd, int mode);
--- a/usr/src/uts/sun4/io/px/px_util.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_util.c	Mon Nov 02 15:58:28 2009 +0800
@@ -170,6 +170,7 @@
 
 	i = ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
 	    "assigned-addresses", (caddr_t)&assign_p, &assign_len);
+
 	if (i) {
 		DBG(DBG_MAP | DBG_CONT, dip, "%s%d: assigned-addresses %d\n",
 		    ddi_driver_name(rdip), ddi_get_instance(rdip), i);
@@ -210,8 +211,8 @@
 px_xlate_reg(px_t *px_p, pci_regspec_t *px_rp, struct regspec *new_rp)
 {
 	int n;
-	px_ranges_t *rng_p = px_p->px_ranges_p;
-	int rng_n = px_p->px_ranges_length / sizeof (px_ranges_t);
+	pci_ranges_t *rng_p = px_p->px_ranges_p;
+	int rng_n = px_p->px_ranges_length / sizeof (pci_ranges_t);
 	uint32_t space_type = PCI_REG_ADDR_G(px_rp->pci_phys_hi);
 	uint64_t reg_begin, reg_end, reg_sz;
 	uint64_t rng_begin, rng_end, rng_sz;
@@ -631,8 +632,8 @@
 px_get_cfg_pabase(px_t *px_p)
 {
 	int i;
-	px_ranges_t *rangep = px_p->px_ranges_p;
-	int nrange = px_p->px_ranges_length / sizeof (px_ranges_t);
+	pci_ranges_t *rangep = px_p->px_ranges_p;
+	int nrange = px_p->px_ranges_length / sizeof (pci_ranges_t);
 	uint32_t cfg_space_type = PCI_REG_ADDR_G(PCI_ADDR_CONFIG);
 
 	ASSERT(cfg_space_type == 0);
--- a/usr/src/uts/sun4/io/px/px_util.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_util.h	Mon Nov 02 15:58:28 2009 +0800
@@ -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_PX_UTIL_H
 #define	_SYS_PX_UTIL_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -52,7 +50,7 @@
 extern int px_xlate_reg(px_t *px_p, pci_regspec_t *pci_rp,
 	struct regspec *new_rp);
 extern int px_search_ranges(px_t *px_p, uint32_t space_type, uint32_t reg_begin,
-	uint32_t reg_end, px_ranges_t **sel_rng_p, uint_t *base_offset_p);
+	uint32_t reg_end, pci_ranges_t **sel_rng_p, uint_t *base_offset_p);
 
 /* bus add intrspec */
 extern off_t px_get_reg_set_size(dev_info_t *child, int rnumber);
--- a/usr/src/uts/sun4/io/px/px_var.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_var.h	Mon Nov 02 15:58:28 2009 +0800
@@ -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_PX_VAR_H
 #define	_SYS_PX_VAR_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/callb.h>
 
 #ifdef	__cplusplus
@@ -47,29 +45,6 @@
 
 /*
  * The following typedef is used to represent a
- * 1275 "bus-range" property of a PCI Bus node.
- */
-typedef struct px_bus_range {
-	uint32_t lo;
-	uint32_t hi;
-} px_bus_range_t;
-
-/*
- * The following typedef is used to represent an entry in the "ranges"
- * property of a device node.
- */
-typedef struct px_ranges {
-	uint32_t child_high;
-	uint32_t child_mid;
-	uint32_t child_low;
-	uint32_t parent_high;
-	uint32_t parent_low;
-	uint32_t size_high;
-	uint32_t size_low;
-} px_ranges_t;
-
-/*
- * The following typedef is used to represent a
  * 1275 "reg" property of a PCI nexus.
  */
 typedef struct px_nexus_regspec {
@@ -99,7 +74,6 @@
 	 */
 	px_state_t px_state;
 	uint_t px_soft_state;
-	uint_t px_open_count;
 	kmutex_t px_mutex;
 
 	/*
@@ -115,8 +89,8 @@
 	 * px device node properties:
 	 */
 	pcie_req_id_t px_bdf;
-	px_bus_range_t px_bus_range;	/* "bus-range" */
-	px_ranges_t *px_ranges_p;	/* "ranges" data & length */
+	pci_bus_range_t px_bus_range;	/* "bus-range" */
+	pci_ranges_t *px_ranges_p;	/* "ranges" data & length */
 	int px_ranges_length;
 	devino_t *px_inos;		/* inos from "interrupts" prop */
 	int px_inos_len;		/* "interrupts" length */
@@ -154,14 +128,8 @@
 	ddi_softint_handle_t    px_dbg_hdl; /* HDL for dbg printing */
 };
 
-/* px soft state flag */
-#define	PX_SOFT_STATE_OPEN		1
-#define	PX_SOFT_STATE_OPEN_EXCL		2
-#define	PX_SOFT_STATE_CLOSED		4
-
 /* px_dev_caps definition */
 #define	PX_BYPASS_DMA_ALLOWED		1
-#define	PX_HOTPLUG_CAPABLE		2
 #define	PX_DMA_SYNC_REQUIRED		4
 
 /* px_pm_flags definitions used with interrupts and FMA code */
@@ -174,7 +142,7 @@
 #define	DIP_TO_STATE(dip)	INST_TO_STATE(DIP_TO_INST(dip))
 
 #define	PX_DEV_TO_SOFTSTATE(dev)	((px_t *)ddi_get_soft_state( \
-	px_state_p, PCIHP_AP_MINOR_NUM_TO_INSTANCE(getminor(dev))))
+	px_state_p, PCI_MINOR_NUM_TO_INSTANCE(getminor(dev))))
 
 extern void *px_state_p;
 
--- a/usr/src/uts/sun4u/io/pci/pci.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4u/io/pci/pci.c	Mon Nov 02 15:58:28 2009 +0800
@@ -23,7 +23,6 @@
  * Use is subject to license terms.
  */
 
-
 /*
  * PCI nexus driver interface
  */
@@ -124,9 +123,9 @@
 extern struct mod_ops mod_driverops;
 
 static struct modldrv modldrv = {
-	&mod_driverops, 	/* Type of module - driver */
-	"PCI Bus nexus driver",	/* Name of module. */
-	&pci_ops,		/* driver ops */
+	&mod_driverops, 			/* Type of module - driver */
+	"Sun4u Host to PCI nexus driver",	/* Name of module. */
+	&pci_ops,				/* driver ops */
 };
 
 static struct modlinkage modlinkage = {
@@ -296,7 +295,6 @@
 		pci_p->pci_dip = dip;
 		mutex_init(&pci_p->pci_mutex, NULL, MUTEX_DRIVER, NULL);
 		pci_p->pci_soft_state = PCI_SOFT_STATE_CLOSED;
-		pci_p->pci_open_count = 0;
 
 		/*
 		 * Get key properties of the pci bridge node and
--- a/usr/src/uts/sun4u/io/pci/pci_devctl.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4u/io/pci/pci_devctl.c	Mon Nov 02 15:58:28 2009 +0800
@@ -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"
-
 /*
  * PCI nexus HotPlug devctl interface
  */
@@ -130,7 +128,6 @@
 		}
 	}
 
-	pci_p->pci_open_count++;
 	mutex_exit(&pci_p->pci_mutex);
 
 	return (0);
@@ -161,7 +158,6 @@
 		}
 
 	pci_p->pci_soft_state = PCI_SOFT_STATE_CLOSED;
-	pci_p->pci_open_count = 0;
 	mutex_exit(&pci_p->pci_mutex);
 	return (0);
 }
--- a/usr/src/uts/sun4u/io/pci/pci_pci.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4u/io/pci/pci_pci.c	Mon Nov 02 15:58:28 2009 +0800
@@ -23,7 +23,6 @@
  * Use is subject to license terms.
  */
 
-
 /*
  *	Sun4u PCI to PCI bus bridge nexus driver
  */
@@ -35,7 +34,7 @@
 #include <sys/autoconf.h>
 #include <sys/ddi_impldefs.h>
 #include <sys/ddi_subrdefs.h>
-#include <sys/pcie.h>
+#include <sys/pci_impl.h>
 #include <sys/pcie_impl.h>
 #include <sys/pci_cap.h>
 #include <sys/pci/pci_nexus.h>
@@ -47,6 +46,7 @@
 #include <sys/ddifm.h>
 #include <sys/pci/pci_pwr.h>
 #include <sys/pci/pci_debug.h>
+#include <sys/hotplug/pci/pcie_hp.h>
 #include <sys/hotplug/pci/pcihp.h>
 #include <sys/open.h>
 #include <sys/stat.h>
@@ -130,7 +130,8 @@
 	ppb_bus_enter,			/* (*bus_enter)()		*/
 	ppb_bus_exit,			/* (*bus_exit)()		*/
 	ppb_bus_power,			/* (*bus_power)()		*/
-	ppb_intr_ops			/* (*bus_intr_op)(); 		*/
+	ppb_intr_ops,			/* (*bus_intr_op)(); 		*/
+	pcie_hp_common_ops		/* (*bus_hp_op)(); 		*/
 };
 
 static int ppb_open(dev_t *devp, int flags, int otyp, cred_t *credp);
@@ -164,7 +165,7 @@
 static int ppb_probe(dev_info_t *);
 static int ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
 static int ppb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
-static int ppb_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
+static int ppb_info(dev_info_t *dip, ddi_info_cmd_t cmd,
     void *arg, void **result);
 static int ppb_pwr(dev_info_t *dip, int component, int level);
 
@@ -238,9 +239,6 @@
 
 	kmutex_t ppb_mutex;
 	uint_t ppb_soft_state;
-#define	PPB_SOFT_STATE_CLOSED		0x00
-#define	PPB_SOFT_STATE_OPEN		0x01
-#define	PPB_SOFT_STATE_OPEN_EXCL	0x02
 	int fm_cap;
 	ddi_iblock_cookie_t fm_ibc;
 
@@ -328,16 +326,18 @@
 
 /*ARGSUSED*/
 static int
-ppb_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
+ppb_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
 {
-	ppb_devstate_t *ppb_p;	/* per ppb state pointer */
 	minor_t		minor = getminor((dev_t)arg);
-	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
-
-	ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state,
+	int		instance = PCI_MINOR_NUM_TO_INSTANCE(minor);
+	ppb_devstate_t	*ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state,
 	    instance);
 
-	switch (infocmd) {
+
+	if (ppb_p->parent_bus != PCIE_PCIECAP_DEV_TYPE_PCIE_DEV)
+		return (pcihp_info(dip, cmd, arg, result));
+
+	switch (cmd) {
 	default:
 		return (DDI_FAILURE);
 
@@ -364,9 +364,12 @@
 static int
 ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
 {
+	dev_info_t *root = ddi_root_node();
 	int instance;
 	ppb_devstate_t *ppb;
+	dev_info_t *pdip;
 	ddi_acc_handle_t config_handle;
+	char *bus;
 
 	switch (cmd) {
 	case DDI_ATTACH:
@@ -386,7 +389,7 @@
 		ppb = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, instance);
 		ppb->dip = devi;
 		mutex_init(&ppb->ppb_mutex, NULL, MUTEX_DRIVER, NULL);
-		ppb->ppb_soft_state = PPB_SOFT_STATE_CLOSED;
+		ppb->ppb_soft_state = PCI_SOFT_STATE_CLOSED;
 		if (pci_config_setup(devi, &config_handle) != DDI_SUCCESS) {
 			mutex_destroy(&ppb->ppb_mutex);
 			ddi_soft_state_free(ppb_state, instance);
@@ -435,30 +438,32 @@
 			mutex_exit(&ppb->ppb_pwr_p->pwr_mutex);
 		}
 
+		ppb->parent_bus = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO;
+		for (pdip = ddi_get_parent(ppb->dip); pdip && (pdip != root) &&
+		    (ppb->parent_bus != PCIE_PCIECAP_DEV_TYPE_PCIE_DEV);
+		    pdip = ddi_get_parent(pdip)) {
+			if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
+			    DDI_PROP_DONTPASS, "device_type", &bus) !=
+			    DDI_PROP_SUCCESS)
+				break;
+
+			if (strcmp(bus, "pciex") == 0)
+				ppb->parent_bus =
+				    PCIE_PCIECAP_DEV_TYPE_PCIE_DEV;
+
+			ddi_prop_free(bus);
+		}
+
 		/*
-		 * Initialize hotplug support on this bus. At minimum
-		 * (for non hotplug bus) this would create ":devctl" minor
-		 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls
-		 * to this bus. This all takes place if this nexus has hot-plug
-		 * slots and successfully initializes Hot Plug Framework.
+		 * Initialize hotplug support on this bus.
 		 */
-		ppb->hotplug_capable = B_FALSE;
-		ppb_init_hotplug(ppb);
-		if (ppb->hotplug_capable == B_FALSE) {
-			/*
-			 * create minor node for devctl interfaces
-			 */
-			if (ddi_create_minor_node(devi, "devctl", S_IFCHR,
-			    PCIHP_AP_MINOR_NUM(instance, PCIHP_DEVCTL_MINOR),
-			    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
-				if (ppb->ppb_pwr_p != NULL) {
-					ppb_pwr_teardown(ppb, devi);
-				}
-				mutex_destroy(&ppb->ppb_mutex);
-				ddi_soft_state_free(ppb_state, instance);
+		if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV)
+			if (pcie_init(devi, NULL) != DDI_SUCCESS) {
+				(void) ppb_detach(devi, DDI_DETACH);
 				return (DDI_FAILURE);
 			}
-		}
+		else
+			ppb_init_hotplug(ppb);
 
 		DEBUG1(DBG_ATTACH, devi,
 		    "ppb_attach(): this nexus %s hotplug slots\n",
@@ -488,6 +493,7 @@
 ppb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
 {
 	ppb_devstate_t *ppb;
+	int		ret = DDI_SUCCESS;
 
 	switch (cmd) {
 	case DDI_DETACH:
@@ -500,12 +506,16 @@
 
 		ppb_fm_fini(ppb);
 
-		if (ppb->hotplug_capable == B_TRUE)
-			if (pcihp_uninit(devi) == DDI_FAILURE)
-				return (DDI_FAILURE);
+		if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV)
+			ret = pcie_uninit(devi);
+		else if (ppb->hotplug_capable == B_TRUE)
+			ret = pcihp_init(devi);
 		else
 			ddi_remove_minor_node(devi, "devctl");
 
+		if (ret != DDI_SUCCESS)
+			return (DDI_FAILURE);
+
 		(void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type");
 
 		if (ppb->ppb_pwr_p != NULL) {
@@ -1428,6 +1438,8 @@
 static void
 ppb_init_hotplug(ppb_devstate_t *ppb)
 {
+	ppb->hotplug_capable = B_FALSE;
+
 	if (ddi_prop_exists(DDI_DEV_T_ANY, ppb->dip, DDI_PROP_DONTPASS,
 	    "hotplug-capable")) {
 		(void) modload("misc", "pcihp");
@@ -1441,6 +1453,18 @@
 			ppb->hotplug_capable = B_TRUE;
 	}
 
+	if (ppb->hotplug_capable == B_FALSE) {
+		/*
+		 * create minor node for devctl interfaces
+		 */
+		if (ddi_create_minor_node(ppb->dip, "devctl", S_IFCHR,
+		    PCI_MINOR_NUM(ddi_get_instance(ppb->dip), PCI_DEVCTL_MINOR),
+		    DDI_NT_NEXUS, 0) != DDI_SUCCESS)
+			cmn_err(CE_WARN,
+			    "%s #%d: Failed to create a minor node",
+			    ddi_driver_name(ppb->dip),
+			    ddi_get_instance(ppb->dip));
+	}
 }
 
 static void
@@ -1516,9 +1540,8 @@
 static int
 ppb_open(dev_t *devp, int flags, int otyp, cred_t *credp)
 {
-	ppb_devstate_t *ppb_p;
-	minor_t		minor = getminor(*devp);
-	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
+	int		instance = PCI_MINOR_NUM_TO_INSTANCE(getminor(*devp));
+	ppb_devstate_t	*ppb_p = ddi_get_soft_state(ppb_state, instance);
 
 	/*
 	 * Make sure the open is for the right file type.
@@ -1526,35 +1549,44 @@
 	if (otyp != OTYP_CHR)
 		return (EINVAL);
 
-	/*
-	 * Get the soft state structure for the device.
-	 */
-	ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state,
-	    instance);
-
 	if (ppb_p == NULL)
 		return (ENXIO);
 
-	if (ppb_p->hotplug_capable == B_TRUE)
-		return ((pcihp_get_cb_ops())->cb_open(devp, flags,
-		    otyp, credp));
+	mutex_enter(&ppb_p->ppb_mutex);
+
+	/*
+	 * Ioctls will be handled by SPARC PCI Express framework for all
+	 * PCIe platforms
+	 */
+	if (ppb_p->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) {
+		int	rv;
+
+		rv = pcie_open(ppb_p->dip, devp, flags, otyp, credp);
+		mutex_exit(&ppb_p->ppb_mutex);
+
+		return (rv);
+	} else if (ppb_p->hotplug_capable == B_TRUE) {
+		mutex_exit(&ppb_p->ppb_mutex);
+
+		return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp,
+		    credp));
+	}
 
 	/*
 	 * Handle the open by tracking the device state.
 	 */
-	mutex_enter(&ppb_p->ppb_mutex);
 	if (flags & FEXCL) {
-		if (ppb_p->ppb_soft_state != PPB_SOFT_STATE_CLOSED) {
+		if (ppb_p->ppb_soft_state != PCI_SOFT_STATE_CLOSED) {
 			mutex_exit(&ppb_p->ppb_mutex);
 			return (EBUSY);
 		}
-		ppb_p->ppb_soft_state = PPB_SOFT_STATE_OPEN_EXCL;
+		ppb_p->ppb_soft_state = PCI_SOFT_STATE_OPEN_EXCL;
 	} else {
-		if (ppb_p->ppb_soft_state == PPB_SOFT_STATE_OPEN_EXCL) {
+		if (ppb_p->ppb_soft_state == PCI_SOFT_STATE_OPEN_EXCL) {
 			mutex_exit(&ppb_p->ppb_mutex);
 			return (EBUSY);
 		}
-		ppb_p->ppb_soft_state = PPB_SOFT_STATE_OPEN;
+		ppb_p->ppb_soft_state = PCI_SOFT_STATE_OPEN;
 	}
 	mutex_exit(&ppb_p->ppb_mutex);
 	return (0);
@@ -1565,25 +1597,34 @@
 static int
 ppb_close(dev_t dev, int flags, int otyp, cred_t *credp)
 {
-	ppb_devstate_t *ppb_p;
-	minor_t		minor = getminor(dev);
-	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
+	int		instance = PCI_MINOR_NUM_TO_INSTANCE(getminor(dev));
+	ppb_devstate_t	*ppb_p = ddi_get_soft_state(ppb_state, instance);
 
 	if (otyp != OTYP_CHR)
 		return (EINVAL);
 
-	ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state,
-	    instance);
-
 	if (ppb_p == NULL)
 		return (ENXIO);
 
-	if (ppb_p->hotplug_capable == B_TRUE)
-		return ((pcihp_get_cb_ops())->cb_close(dev, flags,
-		    otyp, credp));
+	mutex_enter(&ppb_p->ppb_mutex);
+	/*
+	 * Ioctls will be handled by SPARC PCI Express framework for all
+	 * PCIe platforms
+	 */
+	if (ppb_p->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) {
+		int	rv;
 
-	mutex_enter(&ppb_p->ppb_mutex);
-	ppb_p->ppb_soft_state = PPB_SOFT_STATE_CLOSED;
+		rv = pcie_close(ppb_p->dip, dev, flags, otyp, credp);
+		mutex_exit(&ppb_p->ppb_mutex);
+
+		return (rv);
+	} else if (ppb_p->hotplug_capable == B_TRUE) {
+		mutex_exit(&ppb_p->ppb_mutex);
+		return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp,
+		    credp));
+	}
+
+	ppb_p->ppb_soft_state = PCI_SOFT_STATE_CLOSED;
 	mutex_exit(&ppb_p->ppb_mutex);
 	return (0);
 }
@@ -1597,23 +1638,26 @@
 ppb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
 	int *rvalp)
 {
-	ppb_devstate_t *ppb_p;
-	dev_info_t *self;
+	int		instance = PCI_MINOR_NUM_TO_INSTANCE(getminor(dev));
+	ppb_devstate_t	*ppb_p = ddi_get_soft_state(ppb_state, instance);
 	struct devctl_iocdata *dcp;
-	uint_t bus_state;
-	int rv = 0;
-	minor_t		minor = getminor(dev);
-	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
-
-	ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state,
-	    instance);
+	uint_t		bus_state;
+	dev_info_t	*self;
+	int		rv = 0;
 
 	if (ppb_p == NULL)
 		return (ENXIO);
 
-	if (ppb_p->hotplug_capable == B_TRUE)
-		return ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd,
-		    arg, mode, credp, rvalp));
+	/*
+	 * Ioctls will be handled by SPARC PCI Express framework for all
+	 * PCIe platforms
+	 */
+	if (ppb_p->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV)
+		return (pcie_ioctl(ppb_p->dip, dev, cmd, arg, mode, credp,
+		    rvalp));
+	else if (ppb_p->hotplug_capable == B_TRUE)
+		return ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode,
+		    credp, rvalp));
 
 	self = ppb_p->dip;
 
@@ -1670,24 +1714,23 @@
 	return (rv);
 }
 
-static int ppb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
-    int flags, char *name, caddr_t valuep, int *lengthp)
+static int
+ppb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int flags,
+    char *name, caddr_t valuep, int *lengthp)
 {
-	ppb_devstate_t *ppb_p;
-	minor_t		minor = getminor(dev);
-	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
-
-	ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state,
-	    instance);
+	int		instance = PCI_MINOR_NUM_TO_INSTANCE(getminor(dev));
+	ppb_devstate_t	*ppb_p = (ppb_devstate_t *)
+	    ddi_get_soft_state(ppb_state, instance);
 
 	if (ppb_p == NULL)
 		return (ENXIO);
 
-	if (ppb_p->hotplug_capable == B_TRUE)
-		return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op,
-		    flags, name, valuep, lengthp));
+	if (ppb_p->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV)
+		return (pcie_prop_op(dev, dip, prop_op, flags, name,
+		    valuep, lengthp));
 
-	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
+	return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags,
+	    name, valuep, lengthp));
 }
 
 /*
@@ -1696,10 +1739,6 @@
 static void
 ppb_fm_init(ppb_devstate_t *ppb_p)
 {
-	dev_info_t *root = ddi_root_node();
-	dev_info_t *pdip;
-	char *bus;
-
 	ppb_p->fm_cap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE |
 	    DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
 
@@ -1717,21 +1756,6 @@
 	 * Register error callback with our parent.
 	 */
 	ddi_fm_handler_register(ppb_p->dip, ppb_err_callback, NULL);
-
-	ppb_p->parent_bus = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO;
-	for (pdip = ddi_get_parent(ppb_p->dip); pdip && (pdip != root) &&
-	    (ppb_p->parent_bus != PCIE_PCIECAP_DEV_TYPE_PCIE_DEV);
-	    pdip = ddi_get_parent(pdip)) {
-		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
-		    DDI_PROP_DONTPASS, "device_type", &bus) !=
-		    DDI_PROP_SUCCESS)
-			break;
-
-		if (strcmp(bus, "pciex") == 0)
-			ppb_p->parent_bus = PCIE_PCIECAP_DEV_TYPE_PCIE_DEV;
-
-		ddi_prop_free(bus);
-	}
 }
 
 /*
--- a/usr/src/uts/sun4u/io/px/oberon_regs.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4u/io/px/oberon_regs.h	Mon Nov 02 15:58:28 2009 +0800
@@ -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_OBERON_REGS_H
 #define	_SYS_OBERON_REGS_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -226,7 +224,6 @@
 #define	DRAIN_CONTROL_STATUS					0x51100
 #define	DRAIN_CONTROL_STATUS_DRAIN				0
 
-#define	PX_PCIEHP_PIL (LOCK_LEVEL - 1)
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/uts/sun4u/io/px/px_hlib.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4u/io/px/px_hlib.c	Mon Nov 02 15:58:28 2009 +0800
@@ -29,9 +29,8 @@
 #include <sys/vmem.h>
 #include <sys/machsystm.h>	/* lddphys() */
 #include <sys/iommutsb.h>
-#include <sys/pci.h>
-#include <sys/hotplug/pci/pciehpc.h>
 #include <px_obj.h>
+#include <sys/hotplug/pci/pcie_hp.h>
 #include "px_regs.h"
 #include "oberon_regs.h"
 #include "px_csr.h"
@@ -1389,6 +1388,7 @@
 	    LPU_LTSSM_CONFIG4_DATA_RATE) |
 	    (LPU_LTSSM_CONFIG4_N_FTS_DEFAULT <<
 	    LPU_LTSSM_CONFIG4_N_FTS));
+
 	CSR_XS(csr_base, LPU_LTSSM_CONFIG4, val);
 	DBG(DBG_LPU, NULL, "lpu_init - LPU_LTSSM_CONFIG4: 0x%llx\n",
 	    CSR_XR(csr_base, LPU_LTSSM_CONFIG4));
@@ -1734,7 +1734,8 @@
 	 * Write the most significant 30 bits of the TSB physical address
 	 * and the encoded TSB table size.
 	 */
-	for (i = 8; i && (pxu_p->tsb_size < (0x2000 << i)); i--) {}
+	for (i = 8; i && (pxu_p->tsb_size < (0x2000 << i)); i--)
+		;
 
 	val = (((((va_to_pa(pxu_p->tsb_vaddr)) >> 13) << 13) |
 	    ((MMU_PAGE_SHIFT == 13) ? 0 : 1) << 8) | i);
@@ -2128,7 +2129,6 @@
 hvio_intr_settarget(devhandle_t dev_hdl, pxu_t *pxu_p, sysino_t sysino,
     cpuid_t cpuid)
 {
-
 	uint64_t	val, intr_controller;
 	uint32_t	ino = SYSINO_TO_DEVINO(sysino);
 
@@ -2162,8 +2162,7 @@
 	}
 
 	/* For EQ interrupts, set DATA MONDO bit */
-	if ((ino >= PX_DEFAULT_MSIQ_1ST_DEVINO) &&
-	    (ino < (PX_DEFAULT_MSIQ_1ST_DEVINO + PX_DEFAULT_MSIQ_CNT)))
+	if ((ino >= EQ_1ST_DEVINO) && (ino < (EQ_1ST_DEVINO + EQ_CNT)))
 		val |= (0x1ull << INTERRUPT_MAPPING_ENTRIES_MDO_MODE);
 
 	CSRA_XS((caddr_t)dev_hdl, INTERRUPT_MAPPING, ino, val);
@@ -3093,17 +3092,19 @@
 			delay(drv_usectohz(link_status_check));
 			reg = CSR_XR(csr_base, DLU_LINK_LAYER_STATUS);
 
-		    if ((((reg >> DLU_LINK_LAYER_STATUS_INIT_FC_SM_STS) &
-			DLU_LINK_LAYER_STATUS_INIT_FC_SM_STS_MASK) ==
-			DLU_LINK_LAYER_STATUS_INIT_FC_SM_STS_FC_INIT_DONE) &&
-			(reg & (1ull << DLU_LINK_LAYER_STATUS_DLUP_STS)) &&
-			((reg & DLU_LINK_LAYER_STATUS_LNK_STATE_MACH_STS_MASK)
-			==
-			DLU_LINK_LAYER_STATUS_LNK_STATE_MACH_STS_DL_ACTIVE)) {
-			DBG(DBG_HP, NULL, "oberon_hp_pwron : link is up\n");
-				link_up = B_TRUE;
-		    } else
+		if ((((reg >> DLU_LINK_LAYER_STATUS_INIT_FC_SM_STS) &
+		    DLU_LINK_LAYER_STATUS_INIT_FC_SM_STS_MASK) ==
+		    DLU_LINK_LAYER_STATUS_INIT_FC_SM_STS_FC_INIT_DONE) &&
+		    (reg & (1ull << DLU_LINK_LAYER_STATUS_DLUP_STS)) &&
+		    ((reg &
+		    DLU_LINK_LAYER_STATUS_LNK_STATE_MACH_STS_MASK) ==
+		    DLU_LINK_LAYER_STATUS_LNK_STATE_MACH_STS_DL_ACTIVE)) {
+			DBG(DBG_HP, NULL, "oberon_hp_pwron : "
+			    "link is up\n");
+			link_up = B_TRUE;
+		} else
 			link_retry = B_TRUE;
+
 		}
 		/* END CSTYLED */
 	}
@@ -3382,7 +3383,7 @@
 int
 hvio_hotplug_init(dev_info_t *dip, void *arg)
 {
-	pciehpc_regops_t *regops = (pciehpc_regops_t *)arg;
+	pcie_hp_regops_t *regops = (pcie_hp_regops_t *)arg;
 	px_t	*px_p = DIP_TO_STATE(dip);
 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
 	volatile uint64_t reg;
--- a/usr/src/uts/sun4u/io/px/px_lib4u.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4u/io/px/px_lib4u.c	Mon Nov 02 15:58:28 2009 +0800
@@ -40,7 +40,6 @@
 #include <sys/cpuvar.h>
 #include <sys/ivintr.h>
 #include <sys/byteorder.h>
-#include <sys/hotplug/pci/pciehpc.h>
 #include <sys/spl.h>
 #include <px_obj.h>
 #include <sys/pcie_pwr.h>
@@ -51,6 +50,7 @@
 #include "px_lib4u.h"
 #include "px_err.h"
 #include "oberon_regs.h"
+#include <sys/hotplug/pci/pcie_hp.h>
 
 #pragma weak jbus_stst_order
 
@@ -1495,7 +1495,7 @@
 	int		rc_err, fab_err, i;
 	int		acctype = pec_p->pec_safeacc_type;
 	ddi_fm_error_t	derr;
-	px_ranges_t	*ranges_p;
+	pci_ranges_t	*ranges_p;
 	int		range_len;
 	uint32_t	addr_high, addr_low;
 	pcie_req_id_t	bdf = PCIE_INVALID_BDF;
@@ -1520,7 +1520,7 @@
 	/* Figure out if this is a cfg or mem32 access */
 	addr_high = (uint32_t)(addr >> 32);
 	addr_low = (uint32_t)addr;
-	range_len = px_p->px_ranges_length / sizeof (px_ranges_t);
+	range_len = px_p->px_ranges_length / sizeof (pci_ranges_t);
 	i = 0;
 	for (ranges_p = px_p->px_ranges_p; i < range_len; i++, ranges_p++) {
 		if (ranges_p->parent_high == addr_high) {
@@ -2350,7 +2350,7 @@
 uint32_t
 px_fab_get(px_t *px_p, pcie_req_id_t bdf, uint16_t offset)
 {
-	px_ranges_t	*rp = px_p->px_ranges_p;
+	pci_ranges_t	*rp = px_p->px_ranges_p;
 	uint64_t	range_prop, base_addr;
 	int		bank = PCI_REG_ADDR_G(PCI_ADDR_CONFIG);
 	uint32_t	val;
@@ -2369,7 +2369,7 @@
 void
 px_fab_set(px_t *px_p, pcie_req_id_t bdf, uint16_t offset,
     uint32_t val) {
-	px_ranges_t	*rp = px_p->px_ranges_p;
+	pci_ranges_t	*rp = px_p->px_ranges_p;
 	uint64_t	range_prop, base_addr;
 	int		bank = PCI_REG_ADDR_G(PCI_ADDR_CONFIG);
 
@@ -2509,7 +2509,7 @@
  * fetch chip's range propery's value
  */
 uint64_t
-px_get_range_prop(px_t *px_p, px_ranges_t *rp, int bank)
+px_get_range_prop(px_t *px_p, pci_ranges_t *rp, int bank)
 {
 	uint64_t mask, range_prop;
 
@@ -2543,11 +2543,11 @@
 static uint_t
 px_hp_intr(caddr_t arg1, caddr_t arg2)
 {
-	px_t	*px_p = (px_t *)arg1;
-	pxu_t 	*pxu_p = (pxu_t *)px_p->px_plat_p;
-	int	rval;
-
-	rval = pciehpc_intr(px_p->px_dip);
+	px_t		*px_p = (px_t *)arg1;
+	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
+	int		rval;
+
+	rval = pcie_intr(px_p->px_dip);
 
 #ifdef  DEBUG
 	if (rval == DDI_INTR_UNCLAIMED)
@@ -2571,6 +2571,10 @@
 	pxu_t 	*pxu_p = (pxu_t *)px_p->px_plat_p;
 	uint64_t ret;
 
+	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "hotplug-capable") == 0)
+		return (DDI_FAILURE);
+
 	if ((ret = hvio_hotplug_init(dip, arg)) == DDI_SUCCESS) {
 		if (px_lib_intr_devino_to_sysino(px_p->px_dip,
 		    px_p->px_inos[PX_INTR_HOTPLUG], &pxu_p->hp_sysino) !=
@@ -2583,7 +2587,7 @@
 			return (DDI_FAILURE);
 		}
 
-		VERIFY(add_ivintr(pxu_p->hp_sysino, PX_PCIEHP_PIL,
+		VERIFY(add_ivintr(pxu_p->hp_sysino, PCIE_INTR_PRI,
 		    (intrfunc)px_hp_intr, (caddr_t)px_p, NULL, NULL) == 0);
 
 		px_ib_intr_enable(px_p, intr_dist_cpuid(),
@@ -2603,7 +2607,7 @@
 		px_ib_intr_disable(px_p->px_ib_p,
 		    px_p->px_inos[PX_INTR_HOTPLUG], IB_INTR_WAIT);
 
-		VERIFY(rem_ivintr(pxu_p->hp_sysino, PX_PCIEHP_PIL) == 0);
+		VERIFY(rem_ivintr(pxu_p->hp_sysino, PCIE_INTR_PRI) == 0);
 	}
 }
 
@@ -2613,7 +2617,9 @@
 void
 px_hp_intr_redist(px_t *px_p)
 {
-	if (px_p && (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE)) {
+	pcie_bus_t	*bus_p = PCIE_DIP2BUS(px_p->px_dip);
+
+	if (px_p && PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) {
 		px_ib_intr_dist_en(px_p->px_dip, intr_dist_cpuid(),
 		    px_p->px_inos[PX_INTR_HOTPLUG], B_FALSE);
 	}
--- a/usr/src/uts/sun4u/io/px/px_lib4u.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4u/io/px/px_lib4u.h	Mon Nov 02 15:58:28 2009 +0800
@@ -26,7 +26,6 @@
 #ifndef _SYS_PX_LIB4U_H
 #define	_SYS_PX_LIB4U_H
 
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -153,6 +152,14 @@
 #define	EQ_ACTIVE_STATE	0x2			/* ACTIVE */
 #define	EQ_ERROR_STATE	0x4			/* ERROR */
 
+/*
+ * Default EQ Configurations
+ */
+#define	EQ_CNT		36
+#define	EQ_REC_CNT	128
+#define	EQ_1ST_ID	0
+#define	EQ_1ST_DEVINO	24
+
 #define	MMU_INVALID_TTE		0ull
 #define	MMU_TTE_VALID(tte)	(((tte) & MMU_TTE_V) == MMU_TTE_V)
 #define	MMU_OBERON_PADDR_MASK	0x7fffffffffff
@@ -324,7 +331,7 @@
     r_addr_t ra, io_attributes_t attr, io_addr_t *io_addr_p);
 extern uint64_t hvio_get_bypass_base(pxu_t *pxu_p);
 extern uint64_t hvio_get_bypass_end(pxu_t *pxu_p);
-extern uint64_t px_get_range_prop(px_t *px_p, px_ranges_t *rp, int bank);
+extern uint64_t px_get_range_prop(px_t *px_p, pci_ranges_t *rp, int bank);
 
 
 /*
--- a/usr/src/uts/sun4u/px/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4u/px/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -21,11 +21,9 @@
 #
 # uts/sun4u/px/Makefile
 #
-# 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 makefile drives the production of the pci driver kernel module
 #
 #	sun4u implementation architecture dependent
@@ -87,7 +85,7 @@
 #
 #	Dependency
 #
-LDFLAGS += -dy -Nmisc/busra -Nmisc/pcie -Nmisc/pcihp -Nmisc/pciehpc
+LDFLAGS += -dy -Nmisc/pcie
 
 #
 #	Default build targets.
--- a/usr/src/uts/sun4u/sys/pci/pci_obj.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4u/sys/pci/pci_obj.h	Mon Nov 02 15:58:28 2009 +0800
@@ -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,20 +19,19 @@
  * 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.
  */
 
 #ifndef	_SYS_PCI_OBJ_H
 #define	_SYS_PCI_OBJ_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
 #include <sys/pci.h>
+#include <sys/pci_impl.h>
 #include <sys/pci_intr_lib.h>
 #include <sys/pci/pci_nexus.h>
 #include <sys/pci/pci_types.h>
--- a/usr/src/uts/sun4u/sys/pci/pci_tools_ext.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4u/sys/pci/pci_tools_ext.h	Mon Nov 02 15:58:28 2009 +0800
@@ -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,15 +19,13 @@
  * 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.
  */
 
 #ifndef _SYS_PCI_TOOLS_EXT_H
 #define	_SYS_PCI_TOOLS_EXT_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -36,13 +33,6 @@
 /* This file contains pcitool defs exported to other modules of a PCI driver. */
 
 /*
- * Minor numbers for dedicated pcitool nodes.
- * Note that FF and FE minor numbers are used for other minor nodes.
- */
-#define	PCI_TOOL_REG_MINOR_NUM	0xFD
-#define	PCI_TOOL_INTR_MINOR_NUM	0xFC
-
-/*
  * Functions exported from the pci_tools.c module.
  */
 extern int pcitool_dev_reg_ops(dev_t dev, void *arg, int cmd, int mode);
--- a/usr/src/uts/sun4u/sys/pci/pci_var.h	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4u/sys/pci/pci_var.h	Mon Nov 02 15:58:28 2009 +0800
@@ -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_PCI_VAR_H
 #define	_SYS_PCI_VAR_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -126,10 +124,6 @@
 	 */
 	pci_state_t pci_state;
 	uint_t pci_soft_state;
-#define	PCI_SOFT_STATE_OPEN		0x01
-#define	PCI_SOFT_STATE_OPEN_EXCL	0x02
-#define	PCI_SOFT_STATE_CLOSED		0x04
-	uint_t pci_open_count;
 	uint16_t pci_tsb_cookie;	/* IOMMU TSB allocation */
 	kmutex_t pci_mutex;
 
--- a/usr/src/uts/sun4v/io/px/px_lib4v.c	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4v/io/px/px_lib4v.c	Mon Nov 02 15:58:28 2009 +0800
@@ -38,7 +38,6 @@
 #include <sys/hsvc.h>
 #include <px_obj.h>
 #include <sys/machsystm.h>
-#include <sys/hotplug/pci/pcihp.h>
 #include "px_lib4v.h"
 #include "px_err.h"
 
@@ -103,7 +102,7 @@
 	 * any indirect PCI config access services
 	 */
 	(void) ddi_prop_update_int(makedevice(ddi_driver_major(dip),
-	    PCIHP_AP_MINOR_NUM(ddi_get_instance(dip), PCIHP_DEVCTL_MINOR)), dip,
+	    PCI_MINOR_NUM(ddi_get_instance(dip), PCI_DEVCTL_MINOR)), dip,
 	    PCI_BUS_CONF_MAP_PROP, 1);
 
 	DBG(DBG_ATTACH, dip, "px_lib_dev_init: dev_hdl 0x%llx\n", *dev_hdl);
@@ -136,7 +135,7 @@
 	DBG(DBG_DETACH, dip, "px_lib_dev_fini: dip 0x%p\n", dip);
 
 	(void) ddi_prop_remove(makedevice(ddi_driver_major(dip),
-	    PCIHP_AP_MINOR_NUM(ddi_get_instance(dip), PCIHP_DEVCTL_MINOR)), dip,
+	    PCI_MINOR_NUM(ddi_get_instance(dip), PCI_DEVCTL_MINOR)), dip,
 	    PCI_BUS_CONF_MAP_PROP);
 
 	if (--px_vpci_users == 0)
@@ -1508,7 +1507,7 @@
 {
 	uint32_t	addr_high, addr_low;
 	pcie_req_id_t	bdf = PCIE_INVALID_BDF;
-	px_ranges_t	*ranges_p;
+	pci_ranges_t	*ranges_p;
 	int		range_len, i;
 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle;
 	ddi_fm_error_t derr;
@@ -1528,7 +1527,7 @@
 	 * Make sure this failed load came from this PCIe port.  Check by
 	 * matching the upper 32 bits of the address with the ranges property.
 	 */
-	range_len = px_p->px_ranges_length / sizeof (px_ranges_t);
+	range_len = px_p->px_ranges_length / sizeof (pci_ranges_t);
 	i = 0;
 	for (ranges_p = px_p->px_ranges_p; i < range_len; i++, ranges_p++) {
 		if (ranges_p->parent_high == addr_high) {
--- a/usr/src/uts/sun4v/niumx/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4v/niumx/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -20,11 +20,9 @@
 #
 #
 # uts/sun4v/niumx/Makefile
-# 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 makefile drives the production of the niumx driver kernel module
 #
@@ -57,9 +55,8 @@
 INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
 
 #
-#	Include SUN4 and SUN4U specific headers files
+#	Include SUN4V specific headers files
 #
-INC_PATH	+= -I$(UTSBASE)/sun4/io/niumx
 INC_PATH	+= -I$(UTSBASE)/sun4v/io/niumx
 
 #
@@ -73,11 +70,6 @@
 CFLAGS += -dalign
 
 #
-#	Dependency
-#
-LDFLAGS += -dy -Nmisc/busra -Nmisc/pcie
-
-#
 #	Default build targets.
 #
 .KEEP_STATE:
--- a/usr/src/uts/sun4v/px/Makefile	Sun Nov 01 14:14:46 2009 -0800
+++ b/usr/src/uts/sun4v/px/Makefile	Mon Nov 02 15:58:28 2009 +0800
@@ -21,11 +21,9 @@
 #
 # uts/sun4v/px/Makefile
 #
-# 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 makefile drives the production of the px driver kernel module.
 #	sun4v implementation architecture dependent
 #
@@ -89,7 +87,7 @@
 
 #	Dependency
 #
-LDFLAGS += -dy -Nmisc/busra -Nmisc/pcie -Nmisc/pciehpc -Nmisc/pcihp
+LDFLAGS += -dy -Nmisc/pcie
 
 #	Default build targets.
 #