changeset 2305:7954d746a1b5

6392835 move driver central to usr/src 6392843 move driver socal to usr/src 6393456 move driver pcic to usr/src 6393457 move driver pem to usr/src 6393459 move driver envctrltwo to usr/src 6393461 move driver lombus to usr/src 6393465 move driver rmclomv to usr/src 6393468 move driver wrsmd to usr/src 6438236 cfgadm plugins for ac & sysctrl want to be reunited with their drivers in usr/src 6443714 CardBus driver should be moved from usr/closed to usr/src
author stevel
date Thu, 29 Jun 2006 14:43:12 -0700
parents b10a5efc0283
children eb8669cd1052
files usr/src/Makefile usr/src/cmd/mdb/sun4u/modules/Makefile usr/src/cmd/mdb/sun4u/modules/wrsmd/Makefile usr/src/cmd/mdb/sun4u/modules/wrsmd/v9/Makefile usr/src/cmd/mdb/sun4u/modules/wrsmd/wrsmd.c usr/src/lib/cfgadm_plugins/Makefile usr/src/lib/cfgadm_plugins/ac/Makefile usr/src/lib/cfgadm_plugins/ac/Makefile.com usr/src/lib/cfgadm_plugins/ac/ac.xcl usr/src/lib/cfgadm_plugins/ac/common/mapfile-vers usr/src/lib/cfgadm_plugins/ac/common/mema.c usr/src/lib/cfgadm_plugins/ac/common/mema_prom.c usr/src/lib/cfgadm_plugins/ac/common/mema_prom.h usr/src/lib/cfgadm_plugins/ac/common/mema_test.c usr/src/lib/cfgadm_plugins/ac/common/mema_test.h usr/src/lib/cfgadm_plugins/ac/common/mema_test_config.c usr/src/lib/cfgadm_plugins/ac/common/mema_test_subr.c usr/src/lib/cfgadm_plugins/ac/common/mema_util.c usr/src/lib/cfgadm_plugins/ac/common/mema_util.h usr/src/lib/cfgadm_plugins/ac/sparc/Makefile usr/src/lib/cfgadm_plugins/ac/sparcv9/Makefile usr/src/lib/cfgadm_plugins/sysctrl/Makefile usr/src/lib/cfgadm_plugins/sysctrl/Makefile.com usr/src/lib/cfgadm_plugins/sysctrl/common/cfga.c usr/src/lib/cfgadm_plugins/sysctrl/common/mapfile-vers usr/src/lib/cfgadm_plugins/sysctrl/sparc/Makefile usr/src/lib/cfgadm_plugins/sysctrl/sparcv9/Makefile usr/src/lib/cfgadm_plugins/sysctrl/sysctrl.xcl usr/src/uts/common/Makefile.files usr/src/uts/common/Makefile.rules usr/src/uts/common/io/cardbus/cardbus.c usr/src/uts/common/io/cardbus/cardbus.h usr/src/uts/common/io/cardbus/cardbus_cfg.c usr/src/uts/common/io/cardbus/cardbus_cfg.h usr/src/uts/common/io/cardbus/cardbus_hp.c usr/src/uts/common/io/cardbus/cardbus_hp.h usr/src/uts/common/io/cardbus/cardbus_parse.h usr/src/uts/common/io/pcic.c usr/src/uts/common/io/pcic.conf usr/src/uts/common/pcmcia/pem/pem.c usr/src/uts/common/pcmcia/pem/pem.conf usr/src/uts/common/sys/Makefile usr/src/uts/common/sys/lombus.h usr/src/uts/common/sys/pcic_reg.h usr/src/uts/common/sys/pcic_var.h usr/src/uts/common/sys/pem.h usr/src/uts/common/sys/syshw.h usr/src/uts/i86pc/Makefile.i86pc.shared usr/src/uts/i86pc/pcic/Makefile usr/src/uts/intel/Makefile.intel.shared usr/src/uts/intel/cardbus/Makefile usr/src/uts/intel/pem/Makefile usr/src/uts/sparc/Makefile.sparc.shared usr/src/uts/sparc/cardbus/Makefile usr/src/uts/sparc/pcic/Makefile usr/src/uts/sparc/pem/Makefile usr/src/uts/sparc/socal/Makefile usr/src/uts/sun/Makefile.files usr/src/uts/sun/io/socal.c usr/src/uts/sun/io/socal_ucode.c usr/src/uts/sun/sys/Makefile usr/src/uts/sun/sys/socal_cq_defs.h usr/src/uts/sun/sys/socalmap.h usr/src/uts/sun/sys/socalvar.h usr/src/uts/sun4u/Makefile.files usr/src/uts/sun4u/Makefile.sun4u.shared usr/src/uts/sun4u/io/rmclomv.c usr/src/uts/sun4u/io/rmclomv.conf usr/src/uts/sun4u/io/wrsmd.c usr/src/uts/sun4u/io/wrsmd.conf usr/src/uts/sun4u/javelin/Makefile.files usr/src/uts/sun4u/javelin/Makefile.javelin.shared usr/src/uts/sun4u/javelin/envctrltwo/Makefile usr/src/uts/sun4u/javelin/io/envctrltwo.c usr/src/uts/sun4u/javelin/sys/envctrltwo.h usr/src/uts/sun4u/lw2plus/Makefile usr/src/uts/sun4u/lw2plus/Makefile.files usr/src/uts/sun4u/lw2plus/Makefile.lw2plus usr/src/uts/sun4u/lw2plus/Makefile.rules usr/src/uts/sun4u/lw2plus/Makefile.targ usr/src/uts/sun4u/lw2plus/io/lombus.c usr/src/uts/sun4u/lw2plus/io/lombus.conf usr/src/uts/sun4u/lw2plus/lombus/Makefile usr/src/uts/sun4u/rmclomv/Makefile usr/src/uts/sun4u/sunfire/Makefile.files usr/src/uts/sun4u/sunfire/Makefile.sunfire.shared usr/src/uts/sun4u/sunfire/central/Makefile usr/src/uts/sun4u/sunfire/io/central.c usr/src/uts/sun4u/sys/rmclomv_impl.h usr/src/uts/sun4u/sys/wrsmd.h usr/src/uts/sun4u/wrsmd/Makefile usr/src/xmod/cry_files
diffstat 92 files changed, 67887 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/Makefile	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -276,7 +276,7 @@
 	@cd uts/sun4u/boston;	pwd;	$(MAKE) EXPORT_SRC
 	@cd uts/sun4u/seattle;	pwd;	$(MAKE) EXPORT_SRC
 	@cd uts/sun4u/littleneck;	pwd;	$(MAKE) EXPORT_SRC
-	@cd $(CLOSED)/uts/sun4u/lw2plus;	pwd;	$(MAKE) EXPORT_SRC
+	@cd uts/sun4u/lw2plus;	pwd;	$(MAKE) EXPORT_SRC
 	@cd uts/sun4u/lw8;	pwd;	$(MAKE) EXPORT_SRC
 	@cd uts/sun4u/mpxu;	pwd;	$(MAKE) EXPORT_SRC
 	@cd uts/sun4u/opl;      pwd;    $(MAKE) EXPORT_SRC
--- a/usr/src/cmd/mdb/sun4u/modules/Makefile	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/cmd/mdb/sun4u/modules/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -26,10 +26,6 @@
 
 include $(SRC)/Makefile.master
 
-CLOSED_SUN4UMOD = $(CLOSED)/cmd/mdb/sun4u/modules
-
-SUBDIRS = unix wrsm lw8 serengeti
-
-$(CLOSED_BUILD)SUBDIRS += $(CLOSED_SUN4UMOD)/wrsmd
+SUBDIRS = unix wrsm lw8 serengeti wrsmd
 
 include ../../Makefile.subdirs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/sun4u/modules/wrsmd/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+SUBDIRS = v9
+include $(SRC)/cmd/mdb/Makefile.subdirs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/sun4u/modules/wrsmd/v9/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+MODULE = wrsmd.so
+MDBTGT = kvm
+
+MODSRCS = wrsmd.c
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/cmd/Makefile.cmd.64
+include $(SRC)/cmd/mdb/sparc/Makefile.sparcv9
+include $(SRC)/cmd/mdb/sun4u/Makefile.sun4u
+include $(SRC)/cmd/mdb/Makefile.module
+
+CPPFLAGS += -DMP -D_MACHDEP
+CPPFLAGS += -D_KERNEL
+CPPFLAGS += -I../../../../../../../src/cmd/mdb/common
+CPPFLAGS += -I$(SRC)/uts/sun4u
+CPPFLAGS += -I$(SRC)/uts/sfmmu
+CPPFLAGS += -I$(SRC)/uts/sparc/v9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/sun4u/modules/wrsmd/wrsmd.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,294 @@
+/*
+ * 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 2001 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/mdb_modapi.h>
+#include <sys/stream.h>
+#include <sys/note.h>
+#include <sys/wrsmd.h>
+
+#define	WRSMDSTATE_TO_SHORTSTR(x) (				\
+	(x == WRSMD_STATE_NEW) ? "NEW" :				\
+	(x == WRSMD_STATE_INPROGRESS) ? "INPROGRESS" :		\
+	(x == WRSMD_STATE_DELETING) ? "DELETING" :		\
+	(x == WRSMD_STATE_W_SCONNTMO) ? "W_SCONNTMO" :		\
+	(x == WRSMD_STATE_W_ACCEPT) ? "W_ACCEPT" :		\
+	(x == WRSMD_STATE_W_ACK) ? "W_ACK"  :			\
+	(x == WRSMD_STATE_W_READY) ? "W_READY" :			\
+	(x == WRSMD_STATE_W_FQE) ? "W_FQE" :			\
+	(x == WRSMD_STATE_S_REQ_CONNECT) ? "S_REQ_CONNECT" :	\
+	(x == WRSMD_STATE_S_NEWCONN) ? "S_NEWCONN" :		\
+	(x == WRSMD_STATE_S_CONNXFER_ACCEPT) ? "S_CONNXFER_ACCEPT" : \
+	(x == WRSMD_STATE_S_CONNXFER_ACK) ? "S_CONNXFER_ACK" :	\
+	(x == WRSMD_STATE_S_XFER) ? "S_XFER" :			\
+	(x == WRSMD_STATE_S_DELETE) ? "S_DELETE" :		\
+	(x == WRSMD_STATE_S_SCONN) ? "S_SCONN" : "unknown")
+
+
+
+
+/*
+ * wrsmd_dev
+ */
+
+
+/*
+ * Initialize the wrsmd_dev walker by either using the given starting
+ * address, or reading the value of the kernel's wrsmddev pointer.
+ */
+static int
+wrsmd_dev_walk_init(mdb_walk_state_t *wsp)
+{
+	if (wsp->walk_addr == NULL &&
+	    mdb_readvar(&wsp->walk_addr, "wrsmddev") == -1) {
+		mdb_warn("failed to read 'wrsmddev'");
+		return (WALK_ERR);
+	}
+
+	wsp->walk_data = NULL;
+	return (WALK_NEXT);
+}
+
+/*
+ * At each step, read a wrsmd_t into our private storage, and then
+ * invoke the callback function.  We terminate when we reach a NULL next
+ * pointer.
+ */
+static int
+wrsmd_dev_walk_step(mdb_walk_state_t *wsp)
+{
+	int status;
+	wrsmd_t wrsmd;
+
+	if (wsp->walk_addr == NULL)
+		return (WALK_DONE);
+
+	if (mdb_vread(&wrsmd, sizeof (wrsmd), wsp->walk_addr) !=
+	    sizeof (wrsmd)) {
+		mdb_warn("failed to read wrsmd_t at %p", wsp->walk_addr);
+		return (WALK_DONE);
+	}
+
+	status = wsp->walk_callback(wsp->walk_addr, &wrsmd, wsp->walk_cbdata);
+
+	wsp->walk_addr = (uintptr_t)wrsmd.wrsmd_nextp;
+
+	return (status);
+}
+
+
+/*
+ * print list of valid nodes in wrsmd
+ */
+void
+wrsmd_print_nodes(wrsmd_t *wrsmd)
+{
+	int i;
+	wrsmd_dest_t dest;
+	wrsmd_dqe_t dqe;
+	wrsmd_fqe_t fqe;
+
+	mdb_printf("Remote Destinations:\n");
+	mdb_printf("%7s  %34s  %6s  %6s  %8s\n",
+	    "rsmaddr",
+	    "____________state/estate___________",
+	    "dstate",
+	    "refcnt",
+	    "pkts-q'd?");
+
+	for (i = 0; i < RSM_MAX_DESTADDR; i++) {
+		if (wrsmd->wrsmd_desttbl[i]) {
+			if (mdb_vread(&dest, sizeof (dest),
+			    (uintptr_t)wrsmd->wrsmd_desttbl[i]) !=
+			    sizeof (dest)) {
+				mdb_warn("failed to read wrsmd_dest_t at %p",
+				    wrsmd->wrsmd_desttbl[i]);
+				return;
+			}
+
+			mdb_printf("%7d  %17s/%17s  %6d  %6d  %8s\n",
+			    dest.rd_rsm_addr,
+			    WRSMDSTATE_TO_SHORTSTR(dest.rd_state),
+			    WRSMDSTATE_TO_SHORTSTR(dest.rd_estate),
+			    dest.rd_dstate,
+			    dest.rd_refcnt,
+			    dest.rd_queue_h ? "yes" : "no");
+			mdb_printf("		exportseg "
+			    "handle & segid: 0x%16p %8d\n",
+			    dest.rd_lxferhand,
+			    dest.rd_lxfersegid);
+			mdb_printf("		importseg "
+			    "handle & segid: 0x%16p %8d\n",
+			    dest.rd_rxferhand,
+			    dest.rd_rxfersegid);
+			mdb_printf("		loaned-bufs %u\n",
+			    dest.rd_nlb);
+
+			if (mdb_vread(&fqe, sizeof (wrsmd_fqe_t),
+			    (uintptr_t)dest.rd_fqr_n) != sizeof (wrsmd_fqe_t)) {
+				mdb_warn("failed to read fqe at %p",
+				    dest.rd_fqr_n);
+			} else {
+				mdb_printf("		available fqes? %s\n",
+				    (dest.rd_cached_fqr_cnt ||
+				    (fqe.s.fq_seqnum == (dest.rd_fqr_seq &
+				    WRSMD_FQE_SEQ_MASK))) ? "yes" : "no");
+			}
+
+			if (mdb_vread(&dqe, sizeof (wrsmd_dqe_t),
+			    (uintptr_t)dest.rd_dqr_n) != sizeof (wrsmd_dqe_t)) {
+				mdb_warn("failed to read dqe at %p",
+				    dest.rd_dqr_n);
+			} else {
+				mdb_printf("		available dqes? %s\n",
+				    (dqe.s.dq_seqnum == (dest.rd_dqr_seq &
+				    WRSMD_DQE_SEQ_MASK)) ? "yes" : "no");
+			}
+		}
+	}
+
+	mdb_printf("\n");
+}
+
+
+
+/*
+ * dcmd for printing out information about a Wildcat RSM controller
+ * (wrsmd_t).
+ */
+static int
+wrsmd_dev(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+	wrsmd_t wrsmd;
+
+	if (argc != 0)
+		return (DCMD_USAGE);
+
+	/*
+	 * If no wrsmd_t address was specified on the command line,
+	 * we can print out all wrsmd wrsmd (controllers) by invoking the
+	 * walker, using this dcmd itself as the callback.
+	 */
+	if (!(flags & DCMD_ADDRSPEC)) {
+		if (mdb_walk_dcmd("wrsmd_dev", "wrsmd_dev",
+		    argc, argv) == -1) {
+			mdb_warn("failed to walk 'wrsmd_dev_walk'");
+			return (DCMD_ERR);
+		}
+		return (DCMD_OK);
+	}
+
+
+	if (mdb_vread(&wrsmd, sizeof (wrsmd), addr) != sizeof (wrsmd)) {
+		mdb_warn("failed to read wrsmd_t at %p", addr);
+		return (DCMD_OK);
+	}
+
+	/*
+	 * print interesting information
+	 */
+	mdb_printf("\nDevice Instance (Controller Id): %3d\n",
+	    wrsmd.wrsmd_ctlr_id);
+	mdb_printf("--------------------------------------\n");
+	mdb_printf("RSM address: %d\n",
+	    wrsmd.wrsmd_rsm_addr);
+	mdb_printf("attached streams: %d\n",
+	    wrsmd.wrsmd_attached_streams);
+
+	mdb_printf("ipackets %lu ierrors %u opackets %lu oerrors %u\n",
+	    wrsmd.wrsmd_ipackets,
+	    wrsmd.wrsmd_ierrors,
+	    wrsmd.wrsmd_opackets,
+	    wrsmd.wrsmd_oerrors);
+
+	mdb_printf("collisions %u  xfers %u xfer_pkts %u syncdqes %u\n",
+	    wrsmd.wrsmd_collisions,
+	    wrsmd.wrsmd_xfers,
+	    wrsmd.wrsmd_xfer_pkts,
+	    wrsmd.wrsmd_syncdqes);
+
+	mdb_printf("lbufs %u nlbufs %u pullup %u pullup_fail %u\n",
+	    wrsmd.wrsmd_lbufs,
+	    wrsmd.wrsmd_nlbufs,
+	    wrsmd.wrsmd_pullup,
+	    wrsmd.wrsmd_pullup_fail);
+
+	mdb_printf("starts %u start_xfers %u fqetmo_hint %u fqetmo_drops %u "
+	    "maxq_drops %u\n",
+	    wrsmd.wrsmd_starts,
+	    wrsmd.wrsmd_start_xfers,
+	    wrsmd.wrsmd_fqetmo_hint,
+	    wrsmd.wrsmd_fqetmo_drops,
+	    wrsmd.wrsmd_maxq_drops);
+
+	mdb_printf("errs %u in_bytes %lu out_bytes %lu\n",
+	    wrsmd.wrsmd_errs,
+	    wrsmd.wrsmd_in_bytes,
+	    wrsmd.wrsmd_out_bytes);
+
+	wrsmd_print_nodes(&wrsmd);
+
+	mdb_printf("\n");
+	return (DCMD_OK);
+}
+
+
+
+
+/*
+ * setup info
+ */
+
+/*
+ * MDB module linkage information:
+ *
+ * We declare a list of structures describing our dcmds, a list of structures
+ * describing our walkers, and a function named _mdb_init to return a pointer
+ * to our module information.
+ */
+
+static const mdb_dcmd_t dcmds[] = {
+	{ "wrsmd_dev", NULL, "wrsmd device information",
+	    wrsmd_dev },
+	{ NULL }
+};
+
+static const mdb_walker_t walkers[] = {
+	{ "wrsmd_dev", "walk list of wrsmd device structures",
+		wrsmd_dev_walk_init, wrsmd_dev_walk_step, NULL },
+	{ NULL }
+};
+
+static const mdb_modinfo_t modinfo = {
+	MDB_API_VERSION, dcmds, walkers
+};
+
+const mdb_modinfo_t *
+_mdb_init(void)
+{
+	return (&modinfo);
+}
--- a/usr/src/lib/cfgadm_plugins/Makefile	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/lib/cfgadm_plugins/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -29,16 +29,11 @@
 
 include $(SRC)/Makefile.master
 
-CLOSED_PLUGIN = $(CLOSED)/lib/cfgadm_plugins/
-
 COMMON_SUBDIRS= scsi pci usb ib
-sparc_SUBDIRS=	sbd
+sparc_SUBDIRS=	sbd ac sysctrl
 
 i386_SUBDIRS= sata
 
-$(CLOSED_BUILD)sparc_SUBDIRS += $(CLOSED_PLUGIN)/ac
-$(CLOSED_BUILD)sparc_SUBDIRS += $(CLOSED_PLUGIN)/sysctrl
-
 SUBDIRS= $(COMMON_SUBDIRS) $($(MACH)_SUBDIRS)
 
 ALL_SUBDIRS= $(COMMON_SUBDIRS) $(sparc_SUBDIRS) $(i386_SUBDIRS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/ac/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,74 @@
+#
+# 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.
+#
+# 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 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/cfgadm_plugins/ac/Makefile
+
+include		$(SRC)/Makefile.master
+
+SUBDIRS=	$(MACH) $(BUILD64) $(MACH64)
+
+all :=		TARGET= all
+clean :=	TARGET= clean
+clobber :=	TARGET= clobber
+delete :=	TARGET= delete
+install :=	TARGET= install
+lint :=		TARGET= lint
+_msg :=		TARGET= _msg
+catalog :=	TARGET= catalog
+package :=	TARGET= package
+
+TEXT_DOMAIN=	SUNW_OST_OSLIB
+XGETFLAGS=	-a -x ac.xcl
+POFILE=		ac.po
+POFILES=	generic.po
+
+SED=	sed
+GREP=	grep
+CP=	cp
+
+.KEEP_STATE:
+
+all clean clobber delete install lint catalog package: $(SUBDIRS)
+
+$(MACH) $(MACH64):	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]`
+	$(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/ac/Makefile.com	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,99 @@
+#
+# 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.
+#
+# 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 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/ac/Makefile.com
+
+include $(SRC)/lib/cfgadm_plugins/Makefile.com
+
+PLATFORM=	sun4u
+LIBRARY= ac.a
+VERS= .1
+
+OBJECTS= mema.o mema_prom.o mema_test.o mema_test_config.o mema_test_subr.o \
+	 mema_util.o
+
+# include library definitions
+include $(SRC)/lib/Makefile.lib
+
+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.root.bin=	$(INS) -s -d -m $(DIRMODE) $@
+$(CH)INS.dir.root.bin=	$(INS) -s -d -m $(DIRMODE) -u root -g bin $@
+
+USR_PLAT_DIR		= $(ROOT)/usr/platform
+USR_PSM_DIR		= $(USR_PLAT_DIR)/sun4u
+USR_PSM_LIB_DIR		= $(USR_PSM_DIR)/lib
+USR_PSM_LIB_CFG_DIR	= $(USR_PSM_LIB_DIR)/cfgadm
+USR_PSM_LIB_CFG_DIR_64	= $(USR_PSM_LIB_CFG_DIR)/$(MACH64)
+
+ROOTLIBDIR=     $(USR_PSM_LIB_CFG_DIR)
+ROOTLIBDIR64=   $(USR_PSM_LIB_CFG_DIR_64)
+
+MAPFILE=	../common/mapfile-vers
+SRCS=		$(OBJECTS:%.o=../common/%.c)
+
+LIBS = $(DYNLIB)
+
+CFLAGS +=	$(CCVERBOSE)
+DYNFLAGS +=	-M $(MAPFILE)
+LDLIBS +=	-lc
+
+CPPFLAGS +=	-I$(ROOT)/usr/platform/$(PLATFORM)/include
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint:   lintcheck
+
+$(DYNLIB):	$(MAPFILE)
+
+# Create target directories
+$(USR_PSM_DIR):		$(LINKED_DIRS)
+	-$(INS.dir.root.sys)
+
+$(USR_PSM_LIB_DIR):	$(USR_PSM_DIR) $(LINKED_LIB_DIRS)
+	-$(INS.dir.root.bin)
+
+$(USR_PSM_LIB_CFG_DIR):	$(USR_PSM_LIB_DIR) $(LINKED_CFG_DIRS)
+	-$(INS.dir.root.bin)
+
+$(USR_PSM_LIB_CFG_DIR_64):	$(USR_PSM_LIB_CFG_DIR)
+	-$(INS.dir.root.bin)
+
+$(USR_PSM_LIB_CFG_DIR)/%: % $(USR_PSM_LIB_CFG_DIR)
+	-$(INS.file)
+
+$(USR_PSM_LIB_CFG_DIR_64)/%: % $(USR_PSM_LIB_CFG_DIR_64)
+	-$(INS.file)
+
+# include library targets
+include $(SRC)/lib/Makefile.targ
+
+pics/%.o: ../common/%.c
+	$(COMPILE.c) -o $@ $<
+	$(POST_PROCESS_O)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/ac/ac.xcl	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,114 @@
+#
+# 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.
+#
+# 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
+#
+msgid  "disable-at-boot"
+msgid  "enable-at-boot"
+msgid  "timeout"
+msgid  "errno=%d"
+msgid  "bank"
+msgid  "ap_bk_idx(%s)\n"
+msgid  "ap_bk_idx: s=%s, n=%d\n"
+msgid  "ap_bk_idx(%s)=%d\n"
+msgid  "relocate-test"
+msgid  "board %d bank%d"
+msgid  ", "
+msgid  "???"
+msgid  ""
+msgid  "slot%d"
+msgid  " empty"
+msgid  "Gb"
+msgid  "Mb"
+msgid  " %d%s"
+msgid  " (%d%s used)"
+msgid  " base 0x%llx"
+msgid  " interleaved %u-way"
+msgid  " %s"
+msgid  "disabled at boot"
+msgid  " permanent"
+msgid  "memory"
+msgid  "ap_drv_idx(%s)\n"
+msgid  "ac"
+msgid  "ap_drv_idx(%s)=%d\n"
+msgid  "MEMADM_DEBUG"
+msgid  "a"
+msgid  "\nDebug started, pid=%d\n"
+msgid  "IOCTL: AC_MEM_CONFIGURE\n"
+msgid  "IOCTL: AC_MEM_UNCONFIGURE\n"
+msgid  "IOCTL: AC_MEM_TEST_START\n"
+msgid  "IOCTL: AC_MEM_TEST_STOP handle=%#x "
+       "condition=%d\n"
+msgid  "IOCTL: AC_MEM_TEST_READ handle=%#x "
+       "buf=%#x page=%#llx off=%#x count=%#x\n"
+msgid  "IOCTL: AC_MEM_TEST_WRITE handle=%#x "
+       "buf=%#x page=%#llx off=%#x count=%#x\n"
+msgid  "IOCTL: AC_MEM_ADMIN_VER:\n"
+msgid  "IOCTL: AC_MEM_STAT\n"
+msgid  "IOCTL: AC_MEM_EXERCISE arg=%d\n"
+msgid  "IOCTL: unknown (%#x)\n"
+msgid  "IOCTL failed, \"%s\" (errno=%d)\n"
+msgid  "IOCTL succeeded, ret=%d\n"
+msgid  "    handle=%#x tester_pid=%d "
+       "prev_condition=%d bank_size=%#llx "
+       "page_size=%#x line_size=%#x afar_base=%#llx\n"
+msgid  "module_id=%#llx afsr=%#llx "
+       "afar=%#llx udbh_error_reg=%#llx "
+       "udbl_error_reg=%#llx\n"
+msgid  "\n"
+msgid  "    version %d\n"
+msgid  "    rstate=%u ostate=%u "
+       "condition=%u status_time=%#lx board=%u\n"
+msgid  "    real_size=%u use_size=%u "
+       "busy=%u\n"
+msgid  "    page_size=%#x "
+       "phys_pages=%#llx managed=%#llx nonrelocatable=%#llx\n"
+msgid  "    memctl=%#llx "
+       "decode0=%#llx decode1=%#llx\n"
+msgid  "    base=%u npgs=%u"
+       " nopaget=%u nolock=%u isfree=%u reloc=%u"
+       " noreloc=%u\n"
+msgid  "total error %u\n"
+msgid  "quick"
+msgid  "normal"
+msgid  "extended"
+msgid  "max_errors"
+msgid  "Normal test started\n"
+msgid  "Normal test finished\n"
+msgid  "Quick test started\n"
+msgid  "Quick test finished\n"
+msgid  "Extended test started\n"
+msgid  "Extended test finished\n"
+msgid  "    March 1, "
+msgid  "    March 2, "
+msgid  "    March 3, "
+msgid  "    March 4, "
+msgid  "read. "
+msgid  "write. "
+msgid  "compare. "
+msgid  "read/compare. "
+msgid  "repeated read/compare. "
+msgid  "mixed line read/compare. "
+msgid  "line read/compare. "
+msgid  "%s%s%d%% complete.\n"
+msgid  "    Errors at page address: 0x%x.\n"
+msgid  "    Error reading page at address: 0x%x.\n"
+msgid  "    Error writing page at address: 0x%x.\n"
+msgid  "      Offset: 0x%x, data written/read: 0x%2x/0x%2x.\n"
+msgid  "\t-o {quick, normal, extended},[max_errors=#] -t ap_id [ap_id...]\n"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/ac/common/mapfile-vers	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,38 @@
+#
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2005 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, Version 1.0 only
+# (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
+#
+
+SUNWprivate_1.1 {
+	global:
+		cfga_change_state;
+		cfga_private_func;
+		cfga_test;
+		cfga_stat;
+		cfga_list;
+		cfga_help;
+	local:
+		*;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/ac/common/mema.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,1814 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <locale.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/dditypes.h>
+#include <sys/param.h>
+#include <sys/obpdefs.h>
+#include <sys/fhc.h>
+#include <sys/sysctrl.h>
+#include <sys/ac.h>
+#include <sys/spitregs.h>
+#include <config_admin.h>
+#include "mema_util.h"
+#include "mema_test.h"
+#include "mema_prom.h"
+
+#ifdef	DEBUG
+#define	DBG	(void) printf
+#define	DBG1	(void) printf
+#define	DBG3	(void) printf
+#define	DBG4	(void) printf
+#else
+#define	DBG(a, b)
+#define	DBG1(a)
+#define	DBG3(a, b, c)
+#define	DBG4(a, b, c, d)
+#endif
+
+#ifndef P_DER_UE
+/*
+ * <sys/spitregs.h> has these defines inside 'ifdef _KERNEL' at the
+ * time of writing.  Re-define here if that is still the case.
+ */
+
+#define	P_DER_UE	0x00000000000000200ULL	/* UE has occurred */
+#define	P_DER_CE	0x00000000000000100ULL	/* CE has occurred */
+#define	P_DER_E_SYND	0x000000000000000FFULL	/* SYND<7:0>: ECC syndrome */
+#endif /* ! P_DER_UE */
+
+#define	DEV_DEBUG
+#ifdef DEV_DEBUG
+#include <stdio.h>
+#include <stdlib.h>
+
+static FILE *debug_fp;
+static int debugging(void);
+static void dump_ioctl(int, void *);
+static void dump_ioctl_res(int, void *, int, int);
+#else /* DEV_DEBUG */
+#define	dump_ioctl(CMD, ARG)
+#define	dump_ioctl_res(CMD, ARG, RET, ERRNO)
+#endif /* DEV_DEBUG */
+
+typedef struct {
+	uint_t   board;
+	uint_t   bank;
+} mema_bank_t;
+
+static char *mema_opts[] = {
+#define	OPT_BOOT_DISABLE	0
+	"disable-at-boot",
+#define	OPT_BOOT_ENABLE		1
+	"enable-at-boot",
+#define	OPT_TIMEOUT		2
+	"timeout",
+	NULL
+};
+
+#define	OPT_NEEDS_VALUE(O)	((O) == OPT_TIMEOUT)
+
+#define	MAX_OPT_LENGTH		(sizeof ("disable-at-boot"))
+
+/*
+ * For each function there is an array of opt_control structures giving
+ * the valid options.  The array is terminated by an element with the
+ * subopt field set to -1.  The group field is used to identify
+ * mutually exclusive options, with zero meaning no grouping.
+ */
+struct opt_control {
+	int		subopt;
+	int		group;
+};
+
+/*
+ * Returned set of options.
+ * If the option takes a value, it will be set in 'val'
+ * if the corresponding bit is set in 'bits' is set,
+ * otherwise the pointer in 'val' is undefined.
+ */
+#define	OPT_VAL_ARRAY_SIZE	32	/* # bits in 'bits' */
+typedef struct {
+	unsigned int	bits;
+	char		*val[OPT_VAL_ARRAY_SIZE];
+} option_set_t;
+
+#define	OPTSET_INIT(S)		((S).bits = 0)
+#define	_OPT_TO_BIT(O)		(1 << (O))
+#define	OPTSET_SET_VAL(S, O, V)	((S).bits |= _OPT_TO_BIT(O), \
+				(S).val[(O)] = (V))
+#define	OPTSET_TEST(S, O)	(((S).bits & _OPT_TO_BIT(O)) != 0)
+#define	OPTSET_VAL(S, O)	((S).val[(O)])
+#define	OPTSET_IS_EMPTY(S)	((S).bits == 0)
+
+static option_set_t process_options(const char *, struct opt_control *,
+	int *, char **);
+
+static struct opt_control add_opts[] = {
+	{OPT_BOOT_ENABLE, 1},
+	{OPT_BOOT_DISABLE, 1},
+	{-1, 0}
+};
+
+static struct opt_control del_opts[] = {
+	{OPT_BOOT_ENABLE, 1},
+	{OPT_BOOT_DISABLE, 1},
+	{OPT_TIMEOUT, 2},
+	{-1, 0}
+};
+
+static struct opt_control stat_opts[] = {
+	{OPT_BOOT_ENABLE, 1},
+	{OPT_BOOT_DISABLE, 1},
+	{-1, 0}
+};
+
+#if !defined(TEXT_DOMAIN)
+#define	TEXT_DOMAIN	"SYS_TEST"
+#endif
+
+static const char still_testing[] = "bank %s being tested by process %d";
+static const char no_value[] = "sub-option \"%s\" does not take a value";
+static const char missing_value[] = "sub-option \"%s\" needs a value";
+static const char conflict_opt[] = "sub-option \"%s\" conflicts with \"%s\"";
+static const char unk_subopt[] = "sub-option \"%s\" unknown\n"
+	"choose from: %s";
+static const char not_valid[] =
+	"sub-option \"%s\" not valid for this operation\n"
+	"choose from: %s";
+static const char timeout_notnum[] =
+	"timeout value not a positive integer \"%s\"";
+static const char calloc_fail[] = "memory allocation failed (%d*%d bytes)";
+static const char unk_test[] = "test \"%s\" unknown\n"
+	"choose from: %s";
+static const char dup_test[] = "more than one test type specified (\"%s\")";
+static const char dup_num[] = "option specified more than once (\"%s\")";
+static const char no_num[] = "invalid number specified for max_errors(\"%s\")";
+static const char mtest_rw_error[] = "memory test read/write error";
+static const char mtest_lib_error[] = "memory test library error";
+static const char dlist_invalid[] = "invalid disabled-memory-list";
+static const char dlist_write_failed[] = "disabled-memory-list write failed";
+static const char mtest_unknown_error[] = "unknown memory test error";
+static const char ap_invalid[] = "invalid attachment point: %s";
+static const char trans_illegal[] = "illegal transition";
+static const char open_failed[] = "open failed: %s: %s";
+static const char mema_help[] =	"\nAc specific options:\n";
+static const char disable_opts[] = "\t-o disable-at-boot\n";
+static const char enable_opts[] = "\t-o enable-at-boot\n";
+static const char timeout_opts[] = "\t-o timeout=# (seconds)\n";
+static const char test_opts[] =
+	"\t-o {quick, normal, extended},[max_errors=#] -t ap_id [ap_id...]\n";
+static const char private_funcs[] = "\t-x relocate-test ap_id [ap_id...]\n";
+static const char add_is_disabled[] = "memory is disabled at boot";
+static const char add_willbe_disabled[] =
+	"memory will be disabled at boot";
+static const char add_disab_err[] = "cannot get memory disabled status";
+static const char pfunc_unknown[] = "private function \"%s\" unknown";
+
+
+#define	mema_eid(a, b)		(((a) << 8) + (b))
+#define	mema_str(i)		mema_strs[(i)]
+
+#define	AC_BK_BUSY		0
+#define	AC_BK_ID		1
+#define	AC_BD_ID		2
+#define	AC_BD_TYPE		3
+#define	AC_BD_STATE		4
+#define	AC_MEM_TEST_ID		5
+#define	AC_MEM_TEST_PAR		6
+#define	AC_MEM_PERM		7
+#define	AC_KPM_CANCELLED	8
+#define	AC_KPM_REFUSED		9
+#define	AC_KPM_SPAN		10
+#define	AC_KPM_DUP		11
+#define	AC_KPM_FAULT		12
+#define	AC_KPM_RESOURCE		13
+#define	AC_KPM_NOTSUP		14
+#define	AC_KPM_NOHANDLES	15
+#define	AC_KPM_NONRELOC		16
+#define	AC_KPM_HANDLE		17
+#define	AC_KPM_BUSY		18
+#define	AC_KPM_NOTVIABLE	19
+#define	AC_KPM_SEQUENCE		20
+#define	AC_KPM_NOWORK		21
+#define	AC_KPM_NOTFINISHED	22
+#define	AC_KPM_NOTRUNNING	23
+#define	AC_VMEM			24
+#define	CMD_MEM_STAT		25
+#define	CMD_MEM_ADD		26
+#define	CMD_MEM_DEL		27
+#define	CMD_MEM_TEST_START	28
+#define	CMD_MEM_TEST_STOP	29
+#define	AC_UNKNOWN		30
+#define	AC_INTR			31
+#define	AC_TIMEOUT		32
+#define	CMD_MEM_RELOCTEST	33
+#define	AC_DEINTLV		34
+
+static char *
+mema_strs[] = {
+	"memory bank busy",
+	"invalid memory bank",
+	"invalid board id",
+	"invalid board type",
+	"invalid board state",
+	"invalid memory test id",
+	"invalid memory test parameter(s)",
+	"no write permission",
+	"memory operation cancelled",
+	"memory operation refused",
+	"memory already in use (add)",
+	"memory span duplicate (delete)",
+	"memory access test failed (add)",
+	"some resource was not available",
+	"operation not supported",
+	"cannot allocate any more handles",
+	"non-relocatable pages in span",
+	"bad handle supplied",
+	"memory in span is being deleted",
+	"VM viability test failed",
+	"function called out of sequence",
+	"no memory to delete",
+	"delete processing not finished",
+	"delete processing not running",
+	"insufficient virtual memory",
+	"memory stat failed: %s",
+	"memory add failed: %s",
+	"memory delete failed: %s",
+	"memory test start failed: %s",
+	"memory test stop failed: %s",
+	"unknown error",
+	"memory delete killed",
+	"memory delete timeout",
+	"memory relocate-test failed: %s",
+	"memory cannot be de-interleaved"
+};
+
+/*
+ *	AC_MEM_PERM,		EBADF,   AC_ERR_MEM_PERM
+ *	AC_BK_BUSY,		EBUSY,   AC_ERR_MEM_BK
+ *	AC_KPM_CANCELLED,	EINTR,   AC_ERR_KPM_CANCELLED
+ *	AC_KPM_REFUSED,		EINTR,   AC_ERR_KPM_REFUSED
+ *	AC_BK_ID,		EINVAL,  AC_ERR_MEM_BK
+ *	AC_BD_ID,		EINVAL,  AC_ERR_BD
+ *	AC_BD_TYPE,		EINVAL,  AC_ERR_BD_TYPE
+ *	AC_BD_STATE,		EINVAL,  AC_ERR_BD_STATE
+ *	AC_MEM_TEST_ID,		EINVAL,  AC_ERR_MEM_TEST
+ *	AC_MEM_TEST_PAR,	EINVAL,  AC_ERR_MEM_TEST_PAR
+ *	AC_KPM_SPAN,		EINVAL,  AC_ERR_KPM_SPAN
+ *	AC_KPM_DUP,		EINVAL,  AC_ERR_KPM_DUP?
+ *	AC_KPM_FAULT,		EINVAL,  AC_ERR_KPM_FAULT
+ *	AC_KPM_RESOURCE,	EINVAL,  AC_ERR_KPM_RESOURCE
+ *	AC_KPM_NOTSUP,		EINVAL,  AC_ERR_KPM_NOTSUP
+ *	AC_KPM_NOHANDLES,	EINVAL,  AC_ERR_KPM_NOHANDLES
+ *	AC_KPM_NONRELOC,	EINVAL,  AC_ERR_KPM_NONRELOC
+ *	AC_KPM_HANDLE,		EINVAL,  AC_ERR_KPM_HANDLE
+ *	AC_KPM_BUSY,		EINVAL,  AC_ERR_KPM_BUSY
+ *	AC_KPM_NOTVIABLE,	EINVAL,  AC_ERR_KPM_NOTVIABLE
+ *	AC_KPM_SEQUENCE,	EINVAL,  AC_ERR_KPM_SEQUENCE
+ *	AC_KPM_NOWORK,		EINVAL,  AC_ERR_KPM_NOWORK
+ *	AC_KPM_NOTFINISHED,	EINVAL,  AC_ERR_KPM_NOTFINISHED
+ *	AC_KPM_NOTRUNNING,	EINVAL,  AC_ERR_KPM_NOTRUNNING
+ *	AC_VMEM,		ENOMEM,  AC_ERR_VMEM
+ *	AC_INTR,		EINTR,   AC_ERR_INTR
+ *	AC_TIMEOUT,		EINTR,   AC_ERR_TIMEOUT
+ *	AC_DEINTLV,		EINVAL,  AC_ERR_MEM_DEINTLV
+ */
+static int
+mema_sid(int err, int acerr)
+{
+	if (acerr == AC_ERR_DEFAULT)
+		return (AC_UNKNOWN);
+
+	switch (mema_eid(err, acerr)) {
+	case mema_eid(EBADF, AC_ERR_MEM_PERM):
+		return (AC_MEM_PERM);
+	case mema_eid(EBUSY, AC_ERR_MEM_BK):
+		return (AC_BK_BUSY);
+	case mema_eid(EINTR, AC_ERR_KPM_CANCELLED):
+		return (AC_KPM_CANCELLED);
+	case mema_eid(EINTR, AC_ERR_KPM_REFUSED):
+		return (AC_KPM_REFUSED);
+	case mema_eid(EINVAL, AC_ERR_MEM_BK):
+		return (AC_BK_ID);
+	case mema_eid(EINVAL, AC_ERR_BD):
+		return (AC_BD_ID);
+	case mema_eid(EINVAL, AC_ERR_BD_TYPE):
+		return (AC_BD_TYPE);
+	case mema_eid(EINVAL, AC_ERR_BD_STATE):
+		return (AC_BD_STATE);
+	case mema_eid(EINVAL, AC_ERR_MEM_TEST):
+		return (AC_MEM_TEST_ID);
+	case mema_eid(EINVAL, AC_ERR_MEM_TEST_PAR):
+		return (AC_MEM_TEST_PAR);
+	case mema_eid(EINVAL, AC_ERR_KPM_SPAN):
+		return (AC_KPM_SPAN);
+	case mema_eid(EINVAL, AC_ERR_KPM_DUP):
+		return (AC_KPM_DUP);
+	case mema_eid(EINVAL, AC_ERR_KPM_FAULT):
+		return (AC_KPM_FAULT);
+	case mema_eid(EINVAL, AC_ERR_KPM_RESOURCE):
+		return (AC_KPM_RESOURCE);
+	case mema_eid(EINVAL, AC_ERR_KPM_NOTSUP):
+		return (AC_KPM_NOTSUP);
+	case mema_eid(EINVAL, AC_ERR_KPM_NOHANDLES):
+		return (AC_KPM_NOHANDLES);
+	case mema_eid(EINVAL, AC_ERR_KPM_NONRELOC):
+		return (AC_KPM_NONRELOC);
+	case mema_eid(EINVAL, AC_ERR_KPM_HANDLE):
+		return (AC_KPM_HANDLE);
+	case mema_eid(EINVAL, AC_ERR_KPM_BUSY):
+		return (AC_KPM_BUSY);
+	case mema_eid(EINVAL, AC_ERR_KPM_NOTVIABLE):
+		return (AC_KPM_NOTVIABLE);
+	case mema_eid(EINVAL, AC_ERR_KPM_SEQUENCE):
+		return (AC_KPM_SEQUENCE);
+	case mema_eid(EINVAL, AC_ERR_KPM_NOWORK):
+		return (AC_KPM_NOWORK);
+	case mema_eid(EINVAL, AC_ERR_KPM_NOTFINISHED):
+		return (AC_KPM_NOTFINISHED);
+	case mema_eid(EINVAL, AC_ERR_KPM_NOTRUNNING):
+		return (AC_KPM_NOTRUNNING);
+	case mema_eid(ENOMEM, AC_ERR_VMEM):
+		return (AC_VMEM);
+	case mema_eid(EINTR, AC_ERR_INTR):
+		return (AC_INTR);
+	case mema_eid(EINTR, AC_ERR_TIMEOUT):
+		return (AC_TIMEOUT);
+	case mema_eid(EINVAL, AC_ERR_MEM_DEINTLV):
+		return (AC_DEINTLV);
+	default:
+		break;
+	}
+
+	return (AC_UNKNOWN);
+}
+
+static void
+mema_err(ac_cfga_cmd_t *ac, int ret_errno, char **errstring, int cmd)
+{
+	char *cname = mema_str(cmd);
+	char *syserr;
+	char syserr_num[20];
+
+	if (ac) {
+		syserr = mema_str(mema_sid(ret_errno, ac->errtype));
+		syserr = dgettext(TEXT_DOMAIN, syserr);
+	} else {
+		syserr = strerror(ret_errno);
+		/* strerror() does its own gettext(). */
+		if (syserr == NULL) {
+			(void) sprintf(syserr_num, "errno=%d", errno);
+			syserr = syserr_num;
+		}
+	}
+
+	__fmt_errstring(errstring, strlen(syserr),
+	    dgettext(TEXT_DOMAIN, cname), syserr);
+}
+
+static void
+mema_cmd_init(ac_cfga_cmd_t *ac, void *cmd, char *outputstr, int force)
+{
+	(void) memset((void *)ac, 0, sizeof (*ac));
+
+	ac->errtype = AC_ERR_DEFAULT;
+	ac->private = cmd;
+	ac->force = force;
+	ac->outputstr = outputstr;
+
+	(void) memset((void *)outputstr, 0, AC_OUTPUT_LEN);
+}
+
+static int
+ap_bk_idx(const char *ap_id)
+{
+	int id;
+	char *s;
+	static char *bank = "bank";
+
+	DBG("ap_bk_idx(%s)\n", ap_id);
+
+	if ((s = strstr(ap_id, bank)) == NULL)
+		return (-1);
+	else {
+		int n;
+
+		s += strlen(bank);
+		n = strlen(s);
+
+		DBG3("ap_bk_idx: s=%s, n=%d\n", s, n);
+
+		if ((n != 1) || !isdigit(s[0]))
+			return (-1);
+	}
+
+	id = atoi(s);
+
+	if (id < 0 || id > 1)
+		return (-1);
+
+	DBG3("ap_bk_idx(%s)=%d\n", s, id);
+
+	return (id);
+}
+
+static cfga_err_t
+ap_stat(
+	const char *bank_spec,
+	int *fdp,
+	mema_bank_t *bkp,
+	ac_stat_t *stp,
+	char **errstring)
+{
+	int fd;
+	int ret, ret_errno;
+	int bank;
+	mema_bank_t bk;
+	ac_stat_t stat;
+	ac_cfga_cmd_t cmd;
+	char outputstr[AC_OUTPUT_LEN];
+
+	if ((bank = ap_bk_idx(bank_spec)) == -1) {
+		__fmt_errstring(errstring, strlen(bank_spec),
+			dgettext(TEXT_DOMAIN, ap_invalid), bank_spec);
+		return (CFGA_ERROR);
+	}
+
+	bk.bank = bank;
+
+	if ((fd = open(bank_spec, ((fdp != NULL) ? O_RDWR : O_RDONLY), 0)) ==
+	    -1) {
+		char *syserr;
+		char syserr_num[20];
+
+		syserr = strerror(errno);
+		if (syserr == NULL) {
+			(void) sprintf(syserr_num, "errno=%d", errno);
+			syserr = syserr_num;
+		}
+		__fmt_errstring(errstring, strlen(syserr) +
+		    strlen(bank_spec),
+		    dgettext(TEXT_DOMAIN, open_failed), bank_spec, syserr);
+		return (CFGA_ERROR);
+	}
+
+	mema_cmd_init(&cmd, &stat, outputstr, 0);
+	dump_ioctl(AC_MEM_STAT, NULL);
+	ret = ioctl(fd, AC_MEM_STAT, &cmd);
+	ret_errno = errno;
+	dump_ioctl_res(AC_MEM_STAT, &stat, ret, ret_errno);
+
+	if (ret == -1) {
+		mema_err(&cmd, ret_errno, errstring, CMD_MEM_STAT);
+		(void) close(fd);
+		return (CFGA_ERROR);
+	}
+
+	if (fdp)
+		*fdp = fd;
+	else
+		(void) close(fd);
+
+	if (stp)
+		*stp = stat;
+
+	if (bkp) {
+		bkp->bank = bk.bank;
+		bkp->board = stat.board;
+	}
+
+	return (CFGA_OK);
+}
+
+static void
+set_disabled_bits(mema_disabled_t *dp, int value)
+{
+	if (value == 0)
+		*dp &= ~PROM_MEMORY_DISABLED;
+	else
+		*dp |= PROM_MEMORY_DISABLED;
+}
+
+static void
+set_present_bits(mema_disabled_t *dp, ac_stat_t *asp)
+{
+	if (asp->ostate == SYSC_CFGA_OSTATE_CONFIGURED)
+		*dp |= PROM_MEMORY_PRESENT;
+	else
+		*dp &= ~PROM_MEMORY_DISABLED;
+}
+
+static cfga_err_t
+prom_do_options(
+	option_set_t do_option,
+	int board,
+	ac_stat_t *asp,
+	char **errstring)
+{
+	cfga_err_t ret;
+	mema_disabled_t disab;
+
+	if (!prom_read_disabled_list(&disab, board))
+		return (CFGA_ERROR);
+
+	set_present_bits(&disab, asp);
+
+	ret = CFGA_OK;
+
+	if (OPTSET_TEST(do_option, OPT_BOOT_ENABLE)) {
+		set_disabled_bits(&disab, 0);
+		if (!prom_viable_disabled_list(&disab)) {
+			__fmt_errstring(errstring, 0,
+			    dgettext(TEXT_DOMAIN, dlist_invalid));
+			ret = CFGA_ERROR;
+		} else if (!prom_write_disabled_list(&disab, board)) {
+			__fmt_errstring(errstring, 0,
+			    dgettext(TEXT_DOMAIN, dlist_write_failed));
+			ret = CFGA_ERROR;
+		}
+	} else if (OPTSET_TEST(do_option, OPT_BOOT_DISABLE)) {
+		set_disabled_bits(&disab, 1);
+		if (!prom_viable_disabled_list(&disab)) {
+			__fmt_errstring(errstring, 0,
+			    dgettext(TEXT_DOMAIN, dlist_invalid));
+			ret = CFGA_ERROR;
+		} else if (!prom_write_disabled_list(&disab, board)) {
+			__fmt_errstring(errstring, 0,
+			    dgettext(TEXT_DOMAIN, dlist_write_failed));
+			ret = CFGA_ERROR;
+		}
+	}
+
+	return (ret);
+}
+
+static cfga_err_t
+mema_add(
+	const char *bank_spec,
+	const char *options,
+	char **errstring,
+	int force)
+{
+	mema_bank_t bk;
+	int fd, ret, ret_errno;
+	option_set_t do_option;
+	ac_cfga_cmd_t cmd;
+	ac_stat_t stat;
+	char outputstr[AC_OUTPUT_LEN];
+
+	ret = 0;
+	do_option = process_options(options, add_opts, &ret, errstring);
+	if (ret != 0) {
+		return (ret);
+	}
+
+	ret = ap_stat(bank_spec, &fd, &bk, &stat, errstring);
+	if (ret != CFGA_OK)
+		return (ret);
+
+
+	if (stat.rstate != SYSC_CFGA_RSTATE_CONNECTED ||
+	    stat.ostate != SYSC_CFGA_OSTATE_UNCONFIGURED) {
+		__fmt_errstring(errstring, 0,
+		    dgettext(TEXT_DOMAIN, trans_illegal));
+		(void) close(fd);
+		return (CFGA_ERROR);
+	}
+
+	if (!force) {
+		mema_disabled_t disab;
+
+		if (prom_read_disabled_list(&disab, bk.board)) {
+			if (disab != 0 &&
+			    !OPTSET_TEST(do_option, OPT_BOOT_ENABLE)) {
+				__fmt_errstring(errstring, 0,
+				    dgettext(TEXT_DOMAIN, add_is_disabled));
+				(void) close(fd);
+				return (CFGA_ERROR);
+			}
+			if (disab == 0 &&
+			    OPTSET_TEST(do_option, OPT_BOOT_DISABLE)) {
+				__fmt_errstring(errstring, 0,
+				    dgettext(TEXT_DOMAIN, add_willbe_disabled));
+				(void) close(fd);
+				return (CFGA_ERROR);
+			}
+		} else {
+			__fmt_errstring(errstring, 0,
+			    dgettext(TEXT_DOMAIN, add_disab_err));
+			(void) close(fd);
+			return (CFGA_ERROR);
+		}
+	}
+
+	mema_cmd_init(&cmd, NULL, outputstr, force);
+	dump_ioctl(AC_MEM_CONFIGURE, NULL);
+	ret = ioctl(fd, AC_MEM_CONFIGURE, &cmd);
+	ret_errno = errno;
+	dump_ioctl_res(AC_MEM_CONFIGURE, NULL, ret, ret_errno);
+	(void) close(fd);
+
+	if (ret == -1) {
+		mema_err(&cmd, ret_errno, errstring, CMD_MEM_ADD);
+		return (CFGA_ERROR);
+	}
+
+	ret = prom_do_options(do_option, bk.board, &stat, errstring);
+
+	return (ret);
+}
+
+static cfga_err_t
+mema_delete(
+	const char *bank_spec,
+	const char *options,
+	char **errstring,
+	int force)
+{
+	mema_bank_t bk;
+	int fd, ret, ret_errno;
+	option_set_t do_option;
+	ac_cfga_cmd_t cmd;
+	ac_stat_t stat;
+	char outputstr[AC_OUTPUT_LEN];
+	int timeout_secs = -1;	/* Init to 'use default'. */
+
+	ret = 0;
+	do_option = process_options(options, del_opts, &ret, errstring);
+	if (ret != 0) {
+		return (ret);
+	}
+
+	if (OPTSET_TEST(do_option, OPT_TIMEOUT)) {
+		char *to_val;
+		char *ep;
+
+		to_val = OPTSET_VAL(do_option, OPT_TIMEOUT);
+		timeout_secs = (int)strtol(to_val, &ep, 10);
+		if (*ep != '\0' || ep == to_val || timeout_secs < 0) {
+			__fmt_errstring(errstring, strlen(to_val),
+			    dgettext(TEXT_DOMAIN, timeout_notnum), to_val);
+			return (CFGA_ERROR);
+		}
+	}
+
+	ret = ap_stat(bank_spec, &fd, &bk, &stat, errstring);
+	if (ret != CFGA_OK)
+		return (ret);
+
+	if (stat.rstate != SYSC_CFGA_RSTATE_CONNECTED ||
+	    stat.ostate != SYSC_CFGA_OSTATE_CONFIGURED) {
+		__fmt_errstring(errstring, 0,
+		    dgettext(TEXT_DOMAIN, trans_illegal));
+		(void) close(fd);
+		return (CFGA_ERROR);
+	}
+
+	mema_cmd_init(&cmd, NULL, outputstr, force);
+	cmd.arg = timeout_secs;
+	dump_ioctl(AC_MEM_UNCONFIGURE, NULL);
+	ret = ioctl(fd, AC_MEM_UNCONFIGURE, &cmd);
+	ret_errno = errno;
+	dump_ioctl_res(AC_MEM_UNCONFIGURE, NULL, ret, ret_errno);
+	(void) close(fd);
+
+	if (ret == -1) {
+		mema_err(&cmd, ret_errno, errstring, CMD_MEM_DEL);
+		return (CFGA_ERROR);
+	}
+
+	ret = prom_do_options(do_option, bk.board, &stat, errstring);
+
+	return (ret);
+}
+
+/*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 force;
+	cfga_err_t rc;
+
+	if (errstring != NULL)
+		*errstring = NULL;
+
+	force = flags & CFGA_FLAG_FORCE;
+
+	switch (state_change_cmd) {
+	case CFGA_CMD_CONFIGURE:
+		rc =  mema_add(ap_id, options, errstring, force);
+		break;
+
+	case CFGA_CMD_UNCONFIGURE:
+		rc =  mema_delete(ap_id, options, errstring, force);
+		break;
+
+	default:
+		rc = CFGA_OPNOTSUPP;
+		break;
+	}
+
+	return (rc);
+}
+
+/*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)
+{
+	mema_bank_t bk;
+	ac_stat_t stat;
+	int fd, ret, ret_errno;
+	ac_cfga_cmd_t cmd;
+	char outputstr[AC_OUTPUT_LEN];
+
+	if (errstring != NULL)
+		*errstring = NULL;
+
+	ret = ap_stat(ap_id, &fd, &bk, &stat, errstring);
+	if (ret != CFGA_OK)
+		return (ret);
+
+	if (strcmp(function, "relocate-test") == 0) {
+		struct ac_memx_relocate_stats rstat;
+
+		mema_cmd_init(&cmd, NULL, outputstr,
+		    (flags & CFGA_FLAG_FORCE));
+		cmd.arg = AC_MEMX_RELOCATE_ALL;
+		cmd.private = &rstat;
+		(void) memset((void *)&rstat, 0, sizeof (rstat));
+		dump_ioctl(AC_MEM_EXERCISE, &cmd);
+		ret = ioctl(fd, AC_MEM_EXERCISE, &cmd);
+		ret_errno = errno;
+		dump_ioctl_res(AC_MEM_EXERCISE, &cmd, ret, ret_errno);
+		(void) close(fd);
+
+		if (ret == -1) {
+			mema_err(&cmd, ret_errno, errstring, CMD_MEM_RELOCTEST);
+			return (CFGA_ERROR);
+		}
+		return (CFGA_OK);
+	}
+
+	__fmt_errstring(errstring, strlen(function),
+	    dgettext(TEXT_DOMAIN, pfunc_unknown), function);
+
+	return (CFGA_ERROR);
+}
+
+static int
+mtest_run(
+	int fd,
+	int test_fun,
+	mema_bank_t *abkp,
+	struct cfga_msg *msgp,
+	char **errstring,
+	ulong_t max_errors)
+{
+	ac_mem_test_start_t test_start;
+	ac_mem_test_stop_t test_stop;
+	struct mtest_handle handle;
+	int ret, ret_errno;
+	int res;
+	ac_cfga_cmd_t cmd;
+	char outputstr[AC_OUTPUT_LEN];
+
+	(void) memset((void *)&test_start, 0, sizeof (test_start));
+	mema_cmd_init(&cmd, &test_start, outputstr, 0);
+	dump_ioctl(AC_MEM_TEST_START, &test_start);
+	ret = ioctl(fd, AC_MEM_TEST_START, &cmd);
+	ret_errno = errno;
+	dump_ioctl_res(AC_MEM_TEST_START, &test_start, ret, ret_errno);
+
+	if (ret == -1) {
+		if (ret_errno == ENOTSUP) {
+			mema_err(&cmd, ret_errno, errstring,
+				CMD_MEM_TEST_START);
+			return (CFGA_OPNOTSUPP);
+		}
+		if (ret_errno == EBUSY && test_start.tester_pid > 0) {
+			/*
+			 * Bank appears to be being tested.  Check that
+			 * process 'tester_pid' is still running.
+			 */
+			if (kill(test_start.tester_pid, 0) != -1 ||
+			    errno != ESRCH) {
+				cfga_ap_log_id_t bname;
+
+				/* Process still exists. */
+				(void) sprintf(bname, "board %d bank%d",
+				    abkp->board, abkp->bank);
+				__fmt_errstring(errstring, strlen(bname),
+				    dgettext(TEXT_DOMAIN, still_testing),
+				    bname, test_start.tester_pid);
+				return (CFGA_ERROR);
+			}
+			/*
+			 * Do a test stop and re-try the start.
+			 */
+			(void) memset((void *)&test_stop, 0,
+			    sizeof (test_stop));
+			test_stop.handle = test_start.handle;
+			test_stop.condition = SYSC_CFGA_COND_UNKNOWN;
+			mema_cmd_init(&cmd, &test_stop, outputstr, 0);
+			dump_ioctl(AC_MEM_TEST_STOP, &test_stop);
+			ret = ioctl(fd, AC_MEM_TEST_STOP, &cmd);
+			ret_errno = errno;
+			dump_ioctl_res(AC_MEM_TEST_STOP, &test_stop,
+			    ret, ret_errno);
+			/*
+			 * Ignore test stop error processing and re-try the
+			 * start.  The error return will be derived from the
+			 * result of start.
+			 */
+			(void) memset((void *)&test_start, 0,
+			    sizeof (test_start));
+			mema_cmd_init(&cmd, &test_start, outputstr, 0);
+			dump_ioctl(AC_MEM_TEST_START, &test_start);
+			ret = ioctl(fd, AC_MEM_TEST_START, &cmd);
+			ret_errno = errno;
+			dump_ioctl_res(AC_MEM_TEST_START, &test_start,
+			    ret, ret_errno);
+		}
+		/* Test return code again to cover the case of a re-try. */
+		if (ret == -1) {
+			mema_err(&cmd, ret_errno, errstring,
+			    CMD_MEM_TEST_START);
+			return (CFGA_ERROR);
+		}
+	}
+	(void) memset((void *)&handle, 0, sizeof (handle));
+	handle.fd = fd;
+	handle.drvhandle = (void *)&test_start;
+	handle.msgp = msgp;
+	handle.bank_size = test_start.bank_size;
+	handle.page_size = test_start.page_size;
+	handle.line_size = test_start.line_size;
+	handle.lines_per_page = test_start.page_size / test_start.line_size;
+	handle.condition = CFGA_COND_UNKNOWN;
+	handle.max_errors = max_errors;
+
+	res = (*mtest_table[test_fun].test_func)(&handle);
+
+	mtest_deallocate_buf_all(&handle);
+
+	/*
+	 * Convert memory test code to MEMA_ code.
+	 */
+	switch (res) {
+	case MTEST_DONE:
+		res = CFGA_OK;
+		break;
+	case MTEST_LIB_ERROR:
+		__fmt_errstring(errstring, 0, dgettext(TEXT_DOMAIN,
+		    mtest_lib_error));
+		res = CFGA_ERROR;
+		break;
+	case MTEST_DEV_ERROR:
+		__fmt_errstring(errstring, 0, dgettext(TEXT_DOMAIN,
+		    mtest_rw_error));
+		res = CFGA_ERROR;
+		break;
+	default:
+		__fmt_errstring(errstring, 0, dgettext(TEXT_DOMAIN,
+		    mtest_unknown_error));
+		res = CFGA_ERROR;
+		assert(0);
+		break;
+	}
+
+	(void) memset((void *)&test_stop, 0, sizeof (test_stop));
+	test_stop.handle = test_start.handle;
+	switch (handle.condition) {
+	case CFGA_COND_OK:
+		test_stop.condition = SYSC_CFGA_COND_OK;
+		break;
+	case CFGA_COND_FAILING:
+		test_stop.condition = SYSC_CFGA_COND_FAILING;
+		break;
+	case CFGA_COND_FAILED:
+		test_stop.condition = SYSC_CFGA_COND_FAILED;
+		break;
+	case CFGA_COND_UNKNOWN:
+		test_stop.condition = SYSC_CFGA_COND_UNKNOWN;
+		break;
+	default:
+		test_stop.condition = SYSC_CFGA_COND_UNKNOWN;
+		assert(0);
+		break;
+	}
+
+	mema_cmd_init(&cmd, &test_stop, outputstr, 0);
+	dump_ioctl(AC_MEM_TEST_STOP, &test_stop);
+	ret = ioctl(fd, AC_MEM_TEST_STOP, &cmd);
+	ret_errno = errno;
+	dump_ioctl_res(AC_MEM_TEST_STOP, &test_stop, ret, ret_errno);
+	if (ret == -1) {
+		mema_err(&cmd, ret_errno, errstring,
+		    CMD_MEM_TEST_STOP);
+		return (CFGA_ERROR);
+	}
+	return (res);
+}
+
+#define	DRVHANDLE(H)	(((ac_mem_test_start_t *)(H)->drvhandle)->handle)
+
+int
+mtest_write(
+	mtest_handle_t handle,
+	void *page_buf,
+	u_longlong_t page_no,
+	uint_t line_offset,
+	uint_t line_count)
+{
+	ac_mem_test_write_t test_write;
+	int fd, ret, ret_errno;
+	ac_cfga_cmd_t cmd;
+	char outputstr[AC_OUTPUT_LEN];
+
+	(void) memset((void *)&test_write, 0, sizeof (test_write));
+	fd = handle->fd;
+	test_write.handle = DRVHANDLE(handle);
+	test_write.page_buf = page_buf;
+	test_write.address.page_num = page_no;
+	test_write.address.line_offset = line_offset;
+	if (line_count == 0)
+		test_write.address.line_count = handle->lines_per_page;
+	else
+		test_write.address.line_count = line_count;
+
+	mema_cmd_init(&cmd, &test_write, outputstr, 0);
+	dump_ioctl(AC_MEM_TEST_WRITE, &test_write);
+	ret = ioctl(fd, AC_MEM_TEST_WRITE, &cmd);
+	ret_errno = errno;
+	dump_ioctl_res(AC_MEM_TEST_WRITE, &test_write, ret, ret_errno);
+
+	if (ret == -1)
+		return (-1);
+	return (0);
+}
+
+int
+mtest_read(
+	mtest_handle_t handle,
+	void *page_buf,
+	u_longlong_t page_no,
+	uint_t line_offset,
+	uint_t line_count,
+	struct mtest_error *errp)
+{
+	ac_mem_test_read_t test_read;
+	sunfire_processor_error_regs_t errbuf;
+	int fd, ret, ret_errno;
+	ac_cfga_cmd_t cmd;
+	char outputstr[AC_OUTPUT_LEN];
+
+	(void) memset((void *)&test_read, 0, sizeof (test_read));
+	(void) memset((void *)&errbuf, 0, sizeof (errbuf));
+	fd = handle->fd;
+	test_read.handle = DRVHANDLE(handle);
+	test_read.page_buf = page_buf;
+	test_read.address.page_num = page_no;
+	test_read.address.line_offset = line_offset;
+	test_read.error_buf =  &errbuf;
+	if (line_count == 0)
+		test_read.address.line_count = handle->lines_per_page;
+	else
+		test_read.address.line_count = line_count;
+
+	mema_cmd_init(&cmd, &test_read, outputstr, 0);
+	dump_ioctl(AC_MEM_TEST_READ, &test_read);
+	ret = ioctl(fd, AC_MEM_TEST_READ, &cmd);
+	ret_errno = errno;
+	dump_ioctl_res(AC_MEM_TEST_READ, &test_read, ret, ret_errno);
+
+	if (ret == -1) {
+		if (ret_errno == EIO) {
+			/*
+			 * Special case indicating CE or UE.
+			 */
+			if (((errbuf.udbh_error_reg | errbuf.udbl_error_reg) &
+			    P_DER_UE) != 0)
+				errp->error_type = MTEST_ERR_UE;
+			else
+				errp->error_type = MTEST_ERR_CE;
+		} else {
+			return (-1);
+		}
+	} else {
+		errp->error_type = MTEST_ERR_NONE;
+	}
+	return (0);
+}
+
+static char *
+subopt_help_str(char *opts[])
+{
+	char *str;
+	const char *sep;
+	int len;
+	int i, n;
+	static const char help_sep[] = ", ";
+	static const char help_nil[] = "???";
+
+	len = 0;
+	n = 0;
+	for (i = 0; opts[i] != NULL; i++) {
+		n++;
+		len += strlen(opts[i]);
+	}
+	if (n == 0)
+		return (strdup(help_nil));
+	len += (n - 1) * strlen(help_sep);
+	len++;
+	str = (char *)malloc(len);
+	if (str == NULL)
+		return (NULL);
+	*str = '\0';
+	sep = "";
+	for (i = 0; opts[i] != NULL; i++) {
+		(void) strcat(str, sep);
+		(void) strcat(str, opts[i]);
+		sep = help_sep;
+	}
+	return (str);
+}
+
+/*ARGSUSED*/
+cfga_err_t
+cfga_test(
+	const char *ap_id,
+	const char *options,
+	struct cfga_msg *msgp,
+	char **errstring,
+	cfga_flags_t flags)
+{
+	mema_bank_t bk;
+	ac_stat_t stat;
+	int test_fun = -1;
+	int fd, ret;
+	int maxerr_idx;
+	long max_errors = -1;
+	char *ret_p;
+
+	if (errstring != NULL)
+		*errstring = NULL;
+
+	/*
+	 * Decode test level and max error number.
+	 */
+	if (options != NULL && *options != '\0') {
+		char **opts;
+		char *value;
+		char *cp, *free_cp;
+		int subopt;
+
+		/* getsubopt() modifies the input string, so copy it. */
+		cp = strdup(options);
+		if (cp == NULL) {
+			return (CFGA_LIB_ERROR);
+		}
+		free_cp = cp;
+		opts = mtest_build_opts(&maxerr_idx);
+		if (opts == NULL) {
+			free((void *)free_cp);
+			return (CFGA_LIB_ERROR);
+		}
+
+		while (*cp != '\0') {
+			subopt = getsubopt(&cp, opts, &value);
+			if (subopt == -1) {
+				char *hlp;
+
+				hlp = subopt_help_str(opts);
+				if (hlp != NULL) {
+					__fmt_errstring(errstring,
+					strlen(value) + strlen(hlp),
+					dgettext(TEXT_DOMAIN, unk_test),
+					value, hlp);
+					free((void *)hlp);
+				} else {
+					__fmt_errstring(errstring, 20,
+					dgettext(TEXT_DOMAIN, calloc_fail),
+						strlen(options) + 1, 1);
+				}
+				/* Free after printing value. */
+				free((void *)free_cp);
+				return (CFGA_ERROR);
+			}
+
+			if (test_fun != -1 && subopt != test_fun &&
+			    subopt != maxerr_idx) {
+				__fmt_errstring(errstring,
+				    strlen(opts[subopt]),
+				    dgettext(TEXT_DOMAIN, dup_test),
+				    opts[subopt]);
+				free((void *)free_cp);
+				return (CFGA_ERROR);
+			}
+
+			if (subopt < maxerr_idx)
+				test_fun = subopt;
+			else {
+
+				if (max_errors != -1 && subopt == maxerr_idx) {
+					__fmt_errstring(errstring,
+					strlen(opts[subopt]),
+					dgettext(TEXT_DOMAIN, dup_num),
+					opts[subopt]);
+					free((void *)free_cp);
+					return (CFGA_ERROR);
+				}
+
+				if (value == NULL) {
+					__fmt_errstring(errstring,
+					0,
+					dgettext(TEXT_DOMAIN, no_num),
+					"");
+					free((void *)free_cp);
+					return (CFGA_ERROR);
+				}
+
+				max_errors = strtol(value, &ret_p, 10);
+				if ((ret_p == value) || (*ret_p != '\0') ||
+				    (max_errors < 0)) {
+					__fmt_errstring(errstring,
+					strlen(value),
+					dgettext(TEXT_DOMAIN, no_num),
+					value);
+					free((void *)free_cp);
+					return (CFGA_ERROR);
+				}
+			}
+		}
+		free((void *)free_cp);
+	}
+
+	if (test_fun == -1)
+		test_fun = MTEST_DEFAULT_TEST;
+	if (max_errors == -1)
+		max_errors = MAX_ERRORS;
+
+	ret = ap_stat(ap_id, &fd, &bk, &stat, errstring);
+	if (ret != CFGA_OK)
+		return (ret);
+
+	if (stat.rstate != SYSC_CFGA_RSTATE_CONNECTED ||
+	    stat.ostate != SYSC_CFGA_OSTATE_UNCONFIGURED) {
+		__fmt_errstring(errstring, 0,
+		    dgettext(TEXT_DOMAIN, trans_illegal));
+		(void) close(fd);
+		return (CFGA_ERROR);
+	}
+
+	ret = mtest_run(fd, test_fun, &bk,
+	    ((flags & CFGA_FLAG_VERBOSE) != 0) ? msgp : NULL, errstring,
+	    (ulong_t)max_errors);
+
+	(void) close(fd);
+
+	return (ret);
+}
+
+static cfga_stat_t
+rstate_cvt(sysc_cfga_rstate_t rs)
+{
+	cfga_stat_t cs;
+
+	switch (rs) {
+	case SYSC_CFGA_RSTATE_EMPTY:
+		cs = CFGA_STAT_EMPTY;
+		break;
+	case SYSC_CFGA_RSTATE_DISCONNECTED:
+		cs = CFGA_STAT_DISCONNECTED;
+		break;
+	case SYSC_CFGA_RSTATE_CONNECTED:
+		cs = CFGA_STAT_CONNECTED;
+		break;
+	default:
+		cs = CFGA_STAT_NONE;
+		break;
+	}
+
+	return (cs);
+}
+
+static cfga_stat_t
+ostate_cvt(sysc_cfga_ostate_t os)
+{
+	cfga_stat_t cs;
+
+	switch (os) {
+	case SYSC_CFGA_OSTATE_UNCONFIGURED:
+		cs = CFGA_STAT_UNCONFIGURED;
+		break;
+	case SYSC_CFGA_OSTATE_CONFIGURED:
+		cs = CFGA_STAT_CONFIGURED;
+		break;
+	default:
+		cs = CFGA_STAT_NONE;
+		break;
+	}
+
+	return (cs);
+}
+
+static cfga_cond_t
+cond_cvt(sysc_cfga_cond_t sc)
+{
+	cfga_cond_t cc;
+
+	switch (sc) {
+	case SYSC_CFGA_COND_OK:
+		cc = CFGA_COND_OK;
+		break;
+	case SYSC_CFGA_COND_FAILING:
+		cc = CFGA_COND_FAILING;
+		break;
+	case SYSC_CFGA_COND_FAILED:
+		cc = CFGA_COND_FAILED;
+		break;
+	case SYSC_CFGA_COND_UNUSABLE:
+		cc = CFGA_COND_UNUSABLE;
+		break;
+	case SYSC_CFGA_COND_UNKNOWN:
+	default:
+		cc = CFGA_COND_UNKNOWN;
+		break;
+	}
+
+	return (cc);
+}
+
+static void
+info_set(ac_stat_t *asp, mema_bank_t *bkp, cfga_info_t info)
+{
+	mema_disabled_t disab;
+	uint_t board;
+	uint_t n;
+	u_longlong_t decode;
+	uint_t intlv;
+	char *f;
+	char *end;
+
+	end = &info[sizeof (cfga_info_t)];
+	*info = NULL;
+
+	board = bkp->board;
+
+	/* Print the board number in a way that matches the sysctrl AP. */
+	info += snprintf(info, end - info, "slot%d", board);
+
+	if (asp->real_size == 0) {
+		info += snprintf(info, end - info, " empty");
+		return;
+	}
+
+	if ((n = asp->real_size) >= 1024) {
+		n /= 1024;
+		f = "Gb";
+	} else
+		f = "Mb";
+	info += snprintf(info, end - info, " %d%s", n, f);
+
+	if (asp->rstate == SYSC_CFGA_RSTATE_CONNECTED &&
+	    asp->ostate == SYSC_CFGA_OSTATE_CONFIGURED &&
+	    asp->use_size != asp->real_size) {
+		if ((n = asp->use_size) >= 1024) {
+			n /= 1024;
+			f = "Gb";
+		} else
+			f = "Mb";
+		info += snprintf(info, end - info, " (%d%s used)", n, f);
+	}
+
+	if (bkp->bank == 0)
+		decode = asp->ac_decode0;
+	else
+		decode = asp->ac_decode1;
+
+	info += snprintf(info, end - info, " base 0x%llx",
+	    GRP_REALBASE(decode));
+
+	if (bkp->bank == 0)
+		intlv = INTLV0(asp->ac_memctl);
+	else
+		intlv = INTLV1(asp->ac_memctl);
+
+	if (intlv != 1)
+		info += snprintf(info, end - info, " interleaved %u-way",
+		    intlv);
+
+	if (prom_read_disabled_list(&disab, board)) {
+		if (disab != 0) {
+			info += snprintf(info, end - info, " disabled at boot");
+		}
+
+	}
+
+	if (asp->rstate == SYSC_CFGA_RSTATE_CONNECTED &&
+	    asp->ostate == SYSC_CFGA_OSTATE_CONFIGURED &&
+	    asp->nonrelocatable)
+		info += snprintf(info, end - info, " permanent");
+}
+
+static void
+mema_cvt(ac_stat_t *ac, mema_bank_t *bkp, cfga_stat_data_t *cs)
+{
+	(void) strcpy(cs->ap_type, "memory");
+	cs->ap_r_state = rstate_cvt(ac->rstate);
+	cs->ap_o_state = ostate_cvt(ac->ostate);
+	cs->ap_cond = cond_cvt(ac->condition);
+	cs->ap_busy = (cfga_busy_t)ac->busy;
+	cs->ap_status_time = ac->status_time;
+	info_set(ac, bkp, cs->ap_info);
+	cs->ap_log_id[0] = NULL;
+	cs->ap_phys_id[0] = NULL;
+}
+
+/*ARGSUSED*/
+cfga_err_t
+cfga_stat(
+	const char *ap_id,
+	struct cfga_stat_data *cs,
+	const char *options,
+	char **errstring)
+{
+	int ret;
+	mema_bank_t bk;
+	ac_stat_t stat;
+	option_set_t do_option;
+
+	if (errstring != NULL)
+		*errstring = NULL;
+
+	ret = 0;
+	do_option = process_options(options, stat_opts, &ret, errstring);
+	if (ret != 0)
+		return (ret);
+
+	ret = ap_stat(ap_id, NULL, &bk, &stat, errstring);
+	if (ret != CFGA_OK)
+		return (ret);
+
+	mema_cvt(&stat, &bk, cs);
+
+	ret = prom_do_options(do_option, bk.board, &stat, errstring);
+
+	return (ret);
+}
+
+/*ARGSUSED*/
+cfga_err_t
+cfga_list(
+	const char *ap_id,
+	cfga_stat_data_t **ap_list,
+	int *nlist,
+	const char *options,
+	char **errstring)
+{
+	if (errstring != NULL)
+		*errstring = NULL;
+
+	return (CFGA_NOTSUPP);
+}
+
+/*
+ * cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm
+ */
+
+/*ARGSUSED*/
+cfga_err_t
+cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
+{
+
+
+	(*msgp->message_routine)(msgp->appdata_ptr, mema_help);
+	(*msgp->message_routine)(msgp->appdata_ptr, disable_opts);
+	(*msgp->message_routine)(msgp->appdata_ptr, enable_opts);
+	(*msgp->message_routine)(msgp->appdata_ptr, timeout_opts);
+	(*msgp->message_routine)(msgp->appdata_ptr, test_opts);
+	(*msgp->message_routine)(msgp->appdata_ptr, private_funcs);
+
+	return (CFGA_OK);
+}
+
+#if 0
+static ac_mem_version_t
+get_version(int fd)
+{
+	ac_mem_version_t ver;
+	int ret, ret_errno;
+
+	ver = 0;
+	dump_ioctl(AC_MEM_ADMIN_VER, &ver);
+	ret = ioctl(fd, AC_MEM_ADMIN_VER, &ver);
+	ret_errno = errno;
+	dump_ioctl_res(AC_MEM_ADMIN_VER, &ver, ret, ret_errno);
+	return (ver);
+}
+#endif
+
+static char *
+opt_help_str(struct opt_control *opts)
+{
+	char *str;
+	const char *sep;
+	int len;
+	int i, n;
+	static const char help_sep[] = ", ";
+	static const char help_nil[] = "???";
+
+	len = 0;
+	n = 0;
+	for (i = 0; opts[i].subopt != -1; i++) {
+		n++;
+		len += strlen(mema_opts[opts[i].subopt]);
+	}
+	if (n == 0)
+		return (strdup(help_nil));
+	len += (n - 1) * strlen(help_sep);
+	len++;
+	str = (char *)malloc(len);
+	if (str == NULL)
+		return (NULL);
+	*str = '\0';
+	sep = "";
+	for (i = 0; opts[i].subopt != -1; i++) {
+		(void) strcat(str, sep);
+		(void) strcat(str, mema_opts[opts[i].subopt]);
+		sep = help_sep;
+	}
+	return (str);
+}
+
+static option_set_t
+process_options(
+	const char *options,
+	struct opt_control *opts,
+	int *retp,
+	char **errstring)
+{
+	option_set_t opt_set;
+	char *optcopy, *optcopy_alloc;
+	char *value;
+	int subopt;
+	int subopt_err;
+	int i;
+	int group;
+	int need_value;
+
+	OPTSET_INIT(opt_set);
+
+	if (options == NULL || *options == '\0') {
+		return (opt_set);
+	}
+
+	optcopy = optcopy_alloc = strdup(options);
+	if (optcopy_alloc == NULL) {
+		__fmt_errstring(errstring, 20,
+		    dgettext(TEXT_DOMAIN, calloc_fail), strlen(options) + 1, 1);
+		*retp = CFGA_LIB_ERROR;
+		return (opt_set);
+	}
+
+	subopt_err = 0;
+	while (*optcopy != '\0' && subopt_err == 0) {
+		subopt = getsubopt(&optcopy, mema_opts, &value);
+		if (subopt == -1) {
+			char *hlp;
+
+			hlp = opt_help_str(opts);
+			__fmt_errstring(errstring, strlen(value) + strlen(hlp),
+			    dgettext(TEXT_DOMAIN, unk_subopt), value, hlp);
+			free((void *)hlp);
+			subopt_err = 1;
+			break;
+		}
+		for (i = 0; opts[i].subopt != -1; i++) {
+			if (opts[i].subopt == subopt) {
+				group = opts[i].group;
+				break;
+			}
+		}
+		if (opts[i].subopt == -1) {
+			char *hlp;
+
+			hlp = opt_help_str(opts);
+			__fmt_errstring(errstring,
+			    MAX_OPT_LENGTH + strlen(hlp),
+			    dgettext(TEXT_DOMAIN, not_valid),
+			    mema_opts[subopt], hlp);
+			free((void *)hlp);
+			subopt_err = 1;
+			break;
+		}
+		need_value = OPT_NEEDS_VALUE(subopt);
+		if (!need_value && value != NULL) {
+			__fmt_errstring(errstring, MAX_OPT_LENGTH,
+			    dgettext(TEXT_DOMAIN, no_value),
+			    mema_opts[subopt]);
+			subopt_err = 1;
+			break;
+		}
+		if (need_value && value == NULL) {
+			__fmt_errstring(errstring, MAX_OPT_LENGTH,
+			    dgettext(TEXT_DOMAIN, missing_value),
+			    mema_opts[subopt]);
+			subopt_err = 1;
+			break;
+		}
+		if (OPTSET_TEST(opt_set, subopt)) {
+			/* Ignore repeated options. */
+			continue;
+		}
+		if (group != 0 && !OPTSET_IS_EMPTY(opt_set)) {
+			for (i = 0; opts[i].subopt != -1; i++) {
+				if (i == subopt)
+					continue;
+				if (opts[i].group == group &&
+				    OPTSET_TEST(opt_set, opts[i].subopt))
+					break;
+			}
+			if (opts[i].subopt != -1) {
+				__fmt_errstring(errstring, MAX_OPT_LENGTH * 2,
+				    dgettext(TEXT_DOMAIN, conflict_opt),
+				    mema_opts[subopt],
+				    mema_opts[opts[i].subopt]);
+				subopt_err = 1;
+				break;
+			}
+		}
+		OPTSET_SET_VAL(opt_set, subopt, value);
+	}
+	free((void *)optcopy_alloc);
+	if (subopt_err) {
+		*retp = CFGA_ERROR;
+	}
+
+	return (opt_set);
+}
+
+#ifdef DEV_DEBUG
+
+static int
+debugging(void)
+{
+	char *ep;
+	static int inited;
+
+	if (inited)
+		return (debug_fp != NULL);
+	inited = 1;
+
+	if ((ep = getenv("MEMADM_DEBUG")) == NULL) {
+		return (0);
+	}
+	if (*ep == '\0')
+		debug_fp = stderr;
+	else {
+		if ((debug_fp = fopen(ep, "a")) == NULL)
+			return (0);
+	}
+	(void) fprintf(debug_fp, "\nDebug started, pid=%d\n", (int)getpid());
+	return (1);
+}
+
+static void
+dump_ioctl(
+	int cmd,
+	void *arg)
+{
+	if (!debugging())
+		return;
+
+	switch (cmd) {
+	case AC_MEM_CONFIGURE:
+		(void) fprintf(debug_fp, "IOCTL: AC_MEM_CONFIGURE\n");
+		break;
+
+	case AC_MEM_UNCONFIGURE:
+		(void) fprintf(debug_fp, "IOCTL: AC_MEM_UNCONFIGURE\n");
+		break;
+
+	case AC_MEM_TEST_START:
+		(void) fprintf(debug_fp, "IOCTL: AC_MEM_TEST_START\n");
+		break;
+
+	case AC_MEM_TEST_STOP: {
+		ac_mem_test_stop_t *tstop;
+
+		tstop = (ac_mem_test_stop_t *)arg;
+		(void) fprintf(debug_fp, "IOCTL: AC_MEM_TEST_STOP handle=%#x "
+		    "condition=%d\n", tstop->handle, tstop->condition);
+	}
+		break;
+	case AC_MEM_TEST_READ: {
+		ac_mem_test_read_t *tread;
+
+		tread = (ac_mem_test_read_t *)arg;
+		(void) fprintf(debug_fp, "IOCTL: AC_MEM_TEST_READ handle=%#x "
+		    "buf=%#p page=%#llx off=%#x count=%#x\n",
+		    tread->handle, tread->page_buf,
+		    tread->address.page_num,
+		    tread->address.line_offset, tread->address.line_count);
+	}
+		break;
+	case AC_MEM_TEST_WRITE: {
+		ac_mem_test_write_t *twrite;
+
+		twrite = (ac_mem_test_write_t *)arg;
+		(void) fprintf(debug_fp, "IOCTL: AC_MEM_TEST_WRITE handle=%#x "
+		    "buf=%#p page=%#llx off=%#x count=%#x\n",
+		    twrite->handle, twrite->page_buf,
+		    twrite->address.page_num,
+		    twrite->address.line_offset, twrite->address.line_count);
+	}
+		break;
+	case AC_MEM_ADMIN_VER:
+		(void) fprintf(debug_fp, "IOCTL: AC_MEM_ADMIN_VER:\n");
+		break;
+	case AC_MEM_STAT:
+		(void) fprintf(debug_fp, "IOCTL: AC_MEM_STAT\n");
+		break;
+	case AC_MEM_EXERCISE: {
+		ac_cfga_cmd_t *cmdp;
+
+		cmdp = arg;
+		(void) fprintf(debug_fp, "IOCTL: AC_MEM_EXERCISE arg=%d\n",
+		    cmdp->arg);
+		break;
+	}
+	default:
+		(void) fprintf(debug_fp, "IOCTL: unknown (%#x)\n", cmd);
+		break;
+	}
+	(void) fflush(debug_fp);
+}
+
+static void
+dump_ioctl_res(
+	int cmd,
+	void *arg,
+	int ret,
+	int ret_errno)
+{
+	if (!debugging())
+		return;
+
+	if (ret == -1) {
+		(void) fprintf(debug_fp, "IOCTL failed, \"%s\" (errno=%d)\n",
+		    strerror(ret_errno), ret_errno);
+		(void) fflush(debug_fp);
+		return;
+	} else {
+		(void) fprintf(debug_fp, "IOCTL succeeded, ret=%d\n", ret);
+	}
+
+	switch (cmd) {
+	case AC_MEM_CONFIGURE:
+	case AC_MEM_UNCONFIGURE:
+		break;
+	case AC_MEM_TEST_START: {
+		ac_mem_test_start_t *tstart;
+
+		tstart = (ac_mem_test_start_t *)arg;
+		(void) fprintf(debug_fp, "    handle=%#x tester_pid=%d "
+		    "prev_condition=%d bank_size=%#llx "
+		    "page_size=%#x line_size=%#x afar_base=%#llx\n",
+		    tstart->handle, (int)tstart->tester_pid,
+		    tstart->prev_condition,
+		    tstart->bank_size, tstart->page_size,
+		    tstart->line_size, tstart->afar_base);
+	}
+		break;
+	case AC_MEM_TEST_STOP:
+		break;
+	case AC_MEM_TEST_READ: {
+		ac_mem_test_read_t *tread;
+		sunfire_processor_error_regs_t *err;
+
+		tread = (ac_mem_test_read_t *)arg;
+		err = tread->error_buf;
+		if (ret_errno == EIO) {
+			(void) fprintf(debug_fp, "module_id=%#llx afsr=%#llx "
+			    "afar=%#llx udbh_error_reg=%#llx "
+			    "udbl_error_reg=%#llx\n",
+			    (longlong_t)err->module_id, (longlong_t)err->afsr,
+			    (longlong_t)err->afar,
+			    (longlong_t)err->udbh_error_reg,
+			    (longlong_t)err->udbl_error_reg);
+		} else {
+			(void) fprintf(debug_fp, "\n");
+		}
+	}
+		break;
+	case AC_MEM_TEST_WRITE:
+		break;
+	case AC_MEM_ADMIN_VER: {
+		ac_mem_version_t *ver;
+
+		ver = (ac_mem_version_t *)arg;
+		(void) fprintf(debug_fp, "    version %d\n", *ver);
+	}
+		break;
+	case AC_MEM_STAT: {
+		ac_stat_t *tstat;
+
+		tstat = (ac_stat_t *)arg;
+		(void) fprintf(debug_fp, "    rstate=%u ostate=%u "
+		    "condition=%u status_time=%#lx board=%u\n",
+		    (uint_t)tstat->rstate, (uint_t)tstat->ostate,
+		    (uint_t)tstat->condition, (ulong_t)tstat->status_time,
+		    tstat->board);
+		(void) fprintf(debug_fp, "    real_size=%u use_size=%u "
+		    "busy=%u\n",
+		    tstat->real_size, tstat->use_size, tstat->busy);
+		(void) fprintf(debug_fp, "    page_size=%#x "
+		    "phys_pages=%#llx managed=%#llx nonrelocatable=%#llx\n",
+		    tstat->page_size, (longlong_t)tstat->phys_pages,
+		    (longlong_t)tstat->managed,
+		    (longlong_t)tstat->nonrelocatable);
+		(void) fprintf(debug_fp, "    memctl=%#llx "
+		    "decode0=%#llx decode1=%#llx\n",
+		    (longlong_t)tstat->ac_memctl, (longlong_t)tstat->ac_decode0,
+		    (longlong_t)tstat->ac_decode1);
+	}
+		break;
+	case AC_MEM_EXERCISE: {
+		ac_cfga_cmd_t *cmdp;
+
+		cmdp = arg;
+		switch (cmdp->arg) {
+		case AC_MEMX_RELOCATE_ALL: {
+			struct ac_memx_relocate_stats *stp;
+
+			if ((stp = cmdp->private) != NULL) {
+				(void) fprintf(debug_fp, "    base=%u npgs=%u"
+				    " nopaget=%u nolock=%u isfree=%u reloc=%u"
+				    " noreloc=%u\n",
+				    stp->base, stp->npgs, stp->nopaget,
+				    stp->nolock, stp->isfree, stp->reloc,
+				    stp->noreloc);
+			}
+			break;
+		}
+		default:
+			break;
+		}
+		break;
+	}
+	default:
+		break;
+	}
+	(void) fflush(debug_fp);
+}
+#endif /* DEV_DEBUG */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/ac/common/mema_prom.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,270 @@
+/*
+ * 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.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1996-1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/param.h>
+#include <sys/obpdefs.h>
+#include <sys/fhc.h>
+#include <sys/ac.h>
+#include <sys/sysctrl.h>
+#include <sys/openpromio.h>
+#include "mema_prom.h"
+#include <config_admin.h>
+
+
+/*
+ * PROM access routines to get and set disabled lists
+ * Based on code in the usr/src/cmd/eeprom directory.
+ */
+#define	PROMDEV		"/dev/openprom"
+/*
+ * 128 is the size of the largest (currently) property name
+ * 8192 - MAXPROPSIZE - sizeof (int) is the size of the largest
+ * (currently) property value, viz. nvramrc.
+ * the sizeof(u_int) is from struct openpromio
+ */
+
+#define	MAXPROPSIZE	128
+#define	MAXNAMESIZE	MAXPROPSIZE
+#define	MAXVALSIZE	(8192 - MAXPROPSIZE - sizeof (u_int))
+#define	BUFSIZE		(MAXPROPSIZE + MAXVALSIZE + sizeof (u_int))
+typedef union {
+	char buf[BUFSIZE];
+	struct openpromio opp;
+} Oppbuf;
+#define	PROP_MEMORY_LIST	"disabled-memory-list"
+
+static int prom_read_one(mema_disabled_t *, int, int, char *, u_int);
+static int prom_write_one(mema_disabled_t *, int, int, char *, u_int);
+
+int
+prom_read_disabled_list(mema_disabled_t *dp, int bd)
+{
+	int prom_fd;
+	int ret;
+
+	(void) memset((void *)dp, 0, sizeof (*dp));
+	prom_fd = open(PROMDEV, O_RDONLY);
+	if (prom_fd == -1) {
+		return (0);
+	}
+	ret = prom_read_one(dp, bd, prom_fd,
+	    PROP_MEMORY_LIST, PROM_MEMORY_DISABLED);
+	(void) close(prom_fd);
+	return (ret);
+}
+
+int
+prom_write_disabled_list(mema_disabled_t *dp, int bd)
+{
+	int prom_fd;
+	int ret;
+
+	prom_fd = open(PROMDEV, O_RDWR);
+	if (prom_fd == -1) {
+		return (0);
+	}
+	ret = prom_write_one(dp, bd, prom_fd,
+	    PROP_MEMORY_LIST, PROM_MEMORY_DISABLED);
+	(void) close(prom_fd);
+	return (ret);
+}
+
+static int
+prom_read_one(
+	mema_disabled_t *dp,
+	int bd,
+	int prom_fd,
+	char *var,
+	u_int bit)
+{
+	Oppbuf oppbuf;
+	struct openpromio *opp = &oppbuf.opp;
+	int ret;
+
+	(void) memset((void *)&oppbuf, 0, sizeof (oppbuf));
+	(void) strncpy(opp->oprom_array, var, MAXNAMESIZE);
+	opp->oprom_size = MAXVALSIZE;
+	if (ioctl(prom_fd, OPROMGETOPT, opp) == -1) {
+		ret = 0;
+	} else
+	if (opp->oprom_size == 0) {
+		/* Not a failure - just not set to anything */
+		ret = 1;
+	} else {
+		char *cp;
+		int board;
+
+		ret = 1;
+		for (cp = opp->oprom_array; *cp != '\0'; cp++) {
+			switch (*cp) {
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+			case '8':
+			case '9':
+				board = *cp - '0';
+				break;
+			case 'a':
+			case 'b':
+			case 'c':
+			case 'd':
+			case 'e':
+			case 'f':
+				board = *cp - 'a' + 10;
+				break;
+			case 'A':
+			case 'B':
+			case 'C':
+			case 'D':
+			case 'E':
+			case 'F':
+				board = *cp - 'A' + 10;
+				break;
+			default:
+				/* Ignore bad characters. */
+				/* TODO: maybe should set ret to 0? */
+				board = -1;
+				break;
+			}
+			if (board == bd)
+				*dp |= bit;
+		}
+	}
+	return (ret);
+}
+
+static int
+prom_write_one(
+	mema_disabled_t *dp,
+	int bd,
+	int prom_fd,
+	char *var,
+	u_int bit)
+{
+	Oppbuf in_oppbuf;
+	struct openpromio *in_opp = &in_oppbuf.opp;
+	Oppbuf oppbuf;
+	struct openpromio *opp = &oppbuf.opp;
+	int ret;
+	char *cp;
+
+	/* Setup output buffer. */
+	(void) memset((void *)&oppbuf, 0, sizeof (oppbuf));
+	(void) strncpy(opp->oprom_array, var, MAXNAMESIZE);
+	opp->oprom_size = strlen(var) + 1;
+	cp = opp->oprom_array + opp->oprom_size;
+
+	/*
+	 * First read the existing list, filtering out 'bd' if 'bit'
+	 * not set.
+	 */
+	(void) memset((void *)&in_oppbuf, 0, sizeof (in_oppbuf));
+	(void) strncpy(in_opp->oprom_array, var, MAXNAMESIZE);
+	in_opp->oprom_size = MAXVALSIZE;
+	if (ioctl(prom_fd, OPROMGETOPT, in_opp) != -1 &&
+	    in_opp->oprom_size != 0) {
+		char *icp;
+		int board;
+
+		for (icp = in_opp->oprom_array; *icp != '\0'; icp++) {
+			switch (*icp) {
+			case '0': case '1': case '2': case '3':
+			case '4': case '5': case '6': case '7':
+			case '8': case '9':
+				board = *icp - '0';
+				break;
+			case 'a': case 'b': case 'c':
+			case 'd': case 'e': case 'f':
+				board = *icp - 'a' + 10;
+				break;
+			case 'A': case 'B': case 'C':
+			case 'D': case 'E': case 'F':
+				board = *icp - 'A' + 10;
+				break;
+			default:
+				/* Ignore bad characters. */
+				continue;
+			}
+			/* If enabling this board ... */
+			if (board == bd && (*dp & bit) == 0)
+				continue;
+			*cp++ = "0123456789abcdef"[board];
+			opp->oprom_size++;
+		}
+	}
+
+	if ((*dp & bit) != 0) {
+		*cp++ = "0123456789abcdef"[bd];
+		opp->oprom_size++;
+	}
+	if (ioctl(prom_fd, OPROMSETOPT, opp) == -1) {
+		ret = 0;
+	} else {
+		ret = 1;
+	}
+
+	return (ret);
+}
+
+/*
+ * The PROM only has board-level disable of memory.  If two banks are present
+ * on the board, both are either enabled or disabled at boot.
+ * The caller of this routine must set the PROM_MEMORY_PRESENT bits
+ * before calling this function.
+ */
+
+/*ARGSUSED*/
+int
+prom_viable_disabled_list(mema_disabled_t *dp)
+{
+#ifdef	XXX
+	int board;
+
+	for (board = 0; board < MAX_BOARDS; board++) {
+		if ((dp->bank_A[board] & PROM_MEMORY_PRESENT) != 0 &&
+		    (dp->bank_B[board] & PROM_MEMORY_PRESENT) != 0 &&
+		    (dp->bank_A[board] & PROM_MEMORY_DISABLED) !=
+		    (dp->bank_B[board] & PROM_MEMORY_DISABLED)) {
+			return (0);
+		}
+	}
+#endif
+	return (1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/ac/common/mema_prom.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1996-1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _MEMA_SF_PROM_H
+#define	_MEMA_SF_PROM_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned char mema_disabled_t;
+
+extern int prom_read_disabled_list(mema_disabled_t *, int);
+extern int prom_write_disabled_list(mema_disabled_t *, int);
+extern int prom_viable_disabled_list(mema_disabled_t *);
+
+#define	PROM_MEMORY_DISABLED	0x02
+#define	PROM_MEMORY_PRESENT	0x04	/* for viable check */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MEMA_SF_PROM_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/ac/common/mema_test.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,723 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1996-1998, 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/param.h>
+#include <config_admin.h>
+#include <memory.h>
+#include <sys/types.h>
+#include <time.h>
+#include "mema_test.h"
+
+typedef u_longlong_t pbuf_t;
+
+/*
+ * Test for stuck-at fault and transitional faults
+ *   Algorithm:
+ *         for i = 0 to npages
+ *              write(0x55)
+ *         for npages to 0
+ *              read_compare(0x55)
+ *              write(0xaa)
+ *         for 0 to number of pages
+ *              read_compare(0xaa)
+ *              write(0x55)
+ *              read_compare(0x55)
+ *
+ * stuck-at fault is detected because each cell have a 1 and a 0 is read
+ * transitional fault is detected because after each 0 to 1 and 1 to 0
+ * transition the value is check to be sure that the cell is not frozen.
+ */
+
+/*
+ * The following strings are subject of stderr output and
+ * gettext() is not used for them.
+ */
+static const char err_sum[] = "total error %u\n";
+static const char nts_msg[] = "Normal test started\n";
+static const char ntf_msg[] = "Normal test finished\n";
+static const char qts_msg[] = "Quick test started\n";
+static const char qtf_msg[] = "Quick test finished\n";
+static const char ets_msg[] = "Extended test started\n";
+static const char etf_msg[] = "Extended test finished\n";
+static const char m1_msg[] = "    March 1, ";
+static const char m2_msg[] = "    March 2, ";
+static const char m3_msg[] = "    March 3, ";
+static const char m4_msg[] = "    March 4, ";
+static const char wr_msg[] = "write. ";
+static const char rd_cmp_msg[] = "read/compare. ";
+static const char rpt_rd_cmp_msg[] = "repeated read/compare. ";
+static const char ml_rd_cmp_msg[] = "mixed line read/compare. ";
+static const char ln_rd_cmp_msg[] = "line read/compare. ";
+static const char report_msg[] = "%s%s%d%% complete.\n";
+static const char pg_header_msg[] = "    Errors at page address: 0x%x.\n";
+static const char rd_err_msg[] = "    Error reading page at address: 0x%x.\n";
+static const char wr_err_msg[] = "    Error writing page at address: 0x%x.\n";
+static const
+char mem_err_msg[] = "      Offset: 0x%x, data written/read: 0x%2x/0x%2x.\n";
+
+/*
+ * Macros do deal with test conditions.
+ */
+#define	TEST_END(END_MSG) \
+			if ((handle->max_errors != 0) &&\
+				(handle->max_errors == total_errors)) {\
+				mtest_message(handle, (END_MSG));\
+				error_summary(handle, total_errors);\
+				SET_CONDITION(handle, cond);\
+				return (MTEST_DONE);\
+			}
+
+static void
+error_summary(mtest_handle_t handle, uint_t total_errors)
+{
+	char msgbuf[100];
+
+	(void) sprintf(msgbuf, err_sum, total_errors);
+	mtest_message(handle, msgbuf);
+}
+
+
+static void
+error_print(char *writebuf, char *readbuf, mtest_handle_t handle, long pageno,
+	uint_t *total_errorsp)
+{
+	char msgbuf[100];
+	size_t offset;
+
+	(void) sprintf(msgbuf, pg_header_msg, PAGE_SIZE(handle) * pageno);
+	mtest_message(handle, msgbuf);
+
+	for (offset = 0; offset < PAGE_SIZE(handle); offset++) {
+		if ((handle->max_errors != 0) &&
+		    (readbuf[offset] != writebuf[offset]) &&
+		    (handle->max_errors == *total_errorsp))
+			return;
+		else {
+			(*total_errorsp)++;
+			(void) sprintf(msgbuf, mem_err_msg, offset,
+			    writebuf[offset], readbuf[offset]);
+			mtest_message(handle, msgbuf);
+		}
+	}
+}
+
+int
+memory_test_normal(
+	mtest_handle_t handle)
+{
+	pbuf_t *patternbuf1;
+	pbuf_t *patternbuf2;
+	pbuf_t *readbuf;
+	long npages, pageno;
+	struct mtest_error errbuf;
+	uint_t total_errors;
+	cfga_cond_t cond;
+	time_t time_rep;
+	char msgbuf[100];
+
+	patternbuf1 = (pbuf_t *)mtest_allocate_page_buf(handle);
+	patternbuf2 = (pbuf_t *)mtest_allocate_page_buf(handle);
+	readbuf = (pbuf_t *)mtest_allocate_page_buf(handle);
+	if (patternbuf1 == NULL || patternbuf2 == NULL || readbuf == NULL) {
+		return (MTEST_LIB_ERROR);
+	}
+
+	mtest_message(handle, nts_msg);
+	npages = BANK_SIZE(handle) / PAGE_SIZE(handle);
+
+	total_errors = 0;
+	cond = CFGA_COND_OK;
+
+	(void) memset((void *)patternbuf1, 0x55, PAGE_SIZE(handle));
+	(void) memset((void *)patternbuf2, 0xaa, PAGE_SIZE(handle));
+
+	time_rep = time(NULL) + REPORT_SEC;
+
+	for (pageno = 0; pageno < npages; pageno++) {
+		if (mtest_write(handle, (void *)patternbuf1, pageno, 0, 0)
+		    == -1) {
+			(void) sprintf(msgbuf, wr_err_msg, pageno);
+			mtest_message(handle, msgbuf);
+			return (MTEST_DEV_ERROR);
+		}
+		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
+		    (pageno == 0)) {
+			(void) sprintf(msgbuf, report_msg, m1_msg, wr_msg,
+			    ((pageno + 1) * 100) / npages);
+			mtest_message(handle, msgbuf);
+			time_rep = time(NULL) + REPORT_SEC;
+		}
+	}
+	for (pageno = npages-1; pageno >= 0; pageno--) {
+		if (mtest_read(handle, (void *)readbuf, pageno, 0, 0, &errbuf)
+		    == -1) {
+			(void) sprintf(msgbuf, rd_err_msg, pageno);
+			mtest_message(handle, msgbuf);
+			return (MTEST_DEV_ERROR);
+		}
+		if (errbuf.error_type != MTEST_ERR_NONE) {
+			if (errbuf.error_type == MTEST_ERR_CE &&
+			    cond != CFGA_COND_FAILED)
+				cond = CFGA_COND_FAILING;
+			else
+				cond = CFGA_COND_FAILED;
+			total_errors++;
+			/*
+			 * Keep going if max errors is 0 or limit not
+			 * reached.
+			 */
+			TEST_END(ntf_msg);
+		}
+		if (memcmp((void *)patternbuf1, (void *)readbuf,
+		    PAGE_SIZE(handle)) != 0) {
+			cond = CFGA_COND_FAILED;
+			error_print((void *)patternbuf1, (void *)readbuf,
+			    handle, pageno, &total_errors);
+			TEST_END(ntf_msg);
+		}
+		if (mtest_write(handle, (void *)patternbuf2, pageno, 0, 0)
+		    == -1) {
+			(void) sprintf(msgbuf, wr_err_msg, pageno);
+			mtest_message(handle, msgbuf);
+			return (MTEST_DEV_ERROR);
+		}
+		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
+		    (pageno == 0)) {
+			(void) sprintf(msgbuf, report_msg, m1_msg, rd_cmp_msg,
+			    ((npages - pageno) * 100) / npages);
+			mtest_message(handle, msgbuf);
+			time_rep = time(NULL) + REPORT_SEC;
+		}
+	}
+	/* March 2 (repeated) */
+	for (pageno = 0; pageno < npages; pageno++) {
+		if (mtest_read(handle, (void *)readbuf, pageno, 0, 0, &errbuf)
+		    == -1) {
+			(void) sprintf(msgbuf, rd_err_msg, pageno);
+			mtest_message(handle, msgbuf);
+			return (MTEST_DEV_ERROR);
+		}
+		if (errbuf.error_type != MTEST_ERR_NONE) {
+			if (errbuf.error_type == MTEST_ERR_CE &&
+			    cond != CFGA_COND_FAILED)
+				cond = CFGA_COND_FAILING;
+			else
+				cond = CFGA_COND_FAILED;
+			total_errors++;
+			TEST_END(ntf_msg);
+		}
+		if (memcmp((void *)patternbuf2, (void *)readbuf,
+		    PAGE_SIZE(handle)) != 0) {
+			cond = CFGA_COND_FAILED;
+			error_print((void *)patternbuf2, (void *)readbuf,
+			    handle, pageno, &total_errors);
+			TEST_END(ntf_msg);
+		}
+		if (mtest_write(handle, (void *)patternbuf1, pageno, 0, 0)
+		    == -1) {
+			(void) sprintf(msgbuf, wr_err_msg, pageno);
+			mtest_message(handle, msgbuf);
+			return (MTEST_DEV_ERROR);
+		}
+		if (mtest_read(handle, (void *)readbuf, pageno, 0, 0, &errbuf)
+		    == -1) {
+			(void) sprintf(msgbuf, rd_err_msg, pageno);
+			mtest_message(handle, msgbuf);
+			return (MTEST_DEV_ERROR);
+		}
+		if (errbuf.error_type != MTEST_ERR_NONE) {
+			if (errbuf.error_type == MTEST_ERR_CE &&
+			    cond != CFGA_COND_FAILED)
+				cond = CFGA_COND_FAILING;
+			else
+				cond = CFGA_COND_FAILED;
+			total_errors++;
+			TEST_END(ntf_msg);
+		}
+		if (memcmp((void *)patternbuf1, (void *)readbuf,
+		    PAGE_SIZE(handle)) != 0) {
+			cond = CFGA_COND_FAILED;
+			error_print((void *)patternbuf1, (void *)readbuf,
+			    handle, pageno, &total_errors);
+			TEST_END(ntf_msg);
+		}
+		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
+		    (pageno == 0)) {
+			(void) sprintf(msgbuf, report_msg, m2_msg,
+			    rpt_rd_cmp_msg, ((pageno + 1) * 100) / npages);
+			mtest_message(handle, msgbuf);
+			time_rep = time(NULL) + REPORT_SEC;
+		}
+	}
+	mtest_message(handle, ntf_msg);
+	error_summary(handle, total_errors);
+	SET_CONDITION(handle, cond);
+	return (MTEST_DONE);
+}
+
+/* this test look only for stuck-at fault */
+int
+memory_test_quick(
+	mtest_handle_t handle)
+{
+	pbuf_t *patternbuf1;
+	pbuf_t *patternbuf2;
+	pbuf_t *readbuf;
+	long npages, pageno;
+	struct mtest_error errbuf;
+	uint_t total_errors;
+	cfga_cond_t cond;
+	time_t time_rep;
+	char msgbuf[100];
+
+	patternbuf1 = (pbuf_t *)mtest_allocate_page_buf(handle);
+	patternbuf2 = (pbuf_t *)mtest_allocate_page_buf(handle);
+	readbuf = (pbuf_t *)mtest_allocate_page_buf(handle);
+	if (patternbuf1 == NULL || patternbuf2 == NULL || readbuf == NULL) {
+		return (MTEST_LIB_ERROR);
+	}
+
+	mtest_message(handle, qts_msg);
+	npages = BANK_SIZE(handle) / PAGE_SIZE(handle);
+
+	total_errors = 0;
+	cond = CFGA_COND_OK;
+
+	(void) memset((void *)patternbuf1, 0x55, PAGE_SIZE(handle));
+	(void) memset((void *)patternbuf2, 0xaa, PAGE_SIZE(handle));
+
+	time_rep = time(NULL) + REPORT_SEC;
+
+	for (pageno = 0; pageno < npages; pageno++) {
+		if (mtest_write(handle, (void *)patternbuf1, pageno, 0, 0)
+		    == -1) {
+			(void) sprintf(msgbuf, wr_err_msg, pageno);
+			mtest_message(handle, msgbuf);
+			return (MTEST_DEV_ERROR);
+		}
+		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
+		    (pageno == 0)) {
+			(void) sprintf(msgbuf, report_msg, m1_msg, wr_msg,
+			    ((pageno + 1) * 100) / npages);
+			mtest_message(handle, msgbuf);
+			time_rep = time(NULL) + REPORT_SEC;
+		}
+	}
+
+	for (pageno = npages-1; pageno >= 0; pageno--) {
+		if (mtest_read(handle, (void *)readbuf, pageno, 0, 0, &errbuf)
+		    == -1) {
+			(void) sprintf(msgbuf, rd_err_msg, pageno);
+			mtest_message(handle, msgbuf);
+			return (MTEST_DEV_ERROR);
+		}
+		if (errbuf.error_type != MTEST_ERR_NONE) {
+			if (errbuf.error_type == MTEST_ERR_CE &&
+			    cond != CFGA_COND_FAILED)
+				cond = CFGA_COND_FAILING;
+			else
+				cond = CFGA_COND_FAILED;
+			total_errors++;
+			/*
+			 * Keep going if max errors is 0 or limit not
+			 * reached.
+			 */
+			TEST_END(qtf_msg);
+		}
+		if (memcmp((void *)patternbuf1, (void *)readbuf,
+		    PAGE_SIZE(handle)) != 0) {
+			cond = CFGA_COND_FAILED;
+			error_print((void *)patternbuf1, (void *)readbuf,
+			    handle, pageno, &total_errors);
+			TEST_END(qtf_msg);
+		}
+		if (mtest_write(handle, (void *)patternbuf2, pageno, 0, 0)
+		    == -1) {
+			(void) sprintf(msgbuf, wr_err_msg, pageno);
+			mtest_message(handle, msgbuf);
+			return (MTEST_DEV_ERROR);
+		}
+		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
+		    (pageno == 0)) {
+			(void) sprintf(msgbuf, report_msg, m1_msg, rd_cmp_msg,
+			    ((npages - pageno) * 100) / npages);
+			mtest_message(handle, msgbuf);
+			time_rep = time(NULL) + REPORT_SEC;
+		}
+	}
+	/* March 2 */
+	for (pageno = 0; pageno < npages; pageno++) {
+		if (mtest_read(handle, (void *)readbuf, pageno, 0, 0, &errbuf)
+		    == -1) {
+			(void) sprintf(msgbuf, rd_err_msg, pageno);
+			mtest_message(handle, msgbuf);
+			return (MTEST_DEV_ERROR);
+		}
+		if (errbuf.error_type != MTEST_ERR_NONE) {
+			if (errbuf.error_type == MTEST_ERR_CE &&
+			    cond != CFGA_COND_FAILED)
+				cond = CFGA_COND_FAILING;
+			else
+				cond = CFGA_COND_FAILED;
+			total_errors++;
+			TEST_END(qtf_msg);
+		}
+		if (memcmp((void *)patternbuf2, (void *)readbuf,
+		    PAGE_SIZE(handle)) != 0) {
+			cond = CFGA_COND_FAILED;
+			error_print((void *)patternbuf2, (void *)readbuf,
+			    handle, pageno, &total_errors);
+			TEST_END(qtf_msg);
+		}
+		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
+		    (pageno == 0)) {
+			(void) sprintf(msgbuf, report_msg, m2_msg, rd_cmp_msg,
+			    ((pageno + 1) * 100) / npages);
+			mtest_message(handle, msgbuf);
+			time_rep = time(NULL) + REPORT_SEC;
+		}
+	}
+	mtest_message(handle, qtf_msg);
+	error_summary(handle, total_errors);
+	SET_CONDITION(handle, cond);
+	return (MTEST_DONE);
+}
+
+
+/* look for stuck-at, transition, coupling fault: inversion, idempotent */
+int
+memory_test_extended(
+	mtest_handle_t handle)
+{
+	pbuf_t *patternbuf0, *patternbuf1;
+	pbuf_t *readbuf0, *readbuf1, *readbuf2;
+	long npages, pageno;
+	long line;
+	struct mtest_error errbuf;
+	uint_t total_errors;
+	cfga_cond_t cond;
+	time_t time_rep;
+	char msgbuf[100];
+
+	patternbuf0 = (pbuf_t *)mtest_allocate_page_buf(handle);
+	patternbuf1 = (pbuf_t *)mtest_allocate_page_buf(handle);
+	readbuf0 = (pbuf_t *)mtest_allocate_page_buf(handle);
+	readbuf1 = (pbuf_t *)mtest_allocate_page_buf(handle);
+	readbuf2 = (pbuf_t *)mtest_allocate_page_buf(handle);
+	if (patternbuf0 == NULL || patternbuf1 == NULL ||
+	    readbuf0 == NULL || readbuf1 == NULL || readbuf2 == NULL) {
+		return (MTEST_LIB_ERROR);
+	}
+
+	mtest_message(handle, ets_msg);
+	npages = BANK_SIZE(handle) / PAGE_SIZE(handle);
+
+	total_errors = 0;
+	cond = CFGA_COND_OK;
+
+	(void) memset((void *)patternbuf0, 0x55, PAGE_SIZE(handle));
+	(void) memset((void *)patternbuf1, 0xaa, PAGE_SIZE(handle));
+
+	time_rep = time(NULL) + REPORT_SEC;
+
+	for (pageno = 0; pageno < npages; pageno++) {
+		if (mtest_write(handle, (void *)patternbuf0, pageno, 0, 0)
+		    == -1) {
+			(void) sprintf(msgbuf, wr_err_msg, pageno);
+			mtest_message(handle, msgbuf);
+			return (MTEST_DEV_ERROR);
+		}
+		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
+		    (pageno == 0)) {
+			(void) sprintf(msgbuf, report_msg, m1_msg, wr_msg,
+			    ((pageno + 1) * 100) / npages);
+			mtest_message(handle, msgbuf);
+			time_rep = time(NULL) + REPORT_SEC;
+		}
+	}
+
+	/*
+	 * Line tests take 5-9 time longer and the reprting interval
+	 * should be extended 3-5 times.
+	 */
+
+	/* March 1 */
+	for (pageno = npages-1; pageno >= 0; pageno--) {
+		for (line = (LINES_PER_PAGE(handle) - 1); line >= 0; line--) {
+			if (mtest_read(handle, (void *)readbuf0, pageno,
+			    line, 1, &errbuf) == -1) {
+				(void) sprintf(msgbuf, rd_err_msg, pageno);
+				mtest_message(handle, msgbuf);
+				return (MTEST_DEV_ERROR);
+			}
+			if (errbuf.error_type != MTEST_ERR_NONE) {
+				if (errbuf.error_type == MTEST_ERR_CE &&
+				    cond != CFGA_COND_FAILED)
+					cond = CFGA_COND_FAILING;
+				else
+					cond = CFGA_COND_FAILED;
+				total_errors++;
+				/*
+				 * Keep going if max errors is 0 or limit not
+				 * reached.
+				 */
+				TEST_END(ntf_msg);
+			}
+			if (mtest_write(handle, (void*)patternbuf1, pageno,
+			    line, 1) == -1) {
+				(void) sprintf(msgbuf, wr_err_msg, pageno);
+				mtest_message(handle, msgbuf);
+				return (MTEST_DEV_ERROR);
+			}
+			if (mtest_read(handle, (void *)readbuf1, pageno,
+			    line, 1, &errbuf) == -1) {
+				(void) sprintf(msgbuf, rd_err_msg, pageno);
+				mtest_message(handle, msgbuf);
+				return (MTEST_DEV_ERROR);
+			}
+			if (errbuf.error_type != MTEST_ERR_NONE) {
+				if (errbuf.error_type == MTEST_ERR_CE &&
+				    cond != CFGA_COND_FAILED)
+					cond = CFGA_COND_FAILING;
+				else
+					cond = CFGA_COND_FAILED;
+				total_errors++;
+				TEST_END(ntf_msg);
+			}
+			if (mtest_write(handle, (void*)patternbuf0, pageno,
+			    line, 1) == -1) {
+				(void) sprintf(msgbuf, wr_err_msg, pageno);
+				mtest_message(handle, msgbuf);
+				return (MTEST_DEV_ERROR);
+			}
+			if (mtest_read(handle, (void *)readbuf2, pageno,
+			    line, 1, &errbuf) == -1) {
+				(void) sprintf(msgbuf, rd_err_msg, pageno);
+				mtest_message(handle, msgbuf);
+				return (MTEST_DEV_ERROR);
+			}
+			if (errbuf.error_type != MTEST_ERR_NONE) {
+				if (errbuf.error_type == MTEST_ERR_CE &&
+				    cond != CFGA_COND_FAILED)
+					cond = CFGA_COND_FAILING;
+				else
+					cond = CFGA_COND_FAILED;
+				total_errors++;
+				TEST_END(ntf_msg);
+			}
+			if (mtest_write(handle, (void*)patternbuf1, pageno,
+			    line, 1) == -1) {
+				(void) sprintf(msgbuf, wr_err_msg, pageno);
+				return (MTEST_DEV_ERROR);
+			}
+		}	/* line */
+		if (memcmp((void *)patternbuf0, (void *)readbuf0,
+		    PAGE_SIZE(handle)) != 0) {
+			cond = CFGA_COND_FAILED;
+			error_print((void *)patternbuf0, (void *)readbuf0,
+			    handle, pageno, &total_errors);
+			TEST_END(ntf_msg);
+		}
+		if (memcmp((void *)patternbuf1, (void *)readbuf1,
+			PAGE_SIZE(handle)) != 0) {
+			cond = CFGA_COND_FAILED;
+			error_print((void *)patternbuf1, (void *)readbuf1,
+			    handle, pageno, &total_errors);
+			TEST_END(ntf_msg);
+		}
+		if (memcmp((void *)patternbuf0, (void *)readbuf2,
+			PAGE_SIZE(handle)) != 0) {
+			cond = CFGA_COND_FAILED;
+			error_print((void *)patternbuf0, (void *)readbuf2,
+			    handle, pageno, &total_errors);
+			TEST_END(ntf_msg);
+		}
+		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
+		    (pageno == 0)) {
+			(void) sprintf(msgbuf, report_msg, m1_msg,
+			    ml_rd_cmp_msg, ((npages - pageno) * 100) / npages);
+			mtest_message(handle, msgbuf);
+			time_rep = time(NULL) + REPORT_SEC * 3;
+		}
+	}	/* page */
+
+	/* March 2 */
+	for (pageno = npages-1; pageno >= 0; pageno--) {
+		for (line = (LINES_PER_PAGE(handle) - 1); line >= 0; line--) {
+			if (mtest_read(handle, (void *)readbuf0, pageno,
+			    line, 1, &errbuf) == -1) {
+				(void) sprintf(msgbuf, rd_err_msg, pageno);
+				mtest_message(handle, msgbuf);
+				return (MTEST_DEV_ERROR);
+			}
+			if (errbuf.error_type != MTEST_ERR_NONE) {
+				if (errbuf.error_type == MTEST_ERR_CE &&
+				    cond != CFGA_COND_FAILED)
+					cond = CFGA_COND_FAILING;
+				else
+					cond = CFGA_COND_FAILED;
+				total_errors++;
+				/*
+				 * Keep going if max errors is 0 or limit not
+				 * reached.
+				 */
+				TEST_END(ntf_msg);
+			}
+			if (mtest_write(handle, (void*)patternbuf0, pageno,
+			    line, 1) == -1) {
+				(void) sprintf(msgbuf, wr_err_msg, pageno);
+				mtest_message(handle, msgbuf);
+				return (MTEST_DEV_ERROR);
+			}
+			if (mtest_write(handle, (void*)patternbuf1, pageno,
+			    line, 1) == -1) {
+				(void) sprintf(msgbuf, wr_err_msg, pageno);
+				mtest_message(handle, msgbuf);
+				return (MTEST_DEV_ERROR);
+			}
+		}
+		if (memcmp((void *)patternbuf1, (void *)readbuf0,
+			PAGE_SIZE(handle)) != 0) {
+			cond = CFGA_COND_FAILED;
+			total_errors++;
+		}
+		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
+		    (pageno == 0)) {
+			(void) sprintf(msgbuf, report_msg, m2_msg,
+			    ln_rd_cmp_msg, ((npages - pageno) * 100) / npages);
+			mtest_message(handle, msgbuf);
+			time_rep = time(NULL) + REPORT_SEC * 3;
+		}
+	}	/* page */
+
+	/* March 3 */
+	for (pageno = 0; pageno < npages; pageno++) {
+		for (line = 0; line < LINES_PER_PAGE(handle); line++) {
+			if (mtest_read(handle, (void *)readbuf0, pageno,
+			    line, 1, &errbuf) == -1) {
+				(void) sprintf(msgbuf, rd_err_msg, pageno);
+				mtest_message(handle, msgbuf);
+				return (MTEST_DEV_ERROR);
+			}
+			if (errbuf.error_type != MTEST_ERR_NONE) {
+				if (errbuf.error_type == MTEST_ERR_CE &&
+				    cond != CFGA_COND_FAILED)
+					cond = CFGA_COND_FAILING;
+				else
+					cond = CFGA_COND_FAILED;
+				total_errors++;
+				TEST_END(ntf_msg);
+			}
+			if (mtest_write(handle, (void*)patternbuf0, pageno,
+			    line, 1) == -1) {
+				(void) sprintf(msgbuf, wr_err_msg, pageno);
+				mtest_message(handle, msgbuf);
+				return (MTEST_DEV_ERROR);
+			}
+			if (mtest_write(handle, (void*)patternbuf1, pageno,
+			    line, 1) == -1) {
+				(void) sprintf(msgbuf, wr_err_msg, pageno);
+				mtest_message(handle, msgbuf);
+				return (MTEST_DEV_ERROR);
+			}
+			if (mtest_write(handle, (void*)patternbuf0, pageno,
+			    line, 1) == -1) {
+				(void) sprintf(msgbuf, wr_err_msg, pageno);
+				mtest_message(handle, msgbuf);
+				return (MTEST_DEV_ERROR);
+			}
+		}
+		if (memcmp((void *)patternbuf1, (void *)readbuf0,
+			PAGE_SIZE(handle)) != 0) {
+			cond = CFGA_COND_FAILED;
+			error_print((void *)patternbuf1, (void *)readbuf0,
+			    handle, pageno, &total_errors);
+			TEST_END(ntf_msg);
+		}
+		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
+		    (pageno == 0)) {
+			(void) sprintf(msgbuf, report_msg, m3_msg,
+			    ml_rd_cmp_msg, ((pageno + 1) * 100) / npages);
+			mtest_message(handle, msgbuf);
+			time_rep = time(NULL) + REPORT_SEC * 3;
+		}
+	}	/* page */
+
+	/* March 4 */
+	for (pageno = 0; pageno < npages; pageno++) {
+		for (line = 0; line < LINES_PER_PAGE(handle); line++) {
+			if (mtest_read(handle, (void *)readbuf0, pageno,
+			    line, 1, &errbuf) == -1) {
+				(void) sprintf(msgbuf, rd_err_msg, pageno);
+				mtest_message(handle, msgbuf);
+				return (MTEST_DEV_ERROR);
+			}
+			if (errbuf.error_type != MTEST_ERR_NONE) {
+				if (errbuf.error_type == MTEST_ERR_CE &&
+				    cond != CFGA_COND_FAILED)
+					cond = CFGA_COND_FAILING;
+				else
+					cond = CFGA_COND_FAILED;
+				total_errors++;
+				TEST_END(ntf_msg);
+			}
+			if (mtest_write(handle, (void*)patternbuf1, pageno,
+			    line, 1) == -1) {
+				(void) sprintf(msgbuf, wr_err_msg, pageno);
+				mtest_message(handle, msgbuf);
+				return (MTEST_DEV_ERROR);
+			}
+			if (mtest_write(handle, (void*)patternbuf0, pageno,
+			    line, 1) == -1) {
+				(void) sprintf(msgbuf, wr_err_msg, pageno);
+				mtest_message(handle, msgbuf);
+				return (MTEST_DEV_ERROR);
+			}
+		}
+		if (memcmp((void *)patternbuf0, (void *)readbuf0,
+			PAGE_SIZE(handle)) != 0) {
+			cond = CFGA_COND_FAILED;
+			error_print((void *)patternbuf0, (void *)readbuf0,
+			    handle, pageno, &total_errors);
+			TEST_END(ntf_msg);
+		}
+		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
+		    (pageno == 0)) {
+			(void) sprintf(msgbuf, report_msg, m4_msg,
+			    ln_rd_cmp_msg, ((pageno + 1) * 100) / npages);
+			mtest_message(handle, msgbuf);
+			time_rep = time(NULL) + REPORT_SEC * 3;
+		}
+	}	/* page */
+	mtest_message(handle, etf_msg);
+	error_summary(handle, total_errors);
+	SET_CONDITION(handle, cond);
+	return (MTEST_DONE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/ac/common/mema_test.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1996-1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _MEMA_TEST_H
+#define	_MEMA_TEST_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct mtest_alloc_ent {
+	struct mtest_alloc_ent	*next;
+	void			*buf;
+};
+
+struct mtest_handle {
+	u_longlong_t		bank_size;
+	ulong_t			page_size;
+	ulong_t			line_size;
+	ulong_t			lines_per_page;
+	cfga_cond_t		condition;
+	int			fd;
+	ulong_t			max_errors;
+	struct mtest_alloc_ent	*alloc_list;
+	void			*drvhandle;
+	struct cfga_msg		*msgp;
+};
+
+typedef struct mtest_handle *mtest_handle_t;
+
+typedef int mtest_func_t(mtest_handle_t);
+
+struct mtest_table_ent {
+	const char	*test_name;
+	mtest_func_t	*test_func;
+};
+extern struct mtest_table_ent mtest_table[];
+#define	MTEST_DEFAULT_TEST	(0)
+extern char **mtest_build_opts(int *maxerr_idx);
+
+#define	BANK_SIZE(H)		((H)->bank_size)
+#define	PAGE_SIZE(H)		((H)->page_size)
+#define	LINE_SIZE(H)		((H)->line_size)
+#define	LINES_PER_PAGE(H)	((H)->lines_per_page)
+#define	SET_CONDITION(H, C)	((H)->condition = (C))
+
+struct mtest_error {
+	int		error_type;
+};
+
+/*
+ * Error types.
+ */
+#define	MTEST_ERR_NONE		0
+#define	MTEST_ERR_UE		1
+#define	MTEST_ERR_CE		2
+
+/*
+ * Test routine return codes.
+ */
+#define	MTEST_DONE		0
+#define	MTEST_LIB_ERROR		1
+#define	MTEST_DEV_ERROR		2
+
+/*
+ * Each test is allowed maximum number of errors and the index has
+ * to be coordinated with the token table size in mema_test_config.c
+ */
+#define	MAX_ERRORS		32
+#define	REPORT_SEC		5
+
+/*
+ * Test functions should use this buffer allocation interface.
+ * The test framework will deallocate them on return.
+ */
+extern void *mtest_allocate_buf(mtest_handle_t, size_t);
+#define	mtest_allocate_page_buf(H)	mtest_allocate_buf((H), \
+					(size_t)PAGE_SIZE(H))
+extern void mtest_deallocate_buf(mtest_handle_t, void *);
+extern void mtest_deallocate_buf_all(mtest_handle_t);
+
+/*
+ * Test write: mtest_write(handle, buffer, page_num, line_offset, line_count)
+ * A line count of 0 indicates the whole page.
+ * A return of 0 indicates success.  A return of -1 indicates a failure of
+ * the device interface.
+ */
+extern int mtest_write(mtest_handle_t, void *, u_longlong_t, uint_t, uint_t);
+extern int mtest_read(mtest_handle_t, void *, u_longlong_t, uint_t, uint_t,
+    struct mtest_error *);
+
+/*
+ * Message interface. If the upper layer has verbose on, the
+ * message will be seen by the user.
+ */
+extern void mtest_message(mtest_handle_t, const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MEMA_TEST_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/ac/common/mema_test_config.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,79 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1996-1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <config_admin.h>
+#include <memory.h>
+#include "mema_test.h"
+
+extern mtest_func_t memory_test_normal;
+extern mtest_func_t memory_test_quick;
+extern mtest_func_t memory_test_extended;
+
+/*
+ * Default test is first entry in the table (MTEST_DEFAULT_TEST).
+ */
+struct mtest_table_ent mtest_table[] = {
+	{"normal",	memory_test_normal},
+	{"quick",	memory_test_quick},
+	{"extended",	memory_test_extended},
+};
+
+static char **opt_array;
+
+char **
+mtest_build_opts(int *maxerr_idx)
+{
+	if (opt_array == NULL) {
+		int nopts;
+		/*
+		 * Test "type" options here, max_errors should be the
+		 * last one.
+		 */
+		nopts = sizeof (mtest_table) / sizeof (mtest_table[0]);
+		*maxerr_idx = nopts;
+
+		/*
+		 * One extra option for "max_errors"
+		 */
+		opt_array = (char **)malloc((nopts + 2) * sizeof (*opt_array));
+		if (opt_array != NULL) {
+			int i;
+
+			for (i = 0; i < nopts; i++)
+				opt_array[i] = (char *)mtest_table[i].test_name;
+
+			opt_array[nopts] = "max_errors";
+			opt_array[nopts + 1] = NULL;
+		}
+	}
+	*maxerr_idx = sizeof (mtest_table) / sizeof (mtest_table[0]);
+	return (opt_array);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/ac/common/mema_test_subr.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1996-1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/param.h>
+#include <memory.h>
+#include <config_admin.h>
+#include "mema_test.h"
+
+void *
+mtest_allocate_buf(
+	mtest_handle_t handle,
+	size_t size)
+{
+	struct mtest_alloc_ent *new_ent;
+
+	new_ent =
+	    (struct mtest_alloc_ent *)malloc(sizeof (struct mtest_alloc_ent));
+	if (new_ent == NULL)
+		return (NULL);
+
+	new_ent->buf = malloc(size);
+	if (new_ent->buf == NULL) {
+		free((void *)new_ent);
+		return (NULL);
+	}
+	/* TODO: probably not thread safe? */
+	new_ent->next = handle->alloc_list;
+	handle->alloc_list = new_ent;
+
+	return (new_ent->buf);
+}
+
+/* This routine dedicated to George Cameron */
+void
+mtest_deallocate_buf(
+	mtest_handle_t handle,
+	void *buf)
+{
+	struct mtest_alloc_ent **p, *p1;
+
+	p = &handle->alloc_list;
+	while ((*p) != NULL && (*p)->buf != buf)
+		p = &(*p)->next;
+	assert((*p) != NULL);
+	p1 = *p;
+	*p = (*p)->next;
+	free(p1->buf);
+	free((void *)p1);
+}
+
+void
+mtest_deallocate_buf_all(mtest_handle_t handle)
+{
+	struct mtest_alloc_ent *p1;
+
+	while ((p1 = handle->alloc_list) != NULL) {
+		handle->alloc_list = p1->next;
+		free(p1->buf);
+		free((void *)p1);
+	}
+}
+
+void
+mtest_message(mtest_handle_t handle, const char *msg)
+{
+	if (handle->msgp != NULL && handle->msgp->message_routine != NULL) {
+		(*handle->msgp->message_routine)(handle->msgp->appdata_ptr,
+		    msg);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/ac/common/mema_util.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <locale.h>
+#include <sys/param.h>
+#include <config_admin.h>
+#include "mema_util.h"
+
+/*
+ * The libmemadm routines can return arbitrary error strings.  As the
+ * calling program does not know how long these errors might be,
+ * the library routines must allocate the required space and the
+ * calling program must deallocate it.
+ *
+ * This routine povides a printf-like interface for creating the
+ * error strings.
+ */
+
+#define	FMT_STR_SLOP		(16)
+
+void
+__fmt_errstring(
+	char **errstring,
+	size_t extra_length_hint,
+	const char *fmt,
+	...)
+{
+	char *ebuf;
+	size_t elen;
+	va_list ap;
+
+	/*
+	 * If no errors required or error already set, return.
+	 */
+	if ((errstring == NULL) || (*errstring != NULL))
+		return;
+
+	elen = strlen(fmt) + extra_length_hint + FMT_STR_SLOP;
+
+	if ((ebuf = (char *)malloc(elen + 1)) == NULL)
+		return;
+
+	va_start(ap, fmt);
+	(void) vsprintf(ebuf, fmt, ap);
+	va_end(ap);
+
+	if (strlen(ebuf) > elen)
+		abort();
+
+	*errstring = ebuf;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/ac/common/mema_util.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,42 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1996-1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _MEMA_UTIL_H
+#define	_MEMA_UTIL_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void __fmt_errstring(char **, size_t, const char *, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MEMA_UTIL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/ac/sparc/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 1997-1998, by Sun Microsystems, Inc.
+# All rights reserved.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/ac/sparc/Makefile
+
+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/ac/sparcv9/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/ac/sparcv9/Makefile
+
+include ../Makefile.com
+include $(SRC)/lib/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/sysctrl/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,73 @@
+#
+# 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.
+#
+# 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 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/cfgadm_plugins/sysctrl/Makefile
+
+include		$(SRC)/Makefile.master
+
+SUBDIRS=	$(MACH) $(BUILD64) $(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 sysctrl.xcl
+POFILE=		sysctrl.po
+POFILES=	generic.po
+
+SED=	sed
+GREP=	grep
+CP=	cp
+
+.KEEP_STATE:
+
+all clean clobber delete install lint package: $(SUBDIRS)
+
+$(MACH) $(MACH64):	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]`
+	$(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/sysctrl/Makefile.com	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,99 @@
+#
+# 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.
+#
+# 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 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/sysctrl/Makefile.com
+#
+
+include $(SRC)/lib/cfgadm_plugins/Makefile.com
+
+PLATFORM=	sun4u
+LIBRARY= sysctrl.a
+VERS= .1
+
+OBJECTS= cfga.o
+
+# include library definitions
+include $(SRC)/lib/Makefile.lib
+
+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.root.bin=	$(INS) -s -d -m $(DIRMODE) $@
+$(CH)INS.dir.root.bin=	$(INS) -s -d -m $(DIRMODE) -u root -g bin $@
+
+USR_PLAT_DIR		= $(ROOT)/usr/platform
+USR_PSM_DIR		= $(USR_PLAT_DIR)/sun4u
+USR_PSM_LIB_DIR		= $(USR_PSM_DIR)/lib
+USR_PSM_LIB_CFG_DIR	= $(USR_PSM_LIB_DIR)/cfgadm
+USR_PSM_LIB_CFG_DIR_64	= $(USR_PSM_LIB_CFG_DIR)/$(MACH64)
+
+ROOTLIBDIR=     $(USR_PSM_LIB_CFG_DIR)
+ROOTLIBDIR64=   $(USR_PSM_LIB_CFG_DIR_64)
+
+MAPFILE=	../common/mapfile-vers
+SRCS=		$(OBJECTS:%.o=../common/%.c)
+
+LIBS = $(DYNLIB)
+
+CFLAGS +=	$(CCVERBOSE)
+DYNFLAGS +=	-M $(MAPFILE)
+LDLIBS +=	-lc
+
+CPPFLAGS +=	-I$(ROOT)/usr/platform/$(PLATFORM)/include
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint:   lintcheck
+
+$(DYNLIB):	$(MAPFILE)
+
+# Create target directories
+$(USR_PSM_DIR):		$(LINKED_DIRS)
+	-$(INS.dir.root.sys)
+
+$(USR_PSM_LIB_DIR):	$(USR_PSM_DIR)	$(LINKED_LIB_DIRS)
+	-$(INS.dir.root.bin)
+
+$(USR_PSM_LIB_CFG_DIR):	$(USR_PSM_LIB_DIR)	$(LINKED_CFG_DIRS)
+	-$(INS.dir.root.bin)
+
+$(USR_PSM_LIB_CFG_DIR_64):	$(USR_PSM_LIB_CFG_DIR)
+	-$(INS.dir.root.bin)
+
+$(USR_PSM_LIB_CFG_DIR)/%: % $(USR_PSM_LIB_CFG_DIR)
+	-$(INS.file)
+
+$(USR_PSM_LIB_CFG_DIR_64)/%: % $(USR_PSM_LIB_CFG_DIR_64)
+	-$(INS.file)
+
+# include library targets
+include $(SRC)/lib/Makefile.targ
+
+pics/%.o: ../common/%.c
+	$(COMPILE.c) -o $@ $<
+	$(POST_PROCESS_O)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/sysctrl/common/cfga.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,1480 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#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 <stdarg.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/dditypes.h>
+#include <sys/modctl.h>
+#include <sys/obpdefs.h>
+#include <sys/fhc.h>
+#include <sys/sysctrl.h>
+#include <sys/openpromio.h>
+#ifdef	SIM
+#include <sys/stat.h>
+#endif
+#define	CFGA_PLUGIN_LIB
+#include <config_admin.h>
+
+#ifdef	DEBUG
+#define	DBG	printf
+#define	DBG1	printf
+#define	DBG3	printf
+#define	DBG4	printf
+#else
+#define	DBG(a, b)
+#define	DBG1(a)
+#define	DBG3(a, b, c)
+#define	DBG4(a, b, c, d)
+#endif
+
+#define	BD_CPU			1
+#define	BD_MEM			2
+#define	BD_IO_2SBUS		3
+#define	BD_IO_SBUS_FFB		4
+#define	BD_IO_PCI		5
+#define	BD_DISK			6
+#define	BD_IO_2SBUS_SOCPLUS	7
+#define	BD_IO_SBUS_FFB_SOCPLUS	8
+#define	BD_UNKNOWN		9
+#define	CMD_GETSTAT		10
+#define	CMD_LIST		11
+#define	CMD_CONNECT		12
+#define	CMD_DISCONNECT		13
+#define	CMD_CONFIGURE		14
+#define	CMD_UNCONFIGURE		15
+#define	CMD_QUIESCE		16
+#define	CMD_INSERT		17
+#define	CMD_REMOVE		18
+#define	CMD_SET_COND		19
+#define	OPT_ENABLE		20
+#define	OPT_DISABLE		21
+#define	ERR_PROM_OPEN		22
+#define	ERR_PROM_GETPROP	23
+#define	ERR_PROM_SETPROP	24
+#define	ERR_TRANS		25
+#define	ERR_CMD_INVAL		26
+#define	ERR_OPT_INVAL		27
+#define	ERR_AP_INVAL		28
+#define	ERR_DISABLED		29
+#define	DIAG_FORCE		30
+#define	DIAG_TRANS_OK		31
+#define	DIAG_FAILED		32
+#define	DIAG_WAS_ENABLED	33
+#define	DIAG_WAS_DISABLED	34
+#define	DIAG_WILL_ENABLE	35
+#define	DIAG_WILL_DISABLE	36
+#define	HELP_HEADER		37
+#define	HELP_QUIESCE		38
+#define	HELP_INSERT		39
+#define	HELP_REMOVE		40
+#define	HELP_SET_COND		41
+#define	HELP_ENABLE		42
+#define	HELP_DISABLE		43
+#define	HELP_UNKNOWN		44
+#define	ASK_CONNECT		45
+#define	STR_BD			46
+#define	STR_COL			47
+#define	COND_UNKNOWN		48
+#define	COND_OK			49
+#define	COND_FAILING		50
+#define	COND_FAILED		51
+#define	COND_UNUSABLE		52
+#define	SYSC_COOLING		53
+#define	SYSC_POWER		54
+#define	SYSC_PRECHARGE		55
+#define	SYSC_INTRANS		56
+#define	SYSC_UTHREAD		57
+#define	SYSC_KTHREAD		58
+#define	SYSC_DEV_ATTACH		59
+#define	SYSC_DEV_DETACH		60
+#define	SYSC_NDI_ATTACH		61
+#define	SYSC_NDI_DETACH		62
+#define	SYSC_CORE_RESOURCE	63
+#define	SYSC_OSTATE		64
+#define	SYSC_RSTATE		65
+#define	SYSC_COND		66
+#define	SYSC_PROM		67
+#define	SYSC_NOMEM		68
+#define	SYSC_HOTPLUG		69
+#define	SYSC_HW_COMPAT		70
+#define	SYSC_NON_DR_PROM	71
+#define	SYSC_SUSPEND		72
+#define	SYSC_RESUME		73
+#define	SYSC_UNKNOWN		74
+#define	SYSC_DEVSTR		75
+
+/*
+ * The string table contains all the strings used by the platform
+ * library.  The comment next to each string specifies whether the
+ * string should be internationalized (y) or not (n).
+ * Note that there are calls to dgettext() with strings other than
+ * the ones below, they are marked by the li18 symbol.
+ */
+static char *
+cfga_strs[] = {
+	/*   */ NULL,
+	/* n */ "cpu/mem   ",
+	/* n */ "mem       ",
+	/* n */ "dual-sbus ",
+	/* n */ "sbus-upa  ",
+	/* n */ "dual-pci  ",
+	/* n */ "disk      ",
+	/* n */ "soc+sbus  ",
+	/* n */ "soc+upa   ",
+	/* n */ "unknown   ",
+	/* n */ "get-status",
+	/* n */ "list",
+	/* n */ "connect",
+	/* n */ "disconnect",
+	/* n */ "configure",
+	/* n */ "unconfigure",
+	/* n */ "quiesce-test",
+	/* n */ "insert-test",
+	/* n */ "remove-test",
+	/* n */ "set-condition-test",
+	/* n */ "enable-at-boot",
+	/* n */ "disable-at-boot",
+	/* n */ "prom open",
+	/* n */ "prom getprop",
+	/* n */ "prom setprop",
+	/* y */ "invalid transition",
+	/* y */ "invalid command: ",
+	/* y */ "invalid option: ",
+	/* y */ "invalid attachment point: ",
+	/* y */ "board is disabled: must override with ",
+	/* n */ "[-f][-o enable-at-boot]",
+	/* y */ "transition succeeded but ",
+	/* y */ " failed: ",
+	/* y */ "was already enabled at boot time",
+	/* y */ "was already disabled at boot time",
+	/* y */ "will be enabled at boot time",
+	/* y */ "will be disabled at boot time",
+	/* y */ "\nSysctrl specific commands/options:",
+	/* n */ "\t-x quiesce-test ap_id [ap_id...]",
+	/* n */ "\t-x insert-test  ap_id [ap_id...]",
+	/* n */ "\t-x remove-test  ap_id [ap_id...]",
+	/* n */ "\t-x set-condition-test=<condition>",
+	/* n */ "\t-o enable-at-boot",
+	/* n */ "\t-o disable-at-boot",
+	/* y */ "\tunknown command or option: ",
+	/* y */
+	"system will be temporarily suspended to connect a board: proceed",
+	/* y */ "board ",
+	/* y */ ": ",
+	/* n */ "unknown",
+	/* n */ "ok",
+	/* n */ "failing",
+	/* n */ "failed",
+	/* n */ "unusable",
+	/* y */ "not enough cooling for a new board",
+	/* y */ "not enough power for a new board",
+	/* y */ "not enough precharge power for a new board",
+	/* y */ "configuration operation already in progress on this board",
+	/* y */ "could not suspend user process: ",
+	/* y */ "could not suspend system processes",
+	/* y */ "device did not attach",
+	/* y */ "device did not detach",
+	/* y */ "nexus error during attach",
+	/* y */ "nexus error during detach",
+	/* y */ "attempt to remove core system resource",
+	/* y */ "invalid occupant state",
+	/* y */ "invalid receptacle state",
+	/* y */ "insufficient condition",
+	/* y */ "firmware operation error",
+	/* y */ "not enough memory",
+	/* y */ "hotplug feature unavailable on this machine",
+	/* y */ "board does not support dynamic reconfiguration",
+	/* y */ "firmware does not support dynamic reconfiguration",
+	/* y */ "system suspend error",
+	/* y */ "system resume error",
+	/* y */ "unknown system error",
+	/*   */ NULL
+};
+
+#define	cfga_str(i)		cfga_strs[(i)]
+
+#define	cfga_eid(a, b)		(((a) << 8) + (b))
+
+/*
+ *
+ *	Translation table for mapping from an <errno,sysc_err>
+ *	pair to an error string.
+ *
+ *
+ *	SYSC_COOLING,		EAGAIN,  SYSC_ERR_COOLING
+ *	SYSC_POWER,		EAGAIN,  SYSC_ERR_POWER
+ *	SYSC_PRECHARGE,		EAGAIN,  SYSC_ERR_PRECHARGE
+ *	SYSC_INTRANS,		EBUSY,   SYSC_ERR_INTRANS
+ *	SYSC_KTHREAD,		EBUSY,   SYSC_ERR_KTHREAD
+ *	SYSC_DEV_ATTACH,	EBUSY,   SYSC_ERR_NDI_ATTACH
+ *	SYSC_DEV_DETACH,	EBUSY,   SYSC_ERR_NDI_DETACH
+ *	SYSC_NDI_ATTACH,	EFAULT,  SYSC_ERR_NDI_ATTACH
+ *	SYSC_NDI_DETACH,	EFAULT,  SYSC_ERR_NDI_DETACH
+ *	SYSC_CORE_RESOURCE,	EINVAL,  SYSC_ERR_CORE_RESOURCE
+ *	SYSC_OSTATE,		EINVAL,  SYSC_ERR_OSTATE
+ *	SYSC_RSTATE,		EINVAL,  SYSC_ERR_RSTATE
+ *	SYSC_COND,		EINVAL,  SYSC_ERR_COND
+ *	SYSC_PROM,		EIO,     SYSC_ERR_PROM
+ *	SYSC_NOMEM,		ENOMEM,  SYSC_ERR_DR_INIT
+ *	SYSC_NOMEM,		ENOMEM,  SYSC_ERR_NDI_ATTACH
+ *	SYSC_NOMEM,		ENOMEM,  SYSC_ERR_NDI_DETACH
+ *	SYSC_HOTPLUG,		ENOTSUP, SYSC_ERR_HOTPLUG
+ *	SYSC_HW_COMPAT,		ENOTSUP, SYSC_ERR_HW_COMPAT
+ *	SYSC_NON_DR_PROM,	ENOTSUP, SYSC_ERR_NON_DR_PROM
+ *	SYSC_SUSPEND,		ENXIO,   SYSC_ERR_SUSPEND
+ *	SYSC_RESUME,		ENXIO,   SYSC_ERR_RESUME
+ *	SYSC_UTHREAD,		ESRCH,   SYSC_ERR_UTHREAD
+ */
+static int
+cfga_sid(int err, int scerr)
+{
+	if (scerr == SYSC_ERR_DEFAULT)
+		return (SYSC_UNKNOWN);
+
+	switch (cfga_eid(err, scerr)) {
+	case cfga_eid(EAGAIN, SYSC_ERR_COOLING):
+		return (SYSC_COOLING);
+	case cfga_eid(EAGAIN, SYSC_ERR_POWER):
+		return (SYSC_POWER);
+	case cfga_eid(EAGAIN, SYSC_ERR_PRECHARGE):
+		return (SYSC_PRECHARGE);
+	case cfga_eid(EBUSY, SYSC_ERR_INTRANS):
+		return (SYSC_INTRANS);
+	case cfga_eid(EBUSY, SYSC_ERR_KTHREAD):
+		return (SYSC_KTHREAD);
+	case cfga_eid(EBUSY, SYSC_ERR_NDI_ATTACH):
+		return (SYSC_DEV_ATTACH);
+	case cfga_eid(EBUSY, SYSC_ERR_NDI_DETACH):
+		return (SYSC_DEV_DETACH);
+	case cfga_eid(EFAULT, SYSC_ERR_NDI_ATTACH):
+		return (SYSC_NDI_ATTACH);
+	case cfga_eid(EFAULT, SYSC_ERR_NDI_DETACH):
+		return (SYSC_NDI_DETACH);
+	case cfga_eid(EINVAL, SYSC_ERR_CORE_RESOURCE):
+		return (SYSC_CORE_RESOURCE);
+	case cfga_eid(EINVAL, SYSC_ERR_OSTATE):
+		return (SYSC_OSTATE);
+	case cfga_eid(EINVAL, SYSC_ERR_RSTATE):
+		return (SYSC_RSTATE);
+	case cfga_eid(EINVAL, SYSC_ERR_COND):
+		return (SYSC_COND);
+	case cfga_eid(EIO, SYSC_ERR_PROM):
+		return (SYSC_PROM);
+	case cfga_eid(ENOMEM, SYSC_ERR_DR_INIT):
+		return (SYSC_NOMEM);
+	case cfga_eid(ENOMEM, SYSC_ERR_NDI_ATTACH):
+		return (SYSC_NOMEM);
+	case cfga_eid(ENOMEM, SYSC_ERR_NDI_DETACH):
+		return (SYSC_NOMEM);
+	case cfga_eid(ENOTSUP, SYSC_ERR_HOTPLUG):
+		return (SYSC_HOTPLUG);
+	case cfga_eid(ENOTSUP, SYSC_ERR_HW_COMPAT):
+		return (SYSC_HW_COMPAT);
+	case cfga_eid(ENOTSUP, SYSC_ERR_NON_DR_PROM):
+		return (SYSC_NON_DR_PROM);
+	case cfga_eid(ENXIO, SYSC_ERR_SUSPEND):
+		return (SYSC_SUSPEND);
+	case cfga_eid(ENXIO, SYSC_ERR_RESUME):
+		return (SYSC_RESUME);
+	case cfga_eid(ESRCH, SYSC_ERR_UTHREAD):
+		return (SYSC_UTHREAD);
+	default:
+		break;
+	}
+
+	return (SYSC_UNKNOWN);
+}
+
+static void
+sysc_cmd_init(sysc_cfga_cmd_t *sc, char *outputstr, int force)
+{
+	sc->force = force;
+	sc->outputstr = outputstr;
+	sc->errtype = SYSC_ERR_DEFAULT;
+
+	(void) memset((void *)outputstr, 0, sizeof (outputstr));
+
+	cfga_str(SYSC_DEVSTR) = outputstr;
+}
+
+/*
+ * 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 dgettext() to internationalize proper messages.
+ */
+static void
+cfga_err(sysc_cfga_cmd_t *sc, char **errstring, ...)
+{
+	int a;
+	int i;
+	int n;
+	int len;
+	int flen;
+	char *p;
+	char *q;
+	char *s[32];
+	char *failed;
+	va_list ap;
+	char syserr_num[20];
+
+	/*
+	 * If errstring is null it means user in 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_str(DIAG_FAILED));
+	flen = strlen(failed);
+
+	for (n = len = 0; (a = va_arg(ap, int)) != 0; n++) {
+
+		switch (a) {
+		case ERR_PROM_OPEN:
+		case ERR_PROM_GETPROP:
+		case ERR_PROM_SETPROP:
+		case CMD_GETSTAT:
+		case CMD_LIST:
+		case CMD_CONNECT:
+		case CMD_DISCONNECT:
+		case CMD_CONFIGURE:
+		case CMD_UNCONFIGURE:
+		case CMD_QUIESCE:
+		case CMD_INSERT:
+		case CMD_REMOVE:
+		case CMD_SET_COND:
+			p =  cfga_str(a);
+			len += (strlen(p) + flen);
+			s[n] = p;
+			s[++n] = failed;
+
+			DBG("<%s>", p);
+			DBG("<%s>", failed);
+			break;
+
+		case OPT_ENABLE:
+		case OPT_DISABLE:
+			p = dgettext(TEXT_DOMAIN, cfga_str(DIAG_TRANS_OK));
+			q = cfga_str(a);
+			len += (strlen(p) + strlen(q) + flen);
+			s[n] = p;
+			s[++n] = q;
+			s[++n] = failed;
+
+			DBG("<%s>", p);
+			DBG("<%s>", q);
+			DBG("<%s>", failed);
+			break;
+
+		case ERR_CMD_INVAL:
+		case ERR_AP_INVAL:
+		case ERR_OPT_INVAL:
+			p =  dgettext(TEXT_DOMAIN, cfga_str(a));
+			q = va_arg(ap, char *);
+			len += (strlen(p) + strlen(q));
+			s[n] = p;
+			s[++n] = q;
+
+			DBG("<%s>", p);
+			DBG("<%s>", q);
+			break;
+
+		case ERR_TRANS:
+		case ERR_DISABLED:
+			p =  dgettext(TEXT_DOMAIN, cfga_str(a));
+			len += strlen(p);
+			s[n] = p;
+
+			DBG("<%s>", p);
+			break;
+
+		case DIAG_FORCE:
+		default:
+			p =  cfga_str(a);
+			len += strlen(p);
+			s[n] = p;
+
+			DBG("<%s>", p);
+			break;
+		}
+	}
+
+	DBG1("\n");
+	va_end(ap);
+
+	if (errno) {
+		if (sc)
+			i = cfga_sid(errno, (int)sc->errtype);
+		else
+			i = SYSC_UNKNOWN;
+
+		DBG4("cfga_sid(%d,%d)=%d\n", errno, sc->errtype, i);
+
+		if (i == SYSC_UNKNOWN) {
+			p = strerror(errno);
+			if (p == NULL) {
+				(void) sprintf(syserr_num, "errno=%d", errno);
+				p = syserr_num;
+			}
+		} else
+			p = dgettext(TEXT_DOMAIN, cfga_str(i));
+
+		len += strlen(p);
+		s[n++] = p;
+		p = cfga_str(SYSC_DEVSTR);
+		if (p && p[0]) {
+			q = cfga_str(STR_COL);
+
+			len += strlen(q);
+			s[n++] = q;
+			len += strlen(p);
+			s[n++] = p;
+		}
+	}
+
+	if ((p = (char *)calloc(len, 1)) == NULL)
+		return;
+
+	for (i = 0; i < n; i++)
+		(void) strcat(p, s[i]);
+
+	*errstring = p;
+#ifdef	SIM_MSG
+	printf("%s\n", *errstring);
+#endif
+}
+
+/*
+ * This routine accepts a variable number of message IDs and constructs
+ * a corresponding error string which is printed via the message print routine
+ * argument.  The HELP_UNKNOWN message ID has an argument string (the unknown
+ * help topic) that follows.
+ */
+static void
+cfga_msg(struct cfga_msg *msgp, ...)
+{
+	int a;
+	int i;
+	int n;
+	int len;
+	char *p;
+	char *s[32];
+	va_list ap;
+
+	va_start(ap, msgp);
+
+	for (n = len = 0; (a = va_arg(ap, int)) != 0; n++) {
+		DBG("<%d>", a);
+		p =  dgettext(TEXT_DOMAIN, cfga_str(a));
+		len += strlen(p);
+		s[n] = p;
+		if (a == HELP_UNKNOWN) {
+			p = va_arg(ap, char *);
+			len += strlen(p);
+			s[++n] = p;
+		}
+	}
+
+	va_end(ap);
+
+	if ((p = (char *)calloc(len + 1, 1)) == NULL)
+		return;
+
+	for (i = 0; i < n; i++)
+		(void) strcat(p, s[i]);
+	(void) strcat(p, "\n");
+
+#ifdef	SIM_MSG
+	printf("%s", p);
+#else
+	(*msgp->message_routine)(msgp->appdata_ptr, p);
+#endif
+	free(p);
+}
+
+static sysc_cfga_stat_t *
+sysc_stat(const char *ap_id, int *fdp)
+{
+	int fd;
+	static sysc_cfga_stat_t sc_list[MAX_BOARDS];
+
+
+	if ((fd = open(ap_id, O_RDWR, 0)) == -1)
+		return (NULL);
+	else if (ioctl(fd, SYSC_CFGA_CMD_GETSTATUS, sc_list) == -1) {
+		(void) close(fd);
+		return (NULL);
+	} else if (fdp)
+		*fdp = fd;
+	else
+		(void) close(fd);
+
+	return (sc_list);
+}
+
+/*
+ * This code implementes the simulation of the ioctls that transition state.
+ * The GETSTAT ioctl is not simulated.  In this way a snapshot of the system
+ * state is read and manipulated by the simulation routines.  It is basically
+ * a useful debugging tool.
+ */
+#ifdef	SIM
+static int sim_idx;
+static int sim_fd = -1;
+static int sim_size = MAX_BOARDS * sizeof (sysc_cfga_stat_t);
+static sysc_cfga_stat_t sim_sc_list[MAX_BOARDS];
+
+static sysc_cfga_stat_t *
+sim_sysc_stat(const char *ap_id, int *fdp)
+{
+	int fd;
+	struct stat buf;
+
+	if (sim_fd != -1)
+		return (sim_sc_list);
+
+	if ((sim_fd = open("/tmp/cfga_simdata", O_RDWR|O_CREAT)) == -1) {
+		perror("sim_open");
+		exit(1);
+	} else if (fstat(sim_fd, &buf) == -1) {
+		perror("sim_stat");
+		exit(1);
+	}
+
+	if (buf.st_size) {
+		if (buf.st_size != sim_size) {
+			perror("sim_size");
+			exit(1);
+		} else if (read(sim_fd, sim_sc_list, sim_size) == -1) {
+			perror("sim_read");
+			exit(1);
+		}
+	} else if ((fd = open(ap_id, O_RDWR, 0)) == -1)
+		return (NULL);
+	else if (ioctl(fd, SYSC_CFGA_CMD_GETSTATUS, sim_sc_list) == -1) {
+		(void) close(fd);
+		return (NULL);
+	} else if (fdp)
+		*fdp = fd;
+
+	return (sim_sc_list);
+}
+
+static int
+sim_open(char *a, int b, int c)
+{
+	printf("sim_open(%s)\n", a);
+
+	if (strcmp(a, "/dev/openprom") == 0)
+		return (open(a, b, c));
+	return (0);
+}
+
+static int
+sim_close(int a) { return (0); }
+
+static int
+sim_ioctl(int fd, int cmd, void *a)
+{
+	printf("sim_ioctl(%d)\n", sim_idx);
+
+	switch (cmd) {
+	case SYSC_CFGA_CMD_CONNECT:
+		sim_sc_list[sim_idx].rstate = SYSC_CFGA_RSTATE_CONNECTED;
+		break;
+	case SYSC_CFGA_CMD_CONFIGURE:
+		sim_sc_list[sim_idx].ostate = SYSC_CFGA_OSTATE_CONFIGURED;
+		break;
+	case SYSC_CFGA_CMD_UNCONFIGURE:
+		sim_sc_list[sim_idx].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
+		break;
+	case SYSC_CFGA_CMD_DISCONNECT:
+		sim_sc_list[sim_idx].rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
+		break;
+	case SYSC_CFGA_CMD_QUIESCE_TEST:
+	case SYSC_CFGA_CMD_TEST:
+		return (0);
+	case OPROMGETOPT:
+		return (ioctl(fd, OPROMGETOPT, a));
+	case OPROMSETOPT:
+		return (ioctl(fd, OPROMSETOPT, a));
+	}
+
+	if (lseek(sim_fd, SEEK_SET, 0) == -1) {
+		perror("sim_seek");
+		exit(1);
+	}
+	if (write(sim_fd, sim_sc_list, sim_size) == -1) {
+		perror("sim_write");
+		exit(1);
+	}
+
+	return (0);
+}
+
+#define	open(a, b, c)	sim_open((char *)(a), (int)(b), (int)(c))
+#define	close(a)	sim_close(a)
+#define	ioctl(a, b, c)	sim_ioctl((int)(a), (int)(b), (void *)(c))
+#define	sysc_stat(a, b)	sim_sysc_stat(a, b)
+#endif	/* SIM */
+
+static char *promdev = "/dev/openprom";
+static char *dlprop = "disabled-board-list";
+
+#define	BUFSIZE		128
+
+typedef union {
+	char buf[BUFSIZE];
+	struct openpromio opp;
+} oppbuf_t;
+
+static int
+prom_get_prop(int prom_fd, char *var, char **val)
+{
+	static oppbuf_t oppbuf;
+	struct openpromio *opp = &(oppbuf.opp);
+
+	(void) strncpy(opp->oprom_array, var, OBP_MAXPROPNAME);
+	opp->oprom_array[OBP_MAXPROPNAME + 1] = '\0';
+	opp->oprom_size = BUFSIZE;
+
+	DBG3("getprop(%s, %d)\n", opp->oprom_array, opp->oprom_size);
+
+	if (ioctl(prom_fd, OPROMGETOPT, opp) < 0)
+		return (ERR_PROM_GETPROP);
+	else if (opp->oprom_size > 0)
+		*val = opp->oprom_array;
+	else
+		*val = NULL;
+
+	return (0);
+}
+
+static cfga_err_t
+prom_set_prop(int prom_fd, char *var, char *val)
+{
+	oppbuf_t oppbuf;
+	struct openpromio *opp = &(oppbuf.opp);
+	int varlen = strlen(var) + 1;
+	int vallen = strlen(val);
+
+	DBG("prom_set_prop(%s)\n", val);
+
+	(void) strcpy(opp->oprom_array, var);
+	(void) strcpy(opp->oprom_array + varlen, val);
+	opp->oprom_size = varlen + vallen;
+
+	if (ioctl(prom_fd, OPROMSETOPT, opp) < 0)
+		return (ERR_PROM_SETPROP);
+
+	return (0);
+}
+
+static int
+dlist_find(int board, char **dlist, int *disabled)
+{
+	int i;
+	int err;
+	int prom_fd;
+	char *p;
+	char *dl;
+	char b[2];
+
+	if ((prom_fd = open(promdev, O_RDWR, 0)) < 0)
+		return (ERR_PROM_OPEN);
+	else if (err = prom_get_prop(prom_fd, dlprop, dlist)) {
+		(void) close(prom_fd);
+		return (err);
+	} else
+		(void) close(prom_fd);
+
+	b[1] = 0;
+	*disabled = 0;
+
+	if ((dl = *dlist) != NULL) {
+		int len = strlen(dl);
+
+		for (i = 0; i < len; i++) {
+			int bd;
+
+			b[0] = dl[i];
+			bd = strtol(b, &p, 16);
+
+			if (p != b && bd == board)
+				(*disabled)++;
+		}
+	}
+
+	return (0);
+}
+
+static int
+dlist_update(int board, int disable, char *dlist, struct cfga_msg *msgp,
+	int verbose)
+{
+	int i, j, n;
+	int err;
+	int found;
+	int update;
+	int prom_fd;
+	char *p;
+	char b[2];
+	char ndlist[64];
+
+	b[1] = 0;
+	ndlist[0] = 0;
+	j = 0;
+	found = 0;
+	update = 0;
+
+	if ((prom_fd = open(promdev, O_RDWR, 0)) < 0)
+		return (ERR_PROM_OPEN);
+
+	if (dlist) {
+		int len = strlen(dlist);
+
+		for (i = 0; i < len; i++) {
+			int bd;
+
+			b[0] = dlist[i];
+			bd = strtol(b, &p, 16);
+
+			if (p != b && bd == board) {
+
+				found++;
+				if (disable) {
+					if (verbose)
+						cfga_msg(msgp, STR_BD,
+						    DIAG_WAS_DISABLED, 0);
+				} else {
+					if (verbose)
+						cfga_msg(msgp, STR_BD,
+						    DIAG_WILL_ENABLE, 0);
+					update++;
+					continue;
+				}
+			}
+			ndlist[j++] = dlist[i];
+		}
+		ndlist[j] = 0;
+	}
+
+	if (!found)
+		if (disable) {
+			if (verbose)
+				cfga_msg(msgp, STR_BD, DIAG_WILL_DISABLE, 0);
+			p = &ndlist[j];
+			n = sprintf(p, "%x", board);
+			p[n] = 0;
+			update++;
+		} else {
+			if (verbose)
+				cfga_msg(msgp, STR_BD, DIAG_WAS_ENABLED, 0);
+		}
+
+	if (update)
+		err = prom_set_prop(prom_fd, dlprop, ndlist);
+	else
+		err = 0;
+
+	(void) close(prom_fd);
+
+	return (err);
+}
+
+static int
+ap_idx(const char *ap_id)
+{
+	int id;
+	char *s;
+	static char *slot = "slot";
+
+	DBG("ap_idx(%s)\n", ap_id);
+
+	if ((s = strstr(ap_id, slot)) == NULL)
+		return (-1);
+	else {
+		int n;
+
+		s += strlen(slot);
+		n = strlen(s);
+
+		DBG3("ap_idx: s=%s, n=%d\n", s, n);
+
+		switch (n) {
+		case 2:
+			if (!isdigit(s[1]))
+				return (-1);
+		/* FALLTHROUGH */
+		case 1:
+			if (!isdigit(s[0]))
+				return (-1);
+			break;
+		default:
+			return (-1);
+		}
+	}
+
+	if ((id = atoi(s)) > MAX_BOARDS)
+		return (-1);
+
+	DBG3("ap_idx(%s)=%d\n", s, id);
+
+	return (id);
+}
+
+/*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 fd;
+	int idx;
+	int err;
+	int force;
+	int verbose;
+	int opterr;
+	int disable;
+	int disabled;
+	cfga_err_t rc;
+	sysc_cfga_stat_t *ss;
+	sysc_cfga_cmd_t *sc, sysc_cmd;
+	sysc_cfga_rstate_t rs;
+	sysc_cfga_ostate_t os;
+	char *dlist;
+	char outputstr[SYSC_OUTPUT_LEN];
+
+	if (errstring != NULL)
+		*errstring = NULL;
+
+	rc = CFGA_ERROR;
+
+	if (options) {
+		disable = 0;
+		if (strcmp(options, cfga_str(OPT_DISABLE)) == 0)
+			disable++;
+		else if (strcmp(options, cfga_str(OPT_ENABLE))) {
+			cfga_err(NULL, errstring, ERR_OPT_INVAL, options, 0);
+			return (rc);
+		}
+	}
+
+	if ((idx = ap_idx(ap_id)) == -1) {
+		cfga_err(NULL, errstring, ERR_AP_INVAL, ap_id, 0);
+		return (rc);
+	} else if ((ss = sysc_stat(ap_id, &fd)) == NULL) {
+		cfga_err(NULL, errstring, CMD_GETSTAT, 0);
+		return (rc);
+	}
+#ifdef	SIM
+	sim_idx = idx;
+#endif
+	/*
+	 * We disallow connecting on the disabled list unless
+	 * either the FORCE flag or the enable-at-boot option
+	 * is set. The check is made further below
+	 */
+	if (opterr = dlist_find(idx, &dlist, &disabled)) {
+		err = disable ? OPT_DISABLE : OPT_ENABLE;
+		cfga_err(NULL, errstring, err, opterr, 0);
+		(void) close(fd);
+		return (rc);
+	} else
+		force = flags & CFGA_FLAG_FORCE;
+
+	rs = ss[idx].rstate;
+	os = ss[idx].ostate;
+
+	sc = &sysc_cmd;
+	sysc_cmd_init(sc, outputstr, force);
+	verbose = flags & CFGA_FLAG_VERBOSE;
+
+	switch (state_change_cmd) {
+	case CFGA_CMD_CONNECT:
+		if (rs != SYSC_CFGA_RSTATE_DISCONNECTED)
+			cfga_err(NULL, errstring, ERR_TRANS, 0);
+		else if (disabled && !(force || (options && !disable)))
+			cfga_err(NULL, errstring, CMD_CONNECT,
+				ERR_DISABLED, DIAG_FORCE, 0);
+		else if (!(*confp->confirm)(confp->appdata_ptr,
+		    cfga_str(ASK_CONNECT))) {
+			(void) close(fd);
+			return (CFGA_NACK);
+		} else if (ioctl(fd, SYSC_CFGA_CMD_CONNECT, sc) == -1)
+			cfga_err(sc, errstring, CMD_CONNECT, 0);
+		else if (options && (opterr = dlist_update(idx, disable,
+			dlist, msgp, verbose))) {
+			err = disable ? OPT_DISABLE : OPT_ENABLE;
+			cfga_err(NULL, errstring, err, opterr, 0);
+		} else
+			rc = CFGA_OK;
+		break;
+
+	case CFGA_CMD_DISCONNECT:
+		if ((os == SYSC_CFGA_OSTATE_CONFIGURED) &&
+		    (ioctl(fd, SYSC_CFGA_CMD_UNCONFIGURE, sc) == -1)) {
+			cfga_err(sc, errstring, CMD_UNCONFIGURE, 0);
+			(void) close(fd);
+			return (CFGA_ERROR);
+		} else
+			sysc_cmd_init(sc, outputstr, force);
+
+		if (rs == SYSC_CFGA_RSTATE_CONNECTED) {
+			if (ioctl(fd, SYSC_CFGA_CMD_DISCONNECT, sc) == -1)
+				cfga_err(sc, errstring, CMD_DISCONNECT, 0);
+			else if (options && (opterr = dlist_update(idx, disable,
+			    dlist, msgp, verbose))) {
+				err = disable ? OPT_DISABLE : OPT_ENABLE;
+				cfga_err(NULL, errstring, err, opterr, 0);
+			} else
+				rc = CFGA_OK;
+		} else
+			cfga_err(NULL, errstring, ERR_TRANS, 0);
+		break;
+
+	case CFGA_CMD_CONFIGURE:
+		if (rs == SYSC_CFGA_RSTATE_DISCONNECTED)
+			if (disabled && !(force || (options && !disable))) {
+				cfga_err(NULL, errstring, CMD_CONFIGURE,
+					ERR_DISABLED, DIAG_FORCE, 0);
+				(void) close(fd);
+				return (CFGA_ERROR);
+			} else if (!(*confp->confirm)(confp->appdata_ptr,
+			    cfga_str(ASK_CONNECT))) {
+				(void) close(fd);
+				return (CFGA_NACK);
+			} else if (ioctl(fd, SYSC_CFGA_CMD_CONNECT, sc) == -1) {
+				cfga_err(sc, errstring, CMD_CONNECT, 0);
+				(void) close(fd);
+				return (CFGA_ERROR);
+			} else
+				sysc_cmd_init(sc, outputstr, force);
+
+		if (os == SYSC_CFGA_OSTATE_UNCONFIGURED) {
+			if (ioctl(fd, SYSC_CFGA_CMD_CONFIGURE, sc) == -1)
+				cfga_err(sc, errstring, CMD_CONFIGURE, 0);
+			else if (options && (opterr = dlist_update(idx,
+				disable, dlist, msgp, verbose))) {
+				err = disable ? OPT_DISABLE : OPT_ENABLE;
+				cfga_err(NULL, errstring, err, opterr, 0);
+			} else
+				rc = CFGA_OK;
+		} else
+			cfga_err(NULL, errstring, ERR_TRANS, 0);
+		break;
+
+	case CFGA_CMD_UNCONFIGURE:
+		if (os != SYSC_CFGA_OSTATE_CONFIGURED)
+			cfga_err(NULL, errstring, ERR_TRANS, 0);
+		else if (ioctl(fd, SYSC_CFGA_CMD_UNCONFIGURE, sc) == -1)
+			cfga_err(sc, errstring, CMD_UNCONFIGURE, 0);
+		else if (options && (opterr = dlist_update(idx, disable,
+			dlist, msgp, verbose))) {
+			err = disable ? OPT_DISABLE : OPT_ENABLE;
+			cfga_err(NULL, errstring, err, opterr, 0);
+		} else
+			rc = CFGA_OK;
+		break;
+
+	default:
+		rc = CFGA_OPNOTSUPP;
+		break;
+	}
+
+	(void) close(fd);
+	return (rc);
+}
+
+static int
+str2cond(const char *cond)
+{
+	int c;
+
+	if (strcmp(cond, cfga_str(COND_UNKNOWN)) == 0)
+		c =  SYSC_CFGA_COND_UNKNOWN;
+	else if (strcmp(cond, cfga_str(COND_OK)) == 0)
+		c =  SYSC_CFGA_COND_OK;
+	else if (strcmp(cond, cfga_str(COND_FAILING)) == 0)
+		c =  SYSC_CFGA_COND_FAILING;
+	else if (strcmp(cond, cfga_str(COND_FAILED)) == 0)
+		c =  SYSC_CFGA_COND_FAILED;
+	else if (strcmp(cond, cfga_str(COND_UNUSABLE)) == 0)
+		c =  SYSC_CFGA_COND_UNUSABLE;
+	else
+		c = -1;
+
+	return (c);
+}
+
+/*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)
+{
+	int fd;
+	int idx;
+	int len;
+	int cmd;
+	int cond;
+	int err;
+	int opterr;
+	int verbose;
+	int disable;
+	int disabled;
+	cfga_err_t rc;
+	char *str;
+	char *dlist;
+	char outputstr[SYSC_OUTPUT_LEN];
+	sysc_cfga_cmd_t *sc, sysc_cmd;
+
+	if (errstring != NULL)
+		*errstring = NULL;
+
+	verbose = flags & CFGA_FLAG_VERBOSE;
+
+	rc = CFGA_ERROR;
+
+	if (options) {
+		disable = 0;
+		if (strcmp(options, cfga_str(OPT_DISABLE)) == 0)
+			disable++;
+		else if (strcmp(options, cfga_str(OPT_ENABLE))) {
+			cfga_err(NULL, errstring, ERR_OPT_INVAL, options, 0);
+			return (rc);
+		}
+	}
+
+	sc = &sysc_cmd;
+	str = cfga_str(CMD_SET_COND);
+	len = strlen(str);
+
+	if ((strncmp(function, str, len) == 0) && (function[len++] == '=') &&
+	    ((cond = (str2cond(&function[len]))) != -1)) {
+		cmd = SYSC_CFGA_CMD_TEST_SET_COND;
+		err = CMD_SET_COND;
+		sc->arg = cond;
+	} else if (strcmp(function, cfga_str(CMD_QUIESCE)) == 0) {
+		cmd = SYSC_CFGA_CMD_QUIESCE_TEST;
+		err = CMD_QUIESCE;
+	} else if (strcmp(function, cfga_str(CMD_INSERT)) == 0) {
+		cmd = SYSC_CFGA_CMD_TEST;
+		err = CMD_INSERT;
+	} else if (strcmp(function, cfga_str(CMD_REMOVE)) == 0) {
+		cmd = SYSC_CFGA_CMD_TEST;
+		err = CMD_REMOVE;
+	} else {
+		cfga_err(NULL, errstring, ERR_CMD_INVAL, (char *)function, 0);
+		return (rc);
+	}
+
+	sysc_cmd_init(sc, outputstr, 0);
+
+	if ((idx = ap_idx(ap_id)) == -1)
+		cfga_err(NULL, errstring, ERR_AP_INVAL, ap_id, 0);
+	else if (((fd = open(ap_id, O_RDWR, 0)) == -1) ||
+		(ioctl(fd, cmd, sc) == -1))
+		cfga_err(NULL, errstring, err, 0);
+	else
+		rc = CFGA_OK;
+
+	if (options) {
+		opterr = (dlist_find(idx, &dlist, &disabled) ||
+			dlist_update(idx, disable, dlist, msgp, verbose));
+		if (opterr) {
+			err = disable ? OPT_DISABLE : OPT_ENABLE;
+			if (verbose)
+				cfga_msg(msgp, err, opterr, 0);
+		}
+	}
+
+	(void) close(fd);
+	return (rc);
+}
+
+
+/*ARGSUSED*/
+cfga_err_t
+cfga_test(
+	const char *ap_id,
+	const char *options,
+	struct cfga_msg *msgp,
+	char **errstring,
+	cfga_flags_t flags)
+{
+	if (errstring != NULL)
+		*errstring = NULL;
+
+	return (CFGA_OPNOTSUPP);
+}
+
+static cfga_stat_t
+rstate_cvt(sysc_cfga_rstate_t rs)
+{
+	cfga_stat_t cs;
+
+	switch (rs) {
+	case SYSC_CFGA_RSTATE_EMPTY:
+		cs = CFGA_STAT_EMPTY;
+		break;
+	case SYSC_CFGA_RSTATE_DISCONNECTED:
+		cs = CFGA_STAT_DISCONNECTED;
+		break;
+	case SYSC_CFGA_RSTATE_CONNECTED:
+		cs = CFGA_STAT_CONNECTED;
+		break;
+	default:
+		cs = CFGA_STAT_NONE;
+		break;
+	}
+
+	return (cs);
+}
+
+static cfga_stat_t
+ostate_cvt(sysc_cfga_ostate_t os)
+{
+	cfga_stat_t cs;
+
+	switch (os) {
+	case SYSC_CFGA_OSTATE_UNCONFIGURED:
+		cs = CFGA_STAT_UNCONFIGURED;
+		break;
+	case SYSC_CFGA_OSTATE_CONFIGURED:
+		cs = CFGA_STAT_CONFIGURED;
+		break;
+	default:
+		cs = CFGA_STAT_NONE;
+		break;
+	}
+
+	return (cs);
+}
+
+static cfga_cond_t
+cond_cvt(sysc_cfga_cond_t sc)
+{
+	cfga_cond_t cc;
+
+	switch (sc) {
+	case SYSC_CFGA_COND_OK:
+		cc = CFGA_COND_OK;
+		break;
+	case SYSC_CFGA_COND_FAILING:
+		cc = CFGA_COND_FAILING;
+		break;
+	case SYSC_CFGA_COND_FAILED:
+		cc = CFGA_COND_FAILED;
+		break;
+	case SYSC_CFGA_COND_UNUSABLE:
+		cc = CFGA_COND_UNUSABLE;
+		break;
+	case SYSC_CFGA_COND_UNKNOWN:
+	default:
+		cc = CFGA_COND_UNKNOWN;
+		break;
+	}
+
+	return (cc);
+}
+
+static char *
+type_str(enum board_type type)
+{
+	char *type_str;
+
+	switch (type) {
+	case MEM_BOARD:
+		type_str = cfga_str(BD_MEM);
+		break;
+	case CPU_BOARD:
+		type_str = cfga_str(BD_CPU);
+		break;
+	case IO_2SBUS_BOARD:
+		type_str = cfga_str(BD_IO_2SBUS);
+		break;
+	case IO_SBUS_FFB_BOARD:
+		type_str = cfga_str(BD_IO_SBUS_FFB);
+		break;
+	case IO_PCI_BOARD:
+		type_str = cfga_str(BD_IO_PCI);
+		break;
+	case DISK_BOARD:
+		type_str = cfga_str(BD_DISK);
+		break;
+	case IO_2SBUS_SOCPLUS_BOARD:
+		type_str = cfga_str(BD_IO_2SBUS_SOCPLUS);
+		break;
+	case IO_SBUS_FFB_SOCPLUS_BOARD:
+		type_str = cfga_str(BD_IO_SBUS_FFB_SOCPLUS);
+		break;
+	case UNKNOWN_BOARD:
+	default:
+		type_str = cfga_str(BD_UNKNOWN);
+		break;
+	}
+	return (type_str);
+}
+
+static void
+info_set(sysc_cfga_stat_t *sc, cfga_info_t info, int disabled)
+{
+	int i;
+	struct cpu_info *cpu;
+	union bd_un *bd = &sc->bd;
+
+	*info = NULL;
+
+	switch (sc->type) {
+	case CPU_BOARD:
+		for (i = 0, cpu = bd->cpu; i < 2; i++, cpu++) {
+			if (cpu->cpu_speed > 1) {
+				info += sprintf(info, "cpu %d: ", i);
+				info += sprintf(info, "%3d MHz ",
+						cpu->cpu_speed);
+				if (cpu->cache_size)
+					info += sprintf(info, "%0.1fM ",
+						(float)cpu->cache_size /
+						(float)(1024 * 1024));
+			}
+		}
+		break;
+	case IO_SBUS_FFB_BOARD:
+		switch (bd->io2.ffb_size) {
+		case FFB_SINGLE:
+			info += sprintf(info, "single buffered ffb   ");
+			break;
+		case FFB_DOUBLE:
+			info += sprintf(info, "double buffered ffb   ");
+			break;
+		case FFB_NOT_FOUND:
+#ifdef FFB_DR_SUPPORT
+			info += sprintf(info, "no ffb installed   ");
+#endif
+			break;
+		default:
+			info += sprintf(info, "illegal ffb size   ");
+			break;
+		}
+		break;
+	case DISK_BOARD:
+		for (i = 0; i < 2; i++)
+			if (bd->dsk.disk_pres[i])
+				info += sprintf(info, "target: %2d ",
+						bd->dsk.disk_id[i]);
+			else
+				info += sprintf(info, "no disk   ");
+		break;
+	}
+
+	if (disabled)
+		info += sprintf(info, "disabled at boot   ");
+
+	if (sc->no_detach)
+		info += sprintf(info, "non-detachable   ");
+
+	if (sc->plus_board)
+		info += sprintf(info, "100 MHz capable   ");
+}
+
+static void
+sysc_cvt(sysc_cfga_stat_t *sc, cfga_stat_data_t *cs, int disabled)
+{
+	(void) strcpy(cs->ap_type, type_str(sc->type));
+	cs->ap_r_state = rstate_cvt(sc->rstate);
+	cs->ap_o_state = ostate_cvt(sc->ostate);
+	cs->ap_cond = cond_cvt(sc->condition);
+	cs->ap_busy = (cfga_busy_t)sc->in_transition;
+	cs->ap_status_time = sc->last_change;
+	info_set(sc, cs->ap_info, disabled);
+	cs->ap_log_id[0] = NULL;
+	cs->ap_phys_id[0] = NULL;
+}
+
+/*ARGSUSED*/
+cfga_err_t
+cfga_list(
+	const char *ap_id,
+	cfga_stat_data_t **ap_list,
+	int *nlist,
+	const char *options,
+	char **errstring)
+{
+	int i;
+	cfga_err_t rc;
+	sysc_cfga_stat_t *sc;
+	cfga_stat_data_t *cs;
+
+	if (errstring != NULL)
+		*errstring = NULL;
+
+	rc = CFGA_ERROR;
+
+	if (ap_idx(ap_id) == -1)
+		cfga_err(NULL, errstring, ERR_AP_INVAL, ap_id, 0);
+	else if ((sc = sysc_stat(ap_id, NULL)) == NULL)
+		cfga_err(NULL, errstring, CMD_LIST, 0);
+	else if (!(cs = (cfga_stat_data_t *)malloc(MAX_BOARDS * sizeof (*cs))))
+		cfga_err(NULL, errstring, CMD_LIST, 0);
+	else {
+		*ap_list = cs;
+
+		for (*nlist = 0, i = 0; i < MAX_BOARDS; i++, sc++) {
+			if (sc->board == -1)
+				continue;
+			sysc_cvt(sc, cs++, 0); /* XXX - disable */
+			(*nlist)++;
+		}
+
+		rc = CFGA_OK;
+	}
+
+	return (rc);
+}
+
+/*ARGSUSED*/
+cfga_err_t
+cfga_stat(
+	const char *ap_id,
+	struct cfga_stat_data *cs,
+	const char *options,
+	char **errstring)
+{
+	cfga_err_t rc;
+	int idx;
+	int err;
+	int opterr;
+	int disable;
+	int disabled;
+	char *dlist;
+	sysc_cfga_stat_t *sc;
+
+	if (errstring != NULL)
+		*errstring = NULL;
+
+	rc = CFGA_ERROR;
+
+	if (options && options[0]) {
+		disable = 0;
+		if (strcmp(options, cfga_str(OPT_DISABLE)) == 0)
+			disable++;
+		else if (strcmp(options, cfga_str(OPT_ENABLE))) {
+			cfga_err(NULL, errstring, ERR_OPT_INVAL, options, 0);
+			return (rc);
+		}
+	}
+
+	if ((idx = ap_idx(ap_id)) == -1)
+		cfga_err(NULL, errstring, ERR_AP_INVAL, ap_id, 0);
+	else if ((sc = sysc_stat(ap_id, NULL)) == NULL)
+		cfga_err(NULL, errstring, CMD_GETSTAT, 0);
+	else {
+		opterr = dlist_find(idx, &dlist, &disabled);
+		sysc_cvt(sc + idx, cs, disabled);
+
+		rc = CFGA_OK;
+
+		if (options && options[0] && ((opterr != 0) ||
+			((opterr = dlist_update(idx, disable, dlist, NULL, 0))
+			!= 0))) {
+				err = disable ? OPT_DISABLE : OPT_ENABLE;
+				cfga_err(NULL, errstring, err, opterr, 0);
+		}
+	}
+
+	return (rc);
+}
+
+/*ARGSUSED*/
+cfga_err_t
+cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
+{
+	int help = 0;
+
+	if (options) {
+		if (strcmp(options, cfga_str(OPT_DISABLE)) == 0)
+			help = HELP_DISABLE;
+		else if (strcmp(options, cfga_str(OPT_ENABLE)) == 0)
+			help = HELP_ENABLE;
+		else if (strcmp(options, cfga_str(CMD_INSERT)) == 0)
+			help = HELP_INSERT;
+		else if (strcmp(options, cfga_str(CMD_REMOVE)) == 0)
+			help = HELP_REMOVE;
+		else if (strcmp(options, cfga_str(CMD_QUIESCE)) == 0)
+			help = HELP_QUIESCE;
+		else
+			help = HELP_UNKNOWN;
+	}
+
+	if (help)  {
+		if (help == HELP_UNKNOWN)
+			cfga_msg(msgp, help, options, 0);
+		else
+			cfga_msg(msgp, help, 0);
+	} else {
+		cfga_msg(msgp, HELP_HEADER, 0);
+		cfga_msg(msgp, HELP_DISABLE, 0);
+		cfga_msg(msgp, HELP_ENABLE, 0);
+		cfga_msg(msgp, HELP_INSERT, 0);
+		cfga_msg(msgp, HELP_REMOVE, 0);
+		cfga_msg(msgp, HELP_QUIESCE, 0);
+		cfga_msg(msgp, HELP_SET_COND, 0);
+	}
+
+	return (CFGA_OK);
+}
+
+/*
+ * 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/sysctrl/common/mapfile-vers	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,38 @@
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2005 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, Version 1.0 only
+# (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
+#
+
+SUNWprivate_1.1 {
+	global:
+		cfga_change_state;
+		cfga_private_func;
+		cfga_test;
+		cfga_stat;
+		cfga_list;
+		cfga_help;
+	local:
+		*;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/cfgadm_plugins/sysctrl/sparc/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 1997-1998, by Sun Microsystems, Inc.
+# All rights reserved.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/sysctrl/sparc/Makefile
+
+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/sysctrl/sparcv9/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/sysctrl/sparcv9/Makefile
+
+include ../Makefile.com
+include $(SRC)/lib/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/sysctrl/sysctrl.xcl	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,94 @@
+#
+# 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.
+#
+# 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
+#
+msgid  "cpu/mem   "
+msgid  "mem       "
+msgid  "dual-sbus "
+msgid  "sbus-upa  "
+msgid  "dual-pci  "
+msgid  "disk      "
+msgid  "soc+sbus  "
+msgid  "soc+upa   "
+msgid  "unknown   "
+msgid  "get-status"
+msgid  "list"
+msgid  "connect"
+msgid  "disconnect"
+msgid  "configure"
+msgid  "unconfigure"
+msgid  "quiesce-test"
+msgid  "insert-test"
+msgid  "remove-test"
+msgid  "set-condition-test"
+msgid  "enable-at-boot"
+msgid  "disable-at-boot"
+msgid  "prom open"
+msgid  "prom getprop"
+msgid  "prom setprop"
+msgid  "[-f][-o enable-at-boot]"
+msgid  "\t-x quiesce-test ap_id [ap_id...]"
+msgid  "\t-x insert-test  ap_id [ap_id...]"
+msgid  "\t-x remove-test  ap_id [ap_id...]"
+msgid  "\t-x set-condition-test=<condition>"
+msgid  "\t-o enable-at-boot"
+msgid  "\t-o disable-at-boot"
+msgid  "unknown"
+msgid  "ok"
+msgid  "failing"
+msgid  "failed"
+msgid  "unusable"
+msgid  "<%s>"
+msgid  "\n"
+msgid  "cfga_sid(%d,%d)=%d\n"
+msgid  "errno=%d"
+msgid  "%s\n"
+msgid  "<%d>"
+msgid  "%s"
+msgid  "/tmp/cfga_simdata"
+msgid  "sim_open"
+msgid  "sim_stat"
+msgid  "sim_size"
+msgid  "sim_read"
+msgid  "sim_open(%s)\n"
+msgid  "/dev/openprom"
+msgid  "sim_ioctl(%d)\n"
+msgid  "sim_seek"
+msgid  "sim_write"
+msgid  "disabled-board-list"
+msgid  "getprop(%s, %d)\n"
+msgid  "prom_set_prop(%s)\n"
+msgid  "%x"
+msgid  "slot"
+msgid  "ap_idx(%s)\n"
+msgid  "ap_idx: s=%s, n=%d\n"
+msgid  "ap_idx(%s)=%d\n"
+msgid  "cpu %d: "
+msgid  "%3d MHz "
+msgid  "%0.1fM "
+msgid  "single buffered ffb   "
+msgid  "double buffered ffb   "
+msgid  "no ffb installed   "
+msgid  "illegal ffb size   "
+msgid  "target: %2d "
+msgid  "no disk   "
+msgid  "disabled at boot   "
+msgid  "non-detachable   "
+msgid  "100 MHz capable   "
--- a/usr/src/uts/common/Makefile.files	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/uts/common/Makefile.files	Thu Jun 29 14:43:12 2006 -0700
@@ -374,6 +374,8 @@
 
 AUDIOTS_OBJS +=	audiots.o
 
+CARDBUS_OBJS += cardbus.o cardbus_hp.o cardbus_cfg.o
+
 CONSKBD_OBJS += conskbd.o
 
 CONSMS_OBJS +=	consms.o
@@ -1037,6 +1039,10 @@
 		audit_path.o audit_start.o audit_syscalls.o audit_token.o \
 		audit_mem.o audit_zone.o
 
+PCIC_OBJS +=	pcic.o
+
+PEM_OBJS +=	pem.o
+
 RPCSEC_OBJS +=	secmod.o	sec_clnt.o	sec_svc.o	sec_gen.o \
 		auth_des.o	auth_kern.o	auth_loopb.o\
 		authdesprt.o	authdesubr.o	authu_prot.o \
--- a/usr/src/uts/common/Makefile.rules	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/uts/common/Makefile.rules	Thu Jun 29 14:43:12 2006 -0700
@@ -444,6 +444,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/cardbus/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/dld/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -564,6 +568,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/pcmcia/pem/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O) 
+
 $(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/ppp/spppasyn/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -1157,6 +1165,9 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/bge/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/cardbus/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/dld/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
@@ -1418,6 +1429,9 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/pcmcia/pcs/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/pcmcia/pem/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/rpc/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/cardbus/cardbus.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,2892 @@
+/*
+ * 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.
+ */
+
+/*
+ * Copyright (c)  * Copyright (c) 2001 Tadpole Technology plc
+ * All rights reserved.
+ * From "@(#)pcicfg.c   1.31    99/06/18 SMI"
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Cardbus module
+ */
+
+#include <sys/conf.h>
+#include <sys/modctl.h>
+
+#include <sys/pci.h>
+
+#include <sys/ddi.h>
+#include <sys/sunndi.h>
+#include <sys/ddi_impldefs.h>
+
+#include <sys/hotplug/hpcsvc.h>
+
+#include <sys/pctypes.h>
+#include <sys/pcmcia.h>
+#include <sys/sservice.h>
+#include <sys/note.h>
+
+#include <sys/pci/pci_types.h>
+#include <sys/pci/pci_sc.h>
+
+#include <sys/pcic_reg.h>
+#include <sys/pcic_var.h>
+#include <sys/pcmcia.h>
+
+#ifdef sparc
+#include <sys/ddi_subrdefs.h>
+#elif defined(__x86) || defined(__amd64)
+#include <sys/pci_intr_lib.h>
+#include <sys/mach_intr.h>
+#endif
+
+#include "cardbus.h"
+#include "cardbus_parse.h"
+#include "cardbus_hp.h"
+#include "cardbus_cfg.h"
+
+static int cardbus_command_default = PCI_COMM_SERR_ENABLE |
+				PCI_COMM_WAIT_CYC_ENAB |
+				PCI_COMM_PARITY_DETECT |
+				PCI_COMM_ME | PCI_COMM_MAE |
+				PCI_COMM_IO;
+
+static int cardbus_next_instance = 0;
+static int cardbus_count = 0;
+static int number_of_cardbus_cards = 0;
+
+static int cardbus_bus_map(dev_info_t *dip, dev_info_t *rdip,
+		ddi_map_req_t *mp, off_t offset, off_t len, caddr_t *vaddrp);
+static void pcirp2rp(const pci_regspec_t *pci_rp, struct regspec *rp);
+
+static int cardbus_ctlops(dev_info_t *, dev_info_t *,
+			ddi_ctl_enum_t, void *arg, void *);
+static void cardbus_init_child_regs(dev_info_t *child);
+static int cardbus_initchild(dev_info_t *, dev_info_t *,
+			dev_info_t *, void *);
+static int cardbus_name_child(dev_info_t *, char *, int);
+static void cardbus_removechild(dev_info_t *dip);
+
+static int cardbus_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
+		ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), caddr_t arg,
+		ddi_dma_handle_t *handlep);
+static int cardbus_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
+		ddi_dma_handle_t handle);
+static int cardbus_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
+		ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
+		ddi_dma_cookie_t *cp, uint_t *ccountp);
+static int cardbus_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
+		ddi_dma_handle_t handle);
+static int cardbus_dma_flush(dev_info_t *dip, dev_info_t *rdip,
+		ddi_dma_handle_t handle, off_t off, size_t len,
+		uint_t cache_flags);
+static int cardbus_dma_win(dev_info_t *dip, dev_info_t *rdip,
+		ddi_dma_handle_t handle, uint_t win, off_t *offp,
+		size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp);
+static int cardbus_dma_map(dev_info_t *dip, dev_info_t *rdip,
+		struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep);
+
+static int cardbus_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
+		ddi_prop_op_t prop_op, int mod_flags,
+		char *name, caddr_t valuep, int *lengthp);
+
+static int cardbus_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
+		char *eventname, ddi_eventcookie_t *cookiep);
+static int cardbus_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
+		ddi_eventcookie_t cookie, void (*callback)(dev_info_t *dip,
+		ddi_eventcookie_t cookie, void *arg, void *bus_impldata),
+		void *arg, ddi_callback_id_t *cb_id);
+static int cardbus_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id);
+static int cardbus_post_event(dev_info_t *dip, dev_info_t *rdip,
+		ddi_eventcookie_t cookie, void *bus_impldata);
+
+static int cardbus_intr_ops(dev_info_t *dip, dev_info_t *rdip,
+		ddi_intr_op_t intr_op,
+		ddi_intr_handle_impl_t *hdlp, void *result);
+
+static int check_token(char *token, int *len);
+static char *find_token(char **cp, int *l, char *endc);
+static int parse_token(char *token);
+static int token_to_hex(char *token, unsigned *val, int len);
+static int token_to_dec(char *token, unsigned *val, int len);
+static void cardbus_add_prop(struct cb_deviceset_props *cdsp, int type,
+		char *name, caddr_t vp, int len);
+static void cardbus_add_stringprop(struct cb_deviceset_props *cdsp,
+		char *name, char *vp, int len);
+static void cardbus_prop_free(ddi_prop_t *propp);
+static void cardbus_devprops_free(struct cb_deviceset_props *cbdp);
+static int cardbus_parse_devprop(cbus_t *cbp, char *cp);
+static void cardbus_device_props(cbus_t *cbp);
+
+static void cardbus_expand_busrange(dev_info_t *dip);
+
+static int cardbus_convert_properties(dev_info_t *dip);
+static void cardbus_revert_properties(dev_info_t *dip);
+
+/*
+ * driver global data
+ */
+kmutex_t cardbus_list_mutex; /* Protects the probe handle list */
+void *cardbus_state;
+int cardbus_latency_timer = 0x40;
+int cardbus_debug = 0;
+
+/*
+ * Module linkage information for the kernel.
+ */
+extern struct mod_ops mod_miscops;
+static struct modlmisc modlmisc = {
+	&mod_miscops,
+	"Cardbus Configurator support %I%",
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1,
+	&modlmisc,
+	NULL
+};
+
+int
+_init(void)
+{
+	int error;
+
+	error =  ddi_soft_state_init(&cardbus_state, sizeof (cbus_t), 0);
+	if (error != 0)
+		return (error);
+
+	mutex_init(&cardbus_list_mutex, NULL, MUTEX_DRIVER, NULL);
+	if ((error = mod_install(&modlinkage)) != 0) {
+		mutex_destroy(&cardbus_list_mutex);
+	}
+
+	return (error);
+}
+
+int
+_fini(void)
+{
+	int error;
+	if ((error = mod_remove(&modlinkage)) == 0) {
+		mutex_destroy(&cardbus_list_mutex);
+		ddi_soft_state_fini(&cardbus_state);
+	}
+	return (error);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+static
+struct bus_ops cardbusbus_ops = {
+	BUSO_REV,
+	cardbus_bus_map,
+	NULL,
+	NULL,
+	NULL,
+	i_ddi_map_fault,
+	cardbus_dma_map,
+	cardbus_dma_allochdl,
+	cardbus_dma_freehdl,
+	cardbus_dma_bindhdl,
+	cardbus_dma_unbindhdl,
+	cardbus_dma_flush,
+	cardbus_dma_win,
+	ddi_dma_mctl,
+	cardbus_ctlops,			/* (*bus_ctl)();		*/
+	cardbus_prop_op,
+	cardbus_get_eventcookie,	/* (*bus_get_eventcookie)();	*/
+	cardbus_add_eventcall,		/* (*bus_add_eventcall)();	*/
+	cardbus_remove_eventcall,	/* (*bus_remove_eventcall)();	*/
+	cardbus_post_event,		/* (*bus_post_event)();		*/
+	NULL,				/* (*bus_intr_ctl)();		*/
+	NULL,				/* (*bus_config)();		*/
+	NULL,				/* (*bus_unconfig)();		*/
+	NULL,				/* (*bus_fm_init)();		*/
+	NULL,				/* (*bus_fm_fini)();		*/
+	NULL,				/* (*bus_enter)();		*/
+	NULL,				/* (*bus_exit)();		*/
+	NULL,				/* (*bus_power)();		*/
+	cardbus_intr_ops		/* (*bus_intr_op)();		*/
+};
+
+#define	CB_EVENT_TAG_INSERT	0
+#define	CB_EVENT_TAG_REMOVE	1
+
+static ndi_event_definition_t cb_ndi_event_defs[] = {
+	{ CB_EVENT_TAG_INSERT, DDI_DEVI_INSERT_EVENT, EPL_INTERRUPT, 0 },
+	{ CB_EVENT_TAG_REMOVE, DDI_DEVI_REMOVE_EVENT, EPL_INTERRUPT, 0 }
+};
+
+#define	CB_N_NDI_EVENTS \
+	(sizeof (cb_ndi_event_defs) / sizeof (cb_ndi_event_defs[0]))
+
+#ifdef sparc
+struct busnum_ctrl {
+	int	rv;
+	dev_info_t *dip;
+	cardbus_bus_range_t *range;
+};
+
+static int
+cardbus_claim_pci_busnum(dev_info_t *dip, void *arg)
+{
+	cardbus_bus_range_t pci_bus_range;
+	struct busnum_ctrl *ctrl;
+	ndi_ra_request_t req;
+	char bus_type[16] = "(unknown)";
+	int len;
+	uint64_t base;
+	uint64_t retlen;
+
+	ctrl = (struct busnum_ctrl *)arg;
+
+	/* check if this is a PCI bus node */
+	len = sizeof (bus_type);
+	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
+	    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
+	    "device_type",
+	    (caddr_t)&bus_type, &len) != DDI_SUCCESS)
+		return (0);	/* (DDI_WALK_PRUNECHILD); */
+
+	if ((strcmp(bus_type, "pci") != 0) &&
+	    (strcmp(bus_type, "pciex") != 0)) /* it is not a pci bus type */
+		return (0);	/* (DDI_WALK_PRUNECHILD); */
+
+	/* look for the bus-range property */
+	len = sizeof (struct cardbus_bus_range);
+	if (ddi_getlongprop_buf(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
+	    "bus-range", (caddr_t)&pci_bus_range, &len) == DDI_SUCCESS) {
+		cardbus_err(dip, 1, "cardbus_claim_pci_busnum: %u -> %u \n",
+			pci_bus_range.lo, pci_bus_range.hi);
+		if ((pci_bus_range.lo >= ctrl->range->lo) &&
+		    (pci_bus_range.hi <= ctrl->range->hi)) {
+			cardbus_err(dip, 1,
+			    "cardbus_claim_pci_busnum: claim %u -> %u \n",
+			    pci_bus_range.lo, pci_bus_range.hi);
+
+			/* claim the bus range from the bus resource map */
+			bzero((caddr_t)&req, sizeof (req));
+			req.ra_addr = (uint64_t)pci_bus_range.lo;
+			req.ra_flags |= NDI_RA_ALLOC_SPECIFIED;
+			req.ra_len = (uint64_t)pci_bus_range.hi -
+			    (uint64_t)pci_bus_range.lo + 1;
+
+			if (ndi_ra_alloc(ctrl->dip, &req, &base, &retlen,
+			    NDI_RA_TYPE_PCI_BUSNUM, 0) == NDI_SUCCESS)
+				return (0);	/* (DDI_WALK_PRUNECHILD); */
+		}
+	}
+
+	/*
+	 * never Error return.
+	 */
+	ctrl->rv = DDI_SUCCESS;
+	return (DDI_WALK_TERMINATE);
+}
+
+static void
+cardbus_walk_node_child(dev_info_t *parent,
+	int (*f)(dev_info_t *, void *), void *arg)
+{
+	dev_info_t *dip;
+	int ret;
+
+	for (dip = ddi_get_child(parent); dip;
+	    dip = ddi_get_next_sibling(dip)) {
+
+		ret = (*f) (dip, arg);
+		if (ret)
+			return;
+	}
+}
+
+static void cardbus_fix_hostbridge_busrange(dev_info_t *dip)
+{
+	cardbus_bus_range_t bus_range;
+	struct busnum_ctrl ctrl;
+
+	uint64_t next_bus;
+	uint64_t blen;
+	ndi_ra_request_t req;
+	int	len;
+
+	cardbus_err(dip, 1, "cardbus_fix_hostbridge_busrange\n");
+
+	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
+	req.ra_len = 1;
+	if (ndi_ra_alloc(dip, &req,
+	    &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
+	    0) != NDI_SUCCESS) {
+		(void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_PCI_BUSNUM);
+
+		if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_BUSNUM)
+		    == NDI_FAILURE) {
+			cardbus_err(dip, 1, "cardbus_fix_hostbridge_busrange "
+			    "NDI_RA_TYPE_PCI_BUSNUM setup fail\n");
+			return;
+		}
+
+		bus_range.lo = 0;
+		(void) ddi_getlongprop_buf(DDI_DEV_T_NONE, dip,
+		DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus_range, &len);
+		bus_range.hi = 255;
+
+		(void) ndi_ra_free(dip,
+		    (uint64_t)bus_range.lo + 1,
+		    (uint64_t)bus_range.hi - (uint64_t)bus_range.lo,
+		    NDI_RA_TYPE_PCI_BUSNUM, 0);
+
+		ctrl.rv = DDI_SUCCESS;
+		ctrl.dip = dip;
+		ctrl.range = &bus_range;
+
+		cardbus_walk_node_child(dip, cardbus_claim_pci_busnum,
+		    (void*)&ctrl);
+
+		if (ctrl.rv != DDI_SUCCESS)
+			cardbus_err(dip, 1, "cardbus_fix_hostbridge_busrange "
+			    "cardbus_walk_node_child fails\n");
+
+		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
+			    "bus-range", (int *)&bus_range, 2);
+
+	} else {
+		cardbus_err(dip, 1, "cardbus_fix_hostbridge_busrange "
+		    "already set up %x\n", (int)next_bus);
+		(void) ndi_ra_free(dip, next_bus, (uint64_t)1,
+		    NDI_RA_TYPE_PCI_BUSNUM, 0);
+	}
+}
+
+static dev_info_t *
+cardbus_find_hsbridge_dip(dev_info_t *dip)
+{
+	dev_info_t *pdip;
+
+	pdip = ddi_get_parent(dip);
+	while (pdip) {
+		if (ddi_get_parent(pdip) == ddi_root_node())
+			break;
+		pdip = ddi_get_parent(pdip);
+	}
+
+	return (pdip);
+}
+#endif /* sparc */
+
+/*
+ * Attach a device to the cardbus infrastructure.
+ */
+int
+cardbus_attach(dev_info_t *dip, cb_nexus_cb_t *nex_ops)
+{
+	cbus_t *cbp;
+	int cb_instance;
+	anp_t *anp = (anp_t *)ddi_get_driver_private(dip);
+	struct dev_info *devi = DEVI(dip);
+
+	mutex_enter(&cardbus_list_mutex);
+
+	/*
+	 * Make sure that it is not already initialized.
+	 */
+	if (ddi_prop_exists(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
+	    "cbus-instance") == 1) {
+		cmn_err(CE_WARN,
+		    "%s%d: cardbus instance already initialized!\n",
+		    ddi_driver_name(dip), ddi_get_instance(dip));
+		    mutex_exit(&cardbus_list_mutex);
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * initialize soft state structure for the bus instance.
+	 */
+	cb_instance = cardbus_next_instance++;
+
+	if (ddi_soft_state_zalloc(cardbus_state, cb_instance) != DDI_SUCCESS) {
+		cmn_err(CE_WARN, "%s%d: can't allocate cardbus soft state\n",
+		    ddi_driver_name(dip), ddi_get_instance(dip));
+		mutex_exit(&cardbus_list_mutex);
+		return (DDI_FAILURE);
+	}
+
+	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
+	cbp->cb_instance = cb_instance;
+	cbp->cb_dip = dip;
+	mutex_init(&cbp->cb_mutex, NULL, MUTEX_DRIVER, NULL);
+
+	/*
+	 * Save the instance number of the soft state structure for
+	 * this bus as a devinfo property.
+	 */
+	if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
+	    "cbus-instance", (caddr_t)&cb_instance,
+	    sizeof (cb_instance)) != DDI_SUCCESS) {
+		cmn_err(CE_WARN,
+		    "%s%d: failed to add the property 'cbus-instance'",
+		    ddi_driver_name(dip), ddi_get_instance(dip));
+		ddi_soft_state_free(cardbus_state, cb_instance);
+		mutex_exit(&cardbus_list_mutex);
+		return (DDI_FAILURE);
+	}
+
+	cbp->cb_nex_ops = nex_ops;
+	/*
+	 * TODO - Should probably be some sort of locking on the devinfo here.
+	 */
+	cbp->orig_dopsp = devi->devi_ops;
+	cbp->orig_bopsp = devi->devi_ops->devo_bus_ops;
+	cbp->cb_dops = *devi->devi_ops;
+	devi->devi_ops = &cbp->cb_dops;
+
+	if (ndi_event_alloc_hdl(dip, *anp->an_iblock, &cbp->cb_ndi_event_hdl,
+	    NDI_SLEEP) == NDI_SUCCESS) {
+		cbp->cb_ndi_events.ndi_n_events = CB_N_NDI_EVENTS;
+		cbp->cb_ndi_events.ndi_events_version = NDI_EVENTS_REV1;
+		cbp->cb_ndi_events.ndi_event_defs = cb_ndi_event_defs;
+		if (ndi_event_bind_set(cbp->cb_ndi_event_hdl,
+		    &cbp->cb_ndi_events,
+		    NDI_SLEEP) != NDI_SUCCESS) {
+			cardbus_err(dip, 1,
+			    "cardbus_attach: ndi_event_bind_set failed\n");
+		}
+	}
+
+	/*
+	 * Check for device initialization property.
+	 */
+	cardbus_device_props(cbp);
+
+	if (cardbus_init_hotplug(cbp) != DDI_SUCCESS) {
+		ddi_soft_state_free(cardbus_state, cb_instance);
+		mutex_exit(&cardbus_list_mutex);
+		return (DDI_FAILURE);
+	}
+
+#ifdef sparc
+	/* a hack to fix the bus-range problem on pci root nodes */
+	{
+		dev_info_t *hs_dip;
+
+		hs_dip = cardbus_find_hsbridge_dip(dip);
+		cardbus_fix_hostbridge_busrange(hs_dip);
+	}
+#endif
+
+	cardbus_expand_busrange(dip);
+	cardbus_count++;
+	mutex_exit(&cardbus_list_mutex);
+	return (DDI_SUCCESS);
+}
+
+#ifdef TODO
+static int
+cardbus_detach(dev_info_t *dip)
+{
+	int cb_instance;
+	cbus_t *cbp;
+
+	mutex_enter(&cardbus_list_mutex);
+	/* get the instance number for the cardbus soft state data */
+	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+			DDI_PROP_DONTPASS, "cbus-instance", -1);
+	if (cb_instance < 0) {
+		mutex_exit(&cardbus_list_mutex);
+		return (DDI_FAILURE); /* no instance is setup for this bus */
+	}
+
+	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
+
+	if (cbp->cb_dsp) {
+		struct cb_deviceset_props *cbdp, *ncbdp;
+
+		cbdp = cbp->cb_dsp;
+		while (cbdp) {
+			ncbdp = cbdp->next;
+			cardbus_devprops_free(cbdp);
+			cbdp = ncbdp;
+		}
+	}
+	/*
+	 * Unregister the bus with the HPS.
+	 *
+	 * (Note: It is assumed that the HPS framework uninstalls
+	 *  event handlers for all the hot plug slots on this bus.)
+	 */
+	(void) hpc_nexus_unregister_bus(dip);
+
+	if (cbp->cb_ndi_event_hdl != NULL) {
+		(void) ndi_event_unbind_set(cbp->cb_ndi_event_hdl,
+		    &cbp->cb_ndi_events, NDI_SLEEP);
+		ndi_event_free_hdl(cbp->cb_ndi_event_hdl);
+	}
+
+	mutex_destroy(&cbp->cb_mutex);
+	if (cbp->nexus_path)
+		kmem_free(cbp->nexus_path, strlen(cbp->nexus_path) + 1);
+	if (cbp->name)
+		kmem_free(cbp->name, strlen(cbp->name) + 1);
+
+	ddi_soft_state_free(cardbus_state, cb_instance);
+
+	/* remove the 'cbus-instance' property from the devinfo node */
+	(void) ddi_prop_remove(DDI_DEV_T_ANY, dip, "cbus-instance");
+
+	ASSERT(cardbus_count != 0);
+	--cardbus_count;
+
+	mutex_exit(&cardbus_list_mutex);
+	return (DDI_SUCCESS);
+}
+#endif
+
+boolean_t
+cardbus_load_cardbus(dev_info_t *dip, uint_t socket, uint32_t pc_base)
+{
+#ifndef HOTPLUG
+	struct cardbus_config_ctrl ctrl;
+	int circular_count;
+#endif
+	int cb_instance;
+	cbus_t *cbp;
+	struct dev_info *devi = DEVI(dip);
+
+	_NOTE(ARGUNUSED(socket, pc_base))
+
+#if defined(CARDBUS_DEBUG)
+	cardbus_err(dip, 6, "cardbus_load_cardbus\n");
+#endif
+
+	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+			DDI_PROP_DONTPASS, "cbus-instance", -1);
+	ASSERT(cb_instance >= 0);
+	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
+
+	if (cbp->fatal_problem)
+		return (B_FALSE);
+
+	if (cardbus_convert_properties(dip) == DDI_FAILURE)
+		return (B_FALSE);
+
+	number_of_cardbus_cards++;
+	devi->devi_ops->devo_bus_ops = &cardbusbus_ops;
+
+#ifdef HOTPLUG
+	mutex_enter(&cbp->cb_mutex);
+	cbp->card_present = B_TRUE;
+
+	(void) hpc_slot_event_notify(cbp->slot_handle,
+	    HPC_EVENT_SLOT_INSERTION, 0);
+	(void) hpc_slot_event_notify(cbp->slot_handle,
+	    HPC_EVENT_SLOT_POWER_ON, 0);
+	(void) hpc_slot_event_notify(cbp->slot_handle,
+	    HPC_EVENT_SLOT_CONFIGURE, 0);
+
+	mutex_exit(&cbp->cb_mutex);
+#else
+	if (cardbus_configure(cbp) != PCICFG_SUCCESS) {
+#if defined(CARDBUS_DEBUG)
+		cardbus_err(dip, 6, "cardbus_configure failed\n");
+#endif
+		return (B_FALSE);
+	}
+
+	ctrl.rv = NDI_SUCCESS;
+	ctrl.busno = cardbus_primary_busno(dip);
+	ctrl.op = PCICFG_OP_ONLINE;
+	ctrl.dip = NULL;
+	ctrl.flags = PCICFG_FLAGS_CONTINUE;
+
+	/*
+	 * The child of the dip is the cardbus dip. The child of the
+	 * cardbus dip is the device itself
+	 */
+#if defined(CARDBUS_DEBUG)
+	cardbus_err(dip, 8, "cardbus_load_cardbus: calling cbus_configure\n");
+#endif
+	ndi_devi_enter(dip, &circular_count);
+	ddi_walk_devs(ddi_get_child(dip), cbus_configure, (void *)&ctrl);
+	ndi_devi_exit(dip, circular_count);
+
+	if (ctrl.rv != NDI_SUCCESS) {
+		cardbus_err(dip, 1,
+		    "cardbus_load_cardbus (%s%d): failed to attach (%d)\n",
+		    ctrl.dip ? ddi_driver_name(ctrl.dip) : "Unknown",
+		    ctrl.dip ? ddi_get_instance(ctrl.dip) : 0,
+		    ctrl.rv);
+
+		/*
+		 * Returning error here will cause the pcic_load_cardbus() call
+		 * to fail. This will invoke pcic_unload_cardbus() which calls
+		 * cardbus_unload_cardbus() below.
+		 */
+		return (B_FALSE);
+	}
+#endif
+
+#if defined(CARDBUS_DEBUG)
+	cardbus_err(dip, 7, "cardbus_load_cardbus: returning TRUE\n");
+#endif
+
+	return (B_TRUE);
+}
+
+/*
+ * Unload the cardbus module
+ */
+void
+cardbus_unload_cardbus(dev_info_t *dip)
+{
+	int	cb_instance;
+#ifndef HOTPLUG
+	int	prim_bus = cardbus_primary_busno(dip);
+	int	rval;
+#endif
+	cbus_t *cbp;
+	struct dev_info *devi = DEVI(dip);
+
+	cardbus_err(dip, 6, "cardbus_unload_cardbus\n");
+
+	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "cbus-instance", -1);
+	ASSERT(cb_instance >= 0);
+	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
+
+	if (number_of_cardbus_cards == 0)
+		return;
+
+#ifdef HOTPLUG
+	mutex_enter(&cbp->cb_mutex);
+	cbp->card_present = B_FALSE;
+
+	(void) hpc_slot_event_notify(cbp->slot_handle,
+	    HPC_EVENT_SLOT_POWER_OFF, 0);
+	(void) hpc_slot_event_notify(cbp->slot_handle,
+	    HPC_EVENT_SLOT_REMOVAL, 0);
+
+	mutex_exit(&cbp->cb_mutex);
+#else
+
+	cardbus_err(dip, 8,
+	    "cardbus_unload_cardbus: calling cardbus_unconfigure_node\n");
+
+	rval = cardbus_unconfigure_node(dip, prim_bus, B_TRUE);
+
+	if (rval != NDI_SUCCESS) {
+		cardbus_err(dip, 4,
+		    "cardbus_unload_cardbus: "
+		    "cardbus_unconfigure_node failed\n");
+		number_of_cardbus_cards--;
+		cbp->fatal_problem = B_TRUE;
+		cmn_err(CE_WARN,
+		    "cardbus(%s%d): Failed to remove device tree: "
+		    "Slot disabled",
+		    ddi_get_name(dip), ddi_get_instance(dip));
+		return;
+	}
+
+	(void) cardbus_unconfigure(cbp);
+#endif
+
+	/*
+	 * Inform the lower drivers that the card has been removed
+	 */
+	if (cbp->cb_ndi_event_hdl != NULL) {
+		ddi_eventcookie_t cookie;
+		if (ndi_event_retrieve_cookie(cbp->cb_ndi_event_hdl, dip,
+		    DDI_DEVI_REMOVE_EVENT, &cookie, 0) == NDI_SUCCESS) {
+			(void) ndi_event_run_callbacks(cbp->cb_ndi_event_hdl,
+			    dip, cookie, NULL);
+		}
+	}
+
+	devi->devi_ops->devo_bus_ops = cbp->orig_bopsp;
+	--number_of_cardbus_cards;
+
+	cardbus_revert_properties(dip);
+}
+
+boolean_t
+cardbus_can_suspend(dev_info_t *dip)
+{
+#ifdef HOTPLUG
+	cbus_t *cbp;
+	int	cb_instance;
+
+	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "cbus-instance", -1);
+	ASSERT(cb_instance >= 0);
+	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
+	if (cbp->ostate == AP_OSTATE_UNCONFIGURED)
+		return (B_TRUE);
+#endif
+	return (B_FALSE);
+}
+
+static int
+cardbus_convert_properties(dev_info_t *dip)
+{
+	struct pcm_regs *pcic_avail_p, *old_avail_p;
+	pci_regspec_t *cb_avail_p, *new_avail_p;
+	pcic_ranges_t *pcic_range_p, *old_range_p;
+	cardbus_range_t *cb_range_p, *new_range_p;
+	int range_len, range_entries, i;
+	int avail_len, avail_entries;
+
+#if defined(CARDBUS_DEBUG)
+	cardbus_err(dip, 6, "cardbus_convert_properties\n");
+#endif
+
+	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    "#address-cells", 3) != DDI_SUCCESS) {
+		cardbus_err(dip, 1, "cardbus_convert_properties: "
+		    "failed to update #address-cells property\n");
+		return (DDI_FAILURE);
+	}
+	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    "#size-cells", 2) != DDI_SUCCESS) {
+		cardbus_err(dip, 1, "cardbus_convert_properties: "
+		    "failed to update #size-cells property\n");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, "available",
+	    (caddr_t)&pcic_avail_p, &avail_len) != DDI_PROP_SUCCESS) {
+		cardbus_err(dip, 1, "cardbus_convert_properties: "
+		    "no available property for pcmcia\n");
+	} else {
+		avail_entries = avail_len / sizeof (struct pcm_regs);
+		cb_avail_p = kmem_alloc(sizeof (pci_regspec_t) * avail_entries,
+		    KM_SLEEP);
+
+		old_avail_p = pcic_avail_p;
+		new_avail_p = cb_avail_p;
+		for (i = 0; i < avail_entries;
+		    i++, old_avail_p++, new_avail_p++) {
+			new_avail_p->pci_phys_hi = old_avail_p->phys_hi;
+			new_avail_p->pci_phys_mid = 0;
+			new_avail_p->pci_phys_low = old_avail_p->phys_lo;
+			new_avail_p->pci_size_hi = 0;
+			new_avail_p->pci_size_low = old_avail_p->phys_len;
+		}
+
+		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
+		    "available",
+		    (int *)cb_avail_p,
+		    (sizeof (pci_regspec_t) * avail_entries)/sizeof (int));
+
+		kmem_free(pcic_avail_p, avail_len);
+		kmem_free(cb_avail_p, sizeof (pci_regspec_t) * avail_entries);
+	}
+
+	if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, "ranges",
+	    (caddr_t)&pcic_range_p, &range_len) != DDI_PROP_SUCCESS) {
+		cardbus_err(dip, 1, "cardbus_convert_properties: "
+		    "no ranges property for pcmcia\n");
+	} else {
+		range_entries = range_len / sizeof (pcic_ranges_t);
+		cb_range_p = kmem_alloc(
+		    sizeof (cardbus_range_t) * range_entries, KM_SLEEP);
+
+		old_range_p = pcic_range_p;
+		new_range_p = cb_range_p;
+		for (i = 0; i < range_entries;
+		    i++, old_range_p++, new_range_p++) {
+			new_range_p->child_hi =
+			    old_range_p->pcic_range_caddrhi;
+			new_range_p->child_mid = 0;
+			new_range_p->child_lo =
+			    old_range_p->pcic_range_caddrlo;
+			new_range_p->parent_hi =
+			    old_range_p->pcic_range_paddrhi;
+			new_range_p->parent_mid =
+			    old_range_p->pcic_range_paddrmid;
+			new_range_p->parent_lo =
+			    old_range_p->pcic_range_paddrlo;
+			new_range_p->size_hi = 0;
+			new_range_p->size_lo = old_range_p->pcic_range_size;
+		}
+
+		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
+		    (int *)cb_range_p,
+		    (sizeof (cardbus_range_t) * range_entries)/sizeof (int));
+
+		kmem_free(pcic_range_p, range_len);
+		kmem_free(cb_range_p, sizeof (cardbus_range_t) * range_entries);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+static void
+cardbus_revert_properties(dev_info_t *dip)
+{
+#if defined(CARDBUS_DEBUG)
+	cardbus_err(dip, 6, "cardbus_revert_properties\n");
+#endif
+
+	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "#address-cells");
+
+	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "#size-cells");
+
+	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "available");
+}
+
+static int
+cardbus_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
+		ddi_prop_op_t prop_op, int mod_flags,
+		char *name, caddr_t valuep, int *lengthp)
+{
+#if defined(CARDBUS_DEBUG)
+	if ((ch_dip != dip) || (cardbus_debug >= 9))
+		cardbus_err(dip, 6,
+		    "cardbus_prop_op(%s) (dip=0x%p, op=%d, name=%s)\n",
+		    ddi_driver_name(ch_dip), (void *) dip, prop_op, name);
+#endif
+	return (impl_ddi_bus_prop_op(dev, dip, ch_dip, prop_op,
+	    mod_flags, name, valuep, lengthp));
+}
+
+static int
+cardbus_ctlops(dev_info_t *dip, dev_info_t *rdip,
+	ddi_ctl_enum_t ctlop, void *arg, void *result)
+{
+	pci_regspec_t *regs;
+	int	totreg, reglen;
+	const char	*dname = ddi_driver_name(dip);
+
+	ASSERT(number_of_cardbus_cards != 0);
+
+	cardbus_err(dip, 6,
+	    "cardbus_ctlops(%p, %p, %d, %p, %p)\n",
+	    (void *)dip, (void *)rdip, ctlop, (void *)arg, (void *)result);
+
+	switch (ctlop) {
+	case DDI_CTLOPS_UNINITCHILD:
+		cardbus_removechild((dev_info_t *)arg);
+		return (DDI_SUCCESS);
+
+	default:
+		/*
+		 * Do Nothing
+		 */
+		cardbus_err(dip, 8,
+		    "cardbus_ctlops: Unsupported DDI_CTLOP %d\n", ctlop);
+		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
+
+	case DDI_CTLOPS_SIDDEV:		/* see ddi_dev_is_sid(9F) */
+		return (DDI_SUCCESS);
+
+	case DDI_CTLOPS_SLAVEONLY:	/* see ddi_slaveonly(9F) */
+		return (DDI_FAILURE);	/* cardbus */
+
+	case DDI_CTLOPS_REGSIZE:
+	case DDI_CTLOPS_NREGS:
+		if (rdip == (dev_info_t *)NULL) {
+			*(int *)result = 0;
+			return (DDI_FAILURE);
+		}
+		break;
+
+	case DDI_CTLOPS_IOMIN:
+		/*
+		 * If we are using the streaming cache, align at
+		 * least on a cache line boundary. Otherwise use
+		 * whatever alignment is passed in.
+		 */
+
+		if (arg) {
+			int	val = *((int *)result);
+
+#ifdef  PCI_SBUF_LINE_SIZE
+			val = maxbit(val, PCI_SBUF_LINE_SIZE);
+#else
+			val = maxbit(val, 64);
+#endif
+			*((int *)result) = val;
+		}
+		return (DDI_SUCCESS);
+
+	case DDI_CTLOPS_INITCHILD:
+		return (cardbus_initchild(rdip, dip, (dev_info_t *)arg,
+					result));
+
+	case DDI_CTLOPS_REPORTDEV:
+		if (rdip == (dev_info_t *)0)
+			return (DDI_FAILURE);
+
+		if (strcmp("pcs", ddi_node_name(rdip)) == 0)
+			cardbus_err(dip, 1,
+			    "cardbus_ctlops: PCCard socket %d at %s@%s\n",
+			    ddi_get_instance(rdip),
+			    dname, ddi_get_name_addr(dip));
+		else {
+			pci_regspec_t *pci_rp;
+			dev_info_t *next;
+			int	length;
+
+			if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
+			    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
+			    (uint_t *)&length) != DDI_PROP_SUCCESS)
+				return (DDI_FAILURE);
+
+			if (pci_rp->pci_phys_hi == 0)
+				cardbus_err(dip, 1, "%s%d at %s@%s\n",
+				    ddi_driver_name(rdip),
+				    ddi_get_instance(rdip),
+				    dname, ddi_get_name_addr(dip));
+			else {
+				uint8_t bus, device, function;
+				int32_t val32;
+				char	*ptr, buf[128];
+
+				bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
+				device = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
+				function = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
+
+				ptr = buf;
+				(void) sprintf(ptr, "  "
+				    "Bus %3d Device %2d Function %2d",
+				    bus, device, function);
+				ptr = &ptr[strlen(ptr)];
+
+				val32 = ddi_getprop(DDI_DEV_T_ANY, rdip,
+				    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
+				    "vendor-id", -1);
+				if (val32 != -1) {
+					(void) sprintf(ptr, " Vendor 0x%04x",
+					    val32);
+					ptr = &ptr[strlen(ptr)];
+				}
+				val32 = ddi_getprop(DDI_DEV_T_ANY, rdip,
+				    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
+				    "device-id", -1);
+				if (val32 != -1) {
+					(void) sprintf(ptr, " Device 0x%04x",
+					    val32);
+					ptr = &ptr[strlen(ptr)];
+				}
+				val32 = ddi_getprop(DDI_DEV_T_ANY, rdip,
+				    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
+				    "class-code", -1);
+				if (val32 != -1) {
+					const char	*name;
+
+					if ((name = ddi_get_name(rdip)) !=
+					    NULL)
+						(void) sprintf(ptr, " Name %s",
+						    name);
+					else
+						(void) sprintf(ptr,
+						    " Class 0x%x", val32 >> 8);
+					ptr = &ptr[strlen(ptr)];
+				}
+
+				*ptr++ = '\n';
+				ASSERT(((caddr_t)ptr - (caddr_t)buf) <
+					sizeof (buf));
+				*ptr = '\0';
+
+				cardbus_err(dip, 1, buf);
+			}
+			ddi_prop_free(pci_rp);
+
+			for (next = ddi_get_child(rdip); next;
+			    next = ddi_get_next_sibling(next))
+				(void) cardbus_ctlops(next, next,
+				    DDI_CTLOPS_REPORTDEV, arg, result);
+		}
+		return (DDI_SUCCESS);
+	}
+	*(int *)result = 0;
+
+	if (ddi_getlongprop(DDI_DEV_T_NONE, rdip,
+	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg",
+	    (caddr_t)&regs, &reglen) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+
+	totreg = reglen / sizeof (pci_regspec_t);
+	if (ctlop == DDI_CTLOPS_NREGS) {
+		cardbus_err(dip, 6,
+		    "cardbus_ctlops, returning NREGS = %d\n", totreg);
+		*(int *)result = totreg;
+	} else if (ctlop == DDI_CTLOPS_REGSIZE) {
+		const int	rn = *(int *)arg;
+		if (rn > totreg)
+			return (DDI_FAILURE);
+		cardbus_err(dip, 6,
+		    "cardbus_ctlops, returning REGSIZE(%d) = %d\n",
+		    rn, regs[rn].pci_size_low);
+		*(off_t *)result = regs[rn].pci_size_low;
+	}
+	kmem_free(regs, reglen);
+	return (DDI_SUCCESS);
+}
+
+static void
+cardbus_init_child_regs(dev_info_t *child)
+{
+	ddi_acc_handle_t config_handle;
+	uint16_t command_preserve, command;
+#if !defined(__i386) && !defined(__amd64)
+	uint8_t bcr;
+#endif
+	uint8_t header_type;
+	uint8_t min_gnt, latency_timer;
+	uint_t n;
+
+	/*
+	 * Map the child configuration space to for initialization.
+	 *
+	 *  Set the latency-timer register to values appropriate
+	 *  for the devices on the bus (based on other devices
+	 *  MIN_GNT and MAX_LAT registers.
+	 *
+	 *  Set the fast back-to-back enable bit in the command
+	 *  register if it's supported and all devices on the bus
+	 *  have the capability.
+	 *
+	 */
+	if (pci_config_setup(child, &config_handle) != DDI_SUCCESS)
+		return;
+
+	cardbus_err(child, 6, "cardbus_init_child_regs()\n");
+
+	/*
+	 * Determine the configuration header type.
+	 */
+	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
+
+	/*
+	 * Support for "command-preserve" property.  Note that we
+	 * add PCI_COMM_BACK2BACK_ENAB to the bits to be preserved
+	 * since the obp will set this if the device supports and
+	 * all targets on the same bus support it.  Since psycho
+	 * doesn't support PCI_COMM_BACK2BACK_ENAB, it will never
+	 * be set.  This is just here in case future revs do support
+	 * PCI_COMM_BACK2BACK_ENAB.
+	 */
+	command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child,
+	    DDI_PROP_DONTPASS,
+	    "command-preserve", 0);
+	command = pci_config_get16(config_handle, PCI_CONF_COMM);
+	command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB);
+	command |= (cardbus_command_default & ~command_preserve);
+	pci_config_put16(config_handle, PCI_CONF_COMM, command);
+	command = pci_config_get16(config_handle, PCI_CONF_COMM);
+
+#if !defined(__i386) && !defined(__amd64)
+	/*
+	 * If the device has a bus control register then program it
+	 * based on the settings in the command register.
+	 */
+	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
+		bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL);
+		if (cardbus_command_default & PCI_COMM_PARITY_DETECT)
+			bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
+		if (cardbus_command_default & PCI_COMM_SERR_ENABLE)
+			bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE;
+		bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
+		pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr);
+	}
+#endif
+
+	/*
+	 * Initialize cache-line-size configuration register if needed.
+	 */
+	if (ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
+	    "cache-line-size", 0) == 0) {
+
+		pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ,
+		    PCI_CACHE_LINE_SIZE);
+		n = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ);
+		if (n != 0)
+			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
+				"cache-line-size", n);
+	}
+
+	/*
+	 * Initialize latency timer registers if needed.
+	 */
+	if (ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
+	    "latency-timer", 0) == 0) {
+
+		if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
+			latency_timer = cardbus_latency_timer;
+			pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER,
+					latency_timer);
+		} else {
+			min_gnt = pci_config_get8(config_handle,
+						PCI_CONF_MIN_G);
+
+			/*
+			 * Cardbus os only 33Mhz
+			 */
+			if (min_gnt != 0) {
+				latency_timer = min_gnt * 8;
+			}
+		}
+		pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER,
+				latency_timer);
+		n = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER);
+		if (n != 0)
+			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
+				"latency-timer", n);
+	}
+
+	pci_config_teardown(&config_handle);
+}
+
+static int
+cardbus_initchild(dev_info_t *rdip, dev_info_t *dip, dev_info_t *child,
+		void *result)
+{
+	char	name[MAXNAMELEN];
+	const char	*dname = ddi_driver_name(dip);
+	const struct cb_ops *cop;
+
+	_NOTE(ARGUNUSED(rdip, result))
+
+	cardbus_err(child, 6, "cardbus_initchild\n");
+
+	/*
+	 * Name the child
+	 */
+	if (cardbus_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+
+	ddi_set_name_addr(child, name);
+	ddi_set_parent_data(child, NULL);
+
+	if (ndi_dev_is_persistent_node(child) == 0) {
+		/*
+		 * Try to merge the properties from this prototype
+		 * node into real h/w nodes.
+		 */
+		if (ndi_merge_node(child, cardbus_name_child) == DDI_SUCCESS) {
+			/*
+			 * Merged ok - return failure to remove the node.
+			 */
+			cardbus_removechild(child);
+			return (DDI_FAILURE);
+		}
+		/*
+		 * The child was not merged into a h/w node,
+		 * but there's not much we can do with it other
+		 * than return failure to cause the node to be removed.
+		 */
+		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
+		    ddi_driver_name(child), ddi_get_name_addr(child),
+		    ddi_driver_name(child));
+		cardbus_removechild(child);
+		return (DDI_NOT_WELL_FORMED);
+	}
+	cop = DEVI(dip)->devi_ops->devo_cb_ops;
+
+	if ((cop == NULL) || (!(cop->cb_flag & D_HOTPLUG))) {
+		cmn_err(CE_WARN, "%s: driver doesn't support HOTPLUG\n", dname);
+		return (DDI_FAILURE);
+	}
+
+	cardbus_init_child_regs(child);
+
+	/*
+	 * Create ppd if needed.
+	 */
+	if (ddi_get_parent_data(child) == NULL) {
+		struct cardbus_parent_private_data *ppd;
+
+#ifdef sparc
+		ppd = (struct cardbus_parent_private_data *)
+		kmem_zalloc(sizeof (struct cardbus_parent_private_data),
+		    KM_SLEEP);
+
+#elif defined(__x86) || defined(__amd64)
+		ppd = (struct cardbus_parent_private_data *)
+		    kmem_zalloc(sizeof (struct cardbus_parent_private_data)
+			+ sizeof (struct intrspec), KM_SLEEP);
+
+		ppd->ppd.par_intr = (struct intrspec *)(ppd + 1);
+		(ppd->ppd.par_intr)->intrspec_pri = 0;
+		(ppd->ppd.par_intr)->intrspec_vec = 0;
+		(ppd->ppd.par_intr)->intrspec_func = (uint_t (*)()) 0;
+#endif
+
+		if (ddi_getprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS,
+		    "interrupts", -1) != -1)
+			ppd->ppd.par_nintr = 1;
+
+		ppd->code = CB_PPD_CODE;
+
+		cardbus_err(child, 5,
+		    "cardbus_initchild: Creating empty ppd\n");
+		ppd->ppd.par_nreg = 0;
+		ppd->ppd.par_reg = NULL;
+
+		ddi_set_parent_data(child, (caddr_t)ppd);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+static int
+cardbus_name_child(dev_info_t *child, char *name, int namelen)
+{
+	pci_regspec_t *pci_rp;
+	char	**unit_addr;
+	uint_t n;
+	int	bus, device, func;
+
+	/*
+	 * Pseudo nodes indicate a prototype node with per-instance
+	 * properties to be merged into the real h/w device node.
+	 * The interpretation of the unit-address is DD[,F]
+	 * where DD is the device id and F is the function.
+	 */
+	if (ndi_dev_is_persistent_node(child) == 0) {
+		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
+		    DDI_PROP_DONTPASS,
+		    "unit-address", &unit_addr, &n) != DDI_PROP_SUCCESS) {
+			cmn_err(CE_WARN, "cannot name node from %s.conf",
+			    ddi_driver_name(child));
+			return (DDI_FAILURE);
+		}
+		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
+			cmn_err(CE_WARN, "unit-address property in %s.conf"
+			    " not well-formed", ddi_driver_name(child));
+			ddi_prop_free(unit_addr);
+			return (DDI_FAILURE);
+		}
+		(void) snprintf(name, namelen, "%s", *unit_addr);
+		ddi_prop_free(unit_addr);
+		return (DDI_SUCCESS);
+	}
+
+	/*
+	 * Get the address portion of the node name based on
+	 * the function and device number.
+	 */
+	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
+	    "reg", (int **)&pci_rp, &n) != DDI_SUCCESS) {
+		return (DDI_FAILURE);
+	}
+
+	bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
+	device = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
+	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
+	ddi_prop_free(pci_rp);
+
+	if (func != 0)
+		(void) snprintf(name, namelen, "%x,%x", device, func);
+	else
+		(void) snprintf(name, namelen, "%x", device);
+
+	cardbus_err(child, 8,
+	    "cardbus_name_child: system init done [%x][%x][%x]"
+	    " for %s [%s] nodeid: %x @%s\n",
+	    bus, device, func,
+	    ddi_get_name(child), ddi_get_name_addr(child),
+	    DEVI(child)->devi_nodeid, name);
+
+	return (DDI_SUCCESS);
+}
+
+static void
+cardbus_removechild(dev_info_t *dip)
+{
+	struct cardbus_parent_private_data *ppd;
+
+	ddi_set_name_addr(dip, NULL);
+	impl_rem_dev_props(dip);
+	ppd = (struct cardbus_parent_private_data *)ddi_get_parent_data(dip);
+	if (ppd && (ppd->code == CB_PPD_CODE)) {
+		if (ppd->ppd.par_reg && (ppd->ppd.par_nreg > 0))
+			kmem_free((caddr_t)ppd->ppd.par_reg,
+			    ppd->ppd.par_nreg * sizeof (struct regspec));
+#ifdef sparc
+		kmem_free(ppd, sizeof (struct cardbus_parent_private_data));
+#elif defined(__x86) || defined(__amd64)
+		kmem_free(ppd, sizeof (struct cardbus_parent_private_data) +
+		    sizeof (struct intrspec));
+#endif
+		cardbus_err(dip, 5,
+		    "cardbus_removechild: ddi_set_parent_data(NULL)\n");
+		ddi_set_parent_data(dip, NULL);
+	}
+}
+
+
+static char	cb_bnamestr[] = "binding_name";
+static char	cb_venidstr[] = "VendorID";
+static char	cb_devidstr[] = "DeviceID";
+static char	cb_nnamestr[] = "nodename";
+
+static cb_props_parse_tree_t cb_props_parse_tree[] = {
+	{ cb_bnamestr, PT_STATE_STRING_VAR },
+	{ cb_venidstr, PT_STATE_HEX_VAR },
+	{ cb_devidstr, PT_STATE_HEX_VAR } };
+
+static int
+check_token(char *token, int *len)
+{
+	int	state = PT_STATE_DEC_VAR;
+	int	sl = strlen(token), il = 1;
+	char	c;
+
+	if (token[0] == '0' && token[2] && (token[1] == 'x' || token[1] ==
+	    'X')) {
+		state = PT_STATE_HEX_VAR;
+		token += 2;
+	}
+
+	while (c = *token++) {
+		if (isdigit(c))
+			continue;
+		if (c == PARSE_COMMA) {
+			il++;
+			if (token[0] == '0' && token[2] && isx(token[1])) {
+				state = PT_STATE_HEX_VAR;
+				token += 2;
+			}
+			continue;
+		}
+		if (!isxdigit(c)) {
+			*len = sl;
+			return (PT_STATE_STRING_VAR);
+		}
+		state = PT_STATE_HEX_VAR;
+	}
+	*len = il;
+	return (state);
+}
+
+
+static char *
+find_token(char **cp, int *l, char *endc)
+{
+	char	*cpp = *cp;
+
+	while ((**cp && (isalpha(**cp) || isxdigit(**cp) ||
+	    (**cp == PARSE_UNDERSCORE) ||
+	    (**cp == PARSE_COMMA) ||
+	    (**cp == PARSE_DASH)))) {
+		(*cp)++;
+		(*l)++;
+	}
+
+	*endc = **cp;
+	**cp = NULL;
+
+	return (cpp);
+}
+
+static int
+parse_token(char *token)
+{
+	cb_props_parse_tree_t *pt = cb_props_parse_tree;
+	int	k = sizeof (cb_props_parse_tree) /
+	    sizeof (cb_props_parse_tree_t);
+
+	while (k--) {
+		if (strcmp((char *)token, pt->token) == 0)
+			return (pt->state);
+		pt++;
+	}
+
+	return (PT_STATE_UNKNOWN);
+}
+
+static int
+token_to_hex(char *token, unsigned *val, int len)
+{
+	uchar_t c;
+
+	*val = 0;
+	if (token[0] == '0' && (token[1] == 'x' || token[1] == 'X')) {
+		token += 2;
+	}
+
+	while (*token) {
+		if (!isxdigit(*token)) {
+			if (*token == PARSE_COMMA) {
+				if (!(--len))
+					return (1);
+				val++;
+				*val = 0;
+				token++;
+				if (token[0] == '0' && (token[1] == 'x' ||
+				    token[1] == 'X')) {
+					token += 2;
+				}
+				continue;
+			}
+			return (0);
+		}
+		c = toupper(*token);
+		if (c >= 'A')
+			c = c - 'A' + 10 + '0';
+		*val = ((*val * 16) + (c - '0'));
+		token++;
+	}
+
+	return (1);
+}
+
+static int
+token_to_dec(char *token, unsigned *val, int len)
+{
+	*val = 0;
+
+	while (*token) {
+		if (!isdigit(*token)) {
+			if (*token == PARSE_COMMA) {
+				if (!(--len))
+					return (1);
+				val++;
+				*val = 0;
+				token++;
+				continue;
+			}
+			return (0);
+		}
+		*val = ((*val * 10) + (*token - '0'));
+		token++;
+	}
+
+	return (1);
+}
+
+static void
+cardbus_add_prop(struct cb_deviceset_props *cdsp, int type, char *name,
+		caddr_t vp, int len)
+{
+	ddi_prop_t *propp;
+	int	pnlen = strlen(name) + 1;
+
+	propp = (ddi_prop_t *)kmem_zalloc(sizeof (ddi_prop_t), KM_SLEEP);
+	propp->prop_name = (char *)kmem_alloc(pnlen, KM_SLEEP);
+	propp->prop_val = vp;
+	bcopy(name, propp->prop_name, pnlen);
+	propp->prop_len = len;
+	propp->prop_flags = type;
+	propp->prop_next = cdsp->prop_list;
+	cdsp->prop_list = propp;
+}
+
+static void
+cardbus_add_stringprop(struct cb_deviceset_props *cdsp, char *name,
+		char *vp, int len)
+{
+	char	*nstr = kmem_zalloc(len + 1, KM_SLEEP);
+
+	bcopy(vp, nstr, len);
+	cardbus_add_prop(cdsp, DDI_PROP_TYPE_STRING, name, (caddr_t)nstr,
+	    len + 1);
+}
+
+static void
+cardbus_prop_free(ddi_prop_t *propp)
+{
+	if (propp->prop_len) {
+		switch (propp->prop_flags) {
+		case DDI_PROP_TYPE_STRING:
+			kmem_free(propp->prop_val, propp->prop_len);
+			break;
+		case DDI_PROP_TYPE_INT:
+			kmem_free(propp->prop_val,
+			    propp->prop_len * sizeof (int));
+			break;
+		}
+	}
+	kmem_free(propp->prop_name, strlen(propp->prop_name) + 1);
+	kmem_free(propp, sizeof (ddi_prop_t *));
+}
+
+static void
+cardbus_devprops_free(struct cb_deviceset_props *cbdp)
+{
+	ddi_prop_t *propp, *npropp;
+
+	propp = cbdp->prop_list;
+	while (propp) {
+		npropp = propp->prop_next;
+		cardbus_prop_free(propp);
+		propp = npropp;
+	}
+	if (cbdp->nodename)
+		kmem_free(cbdp->nodename, strlen(cbdp->nodename) + 1);
+	if (cbdp->binding_name)
+		kmem_free(cbdp->binding_name, strlen(cbdp->binding_name) +
+		    1);
+	kmem_free(cbdp, sizeof (*cbdp));
+}
+
+/*
+ * Format of "cb-device-init-props" property:
+ * Anything before the semi-colon is an identifying equate, anything
+ * after the semi-colon is a setting equate.
+ *
+ * "binding_name=xXxXxX VendorID=NNNN DeviceID=NNNN; nodename=NewName
+ * 					Prop=PropVal"
+ *
+ */
+static int
+cardbus_parse_devprop(cbus_t *cbp, char *cp)
+{
+	int	state = PT_STATE_TOKEN, qm = 0, em = 0, smc = 0, l = 0;
+	int	length;
+	char	*token = "beginning of line";
+	char	*ptoken = NULL, *quote;
+	char	eq = NULL;
+	struct cb_deviceset_props *cdsp;
+
+	cdsp = (struct cb_deviceset_props *)kmem_zalloc(sizeof (*cdsp),
+	    KM_SLEEP);
+	length = strlen(cp);
+
+	while ((*cp) && (l < length)) {
+		/*
+		 * Check for escaped characters
+		 */
+		if (*cp == PARSE_ESCAPE) {
+			char	*cpp = cp, *cppp = cp + 1;
+
+			em = 1;
+
+			if (!qm) {
+				cmn_err(CE_CONT, "cardbus_parse_devprop: "
+				    "escape not allowed outside "
+				    "of quotes at [%s]\n", token);
+				return (DDI_FAILURE);
+
+			} /* if (!qm) */
+
+			while (*cppp)
+				*cpp++ = *cppp++;
+
+			l++;
+
+			*cpp = NULL;
+		} /* PARSE_ESCAPE */
+
+		/*
+		 * Check for quoted strings
+		 */
+		if (!em && (*cp == PARSE_QUOTE)) {
+			qm ^= 1;
+			if (qm) {
+				quote = cp + 1;
+			} else {
+				*cp = NULL;
+				if (state == PT_STATE_CHECK) {
+					if (strcmp(token, cb_nnamestr) == 0) {
+						cdsp->nodename = kmem_alloc(
+						    strlen(quote) + 1,
+						    KM_SLEEP);
+						(void) strcpy(cdsp->nodename,
+						    quote);
+					} else
+						cardbus_add_stringprop(cdsp,
+						    token, quote,
+						    strlen(quote));
+				} else if (state != PT_STATE_STRING_VAR) {
+					cmn_err(CE_CONT,
+					    "cardbus_parse_devprop: "
+					    "unexpected string [%s] after "
+					    "[%s]\n", quote, token);
+					return (DDI_FAILURE);
+				} else {
+					if (strcmp(token, cb_bnamestr) == 0) {
+						cdsp->binding_name = kmem_alloc(
+						    strlen(quote) + 1,
+						    KM_SLEEP);
+						(void) strcpy(
+						    cdsp->binding_name, quote);
+					}
+				}
+				state = PT_STATE_TOKEN;
+			} /* if (qm) */
+		} /* PARSE_QUOTE */
+
+		em = 0;
+
+		if (!qm && (*cp == PARSE_SEMICOLON)) {
+			smc = 1;
+		}
+
+		/*
+		 * Check for tokens
+		 */
+		else if (!qm && (isalpha(*cp) || isxdigit(*cp))) {
+			int	tl;
+			unsigned	*intp;
+			ptoken = token;
+			token = find_token(&cp, &l, &eq);
+
+			switch (state) {
+			case PT_STATE_TOKEN:
+				if (smc) {
+					if (eq == PARSE_EQUALS)
+						state = PT_STATE_CHECK;
+					else
+						cardbus_add_prop(cdsp,
+						    DDI_PROP_TYPE_ANY,
+						    token,
+						    NULL, 0);
+				} else if (eq == PARSE_EQUALS)
+					switch (state = parse_token(token)) {
+					case PT_STATE_UNKNOWN:
+						cmn_err(CE_CONT,
+						    "cardbus_parse_devprop: "
+						    "unknown token [%s]\n",
+						    token);
+						state = PT_STATE_TOKEN;
+					} /* switch (parse_token) */
+				else
+					state = PT_STATE_TOKEN;
+				break;
+
+			case PT_STATE_CHECK:
+				switch (check_token(token, &tl)) {
+				case PT_STATE_DEC_VAR:
+					intp = (unsigned *)kmem_alloc(
+					    sizeof (int)*tl,
+					    KM_SLEEP);
+					if (token_to_dec(token, intp, tl))
+						cardbus_add_prop(cdsp,
+						    DDI_PROP_TYPE_INT, ptoken,
+						    (caddr_t)intp, tl);
+					else
+						kmem_free(intp,
+						    sizeof (int)*tl);
+					break;
+				case PT_STATE_HEX_VAR:
+					intp = (unsigned *)kmem_alloc(
+					    sizeof (int)*tl,
+					    KM_SLEEP);
+					if (token_to_hex(token, intp, tl))
+						cardbus_add_prop(cdsp,
+						    DDI_PROP_TYPE_INT,
+						    ptoken,
+						    (caddr_t)intp, tl);
+					else
+						kmem_free(intp,
+						    sizeof (int)*tl);
+					break;
+				case PT_STATE_STRING_VAR:
+					if (strcmp(ptoken, cb_nnamestr) == 0) {
+						cdsp->nodename = kmem_alloc(
+						    tl + 1, KM_SLEEP);
+						(void) strcpy(cdsp->nodename,
+						    token);
+					} else
+						cardbus_add_stringprop(cdsp,
+						    ptoken, token, tl);
+					break;
+				}
+				state = PT_STATE_TOKEN;
+				break;
+
+			case PT_STATE_HEX_VAR:
+				if (strcmp(ptoken, cb_venidstr) == 0) {
+					uint_t val;
+					if (token_to_hex(token, &val, 1))
+						cdsp->venid = val;
+				} else if (strcmp(ptoken, cb_devidstr) == 0) {
+					uint_t val;
+					if (token_to_hex(token, &val, 1))
+						cdsp->devid = val;
+				}
+				state = PT_STATE_TOKEN;
+				break;
+
+			case PT_STATE_DEC_VAR:
+				if (strcmp(ptoken, cb_venidstr) == 0) {
+					uint_t val;
+					if (token_to_dec(token, &val, 1))
+						cdsp->venid = val;
+				} else if (strcmp(ptoken, cb_devidstr) == 0) {
+					uint_t val;
+					if (token_to_dec(token, &val, 1))
+						cdsp->devid = val;
+				}
+				state = PT_STATE_TOKEN;
+				break;
+
+			case PT_STATE_STRING_VAR:
+				if (strcmp(ptoken, cb_bnamestr) == 0) {
+					cdsp->binding_name = kmem_alloc(
+					    strlen(token) + 1, KM_SLEEP);
+					(void) strcpy(cdsp->binding_name,
+					    token);
+				}
+				state = PT_STATE_TOKEN;
+				break;
+
+			default:
+				cmn_err(CE_CONT, "cardbus_parse_devprop: "
+				    "unknown state machine state = %d\n",
+				    state);
+
+				cardbus_devprops_free(cdsp);
+				return (DDI_FAILURE);
+			} /* switch (state) */
+			if (eq == PARSE_SEMICOLON)
+				smc = 1;
+		}
+		cp++;
+		l++;
+	} /* while (*cp) */
+
+	if (qm) {
+		cmn_err(CE_CONT, "cb_props_parse_line: unterminated "
+		    "string = [%s]\n", quote);
+		cardbus_devprops_free(cdsp);
+		return (DDI_FAILURE);
+	}
+
+	if (state != PT_STATE_TOKEN) {
+		cmn_err(CE_CONT, "cardbus_parse_devprop: token [%s] "
+		    "requires value\n", token);
+		cardbus_devprops_free(cdsp);
+		return (DDI_FAILURE);
+	}
+
+	if (cdsp->venid == 0 || cdsp->devid == 0) {
+		cmn_err(CE_CONT, "cardbus_parse_devprop: Entry "
+		    "requires VendorID and DeviceID\n");
+		cardbus_devprops_free(cdsp);
+		return (DDI_FAILURE);
+	}
+
+	cdsp->next = cbp->cb_dsp;
+	cbp->cb_dsp = cdsp;
+	return (DDI_SUCCESS);
+}
+
+static void
+cardbus_device_props(cbus_t *cbp)
+{
+	char	**prop_array;
+	uint_t i, n;
+
+	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, cbp->cb_dip,
+	    DDI_PROP_DONTPASS,
+	    "cb-device-init-props", &prop_array,
+	    &n) != DDI_PROP_SUCCESS)
+		return;
+
+	for (i = 0; i < n; i++)
+		(void) cardbus_parse_devprop(cbp, prop_array[i]);
+
+	ddi_prop_free(prop_array);
+}
+
+
+#include <vm/seg_kmem.h>
+extern int	pf_is_memory(pfn_t);
+#define	BUSTYPE_TO_PFN(btype, pfn) (((btype) << 19) | ((pfn) & 0x7FFFF))
+
+static int
+cardbus_rootnex_map_regspec(ddi_map_req_t *mp, caddr_t *vaddrp,
+			uint_t mapping_attr)
+{
+	ulong_t base;
+	caddr_t kaddr;
+	pgcnt_t npages;
+	pfn_t	pfn;
+	uint_t	pgoffset;
+	struct regspec *rp = mp->map_obj.rp;
+
+	/* base addr */
+	base = (ulong_t)rp->regspec_addr & (~MMU_PAGEOFFSET);
+
+	/*
+	 * Take the bustype and the physical page base within the
+	 * bus space and turn it into a 28 bit page frame number.
+	 */
+	pfn = BUSTYPE_TO_PFN(rp->regspec_bustype, mmu_btop(base));
+
+	/*
+	 * Do a quick sanity check to make sure we are in I/O space.
+	 */
+	if (pf_is_memory(pfn))
+		return (DDI_ME_INVAL);
+
+	if (rp->regspec_size == 0) {
+		cardbus_err(NULL, 1,
+		    "cardbus_rootnex_map_regspec: zero regspec_size\n");
+		return (DDI_ME_INVAL);
+	}
+
+	if (mp->map_flags & DDI_MF_DEVICE_MAPPING)
+		*vaddrp = (caddr_t)pfn;
+	else {
+		pgoffset = (ulong_t)rp->regspec_addr & MMU_PAGEOFFSET;
+		npages = mmu_btopr(rp->regspec_size + pgoffset);
+
+		cardbus_err(NULL, 8,
+		    "cardbus_rootnex_map_regspec: "
+		    "Mapping %lu pages physical %x.%lx ",
+		    npages, rp->regspec_bustype, base);
+
+		kaddr = vmem_alloc(heap_arena, ptob(npages), VM_NOSLEEP);
+		if (kaddr == NULL)
+			return (DDI_ME_NORESOURCES);
+
+		/*
+		 * Now map in the pages we've allocated...
+		 */
+		hat_devload(kas.a_hat, kaddr, ptob(npages), pfn,
+		    mp->map_prot | mapping_attr, HAT_LOAD_LOCK);
+
+		*vaddrp = kaddr + pgoffset;
+	}
+
+	cardbus_err(NULL, 8,
+	    "cardbus_rootnex_map_regspec: at virtual %p\n", (void *)*vaddrp);
+	return (0);
+}
+
+static int
+cardbus_rootnex_unmap_regspec(ddi_map_req_t *mp, caddr_t *vaddrp)
+{
+	caddr_t addr = *vaddrp;
+	pgcnt_t npages;
+	uint_t  pgoffset;
+	caddr_t base;
+	struct regspec *rp;
+
+	if (mp->map_flags & DDI_MF_DEVICE_MAPPING)
+		return (0);
+
+	rp = mp->map_obj.rp;
+	pgoffset = (uintptr_t)addr & MMU_PAGEOFFSET;
+
+	if (rp->regspec_size == 0) {
+		cardbus_err(NULL, 1,
+		    "cardbus_rootnex_unmap_regspec: zero regspec_size\n");
+		return (DDI_ME_INVAL);
+	}
+
+	base = addr - pgoffset;
+	npages = mmu_btopr(rp->regspec_size + pgoffset);
+	hat_unload(kas.a_hat, base, ptob(npages), HAT_UNLOAD_UNLOCK);
+	vmem_free(heap_arena, base, ptob(npages));
+
+	/*
+	 * Destroy the pointer - the mapping has logically gone
+	 */
+	*vaddrp = (caddr_t)0;
+
+	return (0);
+}
+
+static int
+cardbus_rootnex_map_handle(ddi_map_req_t *mp)
+{
+	ddi_acc_hdl_t *hp;
+	uint_t hat_flags;
+	register struct regspec *rp;
+
+	/*
+	 * Set up the hat_flags for the mapping.
+	 */
+	hp = mp->map_handlep;
+
+	switch (hp->ah_acc.devacc_attr_endian_flags) {
+	case DDI_NEVERSWAP_ACC:
+		hat_flags = HAT_NEVERSWAP | HAT_STRICTORDER;
+		break;
+	case DDI_STRUCTURE_BE_ACC:
+		hat_flags = HAT_STRUCTURE_BE;
+		break;
+	case DDI_STRUCTURE_LE_ACC:
+		hat_flags = HAT_STRUCTURE_LE;
+		break;
+	default:
+		return (DDI_REGS_ACC_CONFLICT);
+	}
+
+	switch (hp->ah_acc.devacc_attr_dataorder) {
+	case DDI_STRICTORDER_ACC:
+		break;
+	case DDI_UNORDERED_OK_ACC:
+		hat_flags |= HAT_UNORDERED_OK;
+		break;
+	case DDI_MERGING_OK_ACC:
+		hat_flags |= HAT_MERGING_OK;
+		break;
+	case DDI_LOADCACHING_OK_ACC:
+		hat_flags |= HAT_LOADCACHING_OK;
+		break;
+	case DDI_STORECACHING_OK_ACC:
+		hat_flags |= HAT_STORECACHING_OK;
+		break;
+	default:
+		return (DDI_FAILURE);
+	}
+
+	rp = mp->map_obj.rp;
+	if (rp->regspec_size == 0)
+		return (DDI_ME_INVAL);
+
+	hp->ah_hat_flags = hat_flags;
+	hp->ah_pfn = mmu_btop((ulong_t)rp->regspec_addr & (~MMU_PAGEOFFSET));
+	hp->ah_pnum = mmu_btopr(rp->regspec_size +
+	    (ulong_t)rp->regspec_addr & MMU_PAGEOFFSET);
+	return (DDI_SUCCESS);
+}
+
+static int
+cardbus_rootnex_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
+		off_t offset, off_t len, caddr_t *vaddrp)
+{
+	struct regspec *rp, tmp_reg;
+	ddi_map_req_t mr = *mp;	/* Get private copy of request */
+	int	error;
+	uint_t mapping_attr;
+	ddi_acc_hdl_t *hp = NULL;
+
+	mp = &mr;
+
+	switch (mp->map_op)  {
+	case DDI_MO_MAP_LOCKED:
+	case DDI_MO_UNMAP:
+	case DDI_MO_MAP_HANDLE:
+		break;
+	default:
+		cardbus_err(dip, 1,
+		    "cardbus_rootnex_map: unimplemented map op %d.",
+		    mp->map_op);
+		return (DDI_ME_UNIMPLEMENTED);
+	}
+
+	if (mp->map_flags & DDI_MF_USER_MAPPING)  {
+		cardbus_err(dip, 1,
+		    "cardbus_rootnex_map: unimplemented map type: user.");
+		return (DDI_ME_UNIMPLEMENTED);
+	}
+
+	/*
+	 * First, if given an rnumber, convert it to a regspec...
+	 * (Presumably, this is on behalf of a child of the root node)
+	 */
+
+	if (mp->map_type == DDI_MT_RNUMBER)  {
+
+		int	rnumber = mp->map_obj.rnumber;
+
+		rp = i_ddi_rnumber_to_regspec(rdip, rnumber);
+		if (rp == (struct regspec *)0)  {
+			cardbus_err(dip, 1,
+			    "cardbus_rootnex_map: Out of "
+			    "range rnumber <%d>, device <%s>",
+			    rnumber, ddi_get_name(rdip));
+			return (DDI_ME_RNUMBER_RANGE);
+		}
+
+		/*
+		 * Convert the given ddi_map_req_t from rnumber to regspec...
+		 */
+
+		mp->map_type = DDI_MT_REGSPEC;
+		mp->map_obj.rp = rp;
+	}
+
+	/*
+	 * Adjust offset and length correspnding to called values...
+	 */
+
+	tmp_reg = *(mp->map_obj.rp);	/* Preserve underlying data */
+	rp = mp->map_obj.rp = &tmp_reg;	/* Use tmp_reg in request */
+
+	rp->regspec_addr += (uint_t)offset;
+	if (len != 0)
+		rp->regspec_size = (uint_t)len;
+
+	/*
+	 * Apply any parent ranges at this level, if applicable.
+	 * (This is where nexus specific regspec translation takes place.
+	 * Use of this function is implicit agreement that translation is
+	 * provided via ddi_apply_range.)
+	 */
+	cardbus_err(dip, 1, "ppd: %p, %p\n",
+	    (void *) DEVI_PD(dip), (void *) DEVI_PD(rdip));
+
+	cardbus_err(dip, 8,
+	    "cardbus_rootnex_map: applying range of parent "
+	    "<%s> to child <%s>...\n", ddi_get_name(dip), ddi_get_name(rdip));
+
+	if ((error = i_ddi_apply_range(dip, rdip, mp->map_obj.rp)) != 0)
+		return (error);
+
+	switch (mp->map_op)  {
+	case DDI_MO_MAP_LOCKED:
+		/*
+		 * Set up the locked down kernel mapping to the regspec...
+		 */
+
+		/*
+		 * If we were passed an access handle we need to determine
+		 * the "endian-ness" of the mapping and fill in the handle.
+		 */
+		if (mp->map_handlep) {
+			hp = mp->map_handlep;
+			switch (hp->ah_acc.devacc_attr_endian_flags) {
+			case DDI_NEVERSWAP_ACC:
+				mapping_attr = HAT_NEVERSWAP | HAT_STRICTORDER;
+				break;
+			case DDI_STRUCTURE_BE_ACC:
+				mapping_attr = HAT_STRUCTURE_BE;
+				break;
+			case DDI_STRUCTURE_LE_ACC:
+				mapping_attr = HAT_STRUCTURE_LE;
+				break;
+			default:
+				return (DDI_REGS_ACC_CONFLICT);
+			}
+
+			switch (hp->ah_acc.devacc_attr_dataorder) {
+			case DDI_STRICTORDER_ACC:
+				break;
+			case DDI_UNORDERED_OK_ACC:
+				mapping_attr |= HAT_UNORDERED_OK;
+				break;
+			case DDI_MERGING_OK_ACC:
+				mapping_attr |= HAT_MERGING_OK;
+				break;
+			case DDI_LOADCACHING_OK_ACC:
+				mapping_attr |= HAT_LOADCACHING_OK;
+				break;
+			case DDI_STORECACHING_OK_ACC:
+				mapping_attr |= HAT_STORECACHING_OK;
+				break;
+			default:
+				return (DDI_REGS_ACC_CONFLICT);
+			}
+		} else {
+			mapping_attr = HAT_NEVERSWAP | HAT_STRICTORDER;
+		}
+
+		/*
+		 * Set up the mapping.
+		 */
+		error = cardbus_rootnex_map_regspec(mp, vaddrp, mapping_attr);
+
+		/*
+		 * Fill in the access handle if needed.
+		 */
+		if (hp) {
+			hp->ah_addr = *vaddrp;
+			hp->ah_hat_flags = mapping_attr;
+			if (error == 0)
+				impl_acc_hdl_init(hp);
+		}
+		return (error);
+
+	case DDI_MO_UNMAP:
+		/*
+		 * Release mapping...
+		 */
+		return (cardbus_rootnex_unmap_regspec(mp, vaddrp));
+
+	case DDI_MO_MAP_HANDLE:
+		return (cardbus_rootnex_map_handle(mp));
+
+	}
+
+	return (DDI_ME_UNIMPLEMENTED);
+}
+
+/*
+ * dip an ancestor of rdip. Allocate space on dip for rdip
+ */
+static int
+cardbus_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
+		off_t offset, off_t len, caddr_t *vaddrp)
+{
+	register dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent;
+	int	rc;
+
+	cardbus_err(dip, 9,
+	    "cardbus_bus_map(dip=0x%p, rdip=0x%p)\n",
+	    (void *) dip, (void *) rdip);
+
+	if (pdip == NULL)
+		return (DDI_FAILURE);
+
+	/* A child has asked us to set something up */
+	cardbus_err(dip, 9,
+	    "cardbus_bus_map(%s) calling %s - 0x%p, "
+	    "offset 0x%x, len 0x%x\n",
+	    ddi_driver_name(rdip),
+	    ddi_driver_name(pdip),
+	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_map,
+	    (int)offset, (int)len);
+
+	rc = (DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)
+	    (pdip, rdip, mp, offset, len, vaddrp);
+	/* rc = ddi_map(dip, mp, offset, len, vaddrp); */
+
+	if (rc != DDI_SUCCESS)
+		cardbus_err(rdip, 8, "cardbus_bus_map failed, rc = %d\n", rc);
+	else {
+		cardbus_err(rdip, 9, "cardbus_bus_map OK\n");
+		return (DDI_SUCCESS);
+	}
+
+	if (mp->map_type == DDI_MT_RNUMBER) {
+		int	rnumber = mp->map_obj.rnumber;
+		uint_t length;
+		pci_regspec_t *pci_rp;
+		struct regspec regspec;
+		ddi_map_req_t p_map_request;
+
+#if defined(CARDBUS_DEBUG)
+		if (cardbus_debug >= 9)
+			cardbus_dump_family_tree(dip);
+#endif
+
+		cardbus_err(rdip, 8,
+		    "cardbus_bus_map rnumber is %d\n", rnumber);
+
+		if (rnumber < 0)
+			return (DDI_ME_RNUMBER_RANGE);
+
+		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
+		    DDI_PROP_DONTPASS, "reg",
+		    (int **)&pci_rp,
+		    &length) != DDI_PROP_SUCCESS)
+			return (DDI_FAILURE);
+
+		/*
+		 * I think this is bogus. You will never get a length of
+		 * zero if the lookup succeeds.
+		 */
+		if (length == 0) {
+			return (DDI_FAILURE);
+		}
+
+		/* cardbus_dump_reg(rdip, pci_rp, length); */
+
+		/* config space should have mapped in OK earlier */
+		ASSERT(rnumber > 0);
+		/* use as offset into assigned-addresses not reg */
+
+		if (rnumber >= length)
+			return (DDI_ME_RNUMBER_RANGE);
+
+		pci_rp += rnumber;
+
+		pcirp2rp(pci_rp, &regspec);
+		ddi_prop_free(pci_rp-rnumber);
+
+		regspec.regspec_addr += offset;
+		if (len)
+			regspec.regspec_size = len;
+
+		cardbus_err(dip, 1,
+		    "regspec: bustype 0x%x, addr 0x%x, size 0x%x\n",
+		    regspec.regspec_bustype,
+		    regspec.regspec_addr,
+		    regspec.regspec_size);
+
+		ASSERT(regspec.regspec_size > 0);
+
+		p_map_request = *mp;
+		p_map_request.map_type = DDI_MT_REGSPEC;
+		p_map_request.map_obj.rp = &regspec;
+
+		rc = cardbus_rootnex_map(dip, rdip, &p_map_request, 0, 0,
+		    vaddrp);
+		if (rc != DDI_SUCCESS)
+			cardbus_err(rdip, 8,
+			    "cardbus_bus_map(regspec): ddi_map failed, "
+			    "rc = %d\n", rc);
+		else {
+			cardbus_err(rdip, 7,
+			    "cardbus_bus_map(regspec): ddi_map OK\n");
+			return (DDI_SUCCESS);
+		}
+	}
+	return (rc);
+}
+
+static void
+pcirp2rp(const pci_regspec_t *pci_rp, struct regspec *rp)
+{
+	/* bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi); */
+	if (PCI_REG_ADDR_G(pci_rp->pci_phys_hi) ==
+	    PCI_REG_ADDR_G(PCI_ADDR_IO)) {
+		/* I/O */
+		rp->regspec_bustype = 1;
+	} else {
+		/* memory */
+		rp->regspec_bustype = 0;
+	}
+	rp->regspec_addr = pci_rp->pci_phys_low;
+	rp->regspec_size = pci_rp->pci_size_low;
+}
+
+static int
+cardbus_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
+		int (*waitfp)(caddr_t), caddr_t arg,
+		ddi_dma_handle_t *handlep)
+{
+	dev_info_t *pdip = ddi_get_parent(dip);
+
+	cardbus_err(dip, 10,
+	    "cardbus_dma_allochdl(dip=0x%p, rdip=0x%p)\n",
+	    (void *) dip, (void *) rdip);
+
+	if (pdip == NULL)
+		return (DDI_FAILURE);
+
+	cardbus_err(dip, 11,
+	    "cardbus_dma_allochdl calling %s - 0x%p\n",
+	    ddi_driver_name(pdip),
+	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_allochdl);
+
+	return (ddi_dma_allochdl(dip, rdip, attr, waitfp, arg, handlep));
+}
+
+static int
+cardbus_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
+		ddi_dma_handle_t handle)
+{
+	dev_info_t *pdip = ddi_get_parent(dip);
+
+	cardbus_err(dip, 10,
+	    "cardbus_dma_freehdl(dip=0x%p, rdip=0x%p)\n",
+	    (void *) dip, (void *) rdip);
+
+	if (pdip == NULL)
+		return (DDI_FAILURE);
+
+	cardbus_err(dip, 11,
+	    "cardbus_dma_freehdl calling %s - 0x%p\n",
+	    ddi_driver_name(pdip),
+	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_freehdl);
+
+	return (ddi_dma_freehdl(dip, rdip, handle));
+}
+
+static int
+cardbus_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
+		ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
+		ddi_dma_cookie_t *cp, uint_t *ccountp)
+{
+	dev_info_t *pdip = ddi_get_parent(dip);
+
+	cardbus_err(dip, 10,
+	    "cardbus_dma_bindhdl(dip=0x%p, rdip=0x%p)\n",
+	    (void *) dip, (void *) rdip);
+
+	if (pdip == NULL)
+		return (DDI_FAILURE);
+
+	cardbus_err(dip, 11,
+	    "cardbus_dma_bindhdl calling %s - 0x%p\n",
+	    ddi_driver_name(pdip),
+	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_bindhdl);
+
+	return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_bindhdl(pdip,
+	    rdip, handle, dmareq, cp, ccountp));
+}
+
+static int
+cardbus_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
+		ddi_dma_handle_t handle)
+{
+	dev_info_t *pdip = ddi_get_parent(dip);
+
+	cardbus_err(dip, 10,
+	    "cardbus_dma_unbindhdl(dip=0x%p, rdip=0x%p)\n",
+	    (void *) dip, (void *) rdip);
+
+	if (pdip == NULL)
+		return (DDI_FAILURE);
+
+	cardbus_err(dip, 11,
+	    "cardbus_dma_unbindhdl calling %s - 0x%p\n",
+	    ddi_driver_name(pdip),
+	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_unbindhdl);
+
+	return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_unbindhdl(pdip,
+	    rdip, handle));
+}
+
+static int
+cardbus_dma_flush(dev_info_t *dip, dev_info_t *rdip,
+		ddi_dma_handle_t handle, off_t off, size_t len,
+		uint_t cache_flags)
+{
+	dev_info_t *pdip = ddi_get_parent(dip);
+
+	cardbus_err(dip, 10,
+	    "cardbus_dma_flush(dip=0x%p, rdip=0x%p)\n",
+	    (void *) dip, (void *) rdip);
+
+	if (pdip == NULL)
+		return (DDI_FAILURE);
+
+	cardbus_err(dip, 11,
+	    "cardbus_dma_flush calling %s - 0x%p\n",
+	    ddi_driver_name(pdip),
+	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_flush);
+
+	return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_flush(pdip, rdip,
+	    handle, off, len, cache_flags));
+}
+
+static int
+cardbus_dma_win(dev_info_t *dip, dev_info_t *rdip,
+		ddi_dma_handle_t handle, uint_t win, off_t *offp,
+		size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
+{
+	dev_info_t *pdip = ddi_get_parent(dip);
+	cardbus_err(dip, 6,
+	    "cardbus_dma_win(dip=0x%p, rdip=0x%p)\n",
+	    (void *) dip, (void *) rdip);
+
+	if (pdip == NULL)
+		return (DDI_FAILURE);
+
+	cardbus_err(dip, 8,
+	    "cardbus_dma_win calling %s - 0x%p\n",
+	    ddi_driver_name(pdip),
+	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_win);
+
+	return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_win(pdip, rdip,
+	    handle, win, offp, lenp, cookiep, ccountp));
+}
+
+static int
+cardbus_dma_map(dev_info_t *dip, dev_info_t *rdip,
+		struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep)
+{
+	dev_info_t *pdip = ddi_get_parent(dip);
+
+	cardbus_err(dip, 10,
+	    "cardbus_dma_map(dip=0x%p, rdip=0x%p)\n",
+	    (void *) dip, (void *) rdip);
+
+	if (pdip == NULL)
+		return (DDI_FAILURE);
+
+	cardbus_err(dip, 11,
+	    "cardbus_dma_map calling %s - 0x%p\n",
+	    ddi_driver_name(pdip),
+	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_map);
+
+	return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_map(pdip, rdip,
+	    dmareqp, handlep));
+}
+
+static int
+cardbus_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
+		char *eventname, ddi_eventcookie_t *cookiep)
+{
+	cbus_t *cbp;
+	int	cb_instance;
+	int	rc;
+
+	/*
+	 * get the soft state structure for the bus instance.
+	 */
+	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "cbus-instance", -1);
+	ASSERT(cb_instance >= 0);
+	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
+
+	cardbus_err(dip, 6, "cardbus_get_eventcookie %s\n", eventname);
+
+	ASSERT(number_of_cardbus_cards != 0);
+
+	if (cbp->cb_ndi_event_hdl == NULL) {
+		/*
+		 * We can't handle up (probably called at the attachment
+		 * point) so pass it on up
+		 */
+		dev_info_t *pdip = ddi_get_parent(dip);
+		cardbus_err(dip, 8,
+		    "cardbus_get_eventcookie calling %s - 0x%p\n",
+		    ddi_driver_name(pdip),
+		    (void *)
+		    DEVI(pdip)->devi_ops->devo_bus_ops->bus_get_eventcookie);
+		return (DEVI(pdip)->devi_ops->devo_bus_ops->
+		    bus_get_eventcookie(pdip, rdip, eventname, cookiep));
+	}
+
+	cardbus_err(dip, 8,
+	    "cardbus_get_eventcookie calling ndi_event_retrieve_cookie\n");
+
+	rc = ndi_event_retrieve_cookie(cbp->cb_ndi_event_hdl, rdip, eventname,
+	    cookiep, NDI_EVENT_NOPASS);
+
+	cardbus_err(dip, 7,
+	    "cardbus_get_eventcookie rc %d cookie %p\n", rc, (void *)*cookiep);
+	return (rc);
+}
+
+static int
+cardbus_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
+		ddi_eventcookie_t cookie, void (*callback)(dev_info_t *dip,
+		ddi_eventcookie_t cookie, void *arg, void *bus_impldata),
+		void *arg, ddi_callback_id_t *cb_id)
+{
+	cbus_t *cbp;
+	int	cb_instance;
+	int	rc;
+
+	/*
+	 * get the soft state structure for the bus instance.
+	 */
+	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "cbus-instance", -1);
+	ASSERT(cb_instance >= 0);
+	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
+
+	cardbus_err(dip, 6, "cardbus_add_eventcall\n");
+
+	ASSERT(number_of_cardbus_cards != 0);
+
+	if (cbp->cb_ndi_event_hdl == NULL) {
+		/*
+		 * We can't handle up (probably called at the attachment
+		 * point) so pass it on up
+		 */
+		dev_info_t *pdip = ddi_get_parent(dip);
+		cardbus_err(dip, 8,
+		    "cardbus_add_eventcall calling %s - 0x%p\n",
+		    ddi_driver_name(pdip),
+		    (void *)
+		    DEVI(pdip)->devi_ops->devo_bus_ops->bus_add_eventcall);
+		return (DEVI(pdip)->devi_ops->devo_bus_ops->
+		    bus_add_eventcall(pdip, rdip, cookie, callback,
+		    arg, cb_id));
+	}
+
+	cardbus_err(dip, 8,
+	    "cardbus_add_eventcall calling ndi_event_add_callback\n");
+
+	rc = ndi_event_add_callback(cbp->cb_ndi_event_hdl, rdip, cookie,
+	    callback, arg, NDI_EVENT_NOPASS, cb_id);
+	cardbus_err(dip, 7,
+	    "cardbus_add_eventcall rc %d cookie %p\n", rc, (void *)cookie);
+	return (rc);
+}
+
+static int
+cardbus_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
+{
+	cbus_t *cbp;
+	int	cb_instance;
+
+	/*
+	 * get the soft state structure for the bus instance.
+	 */
+	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "cbus-instance", -1);
+	ASSERT(cb_instance >= 0);
+	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
+
+	cardbus_err(dip, 6, "cardbus_remove_eventcall\n");
+
+	ASSERT(number_of_cardbus_cards != 0);
+
+	if (cbp->cb_ndi_event_hdl == NULL) {
+		/*
+		 * We can't handle up (probably called at the attachment
+		 * point) so pass it on up
+		 */
+		dev_info_t *pdip = ddi_get_parent(dip);
+		cardbus_err(dip, 8,
+		    "cardbus_remove_eventcall calling %s - 0x%p\n",
+		    ddi_driver_name(pdip),
+		    (void *)
+		    DEVI(pdip)->devi_ops->devo_bus_ops->bus_remove_eventcall);
+		return (DEVI(pdip)->devi_ops->devo_bus_ops->
+		    bus_remove_eventcall(pdip, cb_id));
+	}
+
+	return (ndi_event_remove_callback(cbp->cb_ndi_event_hdl, cb_id));
+}
+
+static int
+cardbus_post_event(dev_info_t *dip, dev_info_t *rdip,
+		ddi_eventcookie_t cookie, void *bus_impldata)
+{
+	_NOTE(ARGUNUSED(rdip, cookie, bus_impldata))
+	cardbus_err(dip, 1, "cardbus_post_event()\n");
+	return (DDI_FAILURE);
+}
+
+#ifdef sparc
+
+static int cardbus_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
+		ddi_intr_handle_impl_t *hdlp);
+static int cardbus_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
+		ddi_intr_handle_impl_t *hdlp);
+static int cardbus_enable_intr_impl(dev_info_t *dip, dev_info_t *rdip,
+		ddi_intr_handle_impl_t *hdlp);
+static int cardbus_disable_intr_impl(dev_info_t *dip, dev_info_t *rdip,
+		ddi_intr_handle_impl_t *hdlp);
+
+/*ARGSUSED*/
+static int
+cardbus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
+	ddi_intr_handle_impl_t *hdlp, void *result)
+{
+	int ret = DDI_SUCCESS;
+
+#if defined(CARDBUS_DEBUG)
+	cardbus_err(dip, 8, "cardbus_intr_ops() intr_op=%d\n", (int)intr_op);
+#endif
+
+	switch (intr_op) {
+	case DDI_INTROP_GETCAP:
+		*(int *)result = DDI_INTR_FLAG_LEVEL;
+		break;
+	case DDI_INTROP_ALLOC:
+		*(int *)result = hdlp->ih_scratch1;
+		break;
+	case DDI_INTROP_FREE:
+		break;
+	case DDI_INTROP_GETPRI:
+		*(int *)result = hdlp->ih_pri ?
+		    hdlp->ih_pri : cardbus_get_class_pil(rdip);
+		break;
+	case DDI_INTROP_SETPRI:
+		break;
+	case DDI_INTROP_ADDISR:
+	case DDI_INTROP_REMISR:
+		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) {
+			cardbus_err(dip, 1, "Only fixed interrupts\n");
+			return (DDI_FAILURE);
+		}
+		break;
+	case DDI_INTROP_ENABLE:
+		ret = cardbus_enable_intr_impl(dip, rdip, hdlp);
+		break;
+	case DDI_INTROP_DISABLE:
+		ret = cardbus_disable_intr_impl(dip, rdip, hdlp);
+		break;
+	case DDI_INTROP_NINTRS:
+	case DDI_INTROP_NAVAIL:
+		*(int *)result = i_ddi_get_nintrs(rdip);
+		break;
+	case DDI_INTROP_SUPPORTED_TYPES:
+		*(int *)result = i_ddi_get_nintrs(rdip) ?
+		    DDI_INTR_TYPE_FIXED : 0;
+		break;
+	default:
+		ret = DDI_ENOTSUP;
+		break;
+	}
+
+	return (ret);
+}
+
+static int
+cardbus_enable_intr_impl(dev_info_t *dip, dev_info_t *rdip,
+		ddi_intr_handle_impl_t *hdlp)
+{
+	anp_t *anp = (anp_t *)ddi_get_driver_private(dip);
+	set_irq_handler_t sih;
+	uint_t socket = 0; /* We only support devices */
+			    /* with one socket per function */
+
+	ASSERT(anp != NULL);
+
+	cardbus_err(dip, 9,
+	    "cardbus_enable_intr_impl, intr=0x%p, arg1=0x%p, arg2=0x%p"
+	    "rdip=0x%p(%s)\n",
+	    (void *) hdlp->ih_cb_func,
+	    hdlp->ih_cb_arg1, hdlp->ih_cb_arg2,
+	    (void *) rdip, ddi_driver_name(rdip));
+
+	if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) {
+		cardbus_err(dip, 1, "Only fixed interrupts\n");
+		return (DDI_FAILURE);
+	}
+
+	sih.socket = socket;
+	sih.handler_id = (uint64_t)rdip;
+	sih.handler = (f_tt *)hdlp->ih_cb_func;
+	sih.arg1 = hdlp->ih_cb_arg1;
+	sih.arg2 = hdlp->ih_cb_arg2;
+	sih.irq = cardbus_get_class_pil(rdip);
+
+	if ((*anp->an_if->pcif_set_interrupt)(dip, &sih) != SUCCESS)
+		return (DDI_FAILURE);
+
+	return (DDI_SUCCESS);
+}
+
+static int
+cardbus_disable_intr_impl(dev_info_t *dip, dev_info_t *rdip,
+		ddi_intr_handle_impl_t *hdlp)
+{
+	anp_t *anp = (anp_t *)ddi_get_driver_private(dip);
+	clear_irq_handler_t cih;
+	uint_t socket = 0; /* We only support devices with 1 socket per */
+			    /* function. */
+
+	ASSERT(anp != NULL);
+
+	cardbus_err(dip, 9,
+	    "cardbus_disable_intr_impl, intr=0x%p, arg1=0x%p, arg2=0x%p"
+	    "rdip=0x%p(%s%d)\n",
+	    (void *) hdlp->ih_cb_func,
+	    hdlp->ih_cb_arg1, hdlp->ih_cb_arg2,
+	    (void *) rdip, ddi_driver_name(rdip), ddi_get_instance(rdip));
+
+	if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) {
+		cardbus_err(dip, 1, "Only fixed interrupts\n");
+		return (DDI_FAILURE);
+	}
+
+	cih.socket = socket;
+	cih.handler_id = (uint64_t)rdip;
+	cih.handler = (f_tt *)hdlp->ih_cb_func;
+
+	if ((*anp->an_if->pcif_clr_interrupt)(dip, &cih) != SUCCESS)
+		return (DDI_FAILURE);
+
+	return (DDI_SUCCESS);
+}
+
+#elif defined(__x86) || defined(__amd64)
+static int
+cardbus_intr_ops(dev_info_t *dip, dev_info_t *rdip,
+		ddi_intr_op_t op, ddi_intr_handle_impl_t *hdlp,
+		void *result)
+{
+	_NOTE(ARGUNUSED(dip));
+	return i_ddi_intr_ops(ddi_get_parent(rdip), ddi_get_parent(rdip),
+			op, (void *)hdlp, result);
+}
+
+#endif /* ifdef sparc */
+
+#if defined(CARDBUS_DEBUG)
+static int	cardbus_do_pprintf = 0;
+#endif
+
+/*PRINTFLIKE3*/
+void
+cardbus_err(dev_info_t *dip, int level, const char *fmt, ...)
+{
+	if (cardbus_debug && (level <= cardbus_debug)) {
+		va_list adx;
+		int	instance;
+		char	buf[256];
+		const char	*name;
+		char	*nl = "";
+#if !defined(CARDBUS_DEBUG)
+		int	ce;
+		char	qmark = 0;
+
+		if (level <= 3)
+			ce = CE_WARN;
+		else
+			ce = CE_CONT;
+		if (level == 4)
+			qmark = 1;
+#endif
+
+		if (dip) {
+			instance = ddi_get_instance(dip);
+			/* name = ddi_binding_name(dip); */
+			name = ddi_driver_name(dip);
+		} else {
+			instance = 0;
+			name = "";
+		}
+
+		va_start(adx, fmt);
+		/* vcmn_err(ce, fmt, adx); */
+		/* vprintf(fmt, adx); */
+		/* prom_vprintf(fmt, adx); */
+		(void) vsprintf(buf, fmt, adx);
+		va_end(adx);
+
+		if (buf[strlen(buf) - 1] != '\n')
+			nl = "\n";
+
+#if defined(CARDBUS_DEBUG)
+		if (cardbus_do_pprintf) {
+			if (dip) {
+				if (instance >= 0)
+					prom_printf("%s(%d),0x%p: %s%s",
+					    name, instance, dip, buf, nl);
+				else
+					prom_printf("%s,0x%p: %s%s", name,
+					    dip, buf, nl);
+			} else
+				prom_printf("%s%s", buf, nl);
+		} else {
+			if (dip) {
+				if (instance >= 0)
+					cmn_err(CE_CONT, "%s(%d),0x%p: %s%s",
+					    name, instance, (void *) dip,
+					    buf, nl);
+				else
+					cmn_err(CE_CONT, "%s,0x%p: %s%s",
+					    name, (void *) dip, buf, nl);
+			} else
+				cmn_err(CE_CONT, "%s%s", buf, nl);
+		}
+#else
+		if (dip)
+			cmn_err(ce, qmark ? "?%s%d: %s%s" : "%s%d: %s%s",
+			    name, instance, buf, nl);
+		else
+			cmn_err(ce, qmark ? "?%s%s" : "%s%s", buf, nl);
+#endif
+	}
+}
+
+static void cardbus_expand_busrange(dev_info_t *dip)
+{
+	dev_info_t *pdip;
+	cardbus_bus_range_t *bus_range;
+	int len;
+
+	pdip = ddi_get_parent(dip);
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, "bus-range",
+	    (caddr_t)&bus_range, &len) == DDI_PROP_SUCCESS) {
+		ndi_ra_request_t req;
+		uint64_t next_bus, blen;
+		uint32_t ret;
+		ddi_acc_handle_t handle;
+
+		if (bus_range->lo != bus_range->hi)
+			cardbus_err(pdip, 1, "cardbus_expand_busrange: "
+			    "%u -> %u\n", bus_range->lo, bus_range->hi);
+		else {
+
+			bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
+			req.ra_addr = bus_range->lo + 1;
+			req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
+			req.ra_len = 12;
+
+			while ((req.ra_len > 0) &&
+			    (ret = ndi_ra_alloc(ddi_get_parent(pdip), &req,
+			    &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
+			    NDI_RA_PASS)) != NDI_SUCCESS)
+				req.ra_len--;
+
+			if (ret != NDI_SUCCESS) {
+				cardbus_err(pdip, 1, "cardbus_expand_busrange: "
+				    "fail to allocate bus number\n");
+				goto exit;
+			}
+
+			bus_range->hi = bus_range->lo + req.ra_len;
+			if (ndi_prop_update_int_array(DDI_DEV_T_NONE, pdip,
+			    "bus-range", (int *)bus_range, 2) != DDI_SUCCESS) {
+				cardbus_err(pdip, 1, "cardbus_expand_busrange: "
+				    "fail to update bus-range property\n");
+				goto exit;
+			}
+
+			if (pci_config_setup(pdip, &handle) != DDI_SUCCESS) {
+				cardbus_err(pdip, 1, "cardbus_expand_busrange: "
+				    "fail to pci_config_setup\n");
+				goto exit;
+			}
+
+			pci_config_put8(handle, PCI_BCNF_SECBUS, bus_range->lo);
+			pci_config_put8(handle, PCI_BCNF_SUBBUS, bus_range->hi);
+
+			cardbus_err(pdip, 1, "cardbus_expand_busrange: "
+			    "parent dip %u -> %u\n",
+			    pci_config_get8(handle, PCI_BCNF_SECBUS),
+			    pci_config_get8(handle, PCI_BCNF_SUBBUS));
+			pci_config_teardown(&handle);
+
+			if (ndi_ra_map_setup(pdip, NDI_RA_TYPE_PCI_BUSNUM)
+			    != NDI_SUCCESS) {
+				cardbus_err(pdip, 1, "cardbus_expand_busrange: "
+				    "fail to ndi_ra_map_setup of bus number\n");
+				goto exit;
+			}
+
+			(void) ndi_ra_free(pdip,
+			    (uint64_t)bus_range->lo + 1, req.ra_len,
+			    NDI_RA_TYPE_PCI_BUSNUM, 0);
+		}
+
+		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
+		req.ra_len = 2;
+
+		while ((req.ra_len > 0) &&
+		    (ret = ndi_ra_alloc(pdip, &req,
+		    &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
+		    0)) != NDI_SUCCESS)
+			req.ra_len--;
+
+		cardbus_err(dip, 1, "cardbus_expand_busrange: "
+		    "cardbus dip base %u length %d\n",
+		    (int)next_bus, (int)req.ra_len);
+
+		if (ret != NDI_SUCCESS) {
+			cardbus_err(dip, 1, "cardbus_expand_busrange: "
+			    "fail to allocate bus number of length %d "
+			    "from parent\n",
+			    (int)req.ra_len);
+			goto exit;
+		}
+
+		if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_BUSNUM)
+		    != NDI_SUCCESS) {
+			cardbus_err(dip, 1, "cardbus_expand_busrange: "
+			    "fail to ndi_ra_map_setup of bus numbers\n");
+			goto exit;
+		}
+
+		(void) ndi_ra_free(dip,
+		    (uint64_t)next_bus, req.ra_len,
+		    NDI_RA_TYPE_PCI_BUSNUM, 0);
+exit:
+		kmem_free(bus_range, len);
+
+	} else
+		cardbus_err(pdip, 1, "cardbus_expand_busrange: "
+		    "parent dip doesn't have busrange prop\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/cardbus/cardbus.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+/*
+ * Copyright (c)  * Copyright (c) 2001 Tadpole Technology plc
+ * All rights reserved.
+ */
+
+#ifndef	_SYS_CARDBUS_H
+#define	_SYS_CARDBUS_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define	CB_BCNF_BCNTRL_ISA_INT_ENAB	0x0080
+#define	CB_BCNF_BCNTRL_MEM0_PREF	0x0100
+#define	CB_BCNF_BCNTRL_MEM1_PREF	0x0200
+#define	CB_BCNF_BCNTRL_WRITE_POST	0x0400
+
+typedef struct cb_nexus_cb {
+	void	(*enable_intr)(dev_info_t *);
+	void	(*disable_intr)(dev_info_t *);
+} cb_nexus_cb_t;
+
+typedef enum { PCIHP_SOFT_STATE_CLOSED, PCIHP_SOFT_STATE_OPEN,
+		PCIHP_SOFT_STATE_OPEN_EXCL } cbhp_soft_state_t;
+
+/*
+ * Main softstate per cardbus device
+ */
+typedef struct cardbus_dev {
+	int	cb_instance;
+	boolean_t fatal_problem;
+	dev_info_t *cb_dip;
+	kmutex_t cb_mutex;
+	cb_nexus_cb_t *cb_nex_ops;
+	struct dev_ops cb_dops;
+	struct dev_ops *orig_dopsp;
+	struct bus_ops *orig_bopsp;
+	struct cb_deviceset_props *cb_dsp;
+	ndi_event_hdl_t	cb_ndi_event_hdl;
+	ndi_event_set_t	cb_ndi_events;
+#ifdef HOTPLUG
+	/* Nexus specific variables */
+	ap_rstate_t	rstate;		/* state of Receptacle */
+	ap_ostate_t	ostate;		/* state of the Occupant */
+	ap_condition_t	condition;	/* condition of the occupant */
+	cbhp_soft_state_t	soft_state;
+	uint32_t	event_mask;	/* last event mask registerd */
+	boolean_t	auto_config;
+	boolean_t	disabled;
+	char	*name;
+
+	/* Slot specific variables */
+	char	ap_id[32];		/* Attachment point name */
+	char	*nexus_path;		/* Pathname of Nexus */
+	hpc_slot_ops_t	*slot_ops;	/* Ptr HPC entry points */
+	hpc_slot_info_t	slot_info;	/* Bus Specific SlotInfo */
+	hpc_slot_t	slot_handle;	/* HPS slot handle */
+	boolean_t card_present;
+	hpc_led_state_t leds[4];
+#endif
+} cbus_t;
+
+typedef struct cardbus_bus_range {
+	uint32_t lo;
+	uint32_t hi;
+} cardbus_bus_range_t;
+
+typedef struct cardbus_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;
+
+} cardbus_range_t;
+
+#if defined(DEBUG)
+#define	CARDBUS_DEBUG
+#endif
+
+#ifdef CARDBUS_DEBUG
+extern void prom_printf(const char *, ...);
+#endif
+
+extern int cardbus_debug;
+
+#ifdef _KERNEL
+extern int cardbus_attach(dev_info_t *, cb_nexus_cb_t *);
+extern boolean_t cardbus_load_cardbus(dev_info_t *, uint_t, uint32_t);
+extern void cardbus_unload_cardbus(dev_info_t *);
+extern void cardbus_err(dev_info_t *dip, int level, const char *fmt, ...);
+
+/* The following only exists for hotplug support */
+extern int cardbus_open(dev_t *, int, int, cred_t *);
+extern int cardbus_close(dev_t, int, int, cred_t *);
+extern int cardbus_ioctl(dev_t, int, intptr_t, int, cred_t *,
+	    int *);
+extern boolean_t cardbus_is_cb_minor(dev_t);
+extern boolean_t cardbus_can_suspend(dev_info_t *);
+#endif
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif	/* _SYS_CARDBUS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/cardbus/cardbus_cfg.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,4600 @@
+/*
+ * 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.
+ */
+/*
+ * Copyright (c)  * Copyright (c) 2001 Tadpole Technology plc
+ * All rights reserved.
+ * From "@(#)pcicfg.c   1.31    99/06/18 SMI"
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Cardbus configurator
+ */
+
+#include <sys/ddi.h>
+#include <sys/sunndi.h>
+#include <sys/ndi_impldefs.h>
+
+#include <sys/pci.h>
+#include <sys/ebus.h>
+#include <sys/hotplug/hpctrl.h>
+#include <sys/hotplug/pci/pcicfg.h>
+
+#include <sys/pctypes.h>
+#include <sys/pcmcia.h>
+
+#include <sys/isa_defs.h>
+
+#include <sys/note.h>
+
+#include <sys/ethernet.h>
+
+#include "cardbus.h"
+#include "cardbus_parse.h"
+#include "cardbus_cfg.h"
+
+/*
+ * ************************************************************************
+ * *** Implementation specific local data structures/definitions.       ***
+ * ************************************************************************
+ */
+
+#define	PCICFG_MAX_DEVICE 32
+#define	PCICFG_MAX_FUNCTION 8
+
+static uint32_t pcicfg_max_device = PCICFG_MAX_DEVICE;
+static uint32_t pcicfg_max_function = PCICFG_MAX_FUNCTION;
+
+#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	CBCFG_MEMGRAN 0x1000
+#define	CBCFG_IOGRAN 0x4
+
+#define	PCICFG_MEM_MULT 4
+#define	PCICFG_IO_MULT 4
+#define	PCICFG_RANGE_LEN 2 /* Number of range entries */
+
+/*
+ * ISA node declaration structure.
+ */
+struct isa_node {
+	char	*name;
+	char	*compatible[5];
+	char	*type;
+	char	*model;
+	uint16_t	reg;
+	uint16_t	span;
+};
+
+struct cardbus_name_entry {
+	uint32_t class_code;
+	char  *name;
+	int pil;
+};
+
+struct cardbus_find_ctrl {
+	uint_t		bus;
+	uint_t		device;
+	uint_t		function;
+	dev_info_t	*dip;
+};
+
+#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)))
+
+typedef struct cardbus_phdl cardbus_phdl_t;
+
+struct cardbus_phdl {
+
+	dev_info_t	*dip;	/* Associated with the attach point */
+	cardbus_phdl_t  *next;
+
+	uint64_t	memory_base;    /* Memory base for this attach point */
+	uint64_t	memory_last;
+	uint64_t	memory_len;
+	uint32_t	memory_gran;
+	uint32_t	io_base;	/* I/O base for this attach point */
+	uint32_t	io_last;
+	uint32_t	io_len;
+	uint32_t	io_gran;
+
+	int	error;
+	uint_t	highest_bus;    /* Highest bus seen on the probe */
+	ndi_ra_request_t mem_req;	/* allocator request for memory */
+	ndi_ra_request_t io_req;	/* allocator request for I/O */
+};
+
+typedef struct {
+	dev_info_t  *dip;	/* Associated with the attach point */
+	ddi_acc_handle_t handle;    /* open handle on parent PCI config space */
+	uint32_t    io_base;	/* I/O base for this attach point */
+	int	io_decode_reg;
+} isa_phdl_t;
+
+
+/*
+ * forward declarations for routines defined in this module (called here)
+ */
+static cardbus_phdl_t *cardbus_find_phdl(dev_info_t *dip);
+static cardbus_phdl_t *cardbus_create_phdl(dev_info_t *dip);
+static int cardbus_destroy_phdl(dev_info_t *dip);
+static int cardbus_program_ap(dev_info_t *);
+static void cardbus_topbridge_assign(dev_info_t *, cardbus_phdl_t *);
+static int cardbus_bridge_ranges(dev_info_t *, cardbus_phdl_t *,
+			ddi_acc_handle_t);
+static int cardbus_bridge_assign(dev_info_t *, void *);
+static int cardbus_isa_bridge_ranges(dev_info_t *dip, cardbus_phdl_t *entry,
+			ddi_acc_handle_t handle);
+static int cardbus_add_isa_reg(dev_info_t *, void *);
+static int cardbus_allocate_chunk(dev_info_t *, uint8_t, uint8_t);
+static int cardbus_free_chunk(dev_info_t *);
+static void cardbus_setup_bridge(dev_info_t *, cardbus_phdl_t *,
+			ddi_acc_handle_t);
+static void cardbus_update_bridge(dev_info_t *, cardbus_phdl_t *,
+			ddi_acc_handle_t);
+static void cardbus_get_mem(dev_info_t *, cardbus_phdl_t *, uint32_t,
+			uint64_t *);
+static void cardbus_get_io(dev_info_t *, cardbus_phdl_t *, uint32_t,
+			uint32_t *);
+static int cardbus_sum_resources(dev_info_t *, void *);
+static int cardbus_free_bridge_resources(dev_info_t *);
+static int cardbus_free_device_resources(dev_info_t *);
+static int cardbus_free_resources(dev_info_t *);
+static int cardbus_probe_bridge(cbus_t *, dev_info_t *, uint_t,
+			uint_t, uint_t);
+static int cardbus_probe_children(cbus_t *, dev_info_t *, uint_t, uint_t,
+			uint_t, uint8_t *);
+static int cardbus_add_config_reg(dev_info_t *, uint_t, uint_t, uint_t);
+static int cardbus_add_isa_node(cbus_t *, dev_info_t *, struct isa_node *);
+static int cardbus_config_setup(dev_info_t *, ddi_acc_handle_t *);
+static void cardbus_config_teardown(ddi_acc_handle_t *);
+static void cardbus_reparent_children(dev_info_t *, dev_info_t *);
+static int cardbus_update_assigned_prop(dev_info_t *, pci_regspec_t *);
+static int cardbus_update_available_prop(dev_info_t *, uint32_t,
+			uint64_t, uint64_t);
+static int cardbus_update_ranges_prop(dev_info_t *, cardbus_range_t *);
+static int cardbus_update_reg_prop(dev_info_t *dip, uint32_t regvalue,
+			uint_t reg_offset);
+static int cardbus_set_standard_props(dev_info_t *parent, dev_info_t *dip,
+			ddi_acc_handle_t config_handle);
+static int cardbus_set_isa_props(dev_info_t *parent, dev_info_t *dip,
+			char *name, char *compat[]);
+static int cardbus_set_busnode_props(dev_info_t *);
+static int cardbus_set_busnode_isaprops(dev_info_t *);
+static int cardbus_set_childnode_props(dev_info_t *dip,
+			ddi_acc_handle_t config_handle);
+static void cardbus_set_bus_numbers(ddi_acc_handle_t config_handle,
+			uint_t primary, uint_t secondary);
+static void enable_pci_isa_bridge(dev_info_t *dip,
+			ddi_acc_handle_t config_handle);
+static void enable_pci_pci_bridge(dev_info_t *dip,
+			ddi_acc_handle_t config_handle);
+static void enable_cardbus_bridge(dev_info_t *dip,
+			ddi_acc_handle_t config_handle);
+static void disable_pci_pci_bridge(dev_info_t *dip,
+			ddi_acc_handle_t config_handle);
+static void disable_cardbus_bridge(dev_info_t *dip,
+			ddi_acc_handle_t config_handle);
+static void enable_cardbus_device(dev_info_t *, ddi_acc_handle_t);
+static void disable_cardbus_device(ddi_acc_handle_t config_handle);
+static void cardbus_force_boolprop(dev_info_t *dip, char *pname);
+static void cardbus_force_intprop(dev_info_t *dip, char *pname,
+			int *pval, int len);
+static void cardbus_force_stringprop(dev_info_t *dip, char *pname,
+			char *pval);
+static void split_addr(char *, int *, int *);
+#ifdef DEBUG
+static void cardbus_dump_common_config(ddi_acc_handle_t config_handle);
+static void cardbus_dump_device_config(ddi_acc_handle_t config_handle);
+static void cardbus_dump_bridge_config(ddi_acc_handle_t config_handle,
+			uint8_t header_type);
+static void cardbus_dump_config(ddi_acc_handle_t config_handle);
+static void cardbus_dump_reg(dev_info_t *dip, const pci_regspec_t *regspec,
+			int nelems);
+#endif
+
+static cardbus_phdl_t *cardbus_phdl_list = NULL;
+
+static struct cardbus_name_entry cardbus_class_lookup [] = {
+	{ 0x001, "display", 9 },
+	{ 0x100, "scsi", 4 },
+	{ 0x101, "ide", 4 },
+	{ 0x102, "fdc", 4 },
+	{ 0x103, "ipi", 4 },
+	{ 0x104, "raid", 4 },
+	{ 0x200, "ethernet", 6 },
+	{ 0x201, "token-ring", 6 },
+	{ 0x202, "fddi", 6 },
+	{ 0x203, "atm", 6 },
+	{ 0x300, "display", 9 },    /* VGA card */
+	{ 0x380, "display", 9 },    /* other - for the Raptor Card */
+	{ 0x400, "video", 11 },
+	{ 0x401, "sound", 11 },
+	{ 0x500, "memory", 11 },
+	{ 0x501, "flash", 11 },
+	{ 0x600, "host", 11 },
+	{ 0x601, "isa", 11 },
+	{ 0x602, "eisa", 11 },
+	{ 0x603, "mca", 11 },
+	{ 0x604, "pci", 11 },
+	{ 0x605, "pcmcia", 11 },
+	{ 0x606, "nubus", 11 },
+	{ 0x607, "cardbus", 11 },
+	{ 0x680, NULL, 8 },
+	{ 0x700, "serial", 11 },
+	{ 0x701, "parallel", 6 },
+	{ 0x800, "interrupt-controller", 3 },
+	{ 0x801, "dma-controller", 3 },
+	{ 0x802, "timer", 3 },
+	{ 0x803, "rtc", 3 },
+	{ 0x900, "keyboard", 8 },
+	{ 0x901, "pen", 8 },
+	{ 0x902, "mouse", 8 },
+	{ 0xa00, "dock", 1 },
+	{ 0xb00, "cpu", 1 },
+	{ 0xc00, "firewire", 9 },
+	{ 0xc01, "access-bus", 4 },
+	{ 0xc02, "ssa", 4 },
+	{ 0xc03, "usb", 9 },
+	{ 0xc04, "fibre-channel", 6 },
+	{ 0, 0 }
+};
+
+#ifndef _DONT_USE_1275_GENERIC_NAMES
+static char *cardbus_get_class_name(uint32_t classcode);
+#endif /* _DONT_USE_1275_GENERIC_NAMES */
+
+/*
+ * Reprogram ILINE with default value only if BIOS doesn't program it
+ */
+int
+cardbus_validate_iline(dev_info_t *dip, ddi_acc_handle_t handle)
+{
+	uint8_t intline = 0xff;
+
+	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
+	intline = pci_config_get8(handle, PCI_CONF_ILINE);
+	if ((intline == 0) || (intline == 0xff)) {
+		intline = ddi_getprop(DDI_DEV_T_ANY, dip,
+			DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
+			"interrupt-line", 0xff);
+		if (intline == (uint8_t)0xff) {
+			intline = ddi_getprop(DDI_DEV_T_ANY,
+				ddi_get_parent(dip),
+				DDI_PROP_CANSLEEP /* |DDI_PROP_DONTPASS */,
+				"interrupt-line", 0xb);
+		}
+
+		pci_config_put8(handle, PCI_CONF_ILINE, intline);
+	}
+	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+		"interrupt-line", intline);
+	}
+	return (intline);
+}
+
+/*
+ * 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
+cardbus_configure(cbus_t *cbp)
+{
+	uint_t bus;
+	int cardbus_dev, func;
+	dev_info_t *attach_point;
+
+	cardbus_err(cbp->cb_dip, 6, "cardbus_configure ()\n");
+
+	bus = cardbus_primary_busno(cbp->cb_dip);
+
+	if (ndi_devi_alloc(cbp->cb_dip, DEVI_PSEUDO_NEXNAME,
+	    (pnode_t)DEVI_SID_NODEID,
+	    &attach_point) != NDI_SUCCESS) {
+		cardbus_err(cbp->cb_dip, 1,
+		    "cardbus_configure(): Failed to alloc probe node\n");
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * Node name marks this node as the "attachment point".
+	 */
+	if (ndi_devi_set_nodename(attach_point,
+	    "hp_attachment", 0) != NDI_SUCCESS) {
+	    cardbus_err(cbp->cb_dip, 1,
+		    "Failed to set nodename for attachment node\n");
+		(void) ndi_devi_free(attach_point);
+		return (PCICFG_FAILURE);
+	}
+
+	cardbus_err(ddi_get_parent(attach_point), 8,
+	    "Set bus type to cardbus\n");
+	(void) ddi_prop_update_string(DDI_DEV_T_NONE,
+	    ddi_get_parent(attach_point), PCM_DEVICETYPE,
+	    "cardbus");
+
+	split_addr(ddi_get_name_addr(cbp->cb_dip), &cardbus_dev, &func);
+
+	cardbus_err(attach_point, 8,
+	    "Configuring [0x%x][0x%x][0x%x]\n", bus, cardbus_dev, func);
+
+	switch (cardbus_probe_bridge(cbp, attach_point,
+	    bus, cardbus_dev, func)) {
+	case PCICFG_FAILURE:
+		cardbus_err(cbp->cb_dip, 4,
+		    "configure failed: bus [0x%x] slot [0x%x] func [0x%x]\n",
+		    bus, cardbus_dev, func);
+		goto cleanup;
+	case PCICFG_NODEVICE:
+		cardbus_err(cbp->cb_dip, 4,
+		    "no device: bus [0x%x] slot [0x%x] func [0x%x]\n",
+		    bus, cardbus_dev, func);
+		goto cleanup;
+	default:
+		cardbus_err(cbp->cb_dip, 9,
+		    "configure: bus => [%d] slot => [%d] func => [%d]\n",
+		    bus, cardbus_dev, func);
+		break;
+	}
+
+	if (cardbus_program_ap(cbp->cb_dip) == PCICFG_SUCCESS) {
+		(void) cardbus_reparent_children(attach_point, cbp->cb_dip);
+		(void) ndi_devi_free(attach_point);
+		cbp->cb_nex_ops->enable_intr(cbp->cb_dip);
+		return (PCICFG_SUCCESS);
+	}
+
+	cardbus_err(cbp->cb_dip, 1, "Failed to program devices\n");
+
+cleanup:
+	/*
+	 * Clean up a partially created "probe state" tree.
+	 * There are no resources allocated to the in the
+	 * probe state.
+	 */
+
+	cardbus_err(cbp->cb_dip, 6,
+	    "Look up device [0x%x] function [0x%x] to clean up\n",
+	    cardbus_dev, func);
+
+	cardbus_err(cbp->cb_dip, 6,
+	    "Cleaning up device [0x%x] function [0x%x]\n",
+	    cardbus_dev, func);
+
+	/*
+	 * If this was a bridge device it will have a
+	 * probe handle - if not, no harm in calling this.
+	 */
+	(void) cardbus_destroy_phdl(cbp->cb_dip);
+
+	if (ddi_get_child(attach_point)) {
+		/*
+		 * This will free up the node
+		 */
+		(void) ndi_devi_offline(ddi_get_child(attach_point),
+		    NDI_UNCONFIG|NDI_DEVI_REMOVE);
+	}
+	(void) ndi_devi_free(attach_point);
+
+	return (PCICFG_FAILURE);
+}
+
+int
+cardbus_unconfigure(cbus_t *cbp)
+{
+	ddi_acc_handle_t config_handle;
+	dev_info_t *dip = cbp->cb_dip;
+
+	cbp->cb_nex_ops->disable_intr(dip);
+	if (pci_config_setup(dip, &config_handle) == DDI_SUCCESS) {
+		disable_cardbus_bridge(dip, config_handle);
+		(void) pci_config_teardown(&config_handle);
+	} else {
+		cardbus_err(dip, 1,
+		    "cardbus_unconfigure(): Failed to setup config space\n");
+	}
+
+	(void) cardbus_free_chunk(dip);
+	cardbus_err(dip, 6,
+	    "cardbus_unconfigure: calling cardbus_free_bridge_resources\n");
+	(void) cardbus_free_bridge_resources(dip);
+
+	return (PCICFG_SUCCESS);
+}
+
+int
+cardbus_teardown_device(dev_info_t *dip)
+{
+	/*
+	 * Free up resources associated with 'dip'
+	 */
+
+	if (cardbus_free_resources(dip) != PCICFG_SUCCESS) {
+		cardbus_err(dip, 1,
+		    "cardbus_teardown_device: Failed to free resources\n");
+		return (PCICFG_FAILURE);
+	}
+
+	if (ndi_devi_offline(dip, NDI_DEVI_REMOVE) != NDI_SUCCESS) {
+		cardbus_err(dip, 1,
+		    "cardbus_teardown_device: "
+		    "Failed to offline and remove node\n");
+		return (PCICFG_FAILURE);
+	}
+
+	return (PCICFG_SUCCESS);
+}
+
+/*
+ * Get the primary pci bus number. This should be the lowest number
+ * in the bus-range property of our parent.
+ */
+int
+cardbus_primary_busno(dev_info_t *dip)
+{
+	int	len, rval;
+	char	bus_type[16] = "(unknown)";
+	dev_info_t *par = ddi_get_parent(dip);
+	cardbus_bus_range_t *bus_range;
+
+	ASSERT(strcmp(ddi_driver_name(dip), "pcic") == 0);
+	len = sizeof (bus_type);
+	if ((ddi_prop_op(DDI_DEV_T_ANY, par, PROP_LEN_AND_VAL_BUF,
+	    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
+	    "device_type",
+	    (caddr_t)&bus_type, &len) == DDI_SUCCESS)) {
+		ASSERT((strcmp(bus_type, "pci") == 0) ||
+		    (strcmp(bus_type, "cardbus") == 0));
+		if (ddi_getlongprop(DDI_DEV_T_ANY, par, 0, "bus-range",
+		    (caddr_t)&bus_range, &len) == DDI_PROP_SUCCESS) {
+			cardbus_err(dip, 9,
+			    "cardbus_primary_busno: bus range is %d to %d\n",
+			    bus_range->lo, bus_range->hi);
+			rval = (int)bus_range->lo;
+			kmem_free((caddr_t)bus_range, len);
+			return (rval);
+		}
+	}
+
+	cardbus_err(dip, 2,
+	    "cardbus_primary_busno: Not a pci device or no bus-range\n");
+	return (-1);
+}
+
+static cardbus_phdl_t *
+cardbus_find_phdl(dev_info_t *dip)
+{
+	cardbus_phdl_t *entry;
+
+	mutex_enter(&cardbus_list_mutex);
+	for (entry = cardbus_phdl_list; entry != NULL; entry = entry->next) {
+		if (entry->dip == dip) {
+			mutex_exit(&cardbus_list_mutex);
+			return (entry);
+		}
+	}
+	mutex_exit(&cardbus_list_mutex);
+
+	/*
+	 * Did'nt find entry - create one
+	 */
+	return (cardbus_create_phdl(dip));
+}
+
+static cardbus_phdl_t *
+cardbus_create_phdl(dev_info_t *dip)
+{
+	cardbus_phdl_t *new;
+
+	new = (cardbus_phdl_t *)kmem_zalloc(sizeof (cardbus_phdl_t), KM_SLEEP);
+
+	new->dip = dip;
+	new->io_gran = CBCFG_IOGRAN;
+	new->memory_gran = CBCFG_MEMGRAN;
+	mutex_enter(&cardbus_list_mutex);
+	new->next = cardbus_phdl_list;
+	cardbus_phdl_list = new;
+	mutex_exit(&cardbus_list_mutex);
+
+	return (new);
+}
+
+static int
+cardbus_destroy_phdl(dev_info_t *dip)
+{
+	cardbus_phdl_t *entry;
+	cardbus_phdl_t *follow = NULL;
+
+	mutex_enter(&cardbus_list_mutex);
+	for (entry = cardbus_phdl_list; entry != NULL; follow = entry,
+	    entry = entry->next) {
+		if (entry->dip == dip) {
+			if (entry == cardbus_phdl_list) {
+				cardbus_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(dip,
+				    entry->memory_base, entry->memory_len,
+				    NDI_RA_TYPE_MEM, NDI_RA_PASS);
+#ifdef  _LP64
+				cardbus_err(dip, 8,
+				    "cardbus_destroy_phdl: "
+				    "MEMORY BASE = [0x%lx] length [0x%lx]\n",
+				    entry->memory_base, entry->memory_len);
+#else
+				cardbus_err(dip, 8,
+				    "cardbus_destroy_phdl: "
+				    "MEMORY BASE = [0x%llx] length [0x%llx]\n",
+				    entry->memory_base, entry->memory_len);
+#endif
+			}
+			if (entry->io_len > 0) {
+				(void) ndi_ra_free(dip,
+				    entry->io_base, entry->io_len,
+				    NDI_RA_TYPE_IO, NDI_RA_PASS);
+				cardbus_err(dip, 8,
+				    "cardbus_destroy_phdl: "
+				    "IO BASE = [0x%x] length [0x%x]\n",
+				    entry->io_base, entry->io_len);
+			}
+			/*
+			 * Destroy this entry
+			 */
+			kmem_free((caddr_t)entry, sizeof (cardbus_phdl_t));
+			mutex_exit(&cardbus_list_mutex);
+			return (PCICFG_SUCCESS);
+		}
+	}
+
+	mutex_exit(&cardbus_list_mutex);
+
+	/*
+	 * Didn't find the entry
+	 */
+	return (PCICFG_FAILURE);
+}
+
+static int
+cardbus_program_ap(dev_info_t *dip)
+{
+	cardbus_phdl_t *phdl;
+	uint8_t header_type, sec_bus;
+	ddi_acc_handle_t handle;
+
+	if (pci_config_setup(dip, &handle) != DDI_SUCCESS) {
+		cardbus_err(dip, 1,
+		    "cardbus_program_ap: Failed to map config space!\n");
+		return (PCICFG_FAILURE);
+	}
+
+	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
+	sec_bus = pci_config_get8(handle, PCI_BCNF_SECBUS);
+
+	cardbus_err(dip, 6,
+	    "cardbus_program_ap (header_type=0x%x)\n", header_type);
+	(void) pci_config_teardown(&handle);
+
+	/*
+	 * Header type two is PCI to Cardbus bridge, see page 43 of the
+	 * CL-PD6832 data sheet
+	 */
+	switch (header_type & PCI_HEADER_TYPE_M) {
+	case PCI_HEADER_CARDBUS:
+		cardbus_err(dip, 8,
+		    "cardbus_program_ap calling cardbus_allocate_chunk\n");
+		if (cardbus_allocate_chunk(dip,
+		    header_type & PCI_HEADER_TYPE_M,
+		    sec_bus) != PCICFG_SUCCESS) {
+			cardbus_err(dip, 1,
+			    "cardbus_program_ap: "
+			    "Not enough memory to hotplug\n");
+			(void) cardbus_destroy_phdl(dip);
+			return (PCICFG_FAILURE);
+		}
+
+		cardbus_err(dip, 8,
+		    "cardbus_program_ap calling cardbus_find_phdl\n");
+		phdl = cardbus_find_phdl(dip);
+		ASSERT(phdl);
+
+		if (phdl == NULL) {
+			cardbus_err(dip, 1, "cardbus_find_phdl failed\n");
+			return (PCICFG_FAILURE);
+		}
+		phdl->error = PCICFG_SUCCESS;
+		cardbus_err(dip, 8,
+		    "cardbus_program_ap calling cardbus_topbridge_assign\n");
+		cardbus_topbridge_assign(dip, phdl);
+
+		if (phdl->error != PCICFG_SUCCESS) {
+			cardbus_err(dip, 1, "Problem assigning bridge\n");
+			(void) cardbus_destroy_phdl(dip);
+			return (phdl->error);
+		}
+		break;
+
+	default:
+		return (PCICFG_FAILURE);
+	}
+
+	return (PCICFG_SUCCESS);
+}
+
+static void
+cardbus_topbridge_assign(dev_info_t *dip, cardbus_phdl_t *entry)
+{
+	ddi_acc_handle_t handle;
+	uint8_t header_type;
+
+	cardbus_err(dip, 6, "cardbus_topbridge_assign\n");
+
+	if (pci_config_setup(dip, &handle) != DDI_SUCCESS) {
+		cardbus_err(dip, 1,
+		    "cardbus_topbridge_bridge_assign: "
+		    "Failed to map config space!\n");
+		return;
+	}
+
+	header_type = pci_config_get8(handle,
+	    PCI_CONF_HEADER) & PCI_HEADER_TYPE_M;
+
+	/* cardbus bridge is the same as PCI-PCI bridge */
+	ASSERT((header_type == PCI_HEADER_PPB) ||
+	    (header_type == PCI_HEADER_CARDBUS));
+
+	(void) cardbus_bridge_ranges(dip, entry, handle);
+
+	(void) pci_config_teardown(&handle);
+}
+
+static int
+cardbus_bridge_ranges(dev_info_t *dip, cardbus_phdl_t *entry,
+			ddi_acc_handle_t handle)
+{
+	cardbus_range_t range[PCICFG_RANGE_LEN];
+	int bus_range[2];
+	int count;
+	int i;
+
+	cardbus_err(dip, 8, "cardbus_bridge_ranges\n");
+
+	bzero((caddr_t)range, sizeof (cardbus_range_t) * PCICFG_RANGE_LEN);
+
+	(void) cardbus_setup_bridge(dip, entry, handle);
+
+	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), cardbus_bridge_assign, (void *)entry);
+	ndi_devi_exit(dip, count);
+
+	(void) cardbus_update_bridge(dip, entry, handle);
+
+	bus_range[0] = pci_config_get8(handle, PCI_BCNF_SECBUS);
+	bus_range[1] = pci_config_get8(handle, PCI_BCNF_SUBBUS);
+
+	cardbus_err(dip, 8,
+	    "Set up bus-range property to %u->%u\n",
+	    bus_range[0], bus_range[1]);
+
+	if ((i = ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
+	    "bus-range",
+	    bus_range, 2)) != DDI_SUCCESS) {
+
+		if (i == DDI_PROP_NOT_FOUND) {
+			cardbus_err(dip, 8,
+			    "Create bus-range property, %u->%u\n",
+			    bus_range[0], bus_range[1]);
+			i = ddi_prop_create(DDI_DEV_T_NONE, dip,
+			    DDI_PROP_CANSLEEP,
+			    "bus-range", (caddr_t)bus_range,
+			    sizeof (bus_range));
+		}
+
+		if (i != DDI_PROP_SUCCESS) {
+			cardbus_err(dip, 1,
+			    "Failed to set bus-range property, %u->%u (%d)\n",
+			    bus_range[0], bus_range[1], i);
+			entry->error = PCICFG_FAILURE;
+			return (DDI_WALK_TERMINATE);
+		}
+	}
+
+	if (entry->io_len > 0) {
+		range[0].size_lo = entry->io_last - entry->io_base;
+		if (cardbus_update_ranges_prop(dip, &range[0])) {
+			cardbus_err(dip, 1, "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 (cardbus_update_ranges_prop(dip, &range[1])) {
+			cardbus_err(dip, 1,
+			    "Failed to update ranges (memory)\n");
+			entry->error = PCICFG_FAILURE;
+			return (DDI_WALK_TERMINATE);
+		}
+	}
+
+	return (DDI_WALK_PRUNECHILD);
+}
+static int
+cardbus_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, request;
+	uint8_t header_type, base_class;
+	cardbus_phdl_t *entry = (cardbus_phdl_t *)hdl;
+
+	/*
+	 * Ignore the attachment point and pcs.
+	 */
+	if (strcmp(ddi_binding_name(dip), "hp_attachment") == 0 ||
+	    strcmp(ddi_binding_name(dip), "pcs") == 0) {
+		cardbus_err(dip, 8, "cardbus_bridge_assign: Ignoring\n");
+		return (DDI_WALK_CONTINUE);
+	}
+
+
+	cardbus_err(dip, 6, "cardbus_bridge_assign\n");
+
+	if (entry == NULL) {
+		cardbus_err(dip, 1, "Failed to get entry\n");
+		return (DDI_WALK_TERMINATE);
+	}
+	if (cardbus_config_setup(dip, &handle) != DDI_SUCCESS) {
+		cardbus_err(dip, 1,
+		    "cardbus_bridge_assign: Failed to map config space!\n");
+		entry->error = PCICFG_FAILURE;
+		return (DDI_WALK_TERMINATE);
+	}
+
+	header_type = pci_config_get8(handle, PCI_CONF_HEADER) &
+		PCI_HEADER_TYPE_M;
+	base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
+
+	/*
+	 * This function is not called for the top bridge and we are
+	 * not enumerating down a further cardbus interface yet!
+	 */
+	if (base_class == PCI_CLASS_BRIDGE) {
+		uint8_t	sub_class;
+
+		sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
+
+		switch (sub_class) {
+		case PCI_BRIDGE_PCI:
+			if (header_type == PCI_HEADER_PPB) {
+				i = cardbus_bridge_ranges(dip, entry, handle);
+				(void) cardbus_config_teardown(&handle);
+				return (i);
+			}
+			goto bad_device;
+
+		case PCI_BRIDGE_ISA:
+			i = cardbus_isa_bridge_ranges(dip, entry, handle);
+			(void) cardbus_config_teardown(&handle);
+			return (i);
+
+		case PCI_BRIDGE_CARDBUS:
+			/*
+			 * Fall through, there should be at least one register
+			 * set for this.
+			 */
+			break;
+
+		case PCI_BRIDGE_OTHER:
+		default:
+			break;
+		}
+	}
+
+#ifdef sparc
+	/*
+	 * 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);
+	}
+#else
+	(void) cardbus_validate_iline(dip, handle);
+#endif
+
+	/*
+	 * 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) {
+		cardbus_err(dip, 1, "Failed to read reg property\n");
+		entry->error = PCICFG_FAILURE;
+		(void) cardbus_config_teardown(&handle);
+		return (DDI_WALK_TERMINATE);
+	}
+
+	rcount = length / sizeof (pci_regspec_t);
+	cardbus_err(dip, 9, "rcount = %d\n", rcount);
+
+	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) cardbus_get_mem(ddi_get_parent(dip),
+				    entry, reg[i].pci_size_low, &mem_answer);
+				ASSERT(!PCICFG_HIADDR(mem_answer));
+				pci_config_put32(handle, offset,
+				    PCICFG_LOADDR(mem_answer));
+				pci_config_put32(handle, offset + 4,
+				    PCICFG_HIADDR(mem_answer));
+				cardbus_err(dip, 8,
+				    "REGISTER (64)LO [0x%x] ----> [0x%02x]\n",
+				    pci_config_get32(handle, offset), offset);
+				cardbus_err(dip, 8,
+				    "REGISTER (64)HI [0x%x] ----> [0x%02x]\n",
+				    pci_config_get32(handle, offset+4),
+					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) cardbus_get_mem(ddi_get_parent(dip),
+				    entry, reg[i].pci_size_low, &mem_answer);
+				pci_config_put32(handle, offset, 0xffffffff);
+				request = pci_config_get32(handle, offset);
+
+				pci_config_put32(handle, offset,
+				    (uint32_t)mem_answer);
+				reg[i].pci_phys_low = (uint32_t)mem_answer;
+				reg[i].pci_phys_mid = 0;
+				if (((PCI_BASE_TYPE_M & request) ==
+					PCI_BASE_TYPE_ALL) &&
+				    ((PCI_BASE_SPACE_M & request) ==
+					PCI_BASE_SPACE_MEM)) {
+					cardbus_err(dip, 8,
+					    "REGISTER (64)LO [0x%x] ----> "
+					    "[0x%02x]\n",
+					    pci_config_get32(handle, offset),
+						offset);
+					    pci_config_put32(handle,
+						offset + 4, 0);
+					cardbus_err(dip, 8,
+					    "REGISTER (64)HI [0x%x] ----> "
+					    "[0x%02x]\n",
+					    pci_config_get32(handle, offset+4),
+						offset+4);
+				} else {
+					cardbus_err(dip, 8,
+					    "REGISTER (32)LO [0x%x] ----> "
+					    "[0x%02x]\n",
+					    pci_config_get32(handle, offset),
+					    offset);
+				}
+				break;
+
+			case PCI_REG_ADDR_G(PCI_ADDR_IO):
+				/* allocate I/O space from the allocator */
+
+				(void) cardbus_get_io(ddi_get_parent(dip),
+				    entry, reg[i].pci_size_low, &io_answer);
+				pci_config_put32(handle, offset, io_answer);
+				cardbus_err(dip, 8,
+				    "REGISTER (I/O)LO [0x%x] ----> [0x%02x]\n",
+				    pci_config_get32(handle, offset), offset);
+				reg[i].pci_phys_low = io_answer;
+				break;
+
+			default:
+				cardbus_err(dip, 1, "Unknown register type\n");
+				kmem_free(reg, length);
+				(void) cardbus_config_teardown(&handle);
+				entry->error = PCICFG_FAILURE;
+				return (DDI_WALK_TERMINATE);
+			} /* switch */
+
+			/*
+			 * Now that memory locations are assigned,
+			 * update the assigned address property.
+			 */
+			if (cardbus_update_assigned_prop(dip,
+			    &reg[i]) != PCICFG_SUCCESS) {
+				kmem_free(reg, length);
+				(void) cardbus_config_teardown(&handle);
+				entry->error = PCICFG_FAILURE;
+				return (DDI_WALK_TERMINATE);
+			}
+		}
+	}
+	kmem_free(reg, length);
+	enable_cardbus_device(dip, handle);
+#ifdef CARDBUS_DEBUG
+	if (cardbus_debug >= 9) {
+		cardbus_dump_config(handle);
+	}
+#endif
+bad_device:
+	(void) cardbus_config_teardown(&handle);
+	return (DDI_WALK_CONTINUE);
+}
+
+static int
+cardbus_isa_bridge_ranges(dev_info_t *dip, cardbus_phdl_t *entry,
+			ddi_acc_handle_t handle)
+{
+	struct ebus_pci_rangespec range;
+	int count;
+	pci_regspec_t *reg;
+	int length;
+	int rcount;
+	uint32_t io_answer = 0xffffffff;
+	isa_phdl_t isa_phdl;
+	int i;
+
+	cardbus_err(dip, 8, "cardbus_isa_bridge_ranges\n");
+
+	bzero((caddr_t)&range, sizeof (range));
+
+#ifdef sparc
+	/*
+	 * 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);
+	}
+#else
+	(void) cardbus_validate_iline(dip, handle);
+#endif
+
+	/*
+	 * For each "reg" property with a length, allocate memory.
+	 */
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
+	    &length) != DDI_PROP_SUCCESS) {
+		cardbus_err(dip, 1, "Failed to read reg property\n");
+		entry->error = PCICFG_FAILURE;
+		return (DDI_WALK_TERMINATE);
+	}
+
+	rcount = length / sizeof (pci_regspec_t);
+
+	for (i = 0; i < rcount; i++) {
+		if ((reg[i].pci_size_low != 0) || (reg[i].pci_size_hi != 0)) {
+			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
+			case PCI_REG_ADDR_G(PCI_ADDR_IO):
+				/* allocate I/O space from the allocator */
+
+				(void) cardbus_get_io(ddi_get_parent(dip),
+				    entry, reg[i].pci_size_low, &io_answer);
+				cardbus_err(dip, 8,
+				    "ISA (I/O)LO ----> [0x%x]\n", io_answer);
+				reg[i].pci_phys_low = io_answer;
+				range.phys_hi = 0;
+				range.phys_low = io_answer;
+				range.par_phys_hi = reg[i].pci_phys_hi |
+						PCI_REG_REL_M;
+				range.par_phys_low = reg[i].pci_phys_low;
+				range.par_phys_mid = reg[i].pci_phys_mid;
+				range.rng_size = reg[i].pci_size_low;
+				i = rcount;
+				break;
+
+			default:
+				cardbus_err(dip, 1, "Unknown register type\n");
+				kmem_free(reg, length);
+				(void) cardbus_config_teardown(&handle);
+				entry->error = PCICFG_FAILURE;
+				return (DDI_WALK_TERMINATE);
+			} /* switch */
+		}
+	}
+	kmem_free(reg, length);
+
+	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
+	    dip, "ranges", (int *)&range,
+	    sizeof (range)/sizeof (int));
+	if (io_answer != 0xffffffff) {
+		isa_phdl.dip = dip;
+		isa_phdl.handle = handle;
+		isa_phdl.io_base = io_answer;
+		isa_phdl.io_decode_reg = 0x58; /* Pos decoded IO space 0 reg */
+		/* i_ndi_block_device_tree_changes(&count); */
+		ndi_devi_enter(dip, &count);
+		ddi_walk_devs(ddi_get_child(dip),
+			cardbus_add_isa_reg, (void *)&isa_phdl);
+		/* i_ndi_allow_device_tree_changes(count); */
+		ndi_devi_exit(dip, count);
+	}
+	return (DDI_WALK_PRUNECHILD);
+}
+
+/*
+ * This is specific to ITE8888 chip.
+ */
+static int
+cardbus_add_isa_reg(dev_info_t *dip, void *arg)
+{
+	uint32_t	io_reg = 0;
+	int		length;
+	uint32_t	reg[3], *breg;
+	isa_phdl_t	*phdl;
+	uint8_t		sz;
+
+	phdl = (isa_phdl_t *)arg;
+	cardbus_err(dip, 6,
+	    "cardbus_add_isa_reg, base 0x%x\n", phdl->io_base);
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "basereg", (caddr_t)&breg,
+	    &length) != DDI_PROP_SUCCESS) {
+		return (DDI_WALK_CONTINUE);
+	}
+
+	if ((length / sizeof (reg)) < 1) {
+		kmem_free(breg, length);
+		return (DDI_WALK_CONTINUE);
+	}
+
+	/*
+	 * Add the "reg" property.
+	 */
+	reg[0] = 0;
+	reg[1] = breg[1] + phdl->io_base;
+	reg[2] = breg[2];
+
+	/*
+	 * Generate the postive IO decode register setting.
+	 */
+	for (sz = 0; sz < 8; sz++)
+		if ((1<<sz) >= breg[2]) {
+			io_reg = breg[1]
+			    | (1uL <<31) /* Enable */
+			    | (2uL <<29) /* Medium speed */
+			    | (1uL <<28) /* Aliase enable, */
+					/* Don't care A[15:10] */
+			    | (sz<<24); /* Size code */
+			break;
+		}
+
+	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
+	    "reg", (int *)reg, 3);
+	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "basereg");
+
+	if (io_reg) {
+		pci_config_put32(phdl->handle, phdl->io_decode_reg, io_reg);
+		cardbus_err(dip, 6,
+		    "cardbus_add_isa_reg: I/O decode reg (0x%x) set to 0x%x\n",
+		    phdl->io_decode_reg,
+		    pci_config_get32(phdl->handle, phdl->io_decode_reg));
+		phdl->io_decode_reg += sizeof (io_reg);
+	} else
+		cardbus_err(dip, 1,
+		    "cardbus_add_isa_reg: register size (0x%x) too large\n",
+		    breg[2]);
+	kmem_free(breg, length);
+	return (DDI_WALK_CONTINUE);
+}
+
+/*
+ * In case we want to ensure that some space is allocated to the
+ * device tree below the cardbus bridge.
+ * This is only necessary if there is a device that needs to allocate
+ * resource below us. This can happen if there is another cardbus/PCMCIA
+ * bridge downstream.
+ */
+static uint32_t cardbus_min_spare_mem = 0;
+static uint32_t cardbus_min_spare_io = 0;
+
+/*
+ * 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
+cardbus_allocate_chunk(dev_info_t *dip, uint8_t type, uint8_t sec_bus)
+{
+	cardbus_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 = cardbus_find_phdl(dip);
+	ASSERT(phdl);
+
+	mem_request = &phdl->mem_req;
+	io_request  = &phdl->io_req;
+
+	/*
+	 * Set highest_bus here.
+	 * Otherwise if we don't find another bridge
+	 * this never gets set.
+	 */
+	phdl->highest_bus = sec_bus;
+
+	/*
+	 * 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".
+	 */
+	phdl->error = PCICFG_SUCCESS;
+	ndi_devi_enter(dip, &count);
+	ddi_walk_devs(ddi_get_child(dip), cardbus_sum_resources, (void *)phdl);
+	ndi_devi_exit(dip, count);
+
+	if (phdl->error != PCICFG_SUCCESS) {
+		cardbus_err(dip, 1, "Failure summing resources\n");
+		return (phdl->error);
+	}
+
+	/*
+	 * Call into the memory allocator with the request.
+	 * Record the addresses returned in the phdl
+	 */
+#ifdef  _LP64
+	cardbus_err(dip, 8,
+	    "AP requires [0x%lx] bytes of memory space, alligned 0x%x\n",
+	    mem_request->ra_len, phdl->memory_gran);
+	cardbus_err(dip, 8,
+	    "AP requires [0x%lx] bytes of I/O space, alligned 0x%x\n",
+	    io_request->ra_len, phdl->io_gran);
+#else
+	cardbus_err(dip, 8,
+	    "AP requires [0x%llx] bytes of memory space, alligned 0x%x\n",
+	    mem_request->ra_len, phdl->memory_gran);
+	cardbus_err(dip, 8,
+	    "AP requires [0x%llx] bytes of I/O space, alligned 0x%x\n",
+	    io_request->ra_len, phdl->io_gran);
+#endif
+
+	ASSERT(type == PCI_HEADER_CARDBUS);
+
+	mem_request->ra_align_mask = phdl->memory_gran - 1;
+	io_request->ra_align_mask = phdl->io_gran - 1;
+
+	mem_request->ra_len += cardbus_min_spare_mem;
+	if (mem_request->ra_len) {
+		mem_request->ra_len = PCICFG_ROUND_UP(
+					mem_request->ra_len,
+					phdl->memory_gran);
+#ifdef _LP64
+		cardbus_err(dip, 8,
+		    "cardbus_allocate_chunk: ndi_ra_alloc 0x%lx bytes\n",
+		    mem_request->ra_len);
+#else
+		cardbus_err(dip, 8,
+		    "cardbus_allocate_chunk: ndi_ra_alloc 0x%llx bytes\n",
+		    mem_request->ra_len);
+#endif
+
+		if (ndi_ra_alloc(dip, mem_request, &mem_answer, &alen,
+		    NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
+			cardbus_err(dip, 1, "Failed to allocate memory\n");
+			return (PCICFG_FAILURE);
+		}
+
+		phdl->memory_base = phdl->memory_last = mem_answer;
+		phdl->memory_len = alen;
+	}
+
+	io_request->ra_len += cardbus_min_spare_io;
+	if (io_request->ra_len) {
+
+		io_request->ra_boundbase = 0;
+		io_request->ra_boundlen = PCICFG_4GIG_LIMIT;
+		io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
+		io_request->ra_len = PCICFG_ROUND_UP(io_request->ra_len,
+				phdl->io_gran);
+
+		if (ndi_ra_alloc(dip, io_request, &io_answer,
+		    &alen, NDI_RA_TYPE_IO, NDI_RA_PASS) != NDI_SUCCESS) {
+			cardbus_err(dip, 1, "Failed to allocate I/O space\n");
+			if (mem_request->ra_len) {
+				(void) ndi_ra_free(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;
+	}
+
+#ifdef  _LP64
+	cardbus_err(dip, 6,
+	    "MEMORY BASE = [0x%lx] length [0x%lx]\n",
+	    phdl->memory_base, phdl->memory_len);
+#else
+	cardbus_err(dip, 6,
+	    "MEMORY BASE = [0x%llx] length [0x%llx]\n",
+	    phdl->memory_base, phdl->memory_len);
+#endif
+	cardbus_err(dip, 6,
+	    "IO BASE = [0x%x] length [0x%x]\n",
+	    phdl->io_base, phdl->io_len);
+
+	return (PCICFG_SUCCESS);
+}
+
+static int
+cardbus_free_chunk(dev_info_t *dip)
+{
+	uint_t	*bus;
+	int	k;
+
+	cardbus_err(dip, 6, "cardbus_free_chunk\n");
+
+	(void) cardbus_destroy_phdl(dip);
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
+	    &k) != DDI_PROP_SUCCESS) {
+		cardbus_err(dip, 1,
+		    "cardbus_free_chunk: Failed to read bus-range property\n");
+		return (PCICFG_FAILURE);
+	}
+
+	cardbus_err(dip, 6,
+	    "cardbus_free_chunk: Freeing bus [%d] range [%d]\n",
+	    bus[0], bus[1] - bus[0] + 1);
+
+	if (ndi_ra_free(dip,
+	    (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
+	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
+		cardbus_err(dip, 1,
+		    "cardbus_free_chunk: Failed to free bus numbers\n");
+
+		kmem_free(bus, k);
+		return (PCICFG_FAILURE);
+	}
+
+	kmem_free(bus, k);
+	return (PCICFG_SUCCESS);
+}
+
+/*
+ * Put bridge registers into initial state
+ */
+static void
+cardbus_setup_bridge(dev_info_t *dip, cardbus_phdl_t *entry,
+		ddi_acc_handle_t handle)
+{
+	uint8_t header_type = pci_config_get8(handle, PCI_CONF_HEADER);
+
+#ifdef _LP64
+	cardbus_err(NULL, 6,
+	    "cardbus_setup_bridge: "
+	    "highest bus %d, mem_last 0x%lx, io_last 0x%x\n",
+	    entry->highest_bus, entry->memory_last, entry->io_last);
+#else
+	cardbus_err(NULL, 6,
+	    "cardbus_setup_bridge: "
+	    "highest bus %d, mem_last 0x%llx, io_last 0x%x\n",
+	    entry->highest_bus, entry->memory_last, entry->io_last);
+#endif
+
+	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
+		uint32_t uval;
+
+		/*
+		 * The highest bus seen during probing is
+		 * the max-subordinate bus
+		 */
+		pci_config_put8(handle, PCI_BCNF_SUBBUS, entry->highest_bus);
+
+		uval = PCICFG_ROUND_UP(entry->memory_last, PCICFG_MEMGRAN);
+		if (uval != entry->memory_last) {
+#ifdef _LP64
+			cardbus_err(dip, 8,
+			    "Adding [0x%lx] before bridge (mem)\n",
+			    uval - entry->memory_last);
+#else
+			cardbus_err(dip, 8,
+			    "Adding [0x%llx] before bridge (mem)\n",
+			    uval - entry->memory_last);
+#endif
+			(void) cardbus_get_mem(ddi_get_parent(dip), entry,
+			    uval - entry->memory_last, NULL);
+		}
+
+		/*
+		 * Program the memory base register with the
+		 * start of the memory range
+		 */
+#ifdef _LP64
+		cardbus_err(NULL, 8,
+		    "store 0x%x(0x%lx) in pci bridge memory base register\n",
+		    PCICFG_HIWORD(PCICFG_LOADDR(uval)),
+		    entry->memory_last);
+#else
+		cardbus_err(NULL, 8,
+		    "store 0x%x(0x%llx) in pci bridge memory base register\n",
+		    PCICFG_HIWORD(PCICFG_LOADDR(uval)),
+		    entry->memory_last);
+#endif
+		pci_config_put16(handle, PCI_BCNF_MEM_BASE,
+		    PCICFG_HIWORD(PCICFG_LOADDR(uval)));
+
+		uval = PCICFG_ROUND_UP(entry->io_last, PCICFG_IOGRAN);
+		if (uval != entry->io_last) {
+			cardbus_err(dip, 8,
+			    "Adding [0x%x] before bridge (I/O)\n",
+			    uval - entry->io_last);
+			(void) cardbus_get_io(ddi_get_parent(dip), entry,
+			    uval - entry->io_last, NULL);
+		}
+		cardbus_err(NULL, 8,
+		    "store 0x%02x/0x%04x(0x%x) in "
+		    "pci bridge I/O hi/low base register\n",
+		    PCICFG_HIWORD(PCICFG_LOADDR(uval)),
+		    PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(uval))),
+		    entry->io_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(uval))));
+
+		pci_config_put16(handle, PCI_BCNF_IO_BASE_HI,
+		    PCICFG_HIWORD(PCICFG_LOADDR(uval)));
+
+		/*
+		 * 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);
+
+#ifdef sparc
+		/*
+		 * 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);
+		}
+#else
+		(void) cardbus_validate_iline(dip, handle);
+#endif
+
+
+	} else if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_CARDBUS) {
+
+		/*
+		 * The highest bus seen during probing is
+		 * the max-subordinate bus
+		 */
+		pci_config_put8(handle, PCI_CBUS_SUB_BUS_NO,
+		    entry->highest_bus);
+
+		/*
+		 * Program the memory base register with the
+		 * start of the memory range
+		 */
+#ifdef _LP64
+		cardbus_err(NULL, 8,
+		    "store 0x%x(0x%lx) in "
+		    "cardbus memory base register 0, len 0x%lx\n",
+		    PCICFG_LOADDR(entry->memory_last), entry->memory_last,
+		    entry->memory_len);
+#else
+		cardbus_err(NULL, 8,
+		    "store 0x%x(0x%llx) in "
+		    "cardbus memory base register 0, len 0x%llx\n",
+		    PCICFG_LOADDR(entry->memory_last), entry->memory_last,
+		    entry->memory_len);
+#endif
+
+		pci_config_put32(handle, PCI_CBUS_MEM_BASE0,
+		    PCICFG_LOADDR(entry->memory_last));
+
+		/*
+		 * Program the I/O base register with the start of the I/O range
+		 */
+		cardbus_err(NULL, 8,
+		    "store 0x%x in cb IO base register 0 len 0x%x\n",
+		    PCICFG_LOADDR(entry->io_last),
+		    entry->io_len);
+
+		pci_config_put32(handle, PCI_CBUS_IO_BASE0,
+		    PCICFG_LOADDR(entry->io_last));
+
+		/*
+		 * Clear status bits
+		 */
+		pci_config_put16(handle, PCI_CBUS_SEC_STATUS, 0xffff);
+
+#ifdef sparc
+		/*
+		 * 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);
+		}
+#else
+		(void) cardbus_validate_iline(dip, handle);
+#endif
+
+
+		/*
+		 * LATER: use these registers
+		 */
+		pci_config_put32(handle, PCI_CBUS_MEM_BASE1, 0);
+		pci_config_put32(handle, PCI_CBUS_MEM_LIMIT1, 0);
+		pci_config_put32(handle, PCI_CBUS_IO_BASE1, 0);
+		pci_config_put32(handle, PCI_CBUS_IO_LIMIT1, 0);
+	} else {
+		cmn_err(CE_WARN, "header type 0x%x, probably unknown bridge\n",
+		    header_type & PCI_HEADER_TYPE_M);
+	}
+
+	cardbus_err(NULL, 7, "cardbus_setup_bridge complete\n");
+}
+
+static void
+cardbus_update_bridge(dev_info_t *dip, cardbus_phdl_t *entry,
+		ddi_acc_handle_t handle)
+{
+	uint_t length;
+	uint16_t word16 = pci_config_get16(handle, PCI_CONF_COMM);
+	const	uint8_t header_type = pci_config_get8(handle, PCI_CONF_HEADER)
+			& PCI_HEADER_TYPE_M;
+	uint32_t bridge_gran;
+	uint64_t rlval;
+
+	if (header_type == PCI_HEADER_CARDBUS)
+		bridge_gran = CBCFG_MEMGRAN;
+	else
+		bridge_gran = PCICFG_MEMGRAN;
+
+	/*
+	 * Program the memory limit register with the end of the memory range
+	 */
+#ifdef _LP64
+	cardbus_err(dip, 6,
+	    "cardbus_update_bridge: Mem base 0x%lx len 0x%lx "
+	    "last 0x%lx gran 0x%x gran end 0x%lx\n",
+	    entry->memory_base, entry->memory_len,
+	    entry->memory_last, entry->memory_gran,
+	    PCICFG_ROUND_UP(entry->memory_last, entry->memory_gran));
+#else
+	cardbus_err(dip, 6,
+	    "cardbus_update_bridge: Mem base 0x%llx len 0x%llx "
+	    "last 0x%llx gran 0x%x gran end 0x%lx\n",
+	    entry->memory_base, entry->memory_len,
+	    entry->memory_last, entry->memory_gran,
+	    PCICFG_ROUND_UP(entry->memory_last, entry->memory_gran));
+#endif
+	/*
+	 * 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.
+	 */
+	length = PCICFG_ROUND_UP(entry->memory_last + cardbus_min_spare_mem,
+	    bridge_gran) - entry->memory_last;
+
+	if (length > 0) {
+		/*
+		 * This is to allow space that isn't actually being used by
+		 * anything to be allocated by devices such as a downstream
+		 * PCMCIA controller.
+		 */
+		(void) cardbus_get_mem(dip, entry, length, NULL);
+		cardbus_err(dip, 8,
+		    "Added [0x%x] at the top of the bridge (mem)\n", length);
+	}
+
+	if (entry->memory_len) {
+		if (header_type == PCI_HEADER_CARDBUS) {
+			rlval = PCICFG_ROUND_DOWN(entry->memory_last - 1,
+			    CBCFG_MEMGRAN);
+#ifdef _LP64
+			cardbus_err(dip, 8,
+			    "store 0x%x(0x%lx) in memory limit register 0\n",
+			    PCICFG_LOADDR(rlval), rlval);
+#else
+			cardbus_err(dip, 8,
+			    "store 0x%x(0x%llx) in memory limit register 0\n",
+			    PCICFG_LOADDR(rlval), rlval);
+#endif
+			pci_config_put32(handle, PCI_CBUS_MEM_LIMIT0,
+			    PCICFG_LOADDR(rlval));
+		} else {
+			rlval = PCICFG_ROUND_DOWN(entry->memory_last - 1,
+			    PCICFG_MEMGRAN);
+#ifdef _LP64
+			cardbus_err(dip, 8,
+			    "store 0x%x(0x%lx) in memory limit register\n",
+			    PCICFG_HIWORD(PCICFG_LOADDR(rlval)),
+			    rlval);
+#else
+			cardbus_err(dip, 8,
+			    "store 0x%x(0x%llx) in memory limit register\n",
+			    PCICFG_HIWORD(PCICFG_LOADDR(rlval)),
+			    rlval);
+#endif
+			pci_config_put16(handle, PCI_BCNF_MEM_LIMIT,
+			    PCICFG_HIWORD(PCICFG_LOADDR(rlval)));
+		}
+		word16 |= PCI_COMM_MAE;
+	}
+
+	cardbus_err(dip, 6,
+	    "cardbus_update_bridge: I/O base 0x%x len 0x%x last 0x%x "
+	    "gran 0x%x gran_end 0x%lx\n",
+	    entry->io_base, entry->io_len, entry->io_last, entry->io_gran,
+	    PCICFG_ROUND_UP(entry->io_last, entry->io_gran));
+
+	if (header_type == PCI_HEADER_CARDBUS)
+		bridge_gran = CBCFG_IOGRAN;
+	else
+		bridge_gran = 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.
+	 */
+	length = PCICFG_ROUND_UP(entry->io_last + cardbus_min_spare_io,
+	    bridge_gran) - entry->io_last;
+	if (length > 0) {
+		(void) cardbus_get_io(dip, entry, length, NULL);
+		cardbus_err(dip, 8,
+		    "Added [0x%x] at the top of the bridge (I/O)\n",  length);
+	}
+
+	/*
+	 * Program the I/O limit register with the end of the I/O range
+	 */
+	if (entry->io_len) {
+		if (header_type == PCI_HEADER_CARDBUS) {
+			rlval = PCICFG_ROUND_DOWN(entry->io_last - 1,
+			    CBCFG_IOGRAN);
+#ifdef _LP64
+			cardbus_err(dip, 8,
+			    "store 0x%lx in IO limit register 0\n", rlval);
+#else
+			cardbus_err(dip, 8,
+			    "store 0x%llx in IO limit register 0\n", rlval);
+#endif
+			pci_config_put32(handle, PCI_CBUS_IO_LIMIT0, rlval);
+		} else {
+			rlval = PCICFG_ROUND_DOWN(entry->io_last - 1,
+			    PCICFG_IOGRAN);
+#ifdef _LP64
+			cardbus_err(dip, 8,
+			    "store 0x%x/0x%x(0x%lx) in "
+			    "IO limit low/hi register\n",
+			    PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(rlval))),
+			    PCICFG_HIWORD(PCICFG_LOADDR(rlval)),
+			    rlval);
+#else
+			cardbus_err(dip, 8,
+			    "store 0x%x/0x%x(0x%llx) in "
+			    "IO limit low/hi register\n",
+			    PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(rlval))),
+			    PCICFG_HIWORD(PCICFG_LOADDR(rlval)),
+			    rlval);
+#endif
+
+			pci_config_put8(handle, PCI_BCNF_IO_LIMIT_LOW,
+			    PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(rlval))));
+			pci_config_put16(handle, PCI_BCNF_IO_LIMIT_HI,
+			    PCICFG_HIWORD(PCICFG_LOADDR(rlval)));
+		}
+		word16 |= PCI_COMM_IO;
+	}
+
+	pci_config_put16(handle, PCI_CONF_COMM, word16);
+}
+
+static void
+cardbus_get_mem(dev_info_t *dip, cardbus_phdl_t *entry,
+		uint32_t length, uint64_t *ans)
+{
+	uint32_t hole;
+
+#ifdef  _LP64
+	cardbus_err(NULL, 6,
+	    "cardbus_get_mem: memory_last 0x%lx, length 0x%x, "
+	    "memory_base 0x%lx, memory_len 0x%lx ans=0x%p\n",
+	    entry->memory_last, length,
+	    entry->memory_base, entry->memory_len, (void *) ans);
+#else
+	cardbus_err(NULL, 6,
+	    "cardbus_get_mem: memory_last 0x%llx, length 0x%x, "
+	    "memory_base 0x%llx, memory_len 0x%llx ans=0x%p\n",
+	    entry->memory_last, length,
+	    entry->memory_base, entry->memory_len, (void *) ans);
+#endif
+
+	if (ans) {
+		/*
+		 * Round up the request to the "size" boundary
+		 */
+		hole = PCICFG_ROUND_UP(entry->memory_last, length)
+			- entry->memory_last;
+		if (hole != 0) {
+			(void) cardbus_update_available_prop(dip,
+			    PCI_ADDR_MEM32,
+			    entry->memory_last,
+			    (uint64_t)hole);
+			entry->memory_last += hole;
+
+#ifdef  _LP64
+			cardbus_err(NULL, 6,
+			    "cardbus_get_mem: "
+			    "rounded memory_last up by 0x%x to 0x%lx, ",
+			    hole, entry->memory_last);
+#else
+			cardbus_err(NULL, 6,
+			    "cardbus_get_mem: "
+			    "rounded memory_last up by 0x%x to 0x%llx, ",
+			    hole, entry->memory_last);
+#endif
+		}
+	} else
+		(void) cardbus_update_available_prop(dip, PCI_ADDR_MEM32,
+			entry->memory_last,
+			(uint64_t)length);
+
+	/*
+	 * These routines should parcel out the memory
+	 * completely.  There should never be a case of
+	 * over running the bounds.
+	 */
+	if ((entry->memory_last + length) >
+	    (entry->memory_base + entry->memory_len))
+#ifdef  _LP64
+		cardbus_err(NULL, 1,
+		    "cardbus_get_mem: assert will fail %ld <= %ld,"
+		    "(0x%lx + 0x%x) <= (0x%lx + 0x%lx)\n",
+#else
+		cardbus_err(NULL, 1,
+		    "cardbus_get_mem: assert will fail %lld <= %lld, "
+		    "(0x%llx + 0x%x) <= (0x%llx + 0x%llx)\n",
+#endif
+		    entry->memory_last + length,
+		    entry->memory_base + entry->memory_len,
+		    entry->memory_last,
+		    length,
+		    entry->memory_base,
+		    entry->memory_len);
+
+	ASSERT((entry->memory_last + length) <=
+	(entry->memory_base + entry->memory_len));
+	/*
+	 * If ans is NULL don't return anything,
+	 * they are just asking to reserve the memory.
+	 */
+	if (ans != NULL)
+		*ans = entry->memory_last;
+
+	/*
+	 * Increment to the next location
+	 */
+	entry->memory_last += length;
+}
+
+static void
+cardbus_get_io(dev_info_t *dip, cardbus_phdl_t *entry,
+		uint32_t length, uint32_t *ans)
+{
+	uint32_t	hole;
+
+	cardbus_err(NULL, 6,
+	    "cardbus_get_io: io_last 0x%x, length 0x%x, "
+	    "io_base 0x%x, io_len 0x%x ans=0x%p\n",
+	    entry->io_last, length,
+	    entry->io_base, entry->io_len, (void *) ans);
+
+	if (ans) {
+		/*
+		 * Round up the request to the "size" boundary
+		 */
+		hole = PCICFG_ROUND_UP(entry->io_last, length) - entry->io_last;
+		if (hole != 0) {
+			(void) cardbus_update_available_prop(dip, PCI_ADDR_IO,
+			    (uint64_t)entry->io_last,
+			    (uint64_t)hole);
+			entry->io_last += hole;
+
+			cardbus_err(NULL, 6,
+			    "cardbus_get_io: "
+			    "rounded io_last up by 0x%x to 0x%x, ",
+			    hole, entry->io_last);
+		}
+	} else
+		(void) cardbus_update_available_prop(dip, PCI_ADDR_IO,
+		    (uint64_t)entry->io_last,
+		    (uint64_t)length);
+	/*
+	 * These routines should parcel out the memory
+	 * completely.  There should never be a case of
+	 * over running the bounds.
+	 */
+	ASSERT((entry->io_last + length) <=
+	    (entry->io_base + entry->io_len));
+
+	/*
+	 * If ans is NULL don't return anything,
+	 * they are just asking to reserve the memory.
+	 */
+	if (ans != NULL)
+		*ans = entry->io_last;
+
+	/*
+	 * Increment to the next location
+	 */
+	entry->io_last += length;
+}
+
+static int
+cardbus_sum_resources(dev_info_t *dip, void *hdl)
+{
+	cardbus_phdl_t *entry = (cardbus_phdl_t *)hdl;
+	pci_regspec_t *pci_rp;
+	int length;
+	int rcount;
+	int i, ret;
+	ndi_ra_request_t *mem_request;
+	ndi_ra_request_t *io_request;
+	uint8_t header_type, base_class;
+	ddi_acc_handle_t handle;
+
+	/*
+	 * Ignore the attachment point and pcs.
+	 */
+	if (strcmp(ddi_binding_name(dip), "hp_attachment") == 0 ||
+	    strcmp(ddi_binding_name(dip), "pcs") == 0) {
+		cardbus_err(dip, 8, "cardbus_sum_resources: Ignoring\n");
+		return (DDI_WALK_CONTINUE);
+	}
+
+	mem_request = &entry->mem_req;
+	io_request =  &entry->io_req;
+
+	if (cardbus_config_setup(dip, &handle) != DDI_SUCCESS) {
+		cardbus_err(dip, 1,
+		    "cardbus_sum_resources: Failed to map config space!\n");
+		entry->error = PCICFG_FAILURE;
+		return (DDI_WALK_TERMINATE);
+	}
+
+	ret = DDI_WALK_CONTINUE;
+	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
+	base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
+
+	/*
+	 * If its a bridge - just record the highest bus seen
+	 */
+	if (base_class == PCI_CLASS_BRIDGE) {
+		uint8_t	sub_class;
+
+		sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
+
+		switch (sub_class) {
+		case PCI_BRIDGE_PCI:
+			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) cardbus_config_teardown(&handle);
+#if defined(CARDBUS_DEBUG)
+				if (mem_request->ra_len !=
+				    PCICFG_ROUND_UP(mem_request->ra_len,
+				    PCICFG_MEMGRAN)) {
+
+#ifdef _LP64
+					cardbus_err(dip, 8,
+					    "Pre-align [0x%lx] to PCI bridge "
+					    "memory gran "
+					    "[0x%lx] -> [0x%lx]\n",
+					    PCICFG_ROUND_UP(mem_request->ra_len,
+						PCICFG_MEMGRAN) -
+						mem_request->ra_len,
+					    mem_request->ra_len,
+					    PCICFG_ROUND_UP(mem_request->ra_len,
+						PCICFG_MEMGRAN));
+#else
+					cardbus_err(dip, 8,
+					    "Pre-align [0x%llx] to PCI bridge "
+					    "memory gran "
+					    "[0x%llx] -> [0x%lx]\n",
+					    PCICFG_ROUND_UP(mem_request->ra_len,
+						PCICFG_MEMGRAN) -
+						mem_request->ra_len,
+					    mem_request->ra_len,
+					    PCICFG_ROUND_UP(mem_request->ra_len,
+						PCICFG_MEMGRAN));
+#endif
+				}
+
+				if (io_request->ra_len !=
+				    PCICFG_ROUND_UP(io_request->ra_len,
+				    PCICFG_IOGRAN)) {
+
+#ifdef _LP64
+					cardbus_err(dip, 8,
+					    "Pre-align [0x%lx] to PCI bridge "
+					    "I/O gran "
+					    "[0x%lx] -> [0x%lx]\n",
+					    PCICFG_ROUND_UP(io_request->ra_len,
+						PCICFG_IOGRAN) -
+						io_request->ra_len,
+					    io_request->ra_len,
+					    PCICFG_ROUND_UP(io_request->ra_len,
+						PCICFG_IOGRAN));
+#else
+					cardbus_err(dip, 8,
+					    "Pre-align [0x%llx] to PCI bridge "
+					    "I/O gran "
+					    "[0x%llx] -> [0x%lx]\n",
+					    PCICFG_ROUND_UP(io_request->ra_len,
+						PCICFG_IOGRAN) -
+						io_request->ra_len,
+					    io_request->ra_len,
+					    PCICFG_ROUND_UP(io_request->ra_len,
+						PCICFG_IOGRAN));
+#endif
+				}
+
+#endif
+				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 (entry->memory_gran < PCICFG_MEMGRAN)
+					entry->memory_gran = PCICFG_MEMGRAN;
+				if (entry->io_gran < PCICFG_IOGRAN)
+					entry->io_gran = PCICFG_IOGRAN;
+				ddi_walk_devs(ddi_get_child(dip),
+				    cardbus_sum_resources,
+				    (void *)entry);
+#if defined(CARDBUS_DEBUG)
+				if (mem_request->ra_len !=
+				    PCICFG_ROUND_UP(mem_request->ra_len +
+				    cardbus_min_spare_mem, PCICFG_MEMGRAN)) {
+
+#ifdef _LP64
+					cardbus_err(dip, 8,
+					    "Post-align [0x%lx] to PCI bridge "
+					    "memory gran "
+					    "[0x%lx] -> [0x%lx]\n",
+					    PCICFG_ROUND_UP(
+						mem_request->ra_len +
+						cardbus_min_spare_mem,
+						PCICFG_MEMGRAN) -
+						mem_request->ra_len,
+					    mem_request->ra_len,
+					    PCICFG_ROUND_UP(mem_request->ra_len
+						+ cardbus_min_spare_mem,
+						PCICFG_MEMGRAN));
+#else
+					cardbus_err(dip, 8,
+					    "Post-align [0x%llx] to PCI bridge "
+					    "memory gran "
+					    "[0x%llx] -> [0x%lx]\n",
+					    PCICFG_ROUND_UP(
+						mem_request->ra_len +
+						cardbus_min_spare_mem,
+						PCICFG_MEMGRAN) -
+						mem_request->ra_len,
+					    mem_request->ra_len,
+					    PCICFG_ROUND_UP(mem_request->ra_len
+						+ cardbus_min_spare_mem,
+						PCICFG_MEMGRAN));
+#endif
+				}
+
+				if (io_request->ra_len !=
+				    PCICFG_ROUND_UP(io_request->ra_len +
+				    cardbus_min_spare_io,
+				    PCICFG_IOGRAN)) {
+
+#ifdef _LP64
+					cardbus_err(dip, 8,
+					    "Post-align [0x%lx] to PCI bridge "
+					    "I/O gran "
+					    "[0x%lx] -> [0x%lx]\n",
+					    PCICFG_ROUND_UP(io_request->ra_len +
+						cardbus_min_spare_io,
+						PCICFG_IOGRAN) -
+						io_request->ra_len,
+					    io_request->ra_len,
+					    PCICFG_ROUND_UP(io_request->ra_len +
+						cardbus_min_spare_io,
+						PCICFG_IOGRAN));
+#else
+					cardbus_err(dip, 8,
+					    "Post-align [0x%llx] to PCI bridge "
+					    "I/O gran "
+					    "[0x%llx] -> [0x%lx]\n",
+					    PCICFG_ROUND_UP(io_request->ra_len +
+						cardbus_min_spare_io,
+						PCICFG_IOGRAN) -
+						io_request->ra_len,
+					    io_request->ra_len,
+					    PCICFG_ROUND_UP(io_request->ra_len +
+						cardbus_min_spare_io,
+						PCICFG_IOGRAN));
+#endif
+				}
+#endif
+				mem_request->ra_len = PCICFG_ROUND_UP(
+						mem_request->ra_len +
+						    cardbus_min_spare_mem,
+						PCICFG_MEMGRAN);
+				io_request->ra_len = PCICFG_ROUND_UP(
+						io_request->ra_len +
+						    cardbus_min_spare_io,
+						PCICFG_IOGRAN);
+			}
+			return (DDI_WALK_PRUNECHILD);
+
+		case PCI_BRIDGE_CARDBUS:
+			/*
+			 * Cardbus has I/O registers.
+			 */
+			break;
+
+		case PCI_BRIDGE_ISA:
+			/*
+			 * All the registers requirements for ISA
+			 * are stored in the reg structure of the bridge.
+			 * Children of ISA are not of type PCI
+			 * so must not come through here because
+			 * cardbus_config_setup() will fail.
+			 */
+			ret = DDI_WALK_PRUNECHILD;
+			break;
+
+		default:
+			/*
+			 * Treat other bridges as leaf nodes.
+			 */
+			break;
+		}
+	}
+
+	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;
+		(void) cardbus_config_teardown(&handle);
+		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);
+
+			cardbus_err(dip, 8,
+			    "ADDING 32 --->0x%x for BAR@0x%x\n",
+			    pci_rp[i].pci_size_low,
+			    PCI_REG_REG_G(pci_rp[i].pci_phys_hi));
+			/*
+			 * the granualarity needs to be the larger of
+			 * the maximum amount of memory that we're going to
+			 * ask for, and the PCI-PCI bridge granularity (1M)
+			 */
+			if (pci_rp[i].pci_size_low > entry->memory_gran)
+				entry->memory_gran = 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);
+			cardbus_err(dip, 8,
+			    "ADDING 64 --->0x%x for BAR@0x%x\n",
+			    pci_rp[i].pci_size_low,
+			    PCI_REG_REG_G(pci_rp[i].pci_phys_hi));
+
+			if (pci_rp[i].pci_size_low > entry->memory_gran)
+				entry->memory_gran = 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);
+			cardbus_err(dip, 8,
+			    "ADDING I/O --->0x%x for BAR@0x%x\n",
+			    pci_rp[i].pci_size_low,
+			    PCI_REG_REG_G(pci_rp[i].pci_phys_hi));
+
+			if (pci_rp[i].pci_size_low > entry->io_gran)
+				entry->io_gran = 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) cardbus_config_teardown(&handle);
+
+#ifdef  _LP64
+	cardbus_err(dip, 8,
+	    "Memory 0x%lx bytes, I/O 0x%lx bytes, "
+	    "Memgran 0x%x, IOgran 0x%x\n",
+	    mem_request->ra_len, io_request->ra_len,
+	    entry->memory_gran, entry->io_gran);
+#else
+	cardbus_err(dip, 8,
+	    "Memory 0x%llx bytes, I/O 0x%llx bytes, "
+	    "Memgran 0x%x, IOgran 0x%x\n",
+	    mem_request->ra_len, io_request->ra_len,
+	    entry->memory_gran, entry->io_gran);
+#endif
+
+	return (ret);
+}
+
+/*
+ * Free resources allocated to a bridge.
+ * Note that this routine does not call ndi_ra_free() to actually
+ * free memory/IO/Bus. This is done as a single chunk for the entire
+ * device tree in cardbus_free_chunk().
+ */
+static int
+cardbus_free_bridge_resources(dev_info_t *dip)
+{
+	cardbus_range_t	*ranges;
+	uint_t		*bus;
+	int		k;
+	int		length;
+	int		i;
+
+	cardbus_err(dip, 6, "cardbus_free_bridge_resources\n");
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges,
+	    &length) == DDI_PROP_SUCCESS) {
+		for (i = 0; i < length / sizeof (cardbus_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:
+					cardbus_err(dip, 6,
+					    "Need to Free I/O    "
+					    "base/length = [0x%x]/[0x%x]\n",
+					    ranges[i].child_lo,
+					    ranges[i].size_lo);
+					break;
+
+				case PCI_ADDR_MEM32:
+				case PCI_ADDR_MEM64:
+					cardbus_err(dip, 6,
+					    "Need to Free Memory base/length = "
+					    "[0x%x.%x]/[0x%x]\n",
+					    ranges[i].child_mid,
+					    ranges[i].child_lo,
+					    ranges[i].size_lo);
+					break;
+
+				default:
+					cardbus_err(dip, 6,
+					    "Unknown memory space\n");
+					break;
+				}
+			}
+		}
+
+		kmem_free(ranges, length);
+		(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "ranges");
+	} else {
+		cardbus_err(dip, 8,
+		    "cardbus_free_bridge_resources: Failed"
+		    "to read ranges property\n");
+	}
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
+	    &k) != DDI_PROP_SUCCESS) {
+		cardbus_err(dip, 6, "Failed to read bus-range property\n");
+		return (PCICFG_FAILURE);
+	}
+
+	cardbus_err(dip, 6,
+	    "Need to free bus [%d] range [%d]\n",
+	    bus[0], bus[1] - bus[0] + 1);
+
+	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "available");
+	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "bus-range");
+
+	return (PCICFG_SUCCESS);
+}
+
+static int
+cardbus_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) {
+		cardbus_err(dip, 1,
+		    "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++) {
+
+		/*
+		 * Free the resource if the size of it is not zero.
+		 */
+		if ((assigned[i].pci_size_low != 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):
+				cardbus_err(dip, 6,
+				    "Need to return 0x%x of 32 bit MEM 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;
+
+			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
+				cardbus_err(dip, 6,
+				    "Need to return 0x%x of 64 bit MEM space"
+				    " @ 0x%x.%x from register 0x%x\n",
+				    assigned[i].pci_size_low,
+				    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):
+				cardbus_err(dip, 6,
+				    "Need to return 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:
+				cardbus_err(dip, 1, "Unknown register type\n");
+				kmem_free(assigned, length);
+				return (PCICFG_FAILURE);
+			} /* switch */
+		}
+	}
+	kmem_free(assigned, length);
+	return (PCICFG_SUCCESS);
+}
+
+static int
+cardbus_free_resources(dev_info_t *dip)
+{
+	uint32_t classcode;
+
+	classcode = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+				"class-code", -1);
+	/*
+	 * A different algorithim is used for bridges and leaf devices.
+	 */
+	if (classcode != -1) {
+		classcode = ((uint_t)classcode & 0xffff00) >> 8;
+		if (classcode == 0x604 || classcode == 0x607) {
+			if (cardbus_free_bridge_resources(dip)
+			    != PCICFG_SUCCESS) {
+				cardbus_err(dip, 1,
+				    "Failed freeing up bridge resources\n");
+				return (PCICFG_FAILURE);
+			}
+			return (PCICFG_SUCCESS);
+		}
+	}
+
+	if (cardbus_free_device_resources(dip) != PCICFG_SUCCESS) {
+		cardbus_err(dip, 1, "Failed freeing up device resources\n");
+		return (PCICFG_FAILURE);
+	}
+	return (PCICFG_SUCCESS);
+}
+
+static int
+cardbus_probe_bridge(cbus_t *cbp, dev_info_t *attpt, uint_t bus,
+			uint_t device, uint_t func)
+{
+	/* Declairations */
+	cardbus_bus_range_t	*bus_range;
+	int			i, j;
+	uint8_t			header_type;
+	ddi_acc_handle_t	config_handle;
+	ndi_ra_request_t	req;
+	uint_t			new_bus;
+	uint64_t		blen;
+	uint64_t		next_bus;
+	int circ;
+
+	cardbus_err(cbp->cb_dip, 6,
+	    "cardbus_probe_bridge bus %d device %d func %d\n",
+	    bus, device, func);
+
+	ndi_devi_enter(cbp->cb_dip, &circ);
+	if (pci_config_setup(cbp->cb_dip, &config_handle) != DDI_SUCCESS) {
+
+		cardbus_err(cbp->cb_dip, 1,
+		    "cardbus_probe_bridge(): Failed to setup config space\n");
+
+		ndi_devi_exit(cbp->cb_dip, circ);
+		return (PCICFG_FAILURE);
+	}
+
+	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
+
+	/*
+	 * As soon as we have access to config space, check device
+	 * is a bridge.
+	 */
+	if ((header_type & PCI_HEADER_TYPE_M) != PCI_HEADER_CARDBUS)
+		goto failed;
+
+	cardbus_err(cbp->cb_dip, 8,
+	    "---Vendor ID = [0x%04x]\n",
+	    pci_config_get16(config_handle, PCI_CONF_VENID));
+	cardbus_err(cbp->cb_dip, 8,
+	    "---Device ID = [0x%04x]\n",
+	    pci_config_get16(config_handle, PCI_CONF_DEVID));
+
+	/* say what type of header */
+	cardbus_err(cbp->cb_dip, 8,
+	    "--%s bridge found root bus [0x%x] device [0x%x] func [0x%x]\n",
+	    ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) ?
+		"PCI-PCI" : "Cardbus",
+	    bus, device, func);
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, cbp->cb_dip, 0, "bus-range",
+	    (caddr_t)&bus_range, &i) != DDI_PROP_SUCCESS)
+		cardbus_err(cbp->cb_dip, 1,
+		    "No bus-range property seems to have been set up\n");
+	else {
+		cardbus_err(cbp->cb_dip, 8,
+		    "allowable bus range is %u->%u\n",
+		    bus_range->lo, bus_range->hi);
+		kmem_free((caddr_t)bus_range, i);
+	}
+
+	/*
+	 * Get next bus in sequence and program device.
+	 */
+	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
+	req.ra_len = 1;
+
+	if (ndi_ra_alloc(cbp->cb_dip, &req,
+	    &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
+	    NDI_RA_PASS) != NDI_SUCCESS) {
+		cardbus_err(cbp->cb_dip, 1, "Failed to get a bus number\n");
+		goto failed;
+	}
+
+	new_bus = next_bus;
+	cardbus_err(cbp->cb_dip, 8,
+	    "NEW bus found [%u]->[%u]\n", bus, new_bus);
+
+	(void) cardbus_set_bus_numbers(config_handle, bus, new_bus);
+
+	/* Enable it all */
+	enable_cardbus_bridge(cbp->cb_dip, config_handle);
+
+	/*
+	 * Probe all children devices
+	 */
+	for (i = 0; i < pcicfg_max_device; i++)
+		for (j = 0; j < pcicfg_max_function; j++)
+			switch (cardbus_probe_children(cbp, attpt, new_bus, i,
+			    j, &header_type)) {
+
+			case PCICFG_FAILURE:
+				cardbus_err(cbp->cb_dip, 1,
+				    "Failed to configure bus "
+				    "[0x%x] device [0x%x] func [0x%x]\n",
+				    new_bus, i, j);
+				disable_cardbus_bridge(cbp->cb_dip,
+				    config_handle);
+				goto failed;
+
+			case PCICFG_NODEVICE:
+				/*
+				 * if there's no function 0
+				 * there's no point in probing other
+				 * functions
+				 */
+				if (j != 0)
+					break;
+				/* FALLTHROUGH */
+			case PCICFG_NOMULTI:
+				j = pcicfg_max_function;
+				break;
+
+			default:
+				break;
+			}
+
+	(void) pci_config_teardown(&config_handle);
+	(void) i_ndi_config_node(attpt, DS_LINKED, 0);
+	ndi_devi_exit(cbp->cb_dip, circ);
+
+	return (PCICFG_SUCCESS);
+
+failed:
+	(void) pci_config_teardown(&config_handle);
+	ndi_devi_exit(cbp->cb_dip, circ);
+
+	return (PCICFG_FAILURE);
+}
+
+static struct isa_node isa_nodes[] = {
+	{"dummy", {NULL, NULL, NULL, NULL, NULL}, "serial", "", 0x4e, 0x2}
+};
+
+static int
+cardbus_probe_children(cbus_t *cbp, dev_info_t *parent, uint_t bus,
+			uint_t device, uint_t func, uint8_t *header_type)
+{
+	dev_info_t		*new_child;
+	ddi_acc_handle_t	config_handle;
+	int			i, j;
+	ndi_ra_request_t	req;
+	uint64_t		next_bus;
+	uint64_t		blen;
+	uint32_t		request;
+	uint8_t			base_class;
+	uint_t			new_bus;
+	int			ret;
+	int			circ;
+
+	cardbus_err(parent, 6,
+	    "cardbus_probe_children bus %d device %d func %d\n",
+	    bus, device, func);
+
+	/*
+	 * 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.
+	 */
+
+	ndi_devi_enter(parent, &circ);
+
+	if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME,
+	    (pnode_t)DEVI_SID_NODEID,
+	    &new_child) != NDI_SUCCESS) {
+		cardbus_err(parent, 1,
+		    "cardbus_probe_children(): Failed to alloc child node\n");
+		ndi_devi_exit(parent, circ);
+		return (PCICFG_FAILURE);
+	}
+
+	if (cardbus_add_config_reg(new_child, bus,
+	    device, func) != DDI_SUCCESS) {
+		cardbus_err(parent, 1,
+		    "cardbus_probe_children(): Failed to add candidate REG\n");
+		goto failedconfig;
+	}
+
+	if ((ret = cardbus_config_setup(new_child, &config_handle))
+	    != PCICFG_SUCCESS) {
+
+		if (ret == PCICFG_NODEVICE) {
+			(void) ndi_devi_free(new_child);
+			return (ret);
+		}
+		cardbus_err(parent, 1,
+		    "cardbus_probe_children(): Failed to setup config space\n");
+
+		goto failedconfig;
+	}
+
+	base_class = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
+
+	if (func == 0) {
+		/*
+		 * Preserve the header type from function 0.
+		 * Additional functions may not preserve the PCI_HEADER_MULTI
+		 * bit.
+		 */
+		*header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
+	} else if (!(*header_type & PCI_HEADER_MULTI) ||
+		    ((*header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) ||
+		    (base_class == PCI_CLASS_BRIDGE)) {
+
+		(void) cardbus_config_teardown(&config_handle);
+		(void) ndi_devi_free(new_child);
+		return (PCICFG_NOMULTI);
+	}
+
+	/*
+	 * As soon as we have access to config space,
+	 * turn off device. It will get turned on
+	 * later (after memory is assigned).
+	 * not if it's a cardbus device. It may be OK to leave
+	 * it on - try LATER
+	 */
+	disable_cardbus_device(config_handle);
+
+	/*
+	 * Set 1275 properties common to all devices
+	 */
+	if (cardbus_set_standard_props(parent, new_child,
+	    config_handle) != PCICFG_SUCCESS) {
+		cardbus_err(parent, 1, "Failed to set standard properties\n");
+		goto failedchild;
+	}
+
+	/*
+	 * Child node properties  NOTE: Both for PCI-PCI bridge and child node
+	 */
+	if (cardbus_set_childnode_props(new_child,
+	    config_handle) != PCICFG_SUCCESS) {
+		goto failedchild;
+	}
+
+	cardbus_err(parent, 8,
+	    "---Vendor ID = [0x%04x]\n",
+	    pci_config_get16(config_handle, PCI_CONF_VENID));
+	cardbus_err(parent, 8,
+	    "---Device ID = [0x%04x]\n",
+	    pci_config_get16(config_handle, PCI_CONF_DEVID));
+
+	if (base_class == PCI_CLASS_BRIDGE) {
+		uint8_t	sub_class;
+
+		sub_class = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
+
+		switch (sub_class) {
+		case PCI_BRIDGE_PCI:
+			if ((*header_type & PCI_HEADER_TYPE_M)
+			    == PCI_HEADER_PPB) {
+				cardbus_bus_range_t *bus_range;
+				int k;
+
+				/* say what type of header */
+				cardbus_err(parent, 8,
+				    "-- Found PCI-PCI bridge @ "
+				    " bus [0x%x] device [0x%x] func [0x%x]\n",
+				    bus, device, func);
+
+				if (ddi_getlongprop(DDI_DEV_T_ANY,
+				    new_child, 0, "bus-range",
+				    (caddr_t)&bus_range,
+				    &k) != DDI_PROP_SUCCESS)
+					cardbus_err(new_child, 1,
+					    "No bus-range property"
+					    " seems to have been set up\n");
+				else {
+					cardbus_err(new_child, 8,
+					    "allowable bus range is %u->%u\n",
+					    bus_range->lo, bus_range->hi);
+					kmem_free((caddr_t)bus_range, k);
+				}
+
+				/*
+				 * Get next bus in sequence and program device.
+				 */
+				bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
+				req.ra_len = 1;
+
+				if (ndi_ra_alloc(new_child, &req,
+				    &next_bus, &blen,
+				    NDI_RA_TYPE_PCI_BUSNUM,
+				    NDI_RA_PASS) != NDI_SUCCESS) {
+					cardbus_err(new_child, 1,
+					    "Failed to get a bus number\n");
+					goto failedchild;
+				}
+
+				new_bus = next_bus;
+
+				cardbus_err(new_child, 8,
+				    "NEW bus found [%u]->[%u]\n", bus, new_bus);
+
+				/* Enable it all */
+				enable_pci_pci_bridge(new_child, config_handle);
+				(void) cardbus_set_bus_numbers(config_handle,
+				    bus, new_bus);
+
+#if defined(CARDBUS_DEBUG)
+				if (cardbus_debug >= 9) {
+					cardbus_dump_config(config_handle);
+				}
+#endif
+
+				/*
+				 * Set bus properties
+				 */
+				if (cardbus_set_busnode_props(new_child)
+				    != PCICFG_SUCCESS) {
+					cardbus_err(new_child, 1,
+					    "Failed to set busnode props\n");
+					disable_pci_pci_bridge(new_child,
+					    config_handle);
+					goto failedchild;
+				}
+
+				/*
+				 * Probe all children devices
+				 */
+				for (i = 0; i < pcicfg_max_device; i++)
+					for (j = 0; j < pcicfg_max_function;
+					    j++)
+						switch (cardbus_probe_children(
+						    cbp,
+						    new_child,
+						    new_bus, i,
+						    j, header_type)) {
+						case PCICFG_FAILURE:
+							cardbus_err(parent, 1,
+							    "Failed to "
+							    "configure "
+							    "bus [0x%x] "
+							    "device [0x%x] "
+							    "func [0x%x]\n",
+							    new_bus, i, j);
+							disable_pci_pci_bridge(
+								new_child,
+								config_handle);
+							goto failedchild;
+
+						case PCICFG_NODEVICE:
+							/*
+							 * if there's no
+							 * function 0
+							 * there's no point in
+							 * probing other
+							 * functions
+							 */
+							if (j != 0)
+								break;
+							/* FALLTHROUGH */
+						case PCICFG_NOMULTI:
+							j = pcicfg_max_function;
+							break;
+
+						default:
+							break;
+						}
+			}
+			break;
+
+		case PCI_BRIDGE_CARDBUS:
+			cardbus_err(parent, 8,
+			    "--Found Cardbus bridge @ "
+			    "bus [0x%x] device [0x%x] func [0x%x]\n",
+			    bus, device, func);
+			pci_config_put32(config_handle,
+			    PCI_CONF_BASE0, 0xffffffff);
+
+			request = pci_config_get32(config_handle,
+			    PCI_CONF_BASE0);
+
+			/*
+			 * If its a zero length, don't do
+			 * any programming.
+			 */
+			if (request != 0) {
+				if (request == (uint32_t)0xffffffff) {
+					cmn_err(CE_WARN,
+					    "cardbus_probe_children: "
+					    "can't access device");
+					goto failedchild;
+				}
+				/*
+				 * Add to the "reg" property
+				 */
+				if (cardbus_update_reg_prop(new_child,
+				    request,
+				    PCI_CONF_BASE0) != PCICFG_SUCCESS) {
+					goto failedchild;
+				}
+				cardbus_err(parent, 8,
+				    "BASE register [0x%x] asks for "
+				    "[0x%x]=[0x%x](32)\n",
+				    PCI_CONF_BASE0, request,
+				    (~(PCI_BASE_M_ADDR_M & request))+1);
+			}
+			break;
+
+		case PCI_BRIDGE_ISA:
+			cardbus_err(parent, 8,
+			    "--Found ISA bridge @ "
+			    "bus [0x%x] device [0x%x] func [0x%x]\n",
+			    bus, device, func);
+			enable_pci_isa_bridge(new_child, config_handle);
+
+#if defined(CARDBUS_DEBUG)
+			if (cardbus_debug >= 4) {
+				cardbus_dump_common_config(config_handle);
+				cardbus_err(NULL, 1,
+				    " DDMA SlvCh0 = [0x%04x]        "
+				    "DDMA SlvCh1 = [0x%04x]\n",
+				    pci_config_get16(config_handle, 0x40),
+				    pci_config_get16(config_handle, 0x42));
+				cardbus_err(NULL, 1,
+				    " DDMA SlvCh2 = [0x%04x]        "
+				    "DDMA SlvCh3 = [0x%04x]\n",
+				    pci_config_get16(config_handle, 0x44),
+				    pci_config_get16(config_handle, 0x46));
+				cardbus_err(NULL, 1,
+				    " DDMA SlvCh5 = [0x%04x]        "
+				    "DDMA SlvCh6 = [0x%04x]\n",
+				    pci_config_get16(config_handle, 0x4a),
+				    pci_config_get16(config_handle, 0x4c));
+				cardbus_err(NULL, 1,
+				    " DDMA SlvCh7 = [0x%04x]        "
+				    "Misc Cntrl  = [0x%02x]\n",
+				    pci_config_get16(config_handle, 0x4e),
+				    pci_config_get8(config_handle, 0x57));
+				cardbus_err(NULL, 1,
+				    " DMA Cntl    = [0x%02x]          "
+				    "DMA TyF Tim = [0x%02x]\n",
+				    pci_config_get8(config_handle, 0x48),
+				    pci_config_get8(config_handle, 0x49));
+				cardbus_err(NULL, 1,
+				    " TimCntrl    = [0x%02x]          "
+				    "MTOP        = [0x%02x]\n",
+				    pci_config_get8(config_handle, 0x50),
+				    pci_config_get8(config_handle, 0x51));
+				cardbus_err(NULL, 1,
+				    " MDMA Access = [0x%02x]          "
+				    "ROMCS       = [0x%02x]\n",
+				    pci_config_get8(config_handle, 0x52),
+				    pci_config_get8(config_handle, 0x53));
+				cardbus_err(NULL, 1,
+				    " Dscrd Tmr   = [0x%02x]          "
+				    "Retry Tmr   = [0x%02x]\n",
+				    pci_config_get8(config_handle, 0x55),
+				    pci_config_get8(config_handle, 0x54));
+				cardbus_err(NULL, 1,
+				    " I/O Spc 0   = [0x%08x]    "
+				    "I/O Spc 1   = [0x%08x]\n",
+				    pci_config_get32(config_handle, 0x58),
+				    pci_config_get32(config_handle, 0x5c));
+				cardbus_err(NULL, 1,
+				    " I/O Spc 2   = [0x%08x]    "
+				    "I/O Spc 3   = [0x%08x]\n",
+				    pci_config_get32(config_handle, 0x60),
+				    pci_config_get32(config_handle, 0x64));
+				cardbus_err(NULL, 1,
+				    " I/O Spc 4   = [0x%08x]    "
+				    "I/O Spc 5   = [0x%08x]\n",
+				    pci_config_get32(config_handle, 0x68),
+				    pci_config_get32(config_handle, 0x6c));
+				cardbus_err(NULL, 1,
+				    " Mem Spc 0   = [0x%08x]    "
+				    "Mem Spc 1   = [0x%08x]\n",
+				    pci_config_get32(config_handle, 0x70),
+				    pci_config_get32(config_handle, 0x74));
+				cardbus_err(NULL, 1,
+				    " Mem Spc 2   = [0x%08x]    "
+				    "Mem Spc 3   = [0x%08x]\n",
+				    pci_config_get32(config_handle, 0x78),
+				    pci_config_get32(config_handle, 0x7c));
+			}
+#endif
+			/*
+			 * Set bus properties
+			 */
+			if (cardbus_set_busnode_isaprops(new_child)
+			    != PCICFG_SUCCESS) {
+				cardbus_err(new_child, 1,
+				    "Failed to set busnode props\n");
+				disable_cardbus_device(config_handle);
+				goto failedchild;
+			}
+
+			/*
+			 * Add to the "reg" property.
+			 * Simply grab 1K of I/O space.
+			 */
+			if (cardbus_update_reg_prop(new_child,
+			    0xfffffc00 | PCI_BASE_SPACE_IO,
+			    PCI_CONF_BASE0) != PCICFG_SUCCESS) {
+				goto failedchild;
+			}
+
+			/*
+			 * Probe all potential children devices.
+			 */
+			for (i = 0;
+			    i < sizeof (isa_nodes) / sizeof (isa_nodes[0]);
+			    i++)
+				switch (cardbus_add_isa_node(cbp, new_child,
+				    &isa_nodes[i])) {
+				case PCICFG_FAILURE:
+					cardbus_err(parent, 1,
+					    "Failed to configure isa bus\n");
+					disable_cardbus_device(config_handle);
+					goto failedchild;
+
+				case PCICFG_NODEVICE:
+					continue;
+				}
+
+			break;
+
+		case PCI_BRIDGE_OTHER:
+		default:
+			cardbus_err(parent, 8,
+			    "--Found unknown bridge, subclass 0x%x @ "
+			    "bus [0x%x] device [0x%x] func [0x%x]\n",
+			    sub_class, bus, device, func);
+			goto leaf_node;
+		}
+	} else {
+		cardbus_err(parent, 8,
+		    "--Leaf device found "
+		    "bus [0x%x] device [0x%x] func [0x%x]\n",
+		    bus, device, func);
+		/*
+		 * Ethernet devices.
+		 */
+		if (strcmp(ddi_binding_name(new_child), "ethernet") == 0) {
+			extern int localetheraddr(struct ether_addr *,
+			    struct ether_addr *);
+			uchar_t mac[6];
+
+			cardbus_force_stringprop(new_child,
+			    "device_type", "network");
+
+			if (localetheraddr(NULL, (struct ether_addr *)mac)) {
+				(void) ddi_prop_create(DDI_DEV_T_NONE,
+				    new_child,
+				    DDI_PROP_CANSLEEP, "local-mac-address",
+				    (caddr_t)mac, 6);
+			}
+		}
+leaf_node:
+		if (cbp->cb_dsp) {
+			struct cb_deviceset_props *cdsp = cbp->cb_dsp;
+			uint16_t venid = pci_config_get16(config_handle,
+						PCI_CONF_VENID);
+			uint16_t devid = pci_config_get16(config_handle,
+						PCI_CONF_DEVID);
+			ddi_prop_t *propp;
+
+			for (cdsp = cbp->cb_dsp; cdsp; cdsp = cdsp->next) {
+				if (cdsp->binding_name &&
+				    strcmp(ddi_binding_name(new_child),
+				    cdsp->binding_name))
+					continue;
+				if (cdsp->venid && (cdsp->venid != venid))
+					continue;
+				if (cdsp->devid && (cdsp->devid != devid))
+					continue;
+				if (cdsp->nodename) {
+					if (ndi_devi_set_nodename(new_child,
+					    cdsp->nodename,
+					    0) != NDI_SUCCESS)
+						cardbus_err(new_child, 1,
+						    "Failed to set nodename\n");
+				}
+				for (propp = cdsp->prop_list; propp;
+				    propp = propp->prop_next) {
+					switch (propp->prop_flags) {
+					case DDI_PROP_TYPE_INT:
+						cardbus_force_intprop(
+						    new_child,
+						    propp->prop_name,
+						    (int *)propp->prop_val,
+						    propp->prop_len);
+						break;
+					case DDI_PROP_TYPE_STRING:
+						cardbus_force_stringprop(
+						    new_child,
+						    propp->prop_name,
+						    (char *)propp->prop_val);
+						break;
+					case DDI_PROP_TYPE_ANY:
+						cardbus_force_boolprop(
+						    new_child,
+						    propp->prop_name);
+						break;
+					}
+				}
+			}
+		}
+
+#if defined(CARDBUS_DEBUG)
+		if (cardbus_debug >= 9) {
+			cardbus_dump_config(config_handle);
+		}
+#endif
+
+		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) {
+				if (request == (uint32_t)0xffffffff) {
+					cmn_err(CE_WARN,
+					    "cardbus_probe_children: "
+					    "can't access device");
+					goto failedchild;
+				}
+				/*
+				 * Add to the "reg" property
+				 */
+				if (cardbus_update_reg_prop(new_child,
+				    request, i) != PCICFG_SUCCESS) {
+					goto failedchild;
+				}
+			} else {
+				cardbus_err(parent, 8, "All memory found\n");
+				break;
+			}
+
+			/*
+			 * Increment by eight if it is 64 bit address space
+			 * only if memory space
+			 */
+			if (((PCI_BASE_TYPE_M & request)
+				== PCI_BASE_TYPE_ALL) &&
+			    ((PCI_BASE_SPACE_M & request)
+				== PCI_BASE_SPACE_MEM)) {
+				cardbus_err(parent, 8,
+				    "BASE register [0x%x] asks for "
+				    "[0x%x]=[0x%x] (64)\n",
+				    i, request,
+				    (~(PCI_BASE_M_ADDR_M & request))+1);
+				i += 8;
+			} else {
+				cardbus_err(parent, 8,
+				    "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, 0xffffffff);
+
+		request = pci_config_get32(config_handle, PCI_CONF_ROM);
+		/*
+		 * If its a zero length, don't do
+		 * any programming.
+		 */
+
+		if (request != 0) {
+			cardbus_err(parent, 9,
+			    "BASE register [0x%x] asks for "
+			    "[0x%x]=[0x%x] (ROM)\n",
+			    PCI_CONF_ROM, request,
+			    (~(PCI_BASE_ROM_ADDR_M & request))+1);
+			/*
+			 * Add to the "reg" property
+			 */
+			if (cardbus_update_reg_prop(new_child,
+			    request,
+			    PCI_CONF_ROM) != PCICFG_SUCCESS) {
+				goto failedchild;
+			}
+		}
+	}
+
+	(void) cardbus_config_teardown(&config_handle);
+
+	/*
+	 * Attach the child to its parent
+	 */
+	(void) i_ndi_config_node(new_child, DS_LINKED, 0);
+	ndi_devi_exit(parent, circ);
+
+	return (PCICFG_SUCCESS);
+failedchild:
+	/*
+	 * check if it should be taken offline (if online)
+	 */
+	(void) cardbus_config_teardown(&config_handle);
+
+failedconfig:
+
+	(void) ndi_devi_free(new_child);
+	ndi_devi_exit(parent, circ);
+
+	return (PCICFG_FAILURE);
+}
+
+static int
+cardbus_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
+cardbus_add_isa_node(cbus_t *cbp, dev_info_t *parent, struct isa_node *node)
+{
+	dev_info_t		*new_child;
+	int			ret;
+	uint32_t		reg[3];
+
+	_NOTE(ARGUNUSED(cbp))
+
+	cardbus_err(parent, 6, "cardbus_add_isa_node\n");
+
+	/*
+	 * This node will be put immediately below
+	 * "parent". Allocate a blank device node.
+	 */
+	if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME,
+	    (pnode_t)DEVI_SID_NODEID,
+	    &new_child) != NDI_SUCCESS) {
+		cardbus_err(parent, 1,
+		    "cardbus_add_isa_child(): Failed to alloc child node\n");
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * Set properties common to ISA devices
+	 */
+	if (cardbus_set_isa_props(parent, new_child, node->name,
+	    node->compatible) != PCICFG_SUCCESS) {
+		cardbus_err(parent, 1, "Failed to set ISA properties\n");
+		goto failed;
+	}
+
+	cardbus_err(new_child, 8, "--Leaf ISA device\n");
+
+	/*
+	 * Add the "reg" property.
+	 */
+	reg[0] = 0;
+	reg[1] = node->reg;
+	reg[2] = node->span;
+
+	ret = ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
+	    "basereg", (int *)reg, 3);
+	if (ret != DDI_SUCCESS)
+		goto failed;
+
+	(void) i_ndi_config_node(new_child, DS_LINKED, 0);
+
+	return (PCICFG_SUCCESS);
+
+failed:
+	(void) ndi_devi_free(new_child);
+
+	return (PCICFG_FAILURE);
+}
+
+static int
+cardbus_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
+{
+	caddr_t		cfgaddr;
+	ddi_device_acc_attr_t	attr;
+	dev_info_t	*anode;
+	int	status;
+	int	rlen;
+	pci_regspec_t	*reg;
+	int		ret;
+#ifdef sparc
+	int16_t		val;
+#endif
+
+	cardbus_err(dip, 10,
+	    "cardbus_config_setup(dip=0x%p)\n", (void *) dip);
+
+	/*
+	 * Get the pci register spec from the node
+	 */
+	status = ddi_getlongprop(DDI_DEV_T_NONE,
+	    dip, DDI_PROP_DONTPASS, "reg",
+	    (caddr_t)&reg, &rlen);
+
+	cardbus_err(dip, 10,
+	    "cardbus_config_setup, reg = 0x%p\n", (void *) reg);
+
+	switch (status) {
+	case DDI_PROP_SUCCESS:
+		break;
+	case DDI_PROP_NO_MEMORY:
+		cardbus_err(dip, 1, "reg present, but unable to get memory\n");
+		return (PCICFG_FAILURE);
+	default:
+		cardbus_err(dip, 1, "no reg property\n");
+		return (PCICFG_FAILURE);
+	}
+
+	anode = dip;
+
+	/*
+	 * Find the attachment point node
+	 */
+	while ((anode != NULL) && (strcmp(ddi_binding_name(anode),
+	    "hp_attachment") != 0)) {
+		anode = ddi_get_parent(anode);
+	}
+
+	if (anode == NULL) {
+		cardbus_err(dip, 1, "Tree not in PROBE state\n");
+		kmem_free((caddr_t)reg, rlen);
+		return (PCICFG_FAILURE);
+	}
+
+	if ((ret = ndi_prop_update_int_array(DDI_DEV_T_NONE, anode,
+	    "reg", (int *)reg, 5)) != 0) {
+		cardbus_err(dip, 1,
+		    "Failed to update reg property, error code %d\n", ret);
+		kmem_free((caddr_t)reg, rlen);
+		return (PCICFG_FAILURE);
+	}
+
+	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+	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, /* PCI_CONF_HDR_SIZE */
+	    0,
+	    &attr, handle) != DDI_SUCCESS) {
+		cardbus_err(dip, 1,
+		    "Failed to setup registers for [0x%x][0x%x][0x%x]\n",
+		    PCI_REG_BUS_G(reg->pci_phys_hi),
+		    PCI_REG_DEV_G(reg->pci_phys_hi),
+		    PCI_REG_FUNC_G(reg->pci_phys_hi));
+		kmem_free((caddr_t)reg, rlen);
+		return (PCICFG_FAILURE);
+	}
+
+	cardbus_err(dip, 9,
+	    "PROBING =>->->->->->-> [0x%x][0x%x][0x%x] 0x%x 0x%p\n",
+	    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->pci_phys_hi, (void *) cfgaddr);
+
+	/*
+	 * must do peek16 otherwise the system crashes when probing
+	 * a non zero function on a non-multi-function card.
+	 */
+#ifdef sparc
+	if (ddi_peek16(anode, (int16_t *)cfgaddr, &val) != DDI_SUCCESS) {
+		cardbus_err(dip, 8,
+		    "cardbus_config_setup peek failed\n");
+		ret = PCICFG_NODEVICE;
+	} else if (ddi_get16(*handle, (uint16_t *)cfgaddr) == 0xffff) {
+		cardbus_err(dip, 8,
+		    "cardbus_config_setup PCICFG_NODEVICE\n");
+		ret = PCICFG_NODEVICE;
+#elif defined(__x86) || defined(__amd64)
+	if (ddi_get16(*handle, (uint16_t *)cfgaddr) == 0xffff) {
+		cardbus_err(dip, 8,
+		    "cardbus_config_setup PCICFG_NODEVICE\n");
+		ret = PCICFG_NODEVICE;
+#endif
+	} else {
+		cardbus_err(dip, 1,
+		    "cardbus_config_setup found device at:[0x%x][0x%x][0x%x]\n",
+		    PCI_REG_BUS_G(reg->pci_phys_hi),
+		    PCI_REG_DEV_G(reg->pci_phys_hi),
+		    PCI_REG_FUNC_G(reg->pci_phys_hi));
+
+		ret = PCICFG_SUCCESS;
+	}
+
+	kmem_free((caddr_t)reg, rlen);
+	if (ret != PCICFG_SUCCESS) {
+		cardbus_config_teardown(handle);
+	}
+
+	cardbus_err(dip, 7,
+	    "cardbus_config_setup returning %d\n", ret);
+
+	return (ret);
+}
+
+static void
+cardbus_config_teardown(ddi_acc_handle_t *handle)
+{
+	(void) ddi_regs_map_free(handle);
+}
+
+static void
+cardbus_reparent_children(dev_info_t *dip, dev_info_t *parent)
+{
+	dev_info_t *child;
+	int circ;
+
+	while (child = ddi_get_child(dip)) {
+		ASSERT(i_ddi_node_state(child) <= DS_LINKED);
+		/*
+		 * Unlink node from tree before reparenting
+		 */
+		ndi_devi_enter(dip, &circ);
+		(void) i_ndi_unconfig_node(child, DS_PROTO, 0);
+		ndi_devi_exit(dip, circ);
+		DEVI(child)->devi_parent = DEVI(parent);
+		DEVI(child)->devi_bus_ctl = DEVI(parent);
+		ndi_devi_enter(parent, &circ);
+		(void) i_ndi_config_node(child, DS_LINKED, 0);
+		ndi_devi_exit(parent, circ);
+	}
+}
+
+static int
+cardbus_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone)
+{
+	int		alen;
+	pci_regspec_t	*assigned;
+	caddr_t		newreg;
+	uint_t		status;
+
+	status = ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
+	    "assigned-addresses", (caddr_t)&assigned, &alen);
+	switch (status) {
+	case DDI_PROP_SUCCESS:
+		cardbus_err(dip, 5,
+		    "cardbus_update_assigned_prop: found prop len %d\n",
+		    alen);
+		/*
+		 * 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));
+		break;
+
+	case DDI_PROP_NO_MEMORY:
+		cardbus_err(dip, 1,
+		    "no memory for assigned-addresses property\n");
+		return (PCICFG_FAILURE);
+
+	default:
+		cardbus_err(dip, 5,
+		    "cardbus_update_assigned_prop: creating prop\n");
+		alen = 0;
+		newreg = (caddr_t)newone;
+		break;
+	}
+
+	/*
+	 * 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));
+
+	if (status == DDI_PROP_SUCCESS)
+		kmem_free((caddr_t)newreg, alen+sizeof (*newone));
+
+	if (alen)
+		kmem_free(assigned, alen);
+
+	return (PCICFG_SUCCESS);
+}
+
+static int
+cardbus_update_available_prop(dev_info_t *dip, uint32_t hi_type,
+				uint64_t base, uint64_t size)
+{
+	int		alen, rlen;
+	pci_regspec_t	*available, *reg;
+	pci_regspec_t	addition;
+	caddr_t		newreg;
+	uint_t		status;
+
+	cardbus_err(dip, 6, "cardbus_update_available_prop\n");
+
+	status = ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
+	    "reg", (caddr_t)&reg, &rlen);
+
+	switch (status) {
+	case DDI_PROP_SUCCESS:
+		break;
+	case DDI_PROP_NO_MEMORY:
+		cardbus_err(dip, 1, "reg present, but unable to get memory\n");
+		return (PCICFG_FAILURE);
+	default:
+		cardbus_err(dip, 1, "no reg property\n");
+		return (PCICFG_FAILURE);
+	}
+
+	status = ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
+	    "available", (caddr_t)&available, &alen);
+	switch (status) {
+	case DDI_PROP_SUCCESS:
+		break;
+	case DDI_PROP_NO_MEMORY:
+		cardbus_err(dip, 1, "no memory for available property\n");
+		kmem_free((caddr_t)reg, rlen);
+		return (PCICFG_FAILURE);
+	default:
+		alen = 0;
+	}
+
+	/*
+	 * Allocate memory for the existing
+	 * available(s) plus one and then
+	 * build it.
+	 */
+	newreg = kmem_zalloc(alen + sizeof (pci_regspec_t), KM_SLEEP);
+
+	/*
+	 * Build the regspec, then add it to the existing one(s)
+	 */
+	addition.pci_phys_hi = hi_type |
+	    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), 0);
+
+	addition.pci_phys_mid = (uint32_t)((base>>32) & 0xffffffff);
+	addition.pci_phys_low = (uint32_t)(base & 0xffffffff);
+	addition.pci_size_hi = (uint32_t)((size>>32) & 0xffffffff);
+	addition.pci_size_low = (uint32_t)(size & 0xffffffff);
+
+#ifdef DEBUG
+	cardbus_dump_reg(dip, &addition, 1);
+#endif
+
+	if (alen)
+		bcopy(available, newreg, alen);
+	bcopy(&addition, newreg + alen, sizeof (pci_regspec_t));
+
+	/*
+	 * Write out the new "available" spec
+	 */
+	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
+	    "available", (int *)newreg,
+	    (alen + sizeof (pci_regspec_t))/sizeof (int));
+
+	if (alen)
+		kmem_free((caddr_t)available, alen);
+	kmem_free((caddr_t)reg, rlen);
+	kmem_free((caddr_t)newreg, alen + sizeof (pci_regspec_t));
+
+	return (PCICFG_SUCCESS);
+}
+
+static int
+cardbus_update_ranges_prop(dev_info_t *dip, cardbus_range_t *addition)
+{
+	int		rlen;
+	cardbus_range_t	*ranges;
+	caddr_t		newreg;
+	uint_t		status;
+#if defined(CARDBUS_DEBUG)
+	int	i, nrange;
+	const cardbus_range_t	*nr;
+#endif
+
+	cardbus_err(dip, 6, "cardbus_update_ranges_prop\n");
+
+	status = ddi_getlongprop(DDI_DEV_T_NONE,
+	    dip, DDI_PROP_DONTPASS, "ranges",
+	    (caddr_t)&ranges, &rlen);
+
+	switch (status) {
+	case DDI_PROP_SUCCESS:
+		break;
+	case DDI_PROP_NO_MEMORY:
+		cardbus_err(dip, 1,
+		    "ranges present, but unable to get memory\n");
+		return (PCICFG_FAILURE);
+	default:
+		cardbus_err(dip, 8, "no ranges property - creating one\n");
+		if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
+		    dip, "ranges", (int *)addition,
+		    sizeof (cardbus_range_t)/sizeof (int))
+		    != DDI_SUCCESS) {
+			cardbus_err(dip, 1, "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 (cardbus_range_t), KM_SLEEP);
+
+	bcopy(ranges, newreg, rlen);
+	bcopy(addition, newreg + rlen, sizeof (cardbus_range_t));
+
+	/*
+	 * Write out the new "ranges" property
+	 */
+	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
+	    dip, "ranges", (int *)newreg,
+	    (rlen + sizeof (cardbus_range_t))/sizeof (int));
+
+#if defined(CARDBUS_DEBUG)
+	cardbus_err(dip, 8, "cardbus_update_ranges_prop ranges property:\n");
+
+	nrange = rlen / sizeof (cardbus_range_t);
+	nr = (cardbus_range_t *)newreg;
+	for (i = 0; i <= nrange; i++) {
+		/* nrange is one higher for new entry */
+		cardbus_err(dip, 9,
+		    "\trange parent addr 0x%x.0x%x.0x%x "
+		    "child addr 0x%x.0x%x.0x%x size 0x%x.0x%x\n",
+		    nr->parent_hi,
+		    nr->parent_mid, nr->parent_lo,
+		    nr->child_hi,
+		    nr->child_mid, nr->child_lo,
+		    nr->size_hi, nr->size_lo);
+		nr++;
+	}
+#endif
+
+	kmem_free((caddr_t)newreg, rlen+sizeof (cardbus_range_t));
+	kmem_free((caddr_t)ranges, rlen);
+
+	return (PCICFG_SUCCESS);
+}
+
+static int
+cardbus_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_NONE,
+	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
+
+	switch (status) {
+	case DDI_PROP_SUCCESS:
+		break;
+	case DDI_PROP_NO_MEMORY:
+		cardbus_err(dip, 1, "reg present, but unable to get memory\n");
+		return (PCICFG_FAILURE);
+	default:
+		cardbus_err(dip, 1, "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) {
+				/*
+				 * This is a 64 bit PCI memory space.
+				 * It needs to be allocated as 32 bit
+				 * for bus map purposes.
+				 */
+				hiword |= PCI_ADDR_MEM32;
+			}
+		} 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;
+
+	cardbus_err(dip, 8,
+	    "cardbus_update_reg_prop, phys_hi 0x%08x,"
+	    " phys_mid 0x%08x, phys_low 0x%08x, size_hi 0x%08x,"
+	    " size_low 0x%08x\n", hiword, 0, 0, 0, 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)reg, rlen);
+	kmem_free((caddr_t)newreg, rlen+sizeof (pci_regspec_t));
+
+	return (PCICFG_SUCCESS);
+}
+
+/*
+ * Setup the basic 1275 properties based on information found in the config
+ * header of the PCI device
+ */
+static int
+cardbus_set_standard_props(dev_info_t *parent, dev_info_t *dip,
+			ddi_acc_handle_t config_handle)
+{
+	int ret;
+	uint16_t val;
+	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) {
+		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) {
+			cardbus_err(dip, 1, "Failed to sent min-grant\n");
+			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);
+
+	/*
+	 * according to section 6.2.1 of revision 2 of the PCI local
+	 * bus specification - 0FFFFh is an invalid value for the vendor ID
+	 */
+	if (val == 0xffff) {
+		cardbus_err(dip, 1, "Illegal vendor-id 0x%x\n", val);
+		return (PCICFG_FAILURE);
+	}
+	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);
+	}
+	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) {
+		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 (ddi_prop_exists(DDI_DEV_T_ANY, parent, DDI_PROP_DONTPASS,
+	    "fast-back-to-back") &&
+	    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 (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.
+	 */
+
+	/* look in the correct place for header type 2 */
+	byteval = pci_config_get8(config_handle, PCI_CONF_HEADER);
+	if ((byteval & PCI_HEADER_TYPE_M) == PCI_HEADER_TWO) {
+		if ((val = pci_config_get16(config_handle,
+		    PCI_CBUS_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_CBUS_SUBSYSID)) != 0) {
+			if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+			    "subsystem-id", val)) != DDI_SUCCESS) {
+				return (ret);
+			}
+		}
+	} else {
+		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_get8(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
+		 */
+		cardbus_err(dip, 8, "Adding interrupts property\n");
+		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+		    "interrupts", byteval)) != DDI_SUCCESS) {
+			return (ret);
+		}
+	}
+	return (PCICFG_SUCCESS);
+}
+
+/*
+ * Setup the basic properties required by the ISA node.
+ */
+static int
+cardbus_set_isa_props(dev_info_t *parent, dev_info_t *dip,
+			char *name, char *compat[])
+{
+	int ret, n;
+
+	_NOTE(ARGUNUSED(parent))
+
+	cardbus_err(dip, 8, "Adding interrupts property\n");
+	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    "interrupts", 1)) != DDI_SUCCESS) {
+		return (ret);
+	}
+
+	/*
+	 * The node name field needs to be filled in with the name
+	 */
+	if (ndi_devi_set_nodename(dip, name, 0) != NDI_SUCCESS) {
+		cardbus_err(dip, 1, "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;
+	while (compat[n] != NULL)
+		n++;
+
+	if (n != 0)
+		if ((ret = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
+		    "compatible", compat, n)) != DDI_SUCCESS)
+			return (ret);
+
+	return (PCICFG_SUCCESS);
+}
+
+static int
+cardbus_set_busnode_props(dev_info_t *dip)
+{
+	cardbus_err(dip, 6, "cardbus_set_busnode_props\n");
+
+	cardbus_force_stringprop(dip, "device_type", "pci");
+
+	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    "#address-cells", 3) != DDI_SUCCESS) {
+		cardbus_err(dip, 4, "Failed to set #address-cells\n");
+	}
+	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    "#size-cells", 2) != DDI_SUCCESS) {
+		cardbus_err(dip, 4, "Failed to set #size-cells\n");
+	}
+	return (PCICFG_SUCCESS);
+}
+
+static int
+cardbus_set_busnode_isaprops(dev_info_t *dip)
+{
+	cardbus_err(dip, 6, "cardbus_set_busnode_props\n");
+
+	cardbus_force_stringprop(dip, "device_type", "isa");
+
+	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    "#address-cells", 2) != DDI_SUCCESS) {
+		cardbus_err(dip, 4, "Failed to set #address-cells\n");
+	}
+	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    "#size-cells", 1) != DDI_SUCCESS) {
+		cardbus_err(dip, 4, "Failed to set #size-cells\n");
+	}
+	return (PCICFG_SUCCESS);
+}
+
+/*
+ * Use cb%x,%x rather than pci%x,%x so that we can use specific cardbus
+ * drivers in /etc/driver_aliases if required
+ */
+static int
+cardbus_set_childnode_props(dev_info_t *dip, ddi_acc_handle_t config_handle)
+{
+	int		ret;
+#ifndef _DONT_USE_1275_GENERIC_NAMES
+	uint32_t	wordval;
+#endif
+	char		*name;
+	char		buffer[64];
+	uint32_t	classcode;
+	char		*compat[8];
+	int		i, n;
+	uint16_t	subsysid, subvenid, devid, venid;
+	uint8_t		header_type;
+
+	/*
+	 * NOTE: These are for both a child and PCI-PCI bridge node
+	 */
+#ifndef _DONT_USE_1275_GENERIC_NAMES
+	wordval = (pci_config_get16(config_handle, PCI_CONF_SUBCLASS)<< 8) |
+	    (pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
+#endif
+
+	/* Cardbus support */
+	venid = pci_config_get16(config_handle, PCI_CONF_VENID);
+	devid = pci_config_get16(config_handle, PCI_CONF_DEVID);
+
+	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
+	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_TWO) {
+		subvenid = pci_config_get16(config_handle, PCI_CBUS_SUBVENID);
+		subsysid = pci_config_get16(config_handle, PCI_CBUS_SUBSYSID);
+	} else {
+		subvenid = pci_config_get16(config_handle, PCI_CONF_SUBVENID);
+		subsysid = pci_config_get16(config_handle, PCI_CONF_SUBSYSID);
+	}
+
+	if (subsysid != 0) {
+		(void) sprintf(buffer, "pci%x,%x", subvenid, subsysid);
+	} else {
+		(void) sprintf(buffer, "pci%x,%x", venid, devid);
+	}
+
+	cardbus_err(dip, 8, "Childname is %s\n", buffer);
+
+	/*
+	 * 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 = cardbus_get_class_name(wordval>>8)) == NULL) {
+		/*
+		 * Set name to the above fabricated name
+		 */
+		name = buffer;
+	}
+
+	cardbus_err(dip, 8, "Set nodename to %s\n", name);
+#endif
+
+	/*
+	 * The node name field needs to be filled in with the name
+	 */
+	if (ndi_devi_set_nodename(dip, name, 0) != NDI_SUCCESS) {
+		cardbus_err(dip, 1, "Failed to set nodename for node\n");
+		return (PCICFG_FAILURE);
+	}
+
+	/*
+	 * Create the compatible property as an array of pointers
+	 * to strings.  Start with the cb name.
+	 */
+	n = 0;
+
+	if (subsysid != 0) {
+		(void) sprintf(buffer, "cb%x,%x", subvenid, subsysid);
+	} else {
+		(void) sprintf(buffer, "cb%x,%x", venid, devid);
+	}
+
+	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+	(void) strcpy(compat[n++], buffer);
+
+	if (subsysid != 0) {
+		/*
+		 * Add subsys numbers as pci compatible.
+		 */
+		(void) sprintf(buffer, "pci%x,%x", subvenid, subsysid);
+		compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+		(void) strcpy(compat[n++], buffer);
+	}
+
+	/*
+	 * Add in the VendorID/DeviceID compatible name.
+	 */
+	(void) sprintf(buffer, "pci%x,%x", venid, devid);
+
+	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+	(void) strcpy(compat[n++], buffer);
+
+	classcode = (pci_config_get16(config_handle, PCI_CONF_SUBCLASS)<< 8) |
+	    (pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
+
+	/*
+	 * Add in the Classcode
+	 */
+	(void) sprintf(buffer, "pciclass,%06x", classcode);
+
+	cardbus_err(dip, 8, "class code %s\n", buffer);
+
+	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);
+	}
+
+	return (PCICFG_SUCCESS);
+}
+
+/*
+ * Program the bus numbers into the bridge
+ */
+static void
+cardbus_set_bus_numbers(ddi_acc_handle_t config_handle,
+			uint_t primary, uint_t secondary)
+{
+	cardbus_err(NULL, 8,
+	    "cardbus_set_bus_numbers [%d->%d]\n", primary, secondary);
+
+	/*
+	 * Primary bus#
+	 */
+	pci_config_put8(config_handle, PCI_BCNF_PRIBUS, primary);
+
+	/*
+	 * Secondary bus#
+	 */
+	pci_config_put8(config_handle, PCI_BCNF_SECBUS, secondary);
+
+	/*
+	 * Set the subordinate bus number to ff in order to pass through any
+	 * type 1 cycle with a bus number higher than the secondary bus#
+	 * Note that this is reduced once the probe is complete in the
+	 * cardbus_setup_bridge() function.
+	 */
+	pci_config_put8(config_handle, PCI_BCNF_SUBBUS, 0xFF);
+}
+
+static void
+enable_pci_isa_bridge(dev_info_t *dip, ddi_acc_handle_t config_handle)
+{
+	uint16_t comm, stat;
+
+	stat = pci_config_get16(config_handle, PCI_CONF_STAT);
+	comm = pci_config_get16(config_handle, PCI_CONF_COMM);
+
+	/*
+	 * Enable memory, IO, bus mastership and error detection.
+	 */
+	comm |= (PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_IO |
+	    PCI_COMM_PARITY_DETECT | PCI_COMM_SERR_ENABLE);
+	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "fast-back-to-back"))
+		comm |= PCI_COMM_BACK2BACK_ENAB;
+	pci_config_put16(config_handle, PCI_CONF_COMM, comm);
+	cardbus_err(NULL, 8,
+	    "enable_pci_isa_bridge stat 0x%04x comm 0x%04x\n", stat, comm);
+
+	/*
+	 * ITE8888 Specific registers.
+	 */
+	pci_config_put8(config_handle, 0x50, 0x00); /* Timing Control */
+	pci_config_put8(config_handle, 0x52, 0x00); /* Master DMA Access */
+	pci_config_put8(config_handle, 0x53, 0x01); /* ROMCS */
+}
+
+static void
+enable_pci_pci_bridge(dev_info_t *dip, ddi_acc_handle_t config_handle)
+{
+	uint16_t comm, stat, bctrl;
+
+	stat = pci_config_get16(config_handle, PCI_CONF_STAT);
+	comm = pci_config_get16(config_handle, PCI_CONF_COMM);
+	bctrl = pci_config_get16(config_handle, PCI_CBUS_BRIDGE_CTRL);
+
+	comm &= ~(PCI_COMM_IO | PCI_COMM_MAE);
+	comm |= (PCI_COMM_ME | PCI_COMM_PARITY_DETECT | PCI_COMM_SERR_ENABLE);
+
+	/*
+	 * Enable back to back.
+	 */
+	if (stat & PCI_STAT_FBBC)
+		comm |= PCI_COMM_BACK2BACK_ENAB;
+
+	pci_config_put16(config_handle, PCI_CONF_COMM, comm);
+
+	/*
+	 * Reset the sub-ordinate bus.
+	 */
+	if (!(bctrl & PCI_BCNF_BCNTRL_RESET))
+		pci_config_put16(config_handle, PCI_CBUS_BRIDGE_CTRL,
+			bctrl | PCI_BCNF_BCNTRL_RESET);
+	else
+		bctrl &= ~PCI_BCNF_BCNTRL_RESET;
+
+	/*
+	 * Enable error reporting.
+	 */
+	bctrl |= (PCI_BCNF_BCNTRL_PARITY_ENABLE | PCI_BCNF_BCNTRL_SERR_ENABLE |
+	    PCI_BCNF_BCNTRL_MAST_AB_MODE);
+
+	/*
+	 * Enable back to back on secondary bus.
+	 */
+	if (stat & PCI_STAT_FBBC)
+		bctrl |= PCI_BCNF_BCNTRL_B2B_ENAB;
+
+	pci_config_put16(config_handle, PCI_CBUS_BRIDGE_CTRL, bctrl);
+	cardbus_err(dip, 8,
+	    "enable_pci_pci_bridge stat 0x%04x comm 0x%04x bctrl 0x%04x\n",
+	    stat, comm, bctrl);
+}
+
+static int	cardbus_reset_wait = 20;
+
+static void
+enable_cardbus_bridge(dev_info_t *dip, ddi_acc_handle_t config_handle)
+{
+	uint16_t comm, stat, bctrl;
+
+	stat = pci_config_get16(config_handle, PCI_CONF_STAT);
+	comm = pci_config_get16(config_handle, PCI_CONF_COMM);
+	bctrl = pci_config_get16(config_handle, PCI_CBUS_BRIDGE_CTRL);
+
+	/*
+	 * Don't mess with the command register on the cardbus bridge
+	 * itself. This should have been done when it's parent
+	 * did the setup. Some devices *require* certain things to
+	 * disabled, this can be done using the "command-preserve"
+	 * property and if we mess with it here it breaks that.
+	 *
+	 * comm |= (PCI_COMM_ME | PCI_COMM_PARITY_DETECT |
+	 *	PCI_COMM_SERR_ENABLE);
+	 */
+
+	/*
+	 * Reset the sub-ordinate bus.
+	 */
+	if (!(bctrl & PCI_BCNF_BCNTRL_RESET))
+		pci_config_put16(config_handle, PCI_CBUS_BRIDGE_CTRL,
+			bctrl | PCI_BCNF_BCNTRL_RESET);
+	else
+		bctrl &= ~PCI_BCNF_BCNTRL_RESET;
+
+	/*
+	 * Turn off pre-fetch.
+	 */
+	bctrl &= ~(CB_BCNF_BCNTRL_MEM0_PREF | CB_BCNF_BCNTRL_MEM1_PREF |
+	    PCI_BCNF_BCNTRL_PARITY_ENABLE | PCI_BCNF_BCNTRL_SERR_ENABLE);
+
+	/*
+	 * Enable error reporting.
+	 */
+	bctrl |= (PCI_BCNF_BCNTRL_MAST_AB_MODE | CB_BCNF_BCNTRL_WRITE_POST);
+	if (comm & PCI_COMM_PARITY_DETECT)
+		bctrl |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
+	if (comm & PCI_COMM_SERR_ENABLE)
+		bctrl |= PCI_BCNF_BCNTRL_SERR_ENABLE;
+
+	pci_config_put16(config_handle, PCI_CBUS_BRIDGE_CTRL, bctrl);
+	pci_config_put8(config_handle, PCI_CBUS_LATENCY_TIMER,
+	    cardbus_latency_timer);
+
+	pci_config_put16(config_handle, PCI_CONF_STAT, stat);
+	pci_config_put16(config_handle, PCI_CONF_COMM, comm);
+
+	cardbus_err(dip, 8,
+	    "enable_cardbus_bridge() stat 0x%04x comm 0x%04x bctrl 0x%04x\n",
+	    stat, comm, bctrl);
+
+	/* after resetting the bridge, wait for everything to stablize */
+	delay(drv_usectohz(cardbus_reset_wait * 1000));
+
+}
+
+static void
+disable_pci_pci_bridge(dev_info_t *dip, ddi_acc_handle_t config_handle)
+{
+	uint16_t comm, bctrl;
+
+	comm = pci_config_get16(config_handle, PCI_CONF_COMM);
+	bctrl = pci_config_get16(config_handle, PCI_CBUS_BRIDGE_CTRL);
+
+	/*
+	 * Turn off subordinate bus access.
+	 */
+	pci_config_put8(config_handle, PCI_BCNF_SECBUS, 0);
+	pci_config_put8(config_handle, PCI_BCNF_SUBBUS, 0);
+
+	/*
+	 * Disable error reporting.
+	 */
+	bctrl &= ~(PCI_BCNF_BCNTRL_PARITY_ENABLE | PCI_BCNF_BCNTRL_SERR_ENABLE |
+	    PCI_BCNF_BCNTRL_MAST_AB_MODE);
+	comm = 0;
+
+	pci_config_put16(config_handle, PCI_CONF_COMM, comm);
+	pci_config_put16(config_handle, PCI_CBUS_BRIDGE_CTRL, bctrl);
+
+	cardbus_err(dip, 6,
+	    "disable_pci_pci_bridge() stat 0x%04x comm 0x%04x bctrl 0x%04x\n",
+	    pci_config_get16(config_handle, PCI_CONF_STAT), comm, bctrl);
+}
+
+static void
+disable_cardbus_bridge(dev_info_t *dip, ddi_acc_handle_t config_handle)
+{
+	uint16_t comm, bctrl;
+
+	comm = pci_config_get16(config_handle, PCI_CONF_COMM);
+	bctrl = pci_config_get16(config_handle, PCI_CBUS_BRIDGE_CTRL);
+
+	/*
+	 * Turn off subordinate bus access.
+	 */
+	pci_config_put8(config_handle, PCI_BCNF_SECBUS, 0);
+	pci_config_put8(config_handle, PCI_BCNF_SUBBUS, 0);
+
+	/*
+	 * Disable error reporting.
+	 */
+	bctrl &= ~(PCI_BCNF_BCNTRL_PARITY_ENABLE | PCI_BCNF_BCNTRL_SERR_ENABLE |
+	    PCI_BCNF_BCNTRL_MAST_AB_MODE);
+
+	pci_config_put32(config_handle, PCI_CBUS_MEM_LIMIT0, 0);
+	pci_config_put32(config_handle, PCI_CBUS_MEM_BASE0, 0);
+	pci_config_put32(config_handle, PCI_CBUS_IO_LIMIT0, 0);
+	pci_config_put32(config_handle, PCI_CBUS_IO_BASE0, 0);
+	pci_config_put16(config_handle, PCI_CONF_COMM, comm);
+	pci_config_put16(config_handle, PCI_CBUS_BRIDGE_CTRL, bctrl);
+
+	cardbus_err(dip, 6,
+	    "disable_cardbus_bridge() stat 0x%04x comm 0x%04x bctrl 0x%04x\n",
+	    pci_config_get16(config_handle, PCI_CONF_STAT), comm, bctrl);
+}
+
+static void
+enable_cardbus_device(dev_info_t *dip, ddi_acc_handle_t config_handle)
+{
+	uint16_t comm, stat;
+
+	stat = pci_config_get16(config_handle, PCI_CONF_STAT);
+	comm = pci_config_get16(config_handle, PCI_CONF_COMM);
+
+	/*
+	 * Enable memory, IO, bus mastership and error detection.
+	 */
+	comm |= (PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_IO |
+	    PCI_COMM_PARITY_DETECT | PCI_COMM_SERR_ENABLE);
+	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "fast-back-to-back"))
+		comm |= PCI_COMM_BACK2BACK_ENAB;
+	pci_config_put16(config_handle, PCI_CONF_COMM, comm);
+	cardbus_err(NULL, 8,
+	    "enable_cardbus_device stat 0x%04x comm 0x%04x\n", stat, comm);
+}
+
+static void
+disable_cardbus_device(ddi_acc_handle_t config_handle)
+{
+	cardbus_err(NULL, 8, "disable_cardbus_device\n");
+
+	/*
+	 * Turn off everything in the command register.
+	 */
+	pci_config_put16(config_handle, PCI_CONF_COMM, 0x0);
+}
+
+#ifndef _DONT_USE_1275_GENERIC_NAMES
+static char *
+cardbus_get_class_name(uint32_t classcode)
+{
+	struct cardbus_name_entry *ptr;
+
+	for (ptr = &cardbus_class_lookup[0]; ptr->name != NULL; ptr++) {
+		if (ptr->class_code == classcode) {
+			return (ptr->name);
+		}
+	}
+	return (NULL);
+}
+#endif /* _DONT_USE_1275_GENERIC_NAMES */
+
+/*
+ * Work out a pil for a device based on the PCI class code.
+ * Mostly taken from iline_to_pil() in sun4u/io/pci/pcic_intr.c.
+ */
+#ifdef sparc
+int
+cardbus_get_class_pil(dev_info_t *rdip)
+{
+	uint32_t classcode;
+	struct cardbus_name_entry *ptr;
+	int	pil = 1;
+
+	classcode = ddi_prop_get_int(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
+	    "class-code", -1);
+	if (classcode != -1) {
+		classcode = ((uint_t)classcode & 0xffff00) >> 8;
+	} else {
+		cardbus_err(rdip, 1,
+		    "%s%d has no class-code property\n",
+		    ddi_driver_name(rdip), ddi_get_instance(rdip));
+		return (pil);
+	}
+
+	for (ptr = &cardbus_class_lookup[0]; ptr->name != NULL; ptr++) {
+		if (ptr->class_code == classcode) {
+			if (ptr->pil <= 0x9)
+				return (ptr->pil);
+			else {
+				cardbus_err(rdip, 1,
+				    "%s%d has high pil 0xb => 0x9\n",
+				    ddi_driver_name(rdip),
+				    ddi_get_instance(rdip));
+				return (0x9);
+			}
+		}
+	}
+
+	/*
+	 * Not in our table - make a decision using the base-class-code.
+	 */
+	classcode = classcode >> 16; /* Base classcode */
+	switch (classcode) {
+	default:
+	case PCI_CLASS_NONE:
+		pil = 1;
+		break;
+
+	case PCI_CLASS_MASS:
+	case PCI_CLASS_SERIALBUS:
+		pil = 0x4;
+		break;
+
+	case PCI_CLASS_NET:
+		pil = 0x6;
+		break;
+
+	case PCI_CLASS_DISPLAY:
+		pil = 0x9;
+		break;
+
+	case PCI_CLASS_MM:
+	case PCI_CLASS_MEM:
+	case PCI_CLASS_BRIDGE:
+		cardbus_err(rdip, 1,
+		    "%s%d has high pil 0xb => 0x9\n",
+		    ddi_driver_name(rdip), ddi_get_instance(rdip));
+		pil = 0x9;
+		break;
+	}
+	return (pil);
+}
+#endif
+
+static void
+cardbus_force_boolprop(dev_info_t *dip, char *pname)
+{
+	int ret;
+
+	if ((ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
+	    pname)) != DDI_SUCCESS) {
+		if (ret == DDI_PROP_NOT_FOUND)
+			if (ddi_prop_create(DDI_DEV_T_NONE, dip,
+			    DDI_PROP_CANSLEEP, pname,
+			    (caddr_t)NULL, 0) != DDI_SUCCESS)
+				cardbus_err(dip, 4,
+				    "Failed to set boolean property "
+				    "\"%s\"\n", pname);
+	}
+}
+
+static void
+cardbus_force_intprop(dev_info_t *dip, char *pname, int *pval, int len)
+{
+	int ret;
+
+	if ((ret = ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
+	    pname, pval, len)) != DDI_SUCCESS) {
+		if (ret == DDI_PROP_NOT_FOUND)
+			if (ddi_prop_create(DDI_DEV_T_NONE, dip,
+			    DDI_PROP_CANSLEEP, pname,
+			    (caddr_t)pval, len*sizeof (int))
+			    != DDI_SUCCESS)
+				cardbus_err(dip, 4,
+				    "Failed to set int property \"%s\"\n",
+				    pname);
+	}
+}
+
+static void
+cardbus_force_stringprop(dev_info_t *dip, char *pname, char *pval)
+{
+	int ret;
+
+	if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
+	    pname, pval)) != DDI_SUCCESS) {
+		if (ret == DDI_PROP_NOT_FOUND)
+			if (ddi_prop_create(DDI_DEV_T_NONE, dip,
+			    DDI_PROP_CANSLEEP, pname,
+			    pval, strlen(pval) + 1) != DDI_SUCCESS)
+				cardbus_err(dip, 4,
+				    "Failed to set string property "
+				    "\"%s\" to \"%s\"\n",
+				    pname, pval);
+	}
+}
+
+static void
+split_addr(char *naddr, int *dev, int *func)
+{
+	char	c;
+	int	*ip = dev;
+
+	*dev = 0;
+	*func = 0;
+
+	while (c = *naddr++) {
+		if (c == ',') {
+			ip = func;
+			continue;
+		}
+		if (c >= '0' && c <= '9') {
+			*ip = (*ip * 16) + (c - '0');
+		} else if (c >= 'a' && c <= 'f') {
+			*ip = (*ip * 16) + 10 + (c - 'a');
+		} else
+			break;
+	}
+}
+
+#ifdef DEBUG
+static void
+cardbus_dump_common_config(ddi_acc_handle_t config_handle)
+{
+	cardbus_err(NULL, 1,
+	    " Vendor ID   = [0x%04x]        "
+	    "Device ID   = [0x%04x]\n",
+	    pci_config_get16(config_handle, PCI_CONF_VENID),
+	    pci_config_get16(config_handle, PCI_CONF_DEVID));
+	cardbus_err(NULL, 1,
+	    " Command REG = [0x%04x]        "
+	    "Status  REG = [0x%04x]\n",
+	    pci_config_get16(config_handle, PCI_CONF_COMM),
+	    pci_config_get16(config_handle, PCI_CONF_STAT));
+	cardbus_err(NULL, 1,
+	    " Revision ID = [0x%02x]          "
+	    "Prog Class  = [0x%02x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_REVID),
+	    pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
+	cardbus_err(NULL, 1,
+	    " Dev Class   = [0x%02x]          "
+	    "Base Class  = [0x%02x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_SUBCLASS),
+	    pci_config_get8(config_handle, PCI_CONF_BASCLASS));
+	cardbus_err(NULL, 1,
+	    " Cache LnSz  = [0x%02x]          "
+	    "Latency Tmr = [0x%02x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ),
+	    pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER));
+	cardbus_err(NULL, 1,
+	    " Header Type = [0x%02x]          "
+	    "BIST        = [0x%02x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_HEADER),
+	    pci_config_get8(config_handle, PCI_CONF_BIST));
+}
+
+static void
+cardbus_dump_device_config(ddi_acc_handle_t config_handle)
+{
+	cardbus_dump_common_config(config_handle);
+
+	cardbus_err(NULL, 1,
+	    " BASE 0      = [0x%08x]	BASE 1      = [0x%08x]\n",
+	    pci_config_get32(config_handle, PCI_CONF_BASE0),
+	    pci_config_get32(config_handle, PCI_CONF_BASE1));
+	cardbus_err(NULL, 1,
+	    " BASE 2      = [0x%08x]	BASE 3      = [0x%08x]\n",
+	    pci_config_get32(config_handle, PCI_CONF_BASE2),
+	    pci_config_get32(config_handle, PCI_CONF_BASE3));
+	cardbus_err(NULL, 1,
+	    " BASE 4      = [0x%08x]	BASE 5      = [0x%08x]\n",
+	    pci_config_get32(config_handle, PCI_CONF_BASE4),
+	    pci_config_get32(config_handle, PCI_CONF_BASE5));
+	cardbus_err(NULL, 1,
+	    " Cardbus CIS = [0x%08x]	ROM         = [0x%08x]\n",
+	    pci_config_get32(config_handle, PCI_CONF_CIS),
+	    pci_config_get32(config_handle, PCI_CONF_ROM));
+	cardbus_err(NULL, 1,
+	    " Sub VID     = [0x%04x]	Sub SID     = [0x%04x]\n",
+	    pci_config_get16(config_handle, PCI_CONF_SUBVENID),
+	    pci_config_get16(config_handle, PCI_CONF_SUBSYSID));
+	cardbus_err(NULL, 1,
+	    " I Line      = [0x%02x]	I Pin       = [0x%02x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_ILINE),
+	    pci_config_get8(config_handle, PCI_CONF_IPIN));
+	cardbus_err(NULL, 1,
+	    " Max Grant   = [0x%02x]	Max Latent  = [0x%02x]\n",
+	    pci_config_get8(config_handle, PCI_CONF_MIN_G),
+	    pci_config_get8(config_handle, PCI_CONF_MAX_L));
+}
+
+static void
+cardbus_dump_bridge_config(ddi_acc_handle_t config_handle,
+			uint8_t header_type)
+{
+	if (header_type == PCI_HEADER_PPB) {
+		cardbus_dump_common_config(config_handle);
+		cardbus_err(NULL, 1,
+		    "........................................\n");
+	} else {
+		cardbus_dump_common_config(config_handle);
+		cardbus_err(NULL, 1,
+		    " Mem Base    = [0x%08x]	CBus Status = [0x%04x]\n",
+		    pci_config_get32(config_handle, PCI_CBUS_SOCK_REG),
+		    pci_config_get16(config_handle, PCI_CBUS_SEC_STATUS));
+	}
+
+	cardbus_err(NULL, 1,
+	    " Pri Bus	= [0x%02x]		Sec Bus	= [0x%02x]\n",
+	    pci_config_get8(config_handle, PCI_BCNF_PRIBUS),
+	    pci_config_get8(config_handle, PCI_BCNF_SECBUS));
+	cardbus_err(NULL, 1,
+	    " Sub Bus     = [0x%02x]		Sec Latency = [0x%02x]\n",
+	    pci_config_get8(config_handle, PCI_BCNF_SUBBUS),
+	    pci_config_get8(config_handle, PCI_BCNF_LATENCY_TIMER));
+
+	switch (header_type) {
+	case PCI_HEADER_PPB:
+		cardbus_err(NULL, 1,
+		    " I/O Base LO = [0x%02x]	I/O Lim LO  = [0x%02x]\n",
+		    pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW),
+		    pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW));
+		cardbus_err(NULL, 1,
+		    " Sec. Status = [0x%04x]\n",
+		    pci_config_get16(config_handle, PCI_BCNF_SEC_STATUS));
+		cardbus_err(NULL, 1,
+		    " Mem Base    = [0x%04x]	Mem Limit   = [0x%04x]\n",
+		    pci_config_get16(config_handle, PCI_BCNF_MEM_BASE),
+		    pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT));
+		cardbus_err(NULL, 1,
+		    " PF Mem Base = [0x%04x]	PF Mem Lim  = [0x%04x]\n",
+		    pci_config_get16(config_handle, PCI_BCNF_PF_BASE_LOW),
+		    pci_config_get16(config_handle, PCI_BCNF_PF_LIMIT_LOW));
+		cardbus_err(NULL, 1,
+		    " PF Base HI  = [0x%08x]	PF Lim  HI  = [0x%08x]\n",
+		    pci_config_get32(config_handle, PCI_BCNF_PF_BASE_HIGH),
+		    pci_config_get32(config_handle, PCI_BCNF_PF_LIMIT_HIGH));
+		cardbus_err(NULL, 1,
+		    " I/O Base HI = [0x%04x]	I/O Lim HI  = [0x%04x]\n",
+		    pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI),
+		    pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI));
+		cardbus_err(NULL, 1,
+		    " ROM addr    = [0x%08x]\n",
+		    pci_config_get32(config_handle, PCI_BCNF_ROM));
+		break;
+	case PCI_HEADER_CARDBUS:
+		cardbus_err(NULL, 1,
+		    " Mem Base 0  = [0x%08x]	Mem Limit 0 = [0x%08x]\n",
+		    pci_config_get32(config_handle, PCI_CBUS_MEM_BASE0),
+		    pci_config_get32(config_handle, PCI_CBUS_MEM_LIMIT0));
+		cardbus_err(NULL, 1,
+		    " Mem Base 1  = [0x%08x]	Mem Limit 1 = [0x%08x]\n",
+		    pci_config_get32(config_handle, PCI_CBUS_MEM_BASE1),
+		    pci_config_get32(config_handle, PCI_CBUS_MEM_LIMIT1));
+		cardbus_err(NULL, 1,
+		    " IO Base 0   = [0x%08x]	IO Limit 0  = [0x%08x]\n",
+		    pci_config_get32(config_handle, PCI_CBUS_IO_BASE0),
+		    pci_config_get32(config_handle, PCI_CBUS_IO_LIMIT0));
+		cardbus_err(NULL, 1,
+		    " IO Base 1   = [0x%08x]	IO Limit 1  = [0x%08x]\n",
+		    pci_config_get32(config_handle, PCI_CBUS_IO_BASE1),
+		    pci_config_get32(config_handle, PCI_CBUS_IO_LIMIT1));
+		break;
+	}
+	cardbus_err(NULL, 1,
+	    " Intr Line   = [0x%02x]		Intr Pin    = [0x%02x]\n",
+	    pci_config_get8(config_handle, PCI_BCNF_ILINE),
+	    pci_config_get8(config_handle, PCI_BCNF_IPIN));
+	cardbus_err(NULL, 1,
+	    " Bridge Ctrl = [0x%04x]\n",
+	    pci_config_get16(config_handle, PCI_BCNF_BCNTRL));
+
+	switch (header_type) {
+	case PCI_HEADER_CARDBUS:
+		cardbus_err(NULL, 1,
+		    " Sub VID     = [0x%04x]	Sub SID     = [0x%04x]\n",
+		    pci_config_get16(config_handle, PCI_CBUS_SUBVENID),
+		    pci_config_get16(config_handle, PCI_CBUS_SUBSYSID));
+		/* LATER: TI1250 only */
+		cardbus_err(NULL, 1,
+		    " Sys Control = [0x%08x]\n",
+		    pci_config_get32(config_handle, 0x80));
+	}
+}
+
+static void
+cardbus_dump_config(ddi_acc_handle_t config_handle)
+{
+	uint8_t header_type = pci_config_get8(config_handle,
+	    PCI_CONF_HEADER) & PCI_HEADER_TYPE_M;
+
+	if (header_type == PCI_HEADER_PPB || header_type == PCI_HEADER_CARDBUS)
+		cardbus_dump_bridge_config(config_handle, header_type);
+	else
+		cardbus_dump_device_config(config_handle);
+}
+
+static void
+cardbus_dump_reg(dev_info_t *dip, const pci_regspec_t *regspec, int nelems)
+{
+	/* int rlen = nelems * sizeof(pci_regspec_t); */
+
+	cardbus_err(dip, 6,
+	    "cardbus_dump_reg: \"reg\" has %d elements\n", nelems);
+
+#if defined(CARDBUS_DEBUG)
+	if (cardbus_debug >= 1) {
+		int	i;
+		uint32_t *regs = (uint32_t *)regspec;
+
+		for (i = 0; i < nelems; i++) {
+
+			cardbus_err(NULL, 6,
+			    "\t%d:%08x %08x %08x %08x %08x\n",
+			    i, regs[0], regs[1], regs[2], regs[3], regs[4]);
+		}
+	}
+#endif
+}
+
+#endif
+
+#if defined(CARDBUS_DEBUG)
+void
+cardbus_dump_children(dev_info_t *dip, int level)
+{
+	dev_info_t *next;
+
+	cardbus_err(dip, 1,
+	    "\t%d: %s: 0x%p\n", level, ddi_node_name(dip), (void *) dip);
+	for (next = ddi_get_child(dip); next;
+	    next = ddi_get_next_sibling(next))
+		cardbus_dump_children(next, level + 1);
+}
+
+void
+cardbus_dump_family_tree(dev_info_t *dip)
+{
+	cardbus_err(dip, 1, "0x%p family tree:\n", (void *) dip);
+	cardbus_dump_children(dip, 1);
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/cardbus/cardbus_cfg.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+/*
+ * Copyright (c)  * Copyright (c) 2001 Tadpole Technology plc
+ * All rights reserved.
+ */
+
+#ifndef	_SYS_CARDBUS_CFG_H
+#define	_SYS_CARDBUS_CFG_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Cardbus device identifiers
+ */
+#define	CBUS_ID(vend, dev)	((uint32_t)(((uint32_t)(vend) << 16) | (dev)))
+
+#define	CB_PPD_CODE	0x2441
+
+struct cardbus_parent_private_data {
+	struct ddi_parent_private_data	ppd;	/* this format for prtconf */
+	uint16_t	code;	/* == CB_PPD_CODE */
+	/* pci_regspec_t *regs; */
+};
+
+extern kmutex_t cardbus_list_mutex;
+extern int cardbus_latency_timer;
+
+extern int cardbus_configure(cbus_t *cbp);
+extern int cardbus_unconfigure(cbus_t *cbp);
+extern int cardbus_teardown_device(dev_info_t *);
+extern int cardbus_primary_busno(dev_info_t *dip);
+#ifdef sparc
+extern int cardbus_get_class_pil(dev_info_t *rdip);
+#endif
+
+#ifdef DEBUG
+extern void cardbus_dump_children(dev_info_t *dip, int level);
+extern void cardbus_dump_family_tree(dev_info_t *dip);
+#endif
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif	/* _SYS_CARDBUS_CFG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/cardbus/cardbus_hp.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,1823 @@
+/*
+ * 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.
+ */
+
+/*
+ * Copyright (c)  * Copyright (c) 2001 Tadpole Technology plc
+ * All rights reserved.
+ * From "@(#)pcicfg.c   1.31    99/06/18 SMI"
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Cardbus hotplug module
+ */
+
+#include <sys/open.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/ddi.h>
+#include <sys/sunndi.h>
+
+#include <sys/note.h>
+
+#include <sys/pci.h>
+
+#include <sys/hotplug/hpcsvc.h>
+#include <sys/hotplug/pci/pcicfg.h>
+#include <sys/pcic_reg.h>
+
+#include "cardbus.h"
+#include "cardbus_hp.h"
+#include "cardbus_cfg.h"
+
+/*
+ * ************************************************************************
+ * *** Implementation specific data structures/definitions.             ***
+ * ************************************************************************
+ */
+
+#ifndef HPC_MAX_OCCUPANTS
+#define	HPC_MAX_OCCUPANTS 8
+typedef struct hpc_occupant_info {
+	int	i;
+	char 	*id[HPC_MAX_OCCUPANTS];
+} hpc_occupant_info_t;
+#endif
+
+#define	PCICFG_FLAGS_CONTINUE   0x1
+
+#define	PCICFG_OP_ONLINE	0x1
+#define	PCICFG_OP_OFFLINE	0x0
+
+#define	CBHP_DEVCTL_MINOR	255
+
+#define	AP_MINOR_NUM_TO_CB_INSTANCE(x)	((x) & 0xFF)
+#define	AP_MINOR_NUM(x)		(((uint_t)(3) << 8) | ((x) & 0xFF))
+#define	AP_IS_CB_MINOR(x)	(((x)>>8) == (3))
+
+extern int cardbus_debug;
+
+static int cardbus_autocfg_enabled = 1;	/* auto config is enabled by default */
+
+/* static functions */
+static int cardbus_event_handler(caddr_t slot_arg, uint_t event_mask);
+static int cardbus_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl,
+				int request, caddr_t arg);
+static int cardbus_new_slot_state(dev_info_t *dip, hpc_slot_t hdl,
+				hpc_slot_info_t *slot_info, int slot_state);
+static int cardbus_list_occupants(dev_info_t *dip, void *hdl);
+static void create_occupant_props(dev_info_t *self, dev_t dev);
+static void delete_occupant_props(dev_info_t *dip, dev_t dev);
+static int cardbus_configure_ap(cbus_t *cbp);
+static int cardbus_unconfigure_ap(cbus_t *cbp);
+static int cbus_unconfigure(dev_info_t *devi, int prim_bus);
+void cardbus_dump_pci_config(dev_info_t *dip);
+void cardbus_dump_pci_node(dev_info_t *dip);
+
+int
+cardbus_init_hotplug(cbus_t *cbp)
+{
+	char tbuf[MAXNAMELEN];
+	hpc_slot_info_t	slot_info;
+	hpc_slot_ops_t	*slot_ops;
+	hpc_slot_t	slhandle;	/* HPS slot handle */
+
+	/*
+	 *  register the bus instance with the HPS framework.
+	 */
+	if (hpc_nexus_register_bus(cbp->cb_dip,
+	    cardbus_new_slot_state, 0) != 0) {
+		cmn_err(CE_WARN, "%s%d: failed to register the bus with HPS\n",
+		    ddi_driver_name(cbp->cb_dip), cbp->cb_instance);
+		return (DDI_FAILURE);
+	}
+
+	(void) sprintf(cbp->ap_id, "slot%d", cbp->cb_instance);
+	(void) ddi_pathname(cbp->cb_dip, tbuf);
+	cbp->nexus_path = kmem_alloc(strlen(tbuf) + 1, KM_SLEEP);
+	(void) strcpy(cbp->nexus_path, tbuf);
+	cardbus_err(cbp->cb_dip, 8,
+	    "cardbus_init_hotplug: nexus_path set to %s", cbp->nexus_path);
+
+	slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
+	cbp->slot_ops = slot_ops;
+
+	/*
+	 * Fill in the slot information structure that
+	 * describes the slot.
+	 */
+	slot_info.version = HPC_SLOT_INFO_VERSION;
+	slot_info.slot_type = HPC_SLOT_TYPE_PCI;
+	slot_info.slot.pci.device_number = 0;
+	slot_info.slot.pci.slot_capabilities = 0;
+
+	(void) strcpy(slot_info.slot.pci.slot_logical_name, cbp->ap_id);
+
+	slot_ops->hpc_version = HPC_SLOT_OPS_VERSION;
+	slot_ops->hpc_op_connect = NULL;
+	slot_ops->hpc_op_disconnect = NULL;
+	slot_ops->hpc_op_insert = NULL;
+	slot_ops->hpc_op_remove = NULL;
+	slot_ops->hpc_op_control = cardbus_pci_control;
+
+	if (hpc_slot_register(cbp->cb_dip, cbp->nexus_path, &slot_info,
+	    &slhandle, slot_ops, (caddr_t)cbp, 0) != 0) {
+		/*
+		 * If the slot can not be registered,
+		 * then the slot_ops need to be freed.
+		 */
+		cmn_err(CE_WARN,
+		    "cbp%d Unable to Register Slot %s", cbp->cb_instance,
+		    slot_info.slot.pci.slot_logical_name);
+
+		(void) hpc_nexus_unregister_bus(cbp->cb_dip);
+		hpc_free_slot_ops(slot_ops);
+		cbp->slot_ops = NULL;
+		return (DDI_FAILURE);
+	}
+
+	ASSERT(slhandle == cbp->slot_handle);
+
+	cardbus_err(cbp->cb_dip, 8,
+	    "cardbus_init_hotplug: slot_handle 0x%p", cbp->slot_handle);
+	return (DDI_SUCCESS);
+}
+
+static int
+cardbus_event_handler(caddr_t slot_arg, uint_t event_mask)
+{
+	int ap_minor = (int)((uintptr_t)slot_arg);
+	cbus_t *cbp;
+	int cb_instance;
+	int rv = HPC_EVENT_CLAIMED;
+
+	cb_instance = AP_MINOR_NUM_TO_CB_INSTANCE(ap_minor);
+
+	ASSERT(cb_instance >= 0);
+	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
+	mutex_enter(&cbp->cb_mutex);
+
+	switch (event_mask) {
+
+	case HPC_EVENT_SLOT_INSERTION:
+		/*
+		 * A card is inserted in the slot. Just report this
+		 * event and return.
+		 */
+		cardbus_err(cbp->cb_dip, 7,
+		    "cardbus_event_handler(%s%d): card is inserted",
+		    ddi_driver_name(cbp->cb_dip), cbp->cb_instance);
+
+		break;
+
+	case HPC_EVENT_SLOT_CONFIGURE:
+		/*
+		 * Configure the occupant that is just inserted in the slot.
+		 * The receptacle may or may not be in the connected state. If
+		 * the receptacle is not connected and the auto configuration
+		 * is enabled on this slot then connect the slot. If auto
+		 * configuration is enabled then configure the card.
+		 */
+		if (!(cbp->auto_config)) {
+			/*
+			 * auto configuration is disabled.
+			 */
+			cardbus_err(cbp->cb_dip, 7,
+			    "cardbus_event_handler(%s%d): "
+			    "SLOT_CONFIGURE event occured (slot %s)",
+			    ddi_driver_name(cbp->cb_dip), cbp->cb_instance,
+			    cbp->name);
+
+			break;
+		}
+
+		cardbus_err(cbp->cb_dip, 7,
+		    "cardbus_event_handler(%s%d): configure event",
+		    ddi_driver_name(cbp->cb_dip), cbp->cb_instance);
+
+		if (cbp->ostate != AP_OSTATE_UNCONFIGURED) {
+			cmn_err(CE_WARN, "!slot%d already configured\n",
+				cbp->cb_instance);
+			break;
+		}
+
+		/*
+		 * Auto configuration is enabled. First, make sure the
+		 * receptacle is in the CONNECTED state.
+		 */
+		if ((rv = hpc_nexus_connect(cbp->slot_handle,
+		    NULL, 0)) == HPC_SUCCESS) {
+			cbp->rstate = AP_RSTATE_CONNECTED; /* record rstate */
+		}
+
+		if (cardbus_configure_ap(cbp) == HPC_SUCCESS)
+			create_occupant_props(cbp->cb_dip,
+			    makedevice(ddi_name_to_major(ddi_get_name
+			    (cbp->cb_dip)),
+			    ap_minor));
+		else
+			rv = HPC_ERR_FAILED;
+
+		break;
+
+	case HPC_EVENT_SLOT_UNCONFIGURE:
+		/*
+		 * Unconfigure the occupant in this slot.
+		 */
+		if (!(cbp->auto_config)) {
+			/*
+			 * auto configuration is disabled.
+			 */
+			cardbus_err(cbp->cb_dip, 7,
+			    "cardbus_event_handler(%s%d): "
+			    "SLOT_UNCONFIGURE event"
+			    " occured - auto-conf disabled (slot %s)",
+			    ddi_driver_name(cbp->cb_dip), cbp->cb_instance,
+			    cbp->name);
+
+			break;
+		}
+
+		cardbus_err(cbp->cb_dip, 7,
+		    "cardbus_event_handler(%s%d): SLOT_UNCONFIGURE event"
+		    " occured (slot %s)",
+		    ddi_driver_name(cbp->cb_dip), cbp->cb_instance,
+		    cbp->name);
+
+		if (cardbus_unconfigure_ap(cbp) != HPC_SUCCESS)
+			rv = HPC_ERR_FAILED;
+
+		break;
+
+	case HPC_EVENT_SLOT_REMOVAL:
+		/*
+		 * Card is removed from the slot. The card must have been
+		 * unconfigured before this event.
+		 */
+		if (cbp->ostate != AP_OSTATE_UNCONFIGURED) {
+			cardbus_err(cbp->cb_dip, 1,
+			    "cardbus_event_handler(%s%d): "
+			    "card is removed from"
+			    " the slot %s before doing unconfigure!!",
+			    ddi_driver_name(cbp->cb_dip), cbp->cb_instance,
+			    cbp->name);
+
+			break;
+		}
+
+		cardbus_err(cbp->cb_dip, 7,
+		    "cardbus_event_handler(%s%d): "
+		    "card is removed from the slot %s",
+		    ddi_driver_name(cbp->cb_dip), cbp->cb_instance,
+		    cbp->name);
+
+		break;
+
+	case HPC_EVENT_SLOT_POWER_ON:
+		/*
+		 * Slot is connected to the bus. i.e the card is powered
+		 * on.
+		 */
+		cardbus_err(cbp->cb_dip, 7,
+		    "cardbus_event_handler(%s%d): "
+		    "card is powered on in the slot %s",
+		    ddi_driver_name(cbp->cb_dip), cbp->cb_instance,
+		    cbp->name);
+
+		cbp->rstate = AP_RSTATE_CONNECTED; /* record rstate */
+
+		break;
+
+	case HPC_EVENT_SLOT_POWER_OFF:
+		/*
+		 * Slot is disconnected from the bus. i.e the card is powered
+		 * off.
+		 */
+		cardbus_err(cbp->cb_dip, 7,
+		    "cardbus_event_handler(%s%d): "
+		    "card is powered off in the slot %s",
+		    ddi_driver_name(cbp->cb_dip), cbp->cb_instance,
+		    cbp->name);
+
+		cbp->rstate = AP_RSTATE_DISCONNECTED; /* record rstate */
+
+		break;
+
+	default:
+		cardbus_err(cbp->cb_dip, 4,
+		    "cardbus_event_handler(%s%d): "
+		    "unknown event %x for this slot %s",
+		    ddi_driver_name(cbp->cb_dip), cbp->cb_instance,
+		    event_mask, cbp->name);
+
+		break;
+	}
+
+	mutex_exit(&cbp->cb_mutex);
+
+	return (rv);
+}
+
+static int
+cardbus_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request,
+			caddr_t arg)
+{
+	cbus_t *cbp;
+	int rval = HPC_SUCCESS;
+	hpc_led_info_t *hpc_led_info;
+
+	_NOTE(ARGUNUSED(slot_hdl))
+
+	cbp = (cbus_t *)ops_arg;
+	ASSERT(mutex_owned(&cbp->cb_mutex));
+
+	switch (request) {
+
+	case HPC_CTRL_GET_SLOT_STATE:
+	    {
+		hpc_slot_state_t	*hpc_slot_state;
+
+		hpc_slot_state = (hpc_slot_state_t *)arg;
+
+		cardbus_err(cbp->cb_dip, 7,
+		    "cardbus_pci_control() - "
+		    "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=0x%p",
+		    (void *) hpc_slot_state);
+
+		if (cbp->card_present)
+			*hpc_slot_state = HPC_SLOT_CONNECTED;
+		else
+			*hpc_slot_state = HPC_SLOT_EMPTY;
+
+		break;
+	    }
+
+	case HPC_CTRL_GET_BOARD_TYPE:
+	    {
+		hpc_board_type_t	*hpc_board_type;
+
+		hpc_board_type = (hpc_board_type_t *)arg;
+
+		cardbus_err(cbp->cb_dip, 7,
+		    "cardbus_pci_control() - HPC_CTRL_GET_BOARD_TYPE");
+
+		/*
+		 * The HPC driver does not know what board type
+		 * is plugged in.
+		 */
+		*hpc_board_type = HPC_BOARD_PCI_HOTPLUG;
+
+		break;
+	    }
+
+	case HPC_CTRL_DEV_CONFIGURED:
+	case HPC_CTRL_DEV_UNCONFIGURED:
+		cardbus_err(cbp->cb_dip, 5,
+		    "cardbus_pci_control() - HPC_CTRL_DEV_%sCONFIGURED",
+		    request == HPC_CTRL_DEV_UNCONFIGURED ? "UN" : "");
+		break;
+
+	case HPC_CTRL_GET_LED_STATE:
+		hpc_led_info = (hpc_led_info_t *)arg;
+		cardbus_err(cbp->cb_dip, 5,
+		    "cardbus_pci_control() - HPC_CTRL_GET_LED_STATE "
+		    "led %d is %d",
+		    hpc_led_info->led, cbp->leds[hpc_led_info->led]);
+
+		hpc_led_info->state = cbp->leds[hpc_led_info->led];
+		break;
+
+	case HPC_CTRL_SET_LED_STATE:
+		hpc_led_info = (hpc_led_info_t *)arg;
+
+		cardbus_err(cbp->cb_dip, 4,
+		    "cardbus_pci_control() - HPC_CTRL_SET_LED_STATE "
+		    "led %d to %d",
+		    hpc_led_info->led, hpc_led_info->state);
+
+		cbp->leds[hpc_led_info->led] = hpc_led_info->state;
+		break;
+
+	case HPC_CTRL_ENABLE_AUTOCFG:
+		cardbus_err(cbp->cb_dip, 5,
+		    "cardbus_pci_control() - HPC_CTRL_ENABLE_AUTOCFG");
+
+		/*
+		 * Cardbus ALWAYS does auto config, from the slots point of
+		 * view this is turning on the card and making sure it's ok.
+		 * This is all done by the bridge driver before we see any
+		 * indication.
+		 */
+		break;
+
+	case HPC_CTRL_DISABLE_AUTOCFG:
+		cardbus_err(cbp->cb_dip, 5,
+		    "cardbus_pci_control() - HPC_CTRL_DISABLE_AUTOCFG");
+		break;
+
+	case HPC_CTRL_DISABLE_ENUM:
+	case HPC_CTRL_ENABLE_ENUM:
+	default:
+		rval = HPC_ERR_NOTSUPPORTED;
+		break;
+	}
+
+	return (rval);
+}
+
+/*
+ * cardbus_new_slot_state()
+ *
+ * This function is called by the HPS when it finds a hot plug
+ * slot is added or being removed from the hot plug framework.
+ * It returns 0 for success and HPC_ERR_FAILED for errors.
+ */
+static int
+cardbus_new_slot_state(dev_info_t *dip, hpc_slot_t hdl,
+			hpc_slot_info_t *slot_info, int slot_state)
+{
+	int cb_instance;
+	cbus_t *cbp;
+	int ap_minor;
+	int rv = 0;
+
+	cardbus_err(dip, 8,
+	    "cardbus_new_slot_state: slot_handle 0x%p", hdl);
+
+	/*
+	 * get the soft state structure for the bus instance.
+	 */
+	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "cbus-instance", -1);
+	    ASSERT(cb_instance >= 0);
+	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
+
+	mutex_enter(&cbp->cb_mutex);
+
+	switch (slot_state) {
+
+	case HPC_SLOT_ONLINE:
+		/*
+		 * Make sure the slot is not already ONLINE
+		 */
+		if (cbp->slot_handle != NULL) {
+			cardbus_err(dip, 4,
+			    "cardbus_new_slot_state: "
+			    "cardbus already ONLINE!!");
+			rv = HPC_ERR_FAILED;
+			break;
+		}
+
+		/*
+		 * Add the hot plug slot to the bus.
+		 */
+
+		/* create the AP minor node */
+		ap_minor = AP_MINOR_NUM(cb_instance);
+		if (ddi_create_minor_node(dip, slot_info->pci_slot_name,
+		    S_IFCHR, ap_minor,
+		    DDI_NT_PCI_ATTACHMENT_POINT,
+		    0) == DDI_FAILURE) {
+			cardbus_err(dip, 4,
+			    "cardbus_new_slot_state: "
+			    "ddi_create_minor_node failed");
+			rv = HPC_ERR_FAILED;
+			break;
+		}
+
+		/* save the slot handle */
+		cbp->slot_handle = hdl;
+
+		/* setup event handler for all hardware events on the slot */
+		if (hpc_install_event_handler(hdl, -1, cardbus_event_handler,
+		    (caddr_t)((long)ap_minor)) != 0) {
+			cardbus_err(dip, 4,
+			    "cardbus_new_slot_state: "
+			    "install event handler failed");
+			rv = HPC_ERR_FAILED;
+			break;
+		}
+		cbp->event_mask = (uint32_t)0xFFFFFFFF;
+		create_occupant_props(dip,
+		    makedevice(ddi_name_to_major(ddi_get_name(dip)),
+		    ap_minor));
+
+		/* set default auto configuration enabled flag for this slot */
+		cbp->auto_config = cardbus_autocfg_enabled;
+
+		/* copy the slot information */
+		cbp->name = (char *)kmem_alloc(strlen(slot_info->pci_slot_name)
+		    + 1, KM_SLEEP);
+		(void) strcpy(cbp->name, slot_info->pci_slot_name);
+		cardbus_err(cbp->cb_dip, 10,
+		    "cardbus_new_slot_state: cbp->name set to %s", cbp->name);
+
+		cardbus_err(dip, 4,
+		    "Cardbus slot \"%s\" ONLINE\n", slot_info->pci_slot_name);
+
+		cbp->ostate = AP_OSTATE_UNCONFIGURED;
+		cbp->rstate = AP_RSTATE_EMPTY;
+
+		break;
+
+	case HPC_SLOT_OFFLINE:
+		/*
+		 * A hot plug slot is being removed from the bus.
+		 * Make sure there is no occupant configured on the
+		 * slot before removing the AP minor node.
+		 */
+		if (cbp->ostate != AP_OSTATE_UNCONFIGURED) {
+			cmn_err(CE_WARN,
+			    "cardbus: Card is still in configured state");
+			rv = HPC_ERR_FAILED;
+			break;
+		}
+
+		/*
+		 * If the AP device is in open state then return
+		 * error.
+		 */
+		if (cbp->soft_state != PCIHP_SOFT_STATE_CLOSED) {
+			rv = HPC_ERR_FAILED;
+			break;
+		}
+
+		/* remove the minor node */
+		ddi_remove_minor_node(dip, cbp->name);
+		/* free up the memory for the name string */
+		kmem_free(cbp->name, strlen(cbp->name) + 1);
+
+		/* update the slot info data */
+		cbp->name = NULL;
+		cbp->slot_handle = NULL;
+
+		cardbus_err(dip, 6,
+		    "cardbus_new_slot_state: Cardbus slot OFFLINE");
+		break;
+
+	default:
+		cmn_err(CE_WARN,
+		    "cardbus_new_slot_state: unknown slot_state %d\n",
+		    slot_state);
+		rv = HPC_ERR_FAILED;
+	}
+
+	mutex_exit(&cbp->cb_mutex);
+
+	return (rv);
+}
+
+static int
+cardbus_list_occupants(dev_info_t *dip, void *hdl)
+{
+	hpc_occupant_info_t *occupant = (hpc_occupant_info_t *)hdl;
+	char pn[MAXPATHLEN];
+
+	/*
+	 * Ignore the attachment point and pcs.
+	 */
+	if (strcmp(ddi_binding_name(dip), "pcs") == 0) {
+		return (DDI_WALK_CONTINUE);
+	}
+
+	(void) ddi_pathname(dip, pn);
+
+	occupant->id[occupant->i] = kmem_alloc(strlen(pn) + 1, KM_SLEEP);
+	(void) strcpy(occupant->id[occupant->i], pn);
+
+	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);
+}
+
+static void
+create_occupant_props(dev_info_t *self, dev_t dev)
+{
+	hpc_occupant_info_t occupant;
+	int i;
+	int circular;
+
+	occupant.i = 0;
+
+	ndi_devi_enter(self, &circular);
+	ddi_walk_devs(ddi_get_child(self), cardbus_list_occupants,
+	    (void *)&occupant);
+	ndi_devi_exit(self, circular);
+
+	if (occupant.i == 0) {
+		char *c[] = { "" };
+		cardbus_err(self, 1, "create_occupant_props: no occupant\n");
+		(void) ddi_prop_update_string_array(dev, self, "pci-occupant",
+		    c, 1);
+	} else {
+		cardbus_err(self, 1,
+		    "create_occupant_props: %d occupant\n", occupant.i);
+		(void) ddi_prop_update_string_array(dev, self, "pci-occupant",
+		    occupant.id, occupant.i);
+	}
+
+	for (i = 0; i < occupant.i; i++) {
+		kmem_free(occupant.id[i], strlen(occupant.id[i]) + 1);
+	}
+}
+
+static void
+delete_occupant_props(dev_info_t *dip, dev_t dev)
+{
+	if (ddi_prop_remove(dev, dip, "pci-occupant")
+	    != DDI_PROP_SUCCESS)
+		return; /* add error handling */
+
+}
+
+/*
+ * **************************************
+ * CONFIGURE the occupant in the slot.
+ * **************************************
+ */
+static int
+cardbus_configure_ap(cbus_t *cbp)
+{
+	dev_info_t *self = cbp->cb_dip;
+	int rv = HPC_SUCCESS;
+	hpc_slot_state_t rstate;
+	struct cardbus_config_ctrl ctrl;
+	int circular_count;
+
+	/*
+	 * check for valid request:
+	 *  1. It is a hotplug slot.
+	 *  2. The receptacle is in the CONNECTED state.
+	 */
+	if (cbp->slot_handle == NULL || cbp->disabled) {
+		return (ENXIO);
+	}
+
+	/*
+	 * If the occupant is already in (partially) configured
+	 * state then call the ndi_devi_online() on the device
+	 * subtree(s) for this attachment point.
+	 */
+
+	if (cbp->ostate == AP_OSTATE_CONFIGURED) {
+		ctrl.flags = PCICFG_FLAGS_CONTINUE;
+		ctrl.busno = cardbus_primary_busno(self);
+		ctrl.rv = NDI_SUCCESS;
+		ctrl.dip = NULL;
+		ctrl.op = PCICFG_OP_ONLINE;
+
+		ndi_devi_enter(self, &circular_count);
+		ddi_walk_devs(ddi_get_child(self),
+			cbus_configure, (void *)&ctrl);
+		ndi_devi_exit(self, circular_count);
+
+		if (cardbus_debug) {
+			cardbus_dump_pci_config(self);
+			cardbus_dump_pci_node(self);
+		}
+
+		if (ctrl.rv != NDI_SUCCESS) {
+			/*
+			 * one or more of the devices are not
+			 * onlined.
+			 */
+			cmn_err(CE_WARN, "cardbus(%s%d): failed to attach "
+			    "one or more drivers for the card in the slot %s",
+			    ddi_driver_name(self), cbp->cb_instance,
+			    cbp->name);
+		}
+
+		/* tell HPC driver that the occupant is configured */
+		(void) hpc_nexus_control(cbp->slot_handle,
+		    HPC_CTRL_DEV_CONFIGURED, NULL);
+		return (rv);
+	}
+
+	/*
+	 * Occupant is in the UNCONFIGURED state.
+	 */
+
+	/* Check if the receptacle is in the CONNECTED state. */
+	if (hpc_nexus_control(cbp->slot_handle,
+	    HPC_CTRL_GET_SLOT_STATE, (caddr_t)&rstate) != 0) {
+		return (ENXIO);
+	}
+
+	if (rstate != HPC_SLOT_CONNECTED) {
+		/* error. either the slot is empty or connect failed */
+		return (ENXIO);
+	}
+
+	cbp->rstate = AP_RSTATE_CONNECTED; /* record rstate */
+
+	/*
+	 * Call the configurator to configure the card.
+	 */
+	if (cardbus_configure(cbp) != PCICFG_SUCCESS) {
+		return (EIO);
+	}
+
+	/* record the occupant state as CONFIGURED */
+	cbp->ostate = AP_OSTATE_CONFIGURED;
+	cbp->condition = AP_COND_OK;
+
+	/* now, online all the devices in the AP */
+	ctrl.flags = PCICFG_FLAGS_CONTINUE;
+	ctrl.busno = cardbus_primary_busno(self);
+	ctrl.rv = NDI_SUCCESS;
+	ctrl.dip = NULL;
+	ctrl.op = PCICFG_OP_ONLINE;
+
+	ndi_devi_enter(self, &circular_count);
+	ddi_walk_devs(ddi_get_child(self), cbus_configure, (void *)&ctrl);
+	ndi_devi_exit(self, circular_count);
+
+	if (cardbus_debug) {
+		cardbus_dump_pci_config(self);
+		cardbus_dump_pci_node(self);
+	}
+	if (ctrl.rv != NDI_SUCCESS) {
+		/*
+		 * one or more of the devices are not
+		 * ONLINE'd.
+		 */
+		cmn_err(CE_WARN, "cbhp (%s%d): failed to attach one or"
+		    " more drivers for the card in the slot %s",
+		    ddi_driver_name(cbp->cb_dip),
+		    cbp->cb_instance, cbp->name);
+		/* rv = EFAULT; */
+	}
+
+	/* tell HPC driver that the occupant is configured */
+	(void) hpc_nexus_control(cbp->slot_handle,
+		HPC_CTRL_DEV_CONFIGURED, NULL);
+
+	return (rv);
+}
+
+/*
+ * **************************************
+ * UNCONFIGURE the occupant in the slot.
+ * **************************************
+ */
+static int
+cardbus_unconfigure_ap(cbus_t *cbp)
+{
+	dev_info_t *self = cbp->cb_dip;
+	int rv = HPC_SUCCESS, nrv;
+
+	/*
+	 * check for valid request:
+	 *  1. It is a hotplug slot.
+	 *  2. The occupant is in the CONFIGURED state.
+	 */
+
+	if (cbp->slot_handle == NULL || cbp->disabled) {
+		return (ENXIO);
+	}
+
+	/*
+	 * If the occupant is in the CONFIGURED state then
+	 * call the configurator to unconfigure the slot.
+	 */
+	if (cbp->ostate == AP_OSTATE_CONFIGURED) {
+		/*
+		 * Detach all the drivers for the devices in the
+		 * slot.
+		 */
+		nrv = cardbus_unconfigure_node(self,
+		    cardbus_primary_busno(self),
+		    B_TRUE);
+
+		if (nrv != NDI_SUCCESS) {
+			/*
+			 * Failed to detach one or more drivers.
+			 * Restore the status for the drivers
+			 * which are offlined during this step.
+			 */
+			cmn_err(CE_WARN,
+			    "cbhp (%s%d): Failed to offline all devices"
+			    " (slot %s)", ddi_driver_name(cbp->cb_dip),
+			    cbp->cb_instance, cbp->name);
+			rv = EBUSY;
+		} else {
+
+			if (cardbus_unconfigure(cbp) == PCICFG_SUCCESS) {
+				/*
+				 * Now that resources are freed,
+				 * clear EXT and Turn LED ON.
+				 */
+				cbp->ostate = AP_OSTATE_UNCONFIGURED;
+				cbp->condition = AP_COND_UNKNOWN;
+				/*
+				 * send the notification of state change
+				 * to the HPC driver.
+				 */
+				(void) hpc_nexus_control(cbp->slot_handle,
+				    HPC_CTRL_DEV_UNCONFIGURED, NULL);
+			} else {
+				rv = EIO;
+			}
+		}
+	}
+
+	return (rv);
+}
+
+int
+cbus_configure(dev_info_t *dip, void *hdl)
+{
+	pci_regspec_t *pci_rp;
+	int length, rc;
+	struct cardbus_config_ctrl *ctrl = (struct cardbus_config_ctrl *)hdl;
+	uint8_t bus, device, function;
+
+	/*
+	 * Ignore the attachment point and pcs.
+	 */
+	if (strcmp(ddi_binding_name(dip), "hp_attachment") == 0 ||
+	    strcmp(ddi_binding_name(dip), "pcs") == 0) {
+		cardbus_err(dip, 8, "cbus_configure: Ignoring\n");
+		return (DDI_WALK_CONTINUE);
+	}
+
+	cardbus_err(dip, 6, "cbus_configure\n");
+
+	ASSERT(ctrl->op == PCICFG_OP_ONLINE);
+
+	/*
+	 * 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) {
+		/* Porbably not a real device, like PCS for example */
+		if (ddi_get_child(dip) == NULL)
+			return (DDI_WALK_PRUNECHILD);
+
+		cardbus_err(dip, 1, "cubs_configure: Don't configure device\n");
+		ctrl->rv = DDI_FAILURE;
+		ctrl->dip = dip;
+		return (DDI_WALK_TERMINATE);
+	}
+
+	if (pci_rp->pci_phys_hi == 0)
+		return (DDI_WALK_CONTINUE);
+
+	/* get the pci device id information */
+	bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
+	device = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
+	function = 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 (bus <= ctrl->busno)
+		return (DDI_WALK_CONTINUE);
+
+	cardbus_err(dip, 8,
+	    "cbus_configure on-line device at: "
+	    "[0x%x][0x%x][0x%x]\n", bus, device, function);
+
+	rc = ndi_devi_online(dip, NDI_ONLINE_ATTACH|NDI_CONFIG);
+
+	cardbus_err(dip, 7,
+	    "cbus_configure %s\n",
+	    rc == NDI_SUCCESS ? "Success": "Failure");
+
+	if (rc != NDI_SUCCESS)
+		return (DDI_WALK_PRUNECHILD);
+
+	return (DDI_WALK_CONTINUE);
+}
+
+int
+cardbus_unconfigure_node(dev_info_t *dip, int prim_bus, boolean_t top_bridge)
+{
+	dev_info_t *child, *next;
+
+	cardbus_err(dip, 6, "cardbus_unconfigure_node\n");
+
+	/*
+	 * Ignore pcs.
+	 */
+	if (strcmp(ddi_binding_name(dip), "pcs") == 0) {
+		cardbus_err(dip, 8, "cardbus_unconfigure_node: Ignoring\n");
+		return (NDI_SUCCESS);
+	}
+
+	/*
+	 * bottom up off-line
+	 */
+	for (child = ddi_get_child(dip); child; child = next) {
+		int rc;
+		next = ddi_get_next_sibling(child);
+		rc = cardbus_unconfigure_node(child, prim_bus, B_FALSE);
+		if (rc != NDI_SUCCESS)
+			return (rc);
+	}
+
+	/*
+	 * Don't unconfigure the bridge itself.
+	 */
+	if (top_bridge)
+		return (NDI_SUCCESS);
+
+	if (cbus_unconfigure(dip, prim_bus) != NDI_SUCCESS) {
+		cardbus_err(dip, 1,
+		    "cardbus_unconfigure_node: cardbus_unconfigure failed\n");
+		return (NDI_FAILURE);
+	}
+	return (NDI_SUCCESS);
+}
+
+/*
+ * This will turn  resources allocated by cbus_configure()
+ * and remove the device tree from the attachment point
+ * and below.  The routine assumes the devices have their
+ * drivers detached.
+ */
+static int
+cbus_unconfigure(dev_info_t *devi, int prim_bus)
+{
+	pci_regspec_t *pci_rp;
+	uint_t bus, device, func, length;
+	int ndi_flags = NDI_UNCONFIG;
+
+	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, devi,
+	    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
+	    &length) != DDI_PROP_SUCCESS) {
+		/*
+		 * This cannot be one of our devices. If it's something like a
+		 * SCSI device then the attempt to offline the HBA
+		 * (which probably is one of our devices)
+		 * will also do bottom up offlining. That
+		 * will fail if this device is busy. So always
+		 * return success here
+		 * so that the walk will continue.
+		 */
+		return (NDI_SUCCESS);
+	}
+
+	if (pci_rp->pci_phys_hi == 0)
+		return (NDI_FAILURE);
+
+	bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
+
+	if (bus <= prim_bus)
+		return (NDI_SUCCESS);
+
+	device = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
+	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
+	ddi_prop_free(pci_rp);
+
+	cardbus_err(devi, 8,
+	    "cbus_unconfigure: "
+	    "offline bus [0x%x] device [0x%x] function [%x]\n",
+	    bus, device, func);
+	if (ndi_devi_offline(devi, ndi_flags) != NDI_SUCCESS) {
+		cardbus_err(devi, 1,
+		    "Device [0x%x] function [%x] is busy\n", device, func);
+		return (NDI_FAILURE);
+	}
+
+	cardbus_err(devi, 9,
+	    "Tearing down device [0x%x] function [0x%x]\n", device, func);
+
+	if (cardbus_teardown_device(devi) != PCICFG_SUCCESS) {
+		cardbus_err(devi, 1,
+		    "Failed to tear down "
+		    "device [0x%x] function [0x%x]\n", device, func);
+		return (NDI_FAILURE);
+	}
+
+	return (NDI_SUCCESS);
+}
+
+boolean_t
+cardbus_is_cb_minor(dev_t dev)
+{
+	return (AP_IS_CB_MINOR(getminor(dev)) ? B_TRUE : B_FALSE);
+}
+
+int
+cardbus_open(dev_t *devp, int flags, int otyp, cred_t *credp)
+{
+	cbus_t *cbp;
+	int minor;
+
+	_NOTE(ARGUNUSED(credp))
+
+	minor = getminor(*devp);
+
+	/*
+	 * Make sure the open is for the right file type.
+	 */
+	if (otyp != OTYP_CHR)
+	return (EINVAL);
+
+	/*
+	 * Get the soft state structure for the 'devctl' device.
+	 */
+	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state,
+		AP_MINOR_NUM_TO_CB_INSTANCE(minor));
+	if (cbp == NULL)
+		return (ENXIO);
+
+	mutex_enter(&cbp->cb_mutex);
+
+	/*
+	 * Handle the open by tracking the device state.
+	 *
+	 * Note: Needs review w.r.t exclusive access to AP or the bus.
+	 * Currently in the pci plug-in we don't use EXCL open at all
+	 * so the code below implements EXCL access on the bus.
+	 */
+
+	/* enforce exclusive access to the bus */
+	if ((cbp->soft_state == PCIHP_SOFT_STATE_OPEN_EXCL) ||
+	    ((flags & FEXCL) &&
+	    (cbp->soft_state != PCIHP_SOFT_STATE_CLOSED))) {
+		mutex_exit(&cbp->cb_mutex);
+		return (EBUSY);
+	}
+
+	if (flags & FEXCL)
+		cbp->soft_state = PCIHP_SOFT_STATE_OPEN_EXCL;
+	else
+		cbp->soft_state = PCIHP_SOFT_STATE_OPEN;
+
+	mutex_exit(&cbp->cb_mutex);
+	return (0);
+}
+
+/*ARGSUSED*/
+int
+cardbus_close(dev_t dev, int flags, int otyp, cred_t *credp)
+{
+	cbus_t *cbp;
+	int minor;
+
+	_NOTE(ARGUNUSED(credp))
+
+	minor = getminor(dev);
+
+	if (otyp != OTYP_CHR)
+		return (EINVAL);
+
+	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state,
+	    AP_MINOR_NUM_TO_CB_INSTANCE(minor));
+	if (cbp == NULL)
+		return (ENXIO);
+
+	mutex_enter(&cbp->cb_mutex);
+	cbp->soft_state = PCIHP_SOFT_STATE_CLOSED;
+	mutex_exit(&cbp->cb_mutex);
+	return (0);
+}
+
+/*
+ * cardbus_ioctl: devctl hotplug controls
+ */
+/*ARGSUSED*/
+int
+cardbus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
+		int *rvalp)
+{
+	cbus_t *cbp;
+	dev_info_t *self;
+	dev_info_t *child_dip = NULL;
+	struct devctl_iocdata *dcp;
+	uint_t bus_state;
+	int rv = 0;
+	int nrv = 0;
+	int ap_minor;
+	hpc_slot_state_t rstate;
+	devctl_ap_state_t ap_state;
+	struct hpc_control_data hpc_ctrldata;
+	struct hpc_led_info led_info;
+
+	_NOTE(ARGUNUSED(credp))
+
+	ap_minor = getminor(dev);
+	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state,
+	    AP_MINOR_NUM_TO_CB_INSTANCE(ap_minor));
+	if (cbp == NULL)
+		return (ENXIO);
+
+	self = cbp->cb_dip;
+	/*
+	 * read devctl ioctl data
+	 */
+	if ((cmd != DEVCTL_AP_CONTROL) && ndi_dc_allochdl((void *)arg,
+	    &dcp) != NDI_SUCCESS)
+		return (EFAULT);
+
+#ifdef CARDBUS_DEBUG
+{
+	char *cmd_name;
+
+	switch (cmd) {
+	case DEVCTL_DEVICE_GETSTATE: cmd_name = "DEVCTL_DEVICE_GETSTATE"; break;
+	case DEVCTL_DEVICE_ONLINE: cmd_name = "DEVCTL_DEVICE_ONLINE"; break;
+	case DEVCTL_DEVICE_OFFLINE: cmd_name = "DEVCTL_DEVICE_OFFLINE"; break;
+	case DEVCTL_DEVICE_RESET: cmd_name = "DEVCTL_DEVICE_RESET"; break;
+	case DEVCTL_BUS_QUIESCE: cmd_name = "DEVCTL_BUS_QUIESCE"; break;
+	case DEVCTL_BUS_UNQUIESCE: cmd_name = "DEVCTL_BUS_UNQUIESCE"; break;
+	case DEVCTL_BUS_RESET: cmd_name = "DEVCTL_BUS_RESET"; break;
+	case DEVCTL_BUS_RESETALL: cmd_name = "DEVCTL_BUS_RESETALL"; break;
+	case DEVCTL_BUS_GETSTATE: cmd_name = "DEVCTL_BUS_GETSTATE"; break;
+	case DEVCTL_AP_CONNECT: cmd_name = "DEVCTL_AP_CONNECT"; break;
+	case DEVCTL_AP_DISCONNECT: cmd_name = "DEVCTL_AP_DISCONNECT"; break;
+	case DEVCTL_AP_INSERT: cmd_name = "DEVCTL_AP_INSERT"; break;
+	case DEVCTL_AP_REMOVE: cmd_name = "DEVCTL_AP_REMOVE"; break;
+	case DEVCTL_AP_CONFIGURE: cmd_name = "DEVCTL_AP_CONFIGURE"; break;
+	case DEVCTL_AP_UNCONFIGURE: cmd_name = "DEVCTL_AP_UNCONFIGURE"; break;
+	case DEVCTL_AP_GETSTATE: cmd_name = "DEVCTL_AP_GETSTATE"; break;
+	case DEVCTL_AP_CONTROL: cmd_name = "DEVCTL_AP_CONTROL"; break;
+	default: cmd_name = "Unknown"; break;
+	}
+	cardbus_err(cbp->cb_dip, 7,
+	    "cardbus_ioctl: cmd = 0x%x, \"%s\"", cmd, cmd_name);
+}
+#endif
+
+	switch (cmd) {
+	case DEVCTL_DEVICE_GETSTATE:
+	case DEVCTL_DEVICE_ONLINE:
+	case DEVCTL_DEVICE_OFFLINE:
+	case DEVCTL_BUS_GETSTATE:
+		rv = ndi_devctl_ioctl(self, cmd, arg, mode, 0);
+		ndi_dc_freehdl(dcp);
+		return (rv);
+	default:
+		break;
+	}
+
+	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;
+
+	case DEVCTL_AP_CONNECT:
+	case DEVCTL_AP_DISCONNECT:
+		/*
+		 * CONNECT(DISCONNECT) the hot plug slot to(from) the bus.
+		 */
+	case DEVCTL_AP_INSERT:
+	case DEVCTL_AP_REMOVE:
+		/*
+		 * Prepare the slot for INSERT/REMOVE operation.
+		 */
+
+		/*
+		 * check for valid request:
+		 * 	1. It is a hotplug slot.
+		 * 	2. The slot has no occupant that is in
+		 * 	the 'configured' state.
+		 *
+		 * The lower 8 bits of the minor number is the PCI
+		 * device number for the slot.
+		 */
+		if ((cbp->slot_handle == NULL) || cbp->disabled) {
+			rv = ENXIO;
+			break;
+		}
+
+		/* the slot occupant must be in the UNCONFIGURED state */
+		if (cbp->ostate != AP_OSTATE_UNCONFIGURED) {
+			rv = EINVAL;
+			break;
+		}
+
+		/*
+		 * Call the HPC driver to perform the operation on the slot.
+		 */
+		mutex_enter(&cbp->cb_mutex);
+		switch (cmd) {
+		case DEVCTL_AP_INSERT:
+			rv = hpc_nexus_insert(cbp->slot_handle, NULL, 0);
+			break;
+		case DEVCTL_AP_REMOVE:
+			rv = hpc_nexus_remove(cbp->slot_handle, NULL, 0);
+			break;
+		case DEVCTL_AP_CONNECT:
+			if ((rv = hpc_nexus_connect(cbp->slot_handle,
+			    NULL, 0)) == 0)
+				cbp->rstate = AP_RSTATE_CONNECTED;
+			break;
+		case DEVCTL_AP_DISCONNECT:
+			if ((rv = hpc_nexus_disconnect(cbp->slot_handle,
+			    NULL, 0)) == 0)
+				cbp->rstate = AP_RSTATE_DISCONNECTED;
+			break;
+		}
+		mutex_exit(&cbp->cb_mutex);
+
+		switch (rv) {
+		case HPC_ERR_INVALID:
+			rv = ENXIO;
+			break;
+		case HPC_ERR_NOTSUPPORTED:
+			rv = ENOTSUP;
+			break;
+		case HPC_ERR_FAILED:
+			rv = EIO;
+			break;
+		}
+
+		break;
+
+	case DEVCTL_AP_CONFIGURE:
+		/*
+		 * **************************************
+		 * CONFIGURE the occupant in the slot.
+		 * **************************************
+		 */
+
+		mutex_enter(&cbp->cb_mutex);
+		if ((nrv = cardbus_configure_ap(cbp)) == HPC_SUCCESS) {
+			create_occupant_props(cbp->cb_dip, dev);
+		} else
+			rv = nrv;
+		mutex_exit(&cbp->cb_mutex);
+		break;
+
+	case DEVCTL_AP_UNCONFIGURE:
+		/*
+		 * **************************************
+		 * UNCONFIGURE the occupant in the slot.
+		 * **************************************
+		 */
+
+		mutex_enter(&cbp->cb_mutex);
+		if ((nrv = cardbus_unconfigure_ap(cbp)) == HPC_SUCCESS) {
+			delete_occupant_props(cbp->cb_dip, dev);
+		} else
+			rv = nrv;
+		mutex_exit(&cbp->cb_mutex);
+		break;
+
+	case DEVCTL_AP_GETSTATE:
+	    {
+		int mutex_held;
+
+		/*
+		 * return the state of Attachment Point.
+		 *
+		 * If the occupant is in UNCONFIGURED state then
+		 * we should get the receptacle state from the
+		 * HPC driver because the receptacle state
+		 * maintained in the nexus may not be accurate.
+		 */
+
+		/*
+		 * check for valid request:
+		 * 	1. It is a hotplug slot.
+		 */
+		if (cbp->slot_handle == NULL) {
+			rv = ENXIO;
+			break;
+		}
+
+		/* try to acquire the slot mutex */
+		mutex_held = mutex_tryenter(&cbp->cb_mutex);
+
+		if (cbp->ostate == AP_OSTATE_UNCONFIGURED) {
+			if (hpc_nexus_control(cbp->slot_handle,
+			    HPC_CTRL_GET_SLOT_STATE,
+			    (caddr_t)&rstate) != 0) {
+				rv = ENXIO;
+				if (mutex_held)
+					mutex_exit(&cbp->cb_mutex);
+				break;
+			}
+			cbp->rstate = (ap_rstate_t)rstate;
+		}
+
+		ap_state.ap_rstate = cbp->rstate;
+		ap_state.ap_ostate = cbp->ostate;
+		ap_state.ap_condition = cbp->condition;
+		ap_state.ap_last_change = 0;
+		ap_state.ap_error_code = 0;
+		if (mutex_held)
+			ap_state.ap_in_transition = 0; /* AP is not busy */
+		else
+			ap_state.ap_in_transition = 1; /* AP is busy */
+
+		if (mutex_held)
+			mutex_exit(&cbp->cb_mutex);
+
+		/* copy the return-AP-state information to the user space */
+		if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS)
+			rv = ENXIO;
+
+		break;
+
+	    }
+
+	case DEVCTL_AP_CONTROL:
+		/*
+		 * HPC control functions:
+		 * 	HPC_CTRL_ENABLE_SLOT/HPC_CTRL_DISABLE_SLOT
+		 * 		Changes the state of the slot and preserves
+		 * 		the state across the reboot.
+		 * 	HPC_CTRL_ENABLE_AUTOCFG/HPC_CTRL_DISABLE_AUTOCFG
+		 * 		Enables or disables the auto configuration
+		 * 		of hot plugged occupant if the hardware
+		 * 		supports notification of the hot plug
+		 * 		events.
+		 * 	HPC_CTRL_GET_LED_STATE/HPC_CTRL_SET_LED_STATE
+		 * 		Controls the state of an LED.
+		 * 	HPC_CTRL_GET_SLOT_INFO
+		 * 		Get slot information data structure
+		 * 		(hpc_slot_info_t).
+		 * 	HPC_CTRL_GET_BOARD_TYPE
+		 * 		Get board type information (hpc_board_type_t).
+		 * 	HPC_CTRL_GET_CARD_INFO
+		 * 		Get card information (hpc_card_info_t).
+		 *
+		 * These control functions are used by the cfgadm plug-in
+		 * to implement "-x" and "-v" options.
+		 */
+
+		/* copy user ioctl data first */
+#ifdef _MULTI_DATAMODEL
+		if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
+			struct hpc_control32_data hpc_ctrldata32;
+
+			if (copyin((void *)arg, (void *)&hpc_ctrldata32,
+			    sizeof (struct hpc_control32_data)) != 0) {
+				rv = EFAULT;
+				break;
+			}
+			hpc_ctrldata.cmd = hpc_ctrldata32.cmd;
+			hpc_ctrldata.data =
+			    (void *)(intptr_t)hpc_ctrldata32.data;
+		}
+#else
+		if (copyin((void *)arg, (void *)&hpc_ctrldata,
+		    sizeof (struct hpc_control_data)) != 0) {
+			rv = EFAULT;
+			break;
+		}
+#endif
+
+#ifdef CARDBUS_DEBUG
+{
+		char *hpc_name;
+		switch (hpc_ctrldata.cmd) {
+		case HPC_CTRL_GET_LED_STATE:
+			hpc_name = "HPC_CTRL_GET_LED_STATE";
+			break;
+		case HPC_CTRL_SET_LED_STATE:
+			hpc_name = "HPC_CTRL_SET_LED_STATE";
+			break;
+		case HPC_CTRL_ENABLE_SLOT:
+			hpc_name = "HPC_CTRL_ENABLE_SLOT";
+			break;
+		case HPC_CTRL_DISABLE_SLOT:
+			hpc_name = "HPC_CTRL_DISABLE_SLOT";
+			break;
+		case HPC_CTRL_ENABLE_AUTOCFG:
+			hpc_name = "HPC_CTRL_ENABLE_AUTOCFG";
+			break;
+		case HPC_CTRL_DISABLE_AUTOCFG:
+			hpc_name = "HPC_CTRL_DISABLE_AUTOCFG";
+			break;
+		case HPC_CTRL_GET_BOARD_TYPE:
+			hpc_name = "HPC_CTRL_GET_BOARD_TYPE";
+			break;
+		case HPC_CTRL_GET_SLOT_INFO:
+			hpc_name = "HPC_CTRL_GET_SLOT_INFO";
+			break;
+		case HPC_CTRL_GET_CARD_INFO:
+			hpc_name = "HPC_CTRL_GET_CARD_INFO";
+			break;
+		default: hpc_name = "Unknown"; break;
+		}
+		cardbus_err(cbp->cb_dip, 7,
+		    "cardbus_ioctl: HP Control cmd 0x%x - \"%s\"",
+		    hpc_ctrldata.cmd, hpc_name);
+}
+#endif
+		/*
+		 * check for valid request:
+		 * 	1. It is a hotplug slot.
+		 */
+		if (cbp->slot_handle == NULL) {
+			rv = ENXIO;
+			break;
+		}
+
+		mutex_enter(&cbp->cb_mutex);
+		switch (hpc_ctrldata.cmd) {
+		case HPC_CTRL_GET_LED_STATE:
+			/* copy the led info from the user space */
+			if (copyin(hpc_ctrldata.data, (void *)&led_info,
+			    sizeof (hpc_led_info_t)) != 0) {
+				rv = ENXIO;
+				break;
+			}
+
+			/* get the state of LED information */
+			if (hpc_nexus_control(cbp->slot_handle,
+			    HPC_CTRL_GET_LED_STATE,
+			    (caddr_t)&led_info) != 0) {
+				rv = ENXIO;
+				break;
+			}
+
+			/* copy the led info to the user space */
+			if (copyout((void *)&led_info, hpc_ctrldata.data,
+			    sizeof (hpc_led_info_t)) != 0) {
+				rv = ENXIO;
+				break;
+			}
+			break;
+
+		case HPC_CTRL_SET_LED_STATE:
+			/* copy the led info from the user space */
+			if (copyin(hpc_ctrldata.data, (void *)&led_info,
+			    sizeof (hpc_led_info_t)) != 0) {
+				rv = ENXIO;
+				break;
+			}
+
+			/* set the state of an LED */
+			if (hpc_nexus_control(cbp->slot_handle,
+			    HPC_CTRL_SET_LED_STATE,
+			    (caddr_t)&led_info) != 0) {
+				rv = ENXIO;
+				break;
+			}
+
+			break;
+
+		case HPC_CTRL_ENABLE_SLOT:
+			/*
+			 * Enable the slot for hotplug operations.
+			 */
+			cbp->disabled = B_FALSE;
+
+			/* tell the HPC driver also */
+			(void) hpc_nexus_control(cbp->slot_handle,
+				HPC_CTRL_ENABLE_SLOT, NULL);
+
+			break;
+
+		case HPC_CTRL_DISABLE_SLOT:
+			/*
+			 * Disable the slot for hotplug operations.
+			 */
+			cbp->disabled = B_TRUE;
+
+			/* tell the HPC driver also */
+			(void) hpc_nexus_control(cbp->slot_handle,
+				HPC_CTRL_DISABLE_SLOT, NULL);
+
+			break;
+
+		case HPC_CTRL_ENABLE_AUTOCFG:
+			/*
+			 * Enable auto configuration on this slot.
+			 */
+			cbp->auto_config = B_TRUE;
+
+			/* tell the HPC driver also */
+			(void) hpc_nexus_control(cbp->slot_handle,
+				HPC_CTRL_ENABLE_AUTOCFG, NULL);
+			break;
+
+		case HPC_CTRL_DISABLE_AUTOCFG:
+			/*
+			 * Disable auto configuration on this slot.
+			 */
+			cbp->auto_config = B_FALSE;
+
+			/* tell the HPC driver also */
+			(void) hpc_nexus_control(cbp->slot_handle,
+				HPC_CTRL_DISABLE_AUTOCFG, NULL);
+
+			break;
+
+		case HPC_CTRL_GET_BOARD_TYPE:
+		    {
+			hpc_board_type_t board_type;
+
+			/*
+			 * Get board type data structure, hpc_board_type_t.
+			 */
+			if (hpc_nexus_control(cbp->slot_handle,
+			    HPC_CTRL_GET_BOARD_TYPE,
+			    (caddr_t)&board_type) != 0) {
+				rv = ENXIO;
+				break;
+			}
+
+			/* copy the board type info to the user space */
+			if (copyout((void *)&board_type, hpc_ctrldata.data,
+			    sizeof (hpc_board_type_t)) != 0) {
+				rv = ENXIO;
+				break;
+			}
+
+			break;
+		    }
+
+		case HPC_CTRL_GET_SLOT_INFO:
+		    {
+			hpc_slot_info_t slot_info;
+
+			/*
+			 * Get slot information structure, hpc_slot_info_t.
+			 */
+			slot_info.version = HPC_SLOT_INFO_VERSION;
+			slot_info.slot_type = 0;
+			slot_info.pci_slot_capabilities = 0;
+			slot_info.pci_dev_num =
+				(uint16_t)AP_MINOR_NUM_TO_CB_INSTANCE(ap_minor);
+			(void) strcpy(slot_info.pci_slot_name, cbp->name);
+
+			/* copy the slot info structure to the user space */
+			if (copyout((void *)&slot_info, hpc_ctrldata.data,
+			    sizeof (hpc_slot_info_t)) != 0) {
+				rv = ENXIO;
+				break;
+			}
+
+			break;
+		    }
+
+		case HPC_CTRL_GET_CARD_INFO:
+		    {
+			hpc_card_info_t card_info;
+			ddi_acc_handle_t handle;
+
+			/*
+			 * Get card information structure, hpc_card_info_t.
+			 */
+
+			/* verify that the card is configured */
+			if (cbp->ostate != AP_OSTATE_CONFIGURED) {
+				/* either the card is not present or */
+				/* it is not configured. */
+				rv = ENXIO;
+				break;
+			}
+
+			/* get the information from the PCI config header */
+			/* for the function 0. */
+			for (child_dip = ddi_get_child(cbp->cb_dip); child_dip;
+			    child_dip = ddi_get_next_sibling(child_dip))
+				if (strcmp("pcs", ddi_get_name(child_dip)))
+					break;
+
+			if (!child_dip) {
+				rv = ENXIO;
+				break;
+			}
+
+			if (pci_config_setup(child_dip, &handle)
+			    != DDI_SUCCESS) {
+				rv = EIO;
+				break;
+			}
+			card_info.prog_class = pci_config_get8(handle,
+							PCI_CONF_PROGCLASS);
+			card_info.base_class = pci_config_get8(handle,
+							PCI_CONF_BASCLASS);
+			card_info.sub_class = pci_config_get8(handle,
+							PCI_CONF_SUBCLASS);
+			card_info.header_type = pci_config_get8(handle,
+							PCI_CONF_HEADER);
+			pci_config_teardown(&handle);
+
+			/* copy the card info structure to the user space */
+			if (copyout((void *)&card_info, hpc_ctrldata.data,
+			    sizeof (hpc_card_info_t)) != 0) {
+				rv = ENXIO;
+				break;
+			}
+
+			break;
+		    }
+
+		default:
+			rv = EINVAL;
+			break;
+		}
+
+		mutex_exit(&cbp->cb_mutex);
+		break;
+
+	default:
+		rv = ENOTTY;
+	}
+
+	if (cmd != DEVCTL_AP_CONTROL)
+		ndi_dc_freehdl(dcp);
+
+	cardbus_err(cbp->cb_dip, 7,
+	    "cardbus_ioctl: rv = 0x%x", rv);
+
+	return (rv);
+}
+
+struct cardbus_pci_desc {
+	char	*name;
+	ushort_t	offset;
+	int	(*cfg_get_func)();
+	char	*fmt;
+};
+
+static struct cardbus_pci_desc generic_pci_cfg[] = {
+	    { "VendorId    =", 0, (int(*)())pci_config_get16, "%s 0x%04x" },
+	    { "DeviceId    =", 2, (int(*)())pci_config_get16, "%s 0x%04x" },
+	    { "Command     =", 4, (int(*)())pci_config_get16, "%s 0x%04x" },
+	    { "Status      =", 6, (int(*)())pci_config_get16, "%s 0x%04x" },
+	    { "Latency     =", 0xd, (int(*)())pci_config_get8, "%s 0x%02x" },
+	    { "BASE0       =", 0x10, (int(*)())pci_config_get32, "%s 0x%08x" },
+	    { "BASE1       =", 0x14, (int(*)())pci_config_get32, "%s 0x%08x" },
+	    { "BASE2       =", 0x18, (int(*)())pci_config_get32, "%s 0x%08x" },
+	    { "BASE3       =", 0x1c, (int(*)())pci_config_get32, "%s 0x%08x" },
+	    { "BASE4       =", 0x20, (int(*)())pci_config_get32, "%s 0x%08x" },
+	    { "CIS Pointer =", 0x28, (int(*)())pci_config_get32, "%s 0x%08x" },
+	    { "ILINE       =", 0x3c, (int(*)())pci_config_get8, "%s 0x%02x" },
+	    { "IPIN        =", 0x3d, (int(*)())pci_config_get8, "%s 0x%02x" },
+	    { NULL, 0, NULL, NULL }
+};
+
+static struct cardbus_pci_desc cardbus_pci_cfg[] = {
+	    { "VendorId    =", 0, (int(*)())pci_config_get16, "%s 0x%04x" },
+	    { "DeviceId    =", 2, (int(*)())pci_config_get16, "%s 0x%04x" },
+	    { "Command     =", 4, (int(*)())pci_config_get16, "%s 0x%04x" },
+	    { "Status      =", 6, (int(*)())pci_config_get16, "%s 0x%04x" },
+	    { "CacheLineSz =", 0xc, (int(*)())pci_config_get8, "%s 0x%02x" },
+	    { "Latency     =", 0xd, (int(*)())pci_config_get8, "%s 0x%02x" },
+	    { "MemBase Addr=", 0x10, (int(*)())pci_config_get32, "%s 0x%08x" },
+	    { "Pri Bus     =", 0x18, (int(*)())pci_config_get8, "%s 0x%02x" },
+	    { "Sec Bus     =", 0x19, (int(*)())pci_config_get8, "%s 0x%02x" },
+	    { "Sub Bus     =", 0x1a, (int(*)())pci_config_get8, "%s 0x%02x" },
+	    { "CBus Latency=", 0x1b, (int(*)())pci_config_get8, "%s 0x%02x" },
+	    { "Mem0 Base   =", 0x1c, (int(*)())pci_config_get32, "%s 0x%08x" },
+	    { "Mem0 Limit  =", 0x20, (int(*)())pci_config_get32, "%s 0x%08x" },
+	    { "Mem1 Base   =", 0x24, (int(*)())pci_config_get32, "%s 0x%08x" },
+	    { "Mem1 Limit  =", 0x28, (int(*)())pci_config_get32, "%s 0x%08x" },
+	    { "I/O0 Base   =", 0x2c, (int(*)())pci_config_get32, "%s 0x%08x" },
+	    { "I/O0 Limit  =", 0x30, (int(*)())pci_config_get32, "%s 0x%08x" },
+	    { "I/O1 Base   =", 0x34, (int(*)())pci_config_get32, "%s 0x%08x" },
+	    { "I/O1 Limit  =", 0x38, (int(*)())pci_config_get32, "%s 0x%08x" },
+	    { "ILINE       =", 0x3c, (int(*)())pci_config_get8, "%s 0x%02x" },
+	    { "IPIN        =", 0x3d, (int(*)())pci_config_get8, "%s 0x%02x" },
+	    { "Bridge Ctrl =", 0x3e, (int(*)())pci_config_get16, "%s 0x%04x" },
+	    { "Legacy Addr =", 0x44, (int(*)())pci_config_get32, "%s 0x%08x" },
+	    { NULL, 0, NULL, NULL }
+};
+
+static void
+cardbus_dump(struct cardbus_pci_desc *spcfg, ddi_acc_handle_t handle)
+{
+	int	i;
+	for (i = 0; spcfg[i].name; i++) {
+
+		cmn_err(CE_NOTE, spcfg[i].fmt, spcfg[i].name,
+			spcfg[i].cfg_get_func(handle, spcfg[i].offset));
+	}
+
+}
+
+void
+cardbus_dump_pci_node(dev_info_t *dip)
+{
+	dev_info_t *next;
+	struct cardbus_pci_desc *spcfg;
+	ddi_acc_handle_t config_handle;
+	uint32_t VendorId;
+
+	cmn_err(CE_NOTE, "\nPCI leaf node of dip 0x%p:\n", (void *)dip);
+	for (next = ddi_get_child(dip); next;
+		next = ddi_get_next_sibling(next)) {
+
+		VendorId = ddi_getprop(DDI_DEV_T_ANY, next,
+				DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
+				"vendor-id", -1);
+		if (VendorId == -1) {
+			/* not a pci device */
+			continue;
+		}
+
+		if (pci_config_setup(next, &config_handle) != DDI_SUCCESS) {
+			cmn_err(CE_WARN, "!pcic child: non pci device\n");
+			continue;
+		}
+
+		spcfg = generic_pci_cfg;
+		cardbus_dump(spcfg, config_handle);
+		pci_config_teardown(&config_handle);
+
+	}
+
+}
+
+void
+cardbus_dump_pci_config(dev_info_t *dip)
+{
+	struct cardbus_pci_desc *spcfg;
+	ddi_acc_handle_t config_handle;
+
+	if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) {
+	    cmn_err(CE_WARN, "!pci_config_setup() failed on 0x%p", (void *)dip);
+	    return;
+	}
+
+	spcfg = cardbus_pci_cfg;
+	cardbus_dump(spcfg, config_handle);
+
+	pci_config_teardown(&config_handle);
+}
+
+void
+cardbus_dump_socket(dev_info_t *dip)
+{
+	ddi_acc_handle_t 	iohandle;
+	caddr_t		ioaddr;
+	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;
+	if (ddi_regs_map_setup(dip, 1,
+				(caddr_t *)&ioaddr,
+				0,
+				4096,
+				&attr, &iohandle) != DDI_SUCCESS) {
+	    cmn_err(CE_WARN, "Failed to map address for 0x%p", (void *)dip);
+	    return;
+	}
+
+	cmn_err(CE_NOTE, "////////////////////////////////////////");
+	cmn_err(CE_NOTE, "SOCKET_EVENT  = [0x%x]",
+		ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT)));
+	cmn_err(CE_NOTE, "SOCKET_MASK   = [0x%x]",
+		ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_MASK)));
+	cmn_err(CE_NOTE, "SOCKET_STATE  = [0x%x]",
+		ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_PRESENT_STATE)));
+	cmn_err(CE_NOTE, "////////////////////////////////////////");
+
+	ddi_regs_map_free(&iohandle);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/cardbus/cardbus_hp.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+/*
+ * Copyright (c)  * Copyright (c) 2001 Tadpole Technology plc
+ * All rights reserved.
+ */
+
+#ifndef	_SYS_CARDBUS_HP_H
+#define	_SYS_CARDBUS_HP_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+struct  cardbus_config_ctrl {
+	int	op;	/* operation - PCICFG_OP_ONLINE/PCICFG_OP_OFFLINE */
+	int	busno;
+	int	rv;	/* return error code */
+	uint_t	flags;
+	dev_info_t	*dip;	/* first error occurred here */
+};
+
+extern void *cardbus_state;
+
+extern int cardbus_init_hotplug(cbus_t *cbp);
+extern int cardbus_unconfigure_node(dev_info_t *dip, int prim_bus,
+		boolean_t top_bridge);
+extern int cbus_configure(dev_info_t *dip, void *hdl);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif	/* _SYS_CARDBUS_HP_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/cardbus/cardbus_parse.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+/*
+ * Copyright (c)  * Copyright (c) 2001 Tadpole Technology plc
+ * All rights reserved.
+ */
+
+#ifndef	_SYS_CARDBUS_IMPL_H
+#define	_SYS_CARDBUS_IMPL_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Device property initialization structures and defines
+ */
+struct cb_deviceset_props {
+	struct cb_deviceset_props *next;
+	char	*binding_name;
+	uint16_t	venid;
+	uint16_t	devid;
+	char	*nodename;
+	ddi_prop_t	*prop_list;
+};
+
+typedef struct {
+	char	*token;	/* token to look for */
+	int	state;	/* state machine state */
+} cb_props_parse_tree_t;
+
+#define	PARSE_QUOTE		'\''
+#define	PARSE_COMMENT		'#'
+#define	PARSE_ESCAPE		'\\'
+#define	PARSE_UNDERSCORE	'_'
+#define	PARSE_DASH		'-'
+#define	PARSE_SEMICOLON		';'
+#define	PARSE_COMMA		','
+#define	PARSE_EQUALS		'='
+
+/*
+ * state defines for the valued variable state machine
+ */
+#define	PT_STATE_UNKNOWN	0
+#define	PT_STATE_TOKEN		1
+#define	PT_STATE_STRING_VAR	2
+#define	PT_STATE_HEX_VAR	3
+#define	PT_STATE_DEC_VAR	4
+#define	PT_STATE_ESCAPE		5
+#define	PT_STATE_CHECK		6
+
+#undef	isalpha
+#undef	isxdigit
+#undef	ixdigit
+#undef	toupper
+
+#define	isalpha(ch)	(((ch) >= 'a' && (ch) <= 'z') || \
+			((ch) >= 'A' && (ch) <= 'Z'))
+#define	isxdigit(ch)	(isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \
+			((ch) >= 'A' && (ch) <= 'F'))
+#define	isx(ch)		((ch) == 'x' || (ch) == 'X')
+#define	isdigit(ch)	((ch) >= '0' && (ch) <= '9')
+#define	toupper(C)	(((C) >= 'a' && (C) <= 'z')? (C) - 'a' + 'A': (C))
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif	/* _SYS_CARDBUS_IMPL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/pcic.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,7395 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * PCIC device/interrupt handler
+ *	The "pcic" driver handles the Intel 82365SL, Cirrus Logic
+ *	and Toshiba (and possibly other clones) PCMCIA adapter chip
+ *	sets.  It implements a subset of Socket Services as defined
+ *	in the Solaris PCMCIA design documents
+ */
+
+/*
+ * currently defined "properties"
+ *
+ * clock-frequency		bus clock frequency
+ * smi				system management interrupt override
+ * need-mult-irq		need status IRQ for each pair of sockets
+ * disable-audio		don't route audio signal to speaker
+ */
+
+
+#include <sys/types.h>
+#include <sys/inttypes.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/user.h>
+#include <sys/buf.h>
+#include <sys/file.h>
+#include <sys/uio.h>
+#include <sys/conf.h>
+#include <sys/stat.h>
+#include <sys/autoconf.h>
+#include <sys/vtoc.h>
+#include <sys/dkio.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/var.h>
+#include <sys/callb.h>
+#include <sys/open.h>
+#include <sys/ddidmareq.h>
+#include <sys/dma_engine.h>
+#include <sys/kstat.h>
+#include <sys/kmem.h>
+#include <sys/modctl.h>
+#include <sys/pci.h>
+#include <sys/pci_impl.h>
+
+#include <sys/pctypes.h>
+#include <sys/pcmcia.h>
+#include <sys/sservice.h>
+
+#include <sys/note.h>
+
+#include <sys/pcic_reg.h>
+#include <sys/pcic_var.h>
+
+#if defined(__sparc)
+#include <sys/pci/pci_nexus.h>
+#endif
+
+#include <sys/syshw.h>
+#include "cardbus/cardbus.h"
+
+#define	SOFTC_SIZE	(sizeof (anp_t))
+
+static int pcic_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static int pcic_attach(dev_info_t *, ddi_attach_cmd_t);
+static int pcic_detach(dev_info_t *, ddi_detach_cmd_t);
+static uint_t pcic_intr(caddr_t, caddr_t);
+static int pcic_do_io_intr(pcicdev_t *, uint32_t);
+static int pcic_probe(dev_info_t *);
+
+static int pcic_open(dev_t *, int, int, cred_t *);
+static int pcic_close(dev_t, int, int, cred_t *);
+static int pcic_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+
+typedef struct pcm_regs pcm_regs_t;
+
+static void pcic_init_assigned(dev_info_t *);
+static int pcic_apply_avail_ranges(dev_info_t *, pcm_regs_t *,
+	pci_regspec_t *, int);
+int pci_resource_setup_avail(dev_info_t *, pci_regspec_t *, int);
+
+/*
+ * On x86 platforms the ddi_iobp_alloc(9F) and ddi_mem_alloc(9F) calls
+ * are xlated into DMA ctlops. To make this nexus work on x86, we
+ * need to have the default ddi_dma_mctl ctlops in the bus_ops
+ * structure, just to pass the request to the parent. The correct
+ * ctlops should be ddi_no_dma_mctl because so far we don't do DMA.
+ */
+static
+struct bus_ops pcmciabus_ops = {
+	BUSO_REV,
+	pcmcia_bus_map,
+	NULL,
+	NULL,
+	NULL,
+	i_ddi_map_fault,
+	ddi_no_dma_map,
+	ddi_no_dma_allochdl,
+	ddi_no_dma_freehdl,
+	ddi_no_dma_bindhdl,
+	ddi_no_dma_unbindhdl,
+	ddi_no_dma_flush,
+	ddi_no_dma_win,
+	ddi_dma_mctl,
+	pcmcia_ctlops,
+	pcmcia_prop_op,
+	NULL,				/* (*bus_get_eventcookie)();	*/
+	NULL,				/* (*bus_add_eventcall)();	*/
+	NULL,				/* (*bus_remove_eventcall)();	*/
+	NULL,				/* (*bus_post_event)();		*/
+	NULL,				/* (*bus_intr_ctl)();		*/
+	NULL,				/* (*bus_config)(); 		*/
+	NULL,				/* (*bus_unconfig)(); 		*/
+	NULL,				/* (*bus_fm_init)(); 		*/
+	NULL,				/* (*bus_fm_fini)(); 		*/
+	NULL,				/* (*bus_enter)()		*/
+	NULL,				/* (*bus_exit)()		*/
+	NULL,				/* (*bus_power)()		*/
+	pcmcia_intr_ops			/* (*bus_intr_op)(); 		*/
+};
+
+static struct cb_ops pcic_cbops = {
+	pcic_open,
+	pcic_close,
+	nodev,
+	nodev,
+	nodev,
+	nodev,
+	nodev,
+	pcic_ioctl,
+	nodev,
+	nodev,
+	nodev,
+	nochpoll,
+	ddi_prop_op,
+	NULL,
+#ifdef CARDBUS
+	D_NEW | D_MP | D_HOTPLUG
+#else
+	D_NEW | D_MP
+#endif
+};
+
+static struct dev_ops pcic_devops = {
+	DEVO_REV,
+	0,
+	pcic_getinfo,
+	nulldev,
+	pcic_probe,
+	pcic_attach,
+	pcic_detach,
+	nulldev,
+	&pcic_cbops,
+	&pcmciabus_ops,
+	NULL
+};
+
+void *pcic_soft_state_p = NULL;
+static int pcic_maxinst = -1;
+static timeout_id_t pcic_delayed_resume_toid;
+
+int pcic_do_insertion = 1;
+int pcic_do_removal = 1;
+
+struct irqmap {
+	int irq;
+	int count;
+} pcic_irq_map[16];
+
+
+int pcic_debug = 0x0;
+static  void    pcic_err(dev_info_t *dip, int level, const char *fmt, ...);
+extern void cardbus_dump_pci_config(dev_info_t *dip);
+extern void cardbus_dump_socket(dev_info_t *dip);
+extern int cardbus_validate_iline(dev_info_t *dip, ddi_acc_handle_t handle);
+static void pcic_dump_debqueue(char *msg);
+
+#if defined(PCIC_DEBUG)
+static void xxdmp_all_regs(pcicdev_t *, int, uint32_t);
+
+#define	pcic_mutex_enter(a)	\
+	{ \
+		pcic_err(NULL, 10, "Set lock at %d\n", __LINE__); \
+		mutex_enter(a); \
+	};
+
+#define	pcic_mutex_exit(a)	\
+	{ \
+		pcic_err(NULL, 10, "Clear lock at %d\n", __LINE__); \
+		mutex_exit(a); \
+	};
+
+#else
+#define	pcic_mutex_enter(a)	mutex_enter(a)
+#define	pcic_mutex_exit(a)	mutex_exit(a)
+#endif
+
+#define	PCIC_VCC_3VLEVEL	1
+#define	PCIC_VCC_5VLEVEL	2
+#define	PCIC_VCC_12LEVEL	3
+
+/* bit patterns to select voltage levels */
+int pcic_vpp_levels[13] = {
+	0, 0, 0,
+	1,	/* 3.3V */
+	0,
+	1,	/* 5V */
+	0, 0, 0, 0, 0, 0,
+	2	/* 12V */
+};
+
+uint8_t pcic_cbv_levels[13] = {
+	0, 0, 0,
+	3,			/* 3.3V */
+	0,
+	2,			/* 5V */
+	0, 0, 0, 0, 0, 0,
+	1			/* 12V */
+};
+
+struct power_entry pcic_power[4] = {
+	{
+		0, VCC|VPP1|VPP2
+	},
+	{
+		33,		/* 3.3Volt */
+		VCC|VPP1|VPP2
+	},
+	{
+		5*10,		/* 5Volt */
+		VCC|VPP1|VPP2	/* currently only know about this */
+	},
+	{
+		12*10,		/* 12Volt */
+		VPP1|VPP2
+	}
+};
+
+/*
+ * Base used to allocate ranges of PCI memory on x86 systems
+ * Each instance gets a chunk above the base that is used to map
+ * in the memory and I/O windows for that device.
+ * Pages below the base are also allocated for the EXCA registers,
+ * one per instance.
+ */
+#define	PCIC_PCI_MEMCHUNK	0x1000000
+
+static int pcic_wait_insert_time = 5000000;	/* In micro-seconds */
+static int pcic_debounce_time = 200000; /* In micro-seconds */
+
+struct debounce {
+	pcic_socket_t *pcs;
+	clock_t expire;
+	struct debounce *next;
+};
+
+static syshw_t pcic_syshw = {
+	0, "PC Card Socket 0", SH_CONNECTION,
+	SYSHW_CAN_SIGNAL_CHANGE|SYSHW_STATE_VALID|SYSHW_VAL0_VALID,
+	B_FALSE, {2, 0, 0, 0}
+};
+
+static struct debounce *pcic_deb_queue = NULL;
+static kmutex_t pcic_deb_mtx;
+static kcondvar_t pcic_deb_cv;
+static kthread_t *pcic_deb_threadid;
+
+static inthandler_t *pcic_handlers;
+
+static void pcic_setup_adapter(pcicdev_t *);
+static int pcic_change(pcicdev_t *, int);
+static int pcic_ll_reset(pcicdev_t *, int);
+static void pcic_mswait(pcicdev_t *, int, int);
+static boolean_t pcic_check_ready(pcicdev_t *, int);
+static void pcic_set_cdtimers(pcicdev_t *, int, uint32_t, int);
+static void pcic_ready_wait(pcicdev_t *, int);
+extern int pcmcia_get_intr(dev_info_t *, int);
+extern int pcmcia_return_intr(dev_info_t *, int);
+
+static int pcic_callback(dev_info_t *, int (*)(), int);
+static int pcic_inquire_adapter(dev_info_t *, inquire_adapter_t *);
+static int pcic_get_adapter(dev_info_t *, get_adapter_t *);
+static int pcic_get_page(dev_info_t *, get_page_t *);
+static int pcic_get_socket(dev_info_t *, get_socket_t *);
+static int pcic_get_status(dev_info_t *, get_ss_status_t *);
+static int pcic_get_window(dev_info_t *, get_window_t *);
+static int pcic_inquire_socket(dev_info_t *, inquire_socket_t *);
+static int pcic_inquire_window(dev_info_t *, inquire_window_t *);
+static int pcic_reset_socket(dev_info_t *, int, int);
+static int pcic_set_page(dev_info_t *, set_page_t *);
+static int pcic_set_window(dev_info_t *, set_window_t *);
+static int pcic_set_socket(dev_info_t *, set_socket_t *);
+static int pcic_set_interrupt(dev_info_t *, set_irq_handler_t *);
+static int pcic_clear_interrupt(dev_info_t *, clear_irq_handler_t *);
+static void pcic_pm_detection(void *);
+static void pcic_iomem_pci_ctl(ddi_acc_handle_t, uchar_t *, unsigned);
+static int clext_reg_read(pcicdev_t *, int, uchar_t);
+static void clext_reg_write(pcicdev_t *, int, uchar_t, uchar_t);
+static int pcic_calc_speed(pcicdev_t *, uint32_t);
+static int pcic_card_state(pcicdev_t *, pcic_socket_t *);
+static int pcic_find_pci_type(pcicdev_t *);
+static void pcic_82092_smiirq_ctl(pcicdev_t *, int, int, int);
+static void pcic_handle_cd_change(pcicdev_t *, pcic_socket_t *, uint8_t);
+static uint_t pcic_cd_softint(caddr_t, caddr_t);
+static uint8_t pcic_getb(pcicdev_t *, int, int);
+static void pcic_putb(pcicdev_t *, int, int, int8_t);
+static int pcic_set_vcc_level(pcicdev_t *, set_socket_t *);
+static uint_t pcic_softintr(caddr_t, caddr_t);
+
+static void pcic_debounce(pcic_socket_t *);
+static void pcic_delayed_resume(void *);
+static void *pcic_add_debqueue(pcic_socket_t *, int);
+static void pcic_rm_debqueue(void *);
+static void pcic_deb_thread();
+
+static boolean_t pcic_load_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp);
+static void pcic_unload_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp);
+static uint32_t pcic_getcb(pcicdev_t *pcic, int reg);
+static void pcic_putcb(pcicdev_t *pcic, int reg, uint32_t value);
+static void pcic_cb_enable_intr(dev_info_t *);
+static void pcic_cb_disable_intr(dev_info_t *);
+static void pcic_enable_io_intr(pcicdev_t *pcic, int socket, int irq);
+static void pcic_disable_io_intr(pcicdev_t *pcic, int socket);
+
+static cb_nexus_cb_t pcic_cbnexus_ops = {
+	pcic_cb_enable_intr,
+	pcic_cb_disable_intr
+};
+
+static int pcic_exca_powerctl(pcicdev_t *pcic, int socket, int powerlevel);
+static int pcic_cbus_powerctl(pcicdev_t *pcic, int socket);
+
+static void pcic_syshw_cardstate(syshw_t *, void *);
+
+#if defined(__sparc)
+static int pcic_fault(enum pci_fault_ops op, void *arg);
+#endif
+
+/*
+ * Default to support for Voyager IIi if sparc is defined.
+ * Appart from the PCI base addresses this only effect the TI1250.
+ */
+#if defined(sparc)
+#define	VOYAGER
+#endif
+
+
+/*
+ * pcmcia_attach() uses 0 and 128 upwards for the initpcmcia and devctl
+ * interfaces so we use 254.
+ */
+#define	SYSHW_MINOR	254
+
+/*
+ * Forward declarations for syshw interface (See end of file).
+ */
+static void syshw_attach(pcicdev_t *);
+static void syshw_detach(pcicdev_t *);
+static void syshw_resume(pcicdev_t *);
+
+#ifdef VOYAGER
+static uint_t syshw_intr(caddr_t);
+static uint_t syshw_intr_hi(pcicdev_t *);
+#endif
+
+static int syshw_open(dev_t *, int, int, cred_t *);
+static int syshw_close(dev_t, int, int, cred_t *);
+static int syshw_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+static uint32_t syshw_add2map(syshw_t *, void (*)(syshw_t *, void *), void *);
+static void syshw_send_signal(int);
+
+/*
+ * pcmcia interface operations structure
+ * this is the private interface that is exported to the nexus
+ */
+pcmcia_if_t pcic_if_ops = {
+	PCIF_MAGIC,
+	PCIF_VERSION,
+	pcic_callback,
+	pcic_get_adapter,
+	pcic_get_page,
+	pcic_get_socket,
+	pcic_get_status,
+	pcic_get_window,
+	pcic_inquire_adapter,
+	pcic_inquire_socket,
+	pcic_inquire_window,
+	pcic_reset_socket,
+	pcic_set_page,
+	pcic_set_window,
+	pcic_set_socket,
+	pcic_set_interrupt,
+	pcic_clear_interrupt,
+	NULL,
+};
+
+/*
+ * chip type identification routines
+ * this list of functions is searched until one of them succeeds
+ * or all fail.  i82365SL is assumed if failed.
+ */
+static int pcic_ci_cirrus(pcicdev_t *);
+static int pcic_ci_vadem(pcicdev_t *);
+static int pcic_ci_ricoh(pcicdev_t *);
+
+int (*pcic_ci_funcs[])(pcicdev_t *) = {
+	pcic_ci_cirrus,
+	pcic_ci_vadem,
+	pcic_ci_ricoh,
+	NULL
+};
+
+static struct modldrv modldrv = {
+	&mod_driverops,		/* Type of module. This one is a driver */
+	"PCIC PCMCIA adapter driver %I%",	/* Name of the module. */
+	&pcic_devops,		/* driver ops */
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1, (void *)&modldrv, NULL
+};
+
+int
+_init()
+{
+	int stat;
+
+	/* Allocate soft state */
+	if ((stat = ddi_soft_state_init(&pcic_soft_state_p,
+	    SOFTC_SIZE, 2)) != DDI_SUCCESS)
+		return (stat);
+
+	if ((stat = mod_install(&modlinkage)) != 0)
+		ddi_soft_state_fini(&pcic_soft_state_p);
+
+	return (stat);
+}
+
+int
+_fini()
+{
+	int stat = 0;
+
+	if ((stat = mod_remove(&modlinkage)) != 0)
+		return (stat);
+
+	if (pcic_deb_threadid) {
+		mutex_enter(&pcic_deb_mtx);
+		pcic_deb_threadid = 0;
+		while (!pcic_deb_threadid)
+			cv_wait(&pcic_deb_cv, &pcic_deb_mtx);
+		pcic_deb_threadid = 0;
+		mutex_exit(&pcic_deb_mtx);
+
+		mutex_destroy(&pcic_deb_mtx);
+		cv_destroy(&pcic_deb_cv);
+	}
+
+	ddi_soft_state_fini(&pcic_soft_state_p);
+
+	return (stat);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+/*
+ * pcic_getinfo()
+ *	provide instance/device information about driver
+ */
+/*ARGSUSED*/
+static int
+pcic_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
+{
+	anp_t *anp;
+	int error = DDI_SUCCESS;
+	minor_t minor;
+
+	switch (cmd) {
+	    case DDI_INFO_DEVT2DEVINFO:
+		minor = getminor((dev_t)arg);
+		if (minor == SYSHW_MINOR)
+			minor = 0;
+		else
+			minor &= 0x7f;
+		if (!(anp = ddi_get_soft_state(pcic_soft_state_p, minor)))
+			*result = NULL;
+		else
+			*result = anp->an_dip;
+		break;
+	    case DDI_INFO_DEVT2INSTANCE:
+		minor = getminor((dev_t)arg);
+		if (minor == SYSHW_MINOR)
+			minor = 0;
+		else
+			minor &= 0x7f;
+		*result = (void *)((long)minor);
+		break;
+	    default:
+		error = DDI_FAILURE;
+		break;
+	}
+	return (error);
+}
+
+static int
+pcic_probe(dev_info_t *dip)
+{
+	int value;
+	ddi_device_acc_attr_t attr;
+	ddi_acc_handle_t handle;
+	uchar_t *index, *data;
+
+	if (ddi_dev_is_sid(dip) == DDI_SUCCESS)
+	    return (DDI_PROBE_DONTCARE);
+
+	/*
+	 * find a PCIC device (any vendor)
+	 * while there can be up to 4 such devices in
+	 * a system, we currently only look for 1
+	 * per probe.  There will be up to 2 chips per
+	 * instance since they share I/O space
+	 */
+	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
+	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+
+	if (ddi_regs_map_setup(dip, PCIC_ISA_CONTROL_REG_NUM,
+				(caddr_t *)&index,
+				PCIC_ISA_CONTROL_REG_OFFSET,
+				PCIC_ISA_CONTROL_REG_LENGTH,
+				&attr, &handle) != DDI_SUCCESS)
+	    return (DDI_PROBE_FAILURE);
+
+	data = index + 1;
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug)
+		cmn_err(CE_CONT, "pcic_probe: entered\n");
+	if (pcic_debug)
+		cmn_err(CE_CONT, "\tindex=%p\n", (void *)index);
+#endif
+	ddi_put8(handle, index, PCIC_CHIP_REVISION);
+	ddi_put8(handle, data, 0);
+	value = ddi_get8(handle, data);
+#if defined(PCIC_DEBUG)
+	if (pcic_debug)
+		cmn_err(CE_CONT, "\tchip revision register = %x\n", value);
+#endif
+	if ((value & PCIC_REV_MASK) >= PCIC_REV_LEVEL_LOW &&
+	    (value & 0x30) == 0) {
+		/*
+		 * we probably have a PCIC chip in the system
+		 * do a little more checking.  If we find one,
+		 * reset everything in case of softboot
+		 */
+		ddi_put8(handle, index, PCIC_MAPPING_ENABLE);
+		ddi_put8(handle, data, 0);
+		value = ddi_get8(handle, data);
+#if defined(PCIC_DEBUG)
+		if (pcic_debug)
+			cmn_err(CE_CONT, "\tzero test = %x\n", value);
+#endif
+		/* should read back as zero */
+		if (value == 0) {
+			/*
+			 * we do have one and it is off the bus
+			 */
+#if defined(PCIC_DEBUG)
+			if (pcic_debug)
+				cmn_err(CE_CONT, "pcic_probe: success\n");
+#endif
+			ddi_regs_map_free(&handle);
+			return (DDI_PROBE_SUCCESS);
+		}
+	}
+#if defined(PCIC_DEBUG)
+	if (pcic_debug)
+		cmn_err(CE_CONT, "pcic_probe: failed\n");
+#endif
+	ddi_regs_map_free(&handle);
+	return (DDI_PROBE_FAILURE);
+}
+
+/*
+ * These are just defaults they can also be changed via a property in the
+ * conf file.
+ */
+static int pci_config_reg_num = PCIC_PCI_CONFIG_REG_NUM;
+static int pci_control_reg_num = PCIC_PCI_CONTROL_REG_NUM;
+static int pcic_do_pcmcia_sr = 0;
+static int pcic_use_cbpwrctl = PCF_CBPWRCTL;
+
+/*
+ * enable insertion/removal interrupt for 32bit cards
+ */
+static int
+cardbus_enable_cd_intr(dev_info_t *dip)
+{
+	ddi_acc_handle_t	iohandle;
+	caddr_t	ioaddr;
+	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;
+	(void) ddi_regs_map_setup(dip, 1,
+				(caddr_t *)&ioaddr,
+				0,
+				4096,
+				&attr, &iohandle);
+
+	/* CSC Interrupt: Card detect interrupt on */
+	ddi_put32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_MASK),
+		ddi_get32(iohandle,
+		(uint32_t *)(ioaddr+CB_STATUS_MASK)) | CB_SE_CCDMASK);
+
+	ddi_put32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT),
+		ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT)));
+
+	ddi_regs_map_free(&iohandle);
+	return (1);
+}
+
+/*
+ * pcic_attach()
+ *	attach the PCIC (Intel 82365SL/CirrusLogic/Toshiba) driver
+ *	to the system.  This is a child of "sysbus" since that is where
+ *	the hardware lives, but it provides services to the "pcmcia"
+ *	nexus driver.  It gives a pointer back via its private data
+ *	structure which contains both the dip and socket services entry
+ *	points
+ */
+static int
+pcic_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	anp_t *pcic_nexus;
+	pcicdev_t *pcic;
+	int irqlevel, value;
+	int pci_cfrn, pci_ctrn;
+	int i, j, smi, actual;
+	char *typename;
+	char bus_type[16] = "(unknown)";
+	int len = sizeof (bus_type);
+	ddi_device_acc_attr_t attr;
+	anp_t *anp = ddi_get_driver_private(dip);
+	uint_t	pri;
+	syshw_t *shwp;
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug) {
+		cmn_err(CE_CONT, "pcic_attach: entered\n");
+	}
+#endif
+	switch (cmd) {
+	case DDI_ATTACH:
+		break;
+	case DDI_RESUME:
+		pcic = anp->an_private;
+		/*
+		 * for now, this is a simulated resume.
+		 * a real one may need different things.
+		 */
+		if (pcic != NULL && pcic->pc_flags & PCF_SUSPENDED) {
+			mutex_enter(&pcic->pc_lock);
+			/* should probe for new sockets showing up */
+			pcic_setup_adapter(pcic);
+			syshw_resume(pcic);
+			pcic->pc_flags &= ~PCF_SUSPENDED;
+			mutex_exit(&pcic->pc_lock);
+			(void) pcmcia_begin_resume(dip);
+			/*
+			 * this will do the CARD_INSERTION
+			 * due to needing time for threads to
+			 * run, it must be delayed for a short amount
+			 * of time.  pcmcia_wait_insert checks for all
+			 * children to be removed and then triggers insert.
+			 */
+			/*
+			 * The reason for having a single timeout here
+			 * rather than seperate timeout()s for each instance
+			 * is due to the limited number (2) of callout threads
+			 * available in Solaris 2.6. A single 1250A ends up
+			 * as two instances of the interface with one slot each.
+			 * The pcic_delayed_resume() function ends by calling
+			 * pcmcia_wait_insert() which at one point does a
+			 * delay(). delay() is implemented with a timeout()
+			 * call so you end up with both the callout()
+			 * threads waiting to be woken up by another callout().
+			 * This situation locks up the machine hence the
+			 * convolution here to only use one timeout.
+			 */
+			if (!pcic_delayed_resume_toid)
+				pcic_delayed_resume_toid =
+				    timeout(pcic_delayed_resume, (caddr_t)0,
+				    drv_usectohz(pcic_wait_insert_time));
+
+			/*
+			 * for complete implementation need END_RESUME (later)
+			 */
+			return (DDI_SUCCESS);
+
+		}
+		return (DDI_SUCCESS);
+	default:
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Allocate soft state associated with this instance.
+	 */
+	if (ddi_soft_state_zalloc(pcic_soft_state_p,
+				ddi_get_instance(dip)) != DDI_SUCCESS) {
+		cmn_err(CE_CONT, "pcic%d: Unable to alloc state\n",
+			ddi_get_instance(dip));
+		return (DDI_FAILURE);
+	}
+
+	pcic_nexus = ddi_get_soft_state(pcic_soft_state_p,
+	    ddi_get_instance(dip));
+
+	pcic = kmem_zalloc(sizeof (pcicdev_t), KM_SLEEP);
+
+	pcic->dip = dip;
+	pcic_nexus->an_dip = dip;
+	pcic_nexus->an_if = &pcic_if_ops;
+	pcic_nexus->an_private = pcic;
+	pcic->pc_numpower = sizeof (pcic_power)/sizeof (pcic_power[0]);
+	pcic->pc_power = pcic_power;
+
+	pci_ctrn = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
+	    "pci-control-reg-number", pci_control_reg_num);
+	pci_cfrn = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
+	    "pci-config-reg-number", pci_config_reg_num);
+
+	ddi_set_driver_private(dip, pcic_nexus);
+
+	/*
+	 * pcic->pc_irq is really the IPL level we want to run at
+	 * set the default values here and override from intr spec
+	 */
+	pcic->pc_irq = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
+					"interrupt-priorities", -1);
+
+	if (pcic->pc_irq == -1) {
+		int			actual;
+		uint_t			pri;
+		ddi_intr_handle_t	hdl;
+
+		/* see if intrspec tells us different */
+		if (ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED,
+		    0, 1, &actual, DDI_INTR_ALLOC_NORMAL) == DDI_SUCCESS) {
+			if (ddi_intr_get_pri(hdl, &pri) == DDI_SUCCESS)
+				pcic->pc_irq = pri;
+			else
+				pcic->pc_irq = LOCK_LEVEL + 1;
+			(void) ddi_intr_free(hdl);
+		}
+	}
+	pcic_nexus->an_ipl = pcic->pc_irq;
+
+	/*
+	 * Check our parent bus type. We do different things based on which
+	 * bus we're on.
+	 */
+	if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip),
+				PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP,
+				"device_type", (caddr_t)&bus_type[0], &len) !=
+							DDI_PROP_SUCCESS) {
+		if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip),
+				PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP,
+				"bus-type", (caddr_t)&bus_type[0], &len) !=
+							DDI_PROP_SUCCESS) {
+
+			cmn_err(CE_CONT,
+				"pcic%d: can't find parent bus type\n",
+				ddi_get_instance(dip));
+
+			kmem_free(pcic, sizeof (pcicdev_t));
+			return (DDI_FAILURE);
+		}
+	} /* ddi_prop_op("device_type") */
+
+	if (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0) {
+		pcic->pc_flags = PCF_PCIBUS;
+	} else {
+#if defined(__sparc)
+		cmn_err(CE_CONT, "pcic%d: unsupported parent bus type: [%s]\n",
+			ddi_get_instance(dip), bus_type);
+
+		kmem_free(pcic, sizeof (pcicdev_t));
+		return (DDI_FAILURE);
+#else
+		pcic->pc_flags = 0;
+#endif
+	}
+
+	if ((pcic->bus_speed = ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip),
+						DDI_PROP_CANSLEEP,
+						"clock-frequency", 0)) == 0) {
+		if (pcic->pc_flags & PCF_PCIBUS)
+			pcic->bus_speed = PCIC_PCI_DEF_SYSCLK;
+		else
+			pcic->bus_speed = PCIC_ISA_DEF_SYSCLK;
+	} else {
+		/*
+		 * OBP can declare the speed in Hz...
+		 */
+		if (pcic->bus_speed > 1000000)
+			pcic->bus_speed /= 1000000;
+	} /* ddi_prop_op("clock-frequency") */
+
+	pcic->pc_io_type = PCIC_IO_TYPE_82365SL; /* default mode */
+
+#ifdef	PCIC_DEBUG
+	if (pcic_debug) {
+		cmn_err(CE_CONT,
+			"pcic%d: parent bus type = [%s], speed = %d MHz\n",
+			ddi_get_instance(dip),
+			bus_type, pcic->bus_speed);
+	}
+#endif
+
+	/*
+	 * The reg properties on a PCI node are different than those
+	 *	on a non-PCI node. Handle that difference here.
+	 *	If it turns out to be a CardBus chip, we have even more
+	 *	differences.
+	 */
+	if (pcic->pc_flags & PCF_PCIBUS) {
+		int class_code;
+#if defined(__i386) || defined(__amd64)
+		pcic->pc_base = 0x1000000;
+		pcic->pc_bound = (uint32_t)~0;
+		pcic->pc_iobase = 0x1000;
+		pcic->pc_iobound = 0xefff;
+#elif defined(__sparc)
+		pcic->pc_base = 0x0;
+		pcic->pc_bound = (uint32_t)~0;
+		pcic->pc_iobase = 0x00000;
+		pcic->pc_iobound = 0xffff;
+#endif
+
+		/* usually need to get at config space so map first */
+		attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+		attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
+		attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+
+		if (ddi_regs_map_setup(dip, pci_cfrn,
+					(caddr_t *)&pcic->cfgaddr,
+					PCIC_PCI_CONFIG_REG_OFFSET,
+					PCIC_PCI_CONFIG_REG_LENGTH,
+					&attr,
+					&pcic->cfg_handle) !=
+		    DDI_SUCCESS) {
+			cmn_err(CE_CONT,
+				"pcic%d: unable to map config space"
+				"regs\n",
+				ddi_get_instance(dip));
+
+			kmem_free(pcic, sizeof (pcicdev_t));
+			return (DDI_FAILURE);
+		} /* ddi_regs_map_setup */
+
+		class_code = ddi_getprop(DDI_DEV_T_ANY, dip,
+					DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
+					"class-code", -1);
+#ifdef  PCIC_DEBUG
+		if (pcic_debug) {
+			cmn_err(CE_CONT, "pcic_attach class_code=%x\n",
+			    class_code);
+		}
+#endif
+
+		switch (class_code) {
+		case PCIC_PCI_CARDBUS:
+			pcic->pc_flags |= PCF_CARDBUS;
+			pcic->pc_io_type = PCIC_IO_TYPE_YENTA;
+			/*
+			 * Get access to the adapter registers on the
+			 * PCI bus.  A 4K memory page
+			 */
+#if defined(PCIC_DEBUG)
+			pcic_err(dip, 8, "Is Cardbus device\n");
+			if (pcic_debug) {
+				int nr;
+				long rs;
+				(void) ddi_dev_nregs(dip, &nr);
+				pcic_err(dip, 9, "\tdev, cfgaddr 0x%p,"
+				    "cfghndl 0x%p nregs %d",
+				    (void *)pcic->cfgaddr,
+				    (void *)pcic->cfg_handle, nr);
+
+				(void) ddi_dev_regsize(dip,
+				    PCIC_PCI_CONTROL_REG_NUM, &rs);
+
+				pcic_err(dip, 9, "\tsize of reg %d is 0x%x\n",
+				    PCIC_PCI_CONTROL_REG_NUM, (int)rs);
+			}
+#endif
+			attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+			attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
+			attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+
+			if (ddi_regs_map_setup(dip, pci_ctrn,
+						(caddr_t *)&pcic->ioaddr,
+						PCIC_PCI_CONTROL_REG_OFFSET,
+						PCIC_CB_CONTROL_REG_LENGTH,
+						&attr, &pcic->handle) !=
+			    DDI_SUCCESS) {
+				cmn_err(CE_CONT,
+					"pcic%d: unable to map PCI regs\n",
+					ddi_get_instance(dip));
+				ddi_regs_map_free(&pcic->cfg_handle);
+				kmem_free(pcic, sizeof (pcicdev_t));
+				return (DDI_FAILURE);
+			} /* ddi_regs_map_setup */
+
+			/*
+			 * Find out the chip type - If we're on a PCI bus,
+			 *	the adapter has that information in the PCI
+			 *	config space.
+			 * Note that we call pcic_find_pci_type here since
+			 *	it needs a valid mapped pcic->handle to
+			 *	access some of the adapter registers in
+			 *	some cases.
+			 */
+			if (pcic_find_pci_type(pcic) != DDI_SUCCESS) {
+				ddi_regs_map_free(&pcic->handle);
+				ddi_regs_map_free(&pcic->cfg_handle);
+				kmem_free(pcic, sizeof (pcicdev_t));
+				cmn_err(CE_WARN, "pcic: %s: unsupported "
+								"bridge\n",
+							ddi_get_name_addr(dip));
+				return (DDI_FAILURE);
+			}
+			break;
+
+		default:
+		case PCIC_PCI_PCMCIA:
+			/*
+			 * Get access to the adapter IO registers on the
+			 * PCI bus config space.
+			 */
+			attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+			attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
+			attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+
+			/*
+			 * We need a default mapping to the adapter's IO
+			 *	control register space. For most adapters
+			 *	that are of class PCIC_PCI_PCMCIA (or of
+			 *	a default class) the control registers
+			 *	will be using the 82365-type control/data
+			 *	format.
+			 */
+			if (ddi_regs_map_setup(dip, pci_ctrn,
+						(caddr_t *)&pcic->ioaddr,
+						PCIC_PCI_CONTROL_REG_OFFSET,
+						PCIC_PCI_CONTROL_REG_LENGTH,
+						&attr,
+						&pcic->handle) != DDI_SUCCESS) {
+				cmn_err(CE_CONT,
+					"pcic%d: unable to map PCI regs\n",
+					ddi_get_instance(dip));
+				ddi_regs_map_free(&pcic->cfg_handle);
+				kmem_free(pcic, sizeof (pcicdev_t));
+				return (DDI_FAILURE);
+			} /* ddi_regs_map_setup */
+
+			/*
+			 * Find out the chip type - If we're on a PCI bus,
+			 *	the adapter has that information in the PCI
+			 *	config space.
+			 * Note that we call pcic_find_pci_type here since
+			 *	it needs a valid mapped pcic->handle to
+			 *	access some of the adapter registers in
+			 *	some cases.
+			 */
+			if (pcic_find_pci_type(pcic) != DDI_SUCCESS) {
+				ddi_regs_map_free(&pcic->handle);
+				ddi_regs_map_free(&pcic->cfg_handle);
+				kmem_free(pcic, sizeof (pcicdev_t));
+				cmn_err(CE_WARN, "pcic: %s: unsupported "
+								"bridge\n",
+							ddi_get_name_addr(dip));
+				return (DDI_FAILURE);
+			}
+
+			/*
+			 * Some PCI-PCMCIA(R2) adapters are Yenta-compliant
+			 *	for extended registers even though they are
+			 *	not CardBus adapters. For those adapters,
+			 *	re-map pcic->handle to be large enough to
+			 *	encompass the Yenta registers.
+			 */
+			switch (pcic->pc_type) {
+			    case PCIC_TI_PCI1031:
+				ddi_regs_map_free(&pcic->handle);
+
+				if (ddi_regs_map_setup(dip,
+						PCIC_PCI_CONTROL_REG_NUM,
+						(caddr_t *)&pcic->ioaddr,
+						PCIC_PCI_CONTROL_REG_OFFSET,
+						PCIC_CB_CONTROL_REG_LENGTH,
+						&attr,
+						&pcic->handle) != DDI_SUCCESS) {
+					cmn_err(CE_CONT,
+						"pcic%d: unable to map "
+								"PCI regs\n",
+						ddi_get_instance(dip));
+					ddi_regs_map_free(&pcic->cfg_handle);
+					kmem_free(pcic, sizeof (pcicdev_t));
+					return (DDI_FAILURE);
+				} /* ddi_regs_map_setup */
+				break;
+			    default:
+				break;
+			} /* switch (pcic->pc_type) */
+			break;
+		} /* switch (class_code) */
+	} else {
+		/*
+		 * We're not on a PCI bus, so assume an ISA bus type
+		 * register property. Get access to the adapter IO
+		 * registers on a non-PCI bus.
+		 */
+		attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+		attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
+		attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+		pcic->mem_reg_num = PCIC_ISA_MEM_REG_NUM;
+		pcic->io_reg_num = PCIC_ISA_IO_REG_NUM;
+
+		if (ddi_regs_map_setup(dip, PCIC_ISA_CONTROL_REG_NUM,
+					(caddr_t *)&pcic->ioaddr,
+					PCIC_ISA_CONTROL_REG_OFFSET,
+					PCIC_ISA_CONTROL_REG_LENGTH,
+					&attr,
+					&pcic->handle) != DDI_SUCCESS) {
+			cmn_err(CE_CONT,
+				"pcic%d: unable to map ISA registers\n",
+				ddi_get_instance(dip));
+
+			kmem_free(pcic, sizeof (pcicdev_t));
+			return (DDI_FAILURE);
+		} /* ddi_regs_map_setup */
+
+		/* ISA bus is limited to 24-bits, but not first 640K */
+		pcic->pc_base = 0xd0000;
+		pcic->pc_bound = (uint32_t)~0;
+		pcic->pc_iobase = 0x1000;
+		pcic->pc_iobound = 0xefff;
+	} /* !PCF_PCIBUS */
+
+#ifdef  PCIC_DEBUG
+	if (pcic_debug) {
+		cmn_err(CE_CONT, "pcic_attach pc_flags=%x pc_type=%x\n",
+		    pcic->pc_flags, pcic->pc_type);
+	}
+#endif
+
+	/*
+	 * Setup various adapter registers for the PCI case. For the
+	 * non-PCI case, find out the chip type.
+	 */
+	if (pcic->pc_flags & PCF_PCIBUS) {
+		int iline;
+#if defined(__sparc)
+		iline = 0;
+#else
+		iline = cardbus_validate_iline(dip, pcic->cfg_handle);
+#endif
+
+		/* set flags and socket counts based on chip type */
+		switch (pcic->pc_type) {
+			uint32_t cfg;
+		case PCIC_INTEL_i82092:
+			cfg = ddi_get8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_82092_PCICON);
+			/* we can only support 4 Socket version */
+			if (cfg & PCIC_82092_4_SOCKETS) {
+			    pcic->pc_numsockets = 4;
+			    pcic->pc_type = PCIC_INTEL_i82092;
+			    if (iline != 0xFF)
+				    pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
+			    else
+				    pcic->pc_intr_mode = PCIC_INTR_MODE_ISA;
+			} else {
+			    cmn_err(CE_CONT,
+				    "pcic%d: Intel 82092 adapter "
+				    "in unsupported configuration: 0x%x",
+				    ddi_get_instance(pcic->dip), cfg);
+			    pcic->pc_numsockets = 0;
+			} /* PCIC_82092_4_SOCKETS */
+			break;
+		case PCIC_CL_PD6730:
+		case PCIC_CL_PD6729:
+			pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
+			cfg = ddi_getprop(DDI_DEV_T_ANY, dip,
+						DDI_PROP_CANSLEEP,
+						"interrupts", 0);
+			/* if not interrupt pin then must use ISA style IRQs */
+			if (cfg == 0 || iline == 0xFF)
+				pcic->pc_intr_mode = PCIC_INTR_MODE_ISA;
+			else {
+				/*
+				 * we have the option to use PCI interrupts.
+				 * this might not be optimal but in some cases
+				 * is the only thing possible (sparc case).
+				 * we now deterine what is possible.
+				 */
+				pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
+			}
+			pcic->pc_numsockets = 2;
+			pcic->pc_flags |= PCF_IO_REMAP;
+			break;
+		case PCIC_TI_PCI1031:
+			/* this chip doesn't do CardBus but looks like one */
+			pcic->pc_flags &= ~PCF_CARDBUS;
+			/* FALLTHROUGH */
+		default:
+			pcic->pc_flags |= PCF_IO_REMAP;
+			/* FALLTHROUGH */
+			/* indicate feature even if not supported */
+			pcic->pc_flags |= PCF_DMA | PCF_ZV;
+			/* Not sure if these apply to all these chips */
+			pcic->pc_flags |= (PCF_VPPX|PCF_33VCAP);
+			pcic->pc_flags |= pcic_use_cbpwrctl;
+
+			pcic->pc_numsockets = 1; /* one per function */
+			if (iline != 0xFF) {
+				uint8_t cfg;
+				pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
+
+				cfg = ddi_get8(pcic->cfg_handle,
+					(pcic->cfgaddr + PCIC_BRIDGE_CTL_REG));
+				cfg &= (~PCIC_FUN_INT_MOD_ISA);
+				ddi_put8(pcic->cfg_handle, (pcic->cfgaddr +
+					PCIC_BRIDGE_CTL_REG), cfg);
+			}
+			else
+				pcic->pc_intr_mode = PCIC_INTR_MODE_ISA;
+			pcic->pc_io_type = PCIC_IOTYPE_YENTA;
+			break;
+		}
+	} else {
+		/*
+		 * We're not on a PCI bus so do some more
+		 *	checking for adapter type here.
+		 * For the non-PCI bus case:
+		 * It could be any one of a number of different chips
+		 * If we can't determine anything else, it is assumed
+		 * to be an Intel 82365SL.  The Cirrus Logic PD6710
+		 * has an extension register that provides unique
+		 * identification. Toshiba chip isn't detailed as yet.
+		 */
+
+		/* Init the CL id mode */
+		pcic_putb(pcic, 0, PCIC_CHIP_INFO, 0);
+		value = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
+
+		/* default to Intel i82365SL and then refine */
+		pcic->pc_type = PCIC_I82365SL;
+		pcic->pc_chipname = PCIC_TYPE_I82365SL;
+		for (value = 0; pcic_ci_funcs[value] != NULL; value++) {
+			/* go until one succeeds or none left */
+			if (pcic_ci_funcs[value](pcic))
+				break;
+		}
+
+		/* any chip specific flags get set here */
+		switch (pcic->pc_type) {
+		case PCIC_CL_PD6722:
+			pcic->pc_flags |= PCF_DMA;
+		}
+
+		for (i = 0; i < PCIC_MAX_SOCKETS; i++) {
+			/*
+			 * look for total number of sockets.
+			 * basically check each possible socket for
+			 * presence like in probe
+			 */
+
+			/* turn all windows off */
+			pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
+			value = pcic_getb(pcic, i, PCIC_MAPPING_ENABLE);
+
+			/*
+			 * if a zero is read back, then this socket
+			 * might be present. It would be except for
+			 * some systems that map the secondary PCIC
+			 * chip space back to the first.
+			 */
+			if (value != 0) {
+				/* definitely not so skip */
+				/* note: this is for Compaq support */
+				continue;
+			}
+
+			/* further tests */
+			value = pcic_getb(pcic, i, PCIC_CHIP_REVISION) &
+				PCIC_REV_MASK;
+			if (!(value >= PCIC_REV_LEVEL_LOW &&
+				value <= PCIC_REV_LEVEL_HI))
+				break;
+
+			pcic_putb(pcic, i, PCIC_SYSMEM_0_STARTLOW, 0xaa);
+			pcic_putb(pcic, i, PCIC_SYSMEM_1_STARTLOW, 0x55);
+			value = pcic_getb(pcic, i, PCIC_SYSMEM_0_STARTLOW);
+
+			j = pcic_getb(pcic, i, PCIC_SYSMEM_1_STARTLOW);
+			if (value != 0xaa || j != 0x55)
+				break;
+
+			/*
+			 * at this point we know if we have hardware
+			 * of some type and not just the bus holding
+			 * a pattern for us. We still have to determine
+			 * the case where more than 2 sockets are
+			 * really the same due to peculiar mappings of
+			 * hardware.
+			 */
+			j = pcic->pc_numsockets++;
+			pcic->pc_sockets[j].pcs_flags = 0;
+			pcic->pc_sockets[j].pcs_io = pcic->ioaddr;
+			pcic->pc_sockets[j].pcs_socket = i;
+
+			/* put PC Card into RESET, just in case */
+			value = pcic_getb(pcic, i, PCIC_INTERRUPT);
+			pcic_putb(pcic, i, PCIC_INTERRUPT,
+					value & ~PCIC_RESET);
+		}
+
+#if defined(PCIC_DEBUG)
+		if (pcic_debug)
+			cmn_err(CE_CONT, "num sockets = %d\n",
+				pcic->pc_numsockets);
+#endif
+		if (pcic->pc_numsockets == 0) {
+			ddi_regs_map_free(&pcic->handle);
+			kmem_free(pcic, sizeof (pcicdev_t));
+			return (DDI_FAILURE);
+		}
+
+		/*
+		 * need to think this through again in light of
+		 * Compaq not following the model that all the
+		 * chip vendors recommend.  IBM 755 seems to be
+		 * afflicted as well.  Basically, if the vendor
+		 * wired things wrong, socket 0 responds for socket 2
+		 * accesses, etc.
+		 */
+		if (pcic->pc_numsockets > 2) {
+			int count = pcic->pc_numsockets / 4;
+			for (i = 0; i < count; i++) {
+				/* put pattern into socket 0 */
+				pcic_putb(pcic, i,
+						PCIC_SYSMEM_0_STARTLOW, 0x11);
+
+				/* put pattern into socket 2 */
+				pcic_putb(pcic, i + 2,
+						PCIC_SYSMEM_0_STARTLOW, 0x33);
+
+				/* read back socket 0 */
+				value = pcic_getb(pcic, i,
+						    PCIC_SYSMEM_0_STARTLOW);
+
+				/* read back chip 1 socket 0 */
+				j = pcic_getb(pcic, i + 2,
+						PCIC_SYSMEM_0_STARTLOW);
+				if (j == value) {
+					pcic->pc_numsockets -= 2;
+				}
+			}
+		}
+
+		smi = 0xff;	/* no more override */
+
+		if (ddi_getprop(DDI_DEV_T_NONE, dip,
+				DDI_PROP_DONTPASS, "need-mult-irq",
+				0xffff) != 0xffff)
+			pcic->pc_flags |= PCF_MULT_IRQ;
+
+	} /* !PCF_PCIBUS */
+
+	/*
+	 * some platforms/busses need to have resources setup
+	 * this is temporary until a real resource allocator is
+	 * implemented.
+	 */
+
+	pcic_init_assigned(dip);
+
+	typename = pcic->pc_chipname;
+
+#ifdef	PCIC_DEBUG
+	if (pcic_debug) {
+		int nregs, nintrs;
+
+		if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS)
+			nregs = 0;
+
+		if (ddi_dev_nintrs(dip, &nintrs) != DDI_SUCCESS)
+			nintrs = 0;
+
+		cmn_err(CE_CONT,
+			"pcic%d: %d register sets, %d interrupts\n",
+			ddi_get_instance(dip), nregs, nintrs);
+
+		nintrs = 0;
+		while (nregs--) {
+			off_t size;
+
+			if (ddi_dev_regsize(dip, nintrs, &size) ==
+			    DDI_SUCCESS) {
+				cmn_err(CE_CONT,
+					"\tregnum %d size %ld (0x%lx)"
+					"bytes",
+					nintrs, size, size);
+				if (nintrs ==
+				    (pcic->pc_io_type == PCIC_IO_TYPE_82365SL ?
+				    PCIC_ISA_CONTROL_REG_NUM :
+				    PCIC_PCI_CONTROL_REG_NUM))
+					cmn_err(CE_CONT,
+						" mapped at: 0x%p\n",
+						(void *)pcic->ioaddr);
+				else
+					cmn_err(CE_CONT, "\n");
+			} else {
+				cmn_err(CE_CONT,
+					"\tddi_dev_regsize(rnumber"
+					"= %d) returns DDI_FAILURE\n",
+					nintrs);
+			}
+			nintrs++;
+		} /* while */
+	} /* if (pcic_debug) */
+#endif
+
+	cv_init(&pcic->pm_cv, NULL, CV_DRIVER, NULL);
+
+	if (!ddi_getprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
+						"disable-audio", 0))
+		pcic->pc_flags |= PCF_AUDIO;
+
+	if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
+	    "disable-cardbus", 0))
+		pcic->pc_flags &= ~PCF_CARDBUS;
+
+	(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, PCICPROP_CTL,
+	    typename);
+
+	/*
+	 * Init all socket SMI levels to 0 (no SMI)
+	 */
+	for (i = 0; i < PCIC_MAX_SOCKETS; i++) {
+	    pcic->pc_sockets[i].pcs_smi = 0;
+	    pcic->pc_sockets[i].pcs_debounce_id = 0;
+	    pcic->pc_sockets[i].pcs_pcic = pcic;
+	}
+	pcic->pc_lastreg = -1; /* just to make sure we are in sync */
+
+	/*
+	 * Setup the IRQ handler(s)
+	 */
+	switch (pcic->pc_intr_mode) {
+		int xx;
+	case PCIC_INTR_MODE_ISA:
+	/*
+	 * On a non-PCI bus, we just use whatever SMI IRQ level was
+	 *	specified above, and the IO IRQ levels are allocated
+	 *	dynamically.
+	 */
+		for (xx = 15, smi = 0; xx >= 0; xx--) {
+			if (PCIC_IRQ(xx) &
+			    PCIC_AVAIL_IRQS) {
+				smi = pcmcia_get_intr(dip, xx);
+				if (smi >= 0)
+					break;
+			}
+		}
+#if defined(PCIC_DEBUG)
+		if (pcic_debug)
+			cmn_err(CE_NOTE, "\tselected IRQ %d as SMI\n", smi);
+#endif
+		/* init to same so share is easy */
+		for (i = 0; i < pcic->pc_numsockets; i++)
+			pcic->pc_sockets[i].pcs_smi = smi;
+		/* any special handling of IRQ levels */
+		if (pcic->pc_flags & PCF_MULT_IRQ) {
+			for (i = 2; i < pcic->pc_numsockets; i++) {
+				if ((i & 1) == 0) {
+					int xx;
+					for (xx = 15, smi = 0; xx >= 0; xx--) {
+						if (PCIC_IRQ(xx) &
+						    PCIC_AVAIL_IRQS) {
+							smi =
+							    pcmcia_get_intr(dip,
+									    xx);
+							if (smi >= 0)
+								break;
+						}
+					}
+				}
+				if (smi >= 0)
+					pcic->pc_sockets[i].pcs_smi = smi;
+			}
+		}
+		pcic->pc_intr_htblp = kmem_alloc(pcic->pc_numsockets *
+		    sizeof (ddi_intr_handle_t), KM_SLEEP);
+		for (i = 0, irqlevel = -1; i < pcic->pc_numsockets; i++) {
+			struct intrspec *ispecp;
+			struct ddi_parent_private_data *pdp;
+
+			if (irqlevel == pcic->pc_sockets[i].pcs_smi)
+				continue;
+			else {
+				irqlevel = pcic->pc_sockets[i].pcs_smi;
+			}
+			/*
+			 * now convert the allocated IRQ into an intrspec
+			 * and ask our parent to add it.  Don't use
+			 * the ddi_add_intr since we don't have a
+			 * default intrspec in all cases.
+			 *
+			 * note: this sort of violates DDI but we don't
+			 *	 get hardware intrspecs for many of the devices.
+			 *	 at the same time, we know how to allocate them
+			 *	 so we do the right thing.
+			 */
+			if (ddi_intr_alloc(dip, &pcic->pc_intr_htblp[i],
+			    DDI_INTR_TYPE_FIXED, 0, 1, &actual,
+			    DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) {
+				cmn_err(CE_WARN, "%s: ddi_intr_alloc failed",
+				    ddi_get_name(dip));
+				goto isa_exit1;
+			}
+
+			/*
+			 * See earlier note:
+			 * Since some devices don't have 'intrspec'
+			 * we make one up in rootnex.
+			 *
+			 * However, it is not properly initialized as
+			 * the data it needs is present in this driver
+			 * and there is no interface to pass that up.
+			 * Specially 'irqlevel' is very important and
+			 * it is part of pcic struct.
+			 *
+			 * Set 'intrspec' up here; otherwise adding the
+			 * interrupt will fail.
+			 */
+			pdp = ddi_get_parent_data(dip);
+			ispecp = (struct intrspec *)&pdp->par_intr[0];
+			ispecp->intrspec_vec = irqlevel;
+			ispecp->intrspec_pri = pcic->pc_irq;
+
+			/* Stay compatible w/ PCMCIA */
+			pcic->pc_pri = (ddi_iblock_cookie_t)
+			    (uintptr_t)pcic->pc_irq;
+			pcic->pc_dcookie.idev_priority =
+			    (uintptr_t)pcic->pc_pri;
+			pcic->pc_dcookie.idev_vector = (ushort_t)irqlevel;
+
+			(void) ddi_intr_set_pri(pcic->pc_intr_htblp[i],
+			    pcic->pc_irq);
+
+			if (i == 0) {
+				mutex_init(&pcic->intr_lock, NULL, MUTEX_DRIVER,
+				    DDI_INTR_PRI(pcic->pc_irq));
+				mutex_init(&pcic->pc_lock, NULL, MUTEX_DRIVER,
+				    NULL);
+			}
+
+			if (ddi_intr_add_handler(pcic->pc_intr_htblp[i],
+			    pcic_intr, (caddr_t)pcic, NULL)) {
+				cmn_err(CE_WARN,
+				    "%s: ddi_intr_add_handler failed",
+				    ddi_get_name(dip));
+				goto isa_exit2;
+			}
+
+			if (ddi_intr_enable(pcic->pc_intr_htblp[i])) {
+				cmn_err(CE_WARN, "%s: ddi_intr_enable failed",
+				    ddi_get_name(dip));
+				for (j = i; j < 0; j--)
+					(void) ddi_intr_remove_handler(
+					    pcic->pc_intr_htblp[j]);
+				goto isa_exit2;
+			}
+		}
+		break;
+	case PCIC_INTR_MODE_PCI_1:
+	case PCIC_INTR_MODE_PCI:
+		/*
+		 * If we're on a PCI bus, we route all interrupts, both SMI
+		 * and IO interrupts, through a single interrupt line.
+		 * Assign the SMI IRQ level to the IO IRQ level here.
+		 */
+		pcic->pc_pci_intr_hdlp = kmem_alloc(sizeof (ddi_intr_handle_t),
+		    KM_SLEEP);
+		if (ddi_intr_alloc(dip, pcic->pc_pci_intr_hdlp,
+		    DDI_INTR_TYPE_FIXED, 0, 1, &actual,
+		    DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS)
+			goto pci_exit1;
+
+		if (ddi_intr_get_pri(pcic->pc_pci_intr_hdlp[0],
+		    &pri) != DDI_SUCCESS) {
+			(void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]);
+			goto pci_exit1;
+		}
+
+		pcic->pc_pri = (void *)(uintptr_t)pri;
+		mutex_init(&pcic->intr_lock, NULL, MUTEX_DRIVER, pcic->pc_pri);
+		mutex_init(&pcic->pc_lock, NULL, MUTEX_DRIVER, NULL);
+
+		if (ddi_intr_add_handler(pcic->pc_pci_intr_hdlp[0],
+		    pcic_intr, (caddr_t)pcic, NULL))
+			goto pci_exit2;
+
+		if (ddi_intr_enable(pcic->pc_pci_intr_hdlp[0])) {
+			(void) ddi_intr_remove_handler(
+			    pcic->pc_pci_intr_hdlp[0]);
+			goto pci_exit2;
+		}
+
+		/* Stay compatible w/ PCMCIA */
+		pcic->pc_dcookie.idev_priority = (ushort_t)pri;
+
+		/* init to same (PCI) so share is easy */
+		for (i = 0; i < pcic->pc_numsockets; i++)
+			pcic->pc_sockets[i].pcs_smi = 0xF; /* any valid */
+		break;
+	}
+
+	/*
+	 * Setup the adapter hardware to some reasonable defaults.
+	 */
+	mutex_enter(&pcic->pc_lock);
+	/* mark the driver state as attached */
+	pcic->pc_flags |= PCF_ATTACHED;
+	pcic_setup_adapter(pcic);
+
+	for (j = 0; j < pcic->pc_numsockets; j++)
+		if (ddi_intr_add_softint(dip,
+		    &pcic->pc_sockets[j].pcs_cd_softint_hdl,
+		    PCIC_SOFTINT_PRI_VAL, pcic_cd_softint,
+		    (caddr_t)&pcic->pc_sockets[j]) != DDI_SUCCESS)
+			goto pci_exit2;
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug)
+		cmn_err(CE_CONT, "type = %s sockets = %d\n", typename,
+						pcic->pc_numsockets);
+#endif
+
+	pcic_nexus->an_iblock = &pcic->pc_pri;
+	pcic_nexus->an_idev = &pcic->pc_dcookie;
+
+	mutex_exit(&pcic->pc_lock);
+
+#ifdef CARDBUS
+	(void) cardbus_enable_cd_intr(dip);
+	if (pcic_debug) {
+
+		cardbus_dump_pci_config(dip);
+		cardbus_dump_socket(dip);
+	}
+
+	/*
+	 * Give the Cardbus misc module a chance to do it's per-adapter
+	 * instance setup. Note that there is no corresponding detach()
+	 * call.
+	 */
+	if (pcic->pc_flags & PCF_CARDBUS)
+		if (cardbus_attach(dip, &pcic_cbnexus_ops) != DDI_SUCCESS) {
+			cmn_err(CE_CONT,
+			    "pcic_attach: cardbus_attach failed\n");
+			goto pci_exit2;
+		}
+#endif
+
+	/*
+	 * Give the PCMCIA misc module a chance to do it's per-adapter
+	 *	instance setup.
+	 */
+	if ((i = pcmcia_attach(dip, pcic_nexus)) != DDI_SUCCESS)
+		goto pci_exit2;
+
+	syshw_attach(pcic);
+	if (pcic_maxinst == -1) {
+		/* This assumes that all instances run at the same IPL. */
+		mutex_init(&pcic_deb_mtx, NULL, MUTEX_DRIVER, NULL);
+		cv_init(&pcic_deb_cv, NULL, CV_DRIVER, NULL);
+		pcic_deb_threadid = thread_create((caddr_t)NULL, 0,
+		    pcic_deb_thread, (caddr_t)NULL, 0, &p0, TS_RUN,
+		    v.v_maxsyspri - 2);
+	}
+	pcic_maxinst = max(pcic_maxinst, ddi_get_instance(dip));
+	/*
+	 * Setup a debounce timeout to do an initial card detect
+	 * and enable interrupts.
+	 */
+	for (j = 0; j < pcic->pc_numsockets; j++) {
+		shwp = kmem_alloc(sizeof (syshw_t), KM_SLEEP);
+		if (shwp) {
+			bcopy(&pcic_syshw, shwp, sizeof (pcic_syshw));
+			pcic_syshw.id_string[15]++;
+			pcic->pc_sockets[j].pcs_syshwsig =
+			    syshw_add2map(shwp, pcic_syshw_cardstate,
+				&pcic->pc_sockets[j]);
+		}
+		pcic->pc_sockets[j].pcs_debounce_id =
+		    pcic_add_debqueue(&pcic->pc_sockets[j],
+			drv_usectohz(pcic_debounce_time));
+	}
+
+	return (i);
+
+isa_exit2:
+	mutex_destroy(&pcic->intr_lock);
+	mutex_destroy(&pcic->pc_lock);
+	for (j = i; j < 0; j--)
+		(void) ddi_intr_free(pcic->pc_intr_htblp[j]);
+isa_exit1:
+	(void) pcmcia_return_intr(dip, pcic->pc_sockets[i].pcs_smi);
+	ddi_regs_map_free(&pcic->handle);
+	if (pcic->pc_flags & PCF_PCIBUS)
+		ddi_regs_map_free(&pcic->cfg_handle);
+	kmem_free(pcic->pc_intr_htblp, pcic->pc_numsockets *
+	    sizeof (ddi_intr_handle_t));
+	kmem_free(pcic, sizeof (pcicdev_t));
+		return (DDI_FAILURE);
+
+pci_exit2:
+	mutex_destroy(&pcic->intr_lock);
+	mutex_destroy(&pcic->pc_lock);
+	(void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]);
+pci_exit1:
+	ddi_regs_map_free(&pcic->handle);
+	if (pcic->pc_flags & PCF_PCIBUS)
+		ddi_regs_map_free(&pcic->cfg_handle);
+	kmem_free(pcic->pc_pci_intr_hdlp, sizeof (ddi_intr_handle_t));
+	kmem_free(pcic, sizeof (pcicdev_t));
+	return (DDI_FAILURE);
+}
+
+/*
+ * pcic_detach()
+ *	request to detach from the system
+ */
+static int
+pcic_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+	int i;
+
+	switch (cmd) {
+	case DDI_DETACH:
+		/* don't detach if the nexus still talks to us */
+		if (pcic->pc_callback != NULL)
+			return (DDI_FAILURE);
+		syshw_detach(pcic);
+
+		/* kill off the pm simulation */
+		if (pcic->pc_pmtimer)
+			(void) untimeout(pcic->pc_pmtimer);
+
+		/* turn everything off for all sockets and chips */
+		for (i = 0; i < pcic->pc_numsockets; i++) {
+			if (pcic->pc_sockets[i].pcs_debounce_id)
+				pcic_rm_debqueue(
+				    pcic->pc_sockets[i].pcs_debounce_id);
+			pcic->pc_sockets[i].pcs_debounce_id = 0;
+
+			pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0);
+			pcic_putb(pcic, i, PCIC_CARD_DETECT, 0);
+			pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
+			/* disable interrupts and put card into RESET */
+			pcic_putb(pcic, i, PCIC_INTERRUPT, 0);
+		}
+		(void) ddi_intr_disable(pcic->pc_pci_intr_hdlp[0]);
+		(void) ddi_intr_remove_handler(pcic->pc_pci_intr_hdlp[0]);
+		(void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]);
+		kmem_free(pcic->pc_pci_intr_hdlp, sizeof (ddi_intr_handle_t));
+		pcic->pc_flags = 0;
+		mutex_destroy(&pcic->pc_lock);
+		mutex_destroy(&pcic->intr_lock);
+		cv_destroy(&pcic->pm_cv);
+		if (pcic->pc_flags & PCF_PCIBUS)
+		    ddi_regs_map_free(&pcic->cfg_handle);
+		if (pcic->handle)
+		    ddi_regs_map_free(&pcic->handle);
+		kmem_free(pcic, sizeof (pcicdev_t));
+		ddi_soft_state_free(pcic_soft_state_p, ddi_get_instance(dip));
+		return (DDI_SUCCESS);
+
+	case DDI_SUSPEND:
+	case DDI_PM_SUSPEND:
+		/*
+		 * we got a suspend event (either real or imagined)
+		 * so notify the nexus proper that all existing cards
+		 * should go away.
+		 */
+		mutex_enter(&pcic->pc_lock);
+#ifdef CARDBUS
+		if (pcic->pc_flags & PCF_CARDBUS)
+			for (i = 0; i < pcic->pc_numsockets; i++)
+				if ((pcic->pc_sockets[i].pcs_flags &
+				    (PCS_CARD_PRESENT|PCS_CARD_ISCARDBUS)) ==
+				    (PCS_CARD_PRESENT|PCS_CARD_ISCARDBUS))
+					if (!cardbus_can_suspend(dip)) {
+						mutex_exit(&pcic->pc_lock);
+						cmn_err(CE_WARN,
+						    "Please unconfigure all "
+						    "CardBus devices before "
+						    "attempting to suspend\n");
+						return (DDI_FAILURE);
+					}
+#endif
+		/* turn everything off for all sockets and chips */
+		for (i = 0; i < pcic->pc_numsockets; i++) {
+			if (pcic->pc_sockets[i].pcs_debounce_id)
+				pcic_rm_debqueue(
+				    pcic->pc_sockets[i].pcs_debounce_id);
+			pcic->pc_sockets[i].pcs_debounce_id = 0;
+
+			pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0);
+			pcic_putb(pcic, i, PCIC_CARD_DETECT, 0);
+			pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
+			/* disable interrupts and put card into RESET */
+			pcic_putb(pcic, i, PCIC_INTERRUPT, 0);
+			pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0);
+			if (pcic->pc_flags & PCF_CBPWRCTL)
+				pcic_putcb(pcic, CB_CONTROL, 0);
+
+			if (pcic->pc_sockets[i].pcs_flags & PCS_CARD_PRESENT) {
+				pcic->pc_sockets[i].pcs_flags = PCS_STARTING;
+				/*
+				 * Because we are half way through a save
+				 * all this does is schedule a removal event
+				 * to cs for when the system comes back.
+				 * This doesn't actually matter.
+				 */
+				if (!pcic_do_pcmcia_sr && pcic_do_removal &&
+				    pcic->pc_callback) {
+					PC_CALLBACK(pcic->dip, pcic->pc_cb_arg,
+					    PCE_CARD_REMOVAL,
+					    pcic->pc_sockets[i].pcs_socket);
+				}
+			}
+		}
+
+		pcic->pc_flags |= PCF_SUSPENDED;
+		mutex_exit(&pcic->pc_lock);
+		pcic_delayed_resume_toid = 0;
+
+		/*
+		 * when true power management exists, save the adapter
+		 * state here to enable a recovery.  For the emulation
+		 * condition, the state is gone
+		 */
+		return (DDI_SUCCESS);
+
+	default:
+		return (EINVAL);
+	}
+}
+
+static uint32_t pcic_tisysctl_onbits = ((1<<27) | (1<<15) | (1<<14));
+static uint32_t pcic_tisysctl_offbits = 0;
+static uint32_t pcic_default_latency = 0x40;
+
+static void
+pcic_setup_adapter(pcicdev_t *pcic)
+{
+	int i;
+	int value, flags;
+
+	if (pcic->pc_flags & PCF_PCIBUS) {
+		/*
+		 * all PCI-to-PCMCIA bus bridges need memory and I/O enabled
+		 */
+		flags = (PCIC_ENABLE_IO | PCIC_ENABLE_MEM);
+		pcic_iomem_pci_ctl(pcic->cfg_handle, pcic->cfgaddr, flags);
+	}
+	/* enable each socket */
+	for (i = 0; i < pcic->pc_numsockets; i++) {
+		pcic->pc_sockets[i].pcs_flags = 0;
+		/* find out the socket capabilities (I/O vs memory) */
+		value = pcic_getb(pcic, i,
+					PCIC_CHIP_REVISION) & PCIC_REV_ID_MASK;
+		if (value == PCIC_REV_ID_IO || value == PCIC_REV_ID_BOTH)
+			pcic->pc_sockets[i].pcs_flags |= PCS_SOCKET_IO;
+
+		/* disable all windows just in case */
+		pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
+
+		switch (pcic->pc_type) {
+			uint32_t cfg32;
+			uint16_t cfg16;
+			uint8_t cfg;
+
+		    /* enable extended registers for Vadem */
+		    case PCIC_VADEM_VG469:
+		    case PCIC_VADEM:
+
+			/* enable card status change interrupt for socket */
+			break;
+
+		    case PCIC_I82365SL:
+			break;
+
+		    case PCIC_CL_PD6710:
+			pcic_putb(pcic, 0, PCIC_MISC_CTL_2, PCIC_LED_ENABLE);
+			break;
+
+			/*
+			 * On the CL_6730, we need to set up the interrupt
+			 * signalling mode (PCI mode) and set the SMI and
+			 * IRQ interrupt lines to PCI/level-mode.
+			 */
+		    case PCIC_CL_PD6730:
+			switch (pcic->pc_intr_mode) {
+			case PCIC_INTR_MODE_PCI_1:
+				clext_reg_write(pcic, i, PCIC_CLEXT_MISC_CTL_3,
+						((clext_reg_read(pcic, i,
+						PCIC_CLEXT_MISC_CTL_3) &
+						~PCIC_CLEXT_INT_PCI) |
+						PCIC_CLEXT_INT_PCI));
+				clext_reg_write(pcic, i, PCIC_CLEXT_EXT_CTL_1,
+						(PCIC_CLEXT_IRQ_LVL_MODE |
+						PCIC_CLEXT_SMI_LVL_MODE));
+				cfg = PCIC_CL_LP_DYN_MODE;
+				pcic_putb(pcic, i, PCIC_MISC_CTL_2, cfg);
+				break;
+			case PCIC_INTR_MODE_ISA:
+				break;
+			}
+			break;
+			/*
+			 * On the CL_6729, we set the SMI and IRQ interrupt
+			 *	lines to PCI/level-mode. as well as program the
+			 *	correct clock speed divider bit.
+			 */
+		    case PCIC_CL_PD6729:
+			switch (pcic->pc_intr_mode) {
+			case PCIC_INTR_MODE_PCI_1:
+				clext_reg_write(pcic, i, PCIC_CLEXT_EXT_CTL_1,
+						(PCIC_CLEXT_IRQ_LVL_MODE |
+						PCIC_CLEXT_SMI_LVL_MODE));
+
+				break;
+			case PCIC_INTR_MODE_ISA:
+				break;
+			}
+			if (pcic->bus_speed > PCIC_PCI_25MHZ && i == 0) {
+				cfg = 0;
+				cfg |= PCIC_CL_TIMER_CLK_DIV;
+				pcic_putb(pcic, i, PCIC_MISC_CTL_2, cfg);
+			}
+			break;
+		    case PCIC_INTEL_i82092:
+			cfg = PCIC_82092_EN_TIMING;
+			if (pcic->bus_speed < PCIC_SYSCLK_33MHZ)
+			    cfg |= PCIC_82092_PCICLK_25MHZ;
+			ddi_put8(pcic->cfg_handle, pcic->cfgaddr +
+						PCIC_82092_PCICON, cfg);
+			break;
+		    case PCIC_TI_PCI1130:
+		    case PCIC_TI_PCI1131:
+		    case PCIC_TI_PCI1250:
+		    case PCIC_TI_PCI1031:
+			cfg = ddi_get8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_DEVCTL_REG);
+			cfg &= ~PCIC_DEVCTL_INTR_MASK;
+			switch (pcic->pc_intr_mode) {
+			case PCIC_INTR_MODE_ISA:
+				cfg |= PCIC_DEVCTL_INTR_ISA;
+				break;
+			}
+#ifdef PCIC_DEBUG
+			if (pcic_debug) {
+				cmn_err(CE_CONT, "pcic_setup_adapter: "
+				    "write reg 0x%x=%x \n",
+				    PCIC_DEVCTL_REG, cfg);
+			}
+#endif
+			ddi_put8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_DEVCTL_REG,
+					cfg);
+
+			cfg = ddi_get8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_CRDCTL_REG);
+			cfg &= ~(PCIC_CRDCTL_PCIINTR|PCIC_CRDCTL_PCICSC|
+					PCIC_CRDCTL_PCIFUNC);
+			switch (pcic->pc_intr_mode) {
+			case PCIC_INTR_MODE_PCI_1:
+				cfg |= PCIC_CRDCTL_PCIINTR |
+					PCIC_CRDCTL_PCICSC |
+					PCIC_CRDCTL_PCIFUNC;
+				pcic->pc_flags |= PCF_USE_SMI;
+				break;
+			}
+#ifdef PCIC_DEBUG
+			if (pcic_debug) {
+				cmn_err(CE_CONT, "pcic_setup_adapter: "
+				    " write reg 0x%x=%x \n",
+				    PCIC_CRDCTL_REG, cfg);
+			}
+#endif
+			ddi_put8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_CRDCTL_REG,
+					cfg);
+			break;
+		    case PCIC_TI_PCI1221:
+		    case PCIC_TI_PCI1225:
+			cfg = ddi_get8(pcic->cfg_handle,
+			    pcic->cfgaddr + PCIC_DEVCTL_REG);
+			cfg |= (PCIC_DEVCTL_INTR_DFLT | PCIC_DEVCTL_3VCAPABLE);
+#ifdef PCIC_DEBUG
+			if (pcic_debug) {
+				cmn_err(CE_CONT, "pcic_setup_adapter: "
+				    " write reg 0x%x=%x \n",
+				    PCIC_DEVCTL_REG, cfg);
+			}
+#endif
+			ddi_put8(pcic->cfg_handle,
+			    pcic->cfgaddr + PCIC_DEVCTL_REG, cfg);
+
+			cfg = ddi_get8(pcic->cfg_handle,
+			    pcic->cfgaddr + PCIC_DIAG_REG);
+			if (pcic->pc_type == PCIC_TI_PCI1225) {
+				cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC);
+			} else {
+				cfg |= PCIC_DIAG_ASYNC;
+			}
+			pcic->pc_flags |= PCF_USE_SMI;
+#ifdef PCIC_DEBUG
+			if (pcic_debug) {
+				cmn_err(CE_CONT, "pcic_setup_adapter: "
+				    " write reg 0x%x=%x \n",
+				    PCIC_DIAG_REG, cfg);
+			}
+#endif
+			ddi_put8(pcic->cfg_handle,
+			    pcic->cfgaddr + PCIC_DIAG_REG, cfg);
+			break;
+		    case PCIC_TI_PCI1520:
+		    case PCIC_TI_VENDOR:
+			if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) {
+				cfg = ddi_get8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
+				cfg |= PCIC_FUN_INT_MOD_ISA;
+				ddi_put8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
+					cfg);
+			}
+			cfg = ddi_get8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_DEVCTL_REG);
+			cfg &= ~PCIC_DEVCTL_INTR_MASK;
+			if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA)
+				cfg |= PCIC_DEVCTL_INTR_ISA;
+			ddi_put8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_DEVCTL_REG,
+					cfg);
+
+			/* tie INTA and INTB together */
+			cfg = ddi_get8(pcic->cfg_handle,
+				(pcic->cfgaddr + PCIC_SYSCTL_REG + 3));
+			cfg |= PCIC_SYSCTL_INTRTIE;
+			ddi_put8(pcic->cfg_handle, (pcic->cfgaddr +
+				PCIC_SYSCTL_REG + 3), cfg);
+			cfg = ddi_get8(pcic->cfg_handle,
+			    pcic->cfgaddr + PCIC_DIAG_REG);
+			cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC);
+			ddi_put8(pcic->cfg_handle,
+			    pcic->cfgaddr + PCIC_DIAG_REG, cfg);
+			break;
+		    case PCIC_TI_PCI1410:
+			cfg = ddi_get8(pcic->cfg_handle,
+			    pcic->cfgaddr + PCIC_DIAG_REG);
+			cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC);
+			ddi_put8(pcic->cfg_handle,
+			    pcic->cfgaddr + PCIC_DIAG_REG, cfg);
+			break;
+		    case PCIC_TOSHIBA_TOPIC100:
+		    case PCIC_TOSHIBA_TOPIC95:
+		    case PCIC_TOSHIBA_VENDOR:
+			cfg = ddi_get8(pcic->cfg_handle, pcic->cfgaddr +
+				PCIC_TOSHIBA_SLOT_CTL_REG);
+			cfg |= (PCIC_TOSHIBA_SCR_SLOTON |
+				PCIC_TOSHIBA_SCR_SLOTEN);
+			cfg &= (~PCIC_TOSHIBA_SCR_PRT_MASK);
+			cfg |= PCIC_TOSHIBA_SCR_PRT_3E2;
+			ddi_put8(pcic->cfg_handle, pcic->cfgaddr +
+				PCIC_TOSHIBA_SLOT_CTL_REG, cfg);
+			cfg = ddi_get8(pcic->cfg_handle, pcic->cfgaddr +
+				PCIC_TOSHIBA_INTR_CTL_REG);
+			switch (pcic->pc_intr_mode) {
+			case PCIC_INTR_MODE_ISA:
+				cfg &= ~PCIC_TOSHIBA_ICR_SRC;
+				ddi_put8(pcic->cfg_handle,
+					pcic->cfgaddr +
+					PCIC_TOSHIBA_INTR_CTL_REG, cfg);
+
+				cfg = ddi_get8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
+				cfg |= PCIC_FUN_INT_MOD_ISA;
+				ddi_put8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
+					cfg);
+				break;
+			case PCIC_INTR_MODE_PCI_1:
+				cfg |= PCIC_TOSHIBA_ICR_SRC;
+				cfg &= (~PCIC_TOSHIBA_ICR_PIN_MASK);
+				cfg |= PCIC_TOSHIBA_ICR_PIN_INTA;
+				ddi_put8(pcic->cfg_handle,
+					pcic->cfgaddr +
+					PCIC_TOSHIBA_INTR_CTL_REG, cfg);
+				break;
+			}
+			break;
+		    case PCIC_O2MICRO_VENDOR:
+			cfg32 = ddi_get32(pcic->cfg_handle,
+				(uint32_t *)(pcic->cfgaddr +
+				PCIC_O2MICRO_MISC_CTL));
+			switch (pcic->pc_intr_mode) {
+			case PCIC_INTR_MODE_ISA:
+				cfg32 |= (PCIC_O2MICRO_ISA_LEGACY |
+					PCIC_O2MICRO_INT_MOD_PCI);
+				ddi_put32(pcic->cfg_handle,
+					(uint32_t *)(pcic->cfgaddr +
+					PCIC_O2MICRO_MISC_CTL),
+					cfg32);
+				cfg = ddi_get8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
+				cfg |= PCIC_FUN_INT_MOD_ISA;
+				ddi_put8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
+					cfg);
+				break;
+			case PCIC_INTR_MODE_PCI_1:
+				cfg32 &= ~PCIC_O2MICRO_ISA_LEGACY;
+				cfg32 |= PCIC_O2MICRO_INT_MOD_PCI;
+				ddi_put32(pcic->cfg_handle,
+					(uint32_t *)(pcic->cfgaddr +
+					PCIC_O2MICRO_MISC_CTL),
+					cfg32);
+				break;
+			}
+			break;
+		    case PCIC_RICOH_VENDOR:
+			if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) {
+				cfg16 = ddi_get16(pcic->cfg_handle,
+					(uint16_t *)(pcic->cfgaddr +
+					PCIC_RICOH_MISC_CTL_2));
+				cfg16 |= (PCIC_RICOH_CSC_INT_MOD |
+					PCIC_RICOH_FUN_INT_MOD);
+				ddi_put16(pcic->cfg_handle,
+					(uint16_t *)(pcic->cfgaddr +
+					PCIC_RICOH_MISC_CTL_2),
+					cfg16);
+
+				cfg16 = ddi_get16(pcic->cfg_handle,
+					(uint16_t *)(pcic->cfgaddr +
+					PCIC_RICOH_MISC_CTL));
+				cfg16 |= PCIC_RICOH_SIRQ_EN;
+				ddi_put16(pcic->cfg_handle,
+					(uint16_t *)(pcic->cfgaddr +
+					PCIC_RICOH_MISC_CTL),
+					cfg16);
+
+				cfg = ddi_get8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
+				cfg |= PCIC_FUN_INT_MOD_ISA;
+				ddi_put8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
+					cfg);
+			}
+			break;
+		    default:
+			break;
+		} /* switch */
+
+		/* setup general card status change interrupt */
+		switch (pcic->pc_type) {
+			case PCIC_TI_PCI1225:
+			case PCIC_TI_PCI1221:
+			case PCIC_TI_PCI1031:
+			case PCIC_TI_PCI1520:
+			case PCIC_TI_PCI1410:
+				pcic_putb(pcic, i, PCIC_MANAGEMENT_INT,
+				    PCIC_CHANGE_DEFAULT);
+				break;
+			default:
+				if (pcic->pc_intr_mode ==
+					PCIC_INTR_MODE_PCI_1) {
+					pcic_putb(pcic, i, PCIC_MANAGEMENT_INT,
+						PCIC_CHANGE_DEFAULT);
+					break;
+				} else {
+					pcic_putb(pcic, i, PCIC_MANAGEMENT_INT,
+						PCIC_CHANGE_DEFAULT |
+					(pcic->pc_sockets[i].pcs_smi << 4));
+					break;
+				}
+		}
+
+		pcic->pc_flags |= PCF_INTRENAB;
+
+		/* take card out of RESET */
+		pcic_putb(pcic, i, PCIC_INTERRUPT, PCIC_RESET);
+		/* turn power off and let CS do this */
+		pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0);
+
+		/* final chip specific initialization */
+		switch (pcic->pc_type) {
+		    case PCIC_VADEM:
+			pcic_putb(pcic, i, PCIC_VG_CONTROL,
+					PCIC_VC_DELAYENABLE);
+			pcic->pc_flags |= PCF_DEBOUNCE;
+			/* FALLTHROUGH */
+		    case PCIC_I82365SL:
+			pcic_putb(pcic, i, PCIC_GLOBAL_CONTROL,
+					PCIC_GC_CSC_WRITE);
+			/* clear any pending interrupts */
+			value = pcic_getb(pcic, i, PCIC_CARD_STATUS_CHANGE);
+			pcic_putb(pcic, i, PCIC_CARD_STATUS_CHANGE, value);
+			break;
+		    /* The 82092 uses PCI config space to enable interrupts */
+		    case PCIC_INTEL_i82092:
+			pcic_82092_smiirq_ctl(pcic, i, PCIC_82092_CTL_SMI,
+							PCIC_82092_INT_ENABLE);
+			break;
+		    case PCIC_CL_PD6729:
+			if (pcic->bus_speed >= PCIC_PCI_DEF_SYSCLK && i == 0) {
+				value = pcic_getb(pcic, i, PCIC_MISC_CTL_2);
+				pcic_putb(pcic, i, PCIC_MISC_CTL_2,
+						value | PCIC_CL_TIMER_CLK_DIV);
+			}
+			break;
+		} /* switch */
+
+#if defined(PCIC_DEBUG)
+		if (pcic_debug)
+			cmn_err(CE_CONT,
+				"socket %d value=%x, flags = %x (%s)\n",
+				i, value, pcic->pc_sockets[i].pcs_flags,
+				(pcic->pc_sockets[i].pcs_flags &
+					PCS_CARD_PRESENT) ?
+						"card present" : "no card");
+#endif
+	}
+}
+
+/*
+ * pcic_intr(caddr_t, caddr_t)
+ *	interrupt handler for the PCIC style adapter
+ *	handles all basic interrupts and also checks
+ *	for status changes and notifies the nexus if
+ *	necessary
+ *
+ *	On PCI bus adapters, also handles all card
+ *	IO interrupts.
+ */
+/*ARGSUSED*/
+uint32_t
+pcic_intr(caddr_t arg1, caddr_t arg2)
+{
+	pcicdev_t *pcic = (pcicdev_t *)arg1;
+	int value = 0, i, ret = DDI_INTR_UNCLAIMED;
+	uint8_t status;
+	uint_t io_ints;
+
+#if defined(PCIC_DEBUG)
+	pcic_err(pcic->dip, 0xf,
+		"pcic_intr: enter pc_flags=0x%x PCF_ATTACHED=0x%x"
+		" pc_numsockets=%d \n",
+		pcic->pc_flags, PCF_ATTACHED, pcic->pc_numsockets);
+#endif
+
+	if (!(pcic->pc_flags & PCF_ATTACHED))
+	    return (DDI_INTR_UNCLAIMED);
+
+	mutex_enter(&pcic->intr_lock);
+
+	if (pcic->pc_flags & PCF_SUSPENDED) {
+		mutex_exit(&pcic->intr_lock);
+		return (ret);
+	}
+
+	/*
+	 * need to change to only ACK and touch the slot that
+	 * actually caused the interrupt.  Currently everything
+	 * is acked
+	 *
+	 * we need to look at all known sockets to determine
+	 * what might have happened, so step through the list
+	 * of them
+	 */
+#ifdef VOYAGER
+	ret = syshw_intr_hi(pcic);
+#endif
+
+	/*
+	 * Set the bitmask for IO interrupts to initially include all sockets
+	 */
+	io_ints = (1 << pcic->pc_numsockets) - 1;
+
+	for (i = 0; i < pcic->pc_numsockets; i++) {
+		int card_type;
+		pcic_socket_t *sockp;
+		int value_cb = 0;
+
+		sockp = &pcic->pc_sockets[i];
+		/* get the socket's I/O addresses */
+
+		if (sockp->pcs_flags & PCS_WAITING) {
+			io_ints &= ~(1 << i);
+			continue;
+		}
+
+		if (sockp->pcs_flags & PCS_CARD_IO)
+			card_type = IF_IO;
+		else
+			card_type = IF_MEMORY;
+
+		if (pcic->pc_io_type == PCIC_IO_TYPE_YENTA)
+			value_cb = pcic_getcb(pcic, CB_STATUS_EVENT);
+
+		value = pcic_change(pcic, i);
+
+		if ((value != 0) || (value_cb != 0)) {
+			int x = pcic->pc_cb_arg;
+
+			ret = DDI_INTR_CLAIMED;
+
+#if defined(PCIC_DEBUG)
+			pcic_err(pcic->dip, 0x9,
+			    "card_type = %d, value_cb = 0x%x\n",
+			    card_type,
+			    value_cb ? value_cb :
+				pcic_getcb(pcic, CB_STATUS_EVENT));
+			if (pcic_debug)
+				cmn_err(CE_CONT,
+					"\tchange on socket %d (%x)\n", i,
+					value);
+#endif
+			/* find out what happened */
+			status = pcic_getb(pcic, i, PCIC_INTERFACE_STATUS);
+
+			/* acknowledge the interrupt */
+			if (value_cb)
+				pcic_putcb(pcic, CB_STATUS_EVENT, value_cb);
+
+			if (value)
+				pcic_putb(pcic, i, PCIC_CARD_STATUS_CHANGE,
+				    value);
+
+			if (pcic->pc_callback == NULL) {
+				/* if not callback handler, nothing to do */
+				continue;
+			}
+
+			/* Card Detect */
+			if (value & PCIC_CD_DETECT ||
+			    value_cb & CB_PS_CCDMASK) {
+				uint8_t irq;
+#if defined(PCIC_DEBUG)
+				if (pcic_debug)
+					cmn_err(CE_CONT,
+						"\tcd_detect: status=%x,"
+						" flags=%x\n",
+						status, sockp->pcs_flags);
+#else
+#ifdef lint
+				if (status == 0)
+				    status++;
+#endif
+#endif
+				/*
+				 * Turn off all interrupts for this socket here.
+				 */
+				irq = pcic_getb(pcic, sockp->pcs_socket,
+				    PCIC_MANAGEMENT_INT);
+				irq &= ~PCIC_CHANGE_MASK;
+				pcic_putb(pcic, sockp->pcs_socket,
+				    PCIC_MANAGEMENT_INT, irq);
+
+				pcic_putcb(pcic, CB_STATUS_MASK, 0x0);
+
+				if (!sockp->pcs_cd_softint_flg) {
+					sockp->pcs_cd_softint_flg = 1;
+					(void) ddi_intr_trigger_softint(
+					    sockp->pcs_cd_softint_hdl, NULL);
+				}
+
+				io_ints &= ~(1 << i);
+			} /* PCIC_CD_DETECT */
+
+			/* Ready/Change Detect */
+			sockp->pcs_state ^= SBM_RDYBSY;
+			if (card_type == IF_MEMORY && value & PCIC_RD_DETECT) {
+				sockp->pcs_flags |= PCS_READY;
+				PC_CALLBACK(pcic->dip, x, PCE_CARD_READY, i);
+			}
+
+			/* Battery Warn Detect */
+			if (card_type == IF_MEMORY &&
+			    value & PCIC_BW_DETECT &&
+			    !(sockp->pcs_state & SBM_BVD2)) {
+				sockp->pcs_state |= SBM_BVD2;
+				PC_CALLBACK(pcic->dip, x,
+						PCE_CARD_BATTERY_WARN, i);
+			}
+
+			/* Battery Dead Detect */
+			if (value & PCIC_BD_DETECT) {
+				/*
+				 * need to work out event if RI not enabled
+				 * and card_type == IF_IO
+				 */
+				if (card_type == IF_MEMORY &&
+					!(sockp->pcs_state & SBM_BVD1)) {
+					sockp->pcs_state |= SBM_BVD1;
+					PC_CALLBACK(pcic->dip, x,
+							PCE_CARD_BATTERY_DEAD,
+							i);
+				} else {
+					/*
+					 * information in pin replacement
+					 * register if one is available
+					 */
+					PC_CALLBACK(pcic->dip, x,
+							PCE_CARD_STATUS_CHANGE,
+							i);
+				} /* IF_MEMORY */
+			} /* PCIC_BD_DETECT */
+		} /* if pcic_change */
+		/*
+		 * for any controllers that we can detect whether a socket
+		 * had an interrupt for the PC Card, we should sort that out
+		 * here.
+		 */
+	} /* for pc_numsockets */
+
+	/*
+	 * If we're on a PCI bus, we may need to cycle through each IO
+	 *	interrupt handler that is registered since they all
+	 *	share the same interrupt line.
+	 */
+
+
+#if defined(PCIC_DEBUG)
+	pcic_err(pcic->dip, 0xf,
+	    "pcic_intr: pc_intr_mode=%d pc_type=%x io_ints=0x%x\n",
+	    pcic->pc_intr_mode, pcic->pc_type, io_ints);
+#endif
+
+	switch (pcic->pc_intr_mode) {
+	case PCIC_INTR_MODE_PCI_1:
+		value = ~0;
+		/* fix value if adapter can tell us about I/O intrs */
+		switch (pcic->pc_type) {
+
+		case PCIC_TI_PCI1031:
+		case PCIC_TI_PCI1130:
+		case PCIC_TI_PCI1131:
+		case PCIC_TI_PCI1250:
+		case PCIC_TI_PCI1225:
+		case PCIC_TI_PCI1221:
+		case PCIC_TI_PCI1520:
+		case PCIC_TI_PCI1410:
+		case PCIC_TI_VENDOR:
+			i = ddi_get8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_CRDCTL_REG);
+			if (i & PCIC_CRDCTL_IFG)
+				value = 1;
+			else
+				value = 0;
+			i |= PCIC_CRDCTL_IFG;
+			/* clear the condition */
+			ddi_put8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_CRDCTL_REG, i);
+			break;
+		case PCIC_TOSHIBA_TOPIC100:
+		case PCIC_TOSHIBA_TOPIC95:
+		case PCIC_TOSHIBA_VENDOR:
+		case PCIC_RICOH_VENDOR:
+		case PCIC_O2MICRO_VENDOR:
+		default:
+			value = 1;
+			break;
+		}
+		if (value && pcic_do_io_intr(pcic, value) == DDI_INTR_CLAIMED)
+			ret = DDI_INTR_CLAIMED;
+		break;
+	default:
+		break;
+	}
+
+	mutex_exit(&pcic->intr_lock);
+
+#if defined(PCIC_DEBUG)
+	pcic_err(pcic->dip, 0xf,
+	    "pcic_intr: ret=%d value=%d DDI_INTR_CLAIMED=%d\n",
+	    ret, value, DDI_INTR_CLAIMED);
+#endif
+
+	return (ret);
+}
+
+/*
+ * pcic_change()
+ *	check to see if this socket had a change in state
+ *	by checking the status change register
+ */
+static int
+pcic_change(pcicdev_t *pcic, int socket)
+{
+	return (pcic_getb(pcic, socket, PCIC_CARD_STATUS_CHANGE));
+}
+
+/*
+ * pcic_do_io_intr - calls client interrupt handlers
+ */
+static int
+pcic_do_io_intr(pcicdev_t *pcic, uint32_t sockets)
+{
+	inthandler_t *tmp;
+	int ret = DDI_INTR_UNCLAIMED;
+
+#if defined(PCIC_DEBUG)
+	pcic_err(pcic->dip, 0xf,
+		"pcic_do_io_intr: pcic=%p sockets=%d irq_top=%p\n",
+		(void *)pcic, (int)sockets, (void *)pcic->irq_top);
+#endif
+
+	if (pcic->irq_top != NULL) {
+	    tmp = pcic->irq_current;
+
+	    do {
+		int cur = pcic->irq_current->socket;
+		pcic_socket_t *sockp =
+				&pcic->pc_sockets[cur];
+
+#if defined(PCIC_DEBUG)
+		pcic_err(pcic->dip, 0xf,
+		    "\t pcs_flags=0x%x PCS_CARD_PRESENT=0x%x\n",
+		    sockp->pcs_flags, PCS_CARD_PRESENT);
+		pcic_err(pcic->dip, 0xf,
+		    "\t sockets=%d cur=%d intr=%p arg1=%p "
+		    "arg2=%p\n",
+		    sockets, cur, (void *)pcic->irq_current->intr,
+		    pcic->irq_current->arg1,
+		    pcic->irq_current->arg2);
+#endif
+		if (sockp->pcs_flags & PCS_CARD_PRESENT &&
+		    sockets & (1 << cur)) {
+
+			if ((*pcic->irq_current->intr)(pcic->irq_current->arg1,
+			    pcic->irq_current->arg2) == DDI_INTR_CLAIMED)
+				ret = DDI_INTR_CLAIMED;
+
+#if defined(PCIC_DEBUG)
+			pcic_err(pcic->dip, 0xf,
+			    "\t ret=%d DDI_INTR_CLAIMED=%d\n",
+			    ret, DDI_INTR_CLAIMED);
+#endif
+		}
+
+
+		if ((pcic->irq_current = pcic->irq_current->next) == NULL)
+					pcic->irq_current = pcic->irq_top;
+
+	    } while (pcic->irq_current != tmp);
+
+	    if ((pcic->irq_current = pcic->irq_current->next) == NULL)
+					pcic->irq_current = pcic->irq_top;
+
+	} else {
+		ret = DDI_INTR_UNCLAIMED;
+	}
+
+#if defined(PCIC_DEBUG)
+	pcic_err(pcic->dip, 0xf,
+		"pcic_do_io_intr: exit ret=%d DDI_INTR_CLAIMED=%d\n",
+		ret, DDI_INTR_CLAIMED);
+#endif
+
+	return (ret);
+
+}
+
+/*
+ * pcic_inquire_adapter()
+ *	SocketServices InquireAdapter function
+ *	get characteristics of the physical adapter
+ */
+/*ARGSUSED*/
+static int
+pcic_inquire_adapter(dev_info_t *dip, inquire_adapter_t *config)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+
+	config->NumSockets = pcic->pc_numsockets;
+	config->NumWindows = pcic->pc_numsockets * PCIC_NUMWINSOCK;
+	config->NumEDCs = 0;
+	config->AdpCaps = 0;
+	config->ActiveHigh = 0;
+	config->ActiveLow = PCIC_AVAIL_IRQS;
+	config->NumPower = pcic->pc_numpower;
+	config->power_entry = pcic->pc_power; /* until we resolve this */
+#if defined(PCIC_DEBUG)
+	if (pcic_debug) {
+		cmn_err(CE_CONT, "pcic_inquire_adapter:\n");
+		cmn_err(CE_CONT, "\tNumSockets=%d\n", config->NumSockets);
+		cmn_err(CE_CONT, "\tNumWindows=%d\n", config->NumWindows);
+	}
+#endif
+	config->ResourceFlags = 0;
+	switch (pcic->pc_intr_mode) {
+	case PCIC_INTR_MODE_PCI_1:
+		config->ResourceFlags |= RES_OWN_IRQ | RES_IRQ_NEXUS |
+			RES_IRQ_SHAREABLE;
+		break;
+	}
+	return (SUCCESS);
+}
+
+/*
+ * pcic_callback()
+ *	The PCMCIA nexus calls us via this function
+ *	in order to set the callback function we are
+ *	to call the nexus with
+ */
+/*ARGSUSED*/
+static int
+pcic_callback(dev_info_t *dip, int (*handler)(), int arg)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+
+	if (handler != NULL) {
+		pcic->pc_callback = handler;
+		pcic->pc_cb_arg  = arg;
+		pcic->pc_flags |= PCF_CALLBACK;
+	} else {
+		pcic->pc_callback = NULL;
+		pcic->pc_cb_arg = 0;
+		pcic->pc_flags &= ~PCF_CALLBACK;
+	}
+	/*
+	 * we're now registered with the nexus
+	 * it is acceptable to do callbacks at this point.
+	 * don't call back from here though since it could block
+	 */
+	return (PC_SUCCESS);
+}
+
+/*
+ * pcic_calc_speed (pcicdev_t *pcic, uint32_t speed)
+ *	calculate the speed bits from the specified memory speed
+ *	there may be more to do here
+ */
+
+static int
+pcic_calc_speed(pcicdev_t *pcic, uint32_t speed)
+{
+	uint32_t wspeed = 1;	/* assume 1 wait state when unknown */
+	uint32_t bspeed = PCIC_ISA_DEF_SYSCLK;
+
+	switch (pcic->pc_type) {
+	    case PCIC_I82365SL:
+	    case PCIC_VADEM:
+	    case PCIC_VADEM_VG469:
+	    default:
+		/* Intel chip wants it in waitstates */
+		wspeed = mhztons(PCIC_ISA_DEF_SYSCLK) * 3;
+		if (speed <= wspeed)
+			wspeed = 0;
+		else if (speed <= (wspeed += mhztons(bspeed)))
+			wspeed = 1;
+		else if (speed <= (wspeed += mhztons(bspeed)))
+			wspeed = 2;
+		else
+			wspeed = 3;
+		wspeed <<= 6; /* put in right bit positions */
+		break;
+
+	    case PCIC_INTEL_i82092:
+		wspeed = SYSMEM_82092_80NS;
+		if (speed > 80)
+		    wspeed = SYSMEM_82092_100NS;
+		if (speed > 100)
+		    wspeed = SYSMEM_82092_150NS;
+		if (speed > 150)
+		    wspeed = SYSMEM_82092_200NS;
+		if (speed > 200)
+		    wspeed = SYSMEM_82092_250NS;
+		if (speed > 250)
+		    wspeed = SYSMEM_82092_600NS;
+		wspeed <<= 5;	/* put in right bit positions */
+		break;
+
+	} /* switch */
+
+	return (wspeed);
+}
+
+/*
+ * These values are taken from the PC Card Standard Electrical Specification.
+ * Generally the larger value is taken if 2 are possible.
+ */
+static struct pcic_card_times {
+	uint16_t cycle;	/* Speed as found in the atribute space of he card. */
+	uint16_t setup;	/* Corresponding address setup time. */
+	uint16_t width;	/* Corresponding width, OE or WE. */
+	uint16_t hold;	/* Corresponding data or address hold time. */
+} pcic_card_times[] = {
+
+/*
+ * Note: The rounded up times for 250, 200 & 150 have been increased
+ * due to problems with the 3-Com ethernet cards (pcelx) on UBIIi.
+ * See BugID 00663.
+ */
+
+/*
+ * Rounded up times           Original times from
+ * that add up to the         the PCMCIA Spec.
+ * cycle time.
+ */
+	{600, 180, 370, 140},	/* 100, 300,  70 */
+	{400, 120, 300, 90},	/* Made this one up */
+	{250, 100, 190, 70},	/*  30, 150,  30 */
+	{200, 80, 170, 70},	/*  20, 120,  30 */
+	{150, 50, 110, 40},	/*  20,  80,  20 */
+	{100, 40, 80, 40},	/*  10,  60,  15 */
+	{0, 10, 60, 15}		/*  10,  60,  15 */
+};
+
+/*
+ * pcic_set_cdtimers
+ *	This is specific to several Cirrus Logic chips
+ */
+static void
+pcic_set_cdtimers(pcicdev_t *pcic, int socket, uint32_t speed, int tset)
+{
+	int cmd, set, rec, offset, clk_pulse;
+	struct pcic_card_times *ctp;
+
+	if ((tset == IOMEM_CLTIMER_SET_1) || (tset == SYSMEM_CLTIMER_SET_1))
+		offset = 3;
+	else
+		offset = 0;
+
+	clk_pulse = mhztons(pcic->bus_speed);
+	for (ctp = pcic_card_times; speed < ctp->cycle; ctp++);
+
+	/*
+	 * Add (clk_pulse/2) and an extra 1 to account for rounding errors.
+	 */
+	set = ((ctp->setup + 10 + 1 + (clk_pulse/2))/clk_pulse) - 1;
+	if (set < 0)
+		set = 0;
+
+	cmd = ((ctp->width + 10 + 1 + (clk_pulse/2))/clk_pulse) - 1;
+	if (cmd < 0)
+		cmd = 0;
+
+	rec = ((ctp->hold + 10 + 1 + (clk_pulse/2))/clk_pulse) - 2;
+	if (rec < 0)
+		rec = 0;
+
+#if defined(PCIC_DEBUG)
+	pcic_err(pcic->dip, 8, "pcic_set_cdtimers(%d, Timer Set %d)\n"
+	    "ct=%d, cp=%d, cmd=0x%x, setup=0x%x, rec=0x%x\n",
+	    (unsigned)speed, offset == 3 ? 1 : 0,
+	    ctp->cycle, clk_pulse, cmd, set, rec);
+#endif
+
+	pcic_putb(pcic, socket, PCIC_TIME_COMMAND_0 + offset, cmd);
+	pcic_putb(pcic, socket, PCIC_TIME_SETUP_0 + offset, set);
+	pcic_putb(pcic, socket, PCIC_TIME_RECOVER_0 + offset, rec);
+}
+
+/*
+ * pcic_set_window
+ *	essentially the same as the Socket Services specification
+ *	We use socket and not adapter since they are identifiable
+ *	but the rest is the same
+ *
+ *	dip	pcic driver's device information
+ *	window	parameters for the request
+ */
+static int
+pcic_set_window(dev_info_t *dip, set_window_t *window)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+	int select;
+	int socket, pages, which, ret;
+	pcic_socket_t *sockp = &pcic->pc_sockets[window->socket];
+	ra_return_t res;
+	ndi_ra_request_t req;
+	uint32_t base = window->base;
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug) {
+		cmn_err(CE_CONT, "pcic_set_window: entered\n");
+		cmn_err(CE_CONT,
+			"\twindow=%d, socket=%d, WindowSize=%d, speed=%d\n",
+			window->window, window->socket, window->WindowSize,
+			window->speed);
+		cmn_err(CE_CONT,
+			"\tbase=%x, state=%x\n", (unsigned)window->base,
+			(unsigned)window->state);
+	}
+#endif
+
+	/*
+	 * do some basic sanity checking on what we support
+	 * we don't do paged mode
+	 */
+	if (window->state & WS_PAGED) {
+		cmn_err(CE_WARN, "pcic_set_window: BAD_ATTRIBUTE\n");
+		return (BAD_ATTRIBUTE);
+	}
+
+	/*
+	 * we don't care about previous mappings.
+	 * Card Services will deal with that so don't
+	 * even check
+	 */
+
+	socket = window->socket;
+
+	if (!(window->state & WS_IO)) {
+		int win, tmp;
+		pcs_memwin_t *memp;
+#if defined(PCIC_DEBUG)
+		if (pcic_debug)
+			cmn_err(CE_CONT, "\twindow type is memory\n");
+#endif
+		/* this is memory window mapping */
+		win = window->window % PCIC_NUMWINSOCK;
+		tmp = window->window / PCIC_NUMWINSOCK;
+
+		/* only windows 2-6 can do memory mapping */
+		if (tmp != window->socket || win < PCIC_IOWINDOWS) {
+			cmn_err(CE_CONT,
+				"\tattempt to map to non-mem window\n");
+			return (BAD_WINDOW);
+		}
+
+		if (window->WindowSize == 0)
+			window->WindowSize = MEM_MIN;
+		else if ((window->WindowSize & (PCIC_PAGE-1)) != 0) {
+			cmn_err(CE_WARN, "pcic_set_window: BAD_SIZE\n");
+			return (BAD_SIZE);
+		}
+
+		mutex_enter(&pcic->pc_lock); /* protect the registers */
+
+		memp = &sockp->pcs_windows[win].mem;
+		memp->pcw_speed = window->speed;
+
+		win -= PCIC_IOWINDOWS; /* put in right range */
+
+		if (window->WindowSize != memp->pcw_len)
+			which = memp->pcw_len;
+		else
+			which = 0;
+
+		if (window->state & WS_ENABLED) {
+			uint32_t wspeed;
+#if defined(PCIC_DEBUG)
+			if (pcic_debug) {
+				cmn_err(CE_CONT,
+					"\tbase=%x, win=%d\n", (unsigned)base,
+					win);
+				if (which)
+					cmn_err(CE_CONT,
+						"\tneed to remap window\n");
+			}
+#endif
+
+			if (which && (memp->pcw_status & PCW_MAPPED)) {
+				ddi_regs_map_free(&memp->pcw_handle);
+				res.ra_addr_lo = memp->pcw_base;
+				res.ra_len = memp->pcw_len;
+				(void) pcmcia_free_mem(dip, &res);
+				memp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED);
+				memp->pcw_hostmem = NULL;
+				memp->pcw_base = NULL;
+				memp->pcw_len = 0;
+			}
+
+			which = window->WindowSize >> PAGE_SHIFT;
+
+			if (!(memp->pcw_status & PCW_MAPPED)) {
+				ret = 0;
+
+				memp->pcw_base = base;
+				bzero(&req, sizeof (req));
+				req.ra_len = which << PAGE_SHIFT;
+				req.ra_addr = (uint64_t)memp->pcw_base;
+				req.ra_boundbase = pcic->pc_base;
+				req.ra_boundlen  = pcic->pc_bound;
+				req.ra_flags = (memp->pcw_base ?
+					NDI_RA_ALLOC_SPECIFIED : 0) |
+					NDI_RA_ALLOC_BOUNDED;
+				req.ra_align_mask =
+					(PAGESIZE - 1) | (PCIC_PAGE - 1);
+#if defined(PCIC_DEBUG)
+				    pcic_err(dip, 8,
+					    "\tlen 0x%"PRIx64
+					    "addr 0x%"PRIx64"bbase 0x%"PRIx64
+					    " blen 0x%"PRIx64" flags 0x%x"
+					    " algn 0x%"PRIx64"\n",
+					    req.ra_len, req.ra_addr,
+					    req.ra_boundbase,
+					    req.ra_boundlen, req.ra_flags,
+					    req.ra_align_mask);
+#endif
+
+				ret = pcmcia_alloc_mem(dip, &req, &res);
+				if (ret == DDI_FAILURE) {
+					mutex_exit(&pcic->pc_lock);
+					cmn_err(CE_WARN,
+					"\tpcmcia_alloc_mem() failed\n");
+					return (BAD_SIZE);
+				}
+				memp->pcw_base = res.ra_addr_lo;
+				base = memp->pcw_base;
+
+#if defined(PCIC_DEBUG)
+				if (pcic_debug)
+					cmn_err(CE_CONT,
+						"\tsetwindow: new base=%x\n",
+						(unsigned)memp->pcw_base);
+#endif
+				memp->pcw_len = window->WindowSize;
+
+				which = pcmcia_map_reg(pcic->dip,
+						window->child,
+						&res,
+						(uint32_t)(window->state &
+						    0xffff) |
+						    (window->socket << 16),
+						(caddr_t *)&memp->pcw_hostmem,
+						&memp->pcw_handle,
+						&window->attr, NULL);
+
+				if (which != DDI_SUCCESS) {
+
+					cmn_err(CE_WARN, "\tpcmcia_map_reg() "
+						"failed\n");
+
+				    res.ra_addr_lo = memp->pcw_base;
+				    res.ra_len = memp->pcw_len;
+				    (void) pcmcia_free_mem(pcic->dip, &res);
+
+				    mutex_exit(&pcic->pc_lock);
+
+				    return (BAD_WINDOW);
+				}
+				memp->pcw_status |= PCW_MAPPED;
+#if defined(PCIC_DEBUG)
+				if (pcic_debug)
+					cmn_err(CE_CONT,
+						"\tmap=%x, hostmem=%p\n",
+						which,
+						(void *)memp->pcw_hostmem);
+#endif
+			} else {
+				base = memp->pcw_base;
+			}
+
+			/* report the handle back to caller */
+			window->handle = memp->pcw_handle;
+
+#if defined(PCIC_DEBUG)
+			if (pcic_debug) {
+				cmn_err(CE_CONT,
+					"\twindow mapped to %x@%x len=%d\n",
+					(unsigned)window->base,
+					(unsigned)memp->pcw_base,
+					memp->pcw_len);
+			}
+#endif
+
+			/* find the register set offset */
+			select = win * PCIC_MEM_1_OFFSET;
+#if defined(PCIC_DEBUG)
+			if (pcic_debug)
+				cmn_err(CE_CONT, "\tselect=%x\n", select);
+#endif
+
+			/*
+			 * at this point, the register window indicator has
+			 * been converted to be an offset from the first
+			 * set of registers that are used for programming
+			 * the window mapping and the offset used to select
+			 * the correct set of registers to access the
+			 * specified socket.  This allows basing everything
+			 * off the _0 window
+			 */
+
+			/* map the physical page base address */
+			which = (window->state & WS_16BIT) ? SYSMEM_DATA_16 : 0;
+			which |= (window->speed <= MEM_SPEED_MIN) ?
+				SYSMEM_ZERO_WAIT : 0;
+
+			/* need to select register set */
+			select = PCIC_MEM_1_OFFSET * win;
+
+			pcic_putb(pcic, socket,
+					PCIC_SYSMEM_0_STARTLOW + select,
+					SYSMEM_LOW(base));
+			pcic_putb(pcic, socket,
+					PCIC_SYSMEM_0_STARTHI + select,
+					SYSMEM_HIGH(base) | which);
+
+			/*
+			 * Some adapters can decode window addresses greater
+			 * than 16-bits worth, so handle them here.
+			 */
+			switch (pcic->pc_type) {
+			case PCIC_INTEL_i82092:
+				pcic_putb(pcic, socket,
+						PCIC_82092_CPAGE,
+						SYSMEM_EXT(base));
+				break;
+			case PCIC_CL_PD6729:
+			case PCIC_CL_PD6730:
+				clext_reg_write(pcic, socket,
+						PCIC_CLEXT_MMAP0_UA + win,
+						SYSMEM_EXT(base));
+				break;
+			case PCIC_TI_PCI1130:
+				/*
+				 * Note that the TI chip has one upper byte
+				 * per socket so all windows get bound to a
+				 * 16MB segment.  This must be detected and
+				 * handled appropriately.  We can detect that
+				 * it is done by seeing if the pc_base has
+				 * changed and changing when the register
+				 * is first set.  This will force the bounds
+				 * to be correct.
+				 */
+				if (pcic->pc_bound == 0xffffffff) {
+					pcic_putb(pcic, socket,
+						    PCIC_TI_WINDOW_PAGE_PCI,
+						    SYSMEM_EXT(base));
+					pcic->pc_base = SYSMEM_EXT(base) << 24;
+					pcic->pc_bound = 0x1000000;
+				}
+				break;
+			case PCIC_TI_PCI1031:
+			case PCIC_TI_PCI1131:
+			case PCIC_TI_PCI1250:
+			case PCIC_TI_PCI1225:
+			case PCIC_TI_PCI1221:
+			case PCIC_SMC_34C90:
+			case PCIC_CL_PD6832:
+			case PCIC_RICOH_RL5C466:
+			case PCIC_TI_PCI1410:
+			case PCIC_ENE_1410:
+			case PCIC_TI_PCI1510:
+			case PCIC_TI_PCI1520:
+			case PCIC_O2_OZ6912:
+			case PCIC_TI_PCI1420:
+			case PCIC_ENE_1420:
+			case PCIC_TI_VENDOR:
+			case PCIC_TOSHIBA_TOPIC100:
+			case PCIC_TOSHIBA_TOPIC95:
+			case PCIC_TOSHIBA_VENDOR:
+			case PCIC_RICOH_VENDOR:
+			case PCIC_O2MICRO_VENDOR:
+				pcic_putb(pcic, socket,
+						PCIC_YENTA_MEM_PAGE + win,
+						SYSMEM_EXT(base));
+				break;
+			default:
+				cmn_err(CE_NOTE, "pcic_set_window: unknown "
+						"cardbus vendor:0x%X\n",
+						pcic->pc_type);
+				pcic_putb(pcic, socket,
+						PCIC_YENTA_MEM_PAGE + win,
+						SYSMEM_EXT(base));
+
+				break;
+			} /* switch */
+
+			/*
+			 * specify the length of the mapped range
+			 * we convert to pages (rounding up) so that
+			 * the hardware gets the right thing
+			 */
+			pages = (window->WindowSize+PCIC_PAGE-1)/PCIC_PAGE;
+
+			/*
+			 * Setup this window's timing.
+			 */
+			switch (pcic->pc_type) {
+			case PCIC_CL_PD6729:
+			case PCIC_CL_PD6730:
+			case PCIC_CL_PD6710:
+			case PCIC_CL_PD6722:
+				wspeed = SYSMEM_CLTIMER_SET_0;
+				pcic_set_cdtimers(pcic, socket,
+							window->speed,
+							wspeed);
+				break;
+
+			case PCIC_INTEL_i82092:
+			default:
+				wspeed = pcic_calc_speed(pcic, window->speed);
+				break;
+			} /* switch */
+
+#if defined(PCIC_DEBUG)
+			if (pcic_debug)
+				cmn_err(CE_CONT,
+					"\twindow %d speed bits = %x for "
+					"%dns\n",
+					win, (unsigned)wspeed, window->speed);
+#endif
+
+			pcic_putb(pcic, socket, PCIC_SYSMEM_0_STOPLOW + select,
+					SYSMEM_LOW(base +
+						    (pages * PCIC_PAGE)-1));
+
+			wspeed |= SYSMEM_HIGH(base + (pages * PCIC_PAGE)-1);
+			pcic_putb(pcic, socket, PCIC_SYSMEM_0_STOPHI + select,
+					wspeed);
+
+			/*
+			 * now map the card's memory pages - we start with page
+			 * 0
+			 * we also default to AM -- set page might change it
+			 */
+			base = memp->pcw_base;
+			pcic_putb(pcic, socket,
+					PCIC_CARDMEM_0_LOW + select,
+					CARDMEM_LOW(0 - (uint32_t)base));
+
+			pcic_putb(pcic, socket,
+					PCIC_CARDMEM_0_HI + select,
+					CARDMEM_HIGH(0 - (uint32_t)base) |
+					CARDMEM_REG_ACTIVE);
+
+			/*
+			 * enable the window even though redundant
+			 * and SetPage may do it again.
+			 */
+			select = pcic_getb(pcic, socket,
+					PCIC_MAPPING_ENABLE);
+			select |= SYSMEM_WINDOW(win);
+			pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, select);
+			memp->pcw_offset = 0;
+			memp->pcw_status |= PCW_ENABLED;
+		} else {
+			/*
+			 * not only do we unmap the memory, the
+			 * window has been turned off.
+			 */
+			if (which && memp->pcw_status & PCW_MAPPED) {
+				ddi_regs_map_free(&memp->pcw_handle);
+				res.ra_addr_lo = memp->pcw_base;
+				res.ra_len = memp->pcw_len;
+				(void) pcmcia_free_mem(pcic->dip, &res);
+				memp->pcw_hostmem = NULL;
+				memp->pcw_status &= ~PCW_MAPPED;
+			}
+
+			/* disable current mapping */
+			select = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
+			select &= ~SYSMEM_WINDOW(win);
+			pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, select);
+			memp->pcw_status &= ~PCW_ENABLED;
+		}
+		memp->pcw_len = window->WindowSize;
+		window->handle = memp->pcw_handle;
+#if defined(PCIC_DEBUG)
+		if (pcic_debug)
+			xxdmp_all_regs(pcic, window->socket, -1);
+#endif
+	} else {
+		/*
+		 * This is a request for an IO window
+		 */
+		int win, tmp;
+		pcs_iowin_t *winp;
+				/* I/O windows */
+#if defined(PCIC_DEBUG)
+		if (pcic_debug)
+			cmn_err(CE_CONT, "\twindow type is I/O\n");
+#endif
+
+		/* only windows 0 and 1 can do I/O */
+		win = window->window % PCIC_NUMWINSOCK;
+		tmp = window->window / PCIC_NUMWINSOCK;
+
+		if (win >= PCIC_IOWINDOWS || tmp != window->socket) {
+			cmn_err(CE_WARN,
+				"\twindow is out of range (%d)\n",
+				window->window);
+			return (BAD_WINDOW);
+		}
+
+		mutex_enter(&pcic->pc_lock); /* protect the registers */
+
+		winp = &sockp->pcs_windows[win].io;
+		winp->pcw_speed = window->speed;
+		if (window->WindowSize != 1 && window->WindowSize & 1) {
+			/* we don't want an odd-size window */
+			window->WindowSize++;
+		}
+		winp->pcw_len = window->WindowSize;
+
+		if (window->state & WS_ENABLED) {
+			if (winp->pcw_status & PCW_MAPPED) {
+				ddi_regs_map_free(&winp->pcw_handle);
+				res.ra_addr_lo = winp->pcw_base;
+				res.ra_len = winp->pcw_len;
+				(void) pcmcia_free_io(pcic->dip, &res);
+				winp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED);
+			}
+
+			/*
+			 * if the I/O address wasn't allocated, allocate
+			 *	it now. If it was allocated, it better
+			 *	be free to use.
+			 * The winp->pcw_offset value is set and used
+			 *	later on if the particular adapter
+			 *	that we're running on has the ability
+			 *	to translate IO accesses to the card
+			 *	(such as some adapters  in the Cirrus
+			 *	Logic family).
+			 */
+			winp->pcw_offset = 0;
+
+			/*
+			 * Setup the request parameters for the
+			 *	requested base and length. If
+			 *	we're on an adapter that has
+			 *	IO window offset registers, then
+			 *	we don't need a specific base
+			 *	address, just a length, and then
+			 *	we'll cause the correct IO address
+			 *	to be generated on the socket by
+			 *	setting up the IO window offset
+			 *	registers.
+			 * For adapters that support this capability, we
+			 *	always use the IO window offset registers,
+			 *	even if the passed base/length would be in
+			 *	range.
+			 */
+			base = window->base;
+			bzero(&req, sizeof (req));
+			req.ra_len = window->WindowSize;
+
+			req.ra_addr = (uint64_t)
+				((pcic->pc_flags & PCF_IO_REMAP) ? 0 : base);
+			req.ra_flags = (req.ra_addr) ?
+						NDI_RA_ALLOC_SPECIFIED : 0;
+
+			req.ra_flags |= NDI_RA_ALIGN_SIZE;
+			/* need to rethink this */
+			req.ra_boundbase = pcic->pc_iobase;
+			req.ra_boundlen = pcic->pc_iobound;
+			req.ra_flags |= NDI_RA_ALLOC_BOUNDED;
+
+#if defined(PCIC_DEBUG)
+			    pcic_err(dip, 8,
+					"\tlen 0x%"PRIx64" addr 0x%"PRIx64
+					"bbase 0x%"PRIx64
+					"blen 0x%"PRIx64" flags 0x%x algn 0x%"
+					PRIx64"\n",
+					req.ra_len, (uint64_t)req.ra_addr,
+					req.ra_boundbase,
+					req.ra_boundlen, req.ra_flags,
+					req.ra_align_mask);
+#endif
+
+			/*
+			 * Try to allocate the space. If we fail this,
+			 *	return the appropriate error depending
+			 *	on whether the caller specified a
+			 *	specific base address or not.
+			 */
+			if (pcmcia_alloc_io(dip, &req, &res) == DDI_FAILURE) {
+				winp->pcw_status &= ~PCW_ENABLED;
+				mutex_exit(&pcic->pc_lock);
+				cmn_err(CE_WARN, "Failed to alloc I/O:\n"
+					"\tlen 0x%" PRIx64 " addr 0x%" PRIx64
+					"bbase 0x%" PRIx64
+					"blen 0x%" PRIx64 "flags 0x%x"
+					"algn 0x%" PRIx64 "\n",
+					req.ra_len, req.ra_addr,
+					req.ra_boundbase,
+					req.ra_boundlen, req.ra_flags,
+					req.ra_align_mask);
+
+				return (base?BAD_BASE:BAD_SIZE);
+			} /* pcmcia_alloc_io */
+
+			/*
+			 * Don't change the original base. Either we use
+			 * the offset registers below (PCF_IO_REMAP is set)
+			 * or it was allocated correctly anyway.
+			 */
+			winp->pcw_base = res.ra_addr_lo;
+
+#if defined(PCIC_DEBUG)
+			    pcic_err(dip, 8,
+				    "\tsetwindow: new base=%x orig base 0x%x\n",
+				    (unsigned)winp->pcw_base, base);
+#endif
+
+			if ((which = pcmcia_map_reg(pcic->dip,
+						window->child,
+						&res,
+						(uint32_t)(window->state &
+						    0xffff) |
+						    (window->socket << 16),
+						(caddr_t *)&winp->pcw_hostmem,
+						&winp->pcw_handle,
+						&window->attr,
+						base)) != DDI_SUCCESS) {
+
+					cmn_err(CE_WARN, "pcmcia_map_reg()"
+						"failed\n");
+
+				    res.ra_addr_lo = winp->pcw_base;
+				    res.ra_len = winp->pcw_len;
+				    (void) pcmcia_free_io(pcic->dip, &res);
+
+				    mutex_exit(&pcic->pc_lock);
+				    return (BAD_WINDOW);
+			}
+
+			window->handle = winp->pcw_handle;
+			winp->pcw_status |= PCW_MAPPED;
+
+			/* find the register set offset */
+			select = win * PCIC_IO_OFFSET;
+
+#if defined(PCIC_DEBUG)
+			if (pcic_debug) {
+				cmn_err(CE_CONT,
+					"\tenable: window=%d, select=%x, "
+					"base=%x, handle=%p\n",
+					win, select,
+					(unsigned)window->base,
+					(void *)window->handle);
+			}
+#endif
+			/*
+			 * at this point, the register window indicator has
+			 * been converted to be an offset from the first
+			 * set of registers that are used for programming
+			 * the window mapping and the offset used to select
+			 * the correct set of registers to access the
+			 * specified socket.  This allows basing everything
+			 * off the _0 window
+			 */
+
+			/* map the I/O base in */
+			pcic_putb(pcic, socket,
+					PCIC_IO_ADDR_0_STARTLOW + select,
+					LOW_BYTE((uint32_t)winp->pcw_base));
+			pcic_putb(pcic, socket,
+					PCIC_IO_ADDR_0_STARTHI + select,
+					HIGH_BYTE((uint32_t)winp->pcw_base));
+
+			pcic_putb(pcic, socket,
+					PCIC_IO_ADDR_0_STOPLOW + select,
+					LOW_BYTE((uint32_t)winp->pcw_base +
+						window->WindowSize - 1));
+			pcic_putb(pcic, socket,
+					PCIC_IO_ADDR_0_STOPHI + select,
+					HIGH_BYTE((uint32_t)winp->pcw_base +
+						window->WindowSize - 1));
+
+			/*
+			 * We've got the requested IO space, now see if we
+			 *	need to adjust the IO window offset registers
+			 *	so that the correct IO address is generated
+			 *	at the socket. If this window doesn't have
+			 *	this capability, then we're all done setting
+			 *	up the IO resources.
+			 */
+			if (pcic->pc_flags & PCF_IO_REMAP) {
+
+
+				/*
+				 * Note that only 16 bits are used to program
+				 * the registers but leave 32 bits on pcw_offset
+				 * so that we can generate the original base
+				 * in get_window()
+				 */
+				winp->pcw_offset = (base - winp->pcw_base);
+
+				pcic_putb(pcic, socket,
+					PCIC_IO_OFFSET_LOW +
+					(win * PCIC_IO_OFFSET_OFFSET),
+					winp->pcw_offset & 0x0ff);
+				pcic_putb(pcic, socket,
+					PCIC_IO_OFFSET_HI +
+					(win * PCIC_IO_OFFSET_OFFSET),
+					(winp->pcw_offset >> 8) & 0x0ff);
+
+			} /* PCF_IO_REMAP */
+
+			/* now get the other details (size, etc) right */
+
+			/*
+			 * Set the data size control bits here. Most of the
+			 *	adapters will ignore IOMEM_16BIT when
+			 *	IOMEM_IOCS16 is set, except for the Intel
+			 *	82092, which only pays attention to the
+			 *	IOMEM_16BIT bit. Sigh... Intel can't even
+			 *	make a proper clone of their own chip.
+			 * The 82092 also apparently can't set the timing
+			 *	of I/O windows.
+			 */
+			which = (window->state & WS_16BIT) ?
+					(IOMEM_16BIT | IOMEM_IOCS16) : 0;
+
+			switch (pcic->pc_type) {
+			case PCIC_CL_PD6729:
+			case PCIC_CL_PD6730:
+			case PCIC_CL_PD6710:
+			case PCIC_CL_PD6722:
+			case PCIC_CL_PD6832:
+				/*
+				 * Select Timer Set 1 - this will take
+				 *	effect when the PCIC_IO_CONTROL
+				 *	register is written to later on;
+				 *	the call to pcic_set_cdtimers
+				 *	just sets up the timer itself.
+				 */
+				which |= IOMEM_CLTIMER_SET_1;
+				pcic_set_cdtimers(pcic, socket,
+							window->speed,
+							IOMEM_CLTIMER_SET_1);
+				which |= IOMEM_IOCS16;
+				break;
+			case PCIC_TI_PCI1031:
+
+				if (window->state & WS_16BIT)
+				    which |= IOMEM_WAIT16;
+
+				break;
+			case PCIC_TI_PCI1130:
+
+				if (window->state & WS_16BIT)
+				    which |= IOMEM_WAIT16;
+
+				break;
+			case PCIC_INTEL_i82092:
+				break;
+			default:
+				if (window->speed >
+						mhztons(pcic->bus_speed) * 3)
+				    which |= IOMEM_WAIT16;
+#ifdef notdef
+				if (window->speed <
+						mhztons(pcic->bus_speed) * 6)
+				    which |= IOMEM_ZERO_WAIT;
+#endif
+				break;
+			} /* switch (pc_type) */
+
+			/*
+			 * Setup the data width and timing
+			 */
+			select = pcic_getb(pcic, socket, PCIC_IO_CONTROL);
+			select &= ~(PCIC_IO_WIN_MASK << (win * 4));
+			select |= IOMEM_SETWIN(win, which);
+			pcic_putb(pcic, socket, PCIC_IO_CONTROL, select);
+
+			/*
+			 * Enable the IO window
+			 */
+			select = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
+			pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE,
+						select | IOMEM_WINDOW(win));
+
+			winp->pcw_status |= PCW_ENABLED;
+
+#if defined(PCIC_DEBUG)
+			if (pcic_debug) {
+				cmn_err(CE_CONT,
+					"\twhich = %x, select = %x (%x)\n",
+					which, select,
+					IOMEM_SETWIN(win, which));
+				xxdmp_all_regs(pcic, window->socket * 0x40, 24);
+			}
+#endif
+		} else {
+			/*
+			 * not only do we unmap the IO space, the
+			 * window has been turned off.
+			 */
+			if (winp->pcw_status & PCW_MAPPED) {
+				ddi_regs_map_free(&winp->pcw_handle);
+				res.ra_addr_lo = winp->pcw_base;
+				res.ra_len = winp->pcw_len;
+				(void) pcmcia_free_io(pcic->dip, &res);
+				winp->pcw_status &= ~PCW_MAPPED;
+			}
+
+			/* disable current mapping */
+			select = pcic_getb(pcic, socket,
+						PCIC_MAPPING_ENABLE);
+			pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE,
+					select &= ~IOMEM_WINDOW(win));
+			winp->pcw_status &= ~PCW_ENABLED;
+
+			winp->pcw_base = 0;
+			winp->pcw_len = 0;
+			winp->pcw_offset = 0;
+			window->base = 0;
+			/* now make sure we don't accidentally re-enable */
+			/* find the register set offset */
+			select = win * PCIC_IO_OFFSET;
+			pcic_putb(pcic, socket,
+					PCIC_IO_ADDR_0_STARTLOW + select, 0);
+			pcic_putb(pcic, socket,
+					PCIC_IO_ADDR_0_STARTHI + select, 0);
+			pcic_putb(pcic, socket,
+					PCIC_IO_ADDR_0_STOPLOW + select, 0);
+			pcic_putb(pcic, socket,
+					PCIC_IO_ADDR_0_STOPHI + select, 0);
+		}
+	}
+	mutex_exit(&pcic->pc_lock);
+
+	return (SUCCESS);
+}
+
+/*
+ * pcic_card_state()
+ *	compute the instantaneous Card State information
+ */
+static int
+pcic_card_state(pcicdev_t *pcic, pcic_socket_t *sockp)
+{
+	int value, result;
+#if defined(PCIC_DEBUG)
+	int orig_value;
+#endif
+
+	mutex_enter(&pcic->pc_lock); /* protect the registers */
+
+	value = pcic_getb(pcic, sockp->pcs_socket, PCIC_INTERFACE_STATUS);
+
+#if defined(PCIC_DEBUG)
+	orig_value = value;
+	if (pcic_debug >= 8)
+		cmn_err(CE_CONT, "pcic_card_state(%p) if status = %b for %d\n",
+			(void *)sockp,
+			value,
+			"\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI",
+			sockp->pcs_socket);
+#endif
+	/*
+	 * Lie to socket services if we are not ready.
+	 * This is when we are starting up or during debounce timeouts
+	 * or if the card is a cardbus card.
+	 */
+	if (!(sockp->pcs_flags & (PCS_STARTING|PCS_CARD_ISCARDBUS)) &&
+	    !sockp->pcs_debounce_id &&
+	    (value & PCIC_ISTAT_CD_MASK) == PCIC_CD_PRESENT_OK) {
+		result = SBM_CD;
+
+		if (value & PCIC_WRITE_PROTECT || !(value & PCIC_POWER_ON))
+			result |= SBM_WP;
+		if (value & PCIC_POWER_ON) {
+			if (value & PCIC_READY)
+				result |= SBM_RDYBSY;
+			value = (~value) & (PCIC_BVD1 | PCIC_BVD2);
+			if (value & PCIC_BVD1)
+				result |= SBM_BVD1;
+			if (value & PCIC_BVD2)
+				result |= SBM_BVD2;
+		}
+	} else
+		result = 0;
+
+	mutex_exit(&pcic->pc_lock);
+
+#if defined(PCIC_DEBUG)
+	pcic_err(pcic->dip, 8,
+	    "pcic_card_state(%p) if status = %b for %d (rval=0x%x)\n",
+	    (void *) sockp, orig_value,
+	    "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI",
+	    sockp->pcs_socket, result);
+#endif
+
+	return (result);
+}
+
+/*
+ * pcic_set_page()
+ *	SocketServices SetPage function
+ *	set the page of PC Card memory that should be in the mapped
+ *	window
+ */
+/*ARGSUSED*/
+static int
+pcic_set_page(dev_info_t *dip, set_page_t *page)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+	int select;
+	int which, socket, window;
+	uint32_t base;
+	pcs_memwin_t *memp;
+
+	/* get real socket/window numbers */
+	window = page->window % PCIC_NUMWINSOCK;
+	socket = page->window / PCIC_NUMWINSOCK;
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug) {
+		cmn_err(CE_CONT,
+			"pcic_set_page: window=%d, socket=%d, page=%d\n",
+			window, socket, page->page);
+	}
+#endif
+	/* only windows 2-6 work on memory */
+	if (window < PCIC_IOWINDOWS)
+		return (BAD_WINDOW);
+
+	/* only one page supported (but any size) */
+	if (page->page != 0)
+		return (BAD_PAGE);
+
+	mutex_enter(&pcic->pc_lock); /* protect the registers */
+
+	memp = &pcic->pc_sockets[socket].pcs_windows[window].mem;
+	window -= PCIC_IOWINDOWS;
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug)
+		cmn_err(CE_CONT, "\tpcw_base=%x, pcw_hostmem=%p, pcw_len=%x\n",
+			(uint32_t)memp->pcw_base,
+			(void *)memp->pcw_hostmem, memp->pcw_len);
+#endif
+
+	/* window must be enabled */
+	if (!(memp->pcw_status & PCW_ENABLED))
+		return (BAD_ATTRIBUTE);
+
+	/* find the register set offset */
+	select = window * PCIC_MEM_1_OFFSET;
+#if defined(PCIC_DEBUG)
+	if (pcic_debug)
+		cmn_err(CE_CONT, "\tselect=%x\n", select);
+#endif
+
+	/*
+	 * now map the card's memory pages - we start with page 0
+	 */
+
+	which = 0;		/* assume simple case */
+	if (page->state & PS_ATTRIBUTE) {
+		which |= CARDMEM_REG_ACTIVE;
+		memp->pcw_status |= PCW_ATTRIBUTE;
+	} else {
+		memp->pcw_status &= ~PCW_ATTRIBUTE;
+	}
+
+	/*
+	 * if caller says Write Protect, enforce it.
+	 */
+	if (page->state & PS_WP) {
+		which |= CARDMEM_WRITE_PROTECT;
+		memp->pcw_status |= PCW_WP;
+	} else {
+		memp->pcw_status &= ~PCW_WP;
+	}
+#if defined(PCIC_DEBUG)
+	if (pcic_debug) {
+		cmn_err(CE_CONT, "\tmemory type = %s\n",
+			(which & CARDMEM_REG_ACTIVE) ? "attribute" : "common");
+		if (which & CARDMEM_WRITE_PROTECT)
+			cmn_err(CE_CONT, "\twrite protect\n");
+		cmn_err(CE_CONT, "\tpage offset=%x pcw_base=%x (%x)\n",
+			(unsigned)page->offset,
+			(unsigned)memp->pcw_base,
+			(int)page->offset - (int)memp->pcw_base & 0xffffff);
+	}
+#endif
+	/* address computation based on 64MB range and not larger */
+	base = (uint32_t)memp->pcw_base & 0x3ffffff;
+	pcic_putb(pcic, socket, PCIC_CARDMEM_0_LOW + select,
+	    CARDMEM_LOW((int)page->offset - (int)base));
+	(void) pcic_getb(pcic, socket, PCIC_CARDMEM_0_LOW + select);
+	pcic_putb(pcic, socket, PCIC_CARDMEM_0_HI + select,
+	    CARDMEM_HIGH((int)page->offset - base) | which);
+	(void) pcic_getb(pcic, socket, PCIC_CARDMEM_0_HI + select);
+
+	/*
+	 * while not really necessary, this just makes sure
+	 * nothing turned the window off behind our backs
+	 */
+	which = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
+	which |= SYSMEM_WINDOW(window);
+	pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, which);
+	(void) pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
+
+	memp->pcw_offset = (off_t)page->offset;
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug) {
+		cmn_err(CE_CONT, "\tbase=%p, *base=%x\n",
+			(void *)memp->pcw_hostmem,
+			(uint32_t)*memp->pcw_hostmem);
+
+		xxdmp_all_regs(pcic, socket, -1);
+
+		cmn_err(CE_CONT, "\tbase=%p, *base=%x\n",
+			(void *)memp->pcw_hostmem,
+			(uint32_t)*memp->pcw_hostmem);
+	}
+#endif
+
+	if (which & PCW_ATTRIBUTE)
+		pcic_mswait(pcic, socket, 2);
+
+	mutex_exit(&pcic->pc_lock);
+
+	return (SUCCESS);
+}
+
+/*
+ * pcic_set_vcc_level()
+ *
+ *	set voltage based on adapter information
+ *
+ *	this routine implements a limited solution for support of 3.3v cards.
+ *	the general solution, which would fully support the pcmcia spec
+ *	as far as allowing client drivers to request which voltage levels
+ *	to be set, requires more framework support and driver changes - ess
+ */
+static int
+pcic_set_vcc_level(pcicdev_t *pcic, set_socket_t *socket)
+{
+	uint32_t socket_present_state;
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug) {
+		cmn_err(CE_CONT,
+			"pcic_set_vcc_level(pcic=%p, VccLevel=%d)\n",
+			(void *)pcic, socket->VccLevel);
+	}
+#endif
+
+	/*
+	 * check VccLevel
+	 * if this is zero, power is being turned off
+	 * if it is non-zero, power is being turned on.
+	 */
+	if (socket->VccLevel == 0) {
+		return (0);
+	}
+
+	/*
+	 * range checking for sanity's sake
+	 */
+	if (socket->VccLevel >= pcic->pc_numpower) {
+		return (BAD_VCC);
+	}
+
+	switch (pcic->pc_io_type) {
+	/*
+	 * Yenta-compliant adapters have vcc info in the extended registers
+	 * Other adapters can be added as needed, but the 'default' case
+	 * has been left as it was previously so as not to break existing
+	 * adapters.
+	 */
+	case PCIC_IO_TYPE_YENTA:
+		/*
+		 * Here we ignore the VccLevel passed in and read the
+		 * card type from the adapter socket present state register
+		 */
+		socket_present_state =
+			ddi_get32(pcic->handle, (uint32_t *)(pcic->ioaddr +
+				PCIC_PRESENT_STATE_REG));
+#if defined(PCIC_DEBUG)
+		if (pcic_debug) {
+			cmn_err(CE_CONT,
+				"socket present state = 0x%x\n",
+				socket_present_state);
+		}
+#endif
+		switch (socket_present_state & PCIC_VCC_MASK) {
+			case PCIC_VCC_3VCARD:
+				/* fall through */
+			case PCIC_VCC_3VCARD|PCIC_VCC_5VCARD:
+				socket->VccLevel = PCIC_VCC_3VLEVEL;
+				return
+				    (POWER_3VCARD_ENABLE|POWER_OUTPUT_ENABLE);
+			case PCIC_VCC_5VCARD:
+				socket->VccLevel = PCIC_VCC_5VLEVEL;
+				return
+				    (POWER_CARD_ENABLE|POWER_OUTPUT_ENABLE);
+			default:
+				/*
+				 * if no card is present, this can be the
+				 * case of a client making a SetSocket call
+				 * after card removal. In this case we return
+				 * the current power level
+				 */
+				return ((unsigned)ddi_get8(pcic->handle,
+				    pcic->ioaddr + CB_R2_OFFSET +
+					PCIC_POWER_CONTROL));
+		}
+
+	default:
+
+		switch (socket->VccLevel) {
+		case PCIC_VCC_3VLEVEL:
+			return (BAD_VCC);
+		case PCIC_VCC_5VLEVEL:
+			/* enable Vcc */
+			return (POWER_CARD_ENABLE|POWER_OUTPUT_ENABLE);
+		default:
+			return (BAD_VCC);
+		}
+	}
+}
+
+
+/*
+ * pcic_set_socket()
+ *	Socket Services SetSocket call
+ *	sets basic socket configuration
+ */
+static int
+pcic_set_socket(dev_info_t *dip, set_socket_t *socket)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+	pcic_socket_t *sockp = &pcic->pc_sockets[socket->socket];
+	int irq, interrupt, mirq;
+	int powerlevel = 0;
+	int ind, value, orig_pwrctl;
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug) {
+		cmn_err(CE_CONT,
+		    "pcic_set_socket(dip=%p, socket=%d)"
+		    " Vcc=%d Vpp1=%d Vpp2=%d\n", (void *)dip,
+		    socket->socket, socket->VccLevel, socket->Vpp1Level,
+		    socket->Vpp2Level);
+	}
+#endif
+	/*
+	 * check VccLevel, etc. before setting mutex
+	 * if this is zero, power is being turned off
+	 * if it is non-zero, power is being turned on.
+	 * the default case is to assume Vcc only.
+	 */
+
+	/* this appears to be very implementation specific */
+
+	if (socket->Vpp1Level != socket->Vpp2Level)
+		return (BAD_VPP);
+
+	if (socket->VccLevel == 0 || !(sockp->pcs_flags & PCS_CARD_PRESENT)) {
+		powerlevel = 0;
+		sockp->pcs_vcc = 0;
+		sockp->pcs_vpp1 = 0;
+		sockp->pcs_vpp2 = 0;
+	} else {
+#if defined(PCIC_DEBUG)
+		pcic_err(dip, 9, "\tVcc=%d Vpp1Level=%d, Vpp2Level=%d\n",
+		    socket->VccLevel, socket->Vpp1Level, socket->Vpp2Level);
+#endif
+		/* valid Vcc power level? */
+		if (socket->VccLevel >= pcic->pc_numpower)
+			return (BAD_VCC);
+
+		switch (pcic_power[socket->VccLevel].PowerLevel) {
+		case 33:	/* 3.3V */
+		case 60:	/* for bad CIS in Option GPRS card */
+			if (!(pcic->pc_flags & PCF_33VCAP)) {
+				cmn_err(CE_WARN,
+				    "%s%d: Bad Request for 3.3V "
+				    "(Controller incapable)\n",
+				    ddi_get_name(pcic->dip),
+				    ddi_get_instance(pcic->dip));
+				return (BAD_VCC);
+			}
+			/* FALLTHROUGH */
+		case 50:	/* 5V */
+			if ((pcic->pc_io_type == PCIC_IO_TYPE_YENTA) &&
+			    pcic_getcb(pcic, CB_PRESENT_STATE) &
+			    CB_PS_33VCARD) {
+				/*
+				 * This is actually a 3.3V card.
+				 * Solaris Card Services
+				 * doesn't understand 3.3V
+				 * so we cheat and change
+				 * the setting to the one appropriate to 3.3V.
+				 * Note that this is the entry number
+				 * in the pcic_power[] array.
+				 */
+				sockp->pcs_vcc = PCIC_VCC_3VLEVEL;
+			} else
+				sockp->pcs_vcc = socket->VccLevel;
+			break;
+		default:
+			return (BAD_VCC);
+		}
+
+		/* enable Vcc */
+		powerlevel = POWER_CARD_ENABLE;
+
+#if defined(PCIC_DEBUG)
+		if (pcic_debug) {
+			cmn_err(CE_CONT, "\tVcc=%d powerlevel=%x\n",
+			    socket->VccLevel, powerlevel);
+		}
+#endif
+		ind = 0;		/* default index to 0 power */
+		if ((int)socket->Vpp1Level >= 0 &&
+		    socket->Vpp1Level < pcic->pc_numpower) {
+			if (!(pcic_power[socket->Vpp1Level].ValidSignals
+			    & VPP1)) {
+				return (BAD_VPP);
+			}
+			ind = pcic_power[socket->Vpp1Level].PowerLevel/10;
+			powerlevel |= pcic_vpp_levels[ind];
+			sockp->pcs_vpp1 = socket->Vpp1Level;
+		}
+		if ((int)socket->Vpp2Level >= 0 &&
+		    socket->Vpp2Level < pcic->pc_numpower) {
+			if (!(pcic_power[socket->Vpp2Level].ValidSignals
+			    & VPP2)) {
+				return (BAD_VPP);
+			}
+			ind = pcic_power[socket->Vpp2Level].PowerLevel/10;
+			powerlevel |= (pcic_vpp_levels[ind] << 2);
+			sockp->pcs_vpp2 = socket->Vpp2Level;
+		}
+
+		if (pcic->pc_flags & PCF_VPPX) {
+			/*
+			 * this adapter doesn't allow separate Vpp1/Vpp2
+			 * if one is turned on, both are turned on and only
+			 * the Vpp1 bits should be set
+			 */
+			if (sockp->pcs_vpp2 != sockp->pcs_vpp1) {
+				/* must be the same if one not zero */
+				if (sockp->pcs_vpp1 != 0 &&
+				    sockp->pcs_vpp2 != 0) {
+					cmn_err(CE_WARN,
+					    "%s%d: Bad Power Request "
+					    "(Vpp1/2 not the same)\n",
+					    ddi_get_name(pcic->dip),
+					    ddi_get_instance(pcic->dip));
+					return (BAD_VPP);
+				}
+			}
+			powerlevel &= ~(3<<2);
+		}
+
+#if defined(PCIC_DEBUG)
+		if (pcic_debug) {
+			cmn_err(CE_CONT, "\tpowerlevel=%x, ind=%x\n",
+			    powerlevel, ind);
+		}
+#endif
+	}
+	mutex_enter(&pcic->pc_lock); /* protect the registers */
+
+	/* turn socket->IREQRouting off while programming */
+	interrupt = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT);
+	interrupt &= ~PCIC_INTR_MASK;
+	if (pcic->pc_flags & PCF_USE_SMI)
+		interrupt |= PCIC_INTR_ENABLE;
+	pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, interrupt);
+
+	switch (pcic->pc_type) {
+	    case PCIC_INTEL_i82092:
+		pcic_82092_smiirq_ctl(pcic, socket->socket, PCIC_82092_CTL_IRQ,
+						PCIC_82092_INT_DISABLE);
+		break;
+	    default:
+		break;
+	} /* switch */
+
+	/* the SCIntMask specifies events to detect */
+	mirq = pcic_getb(pcic, socket->socket, PCIC_MANAGEMENT_INT);
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug)
+		cmn_err(CE_CONT,
+			"\tSCIntMask=%x, interrupt=%x, mirq=%x\n",
+			socket->SCIntMask, interrupt, mirq);
+#endif
+	mirq &= ~(PCIC_BD_DETECT|PCIC_BW_DETECT|PCIC_RD_DETECT);
+	pcic_putb(pcic, socket->socket, PCIC_MANAGEMENT_INT,
+	    mirq & ~PCIC_CHANGE_MASK);
+
+	/* save the mask we want to use */
+	sockp->pcs_intmask = socket->SCIntMask;
+
+	/*
+	 * Until there is a card present it's not worth enabling
+	 * any interrupts except "Card detect". This is done
+	 * elsewhere in the driver so don't change things if
+	 * there is no card!
+	 */
+	if (sockp->pcs_flags & PCS_CARD_PRESENT) {
+
+		/* now update the hardware to reflect events desired */
+		if (sockp->pcs_intmask & SBM_BVD1 || socket->IFType == IF_IO)
+			mirq |= PCIC_BD_DETECT;
+
+		if (sockp->pcs_intmask & SBM_BVD2)
+			mirq |= PCIC_BW_DETECT;
+
+		if (sockp->pcs_intmask & SBM_RDYBSY)
+			mirq |= PCIC_RD_DETECT;
+
+		if (sockp->pcs_intmask & SBM_CD)
+			mirq |= PCIC_CD_DETECT;
+	}
+
+	if (sockp->pcs_flags & PCS_READY) {
+		/*
+		 * card just came ready.
+		 * make sure enough time elapses
+		 * before touching it.
+		 */
+		sockp->pcs_flags &= ~PCS_READY;
+		pcic_mswait(pcic, socket->socket, 10);
+	}
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug) {
+		cmn_err(CE_CONT, "\tstatus change set to %x\n", mirq);
+	}
+#endif
+
+	switch (pcic->pc_type) {
+	    case PCIC_I82365SL:
+	    case PCIC_VADEM:
+	    case PCIC_VADEM_VG469:
+		/*
+		 * The Intel version has different options. This is a
+		 * special case of GPI which might be used for eject
+		 */
+
+		irq = pcic_getb(pcic, socket->socket, PCIC_CARD_DETECT);
+		if (sockp->pcs_intmask & (SBM_EJECT|SBM_INSERT) &&
+		    pcic->pc_flags & PCF_GPI_EJECT) {
+			irq |= PCIC_GPI_ENABLE;
+		} else {
+			irq &= ~PCIC_GPI_ENABLE;
+		}
+		pcic_putb(pcic, socket->socket, PCIC_CARD_DETECT, irq);
+		break;
+	    case PCIC_CL_PD6710:
+	    case PCIC_CL_PD6722:
+		if (socket->IFType == IF_IO) {
+			pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_2, 0x0);
+			value = pcic_getb(pcic, socket->socket,
+						PCIC_MISC_CTL_1);
+			if (pcic->pc_flags & PCF_AUDIO)
+				value |= PCIC_MC_SPEAKER_ENB;
+			pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1,
+					value);
+		} else {
+			value = pcic_getb(pcic, socket->socket,
+						PCIC_MISC_CTL_1);
+			value &= ~PCIC_MC_SPEAKER_ENB;
+			pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1,
+					value);
+		}
+		break;
+	    case PCIC_CL_PD6729:
+	    case PCIC_CL_PD6730:
+	    case PCIC_CL_PD6832:
+		value = pcic_getb(pcic, socket->socket, PCIC_MISC_CTL_1);
+		if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) {
+		    value |= PCIC_MC_SPEAKER_ENB;
+		} else {
+		    value &= ~PCIC_MC_SPEAKER_ENB;
+		}
+
+		if (pcic_power[sockp->pcs_vcc].PowerLevel == 33)
+			value |= PCIC_MC_3VCC;
+		else
+			value &= ~PCIC_MC_3VCC;
+
+		pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1, value);
+		break;
+
+	    case PCIC_O2_OZ6912:
+		value = pcic_getcb(pcic, CB_MISCCTRL);
+		if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO))
+			value |= (1<<25);
+		else
+			value &= ~(1<<25);
+		pcic_putcb(pcic, CB_MISCCTRL, value);
+		if (pcic_power[sockp->pcs_vcc].PowerLevel == 33)
+			powerlevel |= 0x08;
+		break;
+
+	    case PCIC_TI_PCI1250:
+	    case PCIC_TI_PCI1221:
+	    case PCIC_TI_PCI1225:
+	    case PCIC_TI_PCI1410:
+	    case PCIC_ENE_1410:
+	    case PCIC_TI_PCI1510:
+	    case PCIC_TI_PCI1520:
+	    case PCIC_TI_PCI1420:
+	    case PCIC_ENE_1420:
+		value = ddi_get8(pcic->cfg_handle,
+		    pcic->cfgaddr + PCIC_CRDCTL_REG);
+		if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) {
+			value |= PCIC_CRDCTL_SPKR_ENBL;
+		} else {
+			value &= ~PCIC_CRDCTL_SPKR_ENBL;
+		}
+		ddi_put8(pcic->cfg_handle,
+		    pcic->cfgaddr + PCIC_CRDCTL_REG, value);
+		if (pcic_power[sockp->pcs_vcc].PowerLevel == 33)
+			powerlevel |= 0x08;
+		break;
+	}
+
+	/*
+	 * ctlind processing -- we can ignore this
+	 * there aren't any outputs on the chip for this and
+	 * the GUI will display what it thinks is correct
+	 */
+
+	/*
+	 * If outputs are enabled and the power is going off
+	 * turn off outputs first.
+	 */
+
+	/* power setup -- if necessary */
+	orig_pwrctl = pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL);
+	if ((orig_pwrctl & POWER_OUTPUT_ENABLE) && sockp->pcs_vcc == 0) {
+		orig_pwrctl &= ~POWER_OUTPUT_ENABLE;
+		pcic_putb(pcic, socket->socket,
+		    PCIC_POWER_CONTROL, orig_pwrctl);
+		(void) pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL);
+	}
+
+	if (pcic->pc_flags & PCF_CBPWRCTL) {
+		value = pcic_cbus_powerctl(pcic, socket->socket);
+		powerlevel = 0;
+	} else
+		value = pcic_exca_powerctl(pcic, socket->socket, powerlevel);
+
+	if (value != SUCCESS) {
+		mutex_exit(&pcic->pc_lock);
+		return (value);
+	}
+
+	/*
+	 * If outputs were disabled and the power is going on
+	 * turn on outputs afterwards.
+	 */
+	if (!(orig_pwrctl & POWER_OUTPUT_ENABLE) && sockp->pcs_vcc != 0) {
+		orig_pwrctl = pcic_getb(pcic, socket->socket,
+		    PCIC_POWER_CONTROL);
+		orig_pwrctl |= POWER_OUTPUT_ENABLE;
+		pcic_putb(pcic, socket->socket,
+		    PCIC_POWER_CONTROL, orig_pwrctl);
+		(void) pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL);
+	}
+
+	/*
+	 * Once we have done the power stuff can re-enable management
+	 * interrupts.
+	 */
+	pcic_putb(pcic, socket->socket, PCIC_MANAGEMENT_INT, mirq);
+
+#if defined(PCIC_DEBUG)
+	pcic_err(dip, 8, "\tmanagement int set to %x pwrctl to 0x%x "
+	    "cbctl 0x%x\n",
+	    mirq, pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL),
+	    pcic_getcb(pcic, CB_CONTROL));
+#endif
+
+	/* irq processing */
+	if (socket->IFType == IF_IO) {
+		/* IRQ only for I/O */
+		irq = socket->IREQRouting & PCIC_INTR_MASK;
+		value = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT);
+		value &= ~PCIC_INTR_MASK;
+
+		/* to enable I/O operation */
+		value |= PCIC_IO_CARD | PCIC_RESET;
+		sockp->pcs_flags |= PCS_CARD_IO;
+		if (irq != sockp->pcs_irq) {
+			if (sockp->pcs_irq != 0)
+				cmn_err(CE_CONT,
+					"SetSocket: IRQ mismatch %x != %x!\n",
+					irq, sockp->pcs_irq);
+			else
+				sockp->pcs_irq = irq;
+		}
+		irq = sockp->pcs_irq;
+
+		pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, value);
+		if (socket->IREQRouting & IRQ_ENABLE) {
+			pcic_enable_io_intr(pcic, socket->socket, irq);
+			sockp->pcs_flags |= PCS_IRQ_ENABLED;
+		} else {
+			pcic_disable_io_intr(pcic, socket->socket);
+			sockp->pcs_flags &= ~PCS_IRQ_ENABLED;
+		}
+#if defined(PCIC_DEBUG)
+		if (pcic_debug) {
+			cmn_err(CE_CONT,
+				"\tsocket type is I/O and irq %x is %s\n", irq,
+				(socket->IREQRouting & IRQ_ENABLE) ?
+				"enabled" : "not enabled");
+			xxdmp_all_regs(pcic, socket->socket, 20);
+		}
+#endif
+	} else {
+		/* make sure I/O mode is off */
+
+		sockp->pcs_irq = 0;
+
+		value = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT);
+		value &= ~PCIC_IO_CARD;
+		pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, value);
+		pcic_disable_io_intr(pcic, socket->socket);
+		sockp->pcs_flags &= ~(PCS_CARD_IO|PCS_IRQ_ENABLED);
+	}
+
+	sockp->pcs_state &= ~socket->State;
+
+	mutex_exit(&pcic->pc_lock);
+	return (SUCCESS);
+}
+
+/*
+ * pcic_inquire_socket()
+ *	SocketServices InquireSocket function
+ *	returns basic characteristics of the socket
+ */
+/*ARGSUSED*/
+static int
+pcic_inquire_socket(dev_info_t *dip, inquire_socket_t *socket)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+	int value;
+
+	socket->SCIntCaps = PCIC_DEFAULT_INT_CAPS;
+	socket->SCRptCaps = PCIC_DEFAULT_RPT_CAPS;
+	socket->CtlIndCaps = PCIC_DEFAULT_CTL_CAPS;
+	value = pcic->pc_sockets[socket->socket].pcs_flags;
+	socket->SocketCaps = (value & PCS_SOCKET_IO) ? IF_IO : IF_MEMORY;
+	socket->ActiveHigh = 0;
+	/* these are the usable IRQs */
+	socket->ActiveLow = 0xfff0;
+	return (SUCCESS);
+}
+
+/*
+ * pcic_inquire_window()
+ *	SocketServices InquireWindow function
+ *	returns detailed characteristics of the window
+ *	this is where windows get tied to sockets
+ */
+/*ARGSUSED*/
+static int
+pcic_inquire_window(dev_info_t *dip, inquire_window_t *window)
+{
+	int type, socket;
+
+	type = window->window % PCIC_NUMWINSOCK;
+	socket = window->window / PCIC_NUMWINSOCK;
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug >= 8)
+		cmn_err(CE_CONT,
+			"pcic_inquire_window: window = %d/%d socket=%d\n",
+			window->window, type, socket);
+#endif
+	if (type < PCIC_IOWINDOWS) {
+		window->WndCaps = WC_IO|WC_WAIT;
+		type = IF_IO;
+	} else {
+		window->WndCaps = WC_COMMON|WC_ATTRIBUTE|WC_WAIT;
+		type = IF_MEMORY;
+	}
+
+	/* initialize the socket map - one socket per window */
+	PR_ZERO(window->Sockets);
+	PR_SET(window->Sockets, socket);
+
+	if (type == IF_IO) {
+		iowin_char_t *io;
+		io = &window->iowin_char;
+		io->IOWndCaps = WC_BASE|WC_SIZE|WC_WENABLE|WC_8BIT|
+			WC_16BIT;
+		io->FirstByte = (baseaddr_t)IOMEM_FIRST;
+		io->LastByte = (baseaddr_t)IOMEM_LAST;
+		io->MinSize = IOMEM_MIN;
+		io->MaxSize = IOMEM_MAX;
+		io->ReqGran = IOMEM_GRAN;
+		io->AddrLines = IOMEM_DECODE;
+		io->EISASlot = 0;
+	} else {
+		mem_win_char_t *mem;
+		mem = &window->mem_win_char;
+		mem->MemWndCaps = WC_BASE|WC_SIZE|WC_WENABLE|WC_8BIT|
+			WC_16BIT|WC_WP;
+
+		mem->FirstByte = (baseaddr_t)MEM_FIRST;
+		mem->LastByte = (baseaddr_t)MEM_LAST;
+
+		mem->MinSize = MEM_MIN;
+		mem->MaxSize = MEM_MAX;
+		mem->ReqGran = PCIC_PAGE;
+		mem->ReqBase = 0;
+		mem->ReqOffset = PCIC_PAGE;
+		mem->Slowest = MEM_SPEED_MAX;
+		mem->Fastest = MEM_SPEED_MIN;
+	}
+	return (SUCCESS);
+}
+
+/*
+ * pcic_get_adapter()
+ *	SocketServices GetAdapter function
+ *	this is nearly a no-op.
+ */
+/*ARGSUSED*/
+static int
+pcic_get_adapter(dev_info_t *dip, get_adapter_t *adapt)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+
+	if (pcic->pc_flags & PCF_INTRENAB)
+		adapt->SCRouting = IRQ_ENABLE;
+	adapt->state = 0;
+	return (SUCCESS);
+}
+
+/*
+ * pcic_get_page()
+ *	SocketServices GetPage function
+ *	returns info about the window
+ */
+/*ARGSUSED*/
+static int
+pcic_get_page(dev_info_t *dip, get_page_t *page)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+	int socket, window;
+	pcs_memwin_t *winp;
+
+	socket = page->window / PCIC_NUMWINSOCK;
+	window = page->window % PCIC_NUMWINSOCK;
+
+	/* I/O windows are the first two */
+	if (window < PCIC_IOWINDOWS || socket >= pcic->pc_numsockets) {
+		return (BAD_WINDOW);
+	}
+
+	winp = &pcic->pc_sockets[socket].pcs_windows[window].mem;
+
+	if (page->page != 0)
+		return (BAD_PAGE);
+
+	page->state = 0;
+	if (winp->pcw_status & PCW_ENABLED)
+		page->state |= PS_ENABLED;
+	if (winp->pcw_status & PCW_ATTRIBUTE)
+		page->state |= PS_ATTRIBUTE;
+	if (winp->pcw_status & PCW_WP)
+		page->state |= PS_WP;
+
+	page->offset = (off_t)winp->pcw_offset;
+
+	return (SUCCESS);
+}
+
+/*
+ * pcic_get_socket()
+ *	SocketServices GetSocket
+ *	returns information about the current socket setting
+ */
+/*ARGSUSED*/
+static int
+pcic_get_socket(dev_info_t *dip, get_socket_t *socket)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+	int socknum, irq_enabled;
+	pcic_socket_t *sockp;
+
+	socknum = socket->socket;
+	sockp = &pcic->pc_sockets[socknum];
+
+	socket->SCIntMask = sockp->pcs_intmask;
+	sockp->pcs_state = pcic_card_state(pcic, sockp);
+
+	socket->state = sockp->pcs_state;
+	if (socket->state & SBM_CD) {
+		socket->VccLevel = sockp->pcs_vcc;
+		socket->Vpp1Level = sockp->pcs_vpp1;
+		socket->Vpp2Level = sockp->pcs_vpp2;
+		irq_enabled = (sockp->pcs_flags & PCS_IRQ_ENABLED) ?
+		    IRQ_ENABLE : 0;
+		socket->IRQRouting = sockp->pcs_irq | irq_enabled;
+		socket->IFType = (sockp->pcs_flags & PCS_CARD_IO) ?
+		    IF_IO : IF_MEMORY;
+	} else {
+		socket->VccLevel = 0;
+		socket->Vpp1Level = 0;
+		socket->Vpp2Level = 0;
+		socket->IRQRouting = 0;
+		socket->IFType = IF_MEMORY;
+	}
+	socket->CtlInd = 0;	/* no indicators */
+
+	return (SUCCESS);
+}
+
+/*
+ * pcic_get_status()
+ *	SocketServices GetStatus
+ *	returns status information about the PC Card in
+ *	the selected socket
+ */
+/*ARGSUSED*/
+static int
+pcic_get_status(dev_info_t *dip, get_ss_status_t *status)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+	int socknum, irq_enabled;
+	pcic_socket_t *sockp;
+
+	socknum = status->socket;
+	sockp = &pcic->pc_sockets[socknum];
+
+	status->CardState = pcic_card_state(pcic, sockp);
+	status->SocketState = sockp->pcs_state;
+	status->CtlInd = 0;	/* no indicators */
+
+	if (sockp->pcs_flags & PCS_CARD_PRESENT)
+		status->SocketState |= SBM_CD;
+	if (status->CardState & SBM_CD) {
+		irq_enabled = (sockp->pcs_flags & PCS_CARD_ENABLED) ?
+		    IRQ_ENABLE : 0;
+		status->IRQRouting = sockp->pcs_irq | irq_enabled;
+		status->IFType = (sockp->pcs_flags & PCS_CARD_IO) ?
+		    IF_IO : IF_MEMORY;
+	} else {
+		status->IRQRouting = 0;
+		status->IFType = IF_MEMORY;
+	}
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug >= 8)
+		cmn_err(CE_CONT, "pcic_get_status: socket=%d, CardState=%x,"
+			"SocketState=%x\n",
+			socknum, status->CardState, status->SocketState);
+#endif
+	switch (pcic->pc_type) {
+	uint32_t present_state;
+	case PCIC_TI_PCI1410:
+	case PCIC_TI_PCI1520:
+	case PCIC_TI_PCI1420:
+	case PCIC_ENE_1420:
+	case PCIC_TOSHIBA_TOPIC100:
+	case PCIC_TOSHIBA_TOPIC95:
+	case PCIC_TOSHIBA_VENDOR:
+	case PCIC_O2MICRO_VENDOR:
+	case PCIC_TI_VENDOR:
+	case PCIC_RICOH_VENDOR:
+		present_state = pcic_getcb(pcic, CB_PRESENT_STATE);
+		if (present_state & PCIC_CB_CARD)
+			status->IFType = IF_CARDBUS;
+#if defined(PCIC_DEBUG)
+		if (pcic_debug >= 8)
+		    cmn_err(CE_CONT, "pcic_get_status: present_state=0x%x\n",
+			present_state);
+#endif
+		break;
+	default:
+		break;
+	}
+
+	return (SUCCESS);
+}
+
+/*
+ * pcic_get_window()
+ *	SocketServices GetWindow function
+ *	returns state information about the specified window
+ */
+/*ARGSUSED*/
+static int
+pcic_get_window(dev_info_t *dip, get_window_t *window)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+	int socket, win;
+	pcic_socket_t *sockp;
+	pcs_memwin_t *winp;
+
+	socket = window->window / PCIC_NUMWINSOCK;
+	win = window->window % PCIC_NUMWINSOCK;
+#if defined(PCIC_DEBUG)
+	if (pcic_debug) {
+		cmn_err(CE_CONT, "pcic_get_window(socket=%d, window=%d)\n",
+			socket, win);
+	}
+#endif
+
+	if (socket > pcic->pc_numsockets)
+		return (BAD_WINDOW);
+
+	sockp = &pcic->pc_sockets[socket];
+	winp = &sockp->pcs_windows[win].mem;
+
+	window->socket = socket;
+	window->size = winp->pcw_len;
+	window->speed = winp->pcw_speed;
+	window->handle = (ddi_acc_handle_t)winp->pcw_handle;
+	window->base = (uint32_t)winp->pcw_base + winp->pcw_offset;
+
+	if (win >= PCIC_IOWINDOWS) {
+		window->state = 0;
+	} else {
+		window->state = WS_IO;
+	}
+	if (winp->pcw_status & PCW_ENABLED)
+		window->state |= WS_ENABLED;
+
+	if (winp->pcw_status & PCS_CARD_16BIT)
+		window->state |= WS_16BIT;
+#if defined(PCIC_DEBUG)
+	if (pcic_debug)
+		cmn_err(CE_CONT, "\tsize=%d, speed=%d, base=%p, state=%x\n",
+			window->size, (unsigned)window->speed,
+			(void *)window->handle, window->state);
+#endif
+
+	return (SUCCESS);
+}
+
+/*
+ * pcic_ll_reset
+ *	low level reset
+ *	separated out so it can be called when already locked
+ *
+ *	There are two variables that control the RESET timing:
+ *		pcic_prereset_time - time in mS before asserting RESET
+ *		pcic_reset_time - time in mS to assert RESET
+ *
+ */
+int pcic_prereset_time = 1;
+int pcic_reset_time = 10;
+int pcic_postreset_time = 20;
+int pcic_vpp_is_vcc_during_reset = 0;
+
+static int
+pcic_ll_reset(pcicdev_t *pcic, int socket)
+{
+	int windowbits, iobits;
+	uint32_t pwr;
+
+	/* save windows that were on */
+	windowbits = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
+	if (pcic_reset_time == 0)
+	    return (windowbits);
+	/* turn all windows off */
+	pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, 0);
+
+#if defined(PCIC_DEBUG)
+	pcic_err(pcic->dip, 6,
+		"pcic_ll_reset(socket %d) powerlevel=%x cbctl 0x%x cbps 0x%x\n",
+		socket, pcic_getb(pcic, socket, PCIC_POWER_CONTROL),
+		pcic_getcb(pcic, CB_CONTROL),
+		pcic_getcb(pcic, CB_PRESENT_STATE));
+#endif
+
+	if (pcic_vpp_is_vcc_during_reset) {
+
+	/*
+	 * Set VPP to VCC for the duration of the reset - for aironet
+	 * card.
+	 */
+	    if (pcic->pc_flags & PCF_CBPWRCTL) {
+		pwr = pcic_getcb(pcic, CB_CONTROL);
+		pcic_putcb(pcic, CB_CONTROL, (pwr&~CB_C_VPPMASK)|CB_C_VPPVCC);
+		(void) pcic_getcb(pcic, CB_CONTROL);
+	    } else {
+		pwr = pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
+		pcic_putb(pcic, socket, PCIC_POWER_CONTROL,
+		    pwr | 1);
+		(void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
+	    }
+	}
+
+	if (pcic_prereset_time > 0) {
+		pcic_err(pcic->dip, 8, "pcic_ll_reset pre_wait %d mS\n",
+		    pcic_prereset_time);
+		pcic_mswait(pcic, socket, pcic_prereset_time);
+	}
+
+	/* turn interrupts off and start a reset */
+	pcic_err(pcic->dip, 8,
+		"pcic_ll_reset turn interrupts off and start a reset\n");
+	iobits = pcic_getb(pcic, socket, PCIC_INTERRUPT);
+	iobits &= ~(PCIC_INTR_MASK | PCIC_RESET);
+	pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits);
+	(void) pcic_getb(pcic, socket, PCIC_INTERRUPT);
+
+	switch (pcic->pc_type) {
+	    case PCIC_INTEL_i82092:
+		pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ,
+						PCIC_82092_INT_DISABLE);
+		break;
+	    default:
+		break;
+	} /* switch */
+
+	pcic->pc_sockets[socket].pcs_state = 0;
+
+	if (pcic_reset_time > 0) {
+		pcic_err(pcic->dip, 8, "pcic_ll_reset reset_wait %d mS\n",
+		    pcic_reset_time);
+		pcic_mswait(pcic, socket, pcic_reset_time);
+	}
+
+	pcic_err(pcic->dip, 8, "pcic_ll_reset take it out of reset now\n");
+
+	/* take it out of RESET now */
+	pcic_putb(pcic, socket, PCIC_INTERRUPT, PCIC_RESET | iobits);
+	(void) pcic_getb(pcic, socket, PCIC_INTERRUPT);
+
+	/*
+	 * can't access the card for 20ms, but we really don't
+	 * want to sit around that long. The pcic is still usable.
+	 * memory accesses must wait for RDY to come up.
+	 */
+	if (pcic_postreset_time > 0) {
+		pcic_err(pcic->dip, 8, "pcic_ll_reset post_wait %d mS\n",
+		    pcic_postreset_time);
+		pcic_mswait(pcic, socket, pcic_postreset_time);
+	}
+
+	if (pcic_vpp_is_vcc_during_reset > 1) {
+
+	/*
+	 * Return VPP power to whatever it was before.
+	 */
+	    if (pcic->pc_flags & PCF_CBPWRCTL) {
+		pcic_putcb(pcic, CB_CONTROL, pwr);
+		(void) pcic_getcb(pcic, CB_CONTROL);
+	    } else {
+		pcic_putb(pcic, socket, PCIC_POWER_CONTROL, pwr);
+		(void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
+	    }
+	}
+
+	pcic_err(pcic->dip, 7, "pcic_ll_reset returning 0x%x\n", windowbits);
+
+	return (windowbits);
+}
+
+/*
+ * pcic_reset_socket()
+ *	SocketServices ResetSocket function
+ *	puts the PC Card in the socket into the RESET state
+ *	and then takes it out after the the cycle time
+ *	The socket is back to initial state when done
+ */
+static int
+pcic_reset_socket(dev_info_t *dip, int socket, int mode)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+	int value;
+	int i, mint;
+	pcic_socket_t *sockp;
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug >= 8)
+		cmn_err(CE_CONT, "pcic_reset_socket(%p, %d, %d/%s)\n",
+		    (void *)dip, socket, mode,
+			mode == RESET_MODE_FULL ? "full" : "partial");
+#endif
+
+	mutex_enter(&pcic->pc_lock); /* protect the registers */
+
+	/* Turn off management interupts. */
+	mint = pcic_getb(pcic, socket, PCIC_MANAGEMENT_INT);
+	pcic_putb(pcic, socket, PCIC_MANAGEMENT_INT, mint & ~PCIC_CHANGE_MASK);
+
+	sockp = &pcic->pc_sockets[socket];
+
+	value = pcic_ll_reset(pcic, socket);
+	if (mode == RESET_MODE_FULL) {
+		/* disable and unmap all mapped windows */
+		for (i = 0; i < PCIC_NUMWINSOCK; i++) {
+			if (i < PCIC_IOWINDOWS) {
+				if (sockp->pcs_windows[i].io.pcw_status &
+				    PCW_MAPPED) {
+					pcs_iowin_t *io;
+					io = &sockp->pcs_windows[i].io;
+					io->pcw_status &= ~PCW_ENABLED;
+				}
+			} else {
+				if (sockp->pcs_windows[i].mem.pcw_status &
+				    PCW_MAPPED) {
+					pcs_memwin_t *mem;
+					mem = &sockp->pcs_windows[i].mem;
+					mem->pcw_status &= ~PCW_ENABLED;
+				}
+			}
+		}
+	} else {
+				/* turn windows back on */
+		pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, value);
+		/* wait the rest of the time here */
+		pcic_mswait(pcic, socket, 10);
+	}
+	pcic_putb(pcic, socket, PCIC_MANAGEMENT_INT, mint);
+	mutex_exit(&pcic->pc_lock);
+	return (SUCCESS);
+}
+
+/*
+ * pcic_set_interrupt()
+ *	SocketServices SetInterrupt function
+ */
+static int
+pcic_set_interrupt(dev_info_t *dip, set_irq_handler_t *handler)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+	int value = DDI_SUCCESS;
+	inthandler_t *intr;
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug) {
+		cmn_err(CE_CONT,
+			"pcic_set_interrupt: entered pc_intr_mode=0x%x\n",
+			pcic->pc_intr_mode);
+		cmn_err(CE_CONT,
+			"\t irq_top=%p handler=%p handler_id=%x\n",
+			(void *)pcic->irq_top, (void *)handler->handler,
+			handler->handler_id);
+	}
+#endif
+
+	/*
+	 * If we're on a PCI bus, we route all IO IRQs through a single
+	 *	PCI interrupt (typically INT A#) so we don't have to do
+	 *	much other than add the caller to general interrupt handler
+	 *	and set some state.
+	 */
+
+	intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP);
+	if (intr == NULL)
+		return (NO_RESOURCE);
+
+	switch (pcic->pc_intr_mode) {
+	case PCIC_INTR_MODE_PCI_1:
+		/*
+		 * We only allow above-lock-level IO IRQ handlers
+		 *	in the PCI bus case.
+		 */
+
+		mutex_enter(&pcic->intr_lock);
+
+		if (pcic->irq_top == NULL) {
+		    pcic->irq_top = intr;
+		    pcic->irq_current = pcic->irq_top;
+		} else {
+		    while (pcic->irq_current->next != NULL)
+			pcic->irq_current = pcic->irq_current->next;
+		    pcic->irq_current->next = intr;
+		    pcic->irq_current = pcic->irq_current->next;
+		}
+
+		pcic->irq_current->intr =
+		    (ddi_intr_handler_t *)handler->handler;
+		pcic->irq_current->handler_id = handler->handler_id;
+		pcic->irq_current->arg1 = handler->arg1;
+		pcic->irq_current->arg2 = handler->arg2;
+		pcic->irq_current->socket = handler->socket;
+
+		mutex_exit(&pcic->intr_lock);
+
+		handler->iblk_cookie = &pcic->pc_pri;
+		handler->idev_cookie = &pcic->pc_dcookie;
+		break;
+
+	default:
+		intr->intr = (ddi_intr_handler_t *)handler->handler;
+		intr->handler_id = handler->handler_id;
+		intr->arg1 = handler->arg1;
+		intr->arg2 = handler->arg2;
+		intr->socket = handler->socket;
+		intr->irq = handler->irq;
+
+		/*
+		 * need to revisit this to see if interrupts can be
+		 * shared someday. Note that IRQ is set in the common
+		 * code.
+		 */
+		mutex_enter(&pcic->pc_lock);
+		if (pcic->pc_handlers == NULL) {
+			pcic->pc_handlers = intr;
+			intr->next = intr->prev = intr;
+		} else {
+			insque(intr, pcic->pc_handlers);
+		}
+		mutex_exit(&pcic->pc_lock);
+
+		break;
+	}
+
+	/*
+	 * need to fill in cookies in event of multiple high priority
+	 * interrupt handlers on same IRQ
+	 */
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug) {
+		cmn_err(CE_CONT,
+			"pcic_set_interrupt: exit irq_top=%p value=%d\n",
+			(void *)pcic->irq_top, value);
+	}
+#endif
+
+	if (value == DDI_SUCCESS) {
+		return (SUCCESS);
+	} else {
+		return (BAD_IRQ);
+	}
+}
+
+/*
+ * pcic_clear_interrupt()
+ *	SocketServices ClearInterrupt function
+ *
+ *	Interrupts for PCIC are complicated by the fact that we must
+ *	follow several different models for interrupts.
+ *	ISA: there is an interrupt per adapter and per socket and
+ *		they can't be shared.
+ *	PCI: some adapters have one PCI interrupt available while others
+ *		have up to 4.  Solaris may or may not allow us to use more
+ *		than 1 so we essentially share them all at this point.
+ *	Hybrid: PCI bridge but interrupts wired to host interrupt controller.
+ *		This is like ISA but we have to fudge and create an intrspec
+ *		that PCI's parent understands and bypass the PCI nexus.
+ *	multifunction: this requires sharing the interrupts on a per-socket
+ *		basis.
+ */
+static int
+pcic_clear_interrupt(dev_info_t *dip, clear_irq_handler_t *handler)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+	inthandler_t *intr, *prev, *current;
+	int i;
+
+	/*
+	 * If we're on a PCI bus, we route all IO IRQs through a single
+	 *	PCI interrupt (typically INT A#) so we don't have to do
+	 *	much other than remove the caller from the general
+	 *	interrupt handler callout list.
+	 */
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug) {
+		cmn_err(CE_CONT,
+			"pcic_clear_interrupt: entered pc_intr_mode=0x%x\n",
+			pcic->pc_intr_mode);
+		cmn_err(CE_CONT,
+			"\t irq_top=%p handler=%p handler_id=%x\n",
+			(void *)pcic->irq_top, (void *)handler->handler,
+			handler->handler_id);
+	}
+#endif
+
+	switch (pcic->pc_intr_mode) {
+	case PCIC_INTR_MODE_PCI_1:
+
+		mutex_enter(&pcic->intr_lock);
+		if (pcic->irq_top == NULL) {
+			mutex_exit(&pcic->intr_lock);
+			return (BAD_IRQ);
+		}
+
+		intr = NULL;
+		pcic->irq_current = pcic->irq_top;
+
+		while ((pcic->irq_current != NULL) &&
+				(pcic->irq_current->handler_id !=
+						handler->handler_id)) {
+			intr = pcic->irq_current;
+			pcic->irq_current = pcic->irq_current->next;
+		}
+
+		if (pcic->irq_current == NULL) {
+			mutex_exit(&pcic->intr_lock);
+			return (BAD_IRQ);
+		}
+
+		if (intr != NULL) {
+			intr->next = pcic->irq_current->next;
+		} else {
+			pcic->irq_top = pcic->irq_current->next;
+		}
+
+		current = pcic->irq_current;
+		pcic->irq_current = pcic->irq_top;
+		mutex_exit(&pcic->intr_lock);
+		kmem_free(current, sizeof (inthandler_t));
+
+		break;
+
+	default:
+
+		mutex_enter(&pcic->pc_lock);
+		intr = pcic_handlers;
+		prev = (inthandler_t *)&pcic_handlers;
+
+		while (intr != NULL) {
+		    if (intr->handler_id == handler->handler_id) {
+			i = intr->irq & PCIC_INTR_MASK;
+			if (--pcic_irq_map[i].count == 0) {
+				/* multi-handler form */
+				(void) ddi_intr_disable(pcic->pc_intr_htblp[i]);
+				(void) ddi_intr_remove_handler(
+				    pcic->pc_intr_htblp[i]);
+				(void) ddi_intr_free(pcic->pc_intr_htblp[i]);
+				(void) pcmcia_return_intr(pcic->dip, i);
+#if defined(PCIC_DEBUG)
+				if (pcic_debug) {
+					cmn_err(CE_CONT,
+						"removing interrupt %d at %s "
+						"priority\n", i, "high");
+					cmn_err(CE_CONT,
+						"ddi_remove_intr(%p, %x, %p)\n",
+						(void *)dip,
+						0,
+						(void *)intr->iblk_cookie);
+				}
+#endif
+			}
+			prev->next = intr->next;
+			kmem_free(intr, sizeof (inthandler_t));
+			intr = prev->next;
+		    } else {
+			prev = intr;
+			intr = intr->next;
+		    } /* if (handler_id) */
+		} /* while */
+
+		mutex_exit(&pcic->pc_lock);
+	}
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug) {
+		cmn_err(CE_CONT,
+		"pcic_clear_interrupt: exit irq_top=%p\n",
+		(void *)pcic->irq_top);
+	}
+#endif
+
+
+	return (SUCCESS);
+}
+
+struct intel_regs {
+	char *name;
+	int   off;
+	char *fmt;
+} iregs[] = {
+	{"ident     ", 0},
+	{"if-status ", 1, "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI"},
+	{"power     ", 2, "\020\1Vpp1c0\2Vpp1c1\3Vpp2c0\4Vpp2c1\5PE\6AUTO"
+		"\7DRD\10OE"},
+	{"cardstatus", 4, "\020\1BD\2BW\3RC\4CD\5GPI\6R1\7R2\010R3"},
+	{"enable    ", 6, "\020\1MW0\2MW1\3MW2\4MW3\5MW4\6MEM16\7IO0\10IO1"},
+	{"cd-gcr    ", 0x16, "\020\1MDI16\2CRE\3GPIE\4GPIT\5CDR\6S/W"},
+	{"GCR       ", 0x1e, "\020\1PD\2LEVEL\3WCSC\4PLS14"},
+	{"int-gcr   ", 3, "\020\5INTR\6IO\7~RST\10RI"},
+	{"management", 5, "\020\1BDE\2BWE\3RE\4CDE"},
+	{"volt-sense", 0x1f, "\020\1A_VS1\2A_VS2\3B_VS1\4B_VS2"},
+	{"volt-sel  ", 0x2f, "\020\5EXTCONF\6BUSSELECT\7MIXEDV\10ISAV"},
+	{"VG ext A  ", 0x3c, "\20\3IVS\4CABLE\5CSTEP\6TEST\7RIO"},
+	{"io-ctrl   ", 7, "\020\1DS0\2IOCS0\3ZWS0\4WS0\5DS1\6IOS1\7ZWS1\10WS1"},
+	{"io0-slow  ", 8},
+	{"io0-shi   ", 9},
+	{"io0-elow  ", 0xa},
+	{"io0-ehi   ", 0xb},
+	{"io1-slow  ", 0xc},
+	{"io1-shi   ", 0xd},
+	{"io1-elow  ", 0xe},
+	{"io1-ehi   ", 0xf},
+	{"mem0-slow ", 0x10},
+	{"mem0-shi  ", 0x11, "\020\7ZW\10DS"},
+	{"mem0-elow ", 0x12},
+	{"mem0-ehi  ", 0x13, "\020\7WS0\10WS1"},
+	{"card0-low ", 0x14},
+	{"card0-hi  ", 0x15, "\020\7AM\10WP"},
+	{"mem1-slow ", 0x18},
+	{"mem1-shi  ", 0x19, "\020\7ZW\10DS"},
+	{"mem1-elow ", 0x1a},
+	{"mem1-ehi  ", 0x1b, "\020\7WS0\10WS1"},
+	{"card1-low ", 0x1c},
+	{"card1-hi  ", 0x1d, "\020\7AM\10WP"},
+	{"mem2-slow ", 0x20},
+	{"mem2-shi  ", 0x21, "\020\7ZW\10DS"},
+	{"mem2-elow ", 0x22},
+	{"mem2-ehi  ", 0x23, "\020\7WS0\10WS1"},
+	{"card2-low ", 0x24},
+	{"card2-hi  ", 0x25, "\020\7AM\10WP"},
+	{"mem3-slow ", 0x28},
+	{"mem3-shi  ", 0x29, "\020\7ZW\10DS"},
+	{"mem3-elow ", 0x2a},
+	{"mem3-ehi  ", 0x2b, "\020\7WS0\10WS1"},
+	{"card3-low ", 0x2c},
+	{"card3-hi  ", 0x2d, "\020\7AM\10WP"},
+
+	{"mem4-slow ", 0x30},
+	{"mem4-shi  ", 0x31, "\020\7ZW\10DS"},
+	{"mem4-elow ", 0x32},
+	{"mem4-ehi  ", 0x33, "\020\7WS0\10WS1"},
+	{"card4-low ", 0x34},
+	{"card4-hi  ", 0x35, "\020\7AM\10WP"},
+	{"mpage0    ", 0x40},
+	{"mpage1    ", 0x41},
+	{"mpage2    ", 0x42},
+	{"mpage3    ", 0x43},
+	{"mpage4    ", 0x44},
+	{NULL},
+};
+
+static struct intel_regs cregs[] = {
+	{"misc-ctl1 ", 0x16, "\20\2VCC3\3PMI\4PSI\5SPKR\10INPACK"},
+	{"fifo      ", 0x17, "\20\6DIOP\7DMEMP\10EMPTY"},
+	{"misc-ctl2 ", 0x1e, "\20\1XCLK\2LOW\3SUSP\4CORE5V\5TCD\10RIOUT"},
+	{"chip-info ", 0x1f, "\20\6DUAL"},
+	{"IO-offlow0", 0x36},
+	{"IO-offhi0 ", 0x37},
+	{"IO-offlow1", 0x38},
+	{"IO-offhi1 ", 0x39},
+	NULL,
+};
+
+static struct intel_regs cxregs[] = {
+	{"ext-ctl-1 ", 0x03,
+		"\20\1VCCLCK\2AUTOCLR\3LED\4INVIRQC\5INVIRQM\6PUC"},
+	{"misc-ctl3 ", 0x25, "\20\5HWSUSP"},
+	{"mem0-up   ", 0x05},
+	{"mem1-up   ", 0x06},
+	{"mem2-up   ", 0x07},
+	{"mem3-up   ", 0x08},
+	{"mem4-up   ", 0x09},
+	{NULL}
+};
+
+void
+xxdmp_cl_regs(pcicdev_t *pcic, int socket, uint32_t len)
+{
+	int i, value, j;
+	char buff[256];
+	char *fmt;
+
+	cmn_err(CE_CONT, "--------- Cirrus Logic Registers --------\n");
+	for (buff[0] = '\0', i = 0; cregs[i].name != NULL && len-- != 0; i++) {
+		int sval;
+		if (cregs[i].off == PCIC_MISC_CTL_2)
+			sval = 0;
+		else
+			sval = socket;
+		value = pcic_getb(pcic, sval, cregs[i].off);
+		if (i & 1) {
+			if (cregs[i].fmt)
+				fmt = "%s\t%s\t%b\n";
+			else
+				fmt = "%s\t%s\t%x\n";
+			cmn_err(CE_CONT, fmt, buff,
+				cregs[i].name, value, cregs[i].fmt);
+			buff[0] = '\0';
+		} else {
+			if (cregs[i].fmt)
+				fmt = "\t%s\t%b";
+			else
+				fmt = "\t%s\t%x";
+			(void) sprintf(buff, fmt,
+				cregs[i].name, value, cregs[i].fmt);
+			for (j = strlen(buff); j < 40; j++)
+				buff[j] = ' ';
+			buff[40] = '\0';
+		}
+	}
+	cmn_err(CE_CONT, "%s\n", buff);
+
+	i = pcic_getb(pcic, socket, PCIC_TIME_SETUP_0);
+	j = pcic_getb(pcic, socket, PCIC_TIME_SETUP_1);
+	cmn_err(CE_CONT, "\tsetup-tim0\t%x\tsetup-tim1\t%x\n", i, j);
+
+	i = pcic_getb(pcic, socket, PCIC_TIME_COMMAND_0);
+	j = pcic_getb(pcic, socket, PCIC_TIME_COMMAND_1);
+	cmn_err(CE_CONT, "\tcmd-tim0  \t%x\tcmd-tim1  \t%x\n", i, j);
+
+	i = pcic_getb(pcic, socket, PCIC_TIME_RECOVER_0);
+	j = pcic_getb(pcic, socket, PCIC_TIME_RECOVER_1);
+	cmn_err(CE_CONT, "\trcvr-tim0 \t%x\trcvr-tim1 \t%x\n", i, j);
+
+	cmn_err(CE_CONT, "--------- Extended Registers  --------\n");
+
+	for (buff[0] = '\0', i = 0; cxregs[i].name != NULL && len-- != 0; i++) {
+		value = clext_reg_read(pcic, socket, cxregs[i].off);
+		if (i & 1) {
+			if (cxregs[i].fmt)
+				fmt = "%s\t%s\t%b\n";
+			else
+				fmt = "%s\t%s\t%x\n";
+			cmn_err(CE_CONT, fmt, buff,
+				cxregs[i].name, value, cxregs[i].fmt);
+			buff[0] = '\0';
+		} else {
+			if (cxregs[i].fmt)
+				fmt = "\t%s\t%b";
+			else
+				fmt = "\t%s\t%x";
+			(void) sprintf(buff, fmt,
+				cxregs[i].name, value, cxregs[i].fmt);
+			for (j = strlen(buff); j < 40; j++)
+				buff[j] = ' ';
+			buff[40] = '\0';
+		}
+	}
+}
+
+#if defined(PCIC_DEBUG)
+static void
+xxdmp_all_regs(pcicdev_t *pcic, int socket, uint32_t len)
+{
+	int i, value, j;
+	char buff[256];
+	char *fmt;
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug < 2)
+		return;
+#endif
+	cmn_err(CE_CONT,
+		"----------- PCIC Registers for socket %d---------\n",
+		socket);
+	cmn_err(CE_CONT,
+		"\tname       value                        name       value\n");
+
+	for (buff[0] = '\0', i = 0; iregs[i].name != NULL && len-- != 0; i++) {
+		value = pcic_getb(pcic, socket, iregs[i].off);
+		if (i & 1) {
+			if (iregs[i].fmt)
+				fmt = "%s\t%s\t%b\n";
+			else
+				fmt = "%s\t%s\t%x\n";
+			cmn_err(CE_CONT, fmt, buff,
+				iregs[i].name, value, iregs[i].fmt);
+			buff[0] = '\0';
+		} else {
+			if (iregs[i].fmt)
+				fmt = "\t%s\t%b";
+			else
+				fmt = "\t%s\t%x";
+			(void) sprintf(buff, fmt,
+				iregs[i].name, value, iregs[i].fmt);
+			for (j = strlen(buff); j < 40; j++)
+				buff[j] = ' ';
+			buff[40] = '\0';
+		}
+	}
+	switch (pcic->pc_type) {
+	case PCIC_CL_PD6710:
+	case PCIC_CL_PD6722:
+	case PCIC_CL_PD6729:
+	case PCIC_CL_PD6832:
+		(void) xxdmp_cl_regs(pcic, socket, 0xFFFF);
+		break;
+	}
+	cmn_err(CE_CONT, "%s\n", buff);
+}
+#endif
+
+/*
+ * pcic_mswait(ms)
+ *	sleep ms milliseconds
+ *	call drv_usecwait once for each ms
+ */
+static void
+pcic_mswait(pcicdev_t *pcic, int socket, int ms)
+{
+	if (ms) {
+		pcic->pc_sockets[socket].pcs_flags |= PCS_WAITING;
+		pcic_mutex_exit(&pcic->pc_lock);
+		delay(drv_usectohz(ms*1000));
+		pcic_mutex_enter(&pcic->pc_lock);
+		pcic->pc_sockets[socket].pcs_flags &= ~PCS_WAITING;
+	}
+}
+
+/*
+ * pcic_check_ready(pcic, index, off)
+ *      Wait for card to come ready
+ *      We only wait if the card is NOT in RESET
+ *      and power is on.
+ */
+static boolean_t
+pcic_check_ready(pcicdev_t *pcic, int socket)
+{
+	int ifstate, intstate;
+
+	intstate = pcic_getb(pcic, socket, PCIC_INTERRUPT);
+	ifstate = pcic_getb(pcic, socket, PCIC_INTERFACE_STATUS);
+
+	if ((intstate & PCIC_RESET) &&
+	    ((ifstate & (PCIC_READY|PCIC_POWER_ON|PCIC_ISTAT_CD_MASK)) ==
+	    (PCIC_READY|PCIC_POWER_ON|PCIC_CD_PRESENT_OK)))
+		return (B_TRUE);
+
+#ifdef  PCIC_DEBUG
+	pcic_err(NULL, 5, "pcic_check_read: Card not ready, intstate = 0x%x, "
+	    "ifstate = 0x%x\n", intstate, ifstate);
+	if (pcic_debug) {
+		pcic_debug += 4;
+		xxdmp_all_regs(pcic, socket, -1);
+		pcic_debug -= 4;
+	}
+#endif
+	return (B_FALSE);
+}
+
+/*
+ * Cirrus Logic extended register read/write routines
+ */
+static int
+clext_reg_read(pcicdev_t *pcic, int sn, uchar_t ext_reg)
+{
+	int val;
+
+	switch (pcic->pc_io_type) {
+	case PCIC_IO_TYPE_YENTA:
+		val = ddi_get8(pcic->handle,
+		    pcic->ioaddr + CB_CLEXT_OFFSET + ext_reg);
+		break;
+	default:
+		pcic_putb(pcic, sn, PCIC_CL_EXINDEX, ext_reg);
+		val = pcic_getb(pcic, sn, PCIC_CL_EXINDEX + 1);
+		break;
+	}
+
+	return (val);
+}
+
+static void
+clext_reg_write(pcicdev_t *pcic, int sn, uchar_t ext_reg, uchar_t value)
+{
+	switch (pcic->pc_io_type) {
+	case PCIC_IO_TYPE_YENTA:
+		ddi_put8(pcic->handle,
+		    pcic->ioaddr + CB_CLEXT_OFFSET + ext_reg, value);
+		break;
+	default:
+		pcic_putb(pcic, sn, PCIC_CL_EXINDEX, ext_reg);
+		pcic_putb(pcic, sn, PCIC_CL_EXINDEX + 1, value);
+		break;
+	}
+}
+
+/*
+ * Misc PCI functions
+ */
+static void
+pcic_iomem_pci_ctl(ddi_acc_handle_t handle, uchar_t *cfgaddr, unsigned flags)
+{
+	unsigned cmd;
+
+	if (flags & (PCIC_ENABLE_IO | PCIC_ENABLE_MEM)) {
+		cmd = ddi_get16(handle, (ushort_t *)(cfgaddr + 4));
+		if ((cmd & (PCI_COMM_IO|PCI_COMM_MAE)) ==
+		    (PCI_COMM_IO|PCI_COMM_MAE))
+			return;
+
+		if (flags & PCIC_ENABLE_IO)
+		    cmd |= PCI_COMM_IO;
+
+		if (flags & PCIC_ENABLE_MEM)
+		    cmd |= PCI_COMM_MAE;
+
+		ddi_put16(handle, (ushort_t *)(cfgaddr + 4), cmd);
+	} /* if (PCIC_ENABLE_IO | PCIC_ENABLE_MEM) */
+}
+
+/*
+ * pcic_find_pci_type - Find and return PCI-PCMCIA adapter type
+ */
+static int
+pcic_find_pci_type(pcicdev_t *pcic)
+{
+	uint32_t vend, device;
+
+	vend = ddi_getprop(DDI_DEV_T_ANY, pcic->dip,
+				DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
+				"vendor-id", -1);
+	device = ddi_getprop(DDI_DEV_T_ANY, pcic->dip,
+				DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
+				"device-id", -1);
+
+	device = PCI_ID(vend, device);
+	pcic->pc_type = device;
+	pcic->pc_chipname = "PCI:unknown";
+
+	switch (device) {
+	case PCIC_INTEL_i82092:
+		pcic->pc_chipname = PCIC_TYPE_i82092;
+		break;
+	case PCIC_CL_PD6729:
+		pcic->pc_chipname = PCIC_TYPE_PD6729;
+		/*
+		 * Some 6730's incorrectly identify themselves
+		 *	as a 6729, so we need to do some more tests
+		 *	here to see if the device that's claiming
+		 *	to be a 6729 is really a 6730.
+		 */
+		if ((clext_reg_read(pcic, 0, PCIC_CLEXT_MISC_CTL_3) &
+			PCIC_CLEXT_MISC_CTL_3_REV_MASK) ==
+				0) {
+			pcic->pc_chipname = PCIC_TYPE_PD6730;
+			pcic->pc_type = PCIC_CL_PD6730;
+		}
+		break;
+	case PCIC_CL_PD6730:
+		pcic->pc_chipname = PCIC_TYPE_PD6730;
+		break;
+	case PCIC_CL_PD6832:
+		pcic->pc_chipname = PCIC_TYPE_PD6832;
+		break;
+	case PCIC_SMC_34C90:
+		pcic->pc_chipname = PCIC_TYPE_34C90;
+		break;
+	case PCIC_TOSHIBA_TOPIC95:
+		pcic->pc_chipname = PCIC_TYPE_TOPIC95;
+		break;
+	case PCIC_TOSHIBA_TOPIC100:
+		pcic->pc_chipname = PCIC_TYPE_TOPIC100;
+		break;
+	case PCIC_TI_PCI1031:
+		pcic->pc_chipname = PCIC_TYPE_PCI1031;
+		break;
+	case PCIC_TI_PCI1130:
+		pcic->pc_chipname = PCIC_TYPE_PCI1130;
+		break;
+	case PCIC_TI_PCI1131:
+		pcic->pc_chipname = PCIC_TYPE_PCI1131;
+		break;
+	case PCIC_TI_PCI1250:
+		pcic->pc_chipname = PCIC_TYPE_PCI1250;
+		break;
+	case PCIC_TI_PCI1225:
+		pcic->pc_chipname = PCIC_TYPE_PCI1225;
+		break;
+	case PCIC_TI_PCI1410:
+		pcic->pc_chipname = PCIC_TYPE_PCI1410;
+		break;
+	case PCIC_TI_PCI1510:
+		pcic->pc_chipname = PCIC_TYPE_PCI1510;
+		break;
+	case PCIC_TI_PCI1520:
+		pcic->pc_chipname = PCIC_TYPE_PCI1520;
+		break;
+	case PCIC_TI_PCI1221:
+		pcic->pc_chipname = PCIC_TYPE_PCI1221;
+		break;
+	case PCIC_TI_PCI1050:
+		pcic->pc_chipname = PCIC_TYPE_PCI1050;
+		break;
+	case PCIC_ENE_1410:
+		pcic->pc_chipname = PCIC_TYPE_1410;
+		break;
+	case PCIC_O2_OZ6912:
+		pcic->pc_chipname = PCIC_TYPE_OZ6912;
+		break;
+	case PCIC_RICOH_RL5C466:
+		pcic->pc_chipname = PCIC_TYPE_RL5C466;
+		break;
+	case PCIC_TI_PCI1420:
+		pcic->pc_chipname = PCIC_TYPE_PCI1420;
+		break;
+	case PCIC_ENE_1420:
+		pcic->pc_chipname = PCIC_TYPE_1420;
+		break;
+	default:
+		switch (PCI_ID(vend, (uint32_t)0)) {
+		case PCIC_TOSHIBA_VENDOR:
+			pcic->pc_chipname = PCIC_TYPE_TOSHIBA;
+			pcic->pc_type = PCIC_TOSHIBA_VENDOR;
+			break;
+		case PCIC_TI_VENDOR:
+			pcic->pc_chipname = PCIC_TYPE_TI;
+			pcic->pc_type = PCIC_TI_VENDOR;
+			break;
+		case PCIC_O2MICRO_VENDOR:
+			pcic->pc_chipname = PCIC_TYPE_O2MICRO;
+			pcic->pc_type = PCIC_O2MICRO_VENDOR;
+			break;
+		case PCIC_RICOH_VENDOR:
+			pcic->pc_chipname = PCIC_TYPE_RICOH;
+			pcic->pc_type = PCIC_RICOH_VENDOR;
+			break;
+		default:
+			if (!(pcic->pc_flags & PCF_CARDBUS))
+				return (DDI_FAILURE);
+			pcic->pc_chipname = PCIC_TYPE_YENTA;
+			break;
+		}
+	}
+	return (DDI_SUCCESS);
+}
+
+static void
+pcic_82092_smiirq_ctl(pcicdev_t *pcic, int socket, int intr, int state)
+{
+	uchar_t ppirr = ddi_get8(pcic->cfg_handle,
+					pcic->cfgaddr + PCIC_82092_PPIRR);
+	uchar_t val;
+
+	if (intr == PCIC_82092_CTL_SMI) {
+		val = PCIC_82092_SMI_CTL(socket,
+						PCIC_82092_INT_DISABLE);
+		ppirr &= ~val;
+		val = PCIC_82092_SMI_CTL(socket, state);
+		ppirr |= val;
+	} else {
+		val = PCIC_82092_IRQ_CTL(socket,
+						PCIC_82092_INT_DISABLE);
+		ppirr &= ~val;
+		val = PCIC_82092_IRQ_CTL(socket, state);
+		ppirr |= val;
+	}
+	ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_82092_PPIRR,
+			ppirr);
+}
+
+static uint_t
+pcic_cd_softint(caddr_t arg1, caddr_t arg2)
+{
+	pcic_socket_t *sockp = (pcic_socket_t *)arg1;
+	uint_t rc = DDI_INTR_UNCLAIMED;
+
+	_NOTE(ARGUNUSED(arg2))
+
+	mutex_enter(&sockp->pcs_pcic->pc_lock);
+	if (sockp->pcs_cd_softint_flg) {
+		uint8_t status;
+		sockp->pcs_cd_softint_flg = 0;
+		rc = DDI_INTR_CLAIMED;
+		status = pcic_getb(sockp->pcs_pcic, sockp->pcs_socket,
+			PCIC_INTERFACE_STATUS);
+		pcic_handle_cd_change(sockp->pcs_pcic, sockp, status);
+	}
+	mutex_exit(&sockp->pcs_pcic->pc_lock);
+	return (rc);
+}
+
+int pcic_debounce_cnt = PCIC_REM_DEBOUNCE_CNT;
+int pcic_debounce_intr_time = PCIC_REM_DEBOUNCE_TIME;
+int pcic_debounce_cnt_ok = PCIC_DEBOUNCE_OK_CNT;
+
+#ifdef CARDBUS
+static uint32_t pcic_cbps_on = 0;
+static uint32_t pcic_cbps_off = CB_PS_NOTACARD | CB_PS_CCDMASK |
+				CB_PS_XVCARD | CB_PS_YVCARD;
+#else
+static uint32_t pcic_cbps_on = CB_PS_16BITCARD;
+static uint32_t pcic_cbps_off = CB_PS_NOTACARD | CB_PS_CCDMASK |
+				CB_PS_CBCARD |
+				CB_PS_XVCARD | CB_PS_YVCARD;
+#endif
+static void
+pcic_handle_cd_change(pcicdev_t *pcic, pcic_socket_t *sockp, uint8_t status)
+{
+	boolean_t	do_debounce = B_FALSE;
+	int		debounce_time = drv_usectohz(pcic_debounce_time);
+	uint8_t		irq;
+	timeout_id_t	debounce;
+
+	/*
+	 * Always reset debounce but may need to check original state later.
+	 */
+	debounce = sockp->pcs_debounce_id;
+	sockp->pcs_debounce_id = 0;
+
+	/*
+	 * Check to see whether a card is present or not. There are
+	 *	only two states that we are concerned with - the state
+	 *	where both CD pins are asserted, which means that the
+	 *	card is fully seated, and the state where neither CD
+	 *	pin is asserted, which means that the card is not
+	 *	present.
+	 * The CD signals are generally very noisy and cause a lot of
+	 *	contact bounce as the card is being inserted and
+	 *	removed, so we need to do some software debouncing.
+	 */
+
+#ifdef PCIC_DEBUG
+	    pcic_err(pcic->dip, 6,
+		    "pcic%d handle_cd_change: socket %d card status 0x%x"
+		    " deb 0x%p\n", ddi_get_instance(pcic->dip),
+		    sockp->pcs_socket, status, debounce);
+#endif
+	switch (status & PCIC_ISTAT_CD_MASK) {
+	case PCIC_CD_PRESENT_OK:
+	    sockp->pcs_flags &= ~(PCS_CARD_REMOVED|PCS_CARD_CBREM);
+	    if (!(sockp->pcs_flags & PCS_CARD_PRESENT)) {
+		uint32_t cbps;
+#ifdef PCIC_DEBUG
+		pcic_err(pcic->dip, 8, "New card (0x%x)\n", sockp->pcs_flags);
+#endif
+		cbps = pcic_getcb(pcic, CB_PRESENT_STATE);
+#ifdef PCIC_DEBUG
+		pcic_err(pcic->dip, 8, "CBus PS (0x%x)\n", cbps);
+#endif
+		/*
+		 * Check the CB bits are sane.
+		 */
+		if ((cbps & pcic_cbps_on) != pcic_cbps_on ||
+		    cbps & pcic_cbps_off) {
+		    cmn_err(CE_WARN,
+			    "%s%d: Odd Cardbus Present State 0x%x\n",
+			    ddi_get_name(pcic->dip),
+			    ddi_get_instance(pcic->dip),
+			    cbps);
+		    pcic_putcb(pcic, CB_EVENT_FORCE, CB_EF_CVTEST);
+		    debounce = 0;
+		    debounce_time = drv_usectohz(1000000);
+		}
+		if (debounce) {
+		    sockp->pcs_flags |= PCS_CARD_PRESENT;
+		    if (pcic_do_insertion) {
+
+			cbps = pcic_getcb(pcic, CB_PRESENT_STATE);
+
+			if (cbps & CB_PS_16BITCARD) {
+			    pcic_err(pcic->dip, 8, "16 bit card inserted\n");
+			    sockp->pcs_flags |= PCS_CARD_IS16BIT;
+			    /* calls pcm_adapter_callback() */
+			    if (pcic->pc_callback) {
+
+				(void) ddi_prop_update_string(DDI_DEV_T_NONE,
+					pcic->dip, PCM_DEVICETYPE,
+					"pccard");
+				PC_CALLBACK(pcic->dip, pcic->pc_cb_arg,
+					    PCE_CARD_INSERT,
+					    sockp->pcs_socket);
+			    }
+			} else if (cbps & CB_PS_CBCARD) {
+			    pcic_err(pcic->dip, 8, "32 bit card inserted\n");
+
+			    if (pcic->pc_flags & PCF_CARDBUS) {
+				sockp->pcs_flags |= PCS_CARD_ISCARDBUS;
+#ifdef CARDBUS
+				if (!pcic_load_cardbus(pcic, sockp)) {
+				    pcic_unload_cardbus(pcic, sockp);
+				}
+
+#else
+				cmn_err(CE_NOTE,
+					"32 bit Cardbus not supported in"
+					" this device driver\n");
+#endif
+			    } else {
+				/*
+				 * Ignore the card
+				 */
+				cmn_err(CE_NOTE,
+					"32 bit Cardbus not supported on this"
+					" device\n");
+			    }
+			} else {
+			    cmn_err(CE_NOTE,
+				"Unsupported PCMCIA card inserted\n");
+			}
+		    }
+		    syshw_send_signal(sockp->pcs_syshwsig);
+		} else {
+		    do_debounce = B_TRUE;
+		}
+	    } else {
+		/*
+		 * It is possible to come through here if the system
+		 * starts up with cards already inserted. Do nothing
+		 * and don't worry about it.
+		 */
+#ifdef PCIC_DEBUG
+		pcic_err(pcic->dip, 5,
+			"pcic%d: Odd card insertion indication on socket %d\n",
+			ddi_get_instance(pcic->dip),
+			sockp->pcs_socket);
+#endif
+	    }
+	    break;
+
+	default:
+	    if (!(sockp->pcs_flags & PCS_CARD_PRESENT)) {
+		/*
+		 * Someone has started to insert a card so delay a while.
+		 */
+		do_debounce = B_TRUE;
+		break;
+	    }
+		/*
+		 * Otherwise this is basically the same as not present
+		 * so fall through.
+		 */
+
+		/* FALLTHRU */
+	case 0:
+	    if (sockp->pcs_flags & PCS_CARD_PRESENT) {
+		if (pcic->pc_flags & PCF_CBPWRCTL) {
+		    pcic_putcb(pcic, CB_CONTROL, 0);
+		} else {
+		    pcic_putb(pcic, sockp->pcs_socket, PCIC_POWER_CONTROL, 0);
+		    (void) pcic_getb(pcic, sockp->pcs_socket,
+			PCIC_POWER_CONTROL);
+		}
+#ifdef PCIC_DEBUG
+		pcic_err(pcic->dip, 8, "Card removed\n");
+#endif
+		sockp->pcs_flags &= ~PCS_CARD_PRESENT;
+
+		if (sockp->pcs_flags & PCS_CARD_IS16BIT) {
+		    sockp->pcs_flags &= ~PCS_CARD_IS16BIT;
+		    if (pcic_do_removal && pcic->pc_callback) {
+			PC_CALLBACK(pcic->dip, pcic->pc_cb_arg,
+				    PCE_CARD_REMOVAL, sockp->pcs_socket);
+		    }
+		}
+		if (sockp->pcs_flags & PCS_CARD_ISCARDBUS) {
+		    sockp->pcs_flags &= ~PCS_CARD_ISCARDBUS;
+		    sockp->pcs_flags |= PCS_CARD_CBREM;
+		}
+		sockp->pcs_flags |= PCS_CARD_REMOVED;
+
+		do_debounce = B_TRUE;
+	    }
+	    if (debounce && (sockp->pcs_flags & PCS_CARD_REMOVED)) {
+		if (sockp->pcs_flags & PCS_CARD_CBREM) {
+		/*
+		 * Ensure that we do the unloading in the
+		 * debounce handler, that way we're not doing
+		 * nasty things in an interrupt handler. e.g.
+		 * a USB device will wait for data which will
+		 * obviously never come because we've
+		 * unplugged the device, but the wait will
+		 * wait forever because no interrupts can
+		 * come in...
+		 */
+#ifdef CARDBUS
+		    pcic_unload_cardbus(pcic, sockp);
+		    /* pcic_dump_all(pcic); */
+#endif
+		    sockp->pcs_flags &= ~PCS_CARD_CBREM;
+		}
+		syshw_send_signal(sockp->pcs_syshwsig);
+		sockp->pcs_flags &= ~PCS_CARD_REMOVED;
+	    }
+	    break;
+	} /* switch */
+
+	if (do_debounce) {
+	/*
+	 * Delay doing
+	 * anything for a while so that things can settle
+	 * down a little. Interrupts are already disabled.
+	 * Reset the state and we'll reevaluate the
+	 * whole kit 'n kaboodle when the timeout fires
+	 */
+#ifdef PCIC_DEBUG
+		pcic_err(pcic->dip, 8, "Queueing up debounce timeout for "
+			"socket %d.%d\n",
+			ddi_get_instance(pcic->dip),
+			sockp->pcs_socket);
+#endif
+	    sockp->pcs_debounce_id = pcic_add_debqueue(sockp, debounce_time);
+
+	/*
+	 * We bug out here without re-enabling interrupts. They will
+	 * be re-enabled when the debounce timeout swings through
+	 * here.
+	 */
+	    return;
+	}
+
+	/*
+	 * Turn on Card detect interrupts. Other interrupts will be
+	 * enabled during set_socket calls.
+	 *
+	 * Note that set_socket only changes interrupt settings when there
+	 * is a card present.
+	 */
+	irq = pcic_getb(pcic, sockp->pcs_socket, PCIC_MANAGEMENT_INT);
+	irq |= PCIC_CD_DETECT;
+	pcic_putb(pcic, sockp->pcs_socket, PCIC_MANAGEMENT_INT, irq);
+
+	pcic_err(pcic->dip, 7, "Leaving pcic_handle_cd_change\n");
+}
+
+/*
+ * pcic_getb()
+ *	get an I/O byte based on the yardware decode method
+ */
+static uint8_t
+pcic_getb(pcicdev_t *pcic, int socket, int reg)
+{
+	int work;
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug == 0x7fff) {
+		cmn_err(CE_CONT, "pcic_getb0: pcic=%p socket=%d reg=%d\n",
+			(void *)pcic, socket, reg);
+		cmn_err(CE_CONT, "pcic_getb1: type=%d handle=%p ioaddr=%p \n",
+			pcic->pc_io_type, (void *)pcic->handle,
+			(void *)pcic->ioaddr);
+	}
+#endif
+
+	switch (pcic->pc_io_type) {
+	case PCIC_IO_TYPE_YENTA:
+		return (ddi_get8(pcic->handle,
+		    pcic->ioaddr + CB_R2_OFFSET + reg));
+	default:
+		work = (socket * PCIC_SOCKET_1) | reg;
+		ddi_put8(pcic->handle, pcic->ioaddr, work);
+		return (ddi_get8(pcic->handle, pcic->ioaddr + 1));
+	}
+}
+
+static void
+pcic_putb(pcicdev_t *pcic, int socket, int reg, int8_t value)
+{
+	int work;
+
+#if defined(PCIC_DEBUG)
+	if (pcic_debug == 0x7fff) {
+		cmn_err(CE_CONT,
+			"pcic_putb0: pcic=%p socket=%d reg=%d value=%x \n",
+			(void *)pcic, socket, reg, value);
+		cmn_err(CE_CONT,
+			"pcic_putb1: type=%d handle=%p ioaddr=%p \n",
+			pcic->pc_io_type, (void *)pcic->handle,
+			(void *)pcic->ioaddr);
+	}
+#endif
+
+
+	switch (pcic->pc_io_type) {
+	case PCIC_IO_TYPE_YENTA:
+		ddi_put8(pcic->handle, pcic->ioaddr + CB_R2_OFFSET + reg,
+				value);
+		break;
+	default:
+		work = (socket * PCIC_SOCKET_1) | reg;
+		ddi_put8(pcic->handle, pcic->ioaddr, work);
+		ddi_put8(pcic->handle, pcic->ioaddr + 1, value);
+		break;
+	}
+}
+
+/*
+ * chip identification functions
+ */
+
+/*
+ * chip identification: Cirrus Logic PD6710/6720/6722
+ */
+static int
+pcic_ci_cirrus(pcicdev_t *pcic)
+{
+	int value1, value2;
+
+	/* Init the CL id mode */
+	value1 = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
+	pcic_putb(pcic, 0, PCIC_CHIP_INFO, 0);
+	value1 = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
+	value2 = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
+
+	if ((value1 & PCIC_CI_ID) == PCIC_CI_ID &&
+	    (value2 & PCIC_CI_ID) == 0) {
+		/* chip is a Cirrus Logic and not Intel */
+		pcic->pc_type = PCIC_CL_PD6710;
+		if (value1 & PCIC_CI_SLOTS)
+			pcic->pc_chipname = PCIC_TYPE_PD6720;
+		else
+			pcic->pc_chipname = PCIC_TYPE_PD6710;
+		/* now fine tune things just in case a 6722 */
+		value1 = clext_reg_read(pcic, 0, PCIC_CLEXT_DMASK_0);
+		if (value1 == 0) {
+			clext_reg_write(pcic, 0, PCIC_CLEXT_SCRATCH, 0x55);
+			value1 = clext_reg_read(pcic, 0, PCIC_CLEXT_SCRATCH);
+			if (value1 == 0x55) {
+				pcic->pc_chipname = PCIC_TYPE_PD6722;
+				pcic->pc_type = PCIC_CL_PD6722;
+				clext_reg_write(pcic, 0, PCIC_CLEXT_SCRATCH, 0);
+			}
+		}
+		return (1);
+	}
+	return (0);
+}
+
+/*
+ * chip identification: Vadem (VG365/465/468/469)
+ */
+
+static void
+pcic_vadem_enable(pcicdev_t *pcic)
+{
+	ddi_put8(pcic->handle, pcic->ioaddr, PCIC_VADEM_P1);
+	ddi_put8(pcic->handle, pcic->ioaddr, PCIC_VADEM_P2);
+	ddi_put8(pcic->handle, pcic->ioaddr, pcic->pc_lastreg);
+}
+
+static int
+pcic_ci_vadem(pcicdev_t *pcic)
+{
+	int value;
+
+	pcic_vadem_enable(pcic);
+	value = pcic_getb(pcic, 0, PCIC_CHIP_REVISION);
+	pcic_putb(pcic, 0, PCIC_CHIP_REVISION, 0xFF);
+	if (pcic_getb(pcic, 0, PCIC_CHIP_REVISION) ==
+	    (value | PCIC_VADEM_D3) ||
+	    (pcic_getb(pcic, 0, PCIC_CHIP_REVISION) & PCIC_REV_MASK) ==
+	    PCIC_VADEM_469) {
+		int vadem, new;
+		pcic_vadem_enable(pcic);
+		vadem = pcic_getb(pcic, 0, PCIC_VG_DMA) &
+			~(PCIC_V_UNLOCK | PCIC_V_VADEMREV);
+		new = vadem | (PCIC_V_VADEMREV|PCIC_V_UNLOCK);
+		pcic_putb(pcic, 0, PCIC_VG_DMA, new);
+		value = pcic_getb(pcic, 0, PCIC_CHIP_REVISION);
+
+		/* want to lock but leave mouse or other on */
+		pcic_putb(pcic, 0, PCIC_VG_DMA, vadem);
+		switch (value & PCIC_REV_MASK) {
+		case PCIC_VADEM_365:
+			pcic->pc_chipname = PCIC_VG_365;
+			pcic->pc_type = PCIC_VADEM;
+			break;
+		case PCIC_VADEM_465:
+			pcic->pc_chipname = PCIC_VG_465;
+			pcic->pc_type = PCIC_VADEM;
+			pcic->pc_flags |= PCF_1SOCKET;
+			break;
+		case PCIC_VADEM_468:
+			pcic->pc_chipname = PCIC_VG_468;
+			pcic->pc_type = PCIC_VADEM;
+			break;
+		case PCIC_VADEM_469:
+			pcic->pc_chipname = PCIC_VG_469;
+			pcic->pc_type = PCIC_VADEM_VG469;
+			break;
+		}
+		return (1);
+	}
+	return (0);
+}
+
+/*
+ * chip identification: Ricoh
+ */
+static int
+pcic_ci_ricoh(pcicdev_t *pcic)
+{
+	int value;
+
+	value = pcic_getb(pcic, 0, PCIC_RF_CHIP_IDENT);
+	switch (value) {
+	case PCIC_RF_296:
+		pcic->pc_type = PCIC_RICOH;
+		pcic->pc_chipname = PCIC_TYPE_RF5C296;
+		return (1);
+	case PCIC_RF_396:
+		pcic->pc_type = PCIC_RICOH;
+		pcic->pc_chipname = PCIC_TYPE_RF5C396;
+		return (1);
+	}
+	return (0);
+}
+
+
+/*
+ * set up available address spaces in busra
+ */
+static void
+pcic_init_assigned(dev_info_t *dip)
+{
+	pcm_regs_t *pcic_avail_p;
+	pci_regspec_t *pci_avail_p, *regs;
+	int len, entries, rlen;
+	dev_info_t *pdip;
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "available", (caddr_t)&pcic_avail_p, &len) == DDI_PROP_SUCCESS) {
+		/*
+		 * found "available" property at the cardbus/pcmcia node
+		 * need to translate address space entries from pcmcia
+		 * format to pci format
+		 */
+		entries = len / sizeof (pcm_regs_t);
+		pci_avail_p = kmem_alloc(sizeof (pci_regspec_t) * entries,
+			KM_SLEEP);
+		if (pcic_apply_avail_ranges(dip, pcic_avail_p, pci_avail_p,
+		    entries) == DDI_SUCCESS)
+			(void) pci_resource_setup_avail(dip, pci_avail_p,
+				entries);
+		kmem_free(pcic_avail_p, len);
+		kmem_free(pci_avail_p, entries * sizeof (pci_regspec_t));
+		return;
+	}
+
+	/*
+	 * "legacy" platforms will have "available" property in pci node
+	 */
+	for (pdip = ddi_get_parent(dip); pdip; pdip = ddi_get_parent(pdip)) {
+		if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
+		    "available", (caddr_t)&pci_avail_p, &len) ==
+		    DDI_PROP_SUCCESS) {
+			/* (void) pci_resource_setup(pdip); */
+			kmem_free(pci_avail_p, len);
+			break;
+		}
+	}
+
+	if (pdip == NULL) {
+		int len;
+		char bus_type[16] = "(unknown)";
+		dev_info_t *par;
+
+		cmn_err(CE_CONT,
+		    "?pcic_init_assigned: no available property for pcmcia\n");
+
+		/*
+		 * This code is taken from pci_resource_setup() but does
+		 * not attempt to use the "available" property to populate
+		 * the ndi maps that are created.
+		 * The fact that we will actually
+		 * free some resource below (that was allocated by OBP)
+		 * should be enough to be going on with.
+		 */
+		for (par = dip; par != NULL; par = ddi_get_parent(par)) {
+			len = sizeof (bus_type);
+
+			if ((ddi_prop_op(DDI_DEV_T_ANY, par,
+			    PROP_LEN_AND_VAL_BUF,
+			    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
+			    "device_type",
+			    (caddr_t)&bus_type, &len) == DDI_SUCCESS) &&
+			    (strcmp(bus_type, "pci") == 0))
+				break;
+		}
+		if (par != NULL &&
+		    (ndi_ra_map_setup(par, NDI_RA_TYPE_MEM) != NDI_SUCCESS ||
+		    ndi_ra_map_setup(par, NDI_RA_TYPE_IO) != NDI_SUCCESS))
+			par = NULL;
+	} else {
+#ifdef CARDBUS
+		cardbus_bus_range_t *bus_range;
+		int k;
+
+		if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "bus-range",
+		    (caddr_t)&bus_range, &k) == DDI_PROP_SUCCESS) {
+			if (bus_range->lo != bus_range->hi)
+				pcic_err(pdip, 9, "allowable bus range is "
+				    "%u->%u\n", bus_range->lo, bus_range->hi);
+			else {
+				pcic_err(pdip, 0,
+				    "!No spare PCI bus numbers, range is "
+				    "%u->%u, cardbus isn't usable\n",
+				    bus_range->lo, bus_range->hi);
+			}
+			kmem_free(bus_range, k);
+		} else
+			pcic_err(pdip, 0, "!No bus-range property seems to "
+			    "have been set up\n");
+#endif
+		/*
+		 * Have a valid parent with the "available" property
+		 */
+		(void) pci_resource_setup(pdip);
+	}
+
+	if ((strcmp(ddi_get_name(dip), "pcma") == 0) &&
+	    ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
+	    "assigned-addresses",
+	    (caddr_t)&regs, &rlen) == DDI_SUCCESS) {
+		ra_return_t ra;
+
+		/*
+		 * On the UltraBook IIi the ranges are assigned under
+		 * openboot. If we don't free them here the first I/O
+		 * space that can be used is up above 0x10000 which
+		 * doesn't work for this driver due to restrictions
+		 * on the PCI I/O addresses the controllers can cope with.
+		 * They are never going to be used by anything else
+		 * so free them up to the general pool. AG.
+		 */
+		pcic_err(dip, 1, "Free assigned addresses\n");
+
+		if ((PCI_REG_ADDR_G(regs[0].pci_phys_hi) ==
+		    PCI_REG_ADDR_G(PCI_ADDR_MEM32)) &&
+		    regs[0].pci_size_low == 0x1000000) {
+			ra.ra_addr_lo = regs[0].pci_phys_low;
+			ra.ra_len = regs[0].pci_size_low;
+			(void) pcmcia_free_mem(dip, &ra);
+		}
+		if ((PCI_REG_ADDR_G(regs[1].pci_phys_hi) ==
+		    PCI_REG_ADDR_G(PCI_ADDR_IO)) &&
+		    (regs[1].pci_size_low == 0x8000 ||
+		    regs[1].pci_size_low == 0x4000))   /* UB-IIi || UB-I */
+		{
+			ra.ra_addr_lo = regs[1].pci_phys_low;
+			ra.ra_len = regs[1].pci_size_low;
+			(void) pcmcia_free_io(dip, &ra);
+		}
+		kmem_free((caddr_t)regs, rlen);
+	}
+}
+
+/*
+ * translate "available" from pcmcia format to pci format
+ */
+static int
+pcic_apply_avail_ranges(dev_info_t *dip, pcm_regs_t *pcic_p,
+    pci_regspec_t *pci_p, int entries)
+{
+	int i, range_len, range_entries;
+	pcic_ranges_t *pcic_range_p;
+
+	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
+		    (caddr_t)&pcic_range_p, &range_len) != DDI_PROP_SUCCESS) {
+		cmn_err(CE_CONT, "?pcic_apply_avail_ranges: "
+			"no ranges property for pcmcia\n");
+		return (DDI_FAILURE);
+	}
+
+	range_entries = range_len / sizeof (pcic_ranges_t);
+
+	/* for each "available" entry to be translated */
+	for (i = 0; i < entries; i++, pcic_p++, pci_p++) {
+		int j;
+		pcic_ranges_t *range_p = pcic_range_p;
+		pci_p->pci_phys_hi = -1u; /* default invalid value */
+
+		/* for each "ranges" entry to be searched */
+		for (j = 0; j < range_entries; j++, range_p++) {
+			uint64_t range_end = range_p->pcic_range_caddrlo +
+				range_p->pcic_range_size;
+			uint64_t avail_end = pcic_p->phys_lo + pcic_p->phys_len;
+
+			if ((range_p->pcic_range_caddrhi != pcic_p->phys_hi) ||
+			    (range_p->pcic_range_caddrlo > pcic_p->phys_lo) ||
+			    (range_end < avail_end))
+				continue;
+
+			pci_p->pci_phys_hi = range_p->pcic_range_paddrhi;
+			pci_p->pci_phys_mid = range_p->pcic_range_paddrmid;
+			pci_p->pci_phys_low = range_p->pcic_range_paddrlo
+			    + (pcic_p->phys_lo - range_p->pcic_range_caddrlo);
+			pci_p->pci_size_hi = 0;
+			pci_p->pci_size_low = pcic_p->phys_len;
+		}
+	}
+	kmem_free(pcic_range_p, range_len);
+	return (DDI_SUCCESS);
+}
+
+static int
+pcic_open(dev_t *dev, int flag, int otyp, cred_t *cred)
+{
+	if (getminor(*dev) == SYSHW_MINOR)
+		return (syshw_open(dev, flag, otyp, cred));
+#ifdef CARDBUS
+	if (cardbus_is_cb_minor(*dev))
+		return (cardbus_open(dev, flag, otyp, cred));
+#endif
+	return (EINVAL);
+}
+
+static int
+pcic_close(dev_t dev, int flag, int otyp, cred_t *cred)
+{
+	if (getminor(dev) == SYSHW_MINOR)
+		return (syshw_close(dev, flag, otyp, cred));
+#ifdef CARDBUS
+	if (cardbus_is_cb_minor(dev))
+		return (cardbus_close(dev, flag, otyp, cred));
+#endif
+	return (EINVAL);
+}
+
+static int
+pcic_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred,
+	int *rval)
+{
+	if (getminor(dev) == SYSHW_MINOR)
+		return (syshw_ioctl(dev, cmd, arg, mode, cred, rval));
+#ifdef CARDBUS
+	if (cardbus_is_cb_minor(dev))
+		return (cardbus_ioctl(dev, cmd, arg, mode, cred, rval));
+#endif
+	return (EINVAL);
+}
+
+
+static boolean_t
+pcic_load_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp)
+{
+	uint32_t present_state;
+	dev_info_t *dip = pcic->dip;
+	set_socket_t s;
+	get_socket_t g;
+	boolean_t retval;
+	unsigned vccLevel;
+
+	pcic_err(dip, 8, "entering pcic_load_cardbus\n");
+
+	pcic_mutex_exit(&pcic->pc_lock);
+
+	bzero(&s, sizeof (set_socket_t));
+	s.socket = sockp->pcs_socket;
+	s.SCIntMask = SBM_CD|SBM_RDYBSY;
+	s.IFType = IF_CARDBUS;
+	s.State = (unsigned)~0;
+
+	present_state = pcic_getcb(pcic, CB_PRESENT_STATE);
+	if (present_state & PCIC_VCC_3VCARD)
+		s.VccLevel = PCIC_VCC_3VLEVEL;
+	else if (present_state & PCIC_VCC_5VCARD)
+		s.VccLevel = PCIC_VCC_5VLEVEL;
+	else {
+		cmn_err(CE_CONT,
+		    "pcic_load_cardbus: unsupported card voltage\n");
+		goto failure;
+	}
+	vccLevel = s.VccLevel;
+	s.Vpp1Level = s.Vpp2Level = 0;
+
+	if (pcic_set_socket(dip, &s) != SUCCESS)
+		goto failure;
+
+	if (pcic_reset_socket(dip, sockp->pcs_socket,
+	    RESET_MODE_CARD_ONLY) != SUCCESS)
+		goto failure;
+
+	bzero(&g, sizeof (get_socket_t));
+	g.socket = sockp->pcs_socket;
+	if (pcic_get_socket(dip, &g) != SUCCESS)
+		goto failure;
+
+	bzero(&s, sizeof (set_socket_t));
+	s.socket = sockp->pcs_socket;
+	s.SCIntMask = SBM_CD;
+	s.IREQRouting = g.IRQRouting;
+	s.IFType = g.IFType;
+	s.CtlInd = g.CtlInd;
+	s.State = (unsigned)~0;
+	s.VccLevel = vccLevel;
+	s.Vpp1Level = s.Vpp2Level = 0;
+
+	if (pcic_set_socket(dip, &s) != SUCCESS)
+		goto failure;
+
+	retval = cardbus_load_cardbus(dip, sockp->pcs_socket, pcic->pc_base);
+	goto exit;
+
+failure:
+	retval = B_FALSE;
+
+exit:
+	pcic_mutex_enter(&pcic->pc_lock);
+	pcic_err(dip, 8, "exit pcic_load_cardbus (%s)\n",
+	    retval ? "success" : "failure");
+	return (retval);
+}
+
+static void
+pcic_unload_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp)
+{
+	dev_info_t *dip = pcic->dip;
+	set_socket_t s;
+
+	pcic_mutex_exit(&pcic->pc_lock);
+
+	cardbus_unload_cardbus(dip);
+
+	bzero(&s, sizeof (set_socket_t));
+	s.socket = sockp->pcs_socket;
+	s.SCIntMask = SBM_CD|SBM_RDYBSY;
+	s.IREQRouting = 0;
+	s.IFType = IF_MEMORY;
+	s.CtlInd = 0;
+	s.State = 0;
+	s.VccLevel = s.Vpp1Level = s.Vpp2Level = 0;
+
+	(void) pcic_set_socket(dip, &s);
+
+	pcic_mutex_enter(&pcic->pc_lock);
+}
+
+static uint32_t
+pcic_getcb(pcicdev_t *pcic, int reg)
+{
+	ASSERT(pcic->pc_io_type == PCIC_IO_TYPE_YENTA);
+
+	return (ddi_get32(pcic->handle,
+	    (uint32_t *)(pcic->ioaddr + CB_CB_OFFSET + reg)));
+}
+
+static void
+pcic_putcb(pcicdev_t *pcic, int reg, uint32_t value)
+{
+	ASSERT(pcic->pc_io_type == PCIC_IO_TYPE_YENTA);
+
+	ddi_put32(pcic->handle,
+	    (uint32_t *)(pcic->ioaddr + CB_CB_OFFSET + reg), value);
+}
+
+static void
+pcic_enable_io_intr(pcicdev_t *pcic, int socket, int irq)
+{
+	uint8_t value;
+	uint16_t brdgctl;
+
+	value = pcic_getb(pcic, socket, PCIC_INTERRUPT) & ~PCIC_INTR_MASK;
+	pcic_putb(pcic, socket, PCIC_INTERRUPT, value | irq);
+
+	switch (pcic->pc_type) {
+	case PCIC_INTEL_i82092:
+		pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ,
+		    PCIC_82092_INT_ENABLE);
+		break;
+	case PCIC_O2_OZ6912:
+		value = pcic_getb(pcic, 0, PCIC_CENTDMA);
+		value |= 0x8;
+		pcic_putb(pcic, 0, PCIC_CENTDMA, value);
+		break;
+	case PCIC_CL_PD6832:
+	case PCIC_TI_PCI1250:
+	case PCIC_TI_PCI1221:
+	case PCIC_TI_PCI1225:
+	case PCIC_TI_PCI1410:
+	case PCIC_ENE_1410:
+	case PCIC_TI_PCI1510:
+	case PCIC_TI_PCI1520:
+	case PCIC_TI_PCI1420:
+	case PCIC_ENE_1420:
+		/* route card functional interrupts to PCI interrupts */
+		brdgctl = ddi_get16(pcic->cfg_handle,
+		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
+		pcic_err(NULL, 1,
+		    "pcic_enable_io_intr brdgctl(0x%x) was: 0x%x\n",
+		    PCI_CBUS_BRIDGE_CTRL, brdgctl);
+		brdgctl &= ~PCIC_BRDGCTL_INTR_MASK;
+		ddi_put16(pcic->cfg_handle,
+		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL),
+		    brdgctl);
+		/* Flush the write */
+		(void) ddi_get16(pcic->cfg_handle,
+		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+pcic_disable_io_intr(pcicdev_t *pcic, int socket)
+{
+	uint8_t value;
+	uint16_t brdgctl;
+
+	value = pcic_getb(pcic, socket, PCIC_INTERRUPT) & ~PCIC_INTR_MASK;
+	pcic_putb(pcic, socket, PCIC_INTERRUPT, value);
+
+	switch (pcic->pc_type) {
+	case PCIC_INTEL_i82092:
+		pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ,
+		    PCIC_82092_INT_DISABLE);
+		break;
+	case PCIC_O2_OZ6912:
+		value = pcic_getb(pcic, 0, PCIC_CENTDMA);
+		value &= ~0x8;
+		pcic_putb(pcic, 0, PCIC_CENTDMA, value);
+		/* Flush the write */
+		(void) pcic_getb(pcic, 0, PCIC_CENTDMA);
+		break;
+	case PCIC_CL_PD6832:
+	case PCIC_TI_PCI1250:
+	case PCIC_TI_PCI1221:
+	case PCIC_TI_PCI1225:
+	case PCIC_TI_PCI1410:
+	case PCIC_ENE_1410:
+	case PCIC_TI_PCI1510:
+	case PCIC_TI_PCI1520:
+	case PCIC_TI_PCI1420:
+	case PCIC_ENE_1420:
+		/*
+		 * This maps I/O interrupts to ExCA which
+		 * have been turned off by the write to
+		 * PCIC_INTERRUPT above. It would appear to
+		 * be the only way to actually turn I/O Ints off
+		 * while retaining CS Ints.
+		 */
+		brdgctl = ddi_get16(pcic->cfg_handle,
+		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
+		pcic_err(NULL, 1,
+		    "pcic_disable_io_intr brdgctl(0x%x) was: 0x%x\n",
+		    PCI_CBUS_BRIDGE_CTRL, brdgctl);
+		brdgctl |= PCIC_BRDGCTL_INTR_MASK;
+		ddi_put16(pcic->cfg_handle,
+		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL),
+		    brdgctl);
+		/* Flush the write */
+		(void) ddi_get16(pcic->cfg_handle,
+		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+pcic_cb_enable_intr(dev_info_t *dip)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+
+	mutex_enter(&pcic->pc_lock);
+	pcic_enable_io_intr(pcic, 0, pcic->pc_sockets[0].pcs_irq);
+	mutex_exit(&pcic->pc_lock);
+}
+
+static void
+pcic_cb_disable_intr(dev_info_t *dip)
+{
+	anp_t *anp = ddi_get_driver_private(dip);
+	pcicdev_t *pcic = anp->an_private;
+
+	mutex_enter(&pcic->pc_lock);
+	pcic_disable_io_intr(pcic, 0);
+	mutex_exit(&pcic->pc_lock);
+}
+
+static int
+log_pci_cfg_err(ushort_t e, int bridge_secondary)
+{
+	int	nerr = 0;
+	if (e & PCI_STAT_PERROR) {
+		nerr++;
+		cmn_err(CE_CONT, "detected parity error.\n");
+	}
+	if (e & PCI_STAT_S_SYSERR) {
+		nerr++;
+		if (bridge_secondary)
+			cmn_err(CE_CONT, "received system error.\n");
+		else
+			cmn_err(CE_CONT, "signalled system error.\n");
+	}
+	if (e & PCI_STAT_R_MAST_AB) {
+		nerr++;
+		cmn_err(CE_CONT, "received master abort.\n");
+	}
+	if (e & PCI_STAT_R_TARG_AB)
+		cmn_err(CE_CONT, "received target abort.\n");
+	if (e & PCI_STAT_S_TARG_AB)
+		cmn_err(CE_CONT, "signalled target abort\n");
+	if (e & PCI_STAT_S_PERROR) {
+		nerr++;
+		cmn_err(CE_CONT, "signalled parity error\n");
+	}
+	return (nerr);
+}
+
+#if defined(__sparc)
+static int
+pcic_fault(enum pci_fault_ops op, void *arg)
+{
+	pcicdev_t *pcic = (pcicdev_t *)arg;
+	ushort_t pci_cfg_stat =
+	    pci_config_get16(pcic->cfg_handle, PCI_CONF_STAT);
+	ushort_t pci_cfg_sec_stat =
+	    pci_config_get16(pcic->cfg_handle, 0x16);
+	char	nm[24];
+	int	nerr = 0;
+
+	cardbus_dump_pci_config(pcic->dip);
+
+	switch (op) {
+	case FAULT_LOG:
+		(void) sprintf(nm, "%s-%d", ddi_driver_name(pcic->dip),
+		    ddi_get_instance(pcic->dip));
+
+		cmn_err(CE_WARN, "%s: PCIC fault log start:\n", nm);
+		cmn_err(CE_WARN, "%s: primary err (%x):\n", nm, pci_cfg_stat);
+		nerr += log_pci_cfg_err(pci_cfg_stat, 0);
+		cmn_err(CE_WARN, "%s: sec err (%x):\n", nm, pci_cfg_sec_stat);
+		nerr += log_pci_cfg_err(pci_cfg_sec_stat, 1);
+		cmn_err(CE_CONT, "%s: PCI fault log end.\n", nm);
+		return (nerr);
+	case FAULT_POKEFINI:
+	case FAULT_RESET:
+		pci_config_put16(pcic->cfg_handle,
+		    PCI_CONF_STAT, pci_cfg_stat);
+		pci_config_put16(pcic->cfg_handle, 0x16, pci_cfg_sec_stat);
+		break;
+	case FAULT_POKEFLT:
+		if (!(pci_cfg_stat & PCI_STAT_S_SYSERR))
+			return (1);
+		if (!(pci_cfg_sec_stat & PCI_STAT_R_MAST_AB))
+			return (1);
+		break;
+	default:
+		break;
+	}
+	return (DDI_SUCCESS);
+}
+#endif
+
+static void
+pcic_delayed_resume(void *arg)
+{
+	int	i, j, interrupt;
+	anp_t *pcic_nexus;
+	pcicdev_t *pcic;
+
+	_NOTE(ARGUNUSED(arg))
+
+#if defined(PCIC_DEBUG)
+	pcic_err(NULL, 6, "pcic_delayed_resume(): entered\n");
+#endif
+	for (j = 0; j <= pcic_maxinst; j++) {
+
+		pcic_nexus = ddi_get_soft_state(pcic_soft_state_p, j);
+		if (!pcic_nexus)
+			continue;
+		pcic = (pcicdev_t *)pcic_nexus->an_private;
+		if (!pcic)
+			continue;
+
+		pcic_mutex_enter(&pcic->pc_lock); /* protect the registers */
+		for (i = 0; i < pcic->pc_numsockets; i++) {
+			/* Enable interrupts  on PCI if needs be */
+			interrupt = pcic_getb(pcic, i, PCIC_INTERRUPT);
+			if (pcic->pc_flags & PCF_USE_SMI)
+				interrupt |= PCIC_INTR_ENABLE;
+			pcic_putb(pcic, i, PCIC_INTERRUPT,
+			    PCIC_RESET | interrupt);
+			pcic->pc_sockets[i].pcs_debounce_id =
+			    pcic_add_debqueue(&pcic->pc_sockets[i],
+			    drv_usectohz(pcic_debounce_time));
+		}
+		pcic_mutex_exit(&pcic->pc_lock); /* protect the registers */
+		if (pcic_do_pcmcia_sr)
+			(void) pcmcia_wait_insert(pcic->dip);
+	}
+}
+
+static void
+pcic_debounce(pcic_socket_t *pcs)
+{
+	uint8_t status, stschng;
+
+	pcic_mutex_enter(&pcs->pcs_pcic->pc_lock);
+	pcs->pcs_flags &= ~PCS_STARTING;
+	stschng = pcic_getb(pcs->pcs_pcic, pcs->pcs_socket,
+	    PCIC_CARD_STATUS_CHANGE);
+	status = pcic_getb(pcs->pcs_pcic, pcs->pcs_socket,
+	    PCIC_INTERFACE_STATUS);
+#ifdef PCIC_DEBUG
+	pcic_err(pcs->pcs_pcic->dip, 8,
+	    "pcic_debounce(0x%p, dip=0x%p) socket %d st 0x%x "
+	    "chg 0x%x flg 0x%x\n",
+	    (void *)pcs, (void *) pcs->pcs_pcic->dip, pcs->pcs_socket,
+	    status, stschng, pcs->pcs_flags);
+#endif
+
+	pcic_putb(pcs->pcs_pcic, pcs->pcs_socket, PCIC_CARD_STATUS_CHANGE,
+	    PCIC_CD_DETECT);
+	pcic_handle_cd_change(pcs->pcs_pcic, pcs, status);
+	pcic_mutex_exit(&pcs->pcs_pcic->pc_lock);
+}
+
+static void
+pcic_deb_thread()
+{
+	callb_cpr_t cprinfo;
+	struct debounce *debp;
+	clock_t lastt;
+
+	CALLB_CPR_INIT(&cprinfo, &pcic_deb_mtx,
+	    callb_generic_cpr, "pcic debounce thread");
+	mutex_enter(&pcic_deb_mtx);
+	while (pcic_deb_threadid) {
+		while (pcic_deb_queue) {
+#ifdef PCIC_DEBUG
+			pcic_dump_debqueue("Thread");
+#endif
+			debp = pcic_deb_queue;
+			(void) drv_getparm(LBOLT, &lastt);
+			if (lastt >= debp->expire) {
+				pcic_deb_queue = debp->next;
+				mutex_exit(&pcic_deb_mtx);
+				pcic_debounce(debp->pcs);
+				mutex_enter(&pcic_deb_mtx);
+				kmem_free(debp, sizeof (*debp));
+			} else {
+				(void) cv_timedwait(&pcic_deb_cv,
+				    &pcic_deb_mtx, debp->expire);
+			}
+		}
+		CALLB_CPR_SAFE_BEGIN(&cprinfo);
+		cv_wait(&pcic_deb_cv, &pcic_deb_mtx);
+		CALLB_CPR_SAFE_END(&cprinfo, &pcic_deb_mtx);
+	}
+	pcic_deb_threadid = (kthread_t *)1;
+	cv_signal(&pcic_deb_cv);
+	CALLB_CPR_EXIT(&cprinfo);	/* Also exits the mutex */
+	thread_exit();
+}
+
+static void *
+pcic_add_debqueue(pcic_socket_t *pcs, int clocks)
+{
+	clock_t lbolt;
+	struct debounce *dbp, **dbpp = &pcic_deb_queue;
+
+	(void) drv_getparm(LBOLT, &lbolt);
+	dbp = kmem_alloc(sizeof (struct debounce), KM_NOSLEEP);
+
+	dbp->expire = lbolt + clocks;
+	dbp->pcs = pcs;
+	mutex_enter(&pcic_deb_mtx);
+	while (*dbpp) {
+		if (dbp->expire > (*dbpp)->expire)
+			dbpp = &((*dbpp)->next);
+		else
+			break;
+	}
+	dbp->next = *dbpp;
+	*dbpp = dbp;
+#ifdef PCIC_DEBUG
+	pcic_dump_debqueue("Add");
+#endif
+	cv_signal(&pcic_deb_cv);
+	mutex_exit(&pcic_deb_mtx);
+	return (dbp);
+}
+
+static void
+pcic_rm_debqueue(void *id)
+{
+	struct debounce *dbp, **dbpp = &pcic_deb_queue;
+
+	dbp = (struct debounce *)id;
+	mutex_enter(&pcic_deb_mtx);
+	while (*dbpp) {
+		if (*dbpp == dbp) {
+			*dbpp = dbp->next;
+			kmem_free(dbp, sizeof (*dbp));
+#ifdef PCIC_DEBUG
+			pcic_dump_debqueue("Remove");
+#endif
+			cv_signal(&pcic_deb_cv);
+			mutex_exit(&pcic_deb_mtx);
+			return;
+		}
+		dbpp = &((*dbpp)->next);
+	}
+	pcic_err(NULL, 6, "pcic: Failed to find debounce id 0x%p\n", id);
+	mutex_exit(&pcic_deb_mtx);
+}
+
+
+static int	pcic_powerdelay = 0;
+
+static int
+pcic_exca_powerctl(pcicdev_t *pcic, int socket, int powerlevel)
+{
+	int	ind, value, orig_pwrctl;
+
+	/* power setup -- if necessary */
+	orig_pwrctl = pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
+
+#if defined(PCIC_DEBUG)
+	pcic_err(pcic->dip, 6,
+	    "pcic_exca_powerctl(socket %d) powerlevel=%x orig 0x%x\n",
+	    socket, powerlevel, orig_pwrctl);
+#endif
+	/* Preserve the PCIC_OUTPUT_ENABLE (control lines output enable) bit. */
+	powerlevel = (powerlevel & ~POWER_OUTPUT_ENABLE) |
+	    (orig_pwrctl & POWER_OUTPUT_ENABLE);
+	if (powerlevel != orig_pwrctl) {
+		if (powerlevel & ~POWER_OUTPUT_ENABLE) {
+			int	ifs;
+			/*
+			 * set power to socket
+			 * note that the powerlevel was calculated earlier
+			 */
+			pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel);
+			(void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
+
+			/*
+			 * this second write to the power control register
+			 * is needed to resolve a problem on
+			 * the IBM ThinkPad 750
+			 * where the first write doesn't latch.
+			 * The second write appears to always work and
+			 * doesn't hurt the operation of other chips
+			 * so we can just use it -- this is good since we can't
+			 * determine what chip the 750 actually uses
+			 * (I suspect an early Ricoh).
+			 */
+			pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel);
+
+			value = pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
+			pcic_mswait(pcic, socket, pcic_powerdelay);
+#if defined(PCIC_DEBUG)
+			pcic_err(pcic->dip, 8,
+			    "\tpowerlevel reg = %x (ifs %x)\n",
+			    value, pcic_getb(pcic, socket,
+			    PCIC_INTERFACE_STATUS));
+			pcic_err(pcic->dip, 8,
+			    "CBus regs: PS 0x%x, Control 0x%x\n",
+			    pcic_getcb(pcic, CB_PRESENT_STATE),
+			    pcic_getcb(pcic, CB_CONTROL));
+#endif
+			/*
+			 * since power was touched, make sure it says it
+			 * is on.  This lets it become stable.
+			 */
+			for (ind = 0; ind < 20; ind++) {
+				ifs = pcic_getb(pcic, socket,
+				    PCIC_INTERFACE_STATUS);
+				if (ifs & PCIC_POWER_ON)
+					break;
+				else {
+					pcic_putb(pcic, socket,
+					    PCIC_POWER_CONTROL, 0);
+					(void) pcic_getb(pcic, socket,
+					    PCIC_POWER_CONTROL);
+					pcic_mswait(pcic, socket, 40);
+					if (ind == 10) {
+						pcic_putcb(pcic, CB_EVENT_FORCE,
+						    CB_EF_CVTEST);
+						pcic_mswait(pcic, socket, 100);
+					}
+					pcic_putb(pcic, socket,
+					    PCIC_POWER_CONTROL,
+					    powerlevel & ~POWER_OUTPUT_ENABLE);
+					(void) pcic_getb(pcic, socket,
+					    PCIC_POWER_CONTROL);
+					pcic_mswait(pcic, socket,
+					    pcic_powerdelay);
+					pcic_putb(pcic, socket,
+					    PCIC_POWER_CONTROL, powerlevel);
+					(void) pcic_getb(pcic, socket,
+					    PCIC_POWER_CONTROL);
+					pcic_mswait(pcic, socket,
+					    pcic_powerdelay);
+				}
+			}
+
+			if (!(ifs & PCIC_POWER_ON)) {
+				cmn_err(CE_WARN,
+				    "pcic socket %d: Power didn't get turned"
+				    "on!\nif status 0x%x pwrc 0x%x(x%x) "
+				    "misc1 0x%x igc 0x%x ind %d\n",
+				    socket, ifs,
+				    pcic_getb(pcic, socket, PCIC_POWER_CONTROL),
+				    orig_pwrctl,
+				    pcic_getb(pcic, socket, PCIC_MISC_CTL_1),
+				    pcic_getb(pcic, socket, PCIC_INTERRUPT),
+				    ind);
+				return (BAD_VCC);
+			}
+#if defined(PCIC_DEBUG)
+			pcic_err(pcic->dip, 8,
+			    "\tind = %d, if status %x pwrc 0x%x "
+			    "misc1 0x%x igc 0x%x\n",
+			    ind, ifs,
+			    pcic_getb(pcic, socket, PCIC_POWER_CONTROL),
+			    pcic_getb(pcic, socket, PCIC_MISC_CTL_1),
+			    pcic_getb(pcic, socket, PCIC_INTERRUPT));
+#endif
+		} else {
+			/* explicitly turned off the power */
+			pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel);
+			(void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
+		}
+	}
+	return (SUCCESS);
+}
+
+static int pcic_cbdoreset_during_poweron = 1;
+static int
+pcic_cbus_powerctl(pcicdev_t *pcic, int socket)
+{
+	uint32_t cbctl = 0, orig_cbctl, cbstev, cbps;
+	int ind, iobits;
+	pcic_socket_t *sockp = &pcic->pc_sockets[socket];
+
+	pcic_putcb(pcic, CB_STATUS_EVENT, CB_SE_POWER_CYCLE);
+
+	ind = pcic_power[sockp->pcs_vpp1].PowerLevel/10;
+	cbctl |= pcic_cbv_levels[ind];
+
+	ind = pcic_power[sockp->pcs_vcc].PowerLevel/10;
+	cbctl |= (pcic_cbv_levels[ind]<<4);
+
+	orig_cbctl = pcic_getcb(pcic, CB_CONTROL);
+
+#if defined(PCIC_DEBUG)
+	pcic_err(pcic->dip, 6,
+	    "pcic_cbus_powerctl(socket %d) vcc %d vpp1 %d "
+	    "cbctl 0x%x->0x%x\n",
+	    socket, sockp->pcs_vcc, sockp->pcs_vpp1, orig_cbctl, cbctl);
+#endif
+	if (cbctl != orig_cbctl) {
+	    if (pcic_cbdoreset_during_poweron &&
+		(orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) {
+		iobits = pcic_getb(pcic, socket, PCIC_INTERRUPT);
+		pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits & ~PCIC_RESET);
+	    }
+	    pcic_putcb(pcic, CB_CONTROL, cbctl);
+
+	    if ((cbctl & CB_C_VCCMASK) == (orig_cbctl & CB_C_VCCMASK)) {
+		pcic_mswait(pcic, socket, pcic_powerdelay);
+		return (SUCCESS);
+	    }
+	    for (ind = 0; ind < 20; ind++) {
+		cbstev = pcic_getcb(pcic, CB_STATUS_EVENT);
+
+		if (cbstev & CB_SE_POWER_CYCLE) {
+
+		/*
+		 * delay 400 ms: though the standard defines that the Vcc
+		 * set-up time is 20 ms, some PC-Card bridge requires longer
+		 * duration.
+		 * Note: We should check the status AFTER the delay to give time
+		 * for things to stabilize.
+		 */
+		    pcic_mswait(pcic, socket, 400);
+
+		    cbps = pcic_getcb(pcic, CB_PRESENT_STATE);
+		    if (cbctl && !(cbps & CB_PS_POWER_CYCLE)) {
+			/* break; */
+			cmn_err(CE_WARN, "cbus_powerctl: power off??\n");
+		    }
+		    if (cbctl & CB_PS_BADVCC) {
+			cmn_err(CE_WARN, "cbus_powerctl: bad power request\n");
+			break;
+		    }
+
+#if defined(PCIC_DEBUG)
+		    pcic_err(pcic->dip, 8,
+			"cbstev = 0x%x cbps = 0x%x cbctl 0x%x(0x%x)",
+			cbstev, pcic_getcb(pcic, CB_PRESENT_STATE),
+			cbctl, orig_cbctl);
+#endif
+		    if (pcic_cbdoreset_during_poweron &&
+			(orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) {
+			pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits);
+		    }
+		    return (SUCCESS);
+		}
+		pcic_mswait(pcic, socket, 40);
+	    }
+	    if (pcic_cbdoreset_during_poweron &&
+		(orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) {
+		pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits);
+	    }
+	    cmn_err(CE_WARN,
+		    "pcic socket %d: Power didn't get turned on/off!\n"
+		    "cbstev = 0x%x cbps = 0x%x cbctl 0x%x(0x%x) "
+		    "vcc %d vpp1 %d", socket, cbstev,
+		    pcic_getcb(pcic, CB_PRESENT_STATE),
+		    cbctl, orig_cbctl, sockp->pcs_vcc, sockp->pcs_vpp1);
+	    return (BAD_VCC);
+	}
+	return (SUCCESS);
+}
+
+static int	pcic_do_pprintf = 0;
+
+static void
+pcic_dump_debqueue(char *msg)
+{
+	struct debounce *debp = pcic_deb_queue;
+	clock_t lbolt;
+
+	(void) drv_getparm(LBOLT, &lbolt);
+	pcic_err(NULL, 6, debp ? "pcic debounce list (%s) lbolt 0x%x:\n" :
+	    "pcic debounce_list (%s) EMPTY lbolt 0x%x\n", msg, lbolt);
+	while (debp) {
+		pcic_err(NULL, 6, "%p: exp 0x%x next 0x%p id 0x%p\n",
+		    (void *) debp, (int)debp->expire, (void *) debp->next,
+		    debp->pcs->pcs_debounce_id);
+		debp = debp->next;
+	}
+}
+
+
+/* PRINTFLIKE3 */
+static void
+pcic_err(dev_info_t *dip, int level, const char *fmt, ...)
+{
+	if (pcic_debug && (level <= pcic_debug)) {
+		va_list adx;
+		int	instance;
+		char	buf[256];
+		const char	*name;
+#if !defined(PCIC_DEBUG)
+		int	ce;
+		char	qmark = 0;
+
+		if (level <= 3)
+			ce = CE_WARN;
+		else
+			ce = CE_CONT;
+		if (level == 4)
+			qmark = 1;
+#endif
+
+		if (dip) {
+			instance = ddi_get_instance(dip);
+			/* name = ddi_binding_name(dip); */
+			name = ddi_driver_name(dip);
+		} else {
+			instance = 0;
+			name = "";
+		}
+
+		va_start(adx, fmt);
+		(void) vsprintf(buf, fmt, adx);
+		va_end(adx);
+
+#if defined(PCIC_DEBUG)
+		if (pcic_do_pprintf) {
+			if (dip) {
+				if (instance >= 0)
+					prom_printf("%s(%d),0x%p: %s", name,
+					    instance, dip, buf);
+				else
+					prom_printf("%s,0x%p: %s",
+					    name, dip, buf);
+			} else
+				prom_printf(buf);
+		} else {
+			if (dip) {
+				if (instance >= 0)
+					cmn_err(CE_CONT, "%s(%d),0x%p: %s",
+					    name, instance, (void *) dip, buf);
+				else
+					cmn_err(CE_CONT, "%s,0x%p: %s",
+					    name, (void *) dip, buf);
+			} else
+				cmn_err(CE_CONT, buf);
+		}
+#else
+		if (dip)
+			cmn_err(ce, qmark ? "?%s%d: %s" : "%s%d: %s", name,
+			    instance, buf);
+		else
+			cmn_err(ce, qmark ? "?%s" : buf, buf);
+#endif
+	}
+}
+
+
+static void
+pcic_syshw_cardstate(syshw_t *item, void *arg)
+{
+	pcic_socket_t *pcs = (pcic_socket_t *)arg;
+
+	if (pcs->pcs_flags & PCS_CARD_PRESENT) {
+		item->state = B_TRUE;
+		if (pcs->pcs_flags & PCS_CARD_IS16BIT)
+			item->values[0] = 1;
+		else if (pcs->pcs_flags & PCS_CARD_ISCARDBUS)
+			item->values[0] = 2;
+		else
+			item->values[0] = 0;
+	} else {
+		item->state = B_FALSE;
+		item->values[0] = 0;
+	}
+}
+
+/*
+ * Tadpole additional for the syshw interface used to control the
+ * start/stop switch which is physically linked to the GPIO1 pin
+ * on the 1250a.
+ */
+
+#define	CLIENT_CALLED	0x8000000
+#define	NCE_EVENT_MASK	0xffff
+
+typedef struct _client {
+	pid_t	pid;		/* set by kernel */
+	int	flags;		/* NCE_REGISTER...  */
+	int	priority;	/* >100 unless root */
+	int	events;		/* pending event flags */
+	int	event_sig;	/* SIG... etc */
+	struct _client *next;	/* set by kernel */
+	struct _client *prev;	/* set by kernel */
+} client_data;
+
+static client_data	*cl_data;
+static int	n_clients;
+static kmutex_t	client_mtx, intr_mtx;
+
+static void	delete_client(int);
+
+#ifdef VOYAGER
+static uint32_t	runstop_sig;
+static ddi_softintr_t	softint_id;
+static uchar_t	softint_flag;
+static int	switch_debounce_time = 100;	/* in milliseconds */
+static timeout_id_t	switch_to_id;
+
+static syshw_t syshw_run_stop = {
+	    0, "Run/Stop", SH_SWITCH,
+	    SYSHW_CAN_SIGNAL_CHANGE|SYSHW_STATE_VALID,
+	    B_FALSE, { 0 } };
+
+static void
+syshw_get_run_stop(syshw_t *item, void *arg)
+{
+	pcicdev_t *pcic = (pcicdev_t *)arg;
+
+	if (ddi_get8(pcic->cfg_handle,
+	    pcic->cfgaddr + PCIC_GPIO1_REG) & PCIC_GPIO_DIN)
+		item->state = B_TRUE;
+	else
+		item->state = B_FALSE;
+}
+
+
+#endif
+
+static void
+syshw_attach(pcicdev_t *pcic)
+{
+	if (ddi_get_instance(pcic->dip) != 0)
+		return;
+
+#ifdef VOYAGER
+	if (pcic->pc_type == PCIC_TI_PCI1250) {
+
+		/*
+		 * Only setup run/stop on a Voyager.
+		 * This is currently defined as
+		 * a TI1250 on a SPARC architecture. May have to make this a
+		 * property definition in the future.
+		 */
+		if (ddi_add_softintr(pcic->dip,
+		    DDI_SOFTINT_LOW, &softint_id,
+		    NULL, NULL, syshw_intr,
+		    (caddr_t)pcic) == DDI_SUCCESS) {
+			runstop_sig = syshw_add2map(&syshw_run_stop,
+			    syshw_get_run_stop, pcic);
+			mutex_init(&intr_mtx, NULL, MUTEX_DRIVER,
+			    pcic->pc_pri);
+			ddi_put8(pcic->cfg_handle,
+			    pcic->cfgaddr + PCIC_GPIO1_REG,
+			    PCIC_GPIO_FINPUT | PCIC_GPIO_INTENBL |
+			    PCIC_GPIO_DELTA);
+		}
+	}
+#endif
+	mutex_init(&client_mtx, "syshw client", MUTEX_DRIVER, NULL);
+	(void) ddi_create_minor_node(pcic->dip, "syshw", S_IFCHR,
+	    SYSHW_MINOR, NULL, NULL);
+}
+
+static void
+syshw_detach(pcicdev_t *pcic)
+{
+#ifdef VOYAGER
+	if (pcic->pc_type == PCIC_TI_PCI1250) {
+		pcic_mutex_enter(&intr_mtx);
+
+		/*
+		 * Turn off this interrupt.
+		 */
+		ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_GPIO1_REG,
+		    PCIC_GPIO_FINPUT);
+
+		if (switch_to_id)
+			(void) untimeout(switch_to_id);
+		switch_to_id = 0;
+		softint_flag = 0;
+
+		pcic_mutex_exit(&intr_mtx);
+		ddi_remove_softintr(softint_id);
+		mutex_destroy(&intr_mtx);
+	}
+#endif
+
+	ddi_remove_minor_node(pcic->dip, NULL);
+	mutex_destroy(&client_mtx);
+}
+
+static void
+syshw_resume(pcicdev_t *pcic)
+{
+#ifdef VOYAGER
+	if (pcic->pc_type == PCIC_TI_PCI1250) {
+		ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_GPIO1_REG,
+		    PCIC_GPIO_FINPUT | PCIC_GPIO_INTENBL | PCIC_GPIO_DELTA);
+	}
+#else
+	_NOTE(ARGUNUSED(pcic))
+#endif
+}
+
+#ifdef VOYAGER
+static uint_t
+syshw_intr_hi(pcicdev_t *pcic)
+{
+	uchar_t regval;
+
+	if (pcic->pc_type != PCIC_TI_PCI1250)
+		return (DDI_INTR_UNCLAIMED);
+
+	regval = ddi_get8(pcic->cfg_handle, pcic->cfgaddr + PCIC_GPIO1_REG);
+	if (regval & PCIC_GPIO_DELTA) {
+		pcic_mutex_enter(&intr_mtx);
+		if (softint_flag == 0 && switch_to_id == 0) {
+			softint_flag = 1;
+			ddi_trigger_softintr(softint_id);
+		}
+		ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_GPIO1_REG,
+		    regval);
+		pcic_mutex_exit(&intr_mtx);
+		return (DDI_INTR_CLAIMED);
+	}
+
+	return (DDI_INTR_UNCLAIMED);
+}
+
+/*
+ * Don't deliver the signal until the debounce period has expired.
+ * Unfortuately this means it end up as a three tier interrupt just
+ * to indicate a bit change.
+ */
+static void
+syshw_debounce_to(void *arg)
+{
+	_NOTE(ARGUNUSED(arg))
+
+	if (switch_to_id) {
+		pcic_mutex_enter(&intr_mtx);
+		switch_to_id = 0;
+		pcic_mutex_exit(&intr_mtx);
+		syshw_send_signal(runstop_sig);
+		return;
+	}
+}
+
+static uint_t
+syshw_intr(caddr_t arg)
+{
+	_NOTE(ARGUNUSED(arg))
+
+	if (softint_flag) {
+		pcic_mutex_enter(&intr_mtx);
+		softint_flag = 0;
+		if (!switch_to_id)
+			switch_to_id = timeout(syshw_debounce_to, arg,
+			    drv_usectohz(switch_debounce_time * 1000));
+		pcic_mutex_exit(&intr_mtx);
+		return (DDI_INTR_CLAIMED);
+	}
+	return (DDI_INTR_UNCLAIMED);
+}
+#endif
+
+/*
+ * Send signals to the registered clients
+ */
+static void
+syshw_send_signal(int events)
+{
+	client_data *ptr;
+	proc_t	*pr;
+	int	done_flag;
+
+	ptr = cl_data;
+	while (ptr != NULL) {
+		done_flag = CLIENT_CALLED;
+
+		if ((ptr->flags & events) &&
+		    (ptr->event_sig != 0) &&
+		    ((ptr->flags & done_flag) == 0)) {
+
+			/*
+			 * only call the process if:
+			 * it has not already received the nce signal
+			 * its signal was not zero (just in case)
+			 * and it is registered to receive this signal
+			 */
+			pcic_mutex_enter(&pidlock);
+			pr = prfind(ptr->pid);
+			pcic_mutex_exit(&pidlock);
+			if (pr == NULL) {
+				/*
+				 * This process has died,
+				 * so we free its memory and move on
+				 * start at the begining again:
+				 * a waste of cycles but it makes things easy..
+				 */
+				delete_client(ptr->pid);
+				ptr = cl_data;
+			} else {
+				ptr->events |= (events & ptr->flags &
+				    NCE_EVENT_MASK);
+				psignal(pr, ptr->event_sig);
+				ptr->flags |= done_flag;
+				ptr = ptr->next;
+			}
+		} else {
+			ptr = ptr->next;
+		}
+	}
+
+	ptr = cl_data;
+	while (ptr != NULL) {
+		ptr->flags &= ~done_flag;
+		ptr = ptr->next;
+	}
+}
+
+static int
+syshw_open(dev_t *dev, int flag, int otyp, cred_t *cred)
+{
+	_NOTE(ARGUNUSED(dev, flag, cred))
+
+	if (otyp != OTYP_CHR)
+		return (EINVAL);
+
+	return (0);
+}
+
+static int
+syshw_close(dev_t dev, int flag, int otyp, cred_t *cred)
+{
+	_NOTE(ARGUNUSED(dev, flag, otyp, cred))
+
+	return (0);
+}
+
+/*
+ * Add a client to the list of interested processes
+ */
+static void
+add_client(client_data *new)
+{
+	client_data * ptr;
+
+	n_clients++;
+	if (cl_data == NULL) {
+		cl_data = new;
+		return;
+	}
+
+	ptr = cl_data;
+	while ((ptr->next != NULL) && (ptr->priority <= new->priority))
+		ptr = ptr->next;
+
+	if (ptr == cl_data) {
+		/* at head of the list */
+		cl_data = new;
+		new->next = ptr;
+		new->prev = NULL;
+		if (ptr != NULL)
+			ptr->prev = new;
+	} else {
+		/* somewhere else in the list - insert after */
+		new->next = ptr->next;
+		ptr->next = new;
+		new->prev = ptr;
+		if (new->next != NULL)
+			(new->next)->prev = new;
+	}
+}
+
+/*
+ * Locate a client data structure in the client list by looking for a PID match.
+ */
+static client_data *
+locate_client(pid_t pid)
+{
+	client_data * ptr = cl_data;
+
+	while ((ptr != NULL) && (ptr->pid != pid))
+		ptr = ptr->next;
+
+	return (ptr);
+}
+
+/*
+ * Remove a client record from the client list
+ */
+static void
+delete_client(pid_t pid)
+{
+	client_data * ptr;
+
+	ptr = locate_client(pid);
+	if (ptr == NULL)
+		return;	/* hmmm!! */
+
+	n_clients--;
+
+	if (ptr == cl_data) {
+		/* remove the head of the list */
+		cl_data = ptr->next;
+	}
+	if (ptr->prev != NULL)
+		(ptr->prev)->next = ptr->next;
+	if (ptr->next != NULL)
+		(ptr->next)->prev = ptr->prev;
+
+	kmem_free(ptr, sizeof (client_data));
+}
+
+static void
+unregister_event_client()
+{
+	pcic_mutex_enter(&client_mtx);
+	delete_client(ddi_get_pid());
+	pcic_mutex_exit(&client_mtx);
+}
+
+static int
+register_event_client(client_data *u_client)
+{
+	int	error;
+	client_data * client;
+
+	pcic_mutex_enter(&client_mtx);
+	client = locate_client(ddi_get_pid());
+	if (client) {
+		/*
+		 * we are re-registering ourself
+		 * so we delete the previous entry
+		 */
+		delete_client(ddi_get_pid());
+	}
+
+	client = (client_data *)kmem_alloc(sizeof (client_data), KM_SLEEP);
+
+	if (client) {
+		client->pid = ddi_get_pid();
+		client->priority = u_client->priority;
+		client->flags = u_client->flags & NCE_EVENT_MASK;
+		client->events = 0;
+		client->event_sig = u_client->event_sig;
+		client->next = NULL;
+		client->prev = NULL;
+		add_client(client);
+		error = 0;
+	} else
+		error = EIO;
+
+	pcic_mutex_exit(&client_mtx);
+	return (error);
+}
+
+/*
+ * Read the currently pending event flags for the process in question
+ */
+static int
+check_events_pending(caddr_t data)
+{
+	client_data * client;
+	int	error = 0;
+
+	pcic_mutex_enter(&client_mtx);
+	client = locate_client(ddi_get_pid());
+	if (client) {
+		if (copyout((caddr_t)&client->events, data, sizeof (int)))
+			error = EFAULT;
+		else
+			client->events = 0;
+	} else
+		error = EINVAL;
+
+	pcic_mutex_exit(&client_mtx);
+	return (error);
+}
+
+
+#define	MAXITEMS	8
+static syshw_t *syshw_map[MAXITEMS];
+static void	(*syshw_getfuncs[MAXITEMS])(syshw_t *, void *);
+static void	*syshw_getfunc_args[MAXITEMS];
+static int	nsyshw_items = 0;
+#define	NSYSHW_ITEMS	nsyshw_items
+
+static uint32_t
+syshw_add2map(syshw_t *item, void (*getfunc)(syshw_t *, void *), void *getarg)
+{
+	uint32_t rval = (1 << nsyshw_items);
+	if (nsyshw_items == MAXITEMS)
+		return (0);
+	item->hw_id = nsyshw_items;
+	syshw_map[nsyshw_items] = item;
+	syshw_getfuncs[nsyshw_items] = getfunc;
+	syshw_getfunc_args[nsyshw_items] = getarg;
+	nsyshw_items++;
+	return (rval);
+}
+
+static int
+syshw_ioctl(dev_t dev, int cmd, intptr_t ioctldata, int mode,
+cred_t *cred, int *rval)
+{
+	caddr_t data = (caddr_t)ioctldata;
+	syshw_t sh;
+	hwev_t hwev;
+	client_data dummy_client;
+	int	rc = 0, i;
+
+	_NOTE(ARGUNUSED(dev, mode, cred, rval))
+
+	switch (cmd) {
+	default:
+		rc = EINVAL;
+		break;
+
+	case SYSHW_GET_ITEM:
+	case SYSHW_GET_ITEM_MAXVALUES:
+		if (copyin(data, (caddr_t)&sh, sizeof (sh))) {
+			rc = EFAULT;
+			break;
+		}
+
+		if (sh.hw_id >= NSYSHW_ITEMS) {
+			rc = EINVAL;
+			break;
+		}
+
+		sh = *syshw_map[sh.hw_id];
+		if (!sh.id_string[0]) {
+			rc = ENOTTY;
+			break;
+		}
+		if (cmd == SYSHW_GET_ITEM) {
+			if (syshw_getfuncs[sh.hw_id])
+				syshw_getfuncs[sh.hw_id](&sh,
+				    syshw_getfunc_args[sh.hw_id]);
+			else
+				rc = ENOTTY;
+		}
+
+		if (copyout((caddr_t)&sh, data, sizeof (sh))) {
+			rc = EFAULT;
+			break;
+		}
+		break;
+
+	case SYSHW_SET_ITEM:
+		if (copyin(data, (caddr_t)&sh, sizeof (sh))) {
+			rc = EFAULT;
+			break;
+		}
+
+		if (sh.hw_id >= NSYSHW_ITEMS ||
+		    !syshw_map[sh.hw_id]->id_string[0] ||
+		    !(syshw_map[sh.hw_id]->capabilities &
+		    (SYSHW_STATE_MODIFY | SYSHW_VAL0_MODIFY |
+		    SYSHW_VAL1_MODIFY | SYSHW_VAL2_MODIFY |
+		    SYSHW_VAL3_MODIFY))) {
+			rc = EINVAL;
+			break;
+		}
+
+		switch (sh.hw_id) {
+		default:
+			rc = EINVAL;
+			break;
+		}
+		break;
+
+	case SYSHW_EVREG:
+		if (copyin(data, (caddr_t)&hwev, sizeof (hwev))) {
+			rc = EFAULT;
+			break;
+		}
+
+		for (i = 0; i < NSYSHW_ITEMS; i++) {
+			if (hwev.events & (1 << i) &&
+			    !(syshw_map[i]->capabilities &
+			    SYSHW_CAN_SIGNAL_CHANGE)) {
+				rc = EINVAL;
+				break;
+			}
+		}
+		if (hwev.event_sig != SIGUSR1 && hwev.event_sig != SIGUSR2)
+			rc = EINVAL;
+
+		if (!rc) {
+			dummy_client.priority = 100;
+			dummy_client.flags = hwev.events;
+			dummy_client.event_sig = hwev.event_sig;
+			rc = register_event_client(&dummy_client);
+		}
+		break;
+
+	case SYSHW_EVUNREG:
+		unregister_event_client();
+		break;
+
+	case SYSHW_CHKEV:
+		rc = check_events_pending(data);
+		break;
+	}
+	return (rc);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/pcic.conf	Thu Jun 29 14:43:12 2006 -0700
@@ -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 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+#
+# with the pcmcia/pcic enumerator and the PCI devices
+# there is not much need for this file other than to
+# get the correct interrupt priorities
+#
+interrupt-priorities=6;
+
+#
+# force attach driver to support hotplug activity
+#
+ddi-forceattach=1;
+
+#
+# These are to enable running on an UltraBook & UltraBook IIi
+#
+name="pcma" parent="/pci@1f,0/pci@1" unit-address="1"
+    pci-control-reg-number=3 pci-config-reg-number=0 pci-ispec-num-perinst=0,1
+    disable-cardbus=1;
+name="pcma" parent="/pci@1f,0/pci@1" unit-address="1,1"
+    pci-control-reg-number=3 pci-config-reg-number=0 pci-ispec-num-perinst=0,1
+    disable-cardbus=1;
+#
+# Cardbus device node initialization property.
+# This is an array of strings. Each string is divided into 2 sections
+# seperated by a semi-colon. The device is identified by the items
+# before the semi-colon and properties are set after the semi-colon.
+# 
+cb-device-init-props=
+"VendorID=0x1077 DeviceID=0x2200; nodename='SUNW,qlc'",
+"VendorID=0x108e DeviceID=0x1001; nodename='SUNW,hme'",
+"VendorID=0x1077 DeviceID=0x1020; nodename='SUNW,isptwo'",
+"VendorID=0x108e DeviceID=0x7777; nodename='SUNW,ma'",
+"VendorID=0x102b DeviceID=0x0525; nodename='TSI,mko'",
+"binding_name=display VendorID=0x1002 DeviceID=0x4966; nodename='TSI,fxt' name='TSI,fxt'",
+"binding_name=display VendorID=0x3d3d DeviceID=0x0009; nodename='TSI,gfxp' name='TSI,gfxp' model=GFXP prom-revision='1.10 99/03/15 TSI'",
+"binding_name=display VendorID=0x5333 DeviceID=0x8a22; nodename='Visicom,VigraVision' name='Visicom,VigraVision'";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/pcmcia/pem/pem.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,1182 @@
+/*
+ * 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 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * pem - PCMCIA Event Manager
+ *
+ * gives user level access to PCMCIA event notification and
+ * allows managing devices
+ */
+
+#if defined(DEBUG)
+#define	PEM_DEBUG
+#endif
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/param.h>
+#include <sys/sysmacros.h>
+#include <sys/systm.h>
+#include <sys/stropts.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/kmem.h>
+#include <sys/conf.h>
+#include <sys/ddi.h>
+#include <sys/devops.h>
+#include <sys/sunddi.h>
+#include <sys/ksynch.h>
+#include <sys/stat.h>
+#include <sys/modctl.h>
+#include <sys/kmem.h>
+#include <sys/kstat.h>
+#include <sys/debug.h>
+#include <sys/callb.h>
+
+#include <sys/autoconf.h>
+
+#include <sys/pctypes.h>
+#include <pcmcia/sys/cs_types.h>
+#include <sys/pcmcia.h>
+#include <sys/sservice.h>
+#include <pcmcia/sys/cis.h>
+#include <pcmcia/sys/cis_handlers.h>
+#include <pcmcia/sys/cs.h>
+#include <pcmcia/sys/cs_priv.h>
+#include <pcmcia/sys/cs_stubs.h>
+
+#include <sys/spl.h>
+
+#include <sys/pem.h>
+
+#ifdef PEM_DEBUG
+int	pem_debug = 0;
+#endif
+
+int pem_softint_pend = 0;
+int pem_softint_posted = 0;
+
+char _depends_on[] = "misc/pcmcia";
+
+static int (*cardservices)();
+static int (*Socket_Services)(int, ...);
+uint32_t pem_minors;		/* minors are bit mask */
+
+/*
+ * function prototypes, etc.
+ */
+int _init(void);
+int _fini(void);
+int _info(struct modinfo *modinfop);
+
+static	int pem_open(queue_t *, dev_t *, int, int, cred_t *);
+static	int pem_close(queue_t *, int, cred_t *);
+static	int pem_wput(queue_t *, mblk_t *);
+static	int pem_wsrv(queue_t *q);
+static	int pem_rsrv(queue_t *q);
+static  int pem_attach(dev_info_t *, ddi_attach_cmd_t);
+static  int pem_detach(dev_info_t *, ddi_detach_cmd_t);
+static	int pem_devinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static 	int pem_event_handler(int, int, int, void *);
+static  uint32_t pem_soft_intr(caddr_t);
+static int pem_ioctl(queue_t *, mblk_t *);
+static int pem_cmds(queue_t *q, mblk_t *mp);
+static void pem_error(queue_t *q, mblk_t *, int, int, int);
+static int pem_init_req(queue_t *, mblk_t *, em_init_req_t *);
+static int pem_info_req(queue_t *, mblk_t *, em_info_req_t *);
+static int pem_modify_event_req(queue_t *, mblk_t *,
+					em_modify_event_mask_req_t *);
+static int pem_adapter_info(queue_t *, mblk_t *);
+static int pem_socket_info(queue_t *, mblk_t *);
+static int pem_get_socket(queue_t *, mblk_t *);
+static int pem_ident_socket(queue_t *, mblk_t *);
+static void pem_event_dispatch(int, int, int, void *);
+extern dev_info_t *pcmcia_get_devinfo(int);
+extern int pcmcia_get_minors(dev_info_t *, struct pcm_make_dev **);
+static void pem_flushqueue(queue_t *);
+
+kmutex_t pem_global_lock;
+kmutex_t pem_intr_lock;
+kcondvar_t pem_condvar;
+
+
+ddi_softintr_t pem_intr_id;
+ddi_iblock_cookie_t pem_iblock;
+ddi_idevice_cookie_t pem_dcookie;
+
+client_handle_t pem_cs_handle;
+
+static struct pem_inst {
+	pem_t *pi_pem;
+	queue_t *pi_queue;
+} *pem_instances;
+
+struct pem_event pem_events[PEM_MAX_EVENTS];
+
+/*
+ * Allocate and zero-out "number" structures each of type "structure" in
+ * kernel memory.
+ */
+#define	GETSTRUCT(structure, number)   \
+	((structure *) kmem_zalloc(\
+		(uint32_t)(sizeof (structure) * (number)), KM_NOSLEEP))
+
+/* STREAMS setup glue */
+static struct module_info pem_minfo = {
+	PEM_IDNUM,
+	PEM_NAME,
+	PEM_MIN,
+	PEM_MAX,
+	PEM_HIWATER,
+	PEM_LOWATER
+};
+
+static struct qinit pem_rint = {
+	NULL,
+	pem_rsrv,
+	pem_open,
+	pem_close,
+	NULL,
+	&pem_minfo
+};
+
+static struct qinit pem_wint = {
+	pem_wput,
+	pem_wsrv,
+	NULL,
+	NULL,
+	NULL,
+	&pem_minfo
+};
+
+static struct streamtab pem_info = {
+	&pem_rint,
+	&pem_wint,
+	NULL,
+	NULL
+};
+
+DDI_DEFINE_STREAM_OPS(pem_ops, nulldev, nulldev, pem_attach, pem_detach,
+			nodev, pem_devinfo, D_NEW | D_MP, &pem_info);
+/*
+ * Module linkage information for the kernel.
+ */
+extern struct mod_ops mod_driverops;
+
+static struct modldrv modlmisc = {
+	&mod_driverops,		/* Type of module - a utility provider */
+	"PCMCIA Event Manager %I%",
+	&pem_ops,		/* driver ops */
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1, (void *) &modlmisc, NULL
+};
+
+
+
+int
+_init(void)
+{
+	int e;
+
+	if ((e = ddi_soft_state_init((void **)&pem_instances,
+					sizeof (struct pem_inst), 1)) != 0)
+		return (e);
+
+	mutex_init(&pem_global_lock, NULL, MUTEX_DRIVER, NULL);
+	cv_init(&pem_condvar, NULL, CV_DRIVER, NULL);
+
+	e = mod_install(&modlinkage);
+
+	if (e != 0) {
+		mutex_destroy(&pem_global_lock);
+		cv_destroy(&pem_condvar);
+		ddi_soft_state_fini((void **)&pem_instances);
+	}
+
+	return (e);
+}
+
+int
+_fini(void)
+{
+	int ret;
+
+	if ((ret = mod_remove(&modlinkage)) == 0) {
+		mutex_destroy(&pem_global_lock);
+		cv_destroy(&pem_condvar);
+		ddi_soft_state_fini((void **)&pem_instances);
+	}
+	return (ret);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+
+static int
+pem_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	uchar_t events[EM_EVENT_SIZE];
+	int i;
+
+	switch (cmd) {
+	case DDI_ATTACH:
+		for (i = 0; i < EM_EVENT_SIZE; i++)
+			events[i] = (uchar_t)~0;
+		i = pcmcia_set_em_handler(pem_event_handler,
+					(caddr_t)events,
+					sizeof (events),
+					0x1234,
+					(void **)&cardservices,
+					(void **)&Socket_Services);
+		if (i != 0) {
+#if defined(PEM_DEBUG)
+			if (pem_debug)
+				cmn_err(CE_CONT, "pem: no event handler\n");
+#endif
+			return (DDI_FAILURE);
+		}
+
+		(void) ddi_create_minor_node(dip, "pem", S_IFCHR, 0,
+						"pcmcia:event", 0);
+
+		(void) ddi_add_softintr(dip, DDI_SOFTINT_MED, &pem_intr_id,
+					&pem_iblock,
+					0,
+					pem_soft_intr, (caddr_t)dip);
+
+		mutex_init(&pem_intr_lock, NULL, MUTEX_DRIVER,
+		    (void *)(uintptr_t)__ipltospl(SPL7));
+		break;
+
+	case DDI_RESUME:
+		/*
+		 * we need to tell the daemon to start all over again
+		 * since the world state may have changed.
+		 */
+		break;
+
+	default:
+		return (DDI_FAILURE);
+	}
+	return (DDI_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+pem_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+	clock_t tm;
+
+#ifdef PEM_DEBUG
+	if (pem_debug & PEMTRACE)
+		cmn_err(CE_CONT, "pem_detach cmd=%d pem_minors=%d"
+		    " pem_softint_posted=%d\n",
+		    cmd, pem_minors, pem_softint_posted);
+#endif
+
+	switch (cmd) {
+	case DDI_DETACH:
+		if (pem_minors != 0)
+			return (DDI_FAILURE);
+		mutex_enter(&pem_intr_lock);
+		(void) pcmcia_set_em_handler(NULL, NULL, 0, 0x1234, NULL, NULL);
+
+		while (pem_softint_posted > 0) {
+			/*
+			 * delay for 1 second to allow outstanding soft
+			 * interrupts to be processed before removing the
+			 * soft interrupt handler.
+			 */
+			tm = ddi_get_lbolt();
+			(void) cv_timedwait(&pem_condvar, &pem_intr_lock,
+			    tm + drv_usectohz(100000));
+		}
+
+		ddi_remove_softintr(pem_intr_id);
+		pem_intr_id = 0;
+		mutex_exit(&pem_intr_lock);
+		mutex_destroy(&pem_intr_lock);
+		break;
+	case DDI_SUSPEND:
+		break;
+	default:
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+/*ARGSUSED*/
+static int
+pem_devinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
+{
+	int error = DDI_SUCCESS;
+	switch (cmd) {
+	case DDI_INFO_DEVT2DEVINFO:
+		*result = dip;
+		break;
+	case DDI_INFO_DEVT2INSTANCE:
+		*result = 0;
+		break;
+	default:
+		error = DDI_FAILURE;
+		break;
+	}
+	return (error);
+}
+
+/*
+ * PEM service routines
+ */
+
+/*
+ * pem_open(q, dev, flag, sflag, cred)
+ * generic open routine.  Hardware open will call this. The
+ * hardware open passes in the pemevice structure (one per device class) as
+ * well as all of the normal open parameters.
+ */
+/* ARGSUSED */
+static int
+pem_open(queue_t *q, dev_t *dev, int flag, int sflag, cred_t *cred)
+{
+	pem_t  *pem;
+	mblk_t *mp;
+	struct pem_inst *inst;
+	minor_t minordev;
+
+	ASSERT(q);
+
+	ASSERT(q->q_ptr == NULL);	/* Clone device gives us a fresh Q */
+
+	mutex_enter(&pem_global_lock);
+	/* find minor device number */
+	minordev = ddi_ffs(~pem_minors);
+	if (minordev == 0) {
+		mutex_exit(&pem_global_lock);
+		return (ENXIO);
+	}
+
+	if (ddi_soft_state_zalloc(pem_instances, minordev - 1) != DDI_SUCCESS) {
+		cmn_err(CE_WARN, "pem: cannot allocate state");
+		mutex_exit(&pem_global_lock);
+		return (ENXIO);
+	}
+	inst = (struct pem_inst *)ddi_get_soft_state(pem_instances,
+							minordev - 1);
+
+	if (inst == NULL) {
+		mutex_exit(&pem_global_lock);
+		return (ENXIO);
+	}
+
+	pem_minors |= 1 << (minordev - 1);
+	*dev = makedevice(getmajor(*dev), minordev);
+	minordev--;
+
+	if (pem_cs_handle == 0 && cardservices != NULL) {
+		client_reg_t reg;
+#if defined(PEM_DEBUG)
+		int result;
+#endif
+
+		reg.dip = NULL;
+		reg.Attributes = INFO_SOCKET_SERVICES;
+		reg.EventMask = 0;
+		reg.event_handler = NULL;
+		reg.Version = CS_VERSION;
+#if defined(PEM_DEBUG)
+		result = cardservices(RegisterClient, &pem_cs_handle, &reg);
+		if (pem_debug && result != CS_SUCCESS)
+			cmn_err(CE_CONT, "pem: couldn't register for CS\n");
+#else
+		(void) cardservices(RegisterClient, &pem_cs_handle, &reg);
+#endif
+
+	}
+
+	mutex_exit(&pem_global_lock);
+
+	/*
+	 * get a per-stream structure and link things together so we
+	 * can easily find them later.
+	 */
+	mp = allocb(sizeof (pem_t), BPRI_MED);
+	if (mp == NULL) {
+		return (ENOSR);
+	}
+
+	pem = (pem_t *)mp->b_rptr;
+	ASSERT(pem != NULL);
+	bzero((caddr_t)mp->b_rptr, sizeof (pem_t));
+	pem->pem_mb = mp;
+	pem->pem_qptr = WR(q);
+	pem->pem_id = 0x1234;
+	WR(q)->q_ptr = q->q_ptr = (caddr_t)pem;
+	pem->pem_minor = minordev;
+
+	inst->pi_pem = pem;
+	inst->pi_queue = WR(q);
+
+	qprocson(q);		/* start the queues running */
+	qenable(WR(q));
+	return (0);
+}
+
+/*
+ * pem_close(q) normal stream close call checks current status and cleans up
+ * data structures that were dynamically allocated
+ */
+/* ARGSUSED */
+static int
+pem_close(queue_t *q, int flag, cred_t *cred)
+{
+	pem_t	*pem = (pem_t *)q->q_ptr;
+	struct pem_inst *inst;
+	int minor;
+
+	ASSERT(q);
+	ASSERT(pem);
+
+	qprocsoff(q);
+
+	mutex_enter(&pem_global_lock);
+	/* disassociate the stream from the device */
+	q->q_ptr = WR(q)->q_ptr = NULL;
+
+	if (pem != NULL && pem_instances != NULL) {
+		inst = (struct pem_inst *)ddi_get_soft_state(pem_instances,
+							pem->pem_minor);
+		if (inst != NULL) {
+
+			minor = pem->pem_minor;
+			pem_minors &= ~(1 << minor);
+
+			freeb(pem->pem_mb);
+			inst->pi_pem = NULL;
+			inst->pi_queue = NULL;
+			ddi_soft_state_free(pem_instances, minor);
+		}
+	}
+
+	mutex_exit(&pem_global_lock);
+
+	return (0);
+}
+
+/*
+ * pem_wput(q, mp)
+ * general pem stream write put routine. Receives ioctl's from
+ * user level and data from upper modules and processes them immediately.
+ * M_PROTO/M_PCPROTO are queued for later processing by the service
+ * procedure.
+ */
+
+static int
+pem_wput(q, mp)
+	queue_t *q;		/* queue pointer */
+	mblk_t *mp;		/* message pointer */
+{
+	int err = 0;
+#ifdef PEM_DEBUG
+	if (pem_debug & PEMTRACE)
+		cmn_err(CE_CONT, "pem_wput(%p %p): type %x\n",
+			(void *)q, (void *)mp, DB_TYPE(mp));
+#endif
+
+	switch (DB_TYPE(mp)) {
+	case M_IOCTL:		/* no waiting in ioctl's */
+		err = pem_ioctl(q, mp);
+		break;
+
+	case M_FLUSH:		/* canonical flush handling */
+		if (*mp->b_rptr & FLUSHW)
+			flushq(q, 0);
+		if (*mp->b_rptr & FLUSHR) {
+			flushq(RD(q), 0);
+			*mp->b_rptr &= ~FLUSHW;
+			qreply(q, mp);
+		} else
+			freemsg(mp);
+		break;
+
+	case M_PROTO:
+	case M_PCPROTO:
+		/* for now, we will always queue  proto messages */
+		(void) putq(q, mp);
+		break;
+
+	case M_DATA:
+		/* force a fatal error */
+		merror(q, mp, EIO);
+		break;
+	default:
+#ifdef PEM_DEBUG
+		if (pem_debug & PEMERRS)
+			cmn_err(CE_CONT,
+				"pem: Unexpected packet type from queue: %x\n",
+				DB_TYPE(mp));
+#endif
+		freemsg(mp);
+		break;
+	}
+	return (err);
+}
+
+/*
+ * pem_wsrv - Incoming messages are processed according to the DLPI protocol
+ * specification
+ */
+static int
+pem_wsrv(q)
+	queue_t *q;		/* queue pointer */
+{
+	mblk_t *mp;
+	int	err = 0;
+
+#ifdef PEM_DEBUG
+	if (pem_debug & PEMTRACE)
+		cmn_err(CE_CONT, "pem_wsrv(%p)\n", (void *)q);
+#endif
+
+
+	while ((mp = getq(q)) != NULL) {
+		switch (DB_TYPE(mp)) {
+		case M_IOCTL:
+			/* case where we couldn't do it in the put procedure */
+			err = pem_ioctl(q, mp);
+			break;
+		case M_PROTO:	/* Will be an PM message of some type */
+		case M_PCPROTO:
+			if ((err = pem_cmds(q, mp)) != PEME_OK) {
+				pem_error(q, mp, err, 0, 0);
+			}
+			break;
+		case M_DATA:
+			freemsg(mp);
+			(void) putctl1(RD(q), M_ERROR, EIO);
+			break;
+
+			/* This should never happen */
+		default:
+#ifdef PEM_DEBUG
+			if (pem_debug & PEMERRS)
+				cmn_err(CE_CONT,
+					"pem_wsrv: db_type(%x) not supported\n",
+					mp->b_datap->db_type);
+#endif
+			freemsg(mp);	/* unknown types are discarded */
+			break;
+		}
+	}
+	return (err);
+}
+
+/*
+ * pem_rsrv(q)
+ *	simple read service procedure
+ *	purpose is to avoid the time it takes for packets
+ *	to move through IP so we can get them off the board
+ *	as fast as possible due to limited PC resources.
+ */
+static int
+pem_rsrv(queue_t *q)
+{
+	mblk_t *mp;
+	while ((mp = getq(q)) != NULL) {
+		putnext(q, mp);
+	}
+	return (0);
+}
+
+/*
+ * pem_ioctl(q, mp)
+ * handles all ioctl requests passed downstream. This routine is
+ * passed a pointer to the message block with the ioctl request in it, and a
+ * pointer to the queue so it can respond to the ioctl request with an ack.
+ */
+static int
+pem_ioctl(queue_t *q, mblk_t *mp)
+{
+	struct iocblk *iocp;
+
+#ifdef PEM_DEBUG
+	if (pem_debug & PEMTRACE)
+		cmn_err(CE_CONT, "pem_ioctl(%p %p)\n", (void *)q, (void *)mp);
+#endif
+	iocp = (struct iocblk *)mp->b_rptr;
+	switch (iocp->ioc_cmd) {
+	default:
+		miocnak(q, mp, 0, EINVAL);
+		break;
+	}
+	return (0);
+}
+
+/*
+ * pem_cmds(q, mp)
+ *	process the PM commands as defined in em.h
+ *	note that the primitives return status which is passed back
+ *	to the service procedure.
+ */
+static int
+pem_cmds(q, mp)
+	queue_t *q;		/* queue pointer */
+	mblk_t *mp;		/* message pointer */
+{
+	int result = EINVAL;
+	union em_primitives *prim = (union em_primitives *)mp->b_rptr;
+
+#ifdef PEM_DEBUG
+	if (pem_debug & PEMTRACE)
+		cmn_err(CE_CONT,
+			"pem_cmds(%p, %p):pem=(N/A), prim->em_primitive=%d\n",
+			(void *)q, (void *)mp, (int)prim->em_primitive);
+#endif
+
+	switch (prim->em_primitive) {
+	case EM_INIT_REQ:
+		result = pem_init_req(q, mp, &prim->init_req);
+		break;
+	case EM_INFO_REQ:
+		result = pem_info_req(q, mp, &prim->info_req);
+		break;
+	case EM_MODIFY_EVENT_MASK_REQ:
+		result = pem_modify_event_req(q, mp,
+						&prim->modify_event_mask_req);
+		break;
+
+	case EM_ADAPTER_INFO_REQ:
+		result = pem_adapter_info(q, mp);
+		break;
+	case EM_SOCKET_INFO_REQ:
+		result = pem_socket_info(q, mp);
+		break;
+	case EM_GET_SOCKET_REQ:
+		result = pem_get_socket(q, mp);
+		break;
+	case EM_IDENT_SOCKET_REQ:
+		result = pem_ident_socket(q, mp);
+		break;
+	default:
+#ifdef PEM_DEBUG
+		if (pem_debug & PEMERRS)
+			cmn_err(CE_CONT,
+				"pem_cmds: unknown M_PROTO message: %d\n",
+				(int)prim->em_primitive);
+#endif
+		result = EM_BADPRIM;
+	}
+	return (result);
+}
+
+/*
+ * pem_info_req - generate the response to an info request
+ */
+/* ARGSUSED */
+static int
+pem_info_req(queue_t *q, mblk_t *mp, em_info_req_t *inforeq)
+{
+	pem_t  *pem;
+	int bufsize;
+	em_info_ack_t *infoack;
+
+#ifdef PEM_DEBUG
+	if (pem_debug & PEMTRACE)
+		cmn_err(CE_CONT, "pem_inforeq(%p %p)\n", (void *)q, (void *)mp);
+#endif
+	pem = (pem_t *)q->q_ptr;
+	ASSERT(pem);
+
+	bufsize = sizeof (em_info_ack_t) + EM_EVENT_SIZE * 2;
+	mp = mexchange(q, mp, bufsize, M_PCPROTO, EM_INFO_ACK);
+	if (mp) {
+		infoack = (em_info_ack_t *)mp->b_rptr;
+		bzero((caddr_t)infoack, bufsize);
+		infoack->em_state = pem->pem_state;
+		infoack->em_version = EM_CURRENT_VERSION;
+		if (pem->pem_flags & PEMF_EVENTS) {
+			infoack->em_event_mask_length = EM_EVENT_SIZE;
+			infoack->em_event_mask_offset = sizeof (em_info_ack_t);
+			bcopy((caddr_t)pem->pem_event_mask,
+				(caddr_t)mp->b_rptr +
+				infoack->em_event_mask_offset, EM_EVENT_SIZE);
+		}
+		if (pem->pem_flags & PEMF_CLASSES) {
+			infoack->em_event_class_length = EM_CLASS_SIZE;
+			infoack->em_event_class_offset =
+				sizeof (em_info_ack_t) +
+				infoack->em_event_mask_length;
+			bcopy((caddr_t)pem->pem_event_class,
+				(caddr_t)mp->b_rptr +
+				infoack->em_event_class_offset, EM_CLASS_SIZE);
+		}
+		qreply(q, mp);
+	}
+
+	return (PEME_OK);
+}
+
+/*
+ * pem_init_req - initialize the open stream to receive events, etc.
+ */
+
+static int
+pem_init_req(queue_t *q, mblk_t *mp, em_init_req_t *initreq)
+{
+	uchar_t *event, *class;
+	pem_t *pem = (pem_t *)q->q_ptr;
+
+	if (pem == NULL) {
+		cmn_err(CE_CONT, "pem_init_req: no pem\n");
+		return (PEME_UNAVAILABLE);
+	}
+	pem_flushqueue(q);
+
+	if (initreq->em_event_mask_offset != 0)
+		event = ((uchar_t *)initreq) + initreq->em_event_mask_offset;
+	else
+		event = NULL;
+	if (initreq->em_event_class_offset != 0)
+		class = ((uchar_t *)initreq) + initreq->em_event_class_offset;
+	else
+		class = NULL;
+
+	if (event != NULL && initreq->em_event_mask_length <= EM_EVENT_SIZE) {
+		bcopy((caddr_t)event, (caddr_t)pem->pem_event_mask,
+			initreq->em_event_mask_length);
+		pem->pem_flags |= PEMF_EVENTS;
+	}
+	if (class != NULL && initreq->em_event_mask_length <= EM_CLASS_SIZE) {
+		bcopy((caddr_t)class, (caddr_t)pem->pem_event_class,
+			initreq->em_event_class_length);
+		pem->pem_flags |= PEMF_CLASSES;
+	}
+#if	defined(PEM_DEBUG)
+	if (pem_debug) {
+		cmn_err(CE_CONT, "pem_init_req:\n");
+		cmn_err(CE_CONT, "\tevent mask = %x (len=%d)\n",
+			(int)(*(uint32_t *)event),
+			(int)initreq->em_event_mask_length);
+	}
+#endif
+	pem->pem_flags |= PEMF_INIT;
+	pem->pem_state = EM_INIT;
+
+	mp = mexchange(q, mp, sizeof (em_init_ack_t), M_PCPROTO, EM_INIT_ACK);
+	if (mp != NULL)
+		qreply(q, mp);
+
+	return (PEME_OK);
+}
+
+int
+pem_get_first_tuple(queue_t *q, mblk_t *mp, em_get_first_tuple_req_t *treq)
+{
+	tuple_t tuple;
+	cisinfo_t cisinfo;
+	int result, len;
+	cisparse_t parse;
+
+	if (pem_cs_handle == 0) {
+		return (PEME_UNAVAILABLE);
+	}
+	if (cardservices(ValidateCIS, pem_cs_handle, &cisinfo) != SUCCESS) {
+		return (PEME_NO_CIS);
+	}
+
+	tuple.DesiredTuple = treq->em_desired_tuple;
+	tuple.Socket = treq->em_socket;
+
+	if ((result = cardservices(GetFirstTuple, pem_cs_handle, &tuple)) !=
+	    SUCCESS) {
+		pem_error(q, mp, EM_GET_FIRST_TUPLE_REQ, PEME_NO_TUPLE,
+				result);
+		return (PEME_OK);
+	}
+
+	/* now have a tuple so lets construct a proper response */
+
+	len = tuple.TupleDataLen; /* start assuming length of raw data */
+	len += sizeof (em_get_next_tuple_ack_t);
+	mp = mexchange(q, mp, len, M_PROTO, EM_GET_FIRST_TUPLE_ACK);
+	if (mp == NULL)
+		return (PEME_OK);
+
+	result = cardservices(ParseTuple, pem_cs_handle, &tuple, &parse, NULL);
+	if (result == CS_SUCCESS) {
+		mp->b_cont = allocb(sizeof (cisinfo_t), BPRI_MED);
+		if (mp->b_cont)
+			mp->b_cont->b_wptr += sizeof (cisinfo_t);
+	}
+	qreply(q, mp);
+	return (0);
+}
+
+/*
+ * pem_flushqueue(q)
+ *	used by DLPI primitives that require flushing the queues.
+ *	essentially, this is DL_UNBIND_REQ.
+ */
+static void
+pem_flushqueue(queue_t *q)
+{
+	/* flush all data in both queues */
+	flushq(q, FLUSHDATA);
+	flushq(WR(q), FLUSHDATA);
+	/* flush all the queues upstream */
+	(void) putctl1(q, M_FLUSH, FLUSHRW);
+}
+
+static int
+pem_claim(struct pem_event *pe)
+{
+	int result = 0;
+	mutex_enter(&pem_intr_lock);
+	if (pe->pe_owner == PE_OWN_FREE) {
+		result++;
+		pe->pe_owner++;
+	}
+	mutex_exit(&pem_intr_lock);
+	return (result);
+}
+
+static void
+pem_event_ind(queue_t *q, uint32_t event, uint32_t socket, void *arg)
+{
+	mblk_t *mp;
+	int len;
+	em_event_ind_t *ind;
+
+	len = sizeof (em_event_ind_t);
+	switch (event) {
+	case PCE_DEV_IDENT:
+		len += strlen((char *)arg) + 1;
+		break;
+	case PCE_INIT_DEV:
+		len += sizeof (struct pcm_make_dev);
+		break;
+	}
+
+	mp = allocb(len + sizeof (struct pem_event), BPRI_MED);
+	if (mp == NULL)
+		return;
+	mp->b_cont = NULL;
+	DB_TYPE(mp) = M_PROTO;
+	ind = (em_event_ind_t *)(mp->b_rptr);
+	mp->b_wptr += len;
+
+	ind->em_primitive = EM_EVENT_IND;
+	ind->em_logical_socket = socket;
+	ind->em_event = event;
+	switch (event) {
+		struct pcm_make_dev *devp;
+	case PCE_DEV_IDENT:
+		ind->em_event_info_offset = sizeof (em_event_ind_t);
+		ind->em_event_info_length = strlen((char *)arg) + 1;
+		(void) strncpy((char *)mp->b_rptr + sizeof (em_event_ind_t),
+			(char *)arg, PEMMAXINFO - 1);
+		break;
+	case PCE_INIT_DEV:
+		ind->em_event_info_offset = sizeof (em_event_ind_t);
+		ind->em_event_info_length = sizeof (struct pcm_make_dev);
+		devp = (struct pcm_make_dev *)arg;
+		bcopy((caddr_t)devp,
+			(caddr_t)(mp->b_rptr + sizeof (em_event_ind_t)),
+			PEMMAXINFO);
+		break;
+	}
+	(void) putq(q, mp);
+}
+
+/* ARGSUSED */
+uint32_t
+pem_soft_intr(caddr_t arg)
+{
+	int i;
+	struct pem_event *pe;
+	int serviced = 0;
+
+	do {
+		mutex_enter(&pem_intr_lock);
+		pem_softint_pend = 0;
+		mutex_exit(&pem_intr_lock);
+
+		for (i = 0, pe = pem_events; i < PEM_MAX_EVENTS; i++, pe++) {
+			if (pe->pe_owner == PE_OWN_HANDLER) {
+				/* have an event */
+				pem_event_dispatch(pe->pe_id, pe->pe_event,
+							pe->pe_socket,
+							pe->pe_info);
+				mutex_enter(&pem_intr_lock);
+				pe->pe_owner = PE_OWN_FREE;
+				serviced = 1;
+				pem_softint_posted--;
+				mutex_exit(&pem_intr_lock);
+			}
+		}
+	} while (pem_softint_pend);
+
+	if (serviced)
+		return (DDI_INTR_CLAIMED);
+	return (DDI_INTR_UNCLAIMED);
+}
+
+static void
+pem_event_dispatch(int id, int event, int socket, void *arg)
+{
+	uint32_t minors;
+	int i;
+	struct pem_inst *inst;
+	pem_t *pem;
+	queue_t *q;
+
+#if	defined(PEM_DEBUG)
+	if (pem_debug)
+		cmn_err(CE_CONT, "pem_event_dispatch(%x, %x, %x, %p)\n",
+			id, event, socket, (void *)arg);
+#endif
+	if (pem_instances == NULL)
+		return;
+	mutex_enter(&pem_global_lock);
+	for (i = 0, minors = pem_minors;
+		minors != 0 && i < 4; minors >>= 1, i++) {
+		if (minors & 1) {
+			inst = ddi_get_soft_state(pem_instances, i);
+			if (inst == NULL) {
+				continue;
+			}
+			pem = inst->pi_pem;
+			if (pem == NULL)
+				continue;
+#if	defined(PEM_DEBUG)
+			if (pem_debug)
+				cmn_err(CE_CONT,
+					"\tflags=%x, id=%x, wanted=%d\n",
+					(int)pem->pem_flags,
+					(int)pem->pem_id,
+					PR_GET(pem->pem_event_mask, event));
+#endif
+			if (pem->pem_flags & PEMF_EVENTS &&
+			    pem->pem_id == id &&
+			    PR_GET(pem->pem_event_mask, event)) {
+				q = pem->pem_qptr;
+				pem_event_ind(RD(q), event, socket, arg);
+			}
+		}
+	}
+	mutex_exit(&pem_global_lock);
+}
+
+static int
+pem_event_handler(int id, int event, int socket, void *arg)
+{
+	int i;
+	struct pem_event *pe;
+	int didevents = 0;
+
+#if	defined(PEM_DEBUG)
+	if (pem_debug)
+		cmn_err(CE_CONT, "pem_event_handler(%x, %x, %x, %p)\n",
+			id, event, socket, (void *)arg);
+#endif
+	for (i = 0, pe = pem_events; i < PEM_MAX_EVENTS; i++, pe++) {
+		if (pem_claim(pe)) {
+			pe->pe_event = event;
+			pe->pe_socket = socket;
+			pe->pe_id = id;
+			pe->pe_owner ++; /* give to soft int */
+			switch (event) {
+				struct pcm_make_dev *devp;
+			case PCE_DEV_IDENT:
+				if (arg != NULL)
+					(void) strncpy((char *)pe->pe_info,
+						(char *)arg,
+						MODMAXNAMELEN);
+				break;
+			case PCE_INIT_DEV:
+				devp = (struct pcm_make_dev *)arg;
+				if (arg != NULL)
+					bcopy((caddr_t)devp,
+						(caddr_t)pe->pe_info,
+						PEMMAXINFO);
+			}
+			didevents = 1;
+			break;
+		}
+	}
+	mutex_enter(&pem_intr_lock);
+	if (didevents && pem_intr_id != 0) {
+		pem_softint_pend = 1;
+		pem_softint_posted++;
+		mutex_exit(&pem_intr_lock);
+		ddi_trigger_softintr(pem_intr_id);
+	} else
+		mutex_exit(&pem_intr_lock);
+	return (0);
+}
+
+/* ARGSUSED */
+static void
+pem_error(queue_t *q, mblk_t *mp, int primitive, int error, int suberr)
+{}
+
+/* ARGSUSED */
+static int
+pem_modify_event_req(queue_t *q, mblk_t *mp, em_modify_event_mask_req_t *req)
+{
+	return (0);
+}
+
+static int
+pem_adapter_info(queue_t *q, mblk_t *mp)
+{
+	inquire_adapter_t adapt;
+
+	if (Socket_Services(SS_InquireAdapter, &adapt) == SUCCESS) {
+		int bufsize;
+
+		bufsize = sizeof (em_adapter_info_ack_t);
+		bufsize += adapt.NumPower * sizeof (struct power_entry);
+
+		mp = mexchange(q, mp, bufsize, M_PCPROTO, EM_ADAPTER_INFO_ACK);
+		if (mp != NULL) {
+			em_adapter_info_ack_t *ack;
+			ack = (em_adapter_info_ack_t *)(mp->b_rptr);
+			mp->b_wptr = mp->b_rptr + bufsize;
+			ack->em_num_sockets = adapt.NumSockets;
+			ack->em_num_windows = adapt.NumWindows;
+			ack->em_num_power = adapt.NumPower;
+			if (adapt.NumPower > 0) {
+				ack->em_power_offset =
+					sizeof (em_adapter_info_ack_t);
+				ack->em_power_length = adapt.NumPower *
+					sizeof (struct power_entry);
+				bcopy((caddr_t)adapt.power_entry,
+					(caddr_t)mp->b_rptr +
+					ack->em_power_offset,
+					ack->em_power_length);
+			}
+			(void) putq(RD(q), mp);
+		}
+	}
+	return (PEME_OK);
+}
+
+static int
+pem_socket_info(queue_t *q, mblk_t *mp)
+{
+	inquire_socket_t socket;
+	em_socket_info_ack_t *ack;
+	em_socket_info_req_t *req;
+
+	req = (em_socket_info_req_t *)(mp->b_rptr);
+	socket.socket = req->em_socket;
+	if (Socket_Services(SS_InquireSocket, &socket) == SUCCESS) {
+		mp = mexchange(q, mp, sizeof (em_socket_info_ack_t),
+				M_PCPROTO, EM_SOCKET_INFO_ACK);
+		if (mp != NULL) {
+			ack = (em_socket_info_ack_t *)(mp->b_rptr);
+			mp->b_wptr = mp->b_rptr +
+				sizeof (em_socket_info_ack_t);
+			bzero(mp->b_rptr, sizeof (em_socket_info_ack_t));
+			ack->em_status_int_caps = socket.SCIntCaps;
+			ack->em_status_report_caps = socket.SCRptCaps;
+			ack->em_control_indicator_caps = socket.CtlIndCaps;
+			ack->em_socket_caps = socket.SocketCaps;
+			(void) putq(RD(q), mp);
+		}
+	}
+	return (PEME_OK);
+}
+
+static int
+pem_get_socket(queue_t *q, mblk_t *mp)
+{
+	get_socket_t socket;
+	em_get_socket_ack_t *ack;
+	em_get_socket_req_t *req;
+
+	req = (em_get_socket_req_t *)(mp->b_rptr);
+	socket.socket = req->em_socket;
+
+	if (Socket_Services(SS_GetSocket, &socket) == SUCCESS) {
+		mp = mexchange(q, mp, sizeof (em_get_socket_ack_t),
+				M_PCPROTO, EM_GET_SOCKET_ACK);
+		mp->b_wptr = mp->b_rptr + sizeof (em_get_socket_ack_t);
+		ack = (em_get_socket_ack_t *)(mp->b_rptr);
+		ack->em_socket = socket.socket;
+		ack->em_vcc_level = socket.VccLevel;
+		ack->em_vpp1_level = socket.Vpp1Level;
+		ack->em_vpp2_level = socket.Vpp2Level;
+		ack->em_state = socket.state;
+		ack->em_control_ind = socket.CtlInd;
+		ack->em_ireq_routing = socket.IRQRouting;
+		ack->em_iftype = socket.IFType;
+	}
+	return (PEME_OK);
+}
+
+/*
+ * pem_ident_socket()
+ *	This primitive triggers artificial events for the
+ *	socket. It basically recreates those events that
+ *	have occurred on the socket up to this point in time
+ */
+static int
+pem_ident_socket(queue_t *q, mblk_t *mp)
+{
+	dev_info_t *dip;
+	em_ident_socket_req_t *ident = (em_ident_socket_req_t *)mp->b_rptr;
+	int num_minors, i;
+	struct pcm_make_dev *minors;
+
+	dip = (dev_info_t *)pcmcia_get_devinfo(ident->em_socket);
+	if (dip == NULL)
+		return (PEME_NO_INFO);
+
+	/* OK, have at least a name available */
+
+	pem_event_ind(RD(q), PCE_DEV_IDENT, ident->em_socket,
+			(void *)ddi_get_name(dip));
+
+	num_minors = pcmcia_get_minors(dip, &minors);
+
+	for (i = 0; i < num_minors; i++) {
+		pem_event_ind(RD(q), PCE_INIT_DEV, ident->em_socket,
+				(void *)(minors + i));
+	}
+	if (num_minors > 0)
+		kmem_free(minors, num_minors * sizeof (struct pcm_make_dev));
+	return (PEME_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/pcmcia/pem/pem.conf	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,28 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 1992, by Sun Microsystems, Inc.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+#
+name="pem" parent="pseudo";
--- a/usr/src/uts/common/sys/Makefile	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/uts/common/sys/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -352,6 +352,7 @@
 	pci_impl.h		\
 	pcmcia.h		\
 	pctypes.h		\
+	pem.h			\
 	pfmod.h			\
 	pm.h			\
 	policy.h		\
@@ -567,7 +568,8 @@
 BSCHDRS=			\
 	lom_ebuscodes.h		\
 	lom_io.h		\
-	lom_priv.h
+	lom_priv.h		\
+	lombus.h
 
 MDESCHDRS=			\
 	mdesc.h			\
@@ -888,6 +890,8 @@
 	avintr.h	\
 	dma_engine.h	\
 	i8272A.h	\
+	pcic_reg.h	\
+	pcic_var.h	\
 	pic.h		\
 	pit.h		\
 	rtc.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/lombus.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef	_SYS_LOMBUS_H
+#define	_SYS_LOMBUS_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * Information for client (child) drivers:
+ *
+ *	Register space definitions
+ *	Fault info access
+ *	Fault codes
+ *
+ * LOMbus child regspecs are triples, in the form
+ * 	<space>, <base>, <size>
+ */
+typedef struct {
+	int lombus_space;
+	int lombus_base;
+	int lombus_size;
+} lombus_regspec_t;
+
+#define	LOMBUS_REGSPEC_SIZE	3	/* words/regspec */
+
+
+/*
+ * Register spaces
+ *
+ *	Space	Size	Range		Meaning
+ *		(bits)
+ *
+ *	0	8	[0 .. 16383]	LOM virtual registers
+ *	1	8	[0]		Watchdog pat (on write)
+ *	2	16	[0]		Async event info (read only)
+ *	All	32	[-4 .. -12]	Access handle fault info
+ */
+#define	LOMBUS_VREG_SPACE	(0)
+#define	LOMBUS_PAT_SPACE	(1)
+#define	LOMBUS_EVENT_SPACE	(2)
+
+#define	LOMBUS_MAX_REG		(16383)		/* space 0: [0..16383]	*/
+#define	LOMBUS_PAT_REG		(0)		/* space 1: [0]		*/
+#define	LOMBUS_EVENT_REG	(0)		/* space 2: [0]		*/
+
+#define	LOMBUS_FAULT_REG	(-4)		/* 32-bit only, R/W	*/
+#define	LOMBUS_PROBE_REG	(-8)		/* 32-bit only, R/W	*/
+#define	LOMBUS_ASYNC_REG	(-12)		/* 32-bit only, R/O	*/
+
+
+/*
+ * Internally-generated errors
+ *
+ * Note: LOM-generated errors are 0x00-0x7f and SunVTS uses 0x80-0xff,
+ * so these start at 0x100
+ */
+enum lombus_errs {
+	LOMBUS_ERR_BASE = 0x100,
+
+	/*
+	 * Errors in the way the child is accessing the virtual registers.
+	 * These are programming errors and won't go away on retry!
+	 */
+	LOMBUS_ERR_REG_NUM,		/* register number out of range	*/
+	LOMBUS_ERR_REG_RO,		/* write to read-only register	*/
+	LOMBUS_ERR_REG_SIZE,		/* access with invalid size	*/
+
+	/*
+	 * Error accessing the underlying SIO hardware
+	 * This is unlikely to be recoverable.
+	 */
+	LOMBUS_ERR_SIOHW = 0x110,
+
+	/*
+	 * Errors in the LOMbus <-> LOM firmware protocol
+	 * These may or may not be recoverable, depending
+	 * on the state of the LOM.
+	 */
+	LOMBUS_ERR_TIMEOUT = 0x120,	/* no response from LOM		*/
+	LOMBUS_ERR_OFLOW,		/* rcv buf oflo - LOM babbling?	*/
+	LOMBUS_ERR_SEQUENCE,		/* cmd/reply sequence mismatch	*/
+	LOMBUS_ERR_BADSTATUS,		/* bad status byte in reply pkt	*/
+	LOMBUS_ERR_BADERRCODE		/* invalid error code in reply	*/
+};
+
+
+/*
+ * Time periods, in nanoseconds
+ */
+#define	LOMBUS_ONE_SEC		1000000000LL
+#define	LOMBUS_MIN_PAT		(LOMBUS_ONE_SEC/5)
+#define	LOMBUS_CMD_TIMEOUT	(LOMBUS_ONE_SEC*5)
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_LOMBUS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/pcic_reg.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,631 @@
+/*
+ * 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.
+ */
+
+/*
+ * Intel 82365SL device and register definitions
+ */
+
+#ifndef _PCIC_REG_H
+#define	_PCIC_REG_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * global information
+ */
+#define	PCIC_MAX_CONTROLLERS	4 /* maximum of 4 chips in system */
+
+/*
+ * per socket information
+ */
+
+#define	PCIC_SOCKETS	2	/* number of sockets per PCIC chip */
+#define	PCIC_MEMWINDOWS	5	/* number of memory windows per socket */
+#define	PCIC_IOWINDOWS	2	/* number of I/O address windows per socket */
+/* number of windows per chip */
+#define	PCIC_NUMWINDOWS ((PCIC_MEMWINDOWS + PCIC_IOWINDOWS) * PCIC_SOCKETS)
+/* number of windows per socket */
+#define	PCIC_NUMWINSOCK	(PCIC_MEMWINDOWS+PCIC_IOWINDOWS)
+
+/*
+ * socket selection registers
+ *
+ * the PCIC allows up to 8 sockets per system
+ * this is done by having two sockets per chip and up to 4 chips per
+ * system.  There can be up to 4 sockets (2 PCIC chips) per I/O address.
+ * There are two possible I/O address (index register) values.
+ * socket#	I/O address	value to write to index register
+ *   0		INDEX_REG0	BASE0 + SOCKET_0 + register offset
+ *   1		INDEX_REG0	BASE0 + SOCKET_1 + register offset
+ *   2		INDEX_REG0	BASE1 + SOCKET_0 + register offset
+ *   3		INDEX_REG0	BASE1 + SOCKET_1 + register offset
+ * next 4 are based off of INDEX_REG1
+ */
+
+#define	PCIC_INDEX_REG0	0x3e0	/* first possible index register */
+#define	PCIC_INDEX_REG1	0x3e2	/* second possible index register */
+
+#define	PCIC_BASE0	0x00	/* first set of sockets */
+#define	PCIC_BASE1	0x80	/* second set of sockets */
+
+#define	PCIC_SOCKET_0	0x00	/* first socket */
+#define	PCIC_SOCKET_1	0x40	/* second socket */
+
+#define	PCIC_DATA_REG0	(PCIC_INDEX_REG0+1)
+#define	PCIC_DATA_REG1	(PCIC_INDEX_REG1+1)
+
+/*
+ * per socket register
+ * these are accessed by writing the offset value into the
+ * index register and adding the appropriate base offset and socket offset
+ * the register is then present in the data register.
+ */
+
+/* General Registers */
+
+#define	PCIC_CHIP_REVISION	0x00 /* identification and revision */
+#define	PCIC_INTERFACE_STATUS	0x01 /* Interface status */
+#define	PCIC_POWER_CONTROL	0x02 /* Power and RESETDRV control */
+#define	PCIC_CARD_STATUS_CHANGE	0x04 /* card status change */
+#define	PCIC_MAPPING_ENABLE	0x06 /* address window mapping enable */
+#define	PCIC_CARD_DETECT	0x16 /* card detect&general control register */
+#define	PCIC_MISC_CTL_1		0x16 /* CL version */
+#define	PCIC_GLOBAL_CONTROL	0x1e /* global control register */
+#define	PCIC_MISC_CTL_2		0x1e /* CL version */
+#define	PCIC_CHIP_INFO		0x1f /* Cirrus Logic chip info register */
+
+/* Interrupt Registers */
+
+#define	PCIC_INTERRUPT		0x03 /* interrupt & general control register */
+#define	PCIC_MANAGEMENT_INT	0x05 /* card status change interrupt register */
+
+/* I/O Registers */
+
+#define	PCIC_IO_CONTROL		0x07 /* I/O Control register */
+#define	PCIC_IO_ADDR_0_STARTLOW	0x08 /* I/O address map 0 start low byte */
+#define	PCIC_IO_ADDR_0_STARTHI	0x09 /* I/O address map 0 start high byte */
+#define	PCIC_IO_ADDR_0_STOPLOW	0x0a /* I/O address map 0 stop low byte */
+#define	PCIC_IO_ADDR_0_STOPHI	0x0b /* I/O address map 0 stop high byte */
+#define	PCIC_IO_OFFSET_LOW	0x36 /* I/O Offset for CL */
+#define	PCIC_IO_OFFSET_HI	0x37
+#define	PCIC_IO_OFFSET_OFFSET	2
+
+#define	PCIC_IO_ADDR_1_OFFSET	5 /* offset to second I/O map register set */
+#define	PCIC_IO_WIN_MASK	0xf
+
+/* Memory Registers */
+				/* window 0 */
+#define	PCIC_SYSMEM_0_STARTLOW	0x10 /* system memory map 0 start low byte */
+#define	PCIC_SYSMEM_0_STARTHI	0x11 /* system memory map 0 start high byte */
+#define	PCIC_SYSMEM_0_STOPLOW	0x12 /* system memory map 0 stop low byte */
+#define	PCIC_SYSMEM_0_STOPHI	0x13 /* system memory map 0 stop high byte */
+#define	PCIC_CARDMEM_0_LOW	0x14 /* card memory offset 0 low byte */
+#define	PCIC_CARDMEM_0_HI	0x15 /* card memory offset 0 high byte */
+
+				/* window 1 */
+#define	PCIC_SYSMEM_1_STARTLOW	0x18 /* system memory map 0 start low byte */
+#define	PCIC_SYSMEM_1_STARTHI	0x19 /* system memory map 0 start high byte */
+#define	PCIC_SYSMEM_1_STOPLOW	0x1a /* system memory map 0 stop low byte */
+#define	PCIC_SYSMEM_1_STOPHI	0x1b /* system memory map 0 stop high byte */
+#define	PCIC_CARDMEM_1_LOW	0x1c /* card memory offset 0 low byte */
+#define	PCIC_CARDMEM_1_HI	0x1d /* card memory offset 0 high byte */
+
+#define	PCIC_MEM_1_OFFSET	8 /* offset to second memory map register set */
+#define	PCIC_MEM_2_OFFSET	16
+#define	PCIC_MEM_3_OFFSET	24
+#define	PCIC_MEM_4_OFFSET	32
+
+#define	PCIC_IO_OFFSET		4 /* offset to next set of I/O map registers */
+
+/* Cirrus Logic specific registers */
+#define	PCIC_TIME_SETUP_0	0x3A
+#define	PCIC_TIME_SETUP_1	0x3D
+#define	PCIC_TIME_COMMAND_0	0x3B
+#define	PCIC_TIME_COMMAND_1	0x3E
+#define	PCIC_TIME_RECOVER_0	0x3C
+#define	PCIC_TIME_RECOVER_1	0x3F
+#define	PCIC_ATA_CONTROL	0x26
+#define	PCIC_FIFO_CONTROL	0x17
+#define	PCIC_CL_EXINDEX		0x2e
+#define	PCIC_CL_EXDATA		0x2f
+
+/*
+ * Cirrus Logic PCI-PCMCIA adapters extension register indicies
+ */
+#define	PCIC_CLEXT_SCRATCH	0x00
+#define	PCIC_CLEXT_DMASK_0	0x01
+#define	PCIC_CLEXT_EXT_CTL_1	0x03
+#define	PCIC_CLEXT_MMAP0_UA	0x05
+#define	PCIC_CLEXT_MMAP1_UA	0x06
+#define	PCIC_CLEXT_MMAP2_UA	0x07
+#define	PCIC_CLEXT_MMAP3_UA	0x08
+#define	PCIC_CLEXT_MMAP4_UA	0x09
+#define	PCIC_CLEXT_EXDATA	0x0a
+#define	PCIC_CLEXT_EXT_CTL_2	0x0b	/* 6729 */
+#define	PCIC_CLEXT_MISC_CTL_3	0x25	/* 6730 */
+#define	PCIC_CLEXT_SMB_CTL	0x26	/* 6730 */
+
+/* the 6832 is mapped into different offsets for extension regs */
+
+#define	PCIC_CBCLEXT_MMAP0_UA	0x40 /* minus the 0x800 */
+#define	PCIC_CBCLEXT_MMAP1_UA	0x41
+#define	PCIC_CBCLEXT_MMAP2_UA	0x42
+#define	PCIC_CBCLEXT_MMAP3_UA	0x43
+#define	PCIC_CBCLEXT_MMAP4_UA	0x44
+#define	PCIC_CBCLEXT_MMAP5_UA	0x45
+
+#define	PCIC_CLEXT_MISC_CTL_3_REV_MASK	0xf0
+
+/*
+ * Cirrus Logic PCI-PCMCIA PCIC_CLEXT_EXT_CTL_1 reg bit definitions
+ */
+#define	PCIC_CLEXT_IRQ_LVL_MODE	0x08
+#define	PCIC_CLEXT_SMI_LVL_MODE	0x00 /* see errata 1.0 */
+
+/*
+ * Cirrus Logic PCI-PCMCIA PCIC_MISC_CTL_2 reg bit definitions
+ */
+#define	PCIC_CL_LP_DYN_MODE	0x02	/* low-power dynamic mode */
+#define	PCIC_CL_TIMER_CLK_DIV	0x10	/* PCI clock divide */
+
+/*
+ * Cirrus Logic PCI-PCMCIA PCIC_CLEXT_MISC_CTL_3 reg bit definitions
+ */
+#define	PCIC_CLEXT_INT_PC_PCI	0x00
+#define	PCIC_CLEXT_INT_EXT_HW	0x01
+#define	PCIC_CLEXT_INT_PCI_WAY	0x10
+#define	PCIC_CLEXT_INT_PCI	0x03 /* see errata 1.0 */
+#define	PCIC_CLEXT_PWR_EXT_HW	0x00
+#define	PCIC_CLEXT_PWR_RESERVED	0x04
+#define	PCIC_CLEXT_PWR_TI	0x80
+#define	PCIC_CLEXT_PWR_SMB	0xc0
+
+/*
+ * Intel 82092-AA reg and bit definitions
+ */
+#define	PCIC_82092_PCICON	0x40	/* PCI configuration control */
+#define	PCIC_82092_PCICLK_25MHZ	0x01	/* 25MHz PCI clock */
+#define	PCIC_82092_SLOT_CONFIG	0x06	/* config mask */
+#define	PCIC_82092_2_SOCKETS	0x00	/* 2 sockets */
+#define	PCIC_82092_1_SOCKET	0x02	/* 1 socket + IDE */
+#define	PCIC_82092_4_SOCKETS	0x04	/* 4 sockets + IDE */
+#define	PCIC_82092_EN_TIMING	0x20	/* enhanced memory window timing */
+#define	PCIC_82092_PWB		0x08	/* Post Write Buffering */
+#define	PCIC_82092_RPFB		0x10	/* Read Prefetch Buffering */
+#define	PCIC_82092_PPIRR	0x50	/* interrupt routing register */
+#define	PCIC_82092_SMI_CTL(sock, state)	(state << (sock * 2))
+#define	PCIC_82092_IRQ_CTL(sock, state)	(state << ((sock * 2) + 1))
+#define	PCIC_82092_CTL_SMI	0x01
+#define	PCIC_82092_CTL_IRQ	0x02
+#define	PCIC_82092_INT_DISABLE	0x00
+#define	PCIC_82092_INT_ENABLE	0x01
+#define	PCIC_82092_CPAGE	0x26	/* CPAGE register */
+
+/*
+ * identification and revision register
+ */
+#define	PCIC_REV_ID_MASK	0xc0
+#define	PCIC_REV_ID_IO		0x00
+#define	PCIC_REV_ID_MEM		0x40
+#define	PCIC_REV_ID_BOTH	0x80
+
+/*
+ * interface status register bit definitions
+ */
+#define	PCIC_ISTAT_CD_MASK	0xC /* card detect mask */
+#define	PCIC_CD_PRESENT_OK	0xC /* card is present and fully seated */
+#define	PCIC_CD_NOTPRESENT	0x0 /* card not present */
+#define	PCIC_CD_NOTSEATED_1	0x8 /* card not fully seated */
+#define	PCIC_CD1		0x8
+#define	PCIC_CD_NOTSEATED_2	0x4 /* card not fully seated */
+#define	PCIC_CD2		0x4
+#define	PCIC_WRITE_PROTECT	0x10
+#define	PCIC_READY		0x20
+#define	PCIC_POWER_ON		0x40
+#define	PCIC_VPP_VALID		0x80
+#define	PCIC_BVD1		0x1
+#define	PCIC_BVD2		0x2
+
+/*
+ * memory register definitions
+ */
+#define	SYSMEM_LOW(x)		(((uint32_t)(x)>>12)&0xFF)
+#define	SYSMEM_HIGH(x)		(((uint32_t)(x)>>20)&0xF)
+#define	SYSMEM_EXT(x)		(((uint32_t)(x)>>24)&0xFF)
+#define	SYSMEM_WINDOW(x)	(1<<(x))
+#define	SYSMEM_ZERO_WAIT	0x40 /* zero wait state bit */
+#define	SYSMEM_DATA_16		0x80 /* 16 bit memory bit */
+#define	SYSMEM_MEM16		0x20 /* 16 bit memory in window enable */
+#define	SYSMEM_CLTIMER_SET_0	0x00
+#define	SYSMEM_CLTIMER_SET_1	0x80
+
+#define	SYSMEM_82092_600NS	0x0110
+#define	SYSMEM_82092_250NS	0x0101
+#define	SYSMEM_82092_200NS	0x0100
+#define	SYSMEM_82092_150NS	0x0011
+#define	SYSMEM_82092_100NS	0x0010
+#define	SYSMEM_82092_80NS	0x0001
+
+#define	DEFAULT_AM_ADDR		0xd0000
+
+#define	CARDMEM_REG_ACTIVE	0x40
+#define	CARDMEM_WRITE_PROTECT	0x80
+
+#define	CARDMEM_LOW(x)		(((uint32_t)((x))>>12)&0xFF)
+#define	CARDMEM_HIGH(x)		(((uint32_t)((x))>>20)&0x3F)
+
+#define	POWER_CARD_ENABLE	0x10
+#define	POWER_3VCARD_ENABLE	0x18
+#define	POWER_OUTPUT_ENABLE	0x80
+#define	POWER_VPP_VCC_ENABLE	0x01
+#define	POWER_VPP_12V_ENABLE	0x02
+
+/* interrupt register definitions */
+#define	PCIC_INTR_ENABLE	0x10
+#define	PCIC_IO_CARD		0x20
+#define	PCIC_RESET		0x40
+#define	PCIC_INTR_MASK		0x0f
+
+/* card status change register definitions */
+#define	PCIC_CD_DETECT		0x08
+#define	PCIC_RD_DETECT		0x04
+#define	PCIC_BW_DETECT		0x02
+#define	PCIC_BD_DETECT		0x01
+#define	PCIC_CHANGE_MASK	0x0f
+
+/* card status change interrupt register definitions */
+#define	PCIC_CD_ENABLE		0x08 /* card detect enable */
+#define	PCIC_RD_ENABLE		0x04 /* ready change enable */
+#define	PCIC_BW_ENABLE		0x02 /* battery warning enable */
+#define	PCIC_BD_ENABLE		0x01 /* battery deat enable */
+#define	PCIC_GPI_CHANGE		0x10 /* general purpose interrupt */
+#define	PCIC_CHANGE_DEFAULT	(PCIC_CD_ENABLE|PCIC_RD_ENABLE|\
+					PCIC_BW_ENABLE|PCIC_BD_ENABLE)
+
+/* card detect change register */
+#define	PCIC_GPI_ENABLE		0x04
+#define	PCIC_GPI_TRANSITION	0x08
+#define	PCIC_16MDI		0x01
+#define	PCIC_SOFT_CD_INTR	0x20
+
+/* misc control 1 */
+#define	PCIC_MC_5VDETECT	0x01
+#define	PCIC_MC_3VCC		0x02
+#define	PCIC_MC_PULSE_SMI	0x04
+#define	PCIC_MC_PULSE_IRQ	0x08
+#define	PCIC_MC_SPEAKER_ENB	0x10
+#define	PCIC_MC_INPACK_ENB 	0x80
+
+/* global control registers definitions */
+#define	PCIC_GC_POWERDOWN	0x01
+#define	PCIC_GC_LEVELMODE	0x02
+#define	PCIC_GC_CSC_WRITE	0x04
+#define	PCIC_GC_IRQ1_PULSE	0x08
+
+/* misc control 2 */
+#define	PCIC_MC_BYPASS_FS	0x01
+#define	PCIC_MC_LOWPOWER	0x02
+#define	PCIC_MC_SUSPEND 	0x04
+#define	PCIC_5V_CORE		0x08
+#define	PCIC_LED_ENABLE		0x10
+#define	PCIC_THREESTATE		0x20
+#define	PCIC_CL_DMA		0x40
+#define	PCIC_IRQ15_RI_OUT	0x80
+
+/* chip info register (Cirrus) definitions */
+#define	PCIC_CI_ID	0xc0
+#define	PCIC_CI_SLOTS	0x20
+
+/* Vadem unique registers */
+#define	PCIC_VADEM_P1	0x0E
+#define	PCIC_VADEM_P2	0x37
+
+#define	PCIC_VG_VSENSE	0x1f
+#define	PCIC_VG_VSELECT	0x2f
+#define	PCIC_VG_CONTROL	0x38
+#define	PCIC_VG_TIMER	0x39
+#define	PCIC_VG_DMA	0x3A
+#define	PCIC_VG_EXT_A	0x3C
+#define	PCIC_VG_STATUS	0x3E
+
+/* Vadem DMA Register */
+#define	PCIC_V_DMAWSB	0x04
+#define	PCIC_V_VADEMREV	0x40
+#define	PCIC_V_UNLOCK	0x80
+
+/* Vadem identification register */
+#define	PCIC_VADEM_D3	0x8
+#define	PCIC_VADEM_365	0x9
+#define	PCIC_VADEM_465	0x8
+#define	PCIC_VADEM_468	0xB
+#define	PCIC_VADEM_469	0xC
+
+/* Vadem Voltage Select */
+#define	PCIC_VSEL_EXTENDED	0x10 /* extended mode */
+#define	PCIC_VSEL_BUSSEL	0x20 /* extended buffers on ISA */
+
+/* Vadem Control Register */
+#define	PCIC_VC_DELAYENABLE	0x10
+
+/* Vadem Extended Mode Register A */
+#define	PCIC_VEXT_CABLEMODE	0x08 /* enable external cable */
+
+#define	PCIC_YENTA_MEM_PAGE	0x40 /* yenta defined extended address byte */
+
+/* Ricoh Specific Registers */
+#define	PCIC_RF_CHIP_IDENT	0x3A
+#define	PCIC_RF_296		0x32
+#define	PCIC_RF_396		0xB2
+#define	PCIC_RF_MEM_PAGE	PCIC_YENTA_MEM_PAGE
+
+/* O2 Micro Specific registers */
+#define	PCIC_CENTDMA	0x3C
+#define	PCIC_MULTIFUNC	0x8C
+#define	PCIC_O2_CTRL1	0xD0
+#define	PCIC_O2_CTRL2	0xD4
+
+/* Texas Instruments specific Registers */
+#define	PCIC_INTLINE_REG	0x3C
+#define	PCIC_INTPIN_REG		0x3D
+#define	PCIC_BRIDGE_CTL_REG	0x3e
+#define	PCIC_FUN_INT_MOD_ISA	0x80
+
+/* for PCI1420 chip */
+#define	PCIC_BRDGCTL_INTR_MASK	0x80
+#define	PCIC_GPIO0_REG		0x88
+#define	PCIC_GPIO1_REG		0x89
+#define	PCIC_GPIO2_REG		0x8A
+#define	PCIC_GPIO3_REG		0x8B
+
+#define	PCIC_MFROUTE_REG	0x8c
+#define	PCIC_MFUNC0_MASK	0xF
+#define	PCIC_MFUNC0_INTA	0x2
+
+#define	PCIC_DIAG_REG		0x93
+#define	PCIC_GPIO_FMASK		0xC0
+#define	PCIC_GPIO_INTENBL	0x10
+#define	PCIC_GPIO_DELTA		0x08
+#define	PCIC_GPIO_DOUT		0x02
+#define	PCIC_GPIO_DIN		0x01
+#define	PCIC_GPIO_FOUTPUT	0xC0
+#define	PCIC_GPIO_FINPUT	0x80
+#define	PCIC_GPIO2_IS_PCILOCK	0x00
+#define	PCIC_GPIO3_IS_INTA	0x00
+#define	PCIC_TI_WINDOW_PAGE	0x3C /* legacy */
+#define	PCIC_TI_WINDOW_PAGE_PCI	0x40
+
+#define	PCIC_DIAG_REG		0x93 /* Diagnostic Register */
+/* for PCI1225 chip */
+#define	PCIC_DIAG_CSC		0x20 /* CSC Interrupt Routing Control */
+/* for PCI1221 and PCI1225 chips */
+#define	PCIC_DIAG_ASYNC		0x01 /* Async. interrupt enable */
+
+#define	PCIC_DEVCTL_REG		0x92 /* Device Control Register */
+#define	PCIC_DEVCTL_INTR_MASK	0x06 /* to mask out mode */
+#define	PCIC_DEVCTL_INTR_PCI	0x00 /* PCI style interrupts */
+#define	PCIC_DEVCTL_INTR_ISA	0x02 /* ISA style interrupts */
+#define	PCIC_DEVCTL_INTR_SER	0x04 /* serialize IRQ scheme */
+#define	PCIC_DEVCTL_INTR_RSVD	0x06 /* reserved */
+/* for PCI1221 and PCI1225 chips */
+#define	PCIC_DEVCTL_3VCAPABLE	0x40 /* 3V socket capable force */
+#define	PCIC_DEVCTL_INTR_DFLT	0x06 /* default interrupt mode */
+
+#define	PCIC_CRDCTL_REG		0x91 /* Card Control Register */
+#define	PCIC_CRDCTL_RIENABLE    0x80 /* Ring indicate enable on TI1250a */
+#define	PCIC_CRDCTL_ZVENABLE    0x40 /* Z buffer enable on TI1250a */
+#define	PCIC_CRDCTL_PCIINTR	0x20 /* use PCI INT A/B */
+#define	PCIC_CRDCTL_PCICSC	0x10 /* PCI intr for status */
+#define	PCIC_CRDCTL_PCIFUNC	0x08 /* use PCI intr for cards */
+#define	PCIC_CRDCTL_SPKR_ENBL	0x02 /* Enable speaker plumbing */
+#define	PCIC_CRDCTL_IFG		0x01 /* card interrupt flag */
+
+#define	PCIC_SYSCTL_REG		0x80 /* System Control Register */
+#define	PCIC_SYSCTL_INTRTIE	0x20 /* tie INTA and INTB */
+
+/* for Toshiba chips */
+#define	PCIC_TOSHIBA_SLOT_CTL_REG	0xa0 /* slot control register */
+#define	PCIC_TOSHIBA_SCR_SLOTON		0x80
+#define	PCIC_TOSHIBA_SCR_SLOTEN		0x40
+#define	PCIC_TOSHIBA_SCR_PRT_MASK	0xc
+#define	PCIC_TOSHIBA_SCR_PRT_3E0	0x0
+#define	PCIC_TOSHIBA_SCR_PRT_3E2	0x4
+#define	PCIC_TOSHIBA_SCR_PRT_3E4	0x8
+#define	PCIC_TOSHIBA_SCR_PRT_3E6	0xc
+#define	PCIC_TOSHIBA_INTR_CTL_REG	0xa1 /* interrupt control register */
+#define	PCIC_TOSHIBA_ICR_PIN_MASK	0x30
+#define	PCIC_TOSHIBA_ICR_PIN_DISEN	0x0
+#define	PCIC_TOSHIBA_ICR_PIN_INTA	0x10
+#define	PCIC_TOSHIBA_ICR_PIN_INTB	0x20
+#define	PCIC_TOSHIBA_ICR_MOD_CSC	0x4 /* CSC interrupt mode */
+#define	PCIC_TOSHIBA_ICR_MOD_FUN	0x2 /* Funtional interrupt mode */
+#define	PCIC_TOSHIBA_ICR_SRC		0x1 /* INTA or IRQ */
+
+/* for Ricoh chips */
+#define	PCIC_RICOH_MISC_CTL	0x82
+#define	PCIC_RICOH_SIRQ_EN	0x80	/* serialized IRQ */
+#define	PCIC_RICOH_MISC_CTL_2	0xa0	/* ricoh */
+#define	PCIC_RICOH_CSC_INT_MOD	0x80	/* csc to ISA */
+#define	PCIC_RICOH_FUN_INT_MOD	0x40	/* cint to ISA */
+
+/* for o2micro */
+#define	PCIC_O2MICRO_MISC_CTL	0x28
+#define	PCIC_O2MICRO_INT_MOD_MASK	0x300
+#define	PCIC_O2MICRO_INT_MOD_PCI	0x300
+#define	PCIC_O2MICRO_ISA_LEGACY		0x800
+/*  */
+
+/* SMC 34C90 specific registers */
+#define	PCIC_SMC_MEM_PAGE	0x40
+
+/* available interrupts and interrupt mask */
+#define	PCIC_IRQ(irq)	(1 << (irq))
+#define	PCIC_IRQ03	PCIC_IRQ(3)
+#define	PCIC_IRQ04	PCIC_IRQ(4)
+#define	PCIC_IRQ05	PCIC_IRQ(5)
+#define	PCIC_IRQ07	PCIC_IRQ(7)
+#define	PCIC_IRQ09	PCIC_IRQ(9)
+#define	PCIC_IRQ10	PCIC_IRQ(10)
+#define	PCIC_IRQ11	PCIC_IRQ(11)
+#define	PCIC_IRQ12	PCIC_IRQ(12)
+#define	PCIC_IRQ14	PCIC_IRQ(14)
+#define	PCIC_IRQ15	PCIC_IRQ(15)
+
+#define	PCIC_AVAIL_IRQS	(PCIC_IRQ03|PCIC_IRQ04|PCIC_IRQ05|PCIC_IRQ07|\
+				PCIC_IRQ09|PCIC_IRQ10|PCIC_IRQ11|PCIC_IRQ12|\
+				PCIC_IRQ14|PCIC_IRQ15)
+
+/* page size used for window mapping and memory resource page size */
+#define	PCIC_PAGE	4096
+
+/* used in I/O window mapping */
+#define	HIGH_BYTE(x)	(uchar_t)((((ushort_t)(x)) >> 8) & 0xFF)
+#define	LOW_BYTE(x)	(uchar_t)(((ushort_t)(x)) & 0xFF)
+#define	PCIC_IO_0_MASK	0x0f
+#define	PCIC_IO_1_MASK	0xf0
+#define	IOMEM_WINDOW(x)	(1<<((x)+6))
+
+#define	IOMEM_16BIT		0x01
+#define	IOMEM_IOCS16		0x02
+#define	IOMEM_ZERO_WAIT		0x04
+#define	IOMEM_CLTIMER_SET_0	0x00	/* CL timer set selection */
+#define	IOMEM_CLTIMER_SET_1	0x08	/* CL timer set selection */
+#define	IOMEM_WAIT16		0x08
+#define	IOMEM_SETWIN(w, x)	((x) << ((w)*4))
+
+#define	IOMEM_FIRST	0	/* First I/O address */
+#define	IOMEM_LAST	0xFFFF	/* Last I/O address */
+#define	IOMEM_MIN	1	/* minimum I/O window size */
+#define	IOMEM_MAX	0x10000	/* maximum I/O window size */
+#define	IOMEM_GRAN	1	/* granularity of request */
+#define	IOMEM_DECODE	16	/* number of address lines decoded */
+
+#define	MEM_FIRST	0x10000	/* first memory address */
+#define	MEM_LAST	0xFFFFF	/* last memory address */
+#define	MEM_MIN		PCIC_PAGE /* minimum window size */
+#define	MEM_MAX		0x10000	/* maximum window size */
+#define	PAGE_SHIFT	12	/* bits to shift */
+
+#define	SYSCLK		120	/* sysclk min time (ns) */
+#define	MEM_SPEED_MIN	(SYSCLK*2)
+#define	MEM_SPEED_MAX	(SYSCLK*6)
+
+/* CardBus (Yenta) specific values */
+#define	CB_R2_OFFSET	0x800	/* R2 is always at offset 0x800 */
+#define	CB_CLEXT_OFFSET	0x900	/* Cirrus Logic extended at offset 0x900 */
+#define	CB_CB_OFFSET	0x00	/* Cardbus registers at offset 0 */
+
+/* Cardbus registers in TI 1250A/Cirrus 6832 and probably others.  */
+/* Register offsets (these are 32 bit registers).  */
+#define	CB_STATUS_EVENT		0x00
+#define	CB_STATUS_MASK		0x04
+#define	CB_PRESENT_STATE	0x08
+#define	CB_EVENT_FORCE		0x0c
+#define	CB_CONTROL		0x10
+
+/* TI1420 */
+#define	CB_SOCKET_POWER		0x20
+
+/* Cardbus registers in 02 0Z6912.  */
+#define	CB_SZVCTRL		0x20
+#define	CB_SIMDCTRL		0x24
+#define	CB_MISCCTRL		0x28
+
+/* Register bit definitions.  */
+#define	BYTE_3(x)		((x)<<24)
+#define	BYTE_2(x)		((x)<<16)
+#define	BYTE_1(x)		((x)<<8)
+#define	BYTE_0(x)		(x)
+
+#define	CB_SE_POWER_CYCLE	BYTE_0(0x08)
+#define	CB_SE_CCDMASK		BYTE_0(0x06)
+#define	CB_SE_CCD2		BYTE_0(0x04)
+#define	CB_SE_CCD1		BYTE_0(0x02)
+#define	CB_SE_CSTSCHG		BYTE_0(0x01)
+
+#define	CB_SM_POWER_CYCLE	BYTE_0(0x08)
+#define	CB_SM_CCDMASK		BYTE_0(0x06)
+#define	CB_SM_CCD2		BYTE_0(0x04)
+#define	CB_SM_CCD1		BYTE_0(0x02)
+#define	CB_SM_CSTSCHG		BYTE_0(0x01)
+
+#define	CB_PS_CSTSCHG		BYTE_0(0x01)
+#define	CB_PS_CCDMASK		BYTE_0(0x06)
+#define	CB_PS_NCCD1		BYTE_0(0x02)
+#define	CB_PS_NCCD2		BYTE_0(0x04)
+#define	CB_PS_POWER_CYCLE	BYTE_0(0x08)
+#define	CB_PS_16BITCARD		BYTE_0(0x10)
+#define	CB_PS_CBCARD		BYTE_0(0x20)
+#define	CB_PS_INTERRUPT		BYTE_0(0x40)
+#define	CB_PS_NOTACARD		BYTE_0(0x80)
+
+#define	CB_PS_DATALOST		BYTE_1(0x01)
+#define	CB_PS_BADVCC		BYTE_1(0x02)
+#define	CB_PS_50VCARD		BYTE_1(0x04)
+#define	CB_PS_33VCARD		BYTE_1(0x08)
+#define	CB_PS_XVCARD		BYTE_1(0x10)
+#define	CB_PS_YVCARD		BYTE_1(0x20)
+
+#define	CB_PS_50VSOCKET		BYTE_3(0x10)
+#define	CB_PS_33VSOCKET		BYTE_3(0x20)
+#define	CB_PS_XVSOCKET		BYTE_3(0x40)
+#define	CB_PS_YVSOCKET		BYTE_3(0x80)
+
+#define	CB_EF_CSTSCHG		BYTE_0(0x01)
+#define	CB_EF_CCD1		BYTE_0(0x02)
+#define	CB_EF_CCD2		BYTE_0(0x04)
+#define	CB_EF_POWER_CYCLE	BYTE_0(0x08)
+#define	CB_EF_16BITCARD		BYTE_0(0x10)
+#define	CB_EF_CBCARD		BYTE_0(0x20)
+#define	CB_EF_NOTACARD		BYTE_0(0x80)
+
+#define	CB_EF_DATALOST		BYTE_1(0x01)
+#define	CB_EF_BADVCC		BYTE_1(0x02)
+#define	CB_EF_50V		BYTE_1(0x04)
+#define	CB_EF_33V		BYTE_1(0x08)
+#define	CB_EF_XV		BYTE_1(0x10)
+#define	CB_EF_YV		BYTE_1(0x20)
+#define	CB_EF_CVTEST		BYTE_1(0x40)
+
+#define	CB_C_VPPMASK		BYTE_0(0x07)
+#define	CB_C_VCCMASK		BYTE_0(0x70)
+
+#define	CB_C_VPP0V		BYTE_0(0x00)
+#define	CB_C_VPP12V		BYTE_0(0x01)
+#define	CB_C_VPPVCC		BYTE_0(0x03)
+
+#define	CB_C_VCC0V		BYTE_0(0x00)
+#define	CB_C_VCC50V		BYTE_0(0x20)
+#define	CB_C_VCC33V		BYTE_0(0x30)
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _PCIC_REG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/pcic_var.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,608 @@
+/*
+ * 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.
+ */
+
+/*
+ * PCIC driver specific data structures
+ */
+
+#ifndef _PCIC_VAR_H
+#define	_PCIC_VAR_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * defines and default values for power management simulation
+ */
+#define	PCIC_PM_TIME		3	/* PM timer timeout time in secs */
+#define	PCIC_PM_DETWIN		6	/* detection window in secs */
+#define	PCIC_PM_METHOD_TIME	0x0001	/* use time check */
+#define	PCIC_PM_METHOD_REG	0x0002	/* use reg check */
+#define	PCIC_PM_DEF_METHOD	0	/* use no methods as default */
+
+#define	PCIC_PM_INIT	0x0001	/* init PM handler */
+#define	PCIC_PM_RUN	0x0002	/* normal PM handler operation */
+
+typedef struct pcic_pm_t {
+	int		state;	/* state */
+	uint32_t	ptime;	/* previous time check */
+	dev_info_t	*dip;	/* dip to pass */
+} pcic_pm_t;
+
+/*
+ * Card insertion/removal processing debounce parameters
+ */
+#define	PCIC_REM_DEBOUNCE_CNT	40
+#define	PCIC_REM_DEBOUNCE_TIME	0x1000	/* in uS */
+#define	PCIC_DEBOUNCE_OK_CNT    10
+
+/*
+ * Loop control in pcic_ready_wait
+ *
+ * Multiplying PCIC_READY_WAIT_LOOPS * PCIC_READY_WAIT_TIME gives
+ *	total loop time in mS
+ */
+#define	PCIC_READY_WAIT_LOOPS	205	/* count */
+#define	PCIC_READY_WAIT_TIME	20	/* mS */
+
+typedef struct pcs_memwin {
+	int			pcw_status;
+	uint32_t		pcw_base;
+	int			pcw_len;
+	uint32_t		pcw_speed;
+	volatile caddr_t	pcw_hostmem;
+	off_t			pcw_offset;
+	ddi_acc_handle_t	pcw_handle;
+} pcs_memwin_t;
+
+typedef struct pci_iowin {
+	int 			pcw_status;
+	uint32_t		pcw_base;
+	int			pcw_len;
+	uint32_t		pcw_speed;
+	volatile caddr_t	pcw_hostmem;
+				/* Cirrus Logic specific offset info */
+	int			pcw_offset;
+	ddi_acc_handle_t	pcw_handle;
+} pcs_iowin_t;
+
+#define	PCW_MAPPED	0x0001	/* window is mapped */
+#define	PCW_ENABLED	0x0002	/* window is enabled */
+#define	PCW_ATTRIBUTE	0x0004	/* window is in attribute memory */
+#define	PCW_WP		0x0008	/* window is write protected */
+#define	PCW_OFFSET	0x0010	/* window uses CL style offset */
+
+typedef
+struct pcic_socket {
+	int	pcs_flags;
+	uchar_t	*pcs_io;	/* I/O address of PCIC controller */
+	int	pcs_socket;	/* socket to determine register set */
+	char    pcs_cd_softint_flg;
+	timeout_id_t pcs_debounce_id;	/* timeout for CD debounce */
+	ddi_softint_handle_t pcs_cd_softint_hdl; /* Debounce softint id */
+	struct pcicdev_t *pcs_pcic;
+	uint32_t pcs_syshwsig;
+	caddr_t pcs_phys;
+	int	pcs_iobase;
+	int	pcs_iolen;
+	caddr_t pcs_confbase;
+	int	pcs_conflen;
+	int	pcs_conf_index;	/* used to select which cftable entry to use */
+	int 	pcs_irq;
+	int	pcs_smi;
+	int	pcs_state;
+	int	pcs_status;
+	int	pcs_intmask;
+	uint32_t pcs_vcc;
+	uint32_t pcs_vpp1;
+	uint32_t pcs_vpp2;
+	union pcic_window {
+		pcs_memwin_t mem;
+		pcs_iowin_t  io;
+	}	pcs_windows[PCIC_IOWINDOWS + PCIC_MEMWINDOWS];
+} pcic_socket_t;
+
+#define	PCS_CARD_PRESENT	0x0001	/* card inserted in socket */
+#define	PCS_CARD_IDENTIFIED	0x0002	/* card has been identified */
+#define	PCS_CARD_ENABLED	0x0004	/* card and socket enabled */
+#define	PCS_CARD_WPS		0x0008	/* write protect ignored */
+#define	PCS_IRQ_ENABLED		0x0010	/* irq is a mask of values */
+#define	PCS_CARD_RAM		0x0020	/* ram needs to be mapped */
+#define	PCS_CARD_IO		0x0040	/* card is I/O type */
+#define	PCS_CARD_16BIT		0x0080	/* set in 16-bit mode */
+#define	PCS_SOCKET_IO		0x0100	/* socket is I/O type */
+#define	PCS_READY		0x0200	/* socket just came ready */
+#define	PCS_WAITING		0x0400	/* Doing a wait on this socket */
+#define	PCS_STARTING		0x0800	/* Starting up flag */
+#define	PCS_CARD_ISCARDBUS	0x1000	/* NJH - 32 bit (CARDBUS) card */
+#define	PCS_CARD_IS16BIT	0x2000	/* So we can tell if it's OK */
+#define	PCS_CARD_REMOVED	0x4000	/* Removed but still work to do */
+#define	PCS_CARD_CBREM		0x8000	/* Cardbus specific work to do */
+
+#define	PCIC_MAX_SOCKETS 4	/* 2 per chip up to 2 chips per IO addr */
+
+typedef struct pcic_debounce_state {
+	int insert_cnt;
+	int remove_cnt;
+	int uncertain_cnt;
+	int prev_status;
+	int debounce_cnt;
+	timeout_id_t timeout_id;
+} pcic_debounce_state_t;
+
+typedef struct pcicdev_t {
+	uint32_t		pc_flags;
+	uint32_t		pc_type;
+	char			*pc_chipname;
+	uint32_t		pc_irqs;	/* the possible IRQ levels */
+	uint32_t		pc_smi;		/* SMI IRQ */
+	uint32_t		pc_irq;		/* IO IRQ */
+	int			pc_io_type;
+	int			pc_intr_mode;	/* which interrupt method */
+	dev_info_t		*dip;
+	ddi_idevice_cookie_t	pc_dcookie;	/* Stay compatible w/ PCMCIA */
+	inthandler_t		*sirq[14];	/* List for each level */
+	uint16_t		si_actflg;	/* Bit for each active level */
+	inthandler_t		*irq_top;
+	inthandler_t		*irq_current;
+	ddi_intr_handle_t	*pc_pci_intr_hdlp; /* For PCI based adapters */
+	ddi_iblock_cookie_t	pc_pri;		/* Priority saved for mutexes */
+	ddi_intr_handle_t	*pc_intr_htblp;	/* ISA: interrupt handles */
+	ddi_softint_handle_t	pc_softint_hdl;	/* Softinterrupt handle */
+	kmutex_t		pc_lock;	/* general register lock */
+	kmutex_t		intr_lock;	/* protects fields modified */
+						/* in pcic_intr() */
+	int			pc_numsockets;
+				/* used to inform nexus of events */
+	int			(*pc_callback)();
+	int			pc_cb_arg;
+	int			(*pc_ss_bios)();
+	struct pcic_socket	pc_sockets[PCIC_MAX_SOCKETS];
+	int			pc_numpower;
+	struct power_entry	*pc_power;
+	timeout_id_t		pc_pmtimer;	/* timeout for simulating PM */
+	pcic_pm_t		pmt;		/* PM handler structure */
+	kcondvar_t		pm_cv;		/* CV for suspend/resume sync */
+	ddi_acc_handle_t	handle;		/* PCIC register handle */
+	ddi_acc_handle_t	cfg_handle;	/* PCIC config space handle */
+	uchar_t			*cfgaddr;	/* config address */
+	uchar_t			*ioaddr;	/* PCIC register IO base */
+	int			mem_reg_num;	/* memory space reg number */
+	offset_t		mem_reg_offset;
+	int			io_reg_num;	/* IO space reg number */
+	offset_t		io_reg_offset;
+	int			bus_speed;	/* parent bus speed */
+	uint32_t		pc_timestamp;   /* last time touched */
+	inthandler_t		*pc_handlers;
+	int			pc_lastreg;
+	uint32_t		pc_base;	/* first possible mem-addr */
+	uint32_t		pc_bound;	/* bound length */
+	uint32_t		pc_iobase;	/* first io addr */
+	uint32_t		pc_iobound;
+	pcic_debounce_state_t   deb_state[PCIC_MAX_SOCKETS];
+	int			pc_softintr_req[PCIC_MAX_SOCKETS];
+	struct pcic_cd_change_param {
+		struct pcicdev_t	*pcic;
+		pcic_socket_t		*sockp;
+		int			sn;
+	}  pcic_cd_change_param[PCIC_MAX_SOCKETS];
+} pcicdev_t;
+
+
+
+#define	PCF_ATTACHED	0x00000001
+#define	PCF_CALLBACK	0x00000002	/* callback handler registered */
+#define	PCF_GPI_EJECT	0x00000004	/* GPI signal is eject/insert */
+#define	PCF_INTRENAB	0x00000008
+#define	PCF_USE_SMI	0x00000010	/* use the SMI enable */
+#define	PCF_AUDIO	0x00000020	/* use audio if available */
+#define	PCF_SUSPENDED	0x00000040	/* driver attached but suspended */
+#define	PCF_EXTEND_INTR	0x00000080	/* Use Vadem interrupt sharing */
+#define	PCF_1SOCKET	0x00000100	/* Chip only has one socket  */
+#define	PCF_33VCAP	0x00000200	/* 3.3 Volt capable and coded */
+#define	PCF_CBPWRCTL	0x00000400	/* Use cardbus regs for power ctl */
+#define	PCF_DEBOUNCE	0x00002000	/* Chip has hardware debounce enabled */
+#define	PCF_VPPX	0x00004000	/* Vpp1 and Vpp2 tied together */
+#define	PCF_EXTBUFF	0x00008000	/* Chip strapped for external buffers */
+#define	PCF_PCIBUS	0x00010000	/* this instance on a PCI bus */
+#define	PCF_NOIO_OFF	0x00020000	/* 0 offset for IO mapping */
+#define	PCF_MULT_IRQ	0x00040000
+#define	PCF_IO_REMAP	0x00080000	/* adapter can remap I/O */
+#define	PCF_CARDBUS	0x00100000	/* Yenta CardBus */
+#define	PCF_MEM_PAGE	0x00200000	/* all windows same 16M page */
+
+/* newer features */
+#define	PCF_DMA		0x00400000	/* supports DMA */
+#define	PCF_ZV		0x00800000	/* supports Zoom Video */
+
+#define	PCF_ISA6729	0x01000000	/* 6729 */
+
+/*
+ * misc flags
+ */
+#define	PCIC_FOUND_ADAPTER	0x00000001
+#define	PCIC_ENABLE_IO		0x00000002
+#define	PCIC_ENABLE_MEM		0x00000004
+
+#define	PCIC_SOFTINT_PRI_VAL	0x04	/* value used while adding softint */
+
+/*
+ * interrupt modes
+ * the pcic variants provide a number of interrupt modes.
+ * e.g. on PCI, we can either use PCI interrupts or ISA interrupts
+ * but the SPARC version must use PCI interrupts and x86 "depends"
+ */
+
+#define	PCIC_INTR_MODE_ISA	00 /* default- use ISA mode */
+#define	PCIC_INTR_MODE_PCI	01 /* use pure PCI */
+#define	PCIC_INTR_MODE_PCI_1	02 /* use pure PCI but share */
+#define	PCIC_INTR_MODE_PCI_S	03 /* serial PCI interrupts */
+
+#define	PCIC_INTR_DEF_PRI	11 /* default IPL level */
+
+/*
+ * I/O access types
+ */
+#define	PCIC_IO_TYPE_82365SL	0 /* uses index/data reg model */
+#define	PCIC_IO_TYPE_YENTA	1 /* uses the Yenta spec memory model */
+
+/*
+ * On some PCI busses, the IO and memory resources available to us are
+ *	available via the last two tuples in the reg property. The
+ *	following defines are the reg numbers from the end of the reg
+ *	property, and NOT the reg number itself.
+ */
+#define	PCIC_PCI_MEM_REG_OFFSET	2
+#define	PCIC_PCI_IO_REG_OFFSET	3
+
+/* I/O type 82365SL is default, Yenta is alternative */
+#define	PCIC_IOTYPE_82365SL	0
+#define	PCIC_IOTYPE_YENTA	1 /* CardBus memory mode */
+
+/*
+ * On Yenta cards, the PCI configuration space bridge control register
+ * must match the interrupt * type we have selected.
+ */
+
+#define	PCIC_CB_BRIDGE_CTL	0x3E
+#define	PCIC_BCTL_IREQ_ISA	0x80
+
+/*
+ * On all PCI busses, we get at least two tuples in the reg property. One
+ *	of the tuples is the config space tuple and the other is the PCIC
+ *	IO control register space tuple.
+ */
+
+#define	PCIC_PCI_CONFIG_REG_NUM	0
+#define	PCIC_PCI_CONFIG_REG_OFFSET	0
+#define	PCIC_PCI_CONFIG_REG_LENGTH	0x100
+
+#define	PCIC_PCI_CONTROL_REG_NUM	1
+#define	PCIC_PCI_CONTROL_REG_OFFSET	0
+#define	PCIC_PCI_CONTROL_REG_LENGTH	4
+#define	PCIC_CB_CONTROL_REG_LENGTH	4096 /* CardBus is 4K mem page */
+
+/*
+ * On ISA/EISA/MCA our reg property must look like this:
+ *
+ *	IOreg,0x0,0x8, 0x0,0x0,0x100000, 0x1,0x0,0x1000
+ *	^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^
+ *	adapter regs    general memory	   general IO
+ *
+ * where IOreg specifies the adapter's control registers in
+ *	IO space.
+ * The value of PCIC_ISA_IO_REG_OFFSET must be the first
+ *	component of the third (general IO) register spec.
+ */
+#define	PCIC_ISA_IO_REG_OFFSET		1
+#define	PCIC_ISA_CONTROL_REG_NUM	0
+#define	PCIC_ISA_CONTROL_REG_OFFSET	0	/* XXX MUST be 0! */
+#define	PCIC_ISA_CONTROL_REG_LENGTH	2
+
+#define	PCIC_ISA_MEM_REG_NUM		1
+#define	PCIC_ISA_IO_REG_NUM		2
+
+/*
+ * there are several variants of the 82365 chip from different "clone"
+ * vendors.  Each has a few differences which may or may not have to be
+ * handled.  The following defines are used to identify the chip being
+ * used.  If it can't be determined, then 82365SL is assumed.
+ *
+ * The following are ISA/EISA/MCA-R2 adapters
+ */
+#define	PCIC_I82365SL		0x00 /* Intel 82365SL */
+#define	PCIC_TYPE_I82365SL	"i82365SL"
+#define	PCIC_CL_PD6710		0x01 /* Cirrus Logic CL-PD6710/6720 */
+#define	PCIC_CL_PD6722		0x05 /* Cirrus Logic CL-PD6722 */
+#define	PCIC_TYPE_PD6710	"PD6710"
+#define	PCIC_TYPE_PD6720	"PD6720"
+#define	PCIC_TYPE_PD6722	"PD6722"
+#define	PCIC_VADEM		0x02 /* Vadem VG465/365 */
+#define	PCIC_VADEM_VG469	0x03 /* Vadem VG469 - P&P, etc. */
+#define	PCIC_VG_465		"VG465"
+#define	PCIC_VG_365		"VG365"
+#define	PCIC_VG_468		"VG468"
+#define	PCIC_VG_469		"VG469"
+#define	PCIC_RICOH		0x04
+#define	PCIC_TYPE_RF5C296	"RF5C296"
+#define	PCIC_TYPE_RF5C396	"RF5C396"
+
+/* PCI adapters are known by 32-bit value of vendor+device id */
+#define	PCI_ID(vend, dev)	((uint32_t)(((uint32_t)(vend) << 16) | (dev)))
+
+/*
+ * The following are PCI-R2 adapters
+ * The Cirrus Logic PCI adapters typically have their IRQ3 line
+ *	routed to the PCI INT A# line.
+ */
+#define	PCIC_CL_VENDORID	0x1013
+#define	PCIC_PD6729_DEVID	0x1100
+#define	PCIC_TYPE_PD6729	"PD6729"
+#define	PCIC_CL_PD6729		PCI_ID(PCIC_CL_VENDORID, PCIC_PD6729_DEVID)
+#define	PCIC_PD6729_INTA_ROUTE	0x03
+
+#define	PCIC_TYPE_PD6730	"PD6730"
+#define	PCIC_PD6730_DEVID	0x1101
+#define	PCIC_CL_PD6730		PCI_ID(PCIC_CL_VENDORID, PCIC_PD6730_DEVID)
+#define	PCIC_PD6730_INTA_ROUTE	0x09
+
+#define	PCIC_TYPE_PD6832	"PD6832"
+#define	PCIC_PD6832_DEVID	0x1110
+#define	PCIC_CL_PD6832		PCI_ID(PCIC_CL_VENDORID, PCIC_PD6832_DEVID)
+
+/* Intel i82092AA controller */
+
+#define	PCIC_INTEL_VENDORID	0x8086
+#define	PCIC_TYPE_i82092	"i82092"
+#define	PCIC_i82092_DEVID	0x1221
+#define	PCIC_INTEL_i82092	PCI_ID(PCIC_INTEL_VENDORID, \
+					PCIC_i82092_DEVID)
+#define	PCIC_i82092_INTA_ROUTE	0x0	/* XXX ? what is it really ? XXX */
+
+/* Texas Instruments */
+
+#define	PCIC_TI_VENDORID	0x104C
+#define	PCIC_PCI1050_DEVID	0xAC10
+#define	PCIC_PCI1130_DEVID	0xAC12
+#define	PCIC_PCI1031_DEVID	0xAC13 /* R2 only with Yenta IF */
+#define	PCIC_PCI1131_DEVID	0xAC15
+#define	PCIC_PCI1250_DEVID	0xAC16
+#define	PCIC_PCI1221_DEVID	0xAC19
+#define	PCIC_PCI1225_DEVID	0xAC1C
+#define	PCIC_PCI1220_DEVID	0xAC17
+#define	PCIC_PCI1260_DEVID	0xAC18
+#define	PCIC_PCI1210_DEVID	0xAC1A
+#define	PCIC_PCI1450_DEVID	0xAC1B
+#define	PCIC_PCI1251_DEVID	0xAC1D
+#define	PCIC_PCI1211_DEVID	0xAC1E
+#define	PCIC_PCI1251B_DEVID	0xAC1F
+#define	PCIC_PCI1260B_DEVID	0xAC30
+#define	PCIC_PCI4450_DEVID	0xAC40
+#define	PCIC_PCI4410_DEVID	0xAC41
+#define	PCIC_PCI4451_DEVID	0xAC42
+#define	PCIC_PCI4510_DEVID	0xAC44
+#define	PCIC_PCI1410_DEVID	0xAC50
+#define	PCIC_PCI1420_DEVID	0xAC51
+#define	PCIC_PCI1451_DEVID	0xAC52
+#define	PCIC_PCI1421_DEVID	0xAC53
+#define	PCIC_PCI1520_DEVID	0xAC55
+#define	PCIC_PCI1510_DEVID	0xAC56
+
+#define	PCIC_TI_PCI1130		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1130_DEVID)
+#define	PCIC_TYPE_PCI1130	"PCI1130"
+#define	PCIC_TI_PCI1031		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1031_DEVID)
+#define	PCIC_TYPE_PCI1031	"PCI1031"
+#define	PCIC_TI_PCI1131		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1131_DEVID)
+#define	PCIC_TYPE_PCI1131	"PCI1131"
+#define	PCIC_TI_PCI1250		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1250_DEVID)
+#define	PCIC_TYPE_PCI1250	"PCI1250"
+#define	PCIC_TI_PCI1050		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1050_DEVID)
+#define	PCIC_TYPE_PCI1050	"PCI1050"
+#define	PCIC_TI_PCI1221		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1221_DEVID)
+#define	PCIC_TYPE_PCI1221	"PCI1221"
+#define	PCIC_TI_PCI1225		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1225_DEVID)
+#define	PCIC_TYPE_PCI1225	"PCI1225"
+#define	PCIC_TI_PCI1220		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1220_DEVID)
+#define	PCIC_TYPE_PCI1220	"PCI1220"
+#define	PCIC_TI_PCI1260		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1260_DEVID)
+#define	PCIC_TYPE_PCI1260	"PCI1260"
+#define	PCIC_TI_PCI1210		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1210_DEVID)
+#define	PCIC_TYPE_PCI1210	"PCI1210"
+#define	PCIC_TI_PCI1450		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1450_DEVID)
+#define	PCIC_TYPE_PCI1450	"PCI1450"
+#define	PCIC_TI_PCI1251		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1251_DEVID)
+#define	PCIC_TYPE_PCI1251	"PCI1251"
+#define	PCIC_TI_PCI1211		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1211_DEVID)
+#define	PCIC_TYPE_PCI1211	"PCI1211"
+#define	PCIC_TI_PCI1251B	PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1251B_DEVID)
+#define	PCIC_TYPE_PCI1251B	"PCI1251B"
+#define	PCIC_TI_PCI1260B	PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1260B_DEVID)
+#define	PCIC_TYPE_PCI1260B	"PCI1260B"
+#define	PCIC_TI_PCI4450		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI4450_DEVID)
+#define	PCIC_TYPE_PCI4450	"PCI4450"
+#define	PCIC_TI_PCI4410		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI4410_DEVID)
+#define	PCIC_TYPE_PCI4410	"PCI4410"
+#define	PCIC_TI_PCI4451		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI4451_DEVID)
+#define	PCIC_TYPE_PCI4451	"PCI4451"
+#define	PCIC_TI_PCI4510		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI4510_DEVID)
+#define	PCIC_TYPE_PCI4510	"PCI4510"
+#define	PCIC_TI_PCI1410		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1410_DEVID)
+#define	PCIC_TYPE_PCI1410	"PCI1410"
+#define	PCIC_TI_PCI1420		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1420_DEVID)
+#define	PCIC_TYPE_PCI1420	"PCI1420"
+#define	PCIC_TI_PCI1451		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1451_DEVID)
+#define	PCIC_TYPE_PCI1451	"PCI1451"
+#define	PCIC_TI_PCI1421		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1421_DEVID)
+#define	PCIC_TYPE_PCI1421	"PCI1421"
+#define	PCIC_TI_PCI1510		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1510_DEVID)
+#define	PCIC_TYPE_PCI1510	"PCI1510"
+#define	PCIC_TI_PCI1520		PCI_ID(PCIC_TI_VENDORID, PCIC_PCI1520_DEVID)
+#define	PCIC_TYPE_PCI1520	"PCI1520"
+#define	PCIC_TI_VENDOR		PCI_ID(PCIC_TI_VENDORID, 0x0000)
+#define	PCIC_TYPE_TI		"PCIC_TI"
+
+/* O2 Micro */
+#define	PCIC_O2_VENDORID	0x1217
+#define	PCIC_OZ6912_DEVID	0x6972
+#define	PCIC_O2_OZ6912		PCI_ID(PCIC_O2_VENDORID, PCIC_OZ6912_DEVID)
+#define	PCIC_TYPE_OZ6912	"OZ6912"
+#define	PCIC_O2MICRO_VENDOR	PCI_ID(PCIC_O2_VENDORID, 0x0000)
+#define	PCIC_TYPE_O2MICRO	"O2Micro"
+
+/* ENE */
+#define	PCIC_ENE_VENDORID	0x1524
+#define	PCIC_ENE1410_DEVID	0x1410
+#define	PCIC_ENE_1410		PCI_ID(PCIC_ENE_VENDORID, PCIC_ENE1410_DEVID)
+#define	PCIC_TYPE_1410		"ENE1410"
+#define	PCIC_ENE1420_DEVID	0x1420
+#define	PCIC_ENE_1420		PCI_ID(PCIC_ENE_VENDORID, PCIC_ENE1420_DEVID)
+#define	PCIC_TYPE_1420		"ENE1420"
+
+/* SMC 34C90 */
+#define	PCIC_SMC_VENDORID	0x10B3
+#define	PCIC_SMC34C90_DEVID	0xB106
+#define	PCIC_SMC_34C90		PCI_ID(PCIC_SMC_VENDORID, PCIC_SMC34C90_DEVID)
+#define	PCIC_TYPE_34C90		"SMC34c90"
+
+/* Ricoh RL5CXXX */
+#define	PCIC_RICOH_VENDORID	0x1180
+#define	PCIC_RL5C466_DEVID	0x0466
+#define	PCIC_RL5C475_DEVID	0x0475
+#define	PCIC_RL5C476_DEVID	0x0476
+#define	PCIC_RL5C477_DEVID	0x0477
+#define	PCIC_RL5C478_DEVID	0x0478
+#define	PCIC_RICOH_RL5C466	PCI_ID(PCIC_RICOH_VENDORID, PCIC_RL5C466_DEVID)
+#define	PCIC_RICOH_RL5C475	PCI_ID(PCIC_RICOH_VENDORID, PCIC_RL5C475_DEVID)
+#define	PCIC_RICOH_RL5C476	PCI_ID(PCIC_RICOH_VENDORID, PCIC_RL5C476_DEVID)
+#define	PCIC_RICOH_RL5C477	PCI_ID(PCIC_RICOH_VENDORID, PCIC_RL5C477_DEVID)
+#define	PCIC_RICOH_RL5C478	PCI_ID(PCIC_RICOH_VENDORID, PCIC_RL5C478_DEVID)
+#define	PCIC_TYPE_RL5C466		"RL5C466"
+#define	PCIC_TYPE_RL5C475		"RL5C475"
+#define	PCIC_TYPE_RL5C476		"RL5C476"
+#define	PCIC_TYPE_RL5C477		"RL5C477"
+#define	PCIC_TYPE_RL5C478		"RL5C478"
+#define	PCIC_RICOH_VENDOR	PCI_ID(PCIC_RICOH_VENDORID, 0x0000)
+#define	PCIC_TYPE_RICOH		"Ricoh"
+
+/* Toshiba */
+#define	PCIC_TOSHIBA_VENDORID	0x1179
+#define	PCIC_TOPIC95_DEVID	0x0603
+#define	PCIC_TOSHIBA_TOPIC95	PCI_ID(PCIC_TOSHIBA_VENDORID, \
+					PCIC_TOPIC95_DEVID)
+#define	PCIC_TYPE_TOPIC95	"ToPIC95"
+#define	PCIC_TOPIC100_DEVID	0x0617
+#define	PCIC_TOSHIBA_TOPIC100	PCI_ID(PCIC_TOSHIBA_VENDORID, \
+					PCIC_TOPIC100_DEVID)
+#define	PCIC_TYPE_TOPIC100	"ToPIC100"
+#define	PCIC_TOSHIBA_VENDOR	PCI_ID(PCIC_TOSHIBA_VENDORID, 0x0000)
+#define	PCIC_TYPE_TOSHIBA	"Toshiba"
+
+/* Generic Yenta compliant chip */
+#define	PCIC_TYPE_YENTA		"Yenta"
+
+/* Yenta-compliant vcc register, bits */
+#define	PCIC_PRESENT_STATE_REG	0x8
+#define	PCIC_VCC_MASK		0xc00
+#define	PCIC_VCC_3VCARD		0x800
+#define	PCIC_VCC_5VCARD		0x400
+
+#define	PCIC_16BIT_CARD		0x010		/* 16 bit card */
+#define	PCIC_CB_CARD		0x020		/* cardbus card */
+#define	PCIC_CINT_IREQ		0x040		/* Interrupt present */
+#define	PCIC_NOT_A_CARD		0x080		/* Not a card */
+#define	PCIC_DATA_LOST		0x100		/* Data lost */
+#define	PCIC_BAD_VCC_REQ	0x200		/* Bad Vcc request */
+
+#define	PCICPROP_CTL		"controller"
+
+#define	PCIC_REV_LEVEL_LOW	0x02
+#define	PCIC_REV_LEVEL_HI 	0x04
+#define	PCIC_REV_C		0x04
+#define	PCIC_REV_MASK		0x0f
+
+#define	PCIC_ID_NAME		"pcic"
+#define	PCIC_DEV_NAME		"pcic"
+
+#ifndef	DEVI_PCI_NEXNAME
+#define	DEVI_PCI_NEXNAME	"pci"
+#endif
+
+/* PCI Class Code stuff */
+#define	PCIC_PCI_CLASS(cls, subclass)	(((cls) << 16) | ((subclass) << 8))
+#define	PCIC_PCI_PCMCIA	PCIC_PCI_CLASS(PCI_CLASS_BRIDGE, PCI_BRIDGE_PCMCIA)
+#define	PCIC_PCI_CARDBUS PCIC_PCI_CLASS(PCI_CLASS_BRIDGE, PCI_BRIDGE_CARDBUS)
+
+#define	PCIC_MEM_AM	0	/* Attribute Memory */
+#define	PCIC_MEM_CM	1	/* Common Memory */
+
+#define	PCS_SUBTYPE_UNKNOWN	0x00 /* haven't processed this yet */
+#define	PCS_SUBTYPE_MEMORY	0x01 /* normal memory access */
+#define	PCS_SUBTYPE_FAT		0x02 /* DOS floppy (FAT) file system */
+
+/*
+ * For speed calculation, assume a SYSCLK rate of 8.33MHz
+ *	unless our parent tells us otherwise. 8.33MHz is a
+ *	reasonable default for an ISA bus.
+ */
+#define	PCIC_ISA_DEF_SYSCLK	8	/* MHZ */
+#define	PCIC_PCI_DEF_SYSCLK	33	/* MHZ */
+#define	PCIC_PCI_25MHZ		25
+#define	mhztons(c)		(1000000 / (uint32_t)((c) * 1000))
+#define	PCIC_SYSCLK_25MHZ	25 * 1000 * 1000
+#define	PCIC_SYSCLK_33MHZ	33 * 1000 * 1000
+
+/* simplify the callback so it looks like straight function call */
+#define	PC_CALLBACK	(*pcic->pc_callback)
+
+/* hardware event capabilities -- needs sservice.h */
+#define	PCIC_DEFAULT_INT_CAPS	(SBM_BVD1|SBM_BVD2|SBM_RDYBSY|SBM_CD)
+#define	PCIC_DEFAULT_RPT_CAPS	(PCIC_DEFAULT_INT_CAPS|SBM_WP)
+/* note that we don't support indicators via the PCIC */
+#define	PCIC_DEFAULT_CTL_CAPS	(0)
+
+/* format of pcic "ranges" property */
+typedef struct pcic_ranges {
+	uint32_t pcic_range_caddrhi;
+	uint32_t pcic_range_caddrlo;
+	uint32_t pcic_range_paddrhi;
+	uint32_t pcic_range_paddrmid;
+	uint32_t pcic_range_paddrlo;
+	uint32_t pcic_range_size;
+} pcic_ranges_t;
+
+/* debug stuff */
+#if defined(DEBUG)
+#define	PCIC_DEBUG
+#endif
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _PCIC_VAR_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/pem.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,262 @@
+/*
+ * 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 1999 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * PCMCIA Event Manager Driver
+ */
+
+#ifndef _PEM_H
+#define	_PEM_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* #define	PEM_DEBUG */
+
+#define	PEM_MAX_EVENTS	64
+#define	PEM_IDNUM	0x454D
+#define	PEM_NAME	"pem"
+#define	PEM_MIN		0
+#define	PEM_MAX		1024
+#define	PEM_HIWATER	4096
+#define	PEM_LOWATER	1024
+
+#define	EM_INIT_REQ	0
+#define	EM_INFO_REQ	1
+#define	EM_MODIFY_EVENT_MASK_REQ	2
+#define	EM_GET_FIRST_TUPLE_REQ	3
+#define	EM_GET_NEXT_TUPLE_REQ	4
+
+#define	EM_INIT_ACK	5
+#define	EM_INFO_ACK	6
+#define	EM_EVENT_IND	7
+
+#define	EM_ADAPTER_INFO_REQ	8
+#define	EM_ADAPTER_INFO_ACK	9
+#define	EM_SOCKET_INFO_REQ	10
+#define	EM_SOCKET_INFO_ACK	11
+#define	EM_GET_SOCKET_REQ	12
+#define	EM_GET_SOCKET_ACK	13
+#define	EM_IDENT_SOCKET_REQ	14
+#define	EM_GET_FIRST_TUPLE_ACK	15
+
+#define	EM_BADPRIM	1
+
+
+#define	___VERSION(a, b)	(((a)<<8)|(b))
+#define	EM_VERSION	___VERSION(0, 1)
+#define	EM_CURRENT_VERSION	EM_VERSION
+
+typedef
+struct em_init_req {
+	uint32_t	em_primitive;
+	uint32_t	em_logical_socket;
+	uint32_t	em_event_mask_offset;
+	uint32_t	em_event_mask_length;
+	uint32_t	em_event_class_offset;
+	uint32_t	em_event_class_length;
+} em_init_req_t;
+
+typedef
+struct em_info_req {
+	uint32_t	em_primitive;
+} em_info_req_t;
+
+typedef
+struct em_modify_event_mask_req {
+	uint32_t	em_primitive;
+} em_modify_event_mask_req_t;
+
+typedef
+struct em_get_first_tuple_req {
+	uint32_t	em_primitive;
+	uint32_t	em_socket;
+	uint32_t	em_desired_tuple;
+} em_get_first_tuple_req_t;
+
+typedef
+struct em_get_first_tuple_ack {
+	uint32_t	em_primitive;
+} em_get_first_tuple_ack_t;
+
+typedef
+struct em_get_next_tuple_req {
+	uint32_t	em_primitive;
+} em_get_next_tuple_req_t;
+
+typedef
+struct em_get_next_tuple_ack {
+	uint32_t	em_primitive;
+} em_get_next_tuple_ack_t;
+
+typedef
+struct em_info_ack {
+	uint32_t	em_primitive;
+	uint32_t	em_version;
+	uint32_t	em_state;
+	uint32_t	em_event_mask_offset;
+	uint32_t	em_event_mask_length;
+	uint32_t	em_event_class_offset;
+	uint32_t	em_event_class_length;
+} em_info_ack_t;
+
+typedef
+struct em_event_ind {
+	uint32_t	em_primitive;
+	uint32_t	em_logical_socket;
+	uint32_t	em_event;
+	uint32_t	em_event_info_offset;
+	uint32_t	em_event_info_length;
+} em_event_ind_t;
+
+typedef
+struct em_init_ack {
+	uint32_t	em_primitive;
+} em_init_ack_t;
+
+/* adapter info is essentially InquireAdapter */
+typedef
+struct em_adapter_info_req {
+	uint32_t	em_primitive;
+} em_adapter_info_req_t;
+
+typedef
+struct em_adapter_info_ack {
+	uint32_t	em_primitive;
+	uint32_t	em_num_sockets;
+	uint32_t	em_num_windows;
+	uint32_t	em_num_power;
+	uint32_t	em_power_offset;
+	uint32_t	em_power_length;
+} em_adapter_info_ack_t;
+
+/* socket_info is essentially InquireSocket */
+typedef
+struct em_socket_info_req {
+	uint32_t	em_primitive;
+	uint32_t	em_socket;
+} em_socket_info_req_t;
+
+typedef
+struct em_socket_info_ack {
+	uint32_t	em_primitive;
+	uint32_t	em_status_int_caps;
+	uint32_t	em_status_report_caps;
+	uint32_t	em_control_indicator_caps;
+	uint32_t	em_socket_caps;
+} em_socket_info_ack_t;
+
+/* get_socket */
+typedef
+struct em_get_socket_req {
+	uint32_t	em_primitive;
+	uint32_t	em_socket;
+} em_get_socket_req_t;
+
+typedef
+struct em_get_socket_ack {
+	uint32_t	em_primitive;
+	uint32_t	em_socket;
+	uint32_t	em_vcc_level;
+	uint32_t	em_vpp1_level;
+	uint32_t	em_vpp2_level;
+	uint32_t	em_state;
+	uint32_t	em_control_ind;
+	uint32_t	em_ireq_routing;
+	uint32_t	em_iftype;
+} em_get_socket_ack_t;
+
+typedef
+struct em_ident_socket_req {
+	uint32_t	em_primitive;
+	uint32_t	em_socket;
+} em_ident_socket_req_t;
+
+union em_primitives {
+	uint32_t		   em_primitive;
+	em_init_req_t		   init_req;
+	em_info_req_t		   info_req;
+	em_get_first_tuple_req_t   get_first_tuple_req;
+	em_get_next_tuple_req_t	   get_next_tuple_req;
+	em_info_ack_t		   info_ack;
+	em_event_ind_t		   event_ind;
+	em_modify_event_mask_req_t modify_event_mask_req;
+	em_get_socket_req_t	   get_socket_req;
+	em_ident_socket_req_t	   ident_socket_req;
+};
+
+#define	EM_CLASS_SIZE	32
+#define	EM_EVENT_MASK_SIZE	32
+
+#if defined(_KERNEL)
+#define	EM_EVENT_SIZE	4
+typedef struct pem {
+	uint32_t pem_flags;
+	uint32_t pem_state;
+	uint32_t pem_id;
+	minor_t  pem_minor;
+	queue_t *pem_qptr;
+	mblk_t	*pem_mb;
+	uchar_t  pem_event_class[EM_CLASS_SIZE/sizeof (uchar_t)];
+	uchar_t	 pem_event_mask[EM_EVENT_MASK_SIZE/sizeof (uchar_t)];
+} pem_t;
+
+#define	EM_INIT	1
+#define	PEMF_EVENTS	0x0001
+#define	PEMF_CLASSES	0x0002
+#define	PEMF_INIT	0x0004
+
+#define	PEMMAXINFO	(16 + sizeof (struct pcm_make_dev))
+struct pem_event {
+	int	pe_owner;
+	int	pe_id;
+	int	pe_event;
+	int	pe_socket;
+	uchar_t	pe_info[PEMMAXINFO];
+};
+#define	PE_OWN_FREE	0
+#define	PE_OWN_CLAIMED	1
+#define	PE_OWN_HANDLER	2
+
+#define	PEME_OK			0
+#define	PEME_NO_INFO		1
+#define	PEME_UNAVAILABLE	2
+#define	PEME_NO_CIS		3
+#define	PEME_NO_TUPLE		4
+
+#define	PEMTRACE	0x0001
+#define	PEMERRS		0x0002
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PEM_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/syshw.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,102 @@
+/*
+ * 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_SYSHW_H
+#define	_SYS_SYSHW_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * syshw.h:	Declarations for the common miscellaneous system hardware
+ *		interface.
+ */
+
+#define	SYSHW_IDSTR_LEN	43
+
+/*
+ * Generic ioctls
+ */
+typedef enum {
+    SYSHW_GET_ITEM = 0,	/* Retrieve item information */
+    SYSHW_GET_ITEM_MAXVALUES,	/* Retrieve item Maximium values */
+    SYSHW_SET_ITEM,	/* Set item values (SH_CONTROL type only) */
+    SYSHW_EVREG,	/* Register for events */
+    SYSHW_EVUNREG,	/* Unregister for events */
+    SYSHW_CHKEV,	/* Check events. */
+    SYSHW_ESCAPE	/* Module specific */
+} syshw_ioctl_t;
+
+/*
+ * Response fields
+ */
+typedef enum {
+    SH_SWITCH = 0,		/* A switch */
+    SH_CONNECTION,		/* A connection */
+    SH_POWER,			/* A powersource thing */
+    SH_SOUND,			/* An audio thing */
+    SH_VISUAL,			/* A visual thing */
+    SH_ENV			/* An environment thing */
+} syshw_item_type_t;
+
+typedef struct {
+    uchar_t		hw_id;
+    char		id_string[SYSHW_IDSTR_LEN];
+    syshw_item_type_t	type;		/* Item type */
+    uint_t		capabilities;	/* Capability flags */
+    boolean_t		state;		/* On/Off or Connected/Disconnected.. */
+    int			values[4];	/* Free form item dependant values */
+} syshw_t;
+
+/*
+ * Bits for the syshw_t capability flags field. Note that you can use
+ * i = 1 -> 3;  SYSHW_VAL0_VALID << i, to get the other 3 bits.
+ */
+#define	SYSHW_CAN_SIGNAL_CHANGE		0x0001
+#define	SYSHW_STATE_VALID		0x0010
+#define	SYSHW_VAL0_VALID		0x0100
+#define	SYSHW_VAL1_VALID		0x0200
+#define	SYSHW_VAL2_VALID		0x0400
+#define	SYSHW_VAL3_VALID		0x0800
+#define	SYSHW_STATE_MODIFY		0x0020
+#define	SYSHW_VAL0_MODIFY		0x1000
+#define	SYSHW_VAL1_MODIFY		0x2000
+#define	SYSHW_VAL2_MODIFY		0x4000
+#define	SYSHW_VAL3_MODIFY		0x8000
+
+typedef struct hwev_client {
+    uint_t		events;			/* Pending event flags, this */
+						/* is a bit per hw_id number. */
+    int			event_sig;		/* SIGUSR1, SIGUSR2.. */
+} hwev_t;
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_SYSHW_H */
--- a/usr/src/uts/i86pc/Makefile.i86pc.shared	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/uts/i86pc/Makefile.i86pc.shared	Thu Jun 29 14:43:12 2006 -0700
@@ -265,6 +265,7 @@
 DRV_KMODS	+= mc-amd
 DRV_KMODS	+= power
 DRV_KMODS	+= tzmon
+DRV_KMODS	+= pcic
 
 $(CLOSED_BUILD)CLOSED_DRV_KMODS		+= audiovia823x
 $(CLOSED_BUILD)CLOSED_DRV_KMODS		+= audioens
@@ -276,7 +277,6 @@
 $(CLOSED_BUILD)CLOSED_DRV_KMODS		+= iprb
 $(CLOSED_BUILD)CLOSED_DRV_KMODS		+= memtest
 $(CLOSED_BUILD)CLOSED_DRV_KMODS_32	+= ncrs
-$(CLOSED_BUILD)CLOSED_DRV_KMODS		+= pcic
 $(CLOSED_BUILD)CLOSED_DRV_KMODS		+= pcn
 $(CLOSED_BUILD)CLOSED_DRV_KMODS		+= rtls
 $(CLOSED_BUILD)CLOSED_DRV_KMODS_32	+= sbpro
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/pcic/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,92 @@
+#
+# 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.
+#
+
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the PCIC style PCMCIA adapter
+#	It is mostly a standard driver
+#
+#	i86pc architecture dependent
+#
+
+#
+#	Paths to the base of the uts directory trees
+#
+UTSBASE		= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= pcic
+OBJECTS		= $(PCIC_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(PCIC_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/common/io
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/i86pc/Makefile.i86pc
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+CPPFLAGS	+=	-DCARDBUS
+#
+#	Dependency
+#
+LDFLAGS		+= -dy -Nmisc/busra -Nmisc/pcmcia -Nmisc/cardbus
+
+
+#
+#	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)/i86pc/Makefile.targ
--- a/usr/src/uts/intel/Makefile.intel.shared	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/uts/intel/Makefile.intel.shared	Thu Jun 29 14:43:12 2006 -0700
@@ -341,12 +341,11 @@
 #
 DRV_KMODS	+= pcs
 DRV_KMODS	+= pcata pcmem pcram
-$(CLOSED_BUILD)CLOSED_DRV_KMODS	+= pem
+DRV_KMODS	+= pem
+MISC_KMODS	+= cardbus
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= pcelx
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= pcser
 
-$(CLOSED_BUILD)CLOSED_MISC_KMODS	+= cardbus
-
 #
 #	I2O specific module(s)
 #
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/cardbus/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,97 @@
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# uts/intel/cardbus/Makefile
+#
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of the cardbus kernel module.
+#
+#	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		= cardbus
+OBJECTS		= $(CARDBUS_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(CARDBUS_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)
+
+# 
+# 	Include sun4u specific header files
+#
+INC_PATH        += -I$(UTSBASE)/sun4u -I$(UTSBASE)/sun4 -I$(UTSBASE)/i86pc
+
+#
+# lint pass one enforcement
+#
+CFLAGS += $(CCVERBOSE)
+
+CPPFLAGS        +=      -DHOTPLUG
+
+#	dependency
+LDFLAGS	+=	-dy -Nmisc/busra -Nmisc/pcmcia -Nmisc/hpcsvc
+
+#
+#	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/pem/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,91 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This file makes the PCMCIA Event Manager driver for a intel system
+#
+#	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		= pem
+OBJECTS		= $(PEM_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(PEM_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/common/pcmcia/pem
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+#	Override defaults to build a unique, local modstubs.o.
+#
+MODSTUBS_DIR	 = $(OBJS_DIR)
+$(MODSTUBS_O)	:= AS_CPPFLAGS += -DPEM_MODULE
+CLEANFILES	+= $(MODSTUBS_O)
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
--- a/usr/src/uts/sparc/Makefile.sparc.shared	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/uts/sparc/Makefile.sparc.shared	Thu Jun 29 14:43:12 2006 -0700
@@ -267,6 +267,7 @@
 DRV_KMODS	+= pci_pci px_pci pxb_bcm pcie
 DRV_KMODS	+= i8042 kb8042 mouse8042
 DRV_KMODS	+= fcode
+DRV_KMODS	+= socal
 
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= audioens
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= audioixp
@@ -276,7 +277,6 @@
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= ifp
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= scsi_vhci
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= sgen
-$(CLOSED_BUILD)CLOSED_DRV_KMODS	+= socal
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= uata
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= usbser_edge
 
@@ -292,15 +292,13 @@
 # PCMCIA specific module(s)
 #
 DRV_KMODS	+= stp4020 pcs
-MISC_KMODS	+= busra dada pcmcia
+MISC_KMODS	+= busra cardbus dada pcmcia
 DRV_KMODS	+= pcata pcmem pcram
+DRV_KMODS	+= pcic
+DRV_KMODS	+= pem
 
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= pcelx
-$(CLOSED_BUILD)CLOSED_DRV_KMODS	+= pcic
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= pcser
-$(CLOSED_BUILD)CLOSED_DRV_KMODS	+= pem
-
-$(CLOSED_BUILD)CLOSED_MISC_KMODS	+= cardbus
 
 # Add lvm
 #
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/cardbus/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -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 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# uts/sparc/cardbus/Makefile
+#
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of the cardbus kernel module.
+#
+#	sparc architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE   = ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= cardbus
+OBJECTS		= $(CARDBUS_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(CARDBUS_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 sun4u specific header files
+#
+INC_PATH        += -I$(UTSBASE)/sun4u -I$(UTSBASE)/sun4
+
+#
+#	Overrides
+#
+DEF_BUILDS	= $(DEF_BUILDS64)
+ALL_BUILDS	= $(ALL_BUILDS64)
+CLEANLINTFILES	+= $(LINT64_FILES)
+
+#
+# lint pass one enforcement
+#
+CFLAGS += $(CCVERBOSE)
+
+CPPFLAGS        +=      -DHOTPLUG
+
+#	dependency
+LDFLAGS	+=	-dy -Nmisc/busra -Nmisc/pcmcia -Nmisc/hpcsvc
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS) lint64
+
+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/pcic/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -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 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 PCIC driver kernel module.
+#
+#	sparc architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE   = ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= pcic
+OBJECTS		= $(PCIC_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(PCIC_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/common/io
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sparc/Makefile.sparc
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+#       Include sun4u specific header files
+#
+INC_PATH        += -I$(UTSBASE)/sun4u
+
+#
+#	Overrides
+#
+DEF_BUILDS	= $(DEF_BUILDS64)
+ALL_BUILDS	= $(ALL_BUILDS64)
+CLEANLINTFILES	+= $(LINT64_FILES)
+
+#
+# lint pass one enforcement
+#
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS        +=      -DCARDBUS
+
+#	dependency
+LDFLAGS	+=	-dy -Nmisc/busra -Nmisc/pcmcia -Nmisc/cardbus
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS) lint64
+
+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/pem/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,98 @@
+#
+# 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.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This file makes the PCMCIA Event Manager driver for a sparc system
+#
+#	sparc architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	  = ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= pem
+OBJECTS		= $(PEM_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(PEM_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/common/pcmcia/pem
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sparc/Makefile.sparc
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+#	Override defaults to build a unique, local modstubs.o.
+#
+MODSTUBS_DIR	= $(OBJS_DIR)
+$(MODSTUBS_O)	:= AS_CPPFLAGS += -DPEM_MODULE
+CLEANFILES	+= $(MODSTUBS_O)
+DEF_BUILDS	= $(DEF_BUILDS64)
+ALL_BUILDS	= $(ALL_BUILDS64)
+CLEANLINTFILES	+= $(LINT64_FILES)
+
+#
+# lint pass one enforcement
+#
+CFLAGS += $(CCVERBOSE)
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS) lint64
+
+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/socal/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,98 @@
+#
+# 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.
+#
+# 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/socal/Makefile
+
+#
+# Copyright 2005 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 socal driver kernel
+#	module, which is used for the Photon/FC-AL product
+#
+#	sparc architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSCLOSED = ../..
+UTSBASE	  = ../../../../src/uts
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= socal
+OBJECTS		= $(SOCAL_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(SOCAL_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSCLOSED)/sparc/Makefile.sparc
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+#	Overrides
+#
+CFLAGS		+= $(CCVERBOSE) -dalign
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+all:		$(ALL_DEPS)
+
+def:		$(DEF_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 $(UTSCLOSED)/sparc/Makefile.targ
+
+browser:	$(BINARY)
+
+browser		:= CFLAGS += -xsb
--- a/usr/src/uts/sun/Makefile.files	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/uts/sun/Makefile.files	Thu Jun 29 14:43:12 2006 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -72,6 +72,8 @@
 
 SD_OBJS +=	sd.o sd_xbuf.o
 
+SOCAL_OBJS +=	socal.o socal_ucode.o
+
 CMLB_OBJS +=	cmlb.o
 
 DADA_OBJS +=	dcd_hba.o       dcd_transport.o \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun/io/socal.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,5035 @@
+/*
+ * 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 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * socal - Serial Optical Channel Arbitrated Loop host adapter driver.
+ */
+
+#include <sys/types.h>
+#include <sys/note.h>
+#include <sys/devops.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/user.h>
+#include <sys/buf.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <sys/fcntl.h>
+
+#include <sys/cmn_err.h>
+#include <sys/stropts.h>
+#include <sys/kmem.h>
+
+#include <sys/errno.h>
+#include <sys/open.h>
+#include <sys/varargs.h>
+#include <sys/var.h>
+#include <sys/thread.h>
+#include <sys/debug.h>
+#include <sys/cpu.h>
+#include <sys/autoconf.h>
+#include <sys/conf.h>
+#include <sys/stat.h>
+
+#include <sys/file.h>
+#include <sys/syslog.h>
+
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/ksynch.h>
+#include <sys/ddidmareq.h>
+#include <sys/dditypes.h>
+#include <sys/ethernet.h>
+#include <sys/socalreg.h>
+#include <sys/socalmap.h>
+#include <sys/fc4/fcal.h>
+#include <sys/socal_cq_defs.h>
+#include <sys/fc4/fcal_linkapp.h>
+#include <sys/fc4/fcal_transport.h>
+#include <sys/socalio.h>
+#include <sys/socalvar.h>
+
+/*
+ * Local Macros
+ */
+
+#ifdef DEBUG
+#define	SOCAL_DEBUG 1
+#else
+#define	SOCAL_DEBUG 0
+#endif
+static uchar_t	socal_xrambuf[0x40000];
+static int 	socal_core = SOCAL_TAKE_CORE;
+#if SOCAL_DEBUG > 0 && !defined(lint)
+static	int soc_debug = SOCAL_DEBUG;
+static  int socal_read_stale_data = 0;
+#define	DEBUGF(level, args) \
+	if (soc_debug >= (level)) cmn_err args;
+#define	SOCALDEBUG(level, args) \
+	if (soc_debug >= level) args;
+#else
+#define	DEBUGF(level, args)	/* Nothing */
+#define	SOCALDEBUG(level, args)	/* Nothing */
+#endif
+
+
+/* defines for properties */
+#define	SOCAL_PORT_NO_PROP		"socal_port"
+#define	SOCAL_ALT_PORT_NO_PROP		"port#"
+
+/* for socal_force_reset() */
+#define	RESET_PORT			1
+#define	DONT_RESET_PORT			0
+
+/*
+ * Driver Entry points.
+ */
+static int socal_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
+static int socal_bus_ctl(dev_info_t *dip, dev_info_t *rip,
+	ddi_ctl_enum_t op, void *a, void *v);
+static int socal_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
+static int socal_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
+	void *arg, void **result);
+static unsigned int socal_intr(caddr_t arg);
+static unsigned int socal_dummy_intr(caddr_t arg);
+static int socal_open(dev_t *devp, int flag, int otyp,
+	cred_t *cred_p);
+static int socal_close(dev_t dev, int flag, int otyp,
+	cred_t *cred_p);
+static int socal_ioctl(dev_t dev, int cmd, intptr_t arg,
+	int mode, cred_t *cred_p, int *rval_p);
+
+/*
+ * FC_AL transport functions.
+ */
+static uint_t socal_transport(fcal_packet_t *, fcal_sleep_t, int);
+static uint_t socal_transport_poll(fcal_packet_t *, uint_t, int);
+static uint_t socal_lilp_map(void *, uint_t, uint32_t, uint_t);
+static uint_t socal_force_lip(void *, uint_t, uint_t, uint_t);
+static uint_t socal_force_offline(void *, uint_t, uint_t);
+static uint_t socal_abort_cmd(void *, uint_t, fcal_packet_t *, uint_t);
+static uint_t socal_doit(fcal_packet_t *, socal_port_t *, int,
+    void (*)(), int, int, uint_t *);
+static uint_t socal_els(void *, uint_t, uint_t, uint_t,
+	void (*callback)(), void *, caddr_t, caddr_t *, uint_t);
+static uint_t socal_bypass_dev(void *, uint_t, uint_t);
+static void socal_force_reset(void *, uint_t, uint_t);
+static void socal_add_ulp(void *, uint_t, uchar_t, void (*)(),
+	void (*)(), void (*)(), void *);
+static void socal_remove_ulp(void *, uint_t, uchar_t, void *);
+static void socal_take_core(void *);
+
+/*
+ * Driver internal functions.
+ */
+static void socal_intr_solicited(socal_state_t *, uint32_t srq);
+static void socal_intr_unsolicited(socal_state_t *, uint32_t urq);
+static void socal_lilp_map_done(fcal_packet_t *);
+static void socal_force_lip_done(fcal_packet_t *);
+static void socal_force_offline_done(fcal_packet_t *);
+static void socal_abort_done(fcal_packet_t *);
+static void socal_bypass_dev_done(fcal_packet_t *);
+static fcal_packet_t *socal_packet_alloc(socal_state_t *, fcal_sleep_t);
+static void socal_packet_free(fcal_packet_t *);
+static void socal_disable(socal_state_t *socalp);
+static void socal_init_transport_interface(socal_state_t *socalp);
+static int socal_cqalloc_init(socal_state_t *socalp, uint32_t index);
+static void socal_cqinit(socal_state_t *socalp, uint32_t index);
+static int socal_start(socal_state_t *socalp);
+static void socal_doreset(socal_state_t *socalp);
+static int socal_dodetach(dev_info_t *dip);
+static int socal_diag_request(socal_state_t *socalp, uint32_t port,
+	uint_t *diagcode, uint32_t cmd);
+static void socal_download_ucode(socal_state_t *socalp);
+static void socal_init_cq_desc(socal_state_t *socalp);
+static void socal_init_wwn(socal_state_t *socalp);
+static void socal_enable(socal_state_t *socalp);
+static int socal_establish_pool(socal_state_t *socalp, uint32_t poolid);
+static int socal_add_pool_buffer(socal_state_t *socalp, uint32_t poolid);
+static int socal_issue_adisc(socal_state_t *socalp, uint32_t port, uint32_t
+	dest, la_els_adisc_t *adisc_pl, uint32_t polled);
+static int socal_issue_lbf(socal_state_t *socalp, uint32_t port,
+	uchar_t *flb_pl, size_t length, uint32_t polled);
+static int socal_issue_rls(socal_state_t *socalp, uint32_t port, uint32_t
+	dest, la_els_rls_reply_t *rls_pl, uint32_t polled);
+static void socal_us_els(socal_state_t *, cqe_t *, caddr_t);
+static fcal_packet_t *socal_els_alloc(socal_state_t *, uint32_t, uint32_t,
+	uint32_t, uint32_t, caddr_t *, uint32_t);
+static fcal_packet_t *socal_lbf_alloc(socal_state_t *, uint32_t,
+	uint32_t, uint32_t, caddr_t *, uint32_t);
+static void socal_els_free(socal_priv_cmd_t *);
+static void socal_lbf_free(socal_priv_cmd_t *);
+static int socal_getmap(socal_state_t *socalp, uint32_t port, caddr_t arg,
+	uint32_t polled, int);
+static void socal_flush_overflowq(socal_state_t *, int, int);
+static void socal_deferred_intr(void *);
+static void socal_fix_harda(socal_state_t *socalp, int port);
+
+/*
+ * SOC+ Circular Queue Management routines.
+ */
+static int socal_cq_enque(socal_state_t *, socal_port_t *, cqe_t *, int,
+	fcal_sleep_t, fcal_packet_t *, int);
+
+/*
+ * Utility functions
+ */
+static void socal_disp_err(socal_state_t *, uint_t level, char *mid, char *msg);
+static void socal_wcopy(uint_t *, uint_t *, int);
+
+/*
+ *  Set this bit to enable 64-bit sus mode
+ */
+static	int socal_64bitsbus = 1;
+
+/*
+ * Default soc dma limits
+ */
+
+static ddi_dma_lim_t default_socallim = {
+	(ulong_t)0, (ulong_t)0xffffffff, (uint_t)0xffffffff,
+	DEFAULT_BURSTSIZE | BURST32 | BURST64, 1, (25*1024)
+};
+
+static struct ddi_dma_attr socal_dma_attr = {
+	DMA_ATTR_V0,			/* version */
+	(unsigned long long)0,		/* addr_lo */
+	(unsigned long long)0xffffffff,	/* addr_hi */
+	(unsigned long long)0xffffffff,	/* count max */
+	(unsigned long long)4,		/* align */
+	DEFAULT_BURSTSIZE | BURST32 | BURST64, 	/* burst size */
+	1,				/* minxfer */
+	(unsigned long long)0xffffffff,	/* maxxfer */
+	(unsigned long long)0xffffffff,	/* seg */
+	1,				/* sgllen */
+	4,				/* granularity */
+	0				/* flags */
+};
+
+static struct ddi_device_acc_attr socal_acc_attr = {
+	(ushort_t)DDI_DEVICE_ATTR_V0,	/* version */
+	(uchar_t)DDI_STRUCTURE_BE_ACC,	/* endian flags */
+	(uchar_t)DDI_STRICTORDER_ACC	/* data order */
+};
+
+static struct fcal_transport_ops socal_transport_ops = {
+	socal_transport,
+	socal_transport_poll,
+	socal_lilp_map,
+	socal_force_lip,
+	socal_abort_cmd,
+	socal_els,
+	socal_bypass_dev,
+	socal_force_reset,
+	socal_add_ulp,
+	socal_remove_ulp,
+	socal_take_core
+};
+
+/*
+ * Table used for setting the burst size in the soc+ config register
+ */
+static int socal_burst32_table[] = {
+	SOCAL_CR_BURST_4,
+	SOCAL_CR_BURST_4,
+	SOCAL_CR_BURST_4,
+	SOCAL_CR_BURST_4,
+	SOCAL_CR_BURST_16,
+	SOCAL_CR_BURST_32,
+	SOCAL_CR_BURST_64
+};
+
+/*
+ * Table for setting the burst size for 64-bit sbus mode in soc+'s CR
+ */
+static int socal_burst64_table[] = {
+	(SOCAL_CR_BURST_8 << 8),
+	(SOCAL_CR_BURST_8 << 8),
+	(SOCAL_CR_BURST_8 << 8),
+	(SOCAL_CR_BURST_8 << 8),
+	(SOCAL_CR_BURST_8 << 8),
+	(SOCAL_CR_BURST_32 << 8),
+	(SOCAL_CR_BURST_64 << 8),
+	(SOCAL_CR_BURST_128 << 8)
+};
+
+/*
+ * Tables used to define the sizes of the Circular Queues
+ *
+ * To conserve DVMA/IOPB space, we make some of these queues small...
+ */
+static int socal_req_entries[] = {
+	SOCAL_SMALL_CQ_ENTRIES,		/* Error (reset, lip) requests */
+	SOCAL_MAX_CQ_ENTRIES,		/* Most commands */
+	0,				/* Not currently used */
+	0				/* Not currently used */
+};
+
+static int socal_rsp_entries[] = {
+	SOCAL_MAX_CQ_ENTRIES,		/* Solicited  "SOC_OK" responses */
+	SOCAL_SMALL_CQ_ENTRIES,		/* Solicited error responses */
+	0,			/* Unsolicited responses */
+	0				/* Not currently used */
+};
+
+/*
+ * Bus ops vector
+ */
+
+static struct bus_ops socal_bus_ops = {
+	BUSO_REV,		/* rev */
+	nullbusmap,		/* int (*bus_map)() */
+	0,			/* ddi_intrspec_t (*bus_get_intrspec)(); */
+	0,			/* int (*bus_add_intrspec)(); */
+	0,			/* void	(*bus_remove_intrspec)(); */
+	i_ddi_map_fault,	/* int (*bus_map_fault)() */
+	ddi_dma_map,		/* int (*bus_dma_map)() */
+	ddi_dma_allochdl,
+	ddi_dma_freehdl,
+	ddi_dma_bindhdl,
+	ddi_dma_unbindhdl,
+	ddi_dma_flush,
+	ddi_dma_win,
+	ddi_dma_mctl,		/* int (*bus_dma_ctl)() */
+	socal_bus_ctl,		/* int (*bus_ctl)() */
+	ddi_bus_prop_op		/* int (*bus_prop_op*)() */
+};
+
+static struct cb_ops socal_cb_ops = {
+	socal_open,		/* int (*cb_open)() */
+	socal_close,		/* int (*cb_close)() */
+	nodev,			/* int (*cb_strategy)() */
+	nodev,			/* int (*cb_print)() */
+	nodev,			/* int (*cb_dump)() */
+	nodev,			/* int (*cb_read)() */
+	nodev,			/* int (*cb_write)() */
+	socal_ioctl,		/* int (*cb_ioctl)() */
+	nodev,			/* int (*cb_devmap)() */
+	nodev,			/* int (*cb_mmap)() */
+	nodev,			/* int (*cb_segmap)() */
+	nochpoll,		/* int (*cb_chpoll)() */
+	ddi_prop_op,		/* int (*cb_prop_op)() */
+	0,			/* struct streamtab *cb_str */
+	D_MP|D_NEW|D_HOTPLUG,	/* cb_flag */
+	CB_REV,			/* rev */
+	nodev,			/* int (*cb_aread)() */
+	nodev			/* int (*cb_awrite)() */
+};
+
+/*
+ * Soc driver ops structure.
+ */
+
+static struct dev_ops socal_ops = {
+	DEVO_REV,		/* devo_rev, */
+	0,			/* refcnt */
+	socal_getinfo,		/* get_dev_info */
+	nulldev,		/* identify */
+	nulldev,		/* probe */
+	socal_attach,		/* attach */
+	socal_detach,		/* detach */
+	nodev,			/* reset */
+	&socal_cb_ops,		/* driver operations */
+	&socal_bus_ops		/* bus operations */
+};
+
+/*
+ * Driver private variables.
+ */
+
+static void *socal_soft_state_p = NULL;
+static ddi_dma_lim_t *socallim = NULL;
+
+static uchar_t socal_switch_to_alpa[] = {
+	0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6,
+	0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, 0xcd, 0xcc, 0xcb, 0xca,
+	0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5,
+	0xb4, 0xb3, 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9,
+	0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, 0x98, 0x97,
+	0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79,
+	0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b,
+	0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
+	0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a,
+	0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, 0x3a, 0x39, 0x36, 0x35,
+	0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
+	0x27, 0x26, 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17,
+	0x10, 0x0f, 0x08, 0x04, 0x02, 0x01, 0x00
+};
+
+/*
+ * Firmware related externs
+ */
+extern uint32_t socal_ucode[];
+extern size_t socal_ucode_size;
+
+/*
+ * This is the loadable module wrapper: "module configuration section".
+ */
+
+#include <sys/modctl.h>
+extern struct mod_ops mod_driverops;
+
+/*
+ * Module linkage information for the kernel.
+ */
+#define	SOCAL_NAME "SOC+ FC-AL Host Adapter Driver"
+static	char	socal_version[] = "%I% %E%";
+static struct modldrv modldrv = {
+	&mod_driverops,		/* Type of module.  This one is a driver */
+	SOCAL_NAME " %I%",
+	&socal_ops,		/* driver ops */
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1, (void *)&modldrv, NULL
+};
+
+/*
+ * This is the module initialization/completion routines
+ */
+
+#if !defined(lint)
+static char socal_initmsg[] = "socal _init: socal.c\t%I%\t%E%\n";
+#endif
+
+int
+_init(void)
+{
+	int stat;
+
+	DEBUGF(4, (CE_CONT, socal_initmsg));
+
+	/* Allocate soft state.  */
+	stat = ddi_soft_state_init(&socal_soft_state_p,
+		sizeof (socal_state_t), SOCAL_INIT_ITEMS);
+	if (stat != 0)
+		return (stat);
+
+	/* Install the module */
+	stat = mod_install(&modlinkage);
+	if (stat != 0)
+		ddi_soft_state_fini(&socal_soft_state_p);
+
+	DEBUGF(4, (CE_CONT, "socal: _init: return=%d\n", stat));
+	return (stat);
+}
+
+int
+_fini(void)
+{
+	int stat;
+
+	if ((stat = mod_remove(&modlinkage)) != 0)
+		return (stat);
+
+	DEBUGF(4, (CE_CONT, "socal: _fini: \n"));
+
+	ddi_soft_state_fini(&socal_soft_state_p);
+
+	DEBUGF(4, (CE_CONT, "socal: _fini: return=%d\n", stat));
+	return (stat);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+
+int
+socal_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	int			instance;
+	socal_state_t		*socalp;
+	struct ether_addr	ourmacaddr;
+	socal_port_t		*porta, *portb;
+	char			buf[MAXPATHLEN];
+	char			*cptr, *wwn;
+	int			y;
+	int			i, j;
+	int			burstsize;
+	short			s;
+	int			loop_id;
+
+	int			rval;
+
+
+	instance = ddi_get_instance(dip);
+
+	DEBUGF(4, (CE_CONT, "socal%d entering attach: cmd=%x\n", instance,
+	    cmd));
+
+	if (cmd == DDI_RESUME) {
+		if ((socalp = ddi_get_driver_private(dip)) == NULL)
+			return (DDI_FAILURE);
+
+		if (!socalp->socal_shutdown) {
+			/* our work is already done */
+			return (DDI_SUCCESS);
+		}
+		if (socal_start(socalp) != FCAL_SUCCESS) {
+			return	(DDI_FAILURE);
+		}
+		DEBUGF(4, (CE_CONT, "socal%d resumed\n", instance));
+		return (DDI_SUCCESS);
+	}
+
+	if (cmd != DDI_ATTACH) {
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_dev_is_sid(dip) != DDI_SUCCESS) {
+		cmn_err(CE_WARN, "socal%d probe: Not self-identifying",
+			instance);
+		return (DDI_FAILURE);
+	}
+
+	/* If we are in a slave-slot, then we can't be used. */
+	if (ddi_slaveonly(dip) == DDI_SUCCESS) {
+		cmn_err(CE_WARN,
+			"socal%d attach failed: device in slave-only slot",
+				instance);
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_intr_hilevel(dip, 0)) {
+		/*
+		 * Interrupt number '0' is a high-level interrupt.
+		 * At this point you either add a special interrupt
+		 * handler that triggers a soft interrupt at a lower level,
+		 * or - more simply and appropriately here - you just
+		 * fail the attach.
+		 */
+		cmn_err(CE_WARN,
+		"socal%d attach failed: hilevel interrupt unsupported",
+			instance);
+		return (DDI_FAILURE);
+	}
+
+	/* Allocate soft state. */
+	if (ddi_soft_state_zalloc(socal_soft_state_p, instance)
+	    != DDI_SUCCESS) {
+		cmn_err(CE_WARN, "socal%d attach failed: alloc soft state",
+			instance);
+		return (DDI_FAILURE);
+	}
+	DEBUGF(4, (CE_CONT, "socal%d attach: allocated soft state\n",
+		instance));
+
+	/*
+	 * Initialize the state structure.
+	 */
+	socalp = ddi_get_soft_state(socal_soft_state_p, instance);
+	if (socalp == (socal_state_t *)NULL) {
+		cmn_err(CE_WARN, "socal%d attach failed: bad soft state",
+			instance);
+		return (DDI_FAILURE);
+	}
+	DEBUGF(4, (CE_CONT, "socal%d: attach: soc soft state ptr=0x%p\n",
+		instance, socalp));
+
+	socalp->dip = dip;
+	socallim = &default_socallim;
+	porta = &socalp->port_state[0];
+	portb = &socalp->port_state[1];
+
+	/* Get the full path name for displaying error messages */
+	cptr = ddi_pathname(dip, buf);
+	(void) strcpy(socalp->socal_name, cptr);
+
+	porta->sp_unsol_cb = NULL;
+	portb->sp_unsol_cb = NULL;
+	porta->sp_port = 0;
+	portb->sp_port = 1;
+	porta->sp_board = socalp;
+	portb->sp_board = socalp;
+
+	porta->sp_lilpmap_valid = 0;
+	portb->sp_lilpmap_valid = 0;
+
+	/*
+	 * If an hard loop-id property is present, then the port is going
+	 * to be used in target-mode so set the target-mode flag.
+	 */
+	loop_id = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "port0-loop-id", 127);
+	if (loop_id >= 0 && loop_id <= 126) {
+		porta->sp_status |= PORT_TARGET_MODE;
+		porta->sp_hard_alpa = socal_switch_to_alpa[loop_id];
+	} else porta->sp_hard_alpa = 0xfe;
+
+	loop_id = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "port1-loop-id", 127);
+	if (loop_id >= 0 && loop_id <= 126) {
+		portb->sp_status |= PORT_TARGET_MODE;
+		portb->sp_hard_alpa = socal_switch_to_alpa[loop_id];
+	} else portb->sp_hard_alpa = 0xfe;
+
+	/* Get out Node wwn and calculate port wwns */
+	rval = ddi_prop_op(DDI_DEV_T_ANY, dip,
+		PROP_LEN_AND_VAL_ALLOC, DDI_PROP_DONTPASS |
+		DDI_PROP_CANSLEEP, "wwn", (caddr_t)&wwn, &i);
+
+	if ((rval != DDI_PROP_SUCCESS) || (i < FC_WWN_SIZE) ||
+	    (bcmp(wwn, "00000000", FC_WWN_SIZE) == 0)) {
+		(void) localetheraddr((struct ether_addr *)NULL, &ourmacaddr);
+
+		bcopy((caddr_t)&ourmacaddr, (caddr_t)&s, sizeof (short));
+		socalp->socal_n_wwn.w.wwn_hi = s;
+		bcopy((caddr_t)&ourmacaddr+2,
+			(caddr_t)&socalp->socal_n_wwn.w.wwn_lo,
+			sizeof (uint_t));
+		socalp->socal_n_wwn.w.naa_id = NAA_ID_IEEE;
+		socalp->socal_n_wwn.w.nport_id = 0;
+	} else {
+		bcopy((caddr_t)wwn, (caddr_t)&socalp->socal_n_wwn, FC_WWN_SIZE);
+	}
+
+	if (rval == DDI_SUCCESS)
+		kmem_free((void *)wwn, i);
+
+	for (i = 0; i < FC_WWN_SIZE; i++) {
+		(void) sprintf(&socalp->socal_stats.node_wwn[i << 1],
+			"%02x", socalp->socal_n_wwn.raw_wwn[i]);
+	}
+	DEBUGF(4, (CE_CONT, "socal%d attach: node wwn: %s\n",
+		instance, socalp->socal_stats.node_wwn));
+
+	bcopy((caddr_t)&socalp->socal_n_wwn, (caddr_t)&porta->sp_p_wwn,
+		sizeof (la_wwn_t));
+	bcopy((caddr_t)&socalp->socal_n_wwn, (caddr_t)&portb->sp_p_wwn,
+		sizeof (la_wwn_t));
+	porta->sp_p_wwn.w.naa_id = NAA_ID_IEEE_EXTENDED;
+	portb->sp_p_wwn.w.naa_id = NAA_ID_IEEE_EXTENDED;
+	porta->sp_p_wwn.w.nport_id = instance*2;
+	portb->sp_p_wwn.w.nport_id = instance*2+1;
+
+	for (i = 0; i < FC_WWN_SIZE; i++) {
+		(void) sprintf(&socalp->socal_stats.port_wwn[0][i << 1],
+			"%02x", porta->sp_p_wwn.raw_wwn[i]);
+		(void) sprintf(&socalp->socal_stats.port_wwn[1][i << 1],
+			"%02x", portb->sp_p_wwn.raw_wwn[i]);
+	}
+	DEBUGF(4, (CE_CONT, "socal%d attach: porta wwn: %s\n",
+		instance, socalp->socal_stats.port_wwn[0]));
+	DEBUGF(4, (CE_CONT, "socal%d attach: portb wwn: %s\n",
+		instance, socalp->socal_stats.port_wwn[1]));
+
+	if ((porta->sp_transport = (fcal_transport_t *)
+		kmem_zalloc(sizeof (fcal_transport_t), KM_SLEEP)) == NULL) {
+		socal_disp_err(socalp, CE_WARN, "attach.4011",
+			"attach failed: unable to alloc xport struct");
+		goto fail;
+	}
+
+	if ((portb->sp_transport = (fcal_transport_t *)
+		kmem_zalloc(sizeof (fcal_transport_t), KM_SLEEP)) == NULL) {
+		socal_disp_err(socalp, CE_WARN, "attach.4012",
+			"attach failed: unable to alloc xport struct");
+		goto fail;
+	}
+	DEBUGF(4, (CE_CONT, "socal%d attach: allocated transport structs\n",
+		instance));
+
+	/*
+	 * Map the external ram and registers for SOC+.
+	 * Note: Soc+ sbus host adapter provides 3 register definition
+	 * but on-board Soc+'s  may have only one register definition.
+	 */
+	if ((ddi_dev_nregs(dip, &i) == DDI_SUCCESS) && (i == 1)) {
+		/* Map XRAM */
+		if (ddi_map_regs(dip, 0, &socalp->socal_xrp, 0, 0)
+			!= DDI_SUCCESS) {
+			socalp->socal_xrp = NULL;
+			socal_disp_err(socalp, CE_WARN, "attach.4020",
+				"attach failed: unable to map XRAM");
+			goto fail;
+		}
+		/* Map registers */
+		socalp->socal_rp = (socal_reg_t *)(socalp->socal_xrp +
+			SOCAL_XRAM_SIZE);
+	} else {
+		/* Map EEPROM */
+		if (ddi_map_regs(dip, 0, &socalp->socal_eeprom, 0, 0) !=
+		    DDI_SUCCESS) {
+			socalp->socal_eeprom = NULL;
+			socal_disp_err(socalp, CE_WARN, "attach.4010",
+				"attach failed: unable to map eeprom");
+			goto fail;
+		}
+	DEBUGF(4, (CE_CONT, "socal%d attach: mapped eeprom 0x%p\n",
+		instance, socalp->socal_eeprom));
+		/* Map XRAM */
+		if (ddi_map_regs(dip, 1, &socalp->socal_xrp, 0, 0) !=
+			DDI_SUCCESS) {
+			socalp->socal_xrp = NULL;
+			socal_disp_err(socalp, CE_WARN, "attach.4020",
+				"attach failed: unable to map XRAM");
+			goto fail;
+		}
+	DEBUGF(4, (CE_CONT, "socal%d attach: mapped xram 0x%p\n",
+		instance, socalp->socal_xrp));
+		/* Map registers */
+		if (ddi_map_regs(dip, 2, (caddr_t *)&socalp->socal_rp, 0, 0) !=
+			DDI_SUCCESS) {
+			socalp->socal_rp = NULL;
+			socal_disp_err(socalp, CE_WARN, "attach.4030",
+				"attach failed: unable to map registers");
+			goto fail;
+		}
+	DEBUGF(4, (CE_CONT, "socal%d attach: mapped regs 0x%p\n",
+		instance, socalp->socal_rp));
+	}
+	/*
+	 * Check to see we really have a SOC+ Host Adapter card installed
+	 */
+	if (ddi_peek32(dip, (int32_t *)&socalp->socal_rp->socal_csr.w,
+		(int32_t *)NULL) != DDI_SUCCESS) {
+		socal_disp_err(socalp, CE_WARN, "attach.4040",
+			"attach failed: unable to access status register");
+		goto fail;
+	}
+	/* now that we have our registers mapped make sure soc+ reset */
+	socal_disable(socalp);
+
+	/* try defacing a spot in XRAM */
+	if (ddi_poke32(dip, (int32_t *)(socalp->socal_xrp + SOCAL_XRAM_UCODE),
+		0xdefaced) != DDI_SUCCESS) {
+		socal_disp_err(socalp, CE_WARN, "attach.4050",
+			"attach failed: unable to write host adapter XRAM");
+		goto fail;
+	}
+
+	/* see if it stayed defaced */
+	if (ddi_peek32(dip, (int32_t *)(socalp->socal_xrp + SOCAL_XRAM_UCODE),
+	    (int32_t *)&y)
+		!= DDI_SUCCESS) {
+		socal_disp_err(socalp, CE_WARN, "attach.4051",
+			"attach failed: unable to access host adapter XRAM");
+		goto fail;
+	}
+
+#ifdef DEBUG
+	for (i = 0; i < 4; i++) {
+		socalp->socal_rp->socal_cr.w &=
+			~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
+		socalp->socal_rp->socal_cr.w |= i<<24;
+		cptr = (char *)(socal_xrambuf + (i*0x10000));
+		bcopy((caddr_t)socalp->socal_xrp, (caddr_t)cptr, 0x10000);
+	}
+	socalp->socal_rp->socal_cr.w &= ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
+#endif
+
+	DEBUGF(4, (CE_CONT, "socal%d attach: read xram\n", instance));
+
+	if (y != 0xdefaced) {
+		socal_disp_err(socalp, CE_WARN, "attach.4052",
+			"attach failed: read/write mismatch in XRAM");
+		goto fail;
+	}
+
+	/* Point to the SOC XRAM CQ Descriptor locations. */
+	socalp->xram_reqp = (soc_cq_t *)(socalp->socal_xrp +
+		SOCAL_XRAM_REQ_DESC);
+	socalp->xram_rspp = (soc_cq_t *)(socalp->socal_xrp +
+		SOCAL_XRAM_RSP_DESC);
+
+	if ((socalp->socal_ksp = kstat_create("socal", instance, "statistics",
+	    "controller", KSTAT_TYPE_RAW, sizeof (struct socal_stats),
+	    KSTAT_FLAG_VIRTUAL)) == NULL) {
+		socal_disp_err(socalp, CE_WARN, "attach.4053",
+			"unable to create kstats");
+	} else {
+		socalp->socal_stats.version = 2;
+		(void) sprintf(socalp->socal_stats.drvr_name,
+			"%s: %s", SOCAL_NAME, socal_version);
+		socalp->socal_stats.pstats[0].port = 0;
+		socalp->socal_stats.pstats[1].port = 1;
+		socalp->socal_ksp->ks_data = (void *)&socalp->socal_stats;
+		kstat_install(socalp->socal_ksp);
+	}
+
+	/*
+	 * Install a dummy interrupt routine.
+	 */
+	if (ddi_add_intr(dip,
+		(uint_t)0,
+		&socalp->iblkc,
+		&socalp->idevc,
+		socal_dummy_intr,
+		(caddr_t)socalp) != DDI_SUCCESS) {
+		    socal_disp_err(socalp, CE_WARN, "attach.4060",
+			"attach failed: unable to install interrupt handler");
+		    goto fail;
+	}
+
+	ddi_set_driver_private(dip, socalp);
+
+	/* initialize the interrupt mutex */
+	mutex_init(&socalp->k_imr_mtx, NULL, MUTEX_DRIVER,
+	    (void *)socalp->iblkc);
+
+	mutex_init(&socalp->board_mtx, NULL, MUTEX_DRIVER,
+	    (void *)socalp->iblkc);
+	mutex_init(&socalp->ioctl_mtx, NULL, MUTEX_DRIVER,
+	    (void *)socalp->iblkc);
+
+	/* initialize the abort mutex */
+	mutex_init(&socalp->abort_mtx, NULL, MUTEX_DRIVER,
+	    (void *)socalp->iblkc);
+
+	cv_init(&socalp->board_cv, NULL, CV_DRIVER, NULL);
+	DEBUGF(4, (CE_CONT,
+		"socal%d: attach: inited imr mutex, board mutex, board cv\n",
+		instance));
+
+	/* init the port mutexes */
+	mutex_init(&porta->sp_mtx, NULL, MUTEX_DRIVER, socalp->iblkc);
+	cv_init(&porta->sp_cv, NULL, CV_DRIVER, NULL);
+	mutex_init(&portb->sp_mtx, NULL, MUTEX_DRIVER, socalp->iblkc);
+	cv_init(&portb->sp_cv, NULL, CV_DRIVER, NULL);
+	DEBUGF(4, (CE_CONT, "socal%d: attach: inited port mutexes and cvs\n",
+		instance));
+
+	/* get local copy of service params */
+	socal_wcopy((uint_t *)socalp->socal_xrp + SOCAL_XRAM_SERV_PARAMS,
+		(uint_t *)socalp->socal_service_params, SOCAL_SVC_LENGTH);
+	DEBUGF(4, (CE_CONT, "socal%d: attach: got service params\n", instance));
+	/*
+	 * Initailize the FCAL transport interface.
+	 */
+	socal_init_transport_interface(socalp);
+	DEBUGF(4, (CE_CONT, "socal%d: attach: initalized transport interface\n",
+		instance));
+
+	/*
+	 * Allocate request and response queues and init their mutexs.
+	 */
+	for (i = 0; i < SOCAL_N_CQS; i++) {
+		if (socal_cqalloc_init(socalp, i) != FCAL_SUCCESS) {
+			goto fail;
+		}
+	}
+	DEBUGF(4, (CE_CONT, "socal%d: attach: allocated cqs\n", instance));
+
+	/*
+	 * Adjust the burst size we'll use.
+	 */
+	burstsize = ddi_dma_burstsizes(socalp->request[0].skc_dhandle);
+	DEBUGF(4, (CE_CONT, "socal%d: attach: burstsize = 0x%x\n",
+		instance, burstsize));
+	j = burstsize & BURSTSIZE_MASK;
+	for (i = 0; socal_burst32_table[i] != SOCAL_CR_BURST_64; i++)
+		if (!(j >>= 1)) break;
+
+	socalp->socal_cfg = (socalp->socal_cfg & ~SOCAL_CR_SBUS_BURST_SIZE_MASK)
+		| socal_burst32_table[i];
+
+	if (socal_64bitsbus) {
+	    if (ddi_dma_set_sbus64(socalp->request[0].skc_dhandle,
+		socal_dma_attr.dma_attr_burstsizes | BURST128) == DDI_SUCCESS) {
+			DEBUGF(4, (CE_CONT, "socal%d: enabled 64 bit sbus\n",
+				instance));
+			socalp->socal_cfg |= SOCAL_CR_SBUS_ENHANCED;
+			burstsize = ddi_dma_burstsizes(socalp->request[0].
+			    skc_dhandle);
+		DEBUGF(4, (CE_CONT, "socal%d: attach: 64bit burstsize = 0x%x\n",
+		    instance, burstsize));
+			j = burstsize & BURSTSIZE_MASK;
+			for (i = 0; socal_burst64_table[i] !=
+			    (SOCAL_CR_BURST_128 << 8); i++)
+				if (!(j >>= 1))
+					break;
+
+			socalp->socal_cfg = (socalp->socal_cfg &
+			    ~SOCAL_CR_SBUS_BURST_SIZE_64BIT_MASK) |
+			    socal_burst64_table[i];
+	    }
+	}
+
+	ddi_remove_intr(dip, 0, socalp->iblkc);
+	socalp->iblkc = (void *)NULL;
+	/*
+	 * Install the interrupt routine.
+	 */
+	if (ddi_add_intr(dip,
+		(uint_t)0,
+		&socalp->iblkc,
+		&socalp->idevc,
+		socal_intr,
+		(caddr_t)socalp) != DDI_SUCCESS) {
+		    socal_disp_err(socalp, CE_WARN, "attach.4060",
+			"attach failed: unable to install interrupt handler");
+		    goto fail;
+	}
+
+	DEBUGF(4, (CE_CONT, "socal%d: attach: set config reg %x\n",
+		instance, socalp->socal_cfg));
+
+	if (ddi_create_minor_node(dip, SOCAL_PORTA_NAME, S_IFCHR,
+		instance*N_SOCAL_NPORTS, SOCAL_NT_PORT, 0) != DDI_SUCCESS)
+		goto fail;
+	if (ddi_create_minor_node(dip, SOCAL_PORTB_NAME, S_IFCHR,
+		instance*N_SOCAL_NPORTS+1, SOCAL_NT_PORT, 0) != DDI_SUCCESS)
+		goto fail;
+
+	if (socal_start(socalp) != FCAL_SUCCESS)
+		goto fail;
+	DEBUGF(4, (CE_CONT, "socal%d: attach: soc+ started\n", instance));
+
+	ddi_report_dev(dip);
+
+	DEBUGF(2, (CE_CONT, "socal%d: attach O.K.\n\n", instance));
+
+	return (DDI_SUCCESS);
+
+fail:
+	DEBUGF(4, (CE_CONT, "socal%d: attach: DDI_FAILURE\n", instance));
+
+	/* Make sure soc reset */
+	socal_disable(socalp);
+
+	/* let detach do the dirty work */
+	(void) socal_dodetach(dip);
+
+	return (DDI_FAILURE);
+}
+
+static int
+socal_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+	int		resp;
+	socal_state_t	*socalp;
+	int		i;
+
+
+	switch (cmd) {
+
+	case DDI_SUSPEND:
+		DEBUGF(4, (CE_CONT, "socal: suspend called\n"));
+
+		if ((socalp = ddi_get_driver_private(dip)) == NULL)
+			return (DDI_FAILURE);
+
+		/*
+		 * If any of the ports are in target-mode, don't suspend
+		 */
+		for (i = 0; i < N_SOCAL_NPORTS; i++) {
+			if (socalp->port_state[i].sp_status & PORT_TARGET_MODE)
+				return (DDI_FAILURE);
+		}
+
+		/* do not restart socal after reset */
+		socal_force_reset((void *)socalp, 0, DONT_RESET_PORT);
+
+		return (DDI_SUCCESS);
+
+	case DDI_DETACH:
+		DEBUGF(4, (CE_CONT, "socal: detach called\n"));
+		resp = socal_dodetach(dip);
+		if (resp == DDI_SUCCESS)
+			ddi_set_driver_private(dip, NULL);
+		return (resp);
+
+	default:
+		return (DDI_FAILURE);
+	}
+}
+
+static int
+socal_dodetach(dev_info_t *dip)
+{
+
+	int		instance = ddi_get_instance(dip);
+	int		i;
+	socal_state_t	*socalp;
+	socal_port_t	*portp;
+	socal_unsol_cb_t	*cb, *cbn = NULL;
+
+	/* Get the soft state struct. */
+	if ((socalp = ddi_get_soft_state(socal_soft_state_p, instance)) == 0) {
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * If somebody is still attached to us from above fail
+	 * detach.
+	 */
+	mutex_enter(&socalp->board_mtx);
+	if (socalp->socal_busy > 0) {
+		mutex_exit(&socalp->board_mtx);
+		return (DDI_FAILURE);
+	}
+	/* mark socal_busy = -1 to disallow sftm attach */
+	socalp->socal_busy = -1;
+	mutex_exit(&socalp->board_mtx);
+
+	/* Make sure soc+ reset */
+	mutex_enter(&socalp->k_imr_mtx);
+	socal_disable(socalp);
+	mutex_exit(&socalp->k_imr_mtx);
+
+	/* remove soc+ interrupt */
+	if (socalp->iblkc != (void *)NULL) {
+		ddi_remove_intr(dip, (uint_t)0, socalp->iblkc);
+		DEBUGF(2, (CE_CONT,
+		"socal%d: detach: Removed SOC+ interrupt from ddi\n",
+		instance));
+	}
+
+	for (i = 0; i < N_SOCAL_NPORTS; i++) {
+		portp = &socalp->port_state[i];
+		mutex_destroy(&portp->sp_mtx);
+		cv_destroy(&portp->sp_cv);
+		mutex_destroy(&portp->sp_transport->fcal_mtx);
+		cv_destroy(&portp->sp_transport->fcal_cv);
+		kmem_free((void *)portp->sp_transport,
+			sizeof (fcal_transport_t));
+		for (cb = portp->sp_unsol_cb; cb != (socal_unsol_cb_t *)NULL;
+			cb = cbn) {
+			cbn = cb->next;
+			kmem_free((void *)cb, sizeof (socal_unsol_cb_t));
+		}
+		portp->sp_unsol_cb = (socal_unsol_cb_t *)NULL;
+	}
+
+	/*
+	 * Free request queues, if allocated
+	 */
+	for (i = 0; i < SOCAL_N_CQS; i++) {
+		/* Free the queues and destroy their mutexes. */
+		mutex_destroy(&socalp->request[i].skc_mtx);
+		mutex_destroy(&socalp->response[i].skc_mtx);
+		cv_destroy(&socalp->request[i].skc_cv);
+		cv_destroy(&socalp->response[i].skc_cv);
+
+		if (socalp->request[i].skc_dhandle) {
+			(void) ddi_dma_unbind_handle(socalp->
+			    request[i].skc_dhandle);
+			ddi_dma_free_handle(&socalp->request[i].skc_dhandle);
+		}
+		if (socalp->request[i].skc_cq_raw) {
+			ddi_dma_mem_free(&socalp->request[i].skc_acchandle);
+			socalp->request[i].skc_cq_raw = NULL;
+			socalp->request[i].skc_cq = NULL;
+		}
+		if (socalp->response[i].skc_dhandle) {
+			(void) ddi_dma_unbind_handle(socalp->
+			    response[i].skc_dhandle);
+			ddi_dma_free_handle(&socalp->response[i].skc_dhandle);
+		}
+		if (socalp->response[i].skc_cq_raw) {
+			ddi_dma_mem_free(&socalp->response[i].skc_acchandle);
+			socalp->response[i].skc_cq_raw = NULL;
+			socalp->response[i].skc_cq = NULL;
+		}
+		if (socalp->request[i].deferred_intr_timeoutid) {
+			(void) untimeout(socalp->
+				request[i].deferred_intr_timeoutid);
+		}
+		if (socalp->response[i].deferred_intr_timeoutid) {
+			(void) untimeout(socalp->
+				response[i].deferred_intr_timeoutid);
+		}
+	}
+
+	mutex_destroy(&socalp->abort_mtx);
+	mutex_destroy(&socalp->board_mtx);
+	mutex_destroy(&socalp->ioctl_mtx);
+	cv_destroy(&socalp->board_cv);
+
+	/*
+	 * Free soc data buffer pool
+	 */
+	if (socalp->pool_dhandle) {
+		(void) ddi_dma_unbind_handle(socalp->pool_dhandle);
+		ddi_dma_free_handle(&socalp->pool_dhandle);
+	}
+	if (socalp->pool) {
+		ddi_dma_mem_free(&socalp->pool_acchandle);
+	}
+
+	/* release register maps */
+	/* Unmap EEPROM */
+	if (socalp->socal_eeprom != NULL) {
+		ddi_unmap_regs(dip, 0, &socalp->socal_eeprom, 0, 0);
+	}
+
+	/* Unmap XRAM */
+	if (socalp->socal_xrp != NULL) {
+		ddi_unmap_regs(dip, 1, &socalp->socal_xrp, 0, 0);
+	}
+
+	/* Unmap registers */
+	if (socalp->socal_rp != NULL) {
+		ddi_unmap_regs(dip, 2, (caddr_t *)&socalp->socal_rp, 0, 0);
+	}
+
+	if (socalp->socal_ksp != NULL)
+		kstat_delete(socalp->socal_ksp);
+
+	mutex_destroy(&socalp->k_imr_mtx);
+
+	ddi_remove_minor_node(dip, NULL);
+
+	ddi_soft_state_free(socal_soft_state_p, instance);
+
+	return (DDI_SUCCESS);
+}
+
+
+int
+socal_bus_ctl(dev_info_t *dip, dev_info_t *rip, ddi_ctl_enum_t op,
+	void *a, void *v)
+{
+	int		port;
+
+
+	switch (op) {
+	case DDI_CTLOPS_REPORTDEV:
+		port = ddi_getprop(DDI_DEV_T_ANY, rip, DDI_PROP_DONTPASS,
+		    SOCAL_PORT_NO_PROP, -1);
+		if ((port < 0) || (port > 1)) {
+			port = ddi_getprop(DDI_DEV_T_ANY, rip,
+			    DDI_PROP_DONTPASS, SOCAL_ALT_PORT_NO_PROP, -1);
+		}
+		/* log text identifying this driver (d) & its child (r) */
+		cmn_err(CE_CONT, "?%s%d at %s%d: socal_port %d\n",
+		    ddi_driver_name(rip), ddi_get_instance(rip),
+		    ddi_driver_name(dip), ddi_get_instance(dip),
+		    port);
+		break;
+
+	case DDI_CTLOPS_INITCHILD: {
+		dev_info_t	*child_dip = (dev_info_t *)a;
+		char		name[MAXNAMELEN];
+		socal_state_t	*socalp;
+
+		if ((socalp = ddi_get_driver_private(dip)) == NULL)
+			return (DDI_FAILURE);
+
+		port = ddi_getprop(DDI_DEV_T_ANY, child_dip,
+			DDI_PROP_DONTPASS, SOCAL_PORT_NO_PROP, -1);
+
+		if ((port < 0) || (port > 1)) {
+			port = ddi_getprop(DDI_DEV_T_ANY, child_dip,
+			    DDI_PROP_DONTPASS, SOCAL_ALT_PORT_NO_PROP, -1);
+			if ((port < 0) || (port > 1)) {
+				return (DDI_NOT_WELL_FORMED);
+			}
+		}
+		mutex_enter(&socalp->board_mtx);
+		mutex_enter(&socalp->port_state[port].sp_mtx);
+		if (socalp->port_state[port].sp_status &
+		    (PORT_CHILD_INIT | PORT_TARGET_MODE)) {
+			mutex_exit(&socalp->port_state[port].sp_mtx);
+			mutex_exit(&socalp->board_mtx);
+			return (DDI_FAILURE);
+		}
+		socalp->socal_busy++;
+		socalp->port_state[port].sp_status |= PORT_CHILD_INIT;
+		mutex_exit(&socalp->port_state[port].sp_mtx);
+		mutex_exit(&socalp->board_mtx);
+		ddi_set_parent_data(child_dip,
+		    socalp->port_state[port].sp_transport);
+		(void) sprintf((char *)name, "%x,0", port);
+		ddi_set_name_addr(child_dip, name);
+		break;
+	}
+
+	case DDI_CTLOPS_UNINITCHILD: {
+		dev_info_t	*child_dip = (dev_info_t *)a;
+		socal_state_t	*socalp;
+
+		socalp = ddi_get_driver_private(dip);
+		port = ddi_getprop(DDI_DEV_T_ANY, child_dip,
+			DDI_PROP_DONTPASS, SOCAL_PORT_NO_PROP, -1);
+
+		if ((port < 0) || (port > 1)) {
+			port = ddi_getprop(DDI_DEV_T_ANY, child_dip,
+			    DDI_PROP_DONTPASS, SOCAL_ALT_PORT_NO_PROP, -1);
+			if ((port < 0) || (port > 1)) {
+				return (DDI_NOT_WELL_FORMED);
+			}
+		}
+
+		ddi_set_parent_data(child_dip, NULL);
+		(void) ddi_set_name_addr(child_dip, NULL);
+		mutex_enter(&socalp->board_mtx);
+		mutex_enter(&socalp->port_state[port].sp_mtx);
+		socalp->socal_busy--;
+		socalp->port_state[port].sp_status &= ~PORT_CHILD_INIT;
+		mutex_exit(&socalp->port_state[port].sp_mtx);
+		mutex_exit(&socalp->board_mtx);
+
+		break;
+	}
+
+	case DDI_CTLOPS_IOMIN: {
+		int val;
+
+		val = *((int *)v);
+		val = maxbit(val, socallim->dlim_minxfer);
+		/*
+		 * The 'arg' value of nonzero indicates 'streaming' mode.
+		 * If in streaming mode, pick the largest of our burstsizes
+		 * available and say that that is our minimum value (modulo
+		 * what minxfer is).
+		 */
+		if ((int)(uintptr_t)a) {
+			val = maxbit(val,
+			    1<<(ddi_fls(socallim->dlim_burstsizes)-1));
+		} else {
+			val = maxbit(val,
+			    1<<(ddi_ffs(socallim->dlim_burstsizes)-1));
+		}
+
+		*((int *)v) = val;
+		return (ddi_ctlops(dip, rip, op, a, v));
+	}
+
+	/*
+	 * These ops are not available on this nexus.
+	 */
+
+	case DDI_CTLOPS_DMAPMAPC:
+	case DDI_CTLOPS_REGSIZE:
+	case DDI_CTLOPS_NREGS:
+	case DDI_CTLOPS_AFFINITY:
+	case DDI_CTLOPS_SIDDEV:
+	case DDI_CTLOPS_POKE:
+	case DDI_CTLOPS_PEEK:
+		return (DDI_FAILURE);
+
+	case DDI_CTLOPS_SLAVEONLY:
+	case DDI_CTLOPS_REPORTINT:
+	default:
+		/*
+		 * Remaining requests get passed up to our parent
+		 */
+		DEBUGF(2, (CE_CONT, "%s%d: op (%d) from %s%d\n",
+			ddi_get_name(dip), ddi_get_instance(dip),
+			op, ddi_get_name(rip), ddi_get_instance(rip)));
+		return (ddi_ctlops(dip, rip, op, a, v));
+	}
+
+	return (DDI_SUCCESS);
+}
+
+
+/*ARGSUSED*/
+/*
+ * int
+ * socal_getinfo() - Given the device number, return the devinfo
+ * 	pointer or the instance number.  Note: this routine must be
+ * 	successful on DDI_INFO_DEVT2INSTANCE even before attach.
+ */
+int
+socal_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
+	void **result)
+{
+	int instance;
+	socal_state_t *socalp;
+
+	instance = getminor((dev_t)arg) / 2;
+
+	switch (cmd) {
+	case DDI_INFO_DEVT2DEVINFO:
+		socalp = ddi_get_soft_state(socal_soft_state_p, instance);
+		if (socalp)
+			*result = socalp->dip;
+		else
+			*result = NULL;
+		break;
+
+	case DDI_INFO_DEVT2INSTANCE:
+		*result = (void *)(uintptr_t)instance;
+		break;
+
+	default:
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+/*ARGSUSED*/
+int
+socal_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
+{
+	int 	instance = getminor(*devp)/2;
+	socal_state_t	*socalp =
+			ddi_get_soft_state(socal_soft_state_p, instance);
+	socal_port_t	*port_statep;
+	int		port;
+
+	if (socalp == NULL)
+		return (ENXIO);
+
+	port = getminor(*devp)%2;
+	port_statep = &socalp->port_state[port];
+
+	mutex_enter(&port_statep->sp_mtx);
+	port_statep->sp_status |= PORT_OPEN;
+	mutex_exit(&port_statep->sp_mtx);
+	DEBUGF(2, (CE_CONT,
+	    "socal%d: open of port %d\n", instance, port));
+	return (0);
+}
+
+/*ARGSUSED*/
+int
+socal_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
+{
+	int 	instance = getminor(dev)/2;
+	socal_state_t	*socalp =
+			ddi_get_soft_state(socal_soft_state_p, instance);
+	socal_port_t	*port_statep;
+	int		port;
+
+	port = getminor(dev)%2;
+	port_statep = &socalp->port_state[port];
+
+	mutex_enter(&port_statep->sp_mtx);
+	port_statep->sp_status &= ~PORT_OPEN;
+	mutex_exit(&port_statep->sp_mtx);
+	DEBUGF(2, (CE_CONT,
+	    "socal%d: clsoe of port %d\n", instance, port));
+	return (0);
+}
+
+/*ARGSUSED*/
+int
+socal_ioctl(dev_t dev,
+    int cmd, intptr_t arg, int mode, cred_t *cred_p, int *rval_p)
+{
+	int 	instance = getminor(dev)/2;
+	socal_state_t	*socalp =
+			ddi_get_soft_state(socal_soft_state_p, instance);
+	int		port;
+	socal_port_t	*port_statep;
+	int 		i;
+	uint_t		r;
+	int		offset;
+	int 		retval = FCAL_SUCCESS;
+	la_els_adisc_t		*adisc_pl;
+	la_els_rls_reply_t	*rls_pl;
+	dev_info_t	*dip;
+	char		*buffer, tmp[10];
+	struct socal_fm_version ver;
+#ifdef _MULTI_DATAMODEL
+	struct socal_fm_version32 {
+		uint_t	fcode_ver_len;
+		uint_t	mcode_ver_len;
+		uint_t	prom_ver_len;
+		caddr32_t	fcode_ver;
+		caddr32_t	mcode_ver;
+		caddr32_t	prom_ver;
+	} ver32;
+	uint_t		dm32 = 0;
+#endif
+
+	uchar_t		*flb_pl;
+	flb_hdr_t	*flb_hdr;
+	uint_t		flb_size;
+
+	if (socalp == NULL)
+		return (ENXIO);
+
+	DEBUGF(4, (CE_CONT, "socal%d ioctl: got command %x\n", instance, cmd));
+	port = getminor(dev)%2;
+
+	switch (cmd) {
+		case FCIO_FCODE_MCODE_VERSION:
+#ifdef _MULTI_DATAMODEL
+			switch (ddi_model_convert_from(mode & FMODELS)) {
+				case DDI_MODEL_ILP32:
+					dm32 = 1;
+					if (ddi_copyin((caddr_t)arg,
+					    (caddr_t)&ver32, sizeof (ver32),
+					    mode) == -1)
+						return (EFAULT);
+					ver.fcode_ver_len =
+					    ver32.fcode_ver_len;
+					ver.mcode_ver_len =
+					    ver32.mcode_ver_len;
+					ver.prom_ver_len =
+					    ver32.prom_ver_len;
+					ver.fcode_ver =
+					    (caddr_t)(uintptr_t)ver32.fcode_ver;
+					ver.mcode_ver =
+					    (caddr_t)(uintptr_t)ver32.mcode_ver;
+					ver.prom_ver =
+					    (caddr_t)(uintptr_t)ver32.prom_ver;
+					break;
+				case DDI_MODEL_NONE:
+					if (ddi_copyin((caddr_t)arg,
+					    (caddr_t)&ver, sizeof (ver),
+					    mode) == -1)
+						return (EFAULT);
+			}
+#else /* _MULTI_DATAMODEL */
+			if (ddi_copyin((caddr_t)arg, (caddr_t)&ver,
+				sizeof (ver), mode) == -1)
+				return (EFAULT);
+#endif /* _MULTI_DATAMODEL */
+			dip = socalp->dip;
+			if (ddi_prop_op(DDI_DEV_T_ANY, dip,
+			    PROP_LEN_AND_VAL_ALLOC, DDI_PROP_DONTPASS |
+			    DDI_PROP_CANSLEEP, "version", (caddr_t)&buffer,
+			    &i) != DDI_PROP_SUCCESS)
+				return (EIO);
+			if (i < ver.fcode_ver_len)
+				ver.fcode_ver_len = i;
+			if (ddi_copyout((caddr_t)buffer,
+			    (caddr_t)ver.fcode_ver, ver.fcode_ver_len,
+			    mode) == -1) {
+				kmem_free((caddr_t)buffer, i);
+				return (EFAULT);
+			}
+			kmem_free((caddr_t)buffer, i);
+			if (socalp->socal_eeprom) {
+				for (i = 0; i < SOCAL_N_CQS; i++) {
+					mutex_enter(
+						&socalp->request[i].skc_mtx);
+					mutex_enter(
+						&socalp->response[i].skc_mtx);
+				}
+				i = socalp->socal_rp->socal_cr.w;
+				socalp->socal_rp->socal_cr.w &=
+						~SOCAL_CR_EEPROM_BANK_MASK;
+				socalp->socal_rp->socal_cr.w |= 3 << 16;
+				if (ver.prom_ver_len > 10)
+					ver.prom_ver_len = 10;
+				bcopy((caddr_t)socalp->socal_eeprom + (unsigned)
+				    0xfff6, tmp, 10);
+				socalp->socal_rp->socal_cr.w  = i;
+				for (i = SOCAL_N_CQS-1; i >= 0; i--) {
+					mutex_exit(&socalp->request[i].skc_mtx);
+					mutex_exit(
+						&socalp->response[i].skc_mtx);
+				}
+				if (ddi_copyout((caddr_t)tmp,
+				    (caddr_t)ver.prom_ver,
+				    ver.prom_ver_len, mode) == -1)
+					return (EFAULT);
+			} else {
+				ver.prom_ver_len = 0;
+			}
+			ver.mcode_ver_len = 0;
+#ifdef _MULTI_DATAMODEL
+			if (dm32) {
+				ver32.fcode_ver_len = ver.fcode_ver_len;
+				ver32.mcode_ver_len = ver.mcode_ver_len;
+				ver32.prom_ver_len = ver.prom_ver_len;
+				ver32.fcode_ver = (caddr32_t)(uintptr_t)
+				    ver.fcode_ver;
+				ver32.mcode_ver = (caddr32_t)(uintptr_t)
+				    ver.mcode_ver;
+				ver32.prom_ver = (caddr32_t)(uintptr_t)
+				    ver.prom_ver;
+				if (ddi_copyout((caddr_t)&ver32,
+				    (caddr_t)arg, sizeof (ver32),
+				    mode) == -1)
+					return (EFAULT);
+			} else
+#endif /* _MULTI_DATAMODEL */
+			if (ddi_copyout((caddr_t)&ver, (caddr_t)arg,
+			    sizeof (struct socal_fm_version), mode) == -1)
+				return (EFAULT);
+			break;
+		case FCIO_LOADUCODE:
+			mutex_enter(&socalp->k_imr_mtx);
+			socal_disable(socalp);
+			mutex_exit(&socalp->k_imr_mtx);
+			if (copyin((caddr_t)arg, (caddr_t)socal_ucode, 0x10000)
+			    == -1)
+				return (EFAULT);
+			/* restart socal after resetting */
+			(void) socal_force_reset((void *)socalp, 0,
+			    RESET_PORT);
+			break;
+		case FCIO_DUMPXRAM:
+			for (i = 0; i < SOCAL_N_CQS; i++) {
+				mutex_enter(&socalp->request[i].skc_mtx);
+				mutex_enter(&socalp->response[i].skc_mtx);
+			}
+			for (i = 0; i < 4; i++) {
+				offset = arg+(0x10000 * i);
+				socalp->socal_rp->socal_cr.w &=
+					~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
+				socalp->socal_rp->socal_cr.w |= i<<24;
+				(void) copyout((caddr_t)socalp->socal_xrp,
+					(caddr_t)(uintptr_t)offset, 0x10000);
+			}
+			socalp->socal_rp->socal_cr.w &=
+				~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
+			for (i = SOCAL_N_CQS-1; i >= 0; i--) {
+				mutex_exit(&socalp->request[i].skc_mtx);
+				mutex_exit(&socalp->response[i].skc_mtx);
+			}
+			break;
+#ifdef DEBUG
+		case FCIO_DUMPXRAMBUF:
+			(void) copyout((caddr_t)socal_xrambuf, (caddr_t)arg,
+			    0x40000);
+			break;
+#endif
+		case FCIO_GETMAP:
+			mutex_enter(&socalp->ioctl_mtx);
+			if (socal_getmap(socalp, port, (caddr_t)arg, 0, 0) ==
+			    -1)
+				retval = FCAL_ALLOC_FAILED;
+			mutex_exit(&socalp->ioctl_mtx);
+			break;
+		case FCIO_BYPASS_DEV:
+			mutex_enter(&socalp->ioctl_mtx);
+			retval = socal_bypass_dev((void *)socalp, port, arg);
+			mutex_exit(&socalp->ioctl_mtx);
+			break;
+		case FCIO_FORCE_LIP:
+			mutex_enter(&socalp->ioctl_mtx);
+			retval = socal_force_lip((void *)socalp, port, 0,
+					FCAL_FORCE_LIP);
+			mutex_exit(&socalp->ioctl_mtx);
+			break;
+		case FCIO_FORCE_OFFLINE:
+			mutex_enter(&socalp->ioctl_mtx);
+			retval = socal_force_offline((void *)socalp, port, 0);
+			mutex_exit(&socalp->ioctl_mtx);
+			break;
+		case FCIO_ADISC_ELS:
+		{
+		    if ((adisc_pl =
+			(la_els_adisc_t *)kmem_zalloc(sizeof (la_els_adisc_t),
+			KM_NOSLEEP)) == NULL)
+			    return (ENOMEM);
+
+		    if (copyin((caddr_t)arg, (caddr_t)adisc_pl,
+			sizeof (la_els_adisc_t)) == -1) {
+			kmem_free((void *)adisc_pl, sizeof (la_els_adisc_t));
+			return (EFAULT);
+		    }
+			mutex_enter(&socalp->ioctl_mtx);
+		    retval = socal_issue_adisc(socalp, port, adisc_pl->nport_id,
+			adisc_pl, 0);
+			mutex_exit(&socalp->ioctl_mtx);
+
+		    if (retval == FCAL_SUCCESS) {
+			if (copyout((caddr_t)adisc_pl, (caddr_t)arg,
+				sizeof (la_els_adisc_t)) == -1) {
+				kmem_free((void *)adisc_pl,
+				    sizeof (la_els_adisc_t));
+				return (EFAULT);
+			}
+		    }
+
+		    kmem_free((void *)adisc_pl, sizeof (la_els_adisc_t));
+		    break;
+		}
+		case FCIO_LINKSTATUS:
+		{
+		    int dest;
+		    if ((rls_pl =
+			(la_els_rls_reply_t *)
+			    kmem_zalloc(sizeof (la_els_rls_reply_t),
+			    KM_NOSLEEP)) == NULL)
+			    return (ENOMEM);
+
+		    if (copyin((caddr_t)arg, (caddr_t)rls_pl,
+			sizeof (la_els_rls_reply_t)) == -1) {
+			kmem_free((void *)rls_pl, sizeof (la_els_rls_reply_t));
+			return (EFAULT);
+		    }
+		    dest = (rls_pl->mbz[0] << 16) + (rls_pl->mbz[1] << 8) +
+			rls_pl->mbz[2];
+			mutex_enter(&socalp->ioctl_mtx);
+		    retval = socal_issue_rls(socalp, port, dest,
+			rls_pl, 0);
+			mutex_exit(&socalp->ioctl_mtx);
+
+		    if (retval == FCAL_SUCCESS) {
+			if (copyout((caddr_t)rls_pl, (caddr_t)arg,
+				sizeof (la_els_rls_reply_t)) == -1) {
+				kmem_free((void *)rls_pl,
+				    sizeof (la_els_rls_reply_t));
+				return (EFAULT);
+			}
+		    }
+		    kmem_free((void *)rls_pl, sizeof (la_els_rls_reply_t));
+		    break;
+		}
+		case FCIO_LOOPBACK_INTERNAL:
+			/*
+			 * If userland doesn't provide a location for a return
+			 * value the driver will permanently offline the port,
+			 * ignoring any checks for devices on the loop.
+			 */
+			mutex_enter(&socalp->ioctl_mtx);
+			if (arg == 0) {
+				port_statep = &socalp->port_state[port];
+				mutex_enter(&port_statep->sp_mtx);
+				if (port_statep->sp_status & PORT_DISABLED) {
+					/* Already disabled */
+					mutex_exit(&port_statep->sp_mtx);
+					mutex_exit(&socalp->ioctl_mtx);
+					return (EALREADY);
+				}
+				port_statep->sp_status |= PORT_DISABLED;
+				mutex_exit(&port_statep->sp_mtx);
+			}
+			retval = socal_diag_request((void *)socalp, port, &r,
+				SOC_DIAG_INT_LOOP);
+			mutex_exit(&socalp->ioctl_mtx);
+			if (arg == 0) break;
+			if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
+			    == -1)
+				return (EFAULT);
+			break;
+		case FCIO_LOOPBACK_MANUAL:
+			mutex_enter(&socalp->ioctl_mtx);
+			port_statep = &socalp->port_state[port];
+			mutex_enter(&port_statep->sp_mtx);
+			if (port_statep->sp_status & PORT_DISABLED) {
+				mutex_exit(&port_statep->sp_mtx);
+				mutex_exit(&socalp->ioctl_mtx);
+				return (EBUSY);
+			}
+			mutex_exit(&port_statep->sp_mtx);
+			retval = socal_diag_request((void *)socalp, port, &r,
+				SOC_DIAG_EXT_LOOP);
+			mutex_exit(&socalp->ioctl_mtx);
+			if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
+			    == -1)
+				return (EFAULT);
+			break;
+		case FCIO_NO_LOOPBACK:
+			mutex_enter(&socalp->ioctl_mtx);
+			port_statep = &socalp->port_state[port];
+			mutex_enter(&port_statep->sp_mtx);
+			/* Do not allow online if we're disabled */
+			if (port_statep->sp_status & PORT_DISABLED) {
+				if (arg != 0) {
+					mutex_exit(&port_statep->sp_mtx);
+					mutex_exit(&socalp->ioctl_mtx);
+					/*
+					 * It's permanently disabled -- Need to
+					 * enable it first
+					 */
+					return (EBUSY);
+				}
+				/* This was a request to online. */
+				port_statep->sp_status &= ~PORT_DISABLED;
+			}
+			mutex_exit(&port_statep->sp_mtx);
+			retval = socal_diag_request((void *)socalp, port, &r,
+				SOC_DIAG_REM_LOOP);
+			mutex_exit(&socalp->ioctl_mtx);
+			if (arg == 0) break;
+			if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
+			    == -1)
+				return (EFAULT);
+			break;
+		case FCIO_DIAG_NOP:
+			mutex_enter(&socalp->ioctl_mtx);
+			retval = socal_diag_request((void *)socalp, port, &r,
+				SOC_DIAG_NOP);
+			mutex_exit(&socalp->ioctl_mtx);
+			if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
+			    == -1)
+				return (EFAULT);
+			break;
+		case FCIO_DIAG_XRAM:
+			mutex_enter(&socalp->ioctl_mtx);
+			retval = socal_diag_request((void *)socalp, port, &r,
+				SOC_DIAG_XRAM_TEST);
+			mutex_exit(&socalp->ioctl_mtx);
+			if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
+			    == -1)
+				return (EFAULT);
+			break;
+		case FCIO_DIAG_SOC:
+			mutex_enter(&socalp->ioctl_mtx);
+			retval = socal_diag_request((void *)socalp, port, &r,
+				SOC_DIAG_SOC_TEST);
+			mutex_exit(&socalp->ioctl_mtx);
+			if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
+			    == -1)
+				return (EFAULT);
+			break;
+		case FCIO_DIAG_HCB:
+			mutex_enter(&socalp->ioctl_mtx);
+			retval = socal_diag_request((void *)socalp, port, &r,
+				SOC_DIAG_HCB_TEST);
+			mutex_exit(&socalp->ioctl_mtx);
+			if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
+			    == -1)
+				return (EFAULT);
+			break;
+		case FCIO_DIAG_SOCLB:
+			mutex_enter(&socalp->ioctl_mtx);
+			retval = socal_diag_request((void *)socalp, port, &r,
+				SOC_DIAG_SOCLB_TEST);
+			mutex_exit(&socalp->ioctl_mtx);
+			if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
+			    == -1)
+				return (EFAULT);
+			break;
+		case FCIO_DIAG_SRDSLB:
+			mutex_enter(&socalp->ioctl_mtx);
+			retval = socal_diag_request((void *)socalp, port, &r,
+				SOC_DIAG_SRDSLB_TEST);
+			mutex_exit(&socalp->ioctl_mtx);
+			if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
+			    == -1)
+				return (EFAULT);
+			break;
+		case FCIO_DIAG_EXTLB:
+			mutex_enter(&socalp->ioctl_mtx);
+			retval = socal_diag_request((void *)socalp, port, &r,
+				SOC_DIAG_EXTOE_TEST);
+			mutex_exit(&socalp->ioctl_mtx);
+			if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
+			    == -1)
+				return (EFAULT);
+			break;
+		case FCIO_DIAG_RAW:
+			if (copyin((caddr_t)arg, (caddr_t)&i, sizeof (uint_t))
+			    == -1)
+				return (EFAULT);
+			mutex_enter(&socalp->ioctl_mtx);
+			retval = socal_diag_request((void *)socalp, port, &r,
+				(uint_t)i);
+			mutex_exit(&socalp->ioctl_mtx);
+			if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
+			    == -1)
+				return (EFAULT);
+			break;
+		case FCIO_LOOPBACK_FRAME:
+		    if ((flb_hdr = (flb_hdr_t *)kmem_zalloc(sizeof (flb_hdr_t),
+					KM_NOSLEEP)) == NULL)
+			    return (ENOMEM);
+
+		    if (copyin((caddr_t)arg,
+				(caddr_t)flb_hdr, sizeof (flb_hdr_t)) == -1) {
+			kmem_free((void *)flb_hdr, sizeof (flb_hdr_t));
+			return (EFAULT);
+		    }
+
+		    flb_size = flb_hdr->length;
+
+		    if ((flb_pl =
+			(uchar_t *)kmem_zalloc(flb_size, KM_NOSLEEP)) == NULL)
+			    return (ENOMEM);
+
+		    if (copyin((caddr_t)(arg + sizeof (flb_hdr_t)),
+				(caddr_t)flb_pl, flb_size) == -1) {
+				kmem_free((void *)flb_pl, flb_size);
+				return (EFAULT);
+		    }
+			mutex_enter(&socalp->ioctl_mtx);
+		    retval = socal_issue_lbf(socalp, port, flb_pl,
+						flb_size, 1);
+			mutex_exit(&socalp->ioctl_mtx);
+
+		    if (retval == FCAL_SUCCESS) {
+			if (copyout((caddr_t)flb_pl,
+				    (caddr_t)(arg + sizeof (flb_hdr_t) +
+					flb_hdr->max_length), flb_size) == -1) {
+				kmem_free((void *)flb_pl, flb_size);
+				kmem_free((void *)flb_hdr, sizeof (flb_hdr_t));
+				return (EFAULT);
+			}
+		    }
+
+		    kmem_free((void *)flb_pl, flb_size);
+		    kmem_free((void *)flb_hdr, sizeof (flb_hdr_t));
+		    break;
+		default:
+			return (ENOTTY);
+
+	}
+	switch (retval) {
+		case FCAL_SUCCESS:
+			return (0);
+		case FCAL_ALLOC_FAILED:
+			return (ENOMEM);
+		case FCAL_STATUS_DIAG_BUSY:
+			return (EALREADY);
+		case FCAL_STATUS_DIAG_INVALID:
+			return (EINVAL);
+		default:
+			return (EIO);
+	}
+
+}
+
+/*
+ * Function name : socal_disable()
+ *
+ * Return Values :  none
+ *
+ * Description	 : Reset the soc+
+ *
+ * Context	 : Can be called from different kernel process threads.
+ *		   Can be called by interrupt thread.
+ *
+ * Note:  before calling this, the interface should be locked down
+ * so that it is guaranteed that no other threads are accessing
+ * the hardware.
+ */
+static	void
+socal_disable(socal_state_t *socalp)
+{
+#if !defined(lint)
+	int i;
+#endif
+	/* Don't touch the hardware if the registers aren't mapped */
+	if (!socalp->socal_rp)
+		return;
+
+	socalp->socal_rp->socal_imr = socalp->socal_k_imr = 0;
+	socalp->socal_rp->socal_csr.w = SOCAL_CSR_SOFT_RESET;
+#if !defined(lint)
+	i = socalp->socal_rp->socal_csr.w;
+#endif
+	DEBUGF(9, (CE_CONT, "csr.w = %x\n", i));
+}
+
+/*
+ * Function name : socal_init_transport_interface()
+ *
+ * Return Values :  none
+ *
+ * Description	 : Fill up the fcal_tranpsort struct for ULPs
+ *
+ *
+ * Note:  Only called during attach, so no protection
+ */
+static void
+socal_init_transport_interface(socal_state_t *socalp)
+{
+	int			i;
+	fcal_transport_t	*xport;
+
+	for (i = 0; i < N_SOCAL_NPORTS; i++) {
+		xport = socalp->port_state[i].sp_transport;
+		mutex_init(&xport->fcal_mtx, NULL, MUTEX_DRIVER,
+			(void *)(socalp->iblkc));
+
+		cv_init(&xport->fcal_cv, NULL, CV_DRIVER, NULL);
+
+		xport->fcal_handle = (void *)socalp;
+		xport->fcal_dmalimp = socallim;
+		xport->fcal_iblock = socalp->iblkc;
+		xport->fcal_dmaattr = &socal_dma_attr;
+		xport->fcal_accattr = &socal_acc_attr;
+		xport->fcal_loginparms = socalp->socal_service_params;
+		bcopy((caddr_t)&socalp->socal_n_wwn,
+			(caddr_t)&xport->fcal_n_wwn, sizeof (la_wwn_t));
+		bcopy((caddr_t)&socalp->port_state[i].sp_p_wwn,
+			(caddr_t)&xport->fcal_p_wwn, sizeof (la_wwn_t));
+		xport->fcal_portno = i;
+		xport->fcal_cmdmax = SOCAL_MAX_XCHG;
+		xport->fcal_ops = &socal_transport_ops;
+	}
+}
+
+/*
+ * static int
+ * socal_cqalloc_init() - Inialize the circular queue tables.
+ *	Also, init the locks that are associated with the tables.
+ *
+ *	Returns:	FCAL_SUCCESS, if able to init properly.
+ *			FCAL_FAILURE, if unable to init properly.
+ */
+
+static int
+socal_cqalloc_init(socal_state_t *socalp, uint32_t index)
+{
+	uint32_t cq_size;
+	size_t real_len;
+	uint_t ccount;
+	socal_kcq_t *cqp;
+	int	req_bound = 0, rsp_bound = 0;
+
+	/*
+	 * Initialize the Request and Response Queue locks.
+	 */
+
+	mutex_init(&socalp->request[index].skc_mtx, NULL, MUTEX_DRIVER,
+	    (void *)socalp->iblkc);
+	mutex_init(&socalp->response[index].skc_mtx, NULL, MUTEX_DRIVER,
+	    (void *)socalp->iblkc);
+	cv_init(&socalp->request[index].skc_cv, NULL, CV_DRIVER, NULL);
+	cv_init(&socalp->response[index].skc_cv, NULL, CV_DRIVER, NULL);
+
+	/* Allocate DVMA resources for the Request Queue. */
+	cq_size = socal_req_entries[index] * sizeof (cqe_t);
+	if (cq_size) {
+		cqp = &socalp->request[index];
+
+		if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
+		    DDI_DMA_DONTWAIT, NULL,
+		    &cqp->skc_dhandle) != DDI_SUCCESS) {
+			socal_disp_err(socalp, CE_WARN, "driver.4020",
+			    "!alloc of dma handle failed");
+			goto fail;
+		}
+
+		if (ddi_dma_mem_alloc(cqp->skc_dhandle,
+		    cq_size + SOCAL_CQ_ALIGN, &socal_acc_attr,
+		    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
+		    (caddr_t *)&cqp->skc_cq_raw, &real_len,
+		    &cqp->skc_acchandle) != DDI_SUCCESS) {
+			socal_disp_err(socalp, CE_WARN, "driver.4030",
+			    "!alloc of dma space failed");
+			    goto fail;
+		}
+
+		if (real_len < (cq_size + SOCAL_CQ_ALIGN)) {
+			socal_disp_err(socalp, CE_WARN, "driver.4035",
+			    "!alloc of dma space failed");
+			goto fail;
+		}
+		cqp->skc_cq = (cqe_t *)(((uintptr_t)cqp->skc_cq_raw +
+			(uintptr_t)SOCAL_CQ_ALIGN - 1) &
+			((uintptr_t)(~(SOCAL_CQ_ALIGN-1))));
+
+		if (ddi_dma_addr_bind_handle(cqp->skc_dhandle,
+		    (struct as *)NULL, (caddr_t)cqp->skc_cq, cq_size,
+		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
+		    NULL, &cqp->skc_dcookie, &ccount) != DDI_DMA_MAPPED) {
+			socal_disp_err(socalp, CE_WARN, "driver.4040",
+			    "!bind of dma handle failed");
+			goto fail;
+		}
+
+		req_bound = 1;
+		if (ccount != 1) {
+			socal_disp_err(socalp, CE_WARN, "driver.4045",
+			    "!bind of dma handle failed");
+			goto fail;
+		}
+
+	} else {
+		socalp->request[index].skc_cq_raw = NULL;
+		socalp->request[index].skc_cq = (cqe_t *)NULL;
+		socalp->request[index].skc_dhandle = 0;
+	}
+
+	/* Allocate DVMA resources for the response Queue. */
+	cq_size = socal_rsp_entries[index] * sizeof (cqe_t);
+	if (cq_size) {
+		cqp = &socalp->response[index];
+
+		if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
+		    DDI_DMA_DONTWAIT, NULL,
+		    &cqp->skc_dhandle) != DDI_SUCCESS) {
+			socal_disp_err(socalp, CE_WARN, "driver.4050",
+			    "!alloc of dma handle failed");
+			goto fail;
+		}
+
+		if (ddi_dma_mem_alloc(cqp->skc_dhandle,
+		    cq_size + SOCAL_CQ_ALIGN, &socal_acc_attr,
+		    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
+		    (caddr_t *)&cqp->skc_cq_raw, &real_len,
+		    &cqp->skc_acchandle) != DDI_SUCCESS) {
+			socal_disp_err(socalp, CE_WARN, "driver.4060",
+			    "!alloc of dma space failed");
+			    goto fail;
+		}
+
+		if (real_len < (cq_size + SOCAL_CQ_ALIGN)) {
+			socal_disp_err(socalp, CE_WARN, "driver.4065",
+			    "!alloc of dma space failed");
+			goto fail;
+		}
+
+		cqp->skc_cq = (cqe_t *)(((uintptr_t)cqp->skc_cq_raw +
+			(uintptr_t)SOCAL_CQ_ALIGN - 1) &
+			((uintptr_t)(~(SOCAL_CQ_ALIGN-1))));
+
+		if (ddi_dma_addr_bind_handle(cqp->skc_dhandle,
+		    (struct as *)NULL, (caddr_t)cqp->skc_cq, cq_size,
+		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
+		    NULL, &cqp->skc_dcookie, &ccount) != DDI_DMA_MAPPED) {
+			socal_disp_err(socalp, CE_WARN, "driver.4070",
+			    "!bind of dma handle failed");
+			goto fail;
+		}
+
+		rsp_bound = 1;
+		if (ccount != 1) {
+			socal_disp_err(socalp, CE_WARN, "driver.4075",
+			    "!bind of dma handle failed");
+			goto fail;
+		}
+
+	} else {
+		socalp->response[index].skc_cq_raw = NULL;
+		socalp->response[index].skc_cq = (cqe_t *)NULL;
+		socalp->response[index].skc_dhandle = 0;
+	}
+
+	/*
+	 * Initialize the queue pointers
+	 */
+	socal_cqinit(socalp, index);
+
+	return (FCAL_SUCCESS);
+fail:
+	if (socalp->request[index].skc_dhandle) {
+		if (req_bound)
+			(void) ddi_dma_unbind_handle(socalp->
+			    request[index].skc_dhandle);
+		ddi_dma_free_handle(&socalp->request[index].skc_dhandle);
+	}
+	if (socalp->request[index].skc_cq_raw)
+		ddi_dma_mem_free(&socalp->request[index].skc_acchandle);
+
+	if (socalp->response[index].skc_dhandle) {
+		if (rsp_bound)
+			(void) ddi_dma_unbind_handle(socalp->
+			    response[index].skc_dhandle);
+		ddi_dma_free_handle(&socalp->response[index].skc_dhandle);
+	}
+	if (socalp->response[index].skc_cq_raw)
+		ddi_dma_mem_free(&socalp->response[index].skc_acchandle);
+
+	socalp->request[index].skc_dhandle = NULL;
+	socalp->response[index].skc_dhandle = NULL;
+	socalp->request[index].skc_cq_raw = NULL;
+	socalp->request[index].skc_cq = NULL;
+	socalp->response[index].skc_cq_raw = NULL;
+	socalp->response[index].skc_cq = NULL;
+	mutex_destroy(&socalp->request[index].skc_mtx);
+	mutex_destroy(&socalp->response[index].skc_mtx);
+	cv_destroy(&socalp->request[index].skc_cv);
+	cv_destroy(&socalp->response[index].skc_cv);
+	return (FCAL_FAILURE);
+
+}
+
+/*
+ * socal_cqinit() - initializes the driver's circular queue pointers, etc.
+ */
+
+static void
+socal_cqinit(socal_state_t *socalp, uint32_t index)
+{
+	socal_kcq_t *kcq_req = &socalp->request[index];
+	socal_kcq_t *kcq_rsp = &socalp->response[index];
+
+	/*
+	 * Initialize the Request and Response Queue pointers
+	 */
+	kcq_req->skc_seqno = 1;
+	kcq_rsp->skc_seqno = 1;
+	kcq_req->skc_in = 0;
+	kcq_rsp->skc_in = 0;
+	kcq_req->skc_out = 0;
+	kcq_rsp->skc_out = 0;
+	kcq_req->skc_last_index = socal_req_entries[index] - 1;
+	kcq_rsp->skc_last_index = socal_rsp_entries[index] - 1;
+	kcq_req->skc_full = 0;
+	kcq_rsp->deferred_intr_timeoutid = 0;
+	kcq_req->skc_socalp = socalp;
+	kcq_rsp->skc_socalp = socalp;
+
+	kcq_req->skc_xram_cqdesc =
+		(socalp->xram_reqp + (index * sizeof (struct cq))/8);
+	kcq_rsp->skc_xram_cqdesc =
+		(socalp->xram_rspp + (index * sizeof (struct cq))/8);
+
+	/*  Clear out memory we have allocated */
+	if (kcq_req->skc_cq != NULL)
+		bzero((caddr_t)kcq_req->skc_cq,
+		    socal_req_entries[index] * sizeof (cqe_t));
+	if (kcq_rsp->skc_cq != NULL)
+		bzero((caddr_t)kcq_rsp->skc_cq,
+		    socal_rsp_entries[index] * sizeof (cqe_t));
+}
+
+
+static int
+socal_start(socal_state_t *socalp)
+{
+	uint_t r;
+
+	if (!socalp)
+		return (FCAL_FAILURE);
+
+	socal_download_ucode(socalp);
+	socal_init_cq_desc(socalp);
+	socal_init_wwn(socalp);
+
+	mutex_enter(&socalp->port_state[0].sp_mtx);
+	socalp->port_state[0].sp_status
+		&= (PORT_OPEN|PORT_CHILD_INIT|PORT_DISABLED|PORT_TARGET_MODE);
+	socalp->port_state[0].sp_status |= PORT_OFFLINE;
+	mutex_exit(&socalp->port_state[0].sp_mtx);
+
+	mutex_enter(&socalp->port_state[1].sp_mtx);
+	socalp->port_state[1].sp_status
+		&= (PORT_OPEN|PORT_CHILD_INIT|PORT_DISABLED|PORT_TARGET_MODE);
+	socalp->port_state[1].sp_status |= PORT_OFFLINE;
+	mutex_exit(&socalp->port_state[1].sp_mtx);
+
+	socal_enable(socalp);
+	/* Make sure disabled ports stay disabled. */
+	if (socalp->port_state[0].sp_status & PORT_DISABLED)
+		(void) socal_diag_request((void *)socalp, 0, &r,
+			SOC_DIAG_INT_LOOP);
+	if (socalp->port_state[1].sp_status & PORT_DISABLED)
+		(void) socal_diag_request((void *)socalp, 1, &r,
+			SOC_DIAG_INT_LOOP);
+
+	mutex_enter(&socalp->k_imr_mtx);
+	socalp->socal_shutdown = 0;
+	mutex_exit(&socalp->k_imr_mtx);
+
+	mutex_enter(&socalp->board_mtx);
+	if (socal_establish_pool(socalp, 1) != FCAL_SUCCESS) {
+		mutex_exit(&socalp->board_mtx);
+		return (FCAL_FAILURE);
+	}
+	if (socal_add_pool_buffer(socalp, 1) != FCAL_SUCCESS) {
+		mutex_exit(&socalp->board_mtx);
+		return (FCAL_FAILURE);
+	}
+
+	mutex_exit(&socalp->board_mtx);
+	return (FCAL_SUCCESS);
+}
+
+static void
+socal_doreset(socal_state_t *socalp)
+{
+	int		i;
+	socal_port_t	*port_statep;
+	socal_unsol_cb_t *scbp;
+
+	for (i = 0; i < SOCAL_N_CQS; i++) {
+		mutex_enter(&socalp->request[i].skc_mtx);
+		mutex_enter(&socalp->response[i].skc_mtx);
+	}
+
+	mutex_enter(&socalp->k_imr_mtx);
+	socal_disable(socalp);
+
+	if (socalp->pool_dhandle) {
+		(void) ddi_dma_unbind_handle(socalp->pool_dhandle);
+		ddi_dma_free_handle(&socalp->pool_dhandle);
+	}
+
+	if (socalp->pool)
+		ddi_dma_mem_free(&socalp->pool_acchandle);
+
+	socalp->pool_dhandle = NULL;
+	socalp->pool = NULL;
+
+	for (i = 0; i < SOCAL_N_CQS; i++)
+		socal_cqinit(socalp, i);
+
+	for (i = 0; i < N_SOCAL_NPORTS; i++) {
+		port_statep = &socalp->port_state[i];
+
+		mutex_enter(&port_statep->sp_mtx);
+		port_statep->sp_status &= ~ (PORT_STATUS_MASK |
+			PORT_LILP_PENDING | PORT_LIP_PENDING |
+			PORT_ABORT_PENDING | PORT_BYPASS_PENDING |
+			PORT_ELS_PENDING);
+		mutex_exit(&port_statep->sp_mtx);
+	}
+
+	mutex_exit(&socalp->k_imr_mtx);
+
+	for (i = SOCAL_N_CQS-1; i >= 0; i--) {
+		mutex_exit(&socalp->request[i].skc_mtx);
+		mutex_exit(&socalp->response[i].skc_mtx);
+	}
+
+	for (i = 0; i < N_SOCAL_NPORTS; i++) {
+		for (scbp = socalp->port_state[i].sp_unsol_cb; scbp;
+			scbp = scbp->next)
+			(scbp->statec_cb)(scbp->arg, FCAL_STATE_RESET);
+	}
+
+	for (i = 0; i < SOCAL_N_CQS; i++) {
+		mutex_enter(&socalp->request[i].skc_mtx);
+		mutex_enter(&socalp->response[i].skc_mtx);
+	}
+
+
+	for (i = 0; i < SOCAL_N_CQS; i++) {
+		socalp->request[i].skc_overflowh = NULL;
+		if (socalp->request[i].skc_full & SOCAL_SKC_SLEEP)
+			cv_broadcast(&socalp->request[i].skc_cv);
+	}
+
+	for (i = SOCAL_N_CQS-1; i >= 0; i--) {
+		mutex_exit(&socalp->request[i].skc_mtx);
+		mutex_exit(&socalp->response[i].skc_mtx);
+	}
+
+}
+
+
+/*
+ * Function name : socal_download_ucode ()
+ *
+ * Return Values :
+ *
+ * Description	 : Copies firmware from code that has been linked into
+ *		   the socal module into the soc+'s XRAM.  Prints the date
+ *		   string
+ *
+ */
+static void
+socal_download_ucode(socal_state_t *socalp)
+{
+	uint_t	fw_len = 0;
+	uint_t	date_str[16];
+	auto	char buf[256];
+
+	fw_len = (uint_t)socal_ucode_size;
+
+	/* Copy the firmware image */
+	socal_wcopy((uint_t *)&socal_ucode,
+		(uint_t *)socalp->socal_xrp, fw_len);
+
+	socal_fix_harda(socalp, 0);
+	socal_fix_harda(socalp, 1);
+
+	/* Get the date string from the firmware image */
+	socal_wcopy((uint_t *)(socalp->socal_xrp+SOCAL_XRAM_FW_DATE_STR),
+	    date_str, sizeof (date_str));
+	date_str[sizeof (date_str) / sizeof (uint_t) - 1] = 0;
+
+	if (*(caddr_t)date_str != '\0') {
+	    (void) sprintf(buf, "!Downloading host adapter, fw date code: %s\n",
+		(caddr_t)date_str);
+	    socal_disp_err(socalp, CE_CONT, "driver.1010", buf);
+	    (void) strcpy(socalp->socal_stats.fw_revision, (char *)date_str);
+	} else {
+	    (void) sprintf(buf,
+		"!Downloading host adapter fw, date code: <not available>\n");
+	    socal_disp_err(socalp, CE_CONT, "driver.3010", buf);
+	    (void) strcpy(socalp->socal_stats.fw_revision,
+		"<Not Available>");
+	}
+}
+
+/*
+ * Function name : socal_disp_err()
+ *
+ * Return Values : none
+ *
+ * Description   : displays an error message on the system console
+ *		   with the full device pathname displayed
+ */
+static void
+socal_disp_err(
+	socal_state_t	*socalp,
+	uint_t		level,
+	char		*mid,
+	char		*msg)
+{
+	char c;
+	int instance;
+
+	instance = ddi_get_instance(socalp->dip);
+
+	c = *msg;
+
+	if (c == '!')		/* log only */
+	    cmn_err(level,
+		"!ID[SUNWssa.socal.%s] socal%d: %s", mid, instance, msg+1);
+	else if (c == '?')	/* boot message - log && maybe console */
+	    cmn_err(level,
+		"?ID[SUNWssa.socal.%s] socal%d: %s", mid, instance, msg+1);
+	else if (c == '^')	/* console only */
+	    cmn_err(level, "^socal%d: %s", instance, msg+1);
+	else	{		/* log and console */
+	    cmn_err(level, "^socal%d: %s", instance, msg);
+	    cmn_err(level, "!ID[SUNWssa.socal.%s] socal%d: %s", mid,
+		instance, msg);
+	}
+}
+
+/*
+ * Function name : socal_init_cq_desc()
+ *
+ * Return Values : none
+ *
+ * Description	 : Initializes the request and response queue
+ *		   descriptors in the SOC+'s XRAM
+ *
+ * Context	 : Should only be called during initialiation when
+ *		   the SOC+ is reset.
+ */
+static void
+socal_init_cq_desc(socal_state_t *socalp)
+{
+	soc_cq_t	que_desc[SOCAL_N_CQS];
+	uint32_t	i;
+
+	/*
+	 * Finish CQ table initialization and give the descriptor
+	 * table to the soc+.  Note that we don't use all of the queues
+	 * provided by the hardware, but we make sure we initialize the
+	 * quantities in the unused fields in the hardware to zeroes.
+	 */
+
+	/*
+	 * Do request queues
+	 */
+	for (i = 0; i < SOCAL_N_CQS; i++) {
+		if (socal_req_entries[i]) {
+		    que_desc[i].cq_address =
+			(uint32_t)socalp->request[i].skc_dcookie.dmac_address;
+		    que_desc[i].cq_last_index = socal_req_entries[i] - 1;
+		} else {
+		    que_desc[i].cq_address = (uint32_t)0;
+		    que_desc[i].cq_last_index = 0;
+		}
+		que_desc[i].cq_in = 0;
+		que_desc[i].cq_out = 0;
+		que_desc[i].cq_seqno = 1; /* required by SOC+ microcode */
+	}
+
+	/* copy to XRAM */
+	socal_wcopy((uint_t *)que_desc,		/* pointer to kernel copy */
+		(uint_t *)socalp->xram_reqp,	/* pointer to xram location */
+		SOCAL_N_CQS * sizeof (soc_cq_t));
+
+	/*
+	 * Do response queues
+	 */
+	for (i = 0; i < SOCAL_N_CQS; i++) {
+		if (socal_rsp_entries[i]) {
+		    que_desc[i].cq_last_index = socal_rsp_entries[i] - 1;
+		    que_desc[i].cq_address =
+			(uint32_t)socalp->response[i].skc_dcookie.dmac_address;
+
+		} else {
+		    que_desc[i].cq_address = 0;
+		    que_desc[i].cq_last_index = 0;
+		}
+	}
+
+	/* copy to XRAM */
+	socal_wcopy((uint_t *)que_desc,		/* pointer to kernel copy */
+		(uint_t *)socalp->xram_rspp,	/* pointer to xram location */
+		SOCAL_N_CQS * sizeof (soc_cq_t));
+}
+
+static void
+socal_init_wwn(socal_state_t *socalp)
+{
+	/* copy the node wwn to xram */
+	socal_wcopy((uint_t *)&socalp->socal_n_wwn,
+		(uint_t *)(socalp->socal_xrp +
+		SOCAL_XRAM_NODE_WWN), sizeof (la_wwn_t));
+
+	/* copy port a's wwn to xram */
+	socal_wcopy((uint_t *)&socalp->port_state[0].sp_p_wwn,
+		(uint_t *)(socalp->socal_xrp + SOCAL_XRAM_PORTA_WWN),
+		sizeof (la_wwn_t));
+
+	/* copy port b's wwn to xram */
+	socal_wcopy((uint_t *)&socalp->port_state[1].sp_p_wwn,
+		(uint_t *)(socalp->socal_xrp + SOCAL_XRAM_PORTB_WWN),
+		sizeof (la_wwn_t));
+
+	/*
+	 * need to avoid deadlock by assuring no other thread grabs both of
+	 * these at once
+	 */
+	mutex_enter(&socalp->port_state[0].sp_transport->fcal_mtx);
+	mutex_enter(&socalp->port_state[1].sp_transport->fcal_mtx);
+
+	socal_wcopy((uint_t *)(socalp->socal_xrp + SOCAL_XRAM_SERV_PARAMS),
+		(uint_t *)&socalp->socal_service_params, SOCAL_SVC_LENGTH);
+	mutex_exit(&socalp->port_state[1].sp_transport->fcal_mtx);
+	mutex_exit(&socalp->port_state[0].sp_transport->fcal_mtx);
+}
+
+static void
+socal_enable(socal_state_t *socalp)
+{
+	DEBUGF(2, (CE_CONT, "socal%d: enable:\n",
+		ddi_get_instance(socalp->dip)));
+
+	socalp->socal_rp->socal_cr.w = socalp->socal_cfg;
+	socalp->socal_rp->socal_csr.w = SOCAL_CSR_SOCAL_TO_HOST;
+
+	socalp->socal_k_imr = (uint32_t)SOCAL_CSR_SOCAL_TO_HOST |
+	    SOCAL_CSR_SLV_ACC_ERR;
+	socalp->socal_rp->socal_imr = (uint32_t)socalp->socal_k_imr;
+}
+
+/*
+ * static int
+ * socal_establish_pool() - this routine tells the SOC+ of a buffer pool
+ *	to place LINK ctl application data as it arrives.
+ *
+ *	Returns:
+ *		FCAL_SUCCESS, upon establishing the pool.
+ *		FCAL_FAILURE, if unable to establish the pool.
+ */
+
+static int
+socal_establish_pool(socal_state_t *socalp, uint32_t poolid)
+{
+	soc_pool_request_t	*prq;
+	int			result;
+
+	if ((prq =
+		(soc_pool_request_t *)kmem_zalloc(sizeof (soc_pool_request_t),
+		KM_NOSLEEP)) == NULL)
+			return (FCAL_FAILURE);
+	/*
+	 * Fill in the request structure.
+	 */
+	prq->spr_soc_hdr.sh_request_token = 1;
+	prq->spr_soc_hdr.sh_flags = SOC_FC_HEADER | SOC_UNSOLICITED |
+		SOC_NO_RESPONSE;
+	prq->spr_soc_hdr.sh_class = 0;
+	prq->spr_soc_hdr.sh_seg_cnt = 1;
+	prq->spr_soc_hdr.sh_byte_cnt = 0;
+
+	prq->spr_pool_id = poolid;
+	prq->spr_header_mask = SOCPR_MASK_RCTL;
+	prq->spr_buf_size = SOCAL_POOL_SIZE;
+	prq->spr_n_entries = 0;
+
+	prq->spr_fc_frame_hdr.r_ctl = R_CTL_ELS_REQ;
+	prq->spr_fc_frame_hdr.d_id = 0;
+	prq->spr_fc_frame_hdr.s_id = 0;
+	prq->spr_fc_frame_hdr.type = 0;
+	prq->spr_fc_frame_hdr.f_ctl = 0;
+	prq->spr_fc_frame_hdr.seq_id = 0;
+	prq->spr_fc_frame_hdr.df_ctl = 0;
+	prq->spr_fc_frame_hdr.seq_cnt = 0;
+	prq->spr_fc_frame_hdr.ox_id = 0;
+	prq->spr_fc_frame_hdr.rx_id = 0;
+	prq->spr_fc_frame_hdr.ro = 0;
+
+	prq->spr_cqhdr.cq_hdr_count = 1;
+	prq->spr_cqhdr.cq_hdr_type = CQ_TYPE_ADD_POOL;
+	prq->spr_cqhdr.cq_hdr_flags = 0;
+	prq->spr_cqhdr.cq_hdr_seqno = 0;
+
+	/* Enque the request. */
+	result = socal_cq_enque(socalp, NULL, (cqe_t *)prq, CQ_REQUEST_1,
+		FCAL_NOSLEEP, NULL, 0);
+	kmem_free((void *)prq, sizeof (soc_pool_request_t));
+	return (result);
+
+}
+
+
+/*
+ * static int
+ * soc_add_pool_buffer() - this routine tells the SOC+ to add one buffer
+ *	to an established pool of buffers
+ *
+ *	Returns:
+ *		DDI_SUCCESS, upon establishing the pool.
+ *		DDI_FAILURE, if unable to establish the pool.
+ */
+
+static int
+socal_add_pool_buffer(socal_state_t *socalp, uint32_t poolid)
+{
+	soc_data_request_t	*drq;
+	int			result;
+	size_t			real_len;
+	int			bound = 0;
+	uint_t			ccount;
+
+	if ((drq =
+		(soc_data_request_t *)kmem_zalloc(sizeof (soc_data_request_t),
+		KM_NOSLEEP)) == NULL)
+			return (FCAL_FAILURE);
+
+	/* Allocate DVMA resources for the buffer pool */
+	if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
+	    DDI_DMA_DONTWAIT, NULL, &socalp->pool_dhandle) != DDI_SUCCESS)
+		goto fail;
+
+	if (ddi_dma_mem_alloc(socalp->pool_dhandle, SOCAL_POOL_SIZE,
+	    &socal_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
+	    (caddr_t *)&socalp->pool, &real_len, &socalp->pool_acchandle)
+	    != DDI_SUCCESS)
+		goto fail;
+
+	if (real_len < SOCAL_POOL_SIZE)
+		goto fail;
+
+	if (ddi_dma_addr_bind_handle(socalp->pool_dhandle, (struct as *)NULL,
+	    (caddr_t)socalp->pool, SOCAL_POOL_SIZE,
+	    DDI_DMA_READ | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
+	    NULL, &socalp->pool_dcookie, &ccount) != DDI_DMA_MAPPED)
+		goto fail;
+
+	bound = 1;
+	if (ccount != 1)
+		goto fail;
+
+	/*
+	 * Fill in the request structure.
+	 */
+	drq->sdr_soc_hdr.sh_request_token = poolid;
+	drq->sdr_soc_hdr.sh_flags = SOC_UNSOLICITED | SOC_NO_RESPONSE;
+	drq->sdr_soc_hdr.sh_class = 0;
+	drq->sdr_soc_hdr.sh_seg_cnt = 1;
+	drq->sdr_soc_hdr.sh_byte_cnt = 0;
+
+	drq->sdr_dataseg[0].fc_base =
+		(uint32_t)socalp->pool_dcookie.dmac_address;
+	drq->sdr_dataseg[0].fc_count = SOCAL_POOL_SIZE;
+	drq->sdr_dataseg[1].fc_base = 0;
+	drq->sdr_dataseg[1].fc_count = 0;
+	drq->sdr_dataseg[2].fc_base = 0;
+	drq->sdr_dataseg[2].fc_count = 0;
+	drq->sdr_dataseg[3].fc_base = 0;
+	drq->sdr_dataseg[3].fc_count = 0;
+	drq->sdr_dataseg[4].fc_base = 0;
+	drq->sdr_dataseg[4].fc_count = 0;
+	drq->sdr_dataseg[5].fc_base = 0;
+	drq->sdr_dataseg[5].fc_count = 0;
+
+	drq->sdr_cqhdr.cq_hdr_count = 1;
+	drq->sdr_cqhdr.cq_hdr_type = CQ_TYPE_ADD_BUFFER;
+	drq->sdr_cqhdr.cq_hdr_flags = 0;
+	drq->sdr_cqhdr.cq_hdr_seqno = 0;
+
+	/* Transport the request. */
+	result = socal_cq_enque(socalp, NULL, (cqe_t *)drq, CQ_REQUEST_1,
+		FCAL_NOSLEEP, NULL, 0);
+	kmem_free((void *)drq, sizeof (soc_data_request_t));
+	return (result);
+
+fail:
+	socal_disp_err(socalp, CE_WARN, "driver.4110",
+		"!Buffer pool DVMA alloc failed");
+	if (socalp->pool_dhandle) {
+		if (bound)
+			(void) ddi_dma_unbind_handle(socalp->pool_dhandle);
+		ddi_dma_free_handle(&socalp->pool_dhandle);
+	}
+	if (socalp->pool)
+		ddi_dma_mem_free(&socalp->pool_acchandle);
+	socalp->pool_dhandle = NULL;
+	return (FCAL_FAILURE);
+}
+
+static uint_t
+socal_transport(fcal_packet_t *fcalpkt, fcal_sleep_t sleep, int req_q_no)
+{
+	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
+	socal_port_t	*port_statep;
+#if defined(DEBUG) && !defined(lint)
+	int		instance = ddi_get_instance(socalp->dip);
+#endif
+	int		port;
+	soc_request_t	*sp = (soc_request_t *)&fcalpkt->fcal_socal_request;
+
+	if (sp->sr_soc_hdr.sh_flags & SOC_PORT_B)
+		port = 1;
+	else
+		port = 0;
+	port_statep = &socalp->port_state[port];
+
+	DEBUGF(4, (CE_CONT, "socal%d: transport: packet, sleep = %p, %d\n",
+		instance, fcalpkt, sleep));
+
+	fcalpkt->fcal_cmd_state = 0;
+	fcalpkt->fcal_pkt_flags &= ~(FCFLAG_COMPLETE | FCFLAG_ABORTING);
+
+	return (socal_cq_enque(socalp, port_statep, (cqe_t *)sp,
+	    req_q_no, sleep, fcalpkt, 0));
+}
+
+/*
+ * Function name : socal_cq_enque()
+ *
+ * Return Values :
+ *		FCAL_TRANSPORT_SUCCESS, if able to que the entry.
+ *		FCAL_TRANSPORT_QFULL, if queue full & sleep not set
+ *		FCAL_TRANSPORT_UNAVAIL if this port down
+ *
+ * Description	 : Enqueues an entry into the solicited request
+ *		   queue
+ *
+ * Context	:
+ */
+
+/*ARGSUSED*/
+static int
+socal_cq_enque(socal_state_t *socalp, socal_port_t *port_statep, cqe_t *cqe,
+		int rqix, fcal_sleep_t sleep, fcal_packet_t *to_queue,
+		int mtxheld)
+{
+#if defined(DEBUG) && !defined(lint)
+	int 		instance = ddi_get_instance(socalp->dip);
+#endif
+	socal_kcq_t	*kcq;
+	cqe_t		*sp;
+	uint_t		bitmask, wmask;
+	uchar_t		out;
+	uchar_t		s_out;
+	longlong_t	*p, *q;
+
+	kcq = &socalp->request[rqix];
+
+	bitmask = SOCAL_CSR_1ST_H_TO_S << rqix;
+	wmask = SOCAL_CSR_SOCAL_TO_HOST | bitmask;
+	p = (longlong_t *)cqe;
+
+	/*
+	 * Since we're only reading we don't need a mutex.
+	 */
+	if (socalp->socal_shutdown) {
+		return (FCAL_TRANSPORT_UNAVAIL);
+	}
+	/*
+	 * Get a token early.  That way we won't sleep
+	 * in id32_alloc() with a mutex held.
+	 */
+	if (to_queue) {
+		if ((to_queue->fcal_socal_request.sr_soc_hdr.sh_request_token =
+			SOCAL_ID_GET(to_queue, mtxheld ? FCAL_NOSLEEP :
+				sleep)) == NULL) {
+			return (FCAL_TRANSPORT_QFULL);
+		}
+	}
+	/*
+	 * Grab lock for request queue.
+	 */
+
+	if (!mtxheld)
+		mutex_enter(&kcq->skc_mtx);
+
+	/*
+	 * Determine if the queue is full
+	 */
+
+	do {
+
+	    if (kcq->skc_full) {
+		/*
+		 * If soc's queue full, then we wait for an interrupt
+		 * telling us we are not full.
+		 */
+
+		    if (to_queue) {
+			to_queue->fcal_pkt_next = NULL;
+			if (!kcq->skc_overflowh) {
+			    DEBUGF(2, (CE_CONT,
+				"socal%d: cq_enque: request que %d is full\n",
+				instance, rqix));
+			    kcq->skc_overflowh = to_queue;
+			    socalp->socal_stats.qfulls++;
+			} else
+			    kcq->skc_overflowt->fcal_pkt_next = to_queue;
+			kcq->skc_overflowt = to_queue;
+
+			mutex_enter(&socalp->k_imr_mtx);
+			socalp->socal_rp->socal_imr =
+			    (socalp->socal_k_imr |= bitmask);
+			mutex_exit(&socalp->k_imr_mtx);
+			to_queue->fcal_cmd_state |= FCAL_CMD_IN_TRANSPORT;
+			if (!mtxheld)
+				mutex_exit(&kcq->skc_mtx);
+			return (FCAL_TRANSPORT_SUCCESS);
+		    }
+
+		    if (!mtxheld)
+			mutex_exit(&kcq->skc_mtx);
+		    return (FCAL_TRANSPORT_QFULL);
+	    }
+
+	    if (((kcq->skc_in + 1) & kcq->skc_last_index)
+			== (out = kcq->skc_out)) {
+		/*
+		 * get SOC+'s copy of out to update our copy of out
+		 */
+		s_out =
+		    SOCAL_REQUESTQ_INDEX(rqix, socalp->socal_rp->socal_reqp.w);
+		DEBUGF(2, (CE_CONT,
+			"socal%d: cq_enque: &XRAM cq_in: 0x%p s_out.out 0x%x\n",
+			instance, &kcq->skc_xram_cqdesc->cq_in, s_out));
+
+		kcq->skc_out = out = s_out;
+		/* if soc+'s que still full set flag */
+		kcq->skc_full = ((((kcq->skc_in + 1) &
+			kcq->skc_last_index) == out)) ? SOCAL_SKC_FULL : 0;
+	    }
+
+	} while (kcq->skc_full);
+
+	/* Now enque the entry. */
+	sp = &(kcq->skc_cq[kcq->skc_in]);
+	cqe->cqe_hdr.cq_hdr_seqno = kcq->skc_seqno;
+
+	/* Give the entry to the SOC. */
+	q = (longlong_t *)sp;
+	*q++ = *p++;
+	*q++ = *p++;
+	*q++ = *p++;
+	*q++ = *p++;
+	*q++ = *p++;
+	*q++ = *p++;
+	*q++ = *p++;
+	*q = *p;
+	(void) ddi_dma_sync(kcq->skc_dhandle, (int)((caddr_t)sp -
+	    (caddr_t)kcq->skc_cq), sizeof (cqe_t), DDI_DMA_SYNC_FORDEV);
+	if (to_queue)
+		to_queue->fcal_cmd_state |= FCAL_CMD_IN_TRANSPORT;
+
+	/*
+	 * Update circular queue and ring SOC's doorbell.
+	 */
+	kcq->skc_in++;
+	if ((kcq->skc_in & kcq->skc_last_index) == 0) {
+		kcq->skc_in = 0;
+		kcq->skc_seqno++;
+	}
+
+	socalp->socal_rp->socal_csr.w = wmask | (kcq->skc_in << 24);
+	/* Let lock go for request queue. */
+	if (!mtxheld)
+		mutex_exit(&kcq->skc_mtx);
+
+	return (FCAL_TRANSPORT_SUCCESS);
+}
+
+static uint_t
+socal_transport_poll(fcal_packet_t *fcalpkt, uint_t timeout, int req_q_no)
+{
+	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
+	register volatile socal_reg_t *socalreg = socalp->socal_rp;
+	uint_t			csr;
+	socal_port_t	*port_statep;
+	int		port;
+	soc_request_t	*sp = (soc_request_t *)&fcalpkt->fcal_socal_request;
+	uint32_t	retval;
+	clock_t		ticker, t;
+
+	/* make the timeout meaningful */
+	timeout = drv_usectohz(timeout);
+	if (sp->sr_soc_hdr.sh_flags & SOC_PORT_B)
+		port = 1;
+	else
+		port = 0;
+	port_statep = &socalp->port_state[port];
+
+	fcalpkt->fcal_cmd_state = 0;
+	fcalpkt->fcal_pkt_flags &= ~(FCFLAG_COMPLETE | FCFLAG_ABORTING);
+
+	ticker = ddi_get_lbolt();
+
+	if ((retval = socal_cq_enque(socalp, port_statep, (cqe_t *)sp,
+	    req_q_no, FCAL_NOSLEEP, fcalpkt, 0)) != FCAL_TRANSPORT_SUCCESS) {
+		return (retval);
+	} else {
+		while (!(fcalpkt->fcal_cmd_state & FCAL_CMD_COMPLETE)) {
+			drv_usecwait(SOCAL_NOINTR_POLL_DELAY_TIME);
+			t = ddi_get_lbolt();
+			if ((ticker + timeout) < t)
+				return (FCAL_TRANSPORT_TIMEOUT);
+			csr = socalreg->socal_csr.w;
+			if ((SOCAL_INTR_CAUSE(socalp, csr)) &
+			    SOCAL_CSR_RSP_QUE_0) {
+				socal_intr_solicited(socalp, 0);
+			}
+		}
+	}
+	return (FCAL_TRANSPORT_SUCCESS);
+}
+
+static uint_t
+socal_doit(fcal_packet_t *fcalpkt, socal_port_t *port_statep, int polled,
+    void (*func)(), int timo, int flag, uint_t *diagcode)
+{
+	clock_t lb;
+	uint32_t retval, status;
+	socal_state_t   *socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
+
+	if (polled) {
+		fcalpkt->fcal_pkt_comp = NULL;
+		status = socal_transport_poll(fcalpkt, timo, CQ_REQUEST_0);
+	} else {
+		fcalpkt->fcal_pkt_comp = func;
+		mutex_enter(&port_statep->sp_mtx);
+		port_statep->sp_status |= flag;
+		if ((status = socal_transport(fcalpkt, FCAL_NOSLEEP,
+		    CQ_REQUEST_0)) == FCAL_TRANSPORT_SUCCESS) {
+		    lb = ddi_get_lbolt();
+			while (!(fcalpkt->fcal_cmd_state & FCAL_CMD_COMPLETE)) {
+			if ((retval = cv_timedwait(&port_statep->sp_cv,
+			    &port_statep->sp_mtx,
+			    lb+drv_usectohz(timo))) == -1) {
+			    status = FCAL_TRANSPORT_TIMEOUT;
+			    break;
+			}
+		    }
+		}
+		port_statep->sp_status &= ~flag;
+		mutex_exit(&port_statep->sp_mtx);
+	}
+
+	switch (status) {
+		case FCAL_TRANSPORT_SUCCESS:
+			status = fcalpkt->fcal_pkt_status;
+			if (diagcode)
+				*diagcode = fcalpkt->fcal_diag_status;
+			switch (status) {
+				case FCAL_STATUS_ABORT_FAILED:
+					if (flag == PORT_ABORT_PENDING)
+						retval = FCAL_ABORT_FAILED;
+					break;
+				case FCAL_STATUS_OK:
+					if (flag == PORT_ABORT_PENDING)
+						retval = FCAL_ABORT_FAILED;
+					else
+						retval = FCAL_SUCCESS;
+					break;
+				case FCAL_STATUS_OLD_PORT:
+					retval = FCAL_OLD_PORT;
+					break;
+				case FCAL_STATUS_ERR_OFFLINE:
+					retval = FCAL_OFFLINE;
+					break;
+				case FCAL_STATUS_ABORTED:
+					retval = FCAL_ABORTED;
+					port_statep->sp_board->
+					    socal_stats.pstats[port_statep
+					    ->sp_port].abts_ok++;
+					break;
+				case FCAL_STATUS_BAD_XID:
+					retval = FCAL_BAD_ABORT;
+					break;
+				case FCAL_STATUS_BAD_DID:
+					retval = FCAL_BAD_PARAMS;
+					break;
+				case FCAL_STATUS_DIAG_BUSY:
+				case FCAL_STATUS_DIAG_INVALID:
+					retval = status;
+					break;
+				default:
+					retval = FCAL_LINK_ERROR;
+			}
+			break;
+		case FCAL_TRANSPORT_TIMEOUT:
+			if (flag == PORT_LIP_PENDING ||
+			    flag == PORT_LILP_PENDING) {
+				if (socal_core &&
+					(socal_core & SOCAL_FAILED_LIP)) {
+					socal_core = 0;
+					socal_take_core(socalp);
+				}
+				socal_disp_err(socalp, CE_WARN, "link.6040",
+				"SOCAL:Forcing SOC+ reset as LIP timed out\n");
+				/* restart socal after resetting */
+				(void) socal_force_reset(port_statep->sp_board,
+				    polled, RESET_PORT);
+			}
+			else
+				(void) socal_force_lip(port_statep->sp_board,
+			    port_statep->sp_port, polled, FCAL_FORCE_LIP);
+			retval = FCAL_TIMEOUT;
+			break;
+		case FCAL_TRANSPORT_FAILURE:
+		case FCAL_BAD_PACKET:
+		case FCAL_TRANSPORT_UNAVAIL:
+		case FCAL_TRANSPORT_QFULL:
+			retval = status;
+			break;
+		default:
+			retval = FCAL_LINK_ERROR;
+	}
+	socal_packet_free(fcalpkt);
+	return (retval);
+}
+
+static uint_t
+socal_lilp_map(void *ssp, uint_t port, uint32_t bufid, uint_t polled)
+{
+	fcal_packet_t		*fcalpkt;
+	soc_data_request_t	*sdr;
+	socal_state_t		*socalp = (socal_state_t *)ssp;
+	socal_port_t		*port_statep = &socalp->port_state[port];
+
+	if ((fcalpkt =
+	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
+	    == (fcal_packet_t *)NULL)
+		return (FCAL_ALLOC_FAILED);
+
+	sdr = (soc_data_request_t *)&fcalpkt->fcal_socal_request;
+	if (port)
+	    sdr->sdr_soc_hdr.sh_flags = SOC_PORT_B;
+	sdr->sdr_soc_hdr.sh_seg_cnt = 1;
+	sdr->sdr_soc_hdr.sh_byte_cnt = 132;
+	sdr->sdr_dataseg[0].fc_base = bufid;
+	sdr->sdr_dataseg[0].fc_count = 132;
+	sdr->sdr_cqhdr.cq_hdr_count = 1;
+	sdr->sdr_cqhdr.cq_hdr_type = CQ_TYPE_REPORT_MAP;
+	fcalpkt->fcal_pkt_cookie = (void *)socalp;
+
+	return (socal_doit(fcalpkt, port_statep, polled, socal_lilp_map_done,
+	    SOCAL_LILP_TIMEOUT, PORT_LILP_PENDING, NULL));
+}
+
+static uint_t
+socal_force_lip(void *ssp, uint_t port, uint_t polled, uint_t lip_req)
+{
+	fcal_packet_t		*fcalpkt;
+	soc_cmdonly_request_t	*scr;
+	socal_state_t		*socalp = (socal_state_t *)ssp;
+	socal_port_t		*port_statep = &socalp->port_state[port];
+
+
+	if (lip_req == FCAL_NO_LIP) {
+		mutex_enter(&port_statep->sp_mtx);
+		if ((port_statep->sp_status & PORT_ONLINE_LOOP) &&
+			(port_statep->sp_unsol_cb->statec_cb != NULL)) {
+				mutex_exit(&port_statep->sp_mtx);
+				(*port_statep->sp_unsol_cb->statec_cb)
+				(port_statep->sp_unsol_cb->arg,
+						FCAL_STATUS_LOOP_ONLINE);
+			return (FCAL_SUCCESS);
+
+		} else
+			mutex_exit(&port_statep->sp_mtx);
+	}
+	socalp->socal_stats.pstats[port].lips++;
+	if ((fcalpkt =
+	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
+	    == (fcal_packet_t *)NULL)
+		return (FCAL_ALLOC_FAILED);
+
+	scr = (soc_cmdonly_request_t *)&fcalpkt->fcal_socal_request;
+	if (port)
+	    scr->scr_soc_hdr.sh_flags = SOC_PORT_B;
+	scr->scr_cqhdr.cq_hdr_count = 1;
+	scr->scr_cqhdr.cq_hdr_type = CQ_TYPE_REQUEST_LIP;
+
+	fcalpkt->fcal_pkt_cookie = (void *)socalp;
+	return (socal_doit(fcalpkt, port_statep, polled, socal_force_lip_done,
+	    SOCAL_LIP_TIMEOUT, PORT_LIP_PENDING, NULL));
+}
+
+static uint_t
+socal_abort_cmd(void *ssp, uint_t port, fcal_packet_t *fcalpkt, uint_t polled)
+{
+	fcal_packet_t		*fcalpkt2, *fpkt;
+	soc_cmdonly_request_t	*scr, *tscr;
+	socal_state_t		*socalp = (socal_state_t *)ssp;
+	socal_port_t		*port_statep = &socalp->port_state[port];
+	socal_kcq_t		*kcq;
+
+	socalp->socal_stats.pstats[port].abts++;
+	kcq = &socalp->request[CQ_REQUEST_1];
+	mutex_enter(&kcq->skc_mtx);
+	fcalpkt2 = kcq->skc_overflowh;
+	fpkt = NULL;
+	while (fcalpkt2 != NULL) {
+		if (fcalpkt2 == fcalpkt) {
+			if (fpkt == NULL)
+				kcq->skc_overflowh = fcalpkt->fcal_pkt_next;
+			else {
+				fpkt->fcal_pkt_next = fcalpkt->fcal_pkt_next;
+				if (kcq->skc_overflowt == fcalpkt)
+					kcq->skc_overflowt = fpkt;
+			}
+			mutex_exit(&kcq->skc_mtx);
+			socalp->socal_stats.pstats[port].abts_ok++;
+			SOCAL_ID_FREE(fcalpkt->fcal_socal_request.
+				sr_soc_hdr.sh_request_token);
+			return (FCAL_ABORTED);
+		} else {
+			fpkt = fcalpkt2;
+			fcalpkt2 = fcalpkt2->fcal_pkt_next;
+		}
+	}
+	mutex_exit(&kcq->skc_mtx);
+	if ((fcalpkt2 =
+	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
+	    == (fcal_packet_t *)NULL)
+		return (FCAL_ALLOC_FAILED);
+
+	mutex_enter(&socalp->abort_mtx);
+	/* Too late? */
+	if (fcalpkt->fcal_pkt_flags & FCFLAG_COMPLETE) {
+		socal_packet_free(fcalpkt2);
+		mutex_exit(&socalp->abort_mtx);
+		return (FCAL_ABORTED);
+		/* I lied.  So shoot me. */
+	}
+	/* Mark packet as being aborted and put it in the abort pending list. */
+	fcalpkt->fcal_pkt_flags |= FCFLAG_ABORTING;
+
+	scr = (soc_cmdonly_request_t *)&fcalpkt2->fcal_socal_request;
+	tscr = (soc_cmdonly_request_t *)&fcalpkt->fcal_socal_request;
+	scr->scr_soc_hdr.sh_byte_cnt = tscr->scr_soc_hdr.sh_request_token;
+	scr->scr_cqhdr.cq_hdr_count = 1;
+	scr->scr_cqhdr.cq_hdr_type = CQ_TYPE_REQUEST_ABORT;
+	if (port)
+		scr->scr_soc_hdr.sh_flags = SOC_PORT_B;
+	fcalpkt2->fcal_pkt_cookie = (void *)socalp;
+	mutex_exit(&socalp->abort_mtx);
+
+	return (socal_doit(fcalpkt2, port_statep, polled, socal_abort_done,
+	    SOCAL_ABORT_TIMEOUT, PORT_ABORT_PENDING, NULL));
+}
+
+/*ARGSUSED*/
+static uint_t
+socal_els(void *ssp, uint_t port, uint_t elscode, uint_t dest,
+	void (*callback)(), void *arg, caddr_t reqpl, caddr_t *rsppl,
+	uint_t sleep)
+{
+	return (FCAL_TRANSPORT_FAILURE);
+}
+
+static uint_t
+socal_bypass_dev(void *ssp, uint_t port, uint_t dest)
+{
+	fcal_packet_t		*fcalpkt;
+	soc_cmdonly_request_t	*scr;
+	socal_state_t		*socalp = (socal_state_t *)ssp;
+	socal_port_t		*port_statep = &socalp->port_state[port];
+
+	if ((fcalpkt =
+	    socal_packet_alloc(socalp, FCAL_SLEEP))
+	    == (fcal_packet_t *)NULL)
+		return (FCAL_ALLOC_FAILED);
+
+	scr = (soc_cmdonly_request_t *)&fcalpkt->fcal_socal_request;
+	if (port)
+	    scr->scr_soc_hdr.sh_flags = SOC_PORT_B;
+	scr->scr_soc_hdr.sh_byte_cnt = dest;
+	scr->scr_cqhdr.cq_hdr_count = 1;
+	scr->scr_cqhdr.cq_hdr_type = CQ_TYPE_BYPASS_DEV;
+	return (socal_doit(fcalpkt, port_statep, 0, socal_bypass_dev_done,
+	    SOCAL_BYPASS_TIMEOUT, PORT_BYPASS_PENDING, NULL));
+}
+
+
+/*ARGSUSED*/
+static void
+socal_force_reset(void *ssp, uint_t port, uint_t restart)
+{
+	socal_state_t 	*socalp = (socal_state_t *)ssp;
+
+	mutex_enter(&socalp->k_imr_mtx);
+	if (socalp->socal_shutdown) {
+		mutex_exit(&socalp->k_imr_mtx);
+		return;
+	} else {
+		socalp->socal_shutdown = 1;
+		mutex_exit(&socalp->k_imr_mtx);
+	}
+	socalp->socal_stats.resets++;
+	socal_doreset(socalp);
+	if (restart) {
+		if (socal_start(socalp) != FCAL_SUCCESS) {
+			cmn_err(CE_WARN, "socal: start failed.\n");
+		}
+	}
+}
+
+
+static void
+socal_add_ulp(void *ssp, uint_t port, uchar_t type,
+	void (*ulp_statec_callback)(), void (*ulp_els_callback)(),
+	void (*ulp_data_callback)(), void *arg)
+{
+	socal_state_t	*socalp = (socal_state_t *)ssp;
+	socal_port_t	*port_statep = &socalp->port_state[port];
+	socal_unsol_cb_t *cbentry;
+
+	mutex_enter(&port_statep->sp_mtx);
+	for (cbentry = port_statep->sp_unsol_cb; cbentry;
+	    cbentry = cbentry->next) {
+		if (cbentry->type == type) {
+			cbentry->statec_cb = ulp_statec_callback;
+			cbentry->els_cb = ulp_els_callback;
+			cbentry->data_cb = ulp_data_callback;
+			cbentry->arg = arg;
+			mutex_exit(&port_statep->sp_mtx);
+			return;
+		}
+	}
+	mutex_exit(&port_statep->sp_mtx);
+	if ((cbentry =
+	    (socal_unsol_cb_t *)kmem_zalloc(sizeof (socal_unsol_cb_t),
+	    KM_SLEEP)) == (socal_unsol_cb_t *)NULL) {
+		return;
+	}
+	mutex_enter(&port_statep->sp_mtx);
+	cbentry->statec_cb = ulp_statec_callback;
+	cbentry->els_cb = ulp_els_callback;
+	cbentry->data_cb = ulp_data_callback;
+	cbentry->arg = arg;
+	cbentry->type = type;
+
+	cbentry->next = port_statep->sp_unsol_cb;
+	port_statep->sp_unsol_cb = cbentry;
+	mutex_exit(&port_statep->sp_mtx);
+}
+
+
+/*
+ * remove a ULP with matching type and arg
+ */
+static void
+socal_remove_ulp(void *ssp, uint_t port, uchar_t type, void *arg)
+{
+	socal_state_t		*socalp = (socal_state_t *)ssp;
+	socal_port_t		*port_statep;
+	socal_unsol_cb_t	*cbentry;
+	socal_unsol_cb_t	*p_cbentry;
+
+
+	ASSERT(ssp != NULL);
+	port_statep = &socalp->port_state[port];
+	ASSERT(port_statep != NULL);
+
+	/* scan the list of unsolicited callback entries */
+	mutex_enter(&port_statep->sp_mtx);
+	p_cbentry = NULL;
+	for (cbentry = port_statep->sp_unsol_cb;
+	    cbentry != NULL;
+	    p_cbentry = cbentry, cbentry = cbentry->next) {
+		if ((cbentry->type != type) || (cbentry->arg != arg)) {
+			continue;	/* this entry  doesn't match */
+		}
+		/* found entry to remove */
+		if (port_statep->sp_unsol_cb == cbentry) {
+			/* remove first entry in list */
+			port_statep->sp_unsol_cb = cbentry->next;
+		} else {
+			/* remove other entry in list */
+			if (p_cbentry)
+				p_cbentry->next = cbentry->next;
+		}
+		kmem_free((void *)cbentry, sizeof (socal_unsol_cb_t));
+		DEBUGF(2, (CE_CONT, "socal port %d ULP removed\n", port));
+		break;
+	}
+	mutex_exit(&port_statep->sp_mtx);
+}
+
+
+/*
+ * static unsigned int
+ * socal_intr() - this is the interrupt routine for the SOC. Process all
+ *	possible incoming interrupts from the soc device.
+ */
+
+static unsigned int
+socal_intr(caddr_t arg)
+{
+	socal_state_t *socalp = (socal_state_t *)arg;
+	register volatile socal_reg_t *socalreg = socalp->socal_rp;
+	unsigned csr;
+	int cause = 0;
+#if !defined(lint)
+	int instance = ddi_get_instance(socalp->dip);
+#endif
+	int i, j, request;
+	char full;
+	struct fcal_packet *fpkt, *nfpkt;
+
+	csr = socalreg->socal_csr.w;
+	cause = (int)SOCAL_INTR_CAUSE(socalp, csr);
+
+	DEBUGF(2, (CE_CONT,
+		"socal%d: intr: csr: 0x%x cause: 0x%x\n",
+		instance, csr, cause));
+
+	if (!cause) {
+		socalp->socal_on_intr = 0;
+		return (DDI_INTR_UNCLAIMED);
+	}
+
+	socalp->socal_on_intr = 1;
+
+	while (cause) {
+
+	/*
+	 * Process the unsolicited messages first in case there are some
+	 * high priority async events that we should act on.
+	 *
+	 */
+
+	    if (cause & SOCAL_CSR_RSP_QUE_1) {
+		    socal_intr_unsolicited(socalp, 1);
+	DEBUGF(4, (CE_CONT, "socal%d intr: did unsolicited\n", instance));
+	    }
+
+	    if (cause & SOCAL_CSR_RSP_QUE_0) {
+		    socal_intr_solicited(socalp, 0);
+	DEBUGF(4, (CE_CONT, "socal%d intr: did solicited\n", instance));
+	    }
+
+	/*
+	 * for use with token-only response queues in the future
+	 * if (cause & SOCAL_CSR_RSP_QUE_0) {
+	 *	socal_intr_solicited(socalp, 0);
+	 * }
+	 */
+
+
+	/*
+	 * Process any request interrupts
+	 * We only allow request interrupts when the request
+	 * queue is full and we are waiting so we can enque
+	 * another command.
+	 */
+	    if ((request = (cause & SOCAL_CSR_HOST_TO_SOCAL)) != 0) {
+		socalp->socal_stats.reqq_intrs++;
+		for (i = SOCAL_CSR_1ST_H_TO_S, j = 0; j < SOCAL_N_CQS;
+			j++, i <<= 1) {
+		    if (request & i) {
+			socal_kcq_t *kcq = &socalp->request[j];
+
+			if (kcq->skc_full) {
+			    mutex_enter(&kcq->skc_mtx);
+			    full = kcq->skc_full;
+			    kcq->skc_full = 0;
+			    while ((fpkt = kcq->skc_overflowh) != NULL) {
+				nfpkt = fpkt->fcal_pkt_next;
+				fpkt->fcal_pkt_next = NULL;
+				kcq->skc_overflowh = nfpkt;
+				if (socal_cq_enque(socalp, (socal_port_t *)
+				    fpkt->fcal_pkt_cookie,
+				    (cqe_t *)&fpkt->fcal_socal_request,
+				    j, FCAL_NOSLEEP, NULL, 1) !=
+				    FCAL_TRANSPORT_SUCCESS) {
+				    break;
+				}
+			    }
+			    if (!kcq->skc_overflowh) {
+				if (full & SOCAL_SKC_SLEEP)
+				    cv_broadcast(&kcq->skc_cv);
+
+			    /* Disable this queue's intrs */
+				DEBUGF(2, (CE_CONT,
+				    "socal%d: req que %d overflow cleared\n",
+				    instance, j));
+				mutex_enter(&socalp->k_imr_mtx);
+				socalp->socal_rp->socal_imr =
+				    (socalp->socal_k_imr &= ~i);
+				mutex_exit(&socalp->k_imr_mtx);
+			    }
+			    mutex_exit(&kcq->skc_mtx);
+			}
+		    }
+		}
+	    }
+	    csr = socalreg->socal_csr.w;
+	    cause = (int)SOCAL_INTR_CAUSE(socalp, csr);
+	DEBUGF(4, (CE_CONT, "socal%d intr: did request queues\n", instance));
+
+	}
+
+	socalp->socal_on_intr = 0;
+	return (DDI_INTR_CLAIMED);
+}
+
+static void
+socal_intr_solicited(socal_state_t *socalp, uint32_t srq)
+{
+	socal_kcq_t		*kcq;
+	volatile socal_kcq_t	*kcqv;
+	soc_response_t		*srp;
+	cqe_t			*cqe;
+	uint_t			status, i;
+	fcal_packet_t		*fcalpkt = NULL;
+	soc_header_t		*shp;
+	register volatile socal_reg_t *socalreg = socalp->socal_rp;
+	caddr_t			src, dst;
+	uchar_t			index_in;
+	cq_hdr_t		*cq_hdr;
+	char			val;
+	int			port;
+
+#if defined(DEBUG) && !defined(lint)
+	int instance = ddi_get_instance(socalp->dip);
+#endif
+	auto char buf[80];
+
+	kcq = &socalp->response[srq];
+	kcqv = (volatile socal_kcq_t *)kcq;
+	DEBUGF(4, (CE_CONT, "socal%d intr_sol: entered \n", instance));
+
+	/*
+	 * Grab lock for request queue.
+	 */
+	mutex_enter(&kcq->skc_mtx);
+
+	/*
+	 * Process as many response queue entries as we can.
+	 */
+	cqe = &(kcq->skc_cq[kcqv->skc_out]);
+
+	index_in = SOCAL_RESPONSEQ_INDEX(srq, socalreg->socal_rspp.w);
+
+	if (index_in == kcqv->skc_out) {
+		socalreg->socal_csr.w = ((kcqv->skc_out << 24) |
+		    (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_0));
+
+		/* make sure the write completed */
+		i = socalreg->socal_csr.w;
+
+		index_in = SOCAL_RESPONSEQ_INDEX(srq, socalreg->socal_rspp.w);
+	}
+
+	kcqv->skc_in = index_in;
+
+	while (kcqv->skc_out != index_in) {
+		/* Find out where the newest entry lives in the queue */
+		(void) ddi_dma_sync(kcq->skc_dhandle, 0, 0,
+			DDI_DMA_SYNC_FORKERNEL);
+
+		srp = (soc_response_t *)cqe;
+		port = srp->sr_soc_hdr.sh_flags & SOC_PORT_B;
+		shp = &srp->sr_soc_hdr;
+		cq_hdr = &srp->sr_cqhdr;
+		/*
+		 * It turns out that on faster CPU's we have a problem where
+		 * the soc interrupts us before the response has been DMA'ed
+		 * in. This should not happen but does !!. So to workaround
+		 * the problem for now, check the sequence # of the response.
+		 * If it does not match with what we have, we must be
+		 * reading stale data
+		 */
+		if (cq_hdr->cq_hdr_seqno != kcqv->skc_seqno) {
+#if defined(DEBUG) && !defined(lint)
+			socal_read_stale_data++;
+#endif
+			if (kcq->deferred_intr_timeoutid) {
+				mutex_exit(&kcq->skc_mtx);
+				return;
+			} else {
+				kcq->skc_saved_out = kcqv->skc_out;
+				kcq->skc_saved_seqno = kcqv->skc_seqno;
+				kcq->deferred_intr_timeoutid = timeout(
+					socal_deferred_intr, (caddr_t)kcq,
+					drv_usectohz(10000));
+				mutex_exit(&kcq->skc_mtx);
+				return;
+			}
+		}
+
+		fcalpkt = (fcal_packet_t *)
+				SOCAL_ID_LOOKUP(shp->sh_request_token);
+
+		if ((socal_core & SOCAL_TAKE_CORE) && ddi_peek8(socalp->dip,
+		    (char *)fcalpkt, &val) != DDI_SUCCESS) {
+			cmn_err(CE_WARN, "bad token = %p\n", (void *)fcalpkt);
+			mutex_exit(&kcq->skc_mtx);
+			socal_take_core(socalp);
+		}
+
+		if ((fcalpkt == (fcal_packet_t *)NULL) ||
+			(fcalpkt->fcal_magic != FCALP_MAGIC)) {
+		    (void) sprintf(buf, "!invalid FC packet; \n\
+			in, out, seqno = 0x%x, 0x%x, 0x%x\n",
+			kcqv->skc_in, kcqv->skc_out, kcqv->skc_seqno);
+		    socal_disp_err(socalp, CE_WARN, "link.4060", buf);
+		    DEBUGF(4, (CE_CONT,
+		    "\tsoc CR: 0x%x SAE: 0x%x CSR: 0x%x IMR: 0x%x\n",
+			    socalreg->socal_cr.w,
+			    socalreg->socal_sae.w,
+			    socalreg->socal_csr.w,
+			    socalreg->socal_imr));
+		/*
+		 * Update response queue ptrs and soc registers.
+		 */
+		    kcqv->skc_out++;
+		    if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
+			    kcqv->skc_out = 0;
+			    kcqv->skc_seqno++;
+		    }
+
+		} else {
+
+			DEBUGF(2, (CE_CONT, "packet 0x%p complete\n",
+				fcalpkt));
+			status = srp->sr_soc_status;
+			fcalpkt->fcal_pkt_status = status;
+			DEBUGF(2, (CE_CONT, "SOC status: 0x%x\n", status));
+			/*
+			 * map soc status codes to
+			 * transport status codes
+			 */
+
+			ASSERT((fcalpkt->fcal_cmd_state & FCAL_CMD_COMPLETE)
+				== 0);
+			mutex_enter(&socalp->abort_mtx);
+			fcalpkt->fcal_pkt_flags |= FCFLAG_COMPLETE;
+			mutex_exit(&socalp->abort_mtx);
+
+			/*
+			 * Copy the response frame header (if there is one)
+			 * so that the upper levels can use it.  Note that,
+			 * for now, we'll copy the header only if there was
+			 * some sort of non-OK status, to save the PIO reads
+			 * required to get the header from the host adapter's
+			 * xRAM.
+			 */
+			if (((status != FCAL_STATUS_OK) ||
+			    (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags
+			    & SOC_RESP_HEADER)) &&
+			    (srp->sr_soc_hdr.sh_flags & SOC_FC_HEADER)) {
+				src = (caddr_t)&srp->sr_fc_frame_hdr;
+				dst = (caddr_t)&fcalpkt->fcal_resp_hdr;
+				bcopy(src, dst, sizeof (fc_frame_header_t));
+				fcalpkt->fcal_pkt_flags |= FCFLAG_RESP_HEADER;
+				i = srp->sr_soc_hdr.sh_flags & SOC_PORT_B ?
+				    1 : 0;
+				if ((status != FCAL_STATUS_OK) &&
+					(status <= FCAL_STATUS_MAX_STATUS)) {
+					socalp->socal_stats.pstats[i].
+					resp_status[status]++;
+				} else {
+					socalp->socal_stats.pstats[i].
+					resp_status[FCAL_STATUS_ERROR]++;
+				}
+			} else if (status == FCAL_STATUS_OK) {
+			fcalpkt->fcal_socal_request.sr_soc_hdr.sh_byte_cnt =
+						shp->sh_byte_cnt;
+			}
+			fcalpkt->fcal_diag_status =
+			    (uint32_t)srp->sr_dataseg.fc_base;
+			fcalpkt->fcal_ncmds = srp->sr_ncmds;
+
+			/*
+			 * Update response queue ptrs and soc registers.
+			 */
+			kcqv->skc_out++;
+			if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
+				kcqv->skc_out = 0;
+				kcqv->skc_seqno++;
+			}
+
+			/* For incmplt DMA offline loop by loopback */
+			if (fcalpkt->fcal_pkt_status ==
+				FCAL_STATUS_INCOMPLETE_DMA_ERR) {
+				socal_port_t	*port_statep;
+				uint_t		r;
+
+				/*
+				 * Give up the mutex to avoid a deadlock
+				 * with the loopback routine.
+				 */
+				mutex_exit(&kcq->skc_mtx);
+
+				port_statep = &socalp->port_state[port];
+				mutex_enter(&port_statep->sp_mtx);
+				if (port_statep->sp_status &
+				    PORT_DISABLED) {
+					/* Already disabled */
+					mutex_exit(&port_statep->sp_mtx);
+				} else {
+					port_statep->sp_status |=
+					    PORT_DISABLED;
+					mutex_exit(&port_statep->sp_mtx);
+					(void) socal_diag_request(
+					    (void *)socalp, port,
+					    &r, SOC_DIAG_INT_LOOP);
+				}
+				/* reacquire mutex */
+				mutex_enter(&kcq->skc_mtx);
+			}
+
+			/*
+			 * Complete the packet *ONLY* if it not being aborted
+			 * or the abort has already completed.  Otherwise it is
+			 * not safe to free the ID.
+			 */
+			mutex_enter(&socalp->abort_mtx);
+			if (!(fcalpkt->fcal_pkt_flags & FCFLAG_ABORTING)) {
+				/*
+				 * Call the completion routine
+				 */
+				SOCAL_ID_FREE(shp->sh_request_token);
+				if (fcalpkt->fcal_pkt_comp != NULL) {
+					fcalpkt->fcal_cmd_state |=
+					    FCAL_CMD_COMPLETE;
+
+					/*
+					 * Give up the mutex to avoid a
+					 * deadlock with the callback routine.
+					 */
+					mutex_exit(&socalp->abort_mtx);
+					mutex_exit(&kcq->skc_mtx);
+
+					/* callback */
+					(*fcalpkt->fcal_pkt_comp)(fcalpkt);
+
+					/* reacquire mutex */
+					mutex_enter(&kcq->skc_mtx);
+				} else {
+					fcalpkt->fcal_cmd_state |=
+					    FCAL_CMD_COMPLETE;
+					mutex_exit(&socalp->abort_mtx);
+				}
+			} else {
+				mutex_exit(&socalp->abort_mtx);
+			}
+		}
+
+
+		if (kcq->skc_cq == NULL)
+			/*
+			 * This action averts a potential PANIC scenario
+			 * where the SUSPEND code flow grabbed the kcq->skc_mtx
+			 * when we let it go, to call our completion routine,
+			 * and "initialized" the response queue.  We exit our
+			 * processing loop here, thereby averting a PANIC due
+			 * to a NULL de-reference from the response queue.
+			 *
+			 * Note that this is an interim measure that needs
+			 * to be revisited when this driver is next revised
+			 * for enhanced performance.
+			 */
+			break;
+
+		/*
+		 * We need to re-read the input and output pointers in
+		 * case a polling routine should process some entries
+		 * from the response queue while we're doing a callback
+		 * routine with the response queue mutex dropped.
+		 */
+		cqe = &(kcq->skc_cq[kcqv->skc_out]);
+		index_in = SOCAL_RESPONSEQ_INDEX(srq, socalreg->socal_rspp.w);
+
+		/*
+		 * Mess around with the hardware if we think we've run out
+		 * of entries in the queue, just to make sure we've read
+		 * all entries that are available.
+		 */
+
+		    socalreg->socal_csr.w =
+			((kcqv->skc_out << 24) |
+			(SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_0));
+
+		/* Make sure the csr write has completed */
+		    i = socalreg->socal_csr.w;
+		    DEBUGF(9, (CE_CONT, "csr.w = %x\n", i));
+
+		/*
+		 * Update our idea of where the host adapter has placed
+		 * the most recent entry in the response queue and resync
+		 * the response queue
+		 */
+			index_in =
+			    SOCAL_RESPONSEQ_INDEX(srq, socalreg->socal_rspp.w);
+
+		kcqv->skc_in = index_in;
+	}
+
+	/* Drop lock for request queue. */
+	mutex_exit(&kcq->skc_mtx);
+}
+
+/*
+ * Function name : socal_intr_unsolicited()
+ *
+ * Return Values : none
+ *
+ * Description	 : Processes entries in the unsolicited response
+ *		   queue
+ *
+ *	The SOC+ will give us an unsolicited response
+ *	whenever its status changes: OFFLINE, ONLINE,
+ *	or in response to a packet arriving from an originator.
+ *
+ *	When message requests come in they will be placed in our
+ *	buffer queue or in the next "inline" packet by the SOC hardware.
+ *
+ * Context	: Unsolicited interrupts must be masked
+ */
+
+static void
+socal_intr_unsolicited(socal_state_t *socalp, uint32_t urq)
+{
+	socal_kcq_t		*kcq;
+	volatile socal_kcq_t	*kcqv;
+	soc_response_t		*srp;
+	volatile cqe_t		*cqe;
+	int			port;
+	register uchar_t		t_index, t_seqno;
+	register volatile socal_reg_t *socalreg = socalp->socal_rp;
+	volatile cqe_t		*cqe_cont = NULL;
+	uint_t			i;
+	int			hdr_count;
+	int			status;
+	ushort_t		flags;
+	auto char		buf[256];
+	socal_port_t		*port_statep;
+#if defined(DEBUG) && !defined(lint)
+	int			instance = ddi_get_instance(socalp->dip);
+#endif
+	uchar_t			index_in;
+	socal_unsol_cb_t	*cblist;
+
+	kcq = &socalp->response[urq];
+	kcqv = (volatile socal_kcq_t *)kcq;
+
+	/*
+	 * Grab lock for response queue.
+	 */
+	mutex_enter(&kcq->skc_mtx);
+
+	cqe = (volatile cqe_t *)&(kcq->skc_cq[kcqv->skc_out]);
+
+	index_in = SOCAL_RESPONSEQ_INDEX(urq, socalreg->socal_rspp.w);
+
+	kcqv->skc_in = index_in;
+
+	while (kcqv->skc_out != index_in) {
+		(void) ddi_dma_sync(kcq->skc_dhandle, 0, 0,
+			DDI_DMA_SYNC_FORKERNEL);
+
+		/* Check for continuation entries */
+		if ((hdr_count = cqe->cqe_hdr.cq_hdr_count) != 1) {
+
+		    t_seqno = kcqv->skc_seqno;
+		    t_index = kcqv->skc_out + hdr_count;
+
+		    i = index_in;
+		    if (kcqv->skc_out > index_in)
+			i += kcq->skc_last_index + 1;
+
+		/*
+		 * If we think the continuation entries haven't yet
+		 * arrived, try once more before giving up
+		 */
+		    if (i < t_index) {
+
+			socalreg->socal_csr.w =
+			    ((kcqv->skc_out << 24) |
+			    (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_1));
+
+			/* Make sure the csr write has completed */
+			i = socalreg->socal_csr.w;
+
+			/*
+			 * Update our idea of where the host adapter has placed
+			 * the most recent entry in the response queue
+			 */
+			i = index_in = SOCAL_RESPONSEQ_INDEX(urq,
+				socalreg->socal_rspp.w);
+			if (kcqv->skc_out > index_in)
+			    i += kcq->skc_last_index + 1;
+
+			/*
+			 * Exit if the continuation entries haven't yet
+			 * arrived
+			 */
+			if (i < t_index)
+			    break;
+		    }
+
+		    if (t_index > kcq->skc_last_index) {
+			t_seqno++;
+			t_index &= kcq->skc_last_index;
+		    }
+
+		    cqe_cont = (volatile cqe_t *)
+		    &(kcq->skc_cq[t_index ? t_index - 1 : kcq->skc_last_index]);
+
+
+		    /* A cq_hdr_count > 2 is illegal; throw away the response */
+
+		/*
+		 * XXX - should probably throw out as many entries as the
+		 * hdr_cout tells us there are
+		 */
+		    if (hdr_count != 2) {
+			socal_disp_err(socalp, CE_WARN, "driver.4030",
+			    "!too many continuation entries");
+			DEBUGF(4, (CE_CONT,
+				"socal%d: soc+ unsolicited entry count = %d\n",
+				instance, cqe->cqe_hdr.cq_hdr_count));
+
+			if ((++t_index & kcq->skc_last_index) == 0) {
+			    t_index = 0;
+			    t_seqno++;
+			}
+			kcqv->skc_out = t_index;
+			kcqv->skc_seqno = t_seqno;
+
+			cqe = &(kcq->skc_cq[kcqv->skc_out]);
+			cqe_cont = NULL;
+			continue;
+		    }
+		}
+
+		/*
+		 * Update unsolicited response queue ptrs
+		 */
+		kcqv->skc_out++;
+		if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
+			kcqv->skc_out = 0;
+			kcqv->skc_seqno++;
+		}
+
+		if (cqe_cont != NULL) {
+		    kcqv->skc_out++;
+		    if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
+			    kcqv->skc_out = 0;
+			    kcqv->skc_seqno++;
+		    }
+		}
+
+		if (index_in == kcqv->skc_out) {
+		    socalreg->socal_csr.w = ((kcqv->skc_out << 24) |
+			(SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_1));
+
+		/* Make sure the csr write has completed */
+		    i = socalreg->socal_csr.w;
+		}
+
+		srp = (soc_response_t *)cqe;
+		flags = srp->sr_soc_hdr.sh_flags;
+		port = flags & SOC_PORT_B;
+		port_statep = &socalp->port_state[port];
+
+		/*
+		 * XXX need to deal buffer pool entries here
+		 */
+		switch (flags & ~SOC_PORT_B) {
+		case SOC_UNSOLICITED | SOC_FC_HEADER:
+
+		    srp = (soc_response_t *)cqe;
+
+		    switch (srp->sr_fc_frame_hdr.r_ctl & R_CTL_ROUTING) {
+		    case R_CTL_EXTENDED_SVC:
+			/*
+			 * Extended Link Services frame received
+			 */
+			socalp->socal_stats.pstats[port].els_rcvd++;
+			socal_us_els(socalp, (cqe_t *)cqe, (caddr_t)cqe_cont);
+
+			/* do callbacks to any interested ULPs */
+			mutex_enter(&port_statep->sp_mtx);
+			for (cblist = port_statep->sp_unsol_cb; cblist;
+				cblist = cblist->next) {
+				if (cblist->els_cb) {
+				    mutex_exit(&port_statep->sp_mtx);
+				    mutex_exit(&kcq->skc_mtx);
+				    cblist->els_cb(cblist->arg, (cqe_t *)cqe,
+					(caddr_t)cqe_cont);
+				    mutex_enter(&kcq->skc_mtx);
+				    mutex_enter(&port_statep->sp_mtx);
+				}
+			}
+			mutex_exit(&port_statep->sp_mtx);
+			break;
+		    case R_CTL_BASIC_SVC:
+			(void) sprintf(buf,
+			    "!unsupported Link Service command: 0x%x",
+				srp->sr_fc_frame_hdr.type);
+			socal_disp_err(socalp, CE_WARN, "link.4020", buf);
+			break;
+		    case R_CTL_DEVICE_DATA:
+			switch (srp->sr_fc_frame_hdr.type) {
+			default:
+			    mutex_enter(&port_statep->sp_mtx);
+			    status = 1;
+			    for (cblist = port_statep->sp_unsol_cb; cblist;
+				cblist = cblist->next) {
+				if (cblist->data_cb &&
+				    (cblist->type ==
+				    srp->sr_fc_frame_hdr.type)) {
+					mutex_exit(&port_statep->sp_mtx);
+					mutex_exit(&kcq->skc_mtx);
+					cblist->data_cb(cblist->arg,
+					    (cqe_t *)cqe, (caddr_t)cqe_cont);
+					mutex_enter(&kcq->skc_mtx);
+					mutex_enter(&port_statep->sp_mtx);
+					status = 0;
+				}
+			    }
+			    mutex_exit(&port_statep->sp_mtx);
+
+			    if (status == 0)
+				break;
+
+			    (void) sprintf(buf, "!unknown FC-4 command: 0x%x",
+				srp->sr_fc_frame_hdr.type);
+			    socal_disp_err(socalp, CE_WARN, "link.4030", buf);
+			    break;
+			}
+			break;
+		    default:
+			(void) sprintf(buf, "!unsupported FC frame R_CTL: 0x%x",
+			    srp->sr_fc_frame_hdr.r_ctl);
+			socal_disp_err(socalp, CE_WARN, "link.4040", buf);
+			break;
+		    }
+		    break;
+
+		case SOC_STATUS: {
+
+			/*
+			 * Note that only the lsbyte of the status has
+			 * interesting information...
+			 */
+			status = srp->sr_soc_status;
+
+			switch (status) {
+
+			case FCAL_STATUS_ONLINE:
+				(void) sprintf(buf,
+				"!port %d: Fibre Channel is ONLINE\n", port);
+				socal_disp_err(socalp, CE_CONT, "link.6010",
+					buf);
+				mutex_enter(&port_statep->sp_mtx);
+				port_statep->sp_status &= ~PORT_STATUS_MASK;
+				port_statep->sp_status |= PORT_ONLINE;
+				mutex_exit(&port_statep->sp_mtx);
+				socalp->socal_stats.pstats[port].onlines++;
+				DEBUGF(4, (CE_CONT,
+					"socal%d intr_unsol: ONLINE intr\n",
+					instance));
+				break;
+
+			case FCAL_STATUS_LOOP_ONLINE:
+				(void) sprintf(buf,
+				"!port %d: Fibre Channel Loop is ONLINE\n",
+					port);
+				socal_disp_err(socalp, CE_CONT, "link.6010",
+					buf);
+				mutex_enter(&port_statep->sp_mtx);
+				port_statep->sp_status &= ~PORT_STATUS_MASK;
+				port_statep->sp_status |= PORT_ONLINE_LOOP;
+				mutex_exit(&port_statep->sp_mtx);
+				socalp->socal_stats.pstats[port].online_loops++;
+				DEBUGF(4, (CE_CONT,
+				    "socal%d intr_unsol: ONLINE-LOOP intr\n",
+				    instance));
+				break;
+
+			case FCAL_STATUS_ERR_OFFLINE:
+				/*
+				 * SOC and Responder will both flush
+				 * all active commands.
+				 * So I don't have to do anything
+				 * until it comes back online.
+				 */
+				(void) sprintf(buf,
+				"!port %d: Fibre Channel is OFFLINE\n", port);
+				socal_disp_err(socalp, CE_CONT, "link.5010",
+					buf);
+
+				mutex_enter(&port_statep->sp_mtx);
+				port_statep->sp_status &= ~PORT_STATUS_MASK;
+				port_statep->sp_status |= PORT_OFFLINE;
+				port_statep->sp_lilpmap_valid = 0;
+				mutex_exit(&port_statep->sp_mtx);
+				socalp->socal_stats.pstats[port].offlines++;
+				DEBUGF(4, (CE_CONT,
+				    "socal%d intr_unsol: OFFLINE intr\n",
+				    instance));
+
+				break;
+			default:
+				(void) sprintf(buf, "!unknown status: 0x%x\n",
+				status);
+				socal_disp_err(socalp, CE_WARN, "link.3020",
+					buf);
+			}
+			mutex_exit(&kcq->skc_mtx);
+			mutex_enter(&port_statep->sp_mtx);
+			for (cblist = port_statep->sp_unsol_cb; cblist;
+				cblist = cblist->next) {
+				if (cblist->statec_cb) {
+				    mutex_exit(&port_statep->sp_mtx);
+				    (*cblist->statec_cb)(cblist->arg, status);
+				    mutex_enter(&port_statep->sp_mtx);
+				}
+			}
+			mutex_exit(&port_statep->sp_mtx);
+			if (status == FCAL_STATUS_ERR_OFFLINE) {
+				socal_flush_overflowq(socalp, port,
+				    CQ_REQUEST_0);
+				socal_flush_overflowq(socalp, port,
+				    CQ_REQUEST_1);
+			}
+			mutex_enter(&kcq->skc_mtx);
+			break;
+		}
+		default:
+			(void) sprintf(buf, "!unexpected state: flags: 0x%x\n",
+			flags);
+			socal_disp_err(socalp, CE_WARN, "link.4050", buf);
+			DEBUGF(4, (CE_CONT,
+			"\tsoc CR: 0x%x SAE: 0x%x CSR: 0x%x IMR: 0x%x\n",
+				socalp->socal_rp->socal_cr.w,
+				socalp->socal_rp->socal_sae.w,
+				socalp->socal_rp->socal_csr.w,
+				socalp->socal_rp->socal_imr));
+		}
+
+
+		if (kcq->skc_cq == NULL)
+			/*
+			 * This action averts a potential PANIC scenario
+			 * where the SUSPEND code flow grabbed the kcq->skc_mtx
+			 * when we let it go, to call our completion routine,
+			 * and "initialized" the response queue.  We exit our
+			 * processing loop here, thereby averting a PANIC due
+			 * to a NULL de-reference from the response queue.
+			 *
+			 * Note that this is an interim measure that needs
+			 * to be revisited when this driver is next revised
+			 * for enhanced performance.
+			 */
+			break;
+
+		/*
+		 * We need to re-read the input and output pointers in
+		 * case a polling routine should process some entries
+		 * from the response queue while we're doing a callback
+		 * routine with the response queue mutex dropped.
+		 */
+		cqe = &(kcq->skc_cq[kcqv->skc_out]);
+		index_in = SOCAL_RESPONSEQ_INDEX(urq, socalreg->socal_rspp.w);
+		cqe_cont = NULL;
+
+		/*
+		 * Mess around with the hardware if we think we've run out
+		 * of entries in the queue, just to make sure we've read
+		 * all entries that are available.
+		 */
+		if (index_in == kcqv->skc_out) {
+
+		    socalreg->socal_csr.w =
+			((kcqv->skc_out << 24) |
+			(SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_1));
+
+		/* Make sure the csr write has completed */
+		    i = socalreg->socal_csr.w;
+
+		/*
+		 * Update our idea of where the host adapter has placed
+		 * the most recent entry in the response queue
+		 */
+		    index_in =
+			SOCAL_RESPONSEQ_INDEX(urq, socalreg->socal_rspp.w);
+		}
+
+		socalp->socal_stats.pstats[port].unsol_resps++;
+
+		kcqv->skc_in = index_in;
+
+	}
+
+	/* Release lock for response queue. */
+	mutex_exit(&kcq->skc_mtx);
+}
+
+/*
+ * socal_us_els() - This function handles unsolicited extended link
+ *	service responses received from the soc.
+ */
+static void
+socal_us_els(socal_state_t *socalp, cqe_t *cqe, caddr_t payload)
+{
+	soc_response_t	*srp = (soc_response_t *)cqe;
+	els_payload_t	*els = (els_payload_t *)payload;
+	int	i;
+	char   *bp;
+	auto	char buf[256];
+
+	/*
+	 * There should be a CQE continuation entry for all
+	 * extended link services
+	 */
+	if ((els == NULL) || ((i = srp->sr_soc_hdr.sh_byte_cnt) == 0)) {
+	    socal_disp_err(socalp, CE_WARN, "link.4010",
+		"!incomplete continuation entry");
+	    return;
+	}
+
+	/* Quietly impose a maximum byte count */
+	if (i > SOC_CQE_PAYLOAD)
+		i = SOC_CQE_PAYLOAD;
+	i -= sizeof (union els_cmd_u);
+
+	/*
+	 * Decode the LS_Command code
+	 */
+	switch (els->els_cmd.c.ls_command) {
+	    case LA_ELS_DISPLAY:
+		els->els_data[i] = '\0';	/* terminate the string */
+		for (bp = (char *)&(els->els_data[0]); *bp; bp++) {
+			/* squash newlines */
+			if (*bp == '\n') *bp = ' ';
+		}
+		(void) sprintf(buf, "!message: %s\n", els->els_data);
+		socal_disp_err(socalp, CE_CONT, "link.1010", buf);
+		break;
+
+	    default:
+		DEBUGF(3, (CE_CONT, "!unknown LS_Command, %x\n",
+						els->els_cmd.i));
+		break;
+	}
+
+}
+
+/*ARGSUSED*/
+static fcal_packet_t *
+socal_packet_alloc(socal_state_t *socalp, fcal_sleep_t sleep)
+{
+	int flag;
+	fcal_packet_t *pkt;
+
+	if (sleep == FCAL_SLEEP)
+		flag = KM_SLEEP;
+	else
+		flag = KM_NOSLEEP;
+
+	pkt = (fcal_packet_t *)kmem_zalloc(sizeof (fcal_packet_t), flag);
+
+	if (pkt != (fcal_packet_t *)NULL)
+		pkt->fcal_magic = FCALP_MAGIC;
+
+	return (pkt);
+}
+
+static void
+socal_packet_free(fcal_packet_t *fcalpkt)
+{
+	kmem_free((void *)fcalpkt, sizeof (fcal_packet_t));
+}
+
+static void
+socal_lilp_map_done(fcal_packet_t *fcalpkt)
+{
+	uint32_t	port;
+	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
+
+	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
+		port = 1;
+	else
+		port = 0;
+	mutex_enter(&socalp->port_state[port].sp_mtx);
+	socalp->port_state[port].sp_status &= ~PORT_LILP_PENDING;
+	cv_broadcast(&socalp->port_state[port].sp_cv);
+	mutex_exit(&socalp->port_state[port].sp_mtx);
+}
+
+static void
+socal_force_lip_done(fcal_packet_t *fcalpkt)
+{
+	uint32_t	port;
+	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
+
+	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
+		port = 1;
+	else
+		port = 0;
+	mutex_enter(&socalp->port_state[port].sp_mtx);
+	socalp->port_state[port].sp_status &= ~PORT_LIP_PENDING;
+	cv_broadcast(&socalp->port_state[port].sp_cv);
+	mutex_exit(&socalp->port_state[port].sp_mtx);
+}
+
+static void
+socal_adisc_done(fcal_packet_t *fcalpkt)
+{
+	uint32_t	port;
+	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
+
+	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
+		port = 1;
+	else
+		port = 0;
+	mutex_enter(&socalp->port_state[port].sp_mtx);
+	socalp->port_state[port].sp_status &= ~PORT_ADISC_PENDING;
+	cv_broadcast(&socalp->port_state[port].sp_cv);
+	mutex_exit(&socalp->port_state[port].sp_mtx);
+}
+
+static void
+socal_lbf_done(fcal_packet_t *fcalpkt)
+{
+	uint32_t	port;
+	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
+
+	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
+		port = 1;
+	else
+		port = 0;
+	mutex_enter(&socalp->port_state[port].sp_mtx);
+	socalp->port_state[port].sp_status &= ~PORT_LBF_PENDING;
+	cv_broadcast(&socalp->port_state[port].sp_cv);
+	mutex_exit(&socalp->port_state[port].sp_mtx);
+}
+
+static void
+socal_rls_done(fcal_packet_t *fcalpkt)
+{
+	uint32_t	port;
+	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
+
+	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
+		port = 1;
+	else
+		port = 0;
+	mutex_enter(&socalp->port_state[port].sp_mtx);
+	socalp->port_state[port].sp_status &= ~PORT_RLS_PENDING;
+	cv_broadcast(&socalp->port_state[port].sp_cv);
+	mutex_exit(&socalp->port_state[port].sp_mtx);
+}
+
+static void
+socal_force_offline_done(fcal_packet_t *fcalpkt)
+{
+	uint32_t	port;
+	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
+
+	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
+		port = 1;
+	else
+		port = 0;
+	mutex_enter(&socalp->port_state[port].sp_mtx);
+	socalp->port_state[port].sp_status &= ~PORT_OFFLINE_PENDING;
+	cv_broadcast(&socalp->port_state[port].sp_cv);
+	mutex_exit(&socalp->port_state[port].sp_mtx);
+}
+
+static void
+socal_abort_done(fcal_packet_t *fcalpkt)
+{
+	uint32_t	port;
+	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
+	soc_header_t	*shp =
+		(soc_header_t *)&fcalpkt->fcal_socal_request.sr_soc_hdr;
+	fcal_packet_t	*target = (fcal_packet_t *)
+		SOCAL_ID_LOOKUP(shp->sh_request_token);
+
+	mutex_enter(&socalp->abort_mtx);
+	ASSERT(target->fcal_pkt_flags & FCFLAG_ABORTING);
+	if (!(target->fcal_pkt_flags & FCFLAG_COMPLETE)) {
+		SOCAL_ID_FREE(shp->sh_request_token);
+	}
+	mutex_exit(&socalp->abort_mtx);
+	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
+		port = 1;
+	else
+		port = 0;
+	mutex_enter(&socalp->port_state[port].sp_mtx);
+	socalp->port_state[port].sp_status &= ~PORT_ABORT_PENDING;
+	cv_broadcast(&socalp->port_state[port].sp_cv);
+	mutex_exit(&socalp->port_state[port].sp_mtx);
+}
+
+static void
+socal_bypass_dev_done(fcal_packet_t *fcalpkt)
+{
+	uint32_t	port;
+	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
+	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
+		port = 1;
+	else
+		port = 0;
+	mutex_enter(&socalp->port_state[port].sp_mtx);
+	socalp->port_state[port].sp_status &= ~PORT_BYPASS_PENDING;
+	cv_broadcast(&socalp->port_state[port].sp_cv);
+	mutex_exit(&socalp->port_state[port].sp_mtx);
+}
+
+/*ARGSUSED*/
+static unsigned int
+socal_dummy_intr(caddr_t arg)
+{
+	return (DDI_INTR_UNCLAIMED);
+}
+
+static int
+socal_diag_request(socal_state_t *socalp, uint32_t port, uint_t *diagcode,
+    uint32_t cmd)
+{
+	fcal_packet_t		*fcalpkt;
+	soc_diag_request_t	*sdr;
+	socal_port_t		*port_statep = &socalp->port_state[port];
+	struct fcal_lilp_map	map;
+
+	/* Grabbing the state mutex is totally unnecessary.... */
+	if (!(port_statep->sp_status & PORT_DISABLED)) {
+		if (socal_getmap(socalp, port, (caddr_t)&map, 0, FKIOCTL)
+			!= -1) {
+			if (map.lilp_length != 1 && ((port_statep->sp_status &
+				PORT_ONLINE_LOOP) && cmd != SOC_DIAG_REM_LOOP))
+				return (FCAL_TRANSPORT_UNAVAIL);
+		}
+	}
+	if ((fcalpkt = socal_packet_alloc(socalp, FCAL_SLEEP))
+	    == (fcal_packet_t *)NULL)
+		return (FCAL_ALLOC_FAILED);
+	sdr = (soc_diag_request_t *)&fcalpkt->fcal_socal_request;
+	if (port)
+	    sdr->sdr_soc_hdr.sh_flags = SOC_PORT_B;
+	sdr->sdr_diag_cmd = cmd;
+	sdr->sdr_cqhdr.cq_hdr_count = 1;
+	sdr->sdr_cqhdr.cq_hdr_type = CQ_TYPE_DIAGNOSTIC;
+	fcalpkt->fcal_pkt_cookie = (void *)socalp;
+	return (socal_doit(fcalpkt, port_statep, 1, NULL,
+	    SOCAL_DIAG_TIMEOUT, 0, diagcode));
+}
+
+static uint_t
+socal_force_offline(void *ssp, uint_t port, uint_t polled)
+{
+	fcal_packet_t		*fcalpkt;
+	soc_cmdonly_request_t	*scr;
+	socal_state_t		*socalp = (socal_state_t *)ssp;
+	socal_port_t		*port_statep = &socalp->port_state[port];
+
+	if ((fcalpkt =
+	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
+	    == (fcal_packet_t *)NULL)
+		return (FCAL_ALLOC_FAILED);
+
+	scr = (soc_cmdonly_request_t *)&fcalpkt->fcal_socal_request;
+	if (port)
+	    scr->scr_soc_hdr.sh_flags = SOC_PORT_B;
+	scr->scr_cqhdr.cq_hdr_count = 1;
+	scr->scr_cqhdr.cq_hdr_type = CQ_TYPE_OFFLINE;
+	fcalpkt->fcal_pkt_cookie = (void *)socalp;
+	return (socal_doit(fcalpkt, port_statep, 0, socal_force_offline_done,
+	    SOCAL_OFFLINE_TIMEOUT, PORT_OFFLINE_PENDING, NULL));
+}
+
+static int
+socal_issue_adisc(socal_state_t *socalp, uint32_t port, uint32_t dest,
+	la_els_adisc_t *payload, uint32_t polled)
+{
+	int			retval;
+	la_els_adisc_t		*buf;
+	fcal_packet_t		*fcalpkt;
+	socal_port_t		*port_statep;
+	socal_priv_cmd_t 	*privp;
+
+	port_statep = &socalp->port_state[port];
+
+	if ((fcalpkt =
+	    socal_els_alloc(socalp, port, dest, sizeof (la_els_adisc_t),
+	    sizeof (la_els_adisc_t), (caddr_t *)&privp, polled))
+	    == (fcal_packet_t *)NULL)
+		return (FCAL_ALLOC_FAILED);
+
+	privp = (socal_priv_cmd_t *)fcalpkt->fcal_pkt_private;
+	buf = (la_els_adisc_t *)privp->cmd;
+	buf->ls_code = LA_ELS_ADISC;
+	buf->mbz[0] = 0;
+	buf->mbz[1] = 0;
+	buf->mbz[2] = 0;
+	buf->hard_address = 0;
+	bcopy((caddr_t)&port_statep->sp_p_wwn,
+	    (caddr_t)&buf->port_wwn, sizeof (buf->port_wwn));
+	bcopy((caddr_t)&socalp->socal_n_wwn,
+	    (caddr_t)&buf->node_wwn, sizeof (buf->node_wwn));
+	buf->nport_id = fcalpkt->fcal_socal_request.sr_fc_frame_hdr.s_id;
+	(void) ddi_dma_sync(privp->cmd_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
+
+	retval = socal_doit(fcalpkt, port_statep, 0, socal_adisc_done,
+	    SOCAL_ADISC_TIMEOUT, PORT_ADISC_PENDING, NULL);
+	if (retval == FCAL_SUCCESS) {
+		(void) ddi_dma_sync(privp->rsp_handle, 0, 0,
+				DDI_DMA_SYNC_FORKERNEL);
+		bcopy(privp->rsp, (caddr_t)payload, sizeof (la_els_adisc_t));
+	}
+	privp->fapktp = NULL;
+	socal_els_free(privp);
+	return (retval);
+}
+
+static int
+socal_issue_lbf(socal_state_t *socalp, uint32_t port,
+    uchar_t *payload, size_t length, uint32_t polled)
+{
+	int			retval;
+	fcal_packet_t		*fcalpkt;
+	socal_port_t		*port_statep;
+	socal_priv_cmd_t 	*privp;
+
+	port_statep = &socalp->port_state[port];
+
+	if ((fcalpkt = socal_lbf_alloc(socalp, port, length, length,
+		    (caddr_t *)&privp, polled)) == (fcal_packet_t *)NULL)
+		return (FCAL_ALLOC_FAILED);
+
+	privp = (socal_priv_cmd_t *)fcalpkt->fcal_pkt_private;
+	bcopy((caddr_t)payload, privp->cmd, length);
+	(void) ddi_dma_sync(privp->cmd_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
+
+	retval = socal_doit(fcalpkt, port_statep, polled, socal_lbf_done,
+	    SOCAL_LBF_TIMEOUT, PORT_LBF_PENDING, NULL);
+
+	if (retval == FCAL_SUCCESS) {
+		(void) ddi_dma_sync(privp->rsp_handle, 0, 0,
+				DDI_DMA_SYNC_FORKERNEL);
+		bcopy(privp->rsp, (caddr_t)payload, length);
+	}
+	privp->fapktp = NULL;
+	socal_lbf_free(privp);
+	return (retval);
+}
+
+static int
+socal_issue_rls(socal_state_t *socalp, uint32_t port, uint32_t dest,
+	la_els_rls_reply_t *payload, uint32_t polled)
+{
+	int	retval;
+	la_els_rls_t		*buf;
+	fcal_packet_t		*fcalpkt;
+	socal_port_t		*port_statep;
+	socal_priv_cmd_t 	*privp;
+	uint32_t		arg;
+
+	port_statep = &socalp->port_state[port];
+
+	if (dest == socal_getmap(socalp, port, NULL, 0, 0)) {
+		/* load up the the struct with the local lesb */
+		struct la_els_rjt *rsp = (struct la_els_rjt *)payload;
+
+		rsp->ls_code = LA_ELS_RJT;
+		rsp->mbz[0] = 0;
+		rsp->mbz[1] = 0;
+		rsp->mbz[2] = 0;
+		rsp->reason_code = RJT_UNSUPPORTED;
+		rsp->reserved = 0;
+		rsp->explanation = 0;
+		rsp->vendor = 0;
+		return (FCAL_SUCCESS);
+	}
+
+	if ((fcalpkt =
+	    socal_els_alloc(socalp, port, dest, sizeof (la_els_rls_t),
+	    sizeof (la_els_rls_reply_t), (caddr_t *)&privp, polled))
+	    == (fcal_packet_t *)NULL)
+		return (FCAL_ALLOC_FAILED);
+
+	privp = (socal_priv_cmd_t *)fcalpkt->fcal_pkt_private;
+
+	if (payload->link_failure & 0xff000000)
+		arg = payload->link_failure;
+	else
+		arg = dest;
+
+	buf = (la_els_rls_t *)privp->cmd;
+	buf->ls_code = LA_ELS_RLS;
+	buf->mbz[0] = 0;
+	buf->mbz[1] = 0;
+	buf->mbz[2] = 0;
+	buf->reserved = 0;
+	buf->nport_id[0] = (arg >> 16) & 0xff;
+	buf->nport_id[1] = (arg >> 8) & 0xff;
+	buf->nport_id[2] = arg & 0xff;
+	(void) ddi_dma_sync(privp->cmd_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
+
+	retval = socal_doit(fcalpkt, port_statep, 0, socal_rls_done,
+	    SOCAL_RLS_TIMEOUT, PORT_RLS_PENDING, NULL);
+	if (retval == FCAL_SUCCESS) {
+		(void) ddi_dma_sync(privp->rsp_handle, 0, 0,
+			DDI_DMA_SYNC_FORKERNEL);
+		bcopy(privp->rsp, (caddr_t)payload,
+		    sizeof (la_els_rls_reply_t));
+	}
+	privp->fapktp = NULL;
+	socal_els_free(privp);
+	return (retval);
+}
+
+fcal_packet_t *
+socal_els_alloc(socal_state_t *socalp, uint32_t port, uint32_t dest,
+	uint32_t cmd_size, uint32_t rsp_size, caddr_t *rprivp, uint32_t polled)
+{
+	struct fcal_packet	*fcalpkt;
+	ddi_dma_cookie_t	ccookie;
+	ddi_dma_cookie_t	rcookie;
+	socal_priv_cmd_t	*privp;
+	ddi_dma_handle_t	chandle = NULL;
+	ddi_dma_handle_t	rhandle = NULL;
+	ddi_acc_handle_t	cacchandle;
+	ddi_acc_handle_t	racchandle;
+	soc_request_t		*srp;
+	fc_frame_header_t	*fhp;
+	uint_t			ccount, cmd_bound = 0, rsp_bound = 0;
+	size_t			real_len;
+	caddr_t			cmd;
+	caddr_t			rsp;
+	uint32_t		ouralpa;
+
+	if ((fcalpkt =
+	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
+	    == (fcal_packet_t *)NULL)
+		return (NULL);
+
+	if ((privp =
+	    (socal_priv_cmd_t *)kmem_zalloc(sizeof (socal_priv_cmd_t),
+	    polled ? KM_NOSLEEP : KM_SLEEP)) == (socal_priv_cmd_t *)NULL) {
+		goto fail;
+	}
+
+	rprivp = (caddr_t *)&privp;
+
+	fcalpkt->fcal_pkt_private = (caddr_t)privp;
+	privp->fapktp = (void *)fcalpkt;
+
+	if ((ouralpa = socal_getmap(socalp, port, NULL, 0, 0)) == -1)
+		goto fail;
+
+	if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
+		DDI_DMA_DONTWAIT, NULL, &chandle) != DDI_SUCCESS)
+		goto fail;
+	privp->cmd_handle = chandle;
+
+	if (ddi_dma_mem_alloc(chandle, cmd_size, &socal_acc_attr,
+		DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
+		(caddr_t *)&cmd, &real_len, &cacchandle) != DDI_SUCCESS)
+		goto fail;
+	privp->cmd = cmd;
+	privp->cmd_acchandle = cacchandle;
+
+	if (real_len < cmd_size)
+		goto fail;
+
+	if (ddi_dma_addr_bind_handle(chandle, (struct as *)NULL,
+		(caddr_t)cmd, cmd_size,
+		DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
+		DDI_DMA_DONTWAIT, NULL, &ccookie, &ccount)
+		!= DDI_DMA_MAPPED)
+		goto fail;
+	cmd_bound = 1;
+	if (ccount != 1)
+		goto fail;
+
+	if (rsp_size) {
+	    if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
+		DDI_DMA_DONTWAIT, NULL, &rhandle) != DDI_SUCCESS)
+		goto fail;
+
+	    privp->rsp_handle = rhandle;
+	    if (ddi_dma_mem_alloc(rhandle, rsp_size, &socal_acc_attr,
+		DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
+		&rsp, &real_len, &racchandle) != DDI_SUCCESS)
+		goto fail;
+	    privp->rsp = rsp;
+	    privp->rsp_acchandle = racchandle;
+	    if (real_len < rsp_size)
+		goto fail;
+
+	    if (ddi_dma_addr_bind_handle(rhandle, (struct as *)NULL,
+		rsp, rsp_size,
+		DDI_DMA_READ | DDI_DMA_CONSISTENT,
+		DDI_DMA_DONTWAIT, NULL, &rcookie, &ccount)
+		!= DDI_DMA_MAPPED)
+		goto fail;
+
+	    rsp_bound = 1;
+	    if (ccount != 1)
+		goto fail;
+	}
+
+	srp = (soc_request_t *)&fcalpkt->fcal_socal_request;
+	srp->sr_soc_hdr.sh_flags = SOC_FC_HEADER;
+	if (port)
+	    srp->sr_soc_hdr.sh_flags |= SOC_PORT_B;
+	srp->sr_soc_hdr.sh_class = 3;
+	srp->sr_soc_hdr.sh_byte_cnt = cmd_size;
+	srp->sr_dataseg[0].fc_base = (uint32_t)ccookie.dmac_address;
+	srp->sr_dataseg[0].fc_count = cmd_size;
+	if (rsp_size == 0) {
+	    srp->sr_soc_hdr.sh_seg_cnt = 1;
+	} else {
+	    srp->sr_soc_hdr.sh_seg_cnt = 2;
+	    srp->sr_dataseg[1].fc_base = (uint32_t)rcookie.dmac_address;
+	    srp->sr_dataseg[1].fc_count = rsp_size;
+	}
+	srp->sr_cqhdr.cq_hdr_count = 1;
+	/* this will potentially be overwritten by the calling function */
+	srp->sr_cqhdr.cq_hdr_type = CQ_TYPE_SIMPLE;
+
+	fcalpkt->fcal_pkt_cookie = (void *)socalp;
+
+	/* Fill in the Fabric Channel Header */
+	fhp = &srp->sr_fc_frame_hdr;
+	fhp->r_ctl = R_CTL_ELS_REQ;
+	fhp->d_id = dest;
+	fhp->s_id = ouralpa;
+	fhp->type = TYPE_EXTENDED_LS;
+	fhp->f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
+	fhp->seq_id = 0;
+	fhp->df_ctl  = 0;
+	fhp->seq_cnt = 0;
+	fhp->ox_id = 0xffff;
+	fhp->rx_id = 0xffff;
+	fhp->ro = 0;
+	return (fcalpkt);
+fail:
+	socal_packet_free(fcalpkt);
+	if (privp) {
+		if (privp->cmd_handle) {
+			if (cmd_bound)
+				(void) ddi_dma_unbind_handle(privp->cmd_handle);
+			ddi_dma_free_handle(&privp->cmd_handle);
+		}
+		if (privp->cmd)
+			ddi_dma_mem_free(&privp->cmd_acchandle);
+		if (privp->rsp_handle) {
+			if (rsp_bound)
+				(void) ddi_dma_unbind_handle(privp->rsp_handle);
+			ddi_dma_free_handle(&privp->rsp_handle);
+		}
+		if (privp->rsp)
+			ddi_dma_mem_free(&privp->rsp_acchandle);
+
+		kmem_free(privp, sizeof (*privp));
+	}
+	return (NULL);
+}
+
+fcal_packet_t *
+socal_lbf_alloc(socal_state_t *socalp, uint32_t port,
+	uint32_t cmd_size, uint32_t rsp_size, caddr_t *rprivp,
+	uint32_t polled)
+{
+	struct fcal_packet	*fcalpkt;
+	ddi_dma_cookie_t	ccookie;
+	ddi_dma_cookie_t	rcookie;
+	socal_priv_cmd_t	*privp;
+	ddi_dma_handle_t	chandle = NULL;
+	ddi_dma_handle_t	rhandle = NULL;
+	ddi_acc_handle_t	cacchandle;
+	ddi_acc_handle_t	racchandle;
+	soc_request_t		*srp;
+	fc_frame_header_t	*fhp;
+	uint_t			ccount, cmd_bound = 0, rsp_bound = 0;
+	size_t			real_len;
+	caddr_t			cmd;
+	caddr_t			rsp;
+
+	if ((fcalpkt =
+	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
+	    == (fcal_packet_t *)NULL)
+		return (NULL);
+
+	if ((privp =
+	    (socal_priv_cmd_t *)kmem_zalloc(sizeof (socal_priv_cmd_t),
+	    polled ? KM_NOSLEEP : KM_SLEEP)) == (socal_priv_cmd_t *)NULL) {
+		goto fail;
+	}
+
+	rprivp = (caddr_t *)&privp;
+
+	fcalpkt->fcal_pkt_private = (caddr_t)privp;
+	privp->fapktp = (void *)fcalpkt;
+
+	if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
+		DDI_DMA_DONTWAIT, NULL, &chandle) != DDI_SUCCESS)
+		goto fail;
+	privp->cmd_handle = chandle;
+
+	if (ddi_dma_mem_alloc(chandle, cmd_size, &socal_acc_attr,
+		DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
+		(caddr_t *)&cmd, &real_len, &cacchandle) != DDI_SUCCESS)
+		goto fail;
+	privp->cmd = cmd;
+	privp->cmd_acchandle = cacchandle;
+
+	if (real_len < cmd_size)
+		goto fail;
+
+	if (ddi_dma_addr_bind_handle(chandle, (struct as *)NULL,
+		(caddr_t)cmd, cmd_size,
+		DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
+		DDI_DMA_DONTWAIT, NULL, &ccookie, &ccount)
+		!= DDI_DMA_MAPPED)
+		goto fail;
+	cmd_bound = 1;
+	if (ccount != 1)
+		goto fail;
+
+	if (rsp_size) {
+	    if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
+		DDI_DMA_DONTWAIT, NULL, &rhandle) != DDI_SUCCESS)
+		goto fail;
+
+	    privp->rsp_handle = rhandle;
+	    if (ddi_dma_mem_alloc(rhandle, rsp_size, &socal_acc_attr,
+		DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
+		&rsp, &real_len, &racchandle) != DDI_SUCCESS)
+			goto fail;
+
+	    privp->rsp = rsp;
+	    privp->rsp_acchandle = racchandle;
+	    if (real_len < rsp_size)
+		goto fail;
+
+	    if (ddi_dma_addr_bind_handle(rhandle, (struct as *)NULL,
+		rsp, rsp_size,
+		DDI_DMA_READ | DDI_DMA_CONSISTENT,
+		DDI_DMA_DONTWAIT, NULL, &rcookie, &ccount)
+		!= DDI_DMA_MAPPED)
+			goto fail;
+
+	    rsp_bound = 1;
+	    if (ccount != 1)
+		goto fail;
+	}
+
+	srp = (soc_request_t *)&fcalpkt->fcal_socal_request;
+	srp->sr_soc_hdr.sh_flags = SOC_FC_HEADER;
+	if (port)
+	    srp->sr_soc_hdr.sh_flags |= SOC_PORT_B;
+	srp->sr_soc_hdr.sh_class = 3;
+	srp->sr_soc_hdr.sh_byte_cnt = cmd_size;
+	srp->sr_dataseg[0].fc_base = (uint32_t)ccookie.dmac_address;
+	srp->sr_dataseg[0].fc_count = cmd_size;
+	if (rsp_size == 0) {
+	    srp->sr_soc_hdr.sh_seg_cnt = 1;
+	} else {
+	    srp->sr_soc_hdr.sh_seg_cnt = 2;
+	    srp->sr_dataseg[1].fc_base = (uint32_t)rcookie.dmac_address;
+	    srp->sr_dataseg[1].fc_count = rsp_size;
+	}
+	srp->sr_cqhdr.cq_hdr_count = 1;
+	/* this will potentially be overwritten by the calling function */
+	srp->sr_cqhdr.cq_hdr_type = CQ_TYPE_SIMPLE;
+
+	fcalpkt->fcal_pkt_cookie = (void *)socalp;
+
+	/* Fill in the Fabric Channel Header */
+	fhp = &srp->sr_fc_frame_hdr;
+	fhp->r_ctl = R_CTL_SOLICITED_DATA;
+	fhp->d_id = socalp->port_state[port].sp_src_id;
+	fhp->s_id = socalp->port_state[port].sp_src_id;
+	fhp->type = TYPE_SCSI_FCP;
+	fhp->f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ | F_CTL_LAST_SEQ;
+	fhp->seq_id = 0;
+	fhp->df_ctl  = 0;
+	fhp->seq_cnt = 0;
+	fhp->ox_id = 0xffff;
+	fhp->rx_id = 0xffff;
+	fhp->ro = 0;
+	return (fcalpkt);
+fail:
+	socal_packet_free(fcalpkt);
+	if (privp) {
+		if (privp->cmd_handle) {
+			if (cmd_bound)
+				(void) ddi_dma_unbind_handle(privp->cmd_handle);
+			ddi_dma_free_handle(&privp->cmd_handle);
+		}
+		if (privp->cmd)
+			ddi_dma_mem_free(&privp->cmd_acchandle);
+		if (privp->rsp_handle) {
+			if (rsp_bound)
+				(void) ddi_dma_unbind_handle(privp->rsp_handle);
+			ddi_dma_free_handle(&privp->rsp_handle);
+		}
+		if (privp->rsp)
+			ddi_dma_mem_free(&privp->rsp_acchandle);
+
+		kmem_free(privp, sizeof (*privp));
+	}
+	return (NULL);
+}
+
+void
+socal_els_free(socal_priv_cmd_t *privp)
+{
+	fcal_packet_t		*fcalpkt;
+
+	if (privp)
+		fcalpkt = (fcal_packet_t *)privp->fapktp;
+	else
+		return;
+
+	(void) ddi_dma_unbind_handle(privp->cmd_handle);
+	ddi_dma_free_handle(&privp->cmd_handle);
+	ddi_dma_mem_free(&privp->cmd_acchandle);
+
+	if (privp->rsp_handle) {
+		(void) ddi_dma_unbind_handle(privp->rsp_handle);
+		ddi_dma_free_handle(&privp->rsp_handle);
+	}
+	if (privp->rsp)
+		ddi_dma_mem_free(&privp->rsp_acchandle);
+
+	kmem_free(privp, sizeof (*privp));
+	if (fcalpkt != NULL)
+		socal_packet_free(fcalpkt);
+}
+
+void
+socal_lbf_free(socal_priv_cmd_t *privp)
+{
+	fcal_packet_t		*fcalpkt;
+
+	if (privp)
+		fcalpkt = (fcal_packet_t *)privp->fapktp;
+	else
+		return;
+
+	(void) ddi_dma_unbind_handle(privp->cmd_handle);
+	ddi_dma_free_handle(&privp->cmd_handle);
+	ddi_dma_mem_free(&privp->cmd_acchandle);
+
+	if (privp->rsp_handle) {
+		(void) ddi_dma_unbind_handle(privp->rsp_handle);
+		ddi_dma_free_handle(&privp->rsp_handle);
+	}
+
+	if (privp->rsp)
+		ddi_dma_mem_free(&privp->rsp_acchandle);
+
+	kmem_free(privp, sizeof (*privp));
+	if (fcalpkt != NULL)
+		socal_packet_free(fcalpkt);
+}
+
+static int
+socal_getmap(socal_state_t *socalp, uint32_t port, caddr_t arg,
+	uint32_t polled, int flags)
+{
+	ddi_dma_cookie_t	dcookie;
+	ddi_dma_handle_t	dhandle = NULL;
+	ddi_acc_handle_t	acchandle;
+	size_t			real_len, i;
+	uint_t			ccount;
+	fcal_lilp_map_t		*buf = NULL;
+	int			retval, bound = 0;
+	socal_port_t		*port_statep;
+
+	port_statep = &socalp->port_state[port];
+
+	if (port_statep->sp_lilpmap_valid) {
+
+	    buf = &port_statep->sp_lilpmap; /* give from cache */
+
+	    if (arg) {
+		if (ddi_copyout(buf, (caddr_t)arg,
+		    sizeof (struct lilpmap), flags) == -1)
+			return (-1);
+	    }
+
+	    return (buf->lilp_myalpa);
+	}
+
+	if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
+		DDI_DMA_DONTWAIT, NULL, &dhandle) != DDI_SUCCESS)
+		goto getmap_fail;
+
+	i = sizeof (struct fcal_lilp_map);
+
+	if (ddi_dma_mem_alloc(dhandle, i, &socal_acc_attr,
+	    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
+	    (caddr_t *)&buf, &real_len, &acchandle) != DDI_SUCCESS)
+		goto getmap_fail;
+
+	if (real_len < i)
+		goto getmap_fail;
+
+	if (ddi_dma_addr_bind_handle(dhandle, (struct as *)NULL,
+	    (caddr_t)buf, i, DDI_DMA_READ | DDI_DMA_CONSISTENT,
+	    DDI_DMA_DONTWAIT, NULL, &dcookie, &ccount) != DDI_DMA_MAPPED)
+		goto getmap_fail;
+
+	bound = 1;
+	if (ccount != 1)
+		goto getmap_fail;
+
+	retval = socal_lilp_map((void *)socalp, port,
+	    (uint32_t)dcookie.dmac_address, polled);
+
+	(void) ddi_dma_sync(dhandle, 0, 0, DDI_DMA_SYNC_FORKERNEL);
+
+	if (retval == FCAL_SUCCESS) {
+	    bcopy(buf, &port_statep->sp_lilpmap, sizeof (fcal_lilp_map_t));
+
+	    mutex_enter(&port_statep->sp_mtx);
+	    port_statep->sp_src_id = buf->lilp_myalpa;
+	    port_statep->sp_lilpmap_valid = 1; /* cached */
+	    mutex_exit(&port_statep->sp_mtx);
+
+	    if (arg) {
+		if (ddi_copyout(buf, (caddr_t)arg,
+		    sizeof (struct lilpmap), flags) == -1)
+			goto getmap_fail;
+	    }
+
+	    retval = buf->lilp_myalpa;
+	}
+	else
+		retval = -1;
+
+	(void) ddi_dma_unbind_handle(dhandle);
+	ddi_dma_mem_free(&acchandle);
+	ddi_dma_free_handle(&dhandle);
+	return (retval);
+
+getmap_fail:
+	if (dhandle) {
+		if (bound)
+			(void) ddi_dma_unbind_handle(dhandle);
+		ddi_dma_free_handle(&dhandle);
+	}
+	if (buf)
+		ddi_dma_mem_free(&acchandle);
+	return (-1);
+}
+
+static	void
+socal_wcopy(uint_t *h_src, uint_t *h_dest, int len)
+{
+	int	i;
+	for (i = 0; i < len/4; i++) {
+		*h_dest++ = *h_src++;
+	}
+}
+
+static void
+socal_flush_overflowq(socal_state_t *socalp, int port, int q_no)
+{
+	socal_kcq_t	*kcq;
+	fcal_packet_t	*fpkt1, *fpkt2, *head = NULL, *tmp;
+
+	kcq = &socalp->request[q_no];
+	mutex_enter(&kcq->skc_mtx);
+	fpkt2 = kcq->skc_overflowh;
+	fpkt1 = NULL;
+	while (fpkt2 != NULL) {
+		if ((((soc_request_t *)&fpkt2->fcal_socal_request)
+		    ->sr_soc_hdr.sh_flags & SOC_PORT_B) == port) {
+			if (fpkt1 == NULL)
+				kcq->skc_overflowh = fpkt2->fcal_pkt_next;
+			else {
+				fpkt1->fcal_pkt_next = fpkt2->fcal_pkt_next;
+				if (kcq->skc_overflowt == fpkt2)
+					kcq->skc_overflowt = fpkt1;
+			}
+			tmp = fpkt2->fcal_pkt_next;
+			fpkt2->fcal_pkt_next = head;
+			head = fpkt2;
+			fpkt2 = tmp;
+			SOCAL_ID_FREE(head->fcal_socal_request.
+				sr_soc_hdr.sh_request_token);
+		} else {
+			fpkt1 = fpkt2;
+			fpkt2 = fpkt2->fcal_pkt_next;
+		}
+	}
+	mutex_exit(&kcq->skc_mtx);
+	fpkt2 = head;
+	while (fpkt2 != NULL) {
+		fpkt2->fcal_pkt_status = FCAL_STATUS_ERR_OFFLINE;
+		fpkt2->fcal_cmd_state |= FCAL_CMD_COMPLETE;
+		fpkt2->fcal_pkt_flags |= FCFLAG_COMPLETE;
+		tmp = fpkt2->fcal_pkt_next;
+		if (fpkt2->fcal_pkt_comp != NULL)
+			(*fpkt2->fcal_pkt_comp)(fpkt2);
+		fpkt2 = tmp;
+	}
+}
+
+static void
+socal_deferred_intr(void *arg)
+{
+	socal_kcq_t	*kcq = (socal_kcq_t *)arg;
+	socal_state_t	*socalp = kcq->skc_socalp;
+
+	ASSERT((socalp != NULL));
+
+	mutex_enter(&kcq->skc_mtx);
+
+	if ((kcq->skc_out != kcq->skc_saved_out) ||
+	    (kcq->skc_seqno != kcq->skc_saved_seqno)) {
+		kcq->deferred_intr_timeoutid = 0;
+		mutex_exit(&kcq->skc_mtx);
+		return;
+	}
+
+	if (socalp->socal_on_intr) {
+		mutex_exit(&kcq->skc_mtx);
+		kcq->deferred_intr_timeoutid = timeout(socal_deferred_intr,
+					(caddr_t)kcq, drv_usectohz(10000));
+		return;
+	}
+
+	kcq->deferred_intr_timeoutid = 0;
+	mutex_exit(&kcq->skc_mtx);
+	socal_intr_solicited(socalp, 0);
+}
+
+static void
+socal_take_core(void *arg)
+{
+	socal_state_t	*socalp = (socal_state_t *)arg;
+	int i, instance;
+
+	socal_disable(socalp);
+	for (i = 0; i < SOCAL_N_CQS; i++) {
+		mutex_enter(&socalp->request[i].skc_mtx);
+		mutex_enter(&socalp->response[i].skc_mtx);
+	}
+	for (i = 0; i < 4; i++) {
+		socalp->socal_rp->socal_cr.w &=
+				~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
+		socalp->socal_rp->socal_cr.w |= i<<24;
+		(void) bcopy((caddr_t)socalp->socal_xrp,
+			(caddr_t)&socal_xrambuf[i*0x10000], 0x10000);
+	}
+	for (i = 3; i >= 0; i--) {
+		mutex_exit(&socalp->request[i].skc_mtx);
+		mutex_exit(&socalp->response[i].skc_mtx);
+	}
+	instance = ddi_get_instance(socalp->dip);
+	cmn_err(CE_PANIC,
+		"socal take core (socal instance %d)", instance);
+}
+
+/*
+ * Preset AL_PA in hardware, if is told.
+ */
+static void
+socal_fix_harda(socal_state_t *socalp, int port)
+{
+	socal_port_t	*portp = &socalp->port_state[port];
+	uint_t		*xrp = (uint_t *)socalp->socal_xrp;
+	uint_t		accum, harda;
+
+	harda = portp->sp_hard_alpa;
+	accum = xrp[SOCAL_XRAM_PORTA_HRDA/4];
+	if (port == 0) {
+		accum &= 0x00FFFFFF;
+		accum |= ((harda & 0xFF) << 24);
+	} else {
+		accum &= 0xFF00FFFF;
+		accum |= ((harda & 0xFF) << 16);
+	}
+	xrp[SOCAL_XRAM_PORTA_HRDA/4] = accum;
+}
+
+/*
+ * Target-Mode attach function
+ */
+fcal_transport_t *
+socal_sftm_attach(dev_t dev, int loop_id)
+{
+	int 		instance = getminor(dev) / 2;
+	int		port = getminor(dev) % 2;
+	int		hard_alpa;
+	char		*name;
+	socal_state_t	*socalp;
+
+	/*
+	 * If the device is not a "socal" device, return
+	 */
+	if ((name = ddi_major_to_name(getmajor(dev))) == NULL ||
+	    strcmp(name, "socal") != 0)
+		return (NULL);
+
+	/*
+	 * If no soft state structure, return
+	 */
+	socalp = ddi_get_soft_state(socal_soft_state_p, instance);
+	if (socalp == NULL)
+		return (NULL);
+
+	/*
+	 * If the port is already attached, return
+	 */
+	if (socalp->port_state[port].sp_status & PORT_CHILD_INIT)
+		return (NULL);
+
+	if (loop_id < 0 || loop_id > 126)
+		return (NULL);
+
+	/* if this instance is detaching, don't attach */
+	mutex_enter(&socalp->board_mtx);
+	mutex_enter(&socalp->port_state[port].sp_mtx);
+	if (socalp->socal_busy < 0) {
+		mutex_exit(&socalp->port_state[port].sp_mtx);
+		mutex_exit(&socalp->board_mtx);
+		return (NULL);
+	}
+	socalp->socal_busy++;
+	socalp->port_state[port].sp_status |= PORT_CHILD_INIT;
+	mutex_exit(&socalp->port_state[port].sp_mtx);
+	mutex_exit(&socalp->board_mtx);
+
+	/*
+	 * Since we keep the Hard Loop-id in two config files, warn the
+	 * user if they don't match.
+	 */
+	hard_alpa = socal_switch_to_alpa[loop_id];
+	if (hard_alpa != socalp->port_state[port].sp_hard_alpa) {
+		socalp->port_state[port].sp_hard_alpa = hard_alpa;
+		cmn_err(CE_WARN, "socal%d: Hard Loop-id mismatch - "
+		    "using Loop-id %d",
+		    instance, loop_id);
+	}
+
+	return (socalp->port_state[port].sp_transport);
+}
+
+
+/*
+ * Target-Mode detach function
+ */
+int
+socal_sftm_detach(socal_state_t *socalp, int port)
+{
+	mutex_enter(&socalp->board_mtx);
+	socalp->socal_busy--;
+	socalp->port_state[port].sp_status &= ~PORT_CHILD_INIT;
+	mutex_exit(&socalp->board_mtx);
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun/io/socal_ucode.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,16420 @@
+/*
+ * 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 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+
+/* This file was once generated automatically... */
+
+uint32_t	socal_ucode[] = {
+	0xa106a000u,
+	0xf011f091u,
+	0x0u,
+	0x9e0eu,
+	0xad7cacc0u,
+	0xf05d00ffu,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x20060000u,
+	0xc8000800u,
+	0x1000002u,
+	0x2710u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x80000800u,
+	0xc0000800u,
+	0x1007fffu,
+	0x10000u,
+	0x80000000u,
+	0x800u,
+	0x1000000u,
+	0x10000u,
+	0x12468u,
+	0x0u,
+	0x3af1fcd9u,
+	0x40282329u,
+	0x54687520u,
+	0x4d617920u,
+	0x20332031u,
+	0x383a3530u,
+	0x3a333320u,
+	0x32303031u,
+	0xa000000u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x1u,
+	0x0u,
+	0x0u,
+	0xfefe0800u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0xc405000u,
+	0x46000a00u,
+	0x4001a100u,
+	0xa00000abu,
+	0x1cdc030u,
+	0xf0914701u,
+	0xaf01aefeu,
+	0xc0f5100u,
+	0xc031c533u,
+	0xca35cf37u,
+	0x403334cu,
+	0xad08ac0au,
+	0xf05dc031u,
+	0x9f74e1f3u,
+	0xf0910c00u,
+	0x57004000u,
+	0xa100a056u,
+	0xc020f091u,
+	0x1268c171u,
+	0xc030f091u,
+	0x100a4000u,
+	0xa102a0fcu,
+	0xc0d0f091u,
+	0xad79ac18u,
+	0xf05df091u,
+	0xad7eac1eu,
+	0xf05df091u,
+	0xad79acdcu,
+	0xf05df091u,
+	0xad2aac54u,
+	0xf05df091u,
+	0xad5aac50u,
+	0xf05df091u,
+	0xad5dacd2u,
+	0xf05df091u,
+	0xad5fac00u,
+	0xf05df091u,
+	0x67804000u,
+	0xc075700u,
+	0x4000a100u,
+	0xa0500000u,
+	0x101c030u,
+	0xf0911006u,
+	0xad07ac84u,
+	0xc05cf091u,
+	0x8038e10fu,
+	0xf091ad07u,
+	0xac9cf05du,
+	0xf0910c04u,
+	0x57004000u,
+	0xa19fa028u,
+	0xc020f091u,
+	0xdf71c030u,
+	0xf091e193u,
+	0xf0910000u,
+	0x132c030u,
+	0xf091ad7fu,
+	0xac24f05du,
+	0xf0914000u,
+	0xa107b00eu,
+	0xc020f239u,
+	0xf053f091u,
+	0xad06ac98u,
+	0xf01d4000u,
+	0x7f00000u,
+	0x7e00000u,
+	0x76800000u,
+	0x76700000u,
+	0x9300000u,
+	0x9200000u,
+	0x12900000u,
+	0x12800000u,
+	0x29a00000u,
+	0x29900000u,
+	0x5a700000u,
+	0x2a300000u,
+	0x0u,
+	0x0u,
+	0x7c00000u,
+	0x7d00000u,
+	0x47700000u,
+	0x47600000u,
+	0x7cc00020u,
+	0x7cc00020u,
+	0x7cc00020u,
+	0x7cc00020u,
+	0x7cc00020u,
+	0x7cc00020u,
+	0x7cc00020u,
+	0x7cc00020u,
+	0x7cc00020u,
+	0x7cc00020u,
+	0x7cc00020u,
+	0x7cc00020u,
+	0x7cc00020u,
+	0x7800000u,
+	0xf0d16780u,
+	0x0u,
+	0xad07ac86u,
+	0xc02cf091u,
+	0xc171c03cu,
+	0xf091f0d1u,
+	0xf0910000u,
+	0xad07ac9au,
+	0xc02cf091u,
+	0xc171c03cu,
+	0xf091ad7cu,
+	0xacc0f05du,
+	0xfef0d1u,
+	0xf091f0d1u,
+	0x67800000u,
+	0x0u,
+	0xf0d1f091u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0xf0d1f091u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0xf0d1f091u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x21106u,
+	0xad7cacc0u,
+	0x80a8f19du,
+	0x26f0d1u,
+	0xf091f091u,
+	0xf091f0d1u,
+	0xf091c031u,
+	0xc5332e00u,
+	0x2e042e08u,
+	0x2e0c2e10u,
+	0x2e142e18u,
+	0x2e1c2e20u,
+	0x2e242e28u,
+	0x2e2c2e30u,
+	0x2e342e38u,
+	0xf0d12e3cu,
+	0x2a0ce028u,
+	0xf091f0a8u,
+	0xf091ad08u,
+	0xac8a96b1u,
+	0xf19dcf33u,
+	0xf19d2918u,
+	0xf631c1a6u,
+	0xf091c021u,
+	0xf11df031u,
+	0x2a08e920u,
+	0xf091f9e0u,
+	0xf09196b1u,
+	0xf19dcf33u,
+	0xf19dad12u,
+	0xac10f05du,
+	0xf0910017u,
+	0x1a6c438u,
+	0xf091d4b8u,
+	0xf091e707u,
+	0xf091e07bu,
+	0xf091ad12u,
+	0xac9af01du,
+	0xf0912a0cu,
+	0x8171e191u,
+	0x10f8da1u,
+	0xc173e189u,
+	0xad09acb0u,
+	0xf01df091u,
+	0x4000a1a2u,
+	0xa0aec020u,
+	0xf091c021u,
+	0xe109ad7cu,
+	0xacc0f05du,
+	0x10014u,
+	0x14a0200u,
+	0x301c438u,
+	0xf091d4b8u,
+	0xf091f0d1u,
+	0xf091d188u,
+	0xf09184a1u,
+	0xe113f091u,
+	0x1301c2u,
+	0xc438f091u,
+	0xd4b8f091u,
+	0xf0d1f091u,
+	0xad09acb0u,
+	0x280801f0u,
+	0x80a80120u,
+	0x84b0f11du,
+	0x18084b0u,
+	0xf11d01c0u,
+	0x84b0f11du,
+	0xf0910014u,
+	0x14a0200u,
+	0x316c438u,
+	0xf091d4b8u,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x0u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8702301u,
+	0xe0110b01u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8302300u,
+	0xb000001u,
+	0xc1d8f091u,
+	0x2606c328u,
+	0xf0910600u,
+	0x708df77u,
+	0xe1fdf091u,
+	0x2204211cu,
+	0x34682008u,
+	0xf091e507u,
+	0xf091e07bu,
+	0xf0912804u,
+	0x15884b0u,
+	0xe1910013u,
+	0x146c438u,
+	0xf091d4b8u,
+	0xf091f0d1u,
+	0xf0912a0cu,
+	0xf8da0u,
+	0x8da98daau,
+	0x8173e129u,
+	0x2a08e028u,
+	0xf091f0a8u,
+	0xf0919224u,
+	0xe11396b1u,
+	0xe187cf33u,
+	0xe1138030u,
+	0xad08ac30u,
+	0xf01df091u,
+	0xad08accau,
+	0xf01df091u,
+	0x2891873au,
+	0xe1852918u,
+	0x291af631u,
+	0xca38f091u,
+	0xcd38f091u,
+	0xc171ad0du,
+	0xac78f19du,
+	0xf0912808u,
+	0x1f084a8u,
+	0x2c08931u,
+	0xad0aac16u,
+	0xf19df091u,
+	0x1c088b0u,
+	0xe11d01c1u,
+	0x88b0e117u,
+	0xf0910014u,
+	0x14a0200u,
+	0x315c438u,
+	0xf091d4b8u,
+	0xf091f0d1u,
+	0xf0910014u,
+	0x14a0200u,
+	0x314c438u,
+	0xf091d4b8u,
+	0xf091f0d1u,
+	0xf0912a08u,
+	0x2a8c96b1u,
+	0xe18dcf33u,
+	0xe189f091u,
+	0xad0cac5eu,
+	0xf01d2808u,
+	0x10584b0u,
+	0xad0fac06u,
+	0xf11d0701u,
+	0x18184b0u,
+	0xad0cac7au,
+	0xf11df091u,
+	0x281101e0u,
+	0x88a80120u,
+	0x8931e117u,
+	0xf0910014u,
+	0x14a0200u,
+	0x30ac438u,
+	0xf091d4b8u,
+	0xf091f0d1u,
+	0xf091ad3bu,
+	0xac3af05du,
+	0xf091a1a1u,
+	0xa0e0ea87u,
+	0x4000a1a1u,
+	0xa0d0d081u,
+	0xc020f091u,
+	0xad0aace4u,
+	0xc021f11du,
+	0xf631b076u,
+	0x112u,
+	0xd081ad0au,
+	0xacd8290du,
+	0xd160f091u,
+	0xc131f19du,
+	0xf091280eu,
+	0xe180f091u,
+	0x8130f19du,
+	0xf0912918u,
+	0xd420f091u,
+	0xc131f19du,
+	0xf0912814u,
+	0xe300f091u,
+	0x8130f19du,
+	0xf091f137u,
+	0xca38f091u,
+	0xcd38f091u,
+	0xad0bacf0u,
+	0xf01df091u,
+	0xad0aac7cu,
+	0xb076f131u,
+	0xf01df091u,
+	0xad7aac30u,
+	0xf05df091u,
+	0xca38f091u,
+	0xcd38f091u,
+	0xc021e197u,
+	0xf6310014u,
+	0x14a0200u,
+	0x318c438u,
+	0xf091d4b8u,
+	0xf091f0d1u,
+	0xf091b276u,
+	0x21402043u,
+	0xf091c031u,
+	0x2000340u,
+	0xb076d181u,
+	0xc730f091u,
+	0xea850121u,
+	0x101d096u,
+	0xf0912804u,
+	0xcd16f091u,
+	0x2a8c010fu,
+	0x80a80106u,
+	0x84b0e131u,
+	0x4030105u,
+	0x84b0e129u,
+	0x4020107u,
+	0x84b0e121u,
+	0x401f137u,
+	0xad7aac96u,
+	0xf05df091u,
+	0x14014au,
+	0x2000306u,
+	0xc438f091u,
+	0xd4b8f091u,
+	0xf0d1f091u,
+	0xb276f4a3u,
+	0xca28f091u,
+	0x2d1a2208u,
+	0x21182003u,
+	0xf091ad4eu,
+	0xacf6f05du,
+	0xf091c136u,
+	0xf931e121u,
+	0xf0911468u,
+	0xf137ad7au,
+	0xac96f05du,
+	0xf0910014u,
+	0x14a126cu,
+	0xc438f091u,
+	0xd4b8f091u,
+	0xf0d1f091u,
+	0xcea8f091u,
+	0xc171ceb8u,
+	0xf091ad39u,
+	0xac8af05du,
+	0xf091ad0cu,
+	0xac12c021u,
+	0xf11df091u,
+	0xad3bac3au,
+	0xf05df091u,
+	0x4000a1a1u,
+	0xa0e0ea87u,
+	0x4000a1a1u,
+	0xa0d0d081u,
+	0xc020f091u,
+	0xc036f091u,
+	0xc030f937u,
+	0xad12ac10u,
+	0xf05df091u,
+	0xad3aac74u,
+	0xf05df091u,
+	0x1270001eu,
+	0x17ec438u,
+	0xf091d4b8u,
+	0xf091f0d1u,
+	0xf091c031u,
+	0xc533ca35u,
+	0x600073cu,
+	0xb278f623u,
+	0x8d4f091u,
+	0x28080122u,
+	0x84b0ad0cu,
+	0xac4ef19du,
+	0xf091001au,
+	0x1aac438u,
+	0xf091d4b8u,
+	0xf091e707u,
+	0xf091e07bu,
+	0xf091ad12u,
+	0xac9af01du,
+	0xf091001bu,
+	0x1c2c438u,
+	0xf091d4b8u,
+	0xf091f0d1u,
+	0xf0910017u,
+	0x154c438u,
+	0xf091d4b8u,
+	0xf091e707u,
+	0xf091e07bu,
+	0xf091ad12u,
+	0xac9af01du,
+	0xf0912918u,
+	0x4302a700u,
+	0xa6000604u,
+	0x7000400u,
+	0x580c086u,
+	0xf0911148u,
+	0x8038e12bu,
+	0x12080a8u,
+	0xea850120u,
+	0x10080b0u,
+	0xe19df091u,
+	0xc1a6f091u,
+	0xc021e193u,
+	0xf091c8a6u,
+	0xf0912958u,
+	0xc131ad0du,
+	0xac28f11du,
+	0xf091df77u,
+	0xe111de87u,
+	0xad0cac8au,
+	0xf19d1043u,
+	0x8170f01du,
+	0x5348ad7au,
+	0xac30f05du,
+	0xf091c021u,
+	0xad0dac5cu,
+	0xf11df631u,
+	0xb2762140u,
+	0x2043f091u,
+	0x2804cd16u,
+	0xf0918170u,
+	0x10380a8u,
+	0x2a8c1448u,
+	0xad4eacf6u,
+	0xf05df091u,
+	0xc136f931u,
+	0xad0dac52u,
+	0xf19df091u,
+	0xea850121u,
+	0x101d096u,
+	0xf091cea8u,
+	0xf091c171u,
+	0xceb8f091u,
+	0xe005f091u,
+	0xf137b276u,
+	0xf4a32208u,
+	0x21182003u,
+	0xf0910018u,
+	0x14ac438u,
+	0xf091d4b8u,
+	0xf091e707u,
+	0xf091e07bu,
+	0xf091ad12u,
+	0xac9af01du,
+	0xf091f137u,
+	0xad7aac96u,
+	0xf05df091u,
+	0x1301c2u,
+	0xc438f091u,
+	0xd4b8f091u,
+	0xe707f091u,
+	0xe07bf091u,
+	0xad12ac9au,
+	0xf01df091u,
+	0xf137ad0fu,
+	0xac06037cu,
+	0x8da9f19du,
+	0xc139f11du,
+	0xf091c086u,
+	0xf0918038u,
+	0xf11d0702u,
+	0xc1a6f091u,
+	0xc021e10bu,
+	0xc439ad0eu,
+	0xacccf11du,
+	0xf4312888u,
+	0x3048db2u,
+	0xe1090302u,
+	0x8db2f19du,
+	0x7096477u,
+	0x650066f0u,
+	0x22082118u,
+	0xb276f4a3u,
+	0x2007f091u,
+	0xe607f091u,
+	0xf01df091u,
+	0x4100a312u,
+	0xa210f053u,
+	0xf0912804u,
+	0xcd16f091u,
+	0xe086f091u,
+	0x843af19du,
+	0x70ac4bdu,
+	0xe10fad0eu,
+	0xac50e326u,
+	0xf091f3a6u,
+	0xf091f01du,
+	0xad39ac8au,
+	0xf05df091u,
+	0xc021e189u,
+	0xad0fac06u,
+	0xf01d070bu,
+	0xad3aac74u,
+	0xf05df091u,
+	0x1270001eu,
+	0x17ec438u,
+	0xf091d4b8u,
+	0xf091f0d1u,
+	0xf091b068u,
+	0x110u,
+	0xd8a7ca28u,
+	0xf6391074u,
+	0xc1b6f091u,
+	0xb2760000u,
+	0x108d483u,
+	0x107c08d4u,
+	0xf091c031u,
+	0xce36f091u,
+	0x2a1ccd17u,
+	0xc81de297u,
+	0xf0910014u,
+	0x14a0200u,
+	0x310c438u,
+	0xf091d4b8u,
+	0xf091f0d1u,
+	0xf091d325u,
+	0xe169ca25u,
+	0x500e10bu,
+	0x408d315u,
+	0xe205f091u,
+	0x146e2daau,
+	0xe226f091u,
+	0xf2a6f091u,
+	0xcd07c80du,
+	0x2eac0011u,
+	0x166f337u,
+	0x2e322d34u,
+	0xc328f091u,
+	0x200031cu,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106aad29u,
+	0xac0ef05du,
+	0x2d281270u,
+	0x1e017eu,
+	0xc438f091u,
+	0xd4b8f091u,
+	0xf0d1f091u,
+	0xad0fac06u,
+	0xcf44f091u,
+	0x10184b0u,
+	0xf11d070au,
+	0xc924f091u,
+	0xd9a4f091u,
+	0x2a8c96b1u,
+	0xf19dcf33u,
+	0xf19df091u,
+	0x2804cd16u,
+	0xf091cd24u,
+	0xf0912958u,
+	0xc531ad0fu,
+	0xac32f11du,
+	0xf0919b36u,
+	0x4000a1a2u,
+	0xa0aec020u,
+	0xf091c021u,
+	0xe109ad7cu,
+	0xacc0f05du,
+	0x40014u,
+	0x14a0200u,
+	0x311c438u,
+	0xf091d4b8u,
+	0xf091f0d1u,
+	0xf091ad12u,
+	0xac10f05du,
+	0xf0912808u,
+	0x1f084a8u,
+	0x2c08931u,
+	0xad0facd2u,
+	0xf19df091u,
+	0xe086f091u,
+	0x843ae18bu,
+	0xf091ad0fu,
+	0xac06f01du,
+	0xf091ad0fu,
+	0xacba010fu,
+	0x88a80015u,
+	0x1e4f11du,
+	0x9f720015u,
+	0x1eaf11du,
+	0x9f720014u,
+	0x1dcf11du,
+	0x9f720014u,
+	0x1e4f11du,
+	0x9f720014u,
+	0x1ecf11du,
+	0x9f720014u,
+	0x1f4f11du,
+	0x9f720014u,
+	0x1f4f11du,
+	0x9f720016u,
+	0x174f11du,
+	0xf0910014u,
+	0x14a0200u,
+	0x308c438u,
+	0xf091d4b8u,
+	0xf091f0d1u,
+	0xf091c438u,
+	0xf091d4b8u,
+	0xf091e707u,
+	0xf091e07bu,
+	0xf091ad12u,
+	0xac9af01du,
+	0xf091ad0fu,
+	0xac062808u,
+	0x1f084a8u,
+	0xe1898338u,
+	0xe135f091u,
+	0xf01d0180u,
+	0x84b0e12bu,
+	0x18184b0u,
+	0xe1250182u,
+	0x84b0e11fu,
+	0x18484b0u,
+	0xe1190185u,
+	0x84b0e113u,
+	0x12284b0u,
+	0xe10d0123u,
+	0x84b0e107u,
+	0xf091f01du,
+	0xf091e086u,
+	0xf0910048u,
+	0x8128e11fu,
+	0xf0910019u,
+	0x108c438u,
+	0xf091d4b8u,
+	0xf091e707u,
+	0xf091e07bu,
+	0xf091ad12u,
+	0xac9af01du,
+	0xf091843au,
+	0xf19d0703u,
+	0x1052808u,
+	0x84b0ad10u,
+	0xac76f19du,
+	0xf0912891u,
+	0x873af11du,
+	0xf0910016u,
+	0x178c438u,
+	0xf091d4b8u,
+	0xf091e707u,
+	0xf091e07bu,
+	0xf091ad12u,
+	0xac9af01du,
+	0xf091ff44u,
+	0xf0910204u,
+	0x81b2e10bu,
+	0x20581b2u,
+	0x81b2e197u,
+	0xf0912808u,
+	0x10784b0u,
+	0xe13b0501u,
+	0x20481b2u,
+	0xe1b30502u,
+	0xf01d0202u,
+	0x81b2e19fu,
+	0xf091b276u,
+	0x51430000u,
+	0x160d483u,
+	0x2a1cf0a2u,
+	0xf091e022u,
+	0xf091c713u,
+	0xc219e00fu,
+	0x5000203u,
+	0x81b2e185u,
+	0x5000501u,
+	0x2a1c2e34u,
+	0xb278f623u,
+	0x8d4f091u,
+	0xad11ac7au,
+	0xf05df091u,
+	0xe1950014u,
+	0x14a0200u,
+	0x310c438u,
+	0xf091d4b8u,
+	0xf091f0d1u,
+	0xf0911074u,
+	0x12762e2cu,
+	0x2daae7b8u,
+	0xf091c328u,
+	0xf0910200u,
+	0x31cc101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0x2d280011u,
+	0x1662d32u,
+	0xad29ac0eu,
+	0xca28f091u,
+	0xf05d2d34u,
+	0x28080123u,
+	0x84b0ad11u,
+	0xac56f19du,
+	0x1270001fu,
+	0x148c438u,
+	0xf091d4b8u,
+	0xf091e707u,
+	0xf091e07bu,
+	0xf091ad12u,
+	0xac9af01du,
+	0xf0910021u,
+	0x12cc438u,
+	0xf091d4b8u,
+	0xf091f0d1u,
+	0xf0918922u,
+	0xe18d0104u,
+	0xc1c8f091u,
+	0x80a0c1d8u,
+	0xf091f0d1u,
+	0xf091c1c4u,
+	0xf0918290u,
+	0x9f70ad12u,
+	0xac0cf41du,
+	0x1038691u,
+	0xb274f323u,
+	0x9234cb45u,
+	0xd6832d2au,
+	0x8c4f091u,
+	0x2e2c2eb0u,
+	0x2a34cd17u,
+	0xc81dad11u,
+	0xacd8f41du,
+	0xf091e187u,
+	0xcf27f11du,
+	0xf0912eb0u,
+	0x2aacdd07u,
+	0xd80dc031u,
+	0x2080300u,
+	0x2ab0cd17u,
+	0xc81de405u,
+	0x29b2146au,
+	0x101u,
+	0xf0d1c021u,
+	0x2ab0c713u,
+	0xc2192e34u,
+	0xad12ac0cu,
+	0x292a9f70u,
+	0xf41d9f71u,
+	0xad11ac96u,
+	0xf19df223u,
+	0xdfa4f091u,
+	0xf433c523u,
+	0xf11d0106u,
+	0xb274f323u,
+	0xad11ac96u,
+	0xf01df091u,
+	0xf0d1c031u,
+	0x2916c446u,
+	0xf0911148u,
+	0x8138e10fu,
+	0x1fd80a8u,
+	0xc456f091u,
+	0x2916cbb6u,
+	0xf0912811u,
+	0x8338e187u,
+	0xf091f0d1u,
+	0xf0918538u,
+	0xe111f335u,
+	0xc523e10bu,
+	0x843be187u,
+	0x295addb4u,
+	0xf0912916u,
+	0xc171cb36u,
+	0xf091c406u,
+	0xf0918020u,
+	0xe1910200u,
+	0x312b276u,
+	0xd5832208u,
+	0x21182003u,
+	0xf091f0d1u,
+	0xf0910002u,
+	0x3010000u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8702301u,
+	0xe0110b01u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8302300u,
+	0xb00c1c8u,
+	0xf0910102u,
+	0x80a0c1d8u,
+	0xf0912604u,
+	0xcc28f091u,
+	0xdca8f091u,
+	0xc173c079u,
+	0xcc38f091u,
+	0xdcb8f091u,
+	0xad12acfcu,
+	0xf99d8030u,
+	0x110c0207u,
+	0x85298541u,
+	0x4000a112u,
+	0xa0ded081u,
+	0xc020f091u,
+	0xbc68f01du,
+	0xf0911346u,
+	0x13461346u,
+	0x12ee12eeu,
+	0x134612eeu,
+	0x1346c428u,
+	0xf091bc68u,
+	0xc4a8f091u,
+	0xf01df091u,
+	0x111f100du,
+	0x8238e10fu,
+	0xf0916304u,
+	0xf091ad13u,
+	0xac46f01du,
+	0xf091103au,
+	0x22002104u,
+	0x34682008u,
+	0xf091e507u,
+	0xf091e07bu,
+	0xf0912900u,
+	0x29022803u,
+	0x8038e117u,
+	0xf0910000u,
+	0x114ad47u,
+	0xac2af05du,
+	0xf091ad13u,
+	0xac52f01du,
+	0xf0910000u,
+	0x10cad47u,
+	0xac2af05du,
+	0xf091ca28u,
+	0xf091c021u,
+	0xad13acc2u,
+	0xf11df631u,
+	0xc446f091u,
+	0x10480a0u,
+	0xc456f091u,
+	0xc1c8f091u,
+	0x8238ad13u,
+	0xac8af19du,
+	0xf091c4a8u,
+	0xf091b468u,
+	0x42000023u,
+	0x106c2b4u,
+	0xf0910000u,
+	0xc1d8f091u,
+	0x103a0200u,
+	0x304c101u,
+	0xc1210200u,
+	0x300c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0xc338f091u,
+	0xc888f091u,
+	0x9f70c898u,
+	0xf0916310u,
+	0x2605f0d1u,
+	0xf091ad28u,
+	0xacf4f05du,
+	0xf0910000u,
+	0xc1d8f091u,
+	0x103a0200u,
+	0x304c101u,
+	0xc1210200u,
+	0x300c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0xc338f091u,
+	0xc888f091u,
+	0x9f70c898u,
+	0xf0916310u,
+	0x2605f0d1u,
+	0xf091c328u,
+	0xf0912204u,
+	0x211c3468u,
+	0x2008f091u,
+	0xe507f091u,
+	0xe07bf091u,
+	0xf139c03eu,
+	0xf091ffafu,
+	0x4200a54eu,
+	0xa40203c4u,
+	0xe4a8f091u,
+	0xad14acc8u,
+	0xf05dcf37u,
+	0xea852301u,
+	0x2300f0afu,
+	0xc02ef091u,
+	0xf831ad13u,
+	0xacc2f01du,
+	0xf091c328u,
+	0xf0912204u,
+	0x211c3468u,
+	0x2008f091u,
+	0xe507f091u,
+	0xe07bf091u,
+	0x28040103u,
+	0x84a88030u,
+	0x4000a112u,
+	0xa06ed081u,
+	0xc000f091u,
+	0x103c03eu,
+	0xf09180b0u,
+	0xad13acc2u,
+	0xf11df091u,
+	0x280801c2u,
+	0x8490ad13u,
+	0xacc2f11du,
+	0x1c38490u,
+	0xf11df139u,
+	0xc03ef091u,
+	0xffaf4200u,
+	0xa54ea402u,
+	0x3c2e4a8u,
+	0xf091ad14u,
+	0xacc8f05du,
+	0xcf37ea85u,
+	0x23012300u,
+	0xf0afc02eu,
+	0xf091f831u,
+	0xad13acc2u,
+	0xf01df091u,
+	0x2e9c2844u,
+	0x784a8u,
+	0x3084a0u,
+	0xb52d04u,
+	0x9501d5u,
+	0x2000302u,
+	0xe031f091u,
+	0x2000303u,
+	0xe029f091u,
+	0x2000304u,
+	0xe009f091u,
+	0x2000305u,
+	0xf091b276u,
+	0x6000712u,
+	0xd7832208u,
+	0x21182003u,
+	0xf091ad15u,
+	0xac94f01du,
+	0xf091b276u,
+	0x6000712u,
+	0xd7832208u,
+	0x21182003u,
+	0xf0918030u,
+	0x285cc141u,
+	0x4000a115u,
+	0xa03ad081u,
+	0xc020f091u,
+	0xbc68f01du,
+	0xf0911594u,
+	0x157a157au,
+	0x157a157au,
+	0x157a157au,
+	0x157a1594u,
+	0x157a1594u,
+	0x157a157au,
+	0x157a157au,
+	0x157a1594u,
+	0x1594157au,
+	0x157a1594u,
+	0x1594157au,
+	0x157a157au,
+	0x157a1594u,
+	0x15941594u,
+	0x15941594u,
+	0x1594f139u,
+	0xc03ef091u,
+	0xffafc031u,
+	0xad7bac6eu,
+	0xf05db476u,
+	0xf0afc02eu,
+	0xf091f831u,
+	0xc126f239u,
+	0xcaa6f091u,
+	0xad4eac0au,
+	0xf05df091u,
+	0xad28acf4u,
+	0xf05df091u,
+	0xc1d8u,
+	0xf091103au,
+	0x2000304u,
+	0xc101c121u,
+	0x2000300u,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106ac338u,
+	0xf091c888u,
+	0xf0919f70u,
+	0xc898f091u,
+	0x63102605u,
+	0xf0d1f091u,
+	0x8932e00fu,
+	0x3012a1cu,
+	0xc921e187u,
+	0xf091daa6u,
+	0xf091d03eu,
+	0xf091ffafu,
+	0xc126f239u,
+	0xad4eac0au,
+	0xf05d106au,
+	0xad28acf4u,
+	0xf05df091u,
+	0xc1d8u,
+	0xf091103au,
+	0x2000304u,
+	0xc101c121u,
+	0x2000300u,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106ac338u,
+	0xf091c888u,
+	0xf0919f70u,
+	0xc898f091u,
+	0x63102605u,
+	0xf0afd02eu,
+	0xf091ca28u,
+	0xf639c086u,
+	0xf0918638u,
+	0xe19bf091u,
+	0xcaa6f091u,
+	0xc111cab6u,
+	0xf091c021u,
+	0xe18bf091u,
+	0xad24ac2cu,
+	0xf05df091u,
+	0xf0d1f091u,
+	0xf0d1f091u,
+	0xc2200u,
+	0x3148c328u,
+	0xf0910200u,
+	0x31cc101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0x34682008u,
+	0xf091e507u,
+	0xf091e07bu,
+	0xf091ca28u,
+	0xf6392a04u,
+	0x2a80b276u,
+	0xf22308d4u,
+	0xf091e9b6u,
+	0xf091fa36u,
+	0xf091c1a6u,
+	0xf039c180u,
+	0xf0910103u,
+	0x80b0ad17u,
+	0xac0cf11du,
+	0xf091f139u,
+	0xc03ef091u,
+	0xffafcd06u,
+	0xf0910103u,
+	0x84a88030u,
+	0x4000a112u,
+	0xa06ed081u,
+	0xc000f091u,
+	0x1248a100u,
+	0xa0000600u,
+	0x701ad4au,
+	0xacfcf05du,
+	0x3c0ea85u,
+	0x23012300u,
+	0xf0afc02eu,
+	0xf091f831u,
+	0xad28acf4u,
+	0xf05df091u,
+	0xc1d8u,
+	0xf091103au,
+	0x2000304u,
+	0xc101c121u,
+	0x2000300u,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106ac338u,
+	0xf091c888u,
+	0xf0919f70u,
+	0xc898f091u,
+	0x63102605u,
+	0xad24ac2cu,
+	0xf05df091u,
+	0xf0d1f091u,
+	0xad28acf4u,
+	0xf05df091u,
+	0xc1d8u,
+	0xf091103au,
+	0x2000304u,
+	0xc101c121u,
+	0x2000300u,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106ac338u,
+	0xf091c888u,
+	0xf0919f70u,
+	0xc898f091u,
+	0x63102605u,
+	0xc031cfb8u,
+	0xf0910200u,
+	0x314ad43u,
+	0xac40f05du,
+	0xf091f0d1u,
+	0xf091ad28u,
+	0xacf4f05du,
+	0xf0910000u,
+	0xc1d8f091u,
+	0x103a0200u,
+	0x304c101u,
+	0xc1210200u,
+	0x300c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0xc338f091u,
+	0xc888f091u,
+	0x9f70c898u,
+	0xf0916310u,
+	0x2605cea8u,
+	0xf091c021u,
+	0xe18bf091u,
+	0xad7cacc0u,
+	0xf05d0023u,
+	0xdf71ceb8u,
+	0xf0912303u,
+	0xad08ac0au,
+	0xf05dc031u,
+	0xc1a6f239u,
+	0x8c4f091u,
+	0x2e00c23du,
+	0xad28ac50u,
+	0xf19d104eu,
+	0x2c06c128u,
+	0xf0910200u,
+	0x342c521u,
+	0x2d44b276u,
+	0x112u,
+	0xd4832224u,
+	0x21182002u,
+	0xf091c6c6u,
+	0xf0910110u,
+	0x80a0c6d6u,
+	0xf091ad28u,
+	0xac1ef01du,
+	0x36c086u,
+	0xf09101efu,
+	0x80a80140u,
+	0x80a0c096u,
+	0xf091c1a6u,
+	0xf091c021u,
+	0xe191f031u,
+	0xcd06f091u,
+	0x81700103u,
+	0x80a8e007u,
+	0xf091c180u,
+	0xf0910103u,
+	0x80b0ad18u,
+	0xacc0f11du,
+	0xf091f139u,
+	0xc03ef091u,
+	0xffafcd06u,
+	0xf0910103u,
+	0x84a88030u,
+	0x4000a112u,
+	0xa06ed081u,
+	0xc000f091u,
+	0x1248a100u,
+	0xa0000600u,
+	0x701ad4au,
+	0xacfcf05du,
+	0x3c0ea85u,
+	0x23012300u,
+	0xf0afc02eu,
+	0xf091f831u,
+	0xad28acf4u,
+	0xf05df091u,
+	0xc1d8u,
+	0xf091103au,
+	0x2000304u,
+	0xc101c121u,
+	0x2000300u,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106ac338u,
+	0xf091c888u,
+	0xf0919f70u,
+	0xc898f091u,
+	0x63102605u,
+	0xad24ac2cu,
+	0xf05df091u,
+	0xf0d1f091u,
+	0x280801f0u,
+	0x80a80180u,
+	0x84b0ad19u,
+	0xac5af11du,
+	0xf091ad28u,
+	0xacf4f05du,
+	0xf0910000u,
+	0xc1d8f091u,
+	0x103a0200u,
+	0x304c101u,
+	0xc1210200u,
+	0x300c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0xc338f091u,
+	0xc888f091u,
+	0x9f70c898u,
+	0xf0916310u,
+	0x2605f0d1u,
+	0xf091c1a6u,
+	0xf039c180u,
+	0xf0910103u,
+	0x80b0ad19u,
+	0xacacf11du,
+	0xf091f139u,
+	0xc03ef091u,
+	0xffafcd06u,
+	0xf0910103u,
+	0x84a88030u,
+	0x4000a112u,
+	0xa06ed081u,
+	0xc000f091u,
+	0x1248a100u,
+	0xa0000600u,
+	0x701ad4au,
+	0xacfcf05du,
+	0x3c0ea85u,
+	0x23012300u,
+	0xf0afc02eu,
+	0xf091f831u,
+	0xad28acf4u,
+	0xf05df091u,
+	0xc1d8u,
+	0xf091103au,
+	0x2000304u,
+	0xc101c121u,
+	0x2000300u,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106ac338u,
+	0xf091c888u,
+	0xf0919f70u,
+	0xc898f091u,
+	0x63102605u,
+	0xad27ac68u,
+	0xf01df091u,
+	0x2c00ad1au,
+	0xac82c004u,
+	0xf0910108u,
+	0x8490f091u,
+	0x8030d4c6u,
+	0xf091d526u,
+	0xf091cd21u,
+	0xf11d166au,
+	0xc17700ffu,
+	0xcf29c177u,
+	0xf11df091u,
+	0xc288f091u,
+	0x8038e10bu,
+	0x6042800u,
+	0x9b30e111u,
+	0xf091c008u,
+	0xf0918020u,
+	0xad1aac72u,
+	0xf19df091u,
+	0xffc038u,
+	0xf091d0b8u,
+	0xf091c0a4u,
+	0xf09102ffu,
+	0x3f0c529u,
+	0xe105f091u,
+	0x10fd2d8u,
+	0xf091c1a4u,
+	0xf0910208u,
+	0x300cc13u,
+	0xe285f091u,
+	0x106acdb8u,
+	0xf0910c44u,
+	0x10000104u,
+	0x280084b0u,
+	0xe10d0103u,
+	0x84b0e117u,
+	0xf091f0d1u,
+	0xf091c288u,
+	0xf09101feu,
+	0x80a8c298u,
+	0xf091e06fu,
+	0xf091c148u,
+	0xf091e5a6u,
+	0xf091f666u,
+	0xf091ad4eu,
+	0xac12f01du,
+	0xf091103au,
+	0xd328f091u,
+	0xc1110223u,
+	0x3e4c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0x28d30203u,
+	0x8d2b8932u,
+	0xc111c3b8u,
+	0xf0910200u,
+	0x340c911u,
+	0xe405f091u,
+	0x106a1049u,
+	0x23032200u,
+	0x3148c328u,
+	0xf0910200u,
+	0x31cc101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0x34682008u,
+	0xf091e507u,
+	0xf091e07bu,
+	0xf091ca28u,
+	0xf6398030u,
+	0x28400212u,
+	0x8892e28fu,
+	0xc141c4a8u,
+	0xf091ad1bu,
+	0xacc2f01du,
+	0xf0914000u,
+	0xa11ba03cu,
+	0xd081c020u,
+	0xf091bc68u,
+	0xc4a8f091u,
+	0xf01df091u,
+	0x1bc21bc2u,
+	0x1bc21b62u,
+	0x1bc21bc2u,
+	0x1bc21bc2u,
+	0x1bc21bc2u,
+	0x1bc21bc2u,
+	0x1bc21bc2u,
+	0x1bc21bc2u,
+	0x1bc21bc2u,
+	0x1bc24000u,
+	0xa1a2a00cu,
+	0xb2702204u,
+	0x21302003u,
+	0xf091c328u,
+	0xf0910200u,
+	0x350c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0x22042120u,
+	0x34682008u,
+	0xf091e507u,
+	0xf091e07bu,
+	0xf091b270u,
+	0x130u,
+	0xd4832204u,
+	0x21202003u,
+	0xf0914100u,
+	0xa302a280u,
+	0x4200a5a2u,
+	0xa40cad19u,
+	0xacf0f05du,
+	0x2800c4a8u,
+	0xf091ea85u,
+	0x23012300u,
+	0x103ad328u,
+	0xf091c111u,
+	0x22303e4u,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106a28d3u,
+	0x2038d2bu,
+	0x8932c111u,
+	0xc3b8f091u,
+	0xca28f639u,
+	0x2303ad1eu,
+	0xac0cf05du,
+	0xf091cea8u,
+	0xf0912d22u,
+	0x20110u,
+	0xc5332e3cu,
+	0x1ad2du,
+	0xacacf05du,
+	0x100280bu,
+	0x22003148u,
+	0xc328f091u,
+	0x200031cu,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106a3468u,
+	0x2008f091u,
+	0xe507f091u,
+	0xe07bf091u,
+	0x120u,
+	0x2010300u,
+	0x2e3cca28u,
+	0xf091c03eu,
+	0xf091ffafu,
+	0xad1dac08u,
+	0xf05df091u,
+	0xf0afc02eu,
+	0xf091f631u,
+	0xc6c6f091u,
+	0x11084a8u,
+	0xe10bf091u,
+	0xad7aac96u,
+	0xf05df137u,
+	0xf0d1f091u,
+	0x23035140u,
+	0x2000340u,
+	0xcd15e205u,
+	0x164d164bu,
+	0x2200314eu,
+	0x34682008u,
+	0xf091e507u,
+	0xf091e07bu,
+	0xf091b270u,
+	0x2200314eu,
+	0x2003f091u,
+	0xc915e223u,
+	0xf091e11fu,
+	0xf091d181u,
+	0x2000340u,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106aad1cu,
+	0xac80f01du,
+	0xf091f0d1u,
+	0xf091ad1du,
+	0xac08f05du,
+	0xf0912811u,
+	0x10884a8u,
+	0xe10bf091u,
+	0xad24ac2cu,
+	0xf05df091u,
+	0xf0d1f091u,
+	0xca38f091u,
+	0xf631ad1eu,
+	0xac0cf05du,
+	0xf0910001u,
+	0x1100200u,
+	0x3002e3cu,
+	0x283d0120u,
+	0x80b0e109u,
+	0xf091cea8u,
+	0xf0912d22u,
+	0x1ad2du,
+	0xacacf05du,
+	0x101ea85u,
+	0x23012300u,
+	0xca28f639u,
+	0x28118038u,
+	0xc086f091u,
+	0xe1890110u,
+	0x1efe005u,
+	0x80a880a0u,
+	0xc096f091u,
+	0xf137c03eu,
+	0xf091ffafu,
+	0xad28acf4u,
+	0xf05df091u,
+	0xc1d8u,
+	0xf091103au,
+	0x2000304u,
+	0xc101c121u,
+	0x2000300u,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106ac338u,
+	0xf091c888u,
+	0xf0919f70u,
+	0xc898f091u,
+	0x63102605u,
+	0xcd06f091u,
+	0x10384a8u,
+	0x80304000u,
+	0xa112a06eu,
+	0xd081c000u,
+	0xf0910103u,
+	0x80b0ad1du,
+	0xacdaf11du,
+	0xf091cd06u,
+	0xf0910103u,
+	0x84a88030u,
+	0x4000a112u,
+	0xa06ed081u,
+	0xc000f091u,
+	0x1248a100u,
+	0xa000ca35u,
+	0x6000701u,
+	0xad4aacfcu,
+	0xf05d03c0u,
+	0xea852301u,
+	0x2300f0afu,
+	0xc02ef091u,
+	0xf6312811u,
+	0x11084a8u,
+	0xe187f091u,
+	0xf0d1f091u,
+	0xe086f091u,
+	0x813ae18bu,
+	0x3fead7au,
+	0xac96f01du,
+	0xf137892bu,
+	0xe096f091u,
+	0xf0d1f091u,
+	0xad08ac0au,
+	0xf05dc031u,
+	0xc031c533u,
+	0x2e00c128u,
+	0xf0910200u,
+	0x382c521u,
+	0x2d44ed06u,
+	0xf0918172u,
+	0x30389aau,
+	0xe185f091u,
+	0x81722c86u,
+	0x2012c87u,
+	0xc3a8f091u,
+	0xd7a8f091u,
+	0x6000713u,
+	0xc813e409u,
+	0xf0911268u,
+	0x6000700u,
+	0xc0312e08u,
+	0xca352e8cu,
+	0xb278f623u,
+	0x8c4f091u,
+	0x2e102e94u,
+	0xb2760000u,
+	0x112d483u,
+	0x22242118u,
+	0x2002f091u,
+	0xf337f0d1u,
+	0x2d76b468u,
+	0x4200103au,
+	0xd328f091u,
+	0xc1110223u,
+	0x3e4c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0x28d30203u,
+	0x8d2b8932u,
+	0xc111c3b8u,
+	0xf091ca28u,
+	0xf639de26u,
+	0xf091c061u,
+	0xc061c403u,
+	0xde36f091u,
+	0xad1fac08u,
+	0xc1c8f091u,
+	0x8238f19du,
+	0x230106u,
+	0xc2b4f091u,
+	0xc1d8u,
+	0xf091103au,
+	0x2000304u,
+	0xc101c121u,
+	0x2000300u,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106ac338u,
+	0xf091c888u,
+	0xf0919f70u,
+	0xc898f091u,
+	0x63102605u,
+	0xf0d1f091u,
+	0xc1d8u,
+	0xf091103au,
+	0x2000304u,
+	0xc101c121u,
+	0x2000300u,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106ac338u,
+	0xf091c888u,
+	0xf0919f70u,
+	0xc898f091u,
+	0x63102605u,
+	0xad23ac08u,
+	0xf05d1076u,
+	0xf0d1f091u,
+	0xca28f639u,
+	0xc1a6f039u,
+	0xff40f091u,
+	0x20389b2u,
+	0xe10bf091u,
+	0xad21ac2cu,
+	0xf01df091u,
+	0xc320f091u,
+	0x5c68c3a0u,
+	0xf0915e68u,
+	0x21042080u,
+	0x1f0e50du,
+	0x101f80a8u,
+	0xe187f091u,
+	0xe075f091u,
+	0x29c0103au,
+	0xd328f091u,
+	0xc1110223u,
+	0x3e4c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0x28d30203u,
+	0x8d2b8932u,
+	0xc111c3b8u,
+	0xf0910200u,
+	0x340c911u,
+	0xe4051049u,
+	0x104b2303u,
+	0x22003148u,
+	0xc328f091u,
+	0x200031cu,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106a3468u,
+	0x2008f091u,
+	0xe507f091u,
+	0xe07bf091u,
+	0x28400202u,
+	0x8911e185u,
+	0x8030114eu,
+	0x2128892u,
+	0xad20ac08u,
+	0xf29dc141u,
+	0xc4a8f091u,
+	0xad21ac2cu,
+	0xf01df091u,
+	0x4000a120u,
+	0xa01ed081u,
+	0xc020f091u,
+	0xbc68c4a8u,
+	0xf091f01du,
+	0xf091212cu,
+	0x212c212cu,
+	0x20502044u,
+	0x212c212cu,
+	0x212c212cu,
+	0x212c212cu,
+	0x212c212cu,
+	0x212c212cu,
+	0x212c212cu,
+	0x212c212cu,
+	0x2888843au,
+	0xad21ac28u,
+	0xf11df091u,
+	0x4000a1a2u,
+	0xa00cb270u,
+	0x22042130u,
+	0x2003f091u,
+	0xc328f091u,
+	0x2000350u,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106a2204u,
+	0x21203468u,
+	0x2008f091u,
+	0xe507f091u,
+	0xe07bf091u,
+	0xb2700000u,
+	0x130d483u,
+	0x22042120u,
+	0x2003f091u,
+	0xc1a6f439u,
+	0x2000304u,
+	0xc3a4f091u,
+	0xc501c324u,
+	0xf091c079u,
+	0x5c685e6au,
+	0x22042130u,
+	0x2000f091u,
+	0x1f0e50du,
+	0x101f80a8u,
+	0xe187f091u,
+	0xe075f091u,
+	0x4000a1a2u,
+	0xa05cb270u,
+	0x22042130u,
+	0x2003f091u,
+	0x2000334u,
+	0xc3a4f091u,
+	0xc501c324u,
+	0xf091c079u,
+	0x5c685e6au,
+	0x22042120u,
+	0x2000f091u,
+	0x1f0e50du,
+	0x101f80a8u,
+	0xe187f091u,
+	0xe075f091u,
+	0xb2700000u,
+	0x130d483u,
+	0x22042120u,
+	0x2003f091u,
+	0x4100a3a2u,
+	0xa25c4200u,
+	0xa5a2a40cu,
+	0xad19acf0u,
+	0xf05d104eu,
+	0xc4a8f091u,
+	0xb4684200u,
+	0xea852301u,
+	0x2300103au,
+	0xd328f091u,
+	0xc1110223u,
+	0x3e4c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0x28d30203u,
+	0x8d2b8932u,
+	0xc111c3b8u,
+	0xf091ca28u,
+	0xf639c1a6u,
+	0xf039e6c6u,
+	0xf0910310u,
+	0x89aae10fu,
+	0xf091e486u,
+	0xf0910307u,
+	0x89b2e11bu,
+	0xf091d2a0u,
+	0xf091c501u,
+	0xd2b0f091u,
+	0xd220f091u,
+	0xc07bd230u,
+	0xf091e01bu,
+	0xf091dfa6u,
+	0xf091c413u,
+	0xdfb6f091u,
+	0xdf26f091u,
+	0x100u,
+	0xc41bdf36u,
+	0xf0912d24u,
+	0xd7a8f091u,
+	0xc813ad22u,
+	0xac7af41du,
+	0xad22ac36u,
+	0xc1c8f091u,
+	0x8238f19du,
+	0x230106u,
+	0xc2b4f091u,
+	0xca28f639u,
+	0xc1a6f039u,
+	0xc180f091u,
+	0x10380b0u,
+	0xe19d2811u,
+	0xc01ef091u,
+	0x8338e113u,
+	0xf091c446u,
+	0xf0910101u,
+	0x80a0c456u,
+	0xf091e037u,
+	0xf0910000u,
+	0xc1d8f091u,
+	0x103a0200u,
+	0x304c101u,
+	0xc1210200u,
+	0x300c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0xc338f091u,
+	0xc888f091u,
+	0x9f70c898u,
+	0xf0916310u,
+	0x2605f0d1u,
+	0xf0910000u,
+	0xc1d8f091u,
+	0x103a0200u,
+	0x304c101u,
+	0xc1210200u,
+	0x300c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0xc338f091u,
+	0xc888f091u,
+	0x9f70c898u,
+	0xf0916310u,
+	0x2605ca28u,
+	0xf639ad23u,
+	0xac08f05du,
+	0xf091f0d1u,
+	0xf091c031u,
+	0xc034f091u,
+	0xb278f623u,
+	0x8c4f091u,
+	0xc703c079u,
+	0xc638f091u,
+	0xd6b8f091u,
+	0x2e342924u,
+	0xc3112d24u,
+	0xca28f039u,
+	0xc1a0f439u,
+	0xad11ac7au,
+	0xf05df091u,
+	0xe7b8f091u,
+	0x10741276u,
+	0x2e2c0200u,
+	0x3012d6au,
+	0xe10bf091u,
+	0x2924cc15u,
+	0xe41df091u,
+	0x230106u,
+	0x2d32ca28u,
+	0xf091ad29u,
+	0xac0ef05du,
+	0x2d34ad21u,
+	0xacd0f01du,
+	0xf091ca25u,
+	0xe18bf091u,
+	0xad7cacc0u,
+	0xf05d0021u,
+	0x106cfa28u,
+	0xf091ad29u,
+	0xac0ef05du,
+	0xca35ad22u,
+	0xac80f01du,
+	0xf091f631u,
+	0xfba6f091u,
+	0xc177fbb6u,
+	0xf091eb26u,
+	0xf091cb15u,
+	0xe03ef091u,
+	0xffafc1a6u,
+	0xf0391070u,
+	0xc021e113u,
+	0xf091c180u,
+	0xf0910103u,
+	0x80b0ad23u,
+	0xac9af19du,
+	0xf091ad23u,
+	0xac92c446u,
+	0xf0918238u,
+	0xe189f091u,
+	0xca25f19du,
+	0xf091c446u,
+	0xf0918038u,
+	0xf11d01feu,
+	0x80a8c456u,
+	0xf0910000u,
+	0xc1d8f091u,
+	0x103a0200u,
+	0x304c101u,
+	0xc1210200u,
+	0x300c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0xc338f091u,
+	0xc888f091u,
+	0x9f70c898u,
+	0xf0916310u,
+	0x2605ad24u,
+	0xac0ef01du,
+	0xf091ca25u,
+	0xad24ac0eu,
+	0xf19df091u,
+	0xf139c03eu,
+	0xf091ffafu,
+	0xb2760000u,
+	0x112d483u,
+	0x22082118u,
+	0x2002f091u,
+	0xc888f091u,
+	0x8170c898u,
+	0xf0916302u,
+	0xf091cd06u,
+	0xf0910103u,
+	0x84a88030u,
+	0x4000a112u,
+	0xa06ed081u,
+	0xc000f091u,
+	0x1248a100u,
+	0xa000146eu,
+	0x9f74e105u,
+	0x3c003c1u,
+	0xad4aacfcu,
+	0xf05df091u,
+	0xea852301u,
+	0x2300f0afu,
+	0xc02ef091u,
+	0xf831ad24u,
+	0xac1cf01du,
+	0xf091c888u,
+	0xf0918170u,
+	0xc898f091u,
+	0x6302f091u,
+	0xf0afd02eu,
+	0xf091c523u,
+	0xe107f091u,
+	0xf0d1f091u,
+	0xc0c6f091u,
+	0x8170c0d6u,
+	0xf091c446u,
+	0xf0910102u,
+	0x80a0c456u,
+	0xf091c031u,
+	0xcb36f091u,
+	0xcbb6f091u,
+	0xc406f091u,
+	0x8020ad27u,
+	0xac68f19du,
+	0xf0910310u,
+	0xe6c6f091u,
+	0x803ae185u,
+	0x2100200u,
+	0xc486f091u,
+	0x1f080a8u,
+	0x1c080b0u,
+	0xc086f091u,
+	0xe18b01efu,
+	0x8138e105u,
+	0x89338933u,
+	0x80a88120u,
+	0xc096f091u,
+	0xd1a6f091u,
+	0xc523ad26u,
+	0xacb0f11du,
+	0xf091c43bu,
+	0xe10bf433u,
+	0xad25acfeu,
+	0xf01df091u,
+	0xff44f091u,
+	0x2078daau,
+	0x8932c543u,
+	0x4100a324u,
+	0xa2c6d583u,
+	0xd022f091u,
+	0xbc6af01du,
+	0xf09128deu,
+	0x24d6251cu,
+	0x2548255eu,
+	0x25ac28deu,
+	0x28ded124u,
+	0xf0910000u,
+	0x110c129u,
+	0xad25ac0eu,
+	0xf11df091u,
+	0xc0c6f091u,
+	0x9f70f19du,
+	0xf091c224u,
+	0xf091d2a4u,
+	0xf0912302u,
+	0x2e340400u,
+	0x5000600u,
+	0x700ad25u,
+	0xacc4f01du,
+	0x100c031u,
+	0xcc36f091u,
+	0xad27ac68u,
+	0xf01df091u,
+	0xd124f091u,
+	0xc43be119u,
+	0xc031c0c6u,
+	0xf0919f70u,
+	0xe18fc031u,
+	0xc928f091u,
+	0xcc36f091u,
+	0xf0d1f091u,
+	0xcc36f091u,
+	0xad27ac68u,
+	0xf01df091u,
+	0xc0c6f091u,
+	0x9f70ad27u,
+	0xac68f19du,
+	0xc031cc36u,
+	0xf091f0d1u,
+	0xf091c6c6u,
+	0xf0910110u,
+	0x84a8ad27u,
+	0xac68f19du,
+	0xc031cc36u,
+	0xf0910105u,
+	0xc486f091u,
+	0xc0c6f091u,
+	0x8038ad28u,
+	0xacdef19du,
+	0xb276c086u,
+	0xf0918138u,
+	0xe10ff223u,
+	0x1048021u,
+	0xc096f091u,
+	0xf01df091u,
+	0x8c4f091u,
+	0x23022e34u,
+	0xad25acc4u,
+	0xf01d0102u,
+	0xc6c6f091u,
+	0x11084a8u,
+	0xad27ac68u,
+	0xf19dc031u,
+	0xcc36f091u,
+	0xf0d1f091u,
+	0x2ea82c66u,
+	0xc0312e20u,
+	0x2c27c746u,
+	0xf0910108u,
+	0x8021c756u,
+	0xf091c1a6u,
+	0xf039c180u,
+	0xf0912c06u,
+	0x1c496u,
+	0xf091b276u,
+	0xad48ac84u,
+	0xf05df091u,
+	0xea852301u,
+	0x2300f0d1u,
+	0xf091c031u,
+	0xcc36f091u,
+	0xc6c6f091u,
+	0xe086f091u,
+	0x8038e189u,
+	0x11001efu,
+	0xe00588aau,
+	0x88a2e096u,
+	0xf091c031u,
+	0xc5332e00u,
+	0xc128f091u,
+	0x2000382u,
+	0xc5212d44u,
+	0xed06f091u,
+	0x81720303u,
+	0x89aae185u,
+	0xf0918172u,
+	0x2c860201u,
+	0x2c87c031u,
+	0xde26f091u,
+	0xc543c149u,
+	0xc543c149u,
+	0xe326f091u,
+	0xf3a6f091u,
+	0xcd17c81du,
+	0x6000713u,
+	0xe407f091u,
+	0x6000700u,
+	0x2e08ca35u,
+	0x2e8cb276u,
+	0xf22308c4u,
+	0xf0912e10u,
+	0x2e94b276u,
+	0x112u,
+	0xd4832224u,
+	0x21182002u,
+	0xf0910001u,
+	0x1100200u,
+	0x3002e3cu,
+	0xcea8f091u,
+	0x2d220001u,
+	0xad2dacacu,
+	0xf05d0101u,
+	0xad28ac5cu,
+	0xf01df091u,
+	0xc031cc36u,
+	0xf091ad27u,
+	0xac20c086u,
+	0xf0918638u,
+	0xf19df091u,
+	0xad3bac3au,
+	0xf05df091u,
+	0xf3374000u,
+	0xa1a1a0e0u,
+	0xea874000u,
+	0xa1a1a0d0u,
+	0xd081c020u,
+	0xf091c021u,
+	0xe11df091u,
+	0xc931e10du,
+	0xf091f031u,
+	0xad26acdeu,
+	0xf01df091u,
+	0xf231d022u,
+	0xf091d030u,
+	0xf091f137u,
+	0xad3aacdcu,
+	0xf05df091u,
+	0xad2dacacu,
+	0xf05d0001u,
+	0xad7aac96u,
+	0xf01df137u,
+	0xf0d1f091u,
+	0xcd06f091u,
+	0x10384a8u,
+	0x80304000u,
+	0xa112a06eu,
+	0xd081c000u,
+	0xf0911248u,
+	0xa100a000u,
+	0xad4dac06u,
+	0xf05df091u,
+	0xcea8f091u,
+	0xc021e18bu,
+	0xf091ad7cu,
+	0xacc0f05du,
+	0x23df71u,
+	0xceb8f091u,
+	0xad7aac96u,
+	0xf01df137u,
+	0xf0d1f091u,
+	0xc6c6f091u,
+	0x11084a8u,
+	0xad27ac90u,
+	0xf11df091u,
+	0xcea8f091u,
+	0xc021e18bu,
+	0xf091ad7cu,
+	0xacc0f05du,
+	0x23df71u,
+	0xceb8f091u,
+	0x2303ad08u,
+	0xac0af05du,
+	0xc031c1a6u,
+	0xf23908c4u,
+	0xf0912e00u,
+	0xc23dad28u,
+	0xac50f19du,
+	0x104e2c06u,
+	0xc128f091u,
+	0x2000342u,
+	0xc5212d44u,
+	0xc1a6f239u,
+	0xc222f091u,
+	0xd2a2f091u,
+	0x2e08b276u,
+	0x112u,
+	0xd4832224u,
+	0x21182002u,
+	0xf091ad28u,
+	0xac1ec086u,
+	0xf0918638u,
+	0xe10f2824u,
+	0x18484b0u,
+	0xf11d0030u,
+	0xf01d0031u,
+	0xc446f091u,
+	0x8238f19du,
+	0x35dfa6u,
+	0xf091cf26u,
+	0xf0912a88u,
+	0xcf13ca19u,
+	0xf41d0034u,
+	0xc406f091u,
+	0x8020e11bu,
+	0x2824010fu,
+	0x80a82c0fu,
+	0xcca6f091u,
+	0xc021e10bu,
+	0xf431ad39u,
+	0xac00f05du,
+	0xf091290eu,
+	0xcea8f091u,
+	0x2d220001u,
+	0x1100200u,
+	0x3002e3cu,
+	0x292c0000u,
+	0xad2dacacu,
+	0xf05d0101u,
+	0xc1a6f439u,
+	0xad39ac00u,
+	0xf05df091u,
+	0xc031c1b6u,
+	0xf091c6c6u,
+	0xf0910110u,
+	0x84a8c406u,
+	0xf09184a0u,
+	0xe11ff091u,
+	0xe086f091u,
+	0x813ae18bu,
+	0x3fead7au,
+	0xac96f01du,
+	0xf137892bu,
+	0xe096f091u,
+	0xf0d1f091u,
+	0xe086f091u,
+	0x813ae107u,
+	0xf091f0d1u,
+	0xf091cca6u,
+	0xf091c021u,
+	0xe139f431u,
+	0xdfa4f091u,
+	0xdcb6f091u,
+	0xc031cfb4u,
+	0xf091f135u,
+	0xc1b6f091u,
+	0x5142b274u,
+	0x22002140u,
+	0x2002f091u,
+	0xad36ac7cu,
+	0xf05df091u,
+	0xc1a6f091u,
+	0xc021a128u,
+	0xa09ef111u,
+	0xf091f0d1u,
+	0xf091c888u,
+	0xf0918170u,
+	0xc898f091u,
+	0x6302f091u,
+	0xf0d1f091u,
+	0xe707f091u,
+	0xe07bf091u,
+	0x103ac533u,
+	0x2e28c031u,
+	0x2e2c2d34u,
+	0x22803e2u,
+	0x2d72292cu,
+	0x292e292au,
+	0x2932c021u,
+	0xe11f2934u,
+	0xc021e119u,
+	0xf031292au,
+	0xdfa0f091u,
+	0xc501dfb0u,
+	0xf091df20u,
+	0xf091c07bu,
+	0xdf30f091u,
+	0x10098020u,
+	0xe18b4100u,
+	0xad7cacc0u,
+	0xf05d0030u,
+	0xb234b072u,
+	0xc0312d36u,
+	0x100f2d30u,
+	0x22282110u,
+	0x2003f091u,
+	0xf0d16201u,
+	0xe0050b00u,
+	0xb011034u,
+	0x1232c931u,
+	0xe11bf233u,
+	0xe2a2f091u,
+	0xca258873u,
+	0xe1878873u,
+	0xe06df091u,
+	0x111f8030u,
+	0xc3b2f091u,
+	0xf0d1f091u,
+	0x0u,
+	0x4400a9a1u,
+	0xa870e011u,
+	0xb010000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8300b00u,
+	0x10301232u,
+	0xd131e187u,
+	0x4000f0d1u,
+	0xf091b068u,
+	0xc2a0f091u,
+	0xc021e18bu,
+	0xbc68ad29u,
+	0xaca8f01du,
+	0x6204c888u,
+	0xf0918020u,
+	0xe10b0201u,
+	0xc200f091u,
+	0x110f88b0u,
+	0xc120f091u,
+	0xc1a0f091u,
+	0xc0a0f091u,
+	0xc320f091u,
+	0xc021e123u,
+	0xf231c0a0u,
+	0xf091efa2u,
+	0xf091c815u,
+	0xefb2f091u,
+	0xef22f091u,
+	0x100u,
+	0xc81def32u,
+	0xf091c320u,
+	0xf091e3a0u,
+	0xf091f05du,
+	0xf091ad29u,
+	0xaca8f01du,
+	0x62040000u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x80301108u,
+	0x5a494200u,
+	0xa502a400u,
+	0x4300a7a1u,
+	0xa6b4c741u,
+	0xdd87c741u,
+	0xd98568d1u,
+	0xad2bac20u,
+	0xf01d1319u,
+	0x4000a1a1u,
+	0xa0b0c031u,
+	0xc030f091u,
+	0x90f4000u,
+	0xa1a1a0b4u,
+	0x100u,
+	0xc030f091u,
+	0xf0a1e5f9u,
+	0xf091f0d1u,
+	0x600fad7cu,
+	0xacc0f05du,
+	0x71fe2fu,
+	0xb27ef0a3u,
+	0x8d4f091u,
+	0x10401141u,
+	0x12421343u,
+	0x14441545u,
+	0x1646fe2fu,
+	0xb27ef0a3u,
+	0x8d4f091u,
+	0x10741276u,
+	0x1478167au,
+	0xfe2fb27eu,
+	0xf0a308d4u,
+	0xf091107cu,
+	0xc03ef091u,
+	0x808101cu,
+	0xff2fc0beu,
+	0xf091ad39u,
+	0xac1ef05du,
+	0xf091f12fu,
+	0xc02ef091u,
+	0xbc68b27eu,
+	0xf0a308c4u,
+	0xf091f22fu,
+	0xb468b66au,
+	0xb86cba6eu,
+	0xb27ef0a3u,
+	0x8c4f091u,
+	0xf22f5048u,
+	0x5149524au,
+	0x534b544cu,
+	0x554d564eu,
+	0xb27ef0a3u,
+	0x8c4f091u,
+	0xf22fe015u,
+	0xf09100f0u,
+	0x111f80a8u,
+	0xad2aac7au,
+	0xf19df091u,
+	0xe005f091u,
+	0xe4ed2303u,
+	0x164b0200u,
+	0xc653c0a4u,
+	0xf091c501u,
+	0xc024f091u,
+	0xc0795c68u,
+	0x5e6a2140u,
+	0x208001f0u,
+	0xe50d101fu,
+	0x80a8e187u,
+	0xf091e075u,
+	0xf0918176u,
+	0xc184f091u,
+	0x9b28c006u,
+	0xf0918020u,
+	0xe109ad2bu,
+	0xace8f01du,
+	0xf091283eu,
+	0x8020e189u,
+	0x28fc8da3u,
+	0xe197c031u,
+	0x114ed154u,
+	0xf091c184u,
+	0xf0915b48u,
+	0xad2cacaau,
+	0xf01df091u,
+	0x2d3e4100u,
+	0xa39fa238u,
+	0xc022f091u,
+	0x4000511u,
+	0xc211e20fu,
+	0xf091ad77u,
+	0xacd4f05du,
+	0x4100e187u,
+	0x9f73f0d1u,
+	0xf091124eu,
+	0xe154f091u,
+	0xe184f091u,
+	0x5b4a2140u,
+	0xf2312083u,
+	0xf091e119u,
+	0x8173c0b6u,
+	0xf091c136u,
+	0xf091f016u,
+	0xf0910101u,
+	0xd056f091u,
+	0xf0d1f091u,
+	0xad2fac6au,
+	0xf05df431u,
+	0xf0d1f091u,
+	0x283e0201u,
+	0x8910ad2cu,
+	0xac44f11du,
+	0xf0918030u,
+	0xc016f091u,
+	0xe0a6f091u,
+	0xca25e13du,
+	0xf2352140u,
+	0x2082f091u,
+	0x29bef435u,
+	0x42c3eu,
+	0x4000a1a1u,
+	0xa0302904u,
+	0xc039e109u,
+	0xf0914000u,
+	0xa1a1a070u,
+	0xcea0f091u,
+	0x2d220000u,
+	0x101ad2du,
+	0xacacf05du,
+	0xf0910305u,
+	0xe043f535u,
+	0xf0d1f091u,
+	0xad77acd4u,
+	0xf05d4100u,
+	0xe187124eu,
+	0xf0d1f091u,
+	0xe154f091u,
+	0xe184f091u,
+	0x5b4ac126u,
+	0xf239cfb2u,
+	0xf091c136u,
+	0xf091c533u,
+	0x2d7ef231u,
+	0x21402083u,
+	0xf091c006u,
+	0xf091d046u,
+	0xf0918171u,
+	0xd056f091u,
+	0x8011e107u,
+	0x8030f0d1u,
+	0xf091c016u,
+	0xf091c0a6u,
+	0xf439b274u,
+	0x21402082u,
+	0xf091ad2fu,
+	0xac6af05du,
+	0xf091f0d1u,
+	0xf091ad7cu,
+	0xacc0f05du,
+	0x724000u,
+	0xa1a1a030u,
+	0x2904c039u,
+	0xe109f091u,
+	0x4000a1a1u,
+	0xa070cea0u,
+	0xf0912d22u,
+	0x283e0104u,
+	0x80212c3eu,
+	0x101u,
+	0xad2dacacu,
+	0xf05df091u,
+	0xf0d1f091u,
+	0xad7cacc0u,
+	0xf05d0073u,
+	0xfe2fb27eu,
+	0xf0a308d4u,
+	0xf0911040u,
+	0x11411242u,
+	0x13431444u,
+	0x15451646u,
+	0xfe2fb27eu,
+	0xf0a308d4u,
+	0xf0911074u,
+	0x12761478u,
+	0x167afe2fu,
+	0xb27ef0a3u,
+	0x8d4f091u,
+	0x107cc03eu,
+	0xf0910808u,
+	0x101cff2fu,
+	0xc0bef091u,
+	0xad39ac1eu,
+	0xf05df091u,
+	0xf12fc02eu,
+	0xf091bc68u,
+	0xb27ef0a3u,
+	0x8c4f091u,
+	0xf22fb468u,
+	0xb66ab86cu,
+	0xba6eb27eu,
+	0xf0a308c4u,
+	0xf091f22fu,
+	0x50485149u,
+	0x524a534bu,
+	0x544c554du,
+	0x564eb27eu,
+	0xf0a308c4u,
+	0xf091f22fu,
+	0xad2daca2u,
+	0xf01df091u,
+	0xc03ef091u,
+	0xffaf100du,
+	0x111f00f0u,
+	0x111f80a8u,
+	0xad2cace4u,
+	0xf19df091u,
+	0x100d0118u,
+	0x84a8e107u,
+	0xf0910cc0u,
+	0x1600f0afu,
+	0xc02ef091u,
+	0xe005f091u,
+	0xe4cf1148u,
+	0x8020e10bu,
+	0x4100a302u,
+	0xa228e00bu,
+	0x4a054a04u,
+	0x4100a302u,
+	0xa2201319u,
+	0x21408932u,
+	0xc653c0a2u,
+	0xf091c501u,
+	0xc022f091u,
+	0xc0795c68u,
+	0x5e6ad1a2u,
+	0xf0912cffu,
+	0x14198174u,
+	0x922a4000u,
+	0xa1aaa020u,
+	0xc031c030u,
+	0xf0914000u,
+	0xa1aaa022u,
+	0x822103cu,
+	0xc030f091u,
+	0x15188294u,
+	0xad2eac7cu,
+	0xf19df091u,
+	0xd03ef091u,
+	0xffaf4000u,
+	0xa1aaa022u,
+	0xd020f091u,
+	0x822103cu,
+	0xc030f091u,
+	0xc53100f0u,
+	0x100c529u,
+	0xe13df091u,
+	0x4000a1aau,
+	0xa020c020u,
+	0xf091c171u,
+	0xc030f091u,
+	0x23b0388u,
+	0xc131e1a3u,
+	0xf0910008u,
+	0xb001c48u,
+	0x53000b01u,
+	0x1c485300u,
+	0x10060108u,
+	0x80a01c48u,
+	0x5700ad7cu,
+	0xacc0f05du,
+	0x77f0afu,
+	0xd02ef091u,
+	0xad2eac04u,
+	0xf01df091u,
+	0x208101f0u,
+	0xe50d101fu,
+	0x80a8e187u,
+	0xf091e075u,
+	0xf091ad2eu,
+	0xacaaf49du,
+	0xc031e132u,
+	0xf0919224u,
+	0xe189f091u,
+	0x8173f1d2u,
+	0xf091f0d1u,
+	0x5b4a100du,
+	0x111f00f0u,
+	0x111f80a8u,
+	0xad2eacd2u,
+	0xf19df091u,
+	0x100d0118u,
+	0x84a8e107u,
+	0xf0910cc0u,
+	0x1600ad2eu,
+	0xac96f01du,
+	0xf091ad7cu,
+	0xacc0f05du,
+	0x74fe2fu,
+	0xb27ef0a3u,
+	0x8d4f091u,
+	0x10401141u,
+	0x12421343u,
+	0x14441545u,
+	0x1646fe2fu,
+	0xb27ef0a3u,
+	0x8d4f091u,
+	0x10741276u,
+	0x1478167au,
+	0xfe2fb27eu,
+	0xf0a308d4u,
+	0xf091107cu,
+	0xc03ef091u,
+	0x808101cu,
+	0xff2fc0beu,
+	0xf091ad39u,
+	0xac1ef05du,
+	0xf091f12fu,
+	0xc02ef091u,
+	0xbc68b27eu,
+	0xf0a308c4u,
+	0xf091f22fu,
+	0xb468b66au,
+	0xb86cba6eu,
+	0xb27ef0a3u,
+	0x8c4f091u,
+	0xf22f5048u,
+	0x5149524au,
+	0x534b544cu,
+	0x554d564eu,
+	0xb27ef0a3u,
+	0x8c4f091u,
+	0xf22fad2du,
+	0xacc6f01du,
+	0xf0914400u,
+	0xa9a1a830u,
+	0x2904c039u,
+	0xe10b0b00u,
+	0x4400a9a1u,
+	0xa8700b01u,
+	0x70287du,
+	0x80a8e10bu,
+	0xf091ad38u,
+	0xac1ef01du,
+	0xf0914000u,
+	0xa12fa0b0u,
+	0x8739e109u,
+	0x85414000u,
+	0xa12fa0d0u,
+	0xd081c020u,
+	0xf091bc68u,
+	0xf01df091u,
+	0x2ff0356eu,
+	0x3548346eu,
+	0x346e346eu,
+	0x30243078u,
+	0x2ff8302cu,
+	0x303c3034u,
+	0x301c3252u,
+	0x32fc3320u,
+	0x341e381eu,
+	0x381e381eu,
+	0x381e381eu,
+	0x381e381eu,
+	0x381e381eu,
+	0x381e381eu,
+	0x381e381eu,
+	0x381e381eu,
+	0xad38ac6eu,
+	0xf01df091u,
+	0xf135c03eu,
+	0xf091ffafu,
+	0xc188f091u,
+	0xad43acd6u,
+	0xf05d1448u,
+	0xf0afc02eu,
+	0xf091f431u,
+	0xad38ac6eu,
+	0xf01df091u,
+	0xad38ac6eu,
+	0xf01df091u,
+	0xad38ac6eu,
+	0xf01df091u,
+	0xad3bac52u,
+	0xf01df091u,
+	0xad3cac32u,
+	0xf01df091u,
+	0xad3bacaau,
+	0xf01df091u,
+	0xad38ac6eu,
+	0xf01df091u,
+	0x3192u,
+	0x131fau,
+	0x231fau,
+	0x3226u,
+	0x130beu,
+	0x230beu,
+	0x8030beu,
+	0x20030beu,
+	0x40030beu,
+	0x80030beu,
+	0x3122u,
+	0x4000a19fu,
+	0xa054d020u,
+	0xf091c523u,
+	0xad31ac02u,
+	0xf19df091u,
+	0xc030f935u,
+	0x2000309u,
+	0x290ec413u,
+	0xe28bf091u,
+	0xad31ac22u,
+	0xf01df091u,
+	0xc2414000u,
+	0xa130a04cu,
+	0xd081c020u,
+	0xf091d0a0u,
+	0xf091bc6au,
+	0xf01df091u,
+	0x4000u,
+	0xa130a0bcu,
+	0xc030f091u,
+	0x2000310u,
+	0x4310544u,
+	0xad7eacceu,
+	0xf05df091u,
+	0xad31ac02u,
+	0xf19df091u,
+	0xd124f091u,
+	0x410c03bu,
+	0xe1050300u,
+	0x4204000u,
+	0xa19fa050u,
+	0xd020f091u,
+	0xc525d030u,
+	0xf091f0d1u,
+	0xf0912303u,
+	0xad08ac0au,
+	0xf05dc031u,
+	0xc533c031u,
+	0x2e100200u,
+	0x3322e0cu,
+	0xb274ad31u,
+	0xacc8f01du,
+	0x5142ad31u,
+	0xac920400u,
+	0xf01d0533u,
+	0x19f70u,
+	0x29f56u,
+	0x809f56u,
+	0x2009f5cu,
+	0x4009f60u,
+	0x8009f64u,
+	0x4100a331u,
+	0xa22c4000u,
+	0xa130a0bcu,
+	0xc020f091u,
+	0xd022f091u,
+	0xc531e109u,
+	0xf091c4f3u,
+	0xe073f091u,
+	0xd0a2f091u,
+	0xb26a4100u,
+	0x21e0304u,
+	0xc42be115u,
+	0xf0914000u,
+	0xa19fa050u,
+	0xd020f091u,
+	0xcc3be185u,
+	0xf091c2f3u,
+	0x1072c022u,
+	0xf0910400u,
+	0x500b068u,
+	0x2303ad08u,
+	0xac0af05du,
+	0xc0311270u,
+	0xc0312e10u,
+	0x126c2e0cu,
+	0x4000510u,
+	0xad80ac92u,
+	0xf05df091u,
+	0x4000a19fu,
+	0xa054c020u,
+	0xf239b472u,
+	0x100u,
+	0xc030f091u,
+	0x8c4f091u,
+	0xc23dad39u,
+	0xac00f19du,
+	0xf0912e00u,
+	0x103u,
+	0xc82d0000u,
+	0x140ca21u,
+	0x9fb72e84u,
+	0xcf37ca35u,
+	0x2e882e94u,
+	0x600ad38u,
+	0xacdef01du,
+	0xf091cf08u,
+	0xf09104f0u,
+	0x92281049u,
+	0x8220cf18u,
+	0xf091c188u,
+	0xf091ad43u,
+	0xacd6f05du,
+	0x14480000u,
+	0x1000400u,
+	0x500ad31u,
+	0xac92f01du,
+	0xf091cf08u,
+	0xf09104f0u,
+	0x92280000u,
+	0x8220cf18u,
+	0xf091c188u,
+	0xf091ad43u,
+	0xacd6f05du,
+	0x14480000u,
+	0x1000400u,
+	0x500ad31u,
+	0xac92f01du,
+	0xf0912a08u,
+	0x4002a100u,
+	0xa0000604u,
+	0x7000400u,
+	0x580c080u,
+	0xf0918038u,
+	0xe1232948u,
+	0xc1a0f239u,
+	0xc022f091u,
+	0xc131e195u,
+	0x294ac0a2u,
+	0xf091c131u,
+	0xe18bf091u,
+	0xad32aca8u,
+	0xf01df091u,
+	0xdf77e111u,
+	0xd281ad32u,
+	0xac62f19du,
+	0x10408170u,
+	0xf01d5048u,
+	0xad38ac0au,
+	0xf01df091u,
+	0xf135c03eu,
+	0xf091ffafu,
+	0xb670ad7au,
+	0xaceaf05du,
+	0xf091c1a6u,
+	0xf439f135u,
+	0xf0afc02eu,
+	0xf091c1b6u,
+	0xf091f031u,
+	0xc124f091u,
+	0xc130f091u,
+	0xc184f091u,
+	0xc190f091u,
+	0xc924f091u,
+	0xc930f091u,
+	0xc9a4f091u,
+	0xc9b0f091u,
+	0xcd24f091u,
+	0xcd30f091u,
+	0xad39ac00u,
+	0xf01df091u,
+	0xf135c03eu,
+	0xf091ffafu,
+	0xc188f091u,
+	0xad69acceu,
+	0xf05d1448u,
+	0xf0afc02eu,
+	0xf091f431u,
+	0xad38ac6eu,
+	0xf01df091u,
+	0x2a1080a8u,
+	0x8128e189u,
+	0x848013u,
+	0xe28bf091u,
+	0xad38ac5au,
+	0xf01df091u,
+	0xcfa8f091u,
+	0xc021e18fu,
+	0xf091c008u,
+	0xf0911148u,
+	0x8020e18bu,
+	0xf091ad38u,
+	0xac32f01du,
+	0xf091ce28u,
+	0xf091c021u,
+	0xad33acdcu,
+	0xf11df091u,
+	0x2000304u,
+	0xc111b068u,
+	0x40005140u,
+	0xc288f091u,
+	0x8038e105u,
+	0x1u,
+	0xc090f091u,
+	0xc0c8f091u,
+	0xc0d0f091u,
+	0x2a8c0384u,
+	0x2408113u,
+	0xe205104bu,
+	0x104ab270u,
+	0x31482082u,
+	0xf0915c6cu,
+	0x5e6e3148u,
+	0x208101f0u,
+	0xe50d101fu,
+	0x80a8e187u,
+	0xf091e075u,
+	0xf0918d13u,
+	0xe21bf091u,
+	0xe117f091u,
+	0x114a8030u,
+	0xd081cc07u,
+	0xc031c80du,
+	0xad33ac8eu,
+	0xf01df091u,
+	0xad38ac6eu,
+	0xf01df091u,
+	0x2a8cc288u,
+	0xf0918038u,
+	0xe1050200u,
+	0x201f0c8u,
+	0xf0910011u,
+	0x1052e00u,
+	0x1ffu,
+	0x2ff03ffu,
+	0x2e045c6cu,
+	0x5e6e2108u,
+	0x208101f0u,
+	0xe50d101fu,
+	0x80a8e187u,
+	0xf091e075u,
+	0xf091ad38u,
+	0xac6ef01du,
+	0xf0912a10u,
+	0x80a88128u,
+	0xe189001cu,
+	0x8013e28bu,
+	0xf091ad38u,
+	0xac5af01du,
+	0xf0910002u,
+	0x158ea87u,
+	0x41000002u,
+	0x140b268u,
+	0x2a8c001cu,
+	0x31482082u,
+	0xf0915c6cu,
+	0x5e6e3148u,
+	0x208101f0u,
+	0xe50d101fu,
+	0x80a8e187u,
+	0xf091e075u,
+	0xf091ad38u,
+	0xac6ef01du,
+	0xf091d188u,
+	0xf0918071u,
+	0xe10bf091u,
+	0xad38ac32u,
+	0xf01df091u,
+	0x28079e70u,
+	0xad37ace2u,
+	0xf41df091u,
+	0xc031c234u,
+	0xf091c2b4u,
+	0xf091ad7au,
+	0xac30f05du,
+	0xf091c021u,
+	0xad37acbau,
+	0xf11df631u,
+	0xb2762140u,
+	0x2043f091u,
+	0xc1b6f935u,
+	0xcd34f937u,
+	0x282b2867u,
+	0x80b0e197u,
+	0x282a2866u,
+	0x80b0e18fu,
+	0x28292865u,
+	0x80b0e187u,
+	0xf091cdb4u,
+	0xf937ea85u,
+	0x310011u,
+	0xc096f091u,
+	0xc0310200u,
+	0x340b076u,
+	0xd181c730u,
+	0xf0912806u,
+	0x28651468u,
+	0x29e6ad4eu,
+	0xacf6f05du,
+	0xf091c021u,
+	0xe10bf091u,
+	0xad37ac90u,
+	0xf01df091u,
+	0xc136f931u,
+	0xcea8f091u,
+	0xc171ceb8u,
+	0xf0912302u,
+	0xc031c533u,
+	0x2e282e20u,
+	0x2c260001u,
+	0x2c272303u,
+	0x29102952u,
+	0x23022e34u,
+	0x23032806u,
+	0x23022c06u,
+	0xad48ac84u,
+	0xf05df091u,
+	0xf0d1f091u,
+	0xd188f091u,
+	0x8071e10bu,
+	0xf091ad38u,
+	0xac32f01du,
+	0xf0912807u,
+	0x9f70ad37u,
+	0xace2f41du,
+	0xf091ad36u,
+	0xac12f01du,
+	0x282dd188u,
+	0xf0918071u,
+	0xe10bf091u,
+	0xad38ac32u,
+	0xf01df091u,
+	0x28079f70u,
+	0xad37ace2u,
+	0xf41df091u,
+	0x282d0180u,
+	0x22084a8u,
+	0xad36ac12u,
+	0xf19d8928u,
+	0xad36ac12u,
+	0xf11df091u,
+	0xad7aac30u,
+	0xf05df091u,
+	0xc021ad37u,
+	0xacbaf11du,
+	0xf631b276u,
+	0x21402043u,
+	0xf091c1b6u,
+	0xf935cd34u,
+	0xf937ea85u,
+	0x310011u,
+	0xc096f091u,
+	0xc0310200u,
+	0x340b076u,
+	0xd181c730u,
+	0xf0912806u,
+	0x28651468u,
+	0x29e6ad4eu,
+	0xacf6f05du,
+	0xf091c021u,
+	0xe199f091u,
+	0xc136f931u,
+	0xcea8f091u,
+	0xc171ceb8u,
+	0xf091ad36u,
+	0xac92f01du,
+	0xf091ad37u,
+	0xac90f01du,
+	0xc0310180u,
+	0x8029e187u,
+	0x2934e005u,
+	0xf0912936u,
+	0xf631ad38u,
+	0xac0ac086u,
+	0xf0918038u,
+	0x621f11du,
+	0x14482934u,
+	0xd8a6f091u,
+	0xc033062cu,
+	0xf19d2936u,
+	0xd926f091u,
+	0xf19d0637u,
+	0xd1a6f091u,
+	0xc523e189u,
+	0x1074813cu,
+	0xe127c031u,
+	0x132u,
+	0xd4875143u,
+	0x400053eu,
+	0xc022f091u,
+	0xc021e109u,
+	0xf091f231u,
+	0xe073d683u,
+	0xc032f935u,
+	0xf0d1f091u,
+	0xc0d6f091u,
+	0xf135c1b6u,
+	0xf091c086u,
+	0xf0918438u,
+	0xad37acceu,
+	0xf11df091u,
+	0xc124f091u,
+	0xc439ad37u,
+	0xac36f11du,
+	0xf091287du,
+	0x280b0u,
+	0xe18700b5u,
+	0x1018921u,
+	0xb2765143u,
+	0x160u,
+	0xd483c224u,
+	0xf091d2a4u,
+	0xf091c132u,
+	0xf091d1b2u,
+	0xf091ce24u,
+	0xf091dea4u,
+	0xf091c032u,
+	0xf091d0b2u,
+	0xf091c031u,
+	0xc232f091u,
+	0xc2b2f091u,
+	0xce34f091u,
+	0xceb4f091u,
+	0xc234f091u,
+	0xc2b4f091u,
+	0xc533c031u,
+	0x23022e18u,
+	0x11411272u,
+	0x2e080200u,
+	0x324c585u,
+	0x11422d44u,
+	0x2c43c126u,
+	0xf8390005u,
+	0xc914f091u,
+	0xc184f091u,
+	0x200030cu,
+	0x640ad51u,
+	0xac58f05du,
+	0xf091ad54u,
+	0xac2af05du,
+	0xf091f0d1u,
+	0xf091283du,
+	0x28862302u,
+	0x10184b0u,
+	0xe19b0303u,
+	0x8db2e195u,
+	0xf091f137u,
+	0x2d220055u,
+	0x1582d20u,
+	0xc031c533u,
+	0xe009f091u,
+	0xc031c533u,
+	0x2e202e28u,
+	0x2c260001u,
+	0x2c27c224u,
+	0xf091d2a4u,
+	0xf0912e34u,
+	0xc031c234u,
+	0xf091c2b4u,
+	0xf091c184u,
+	0xf0912c06u,
+	0xad48ac84u,
+	0xf05df091u,
+	0xf0d1f091u,
+	0xc03ef935u,
+	0xffaff137u,
+	0xad7aac96u,
+	0xf05df091u,
+	0xf0afc02eu,
+	0xf4390000u,
+	0x1000200u,
+	0x327ad38u,
+	0xac96f05du,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x1000200u,
+	0x322ad38u,
+	0xac96f05du,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x1000200u,
+	0x329ad38u,
+	0xac96f05du,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x1000200u,
+	0x321ad38u,
+	0xac96f05du,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x1000200u,
+	0x328ad38u,
+	0xac96f05du,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x1000200u,
+	0x323ad38u,
+	0xac96f05du,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x1000200u,
+	0x320ad38u,
+	0xac96f05du,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x1000200u,
+	0x311ad38u,
+	0xac96f05du,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x1000200u,
+	0x327ad38u,
+	0xac96f05du,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x1000200u,
+	0x313ad38u,
+	0xac96f05du,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x1000200u,
+	0x300ad38u,
+	0xac96f05du,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x1000200u,
+	0x325ad38u,
+	0xac96f05du,
+	0xf091f0d1u,
+	0xf0912e0cu,
+	0xb27408c4u,
+	0xf091c23du,
+	0xad39ac00u,
+	0xf19df091u,
+	0x2e000000u,
+	0x103c82du,
+	0x140u,
+	0xca219fb7u,
+	0x2e84c13du,
+	0xe111ca35u,
+	0x124u,
+	0xc0852224u,
+	0x21182002u,
+	0xf091cf37u,
+	0x2e882e90u,
+	0x2e940600u,
+	0xcea8f091u,
+	0x2d220001u,
+	0x110c533u,
+	0xe124f091u,
+	0xc23de195u,
+	0x2e3c8030u,
+	0xc33de105u,
+	0x10184b1u,
+	0xad2dacacu,
+	0xf05d104eu,
+	0xf135c021u,
+	0xe187f091u,
+	0xf0d1f091u,
+	0xdfa4f091u,
+	0xf433ad78u,
+	0xac9cf05du,
+	0x4100e065u,
+	0xf091101fu,
+	0x1f084a8u,
+	0x10084b0u,
+	0xe193f091u,
+	0xad29ac60u,
+	0xf05df091u,
+	0xad39ac7cu,
+	0xf01df091u,
+	0x10284b0u,
+	0xe193f091u,
+	0xad29ac64u,
+	0xf05df091u,
+	0xad39ac7cu,
+	0xf01df091u,
+	0x10184b0u,
+	0xe193f091u,
+	0xad7cac5eu,
+	0xf05df091u,
+	0xad39ac7cu,
+	0xf01df091u,
+	0x10384b0u,
+	0xe18bf091u,
+	0xad7cac62u,
+	0xf05df091u,
+	0xea850b01u,
+	0xb000c01u,
+	0x5600f0d1u,
+	0xf0910000u,
+	0x108ad3au,
+	0xac66b076u,
+	0xd081c0a0u,
+	0xf091c021u,
+	0xf19df091u,
+	0x4000a1a2u,
+	0xa000ea87u,
+	0x4000a1a1u,
+	0xa0f0ad3au,
+	0xac6ad020u,
+	0xf091c523u,
+	0xf11df233u,
+	0x2910b472u,
+	0x2000324u,
+	0xd985e224u,
+	0xf0918034u,
+	0xe117f091u,
+	0xd022f091u,
+	0xc523f11du,
+	0xf2334200u,
+	0xa539a4bcu,
+	0xf015f091u,
+	0xba72f522u,
+	0xf091c0a2u,
+	0xf091c021u,
+	0xf11df431u,
+	0xd622f091u,
+	0xdf73d632u,
+	0xf091de36u,
+	0xf091c424u,
+	0xf091df71u,
+	0xc434f091u,
+	0xc341b274u,
+	0x2000314u,
+	0xd483d583u,
+	0xb0760000u,
+	0x108d081u,
+	0xc022f091u,
+	0xc030f091u,
+	0xc0a2f091u,
+	0xc0b0f091u,
+	0xc122f091u,
+	0xc130f091u,
+	0xc1a2f091u,
+	0xc1b0f091u,
+	0xfcb6f091u,
+	0x88c092u,
+	0xf091c424u,
+	0xf091c021u,
+	0xe195f091u,
+	0xb27ac2f3u,
+	0xb07ac6f1u,
+	0xf01ad78u,
+	0xac9cf05du,
+	0x4100f0d1u,
+	0xf091ad3au,
+	0xac66c031u,
+	0xf01df091u,
+	0x2a9cb276u,
+	0x10cu,
+	0xd483c022u,
+	0xf091d0a2u,
+	0xf091c703u,
+	0xc2092e2cu,
+	0xcca6f091u,
+	0xdd26f091u,
+	0x2a9cc713u,
+	0x4080500u,
+	0x2daac115u,
+	0xe405f091u,
+	0x2d6a292au,
+	0xf1372d34u,
+	0x3a01d4u,
+	0x2d32c328u,
+	0xf0910200u,
+	0x31cc101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0xad29ac0eu,
+	0xf05d2d28u,
+	0xf0d1f091u,
+	0xad11ac66u,
+	0xf01df091u,
+	0x2303ad08u,
+	0xac0af05du,
+	0xc031c226u,
+	0xf0912d12u,
+	0x101u,
+	0x2d10cfa6u,
+	0xf0912d20u,
+	0xce26f091u,
+	0x80302d22u,
+	0xc128f091u,
+	0x2000382u,
+	0xc1212d04u,
+	0x32c06u,
+	0x2012c87u,
+	0xca350600u,
+	0x7002e8cu,
+	0xb2760000u,
+	0x112d483u,
+	0x22242118u,
+	0x2002f091u,
+	0x10110u,
+	0x2000300u,
+	0x2e3cf0d1u,
+	0xf091298eu,
+	0x29582814u,
+	0x84b1c505u,
+	0xc1010200u,
+	0x307c129u,
+	0xc141f0d1u,
+	0xf091ad3cu,
+	0xac78f05du,
+	0xf091ad38u,
+	0xac82ca25u,
+	0xf19df091u,
+	0xad77acd4u,
+	0xf05d4100u,
+	0xa3a2a200u,
+	0x4000a1a2u,
+	0xa004ea8bu,
+	0x4100a3a1u,
+	0xa2f0a1a1u,
+	0xa0f40f00u,
+	0xf091f231u,
+	0xba72f323u,
+	0x220c2134u,
+	0x2003f091u,
+	0xc533d0bau,
+	0xf091d13au,
+	0xf091d1bau,
+	0xf091ad38u,
+	0xac6ef01du,
+	0xf091ad3cu,
+	0xac78f05du,
+	0xf091ca25u,
+	0xe187ad38u,
+	0xac82f01du,
+	0xf635b276u,
+	0xc2f3b076u,
+	0xc6f1d020u,
+	0xf091c523u,
+	0xe113f091u,
+	0xf01f091u,
+	0xad78ac9cu,
+	0xf05d4100u,
+	0xe05ff091u,
+	0xa3a2a200u,
+	0x4000a1a2u,
+	0xa004ea8du,
+	0x4100a3a1u,
+	0xa2f04000u,
+	0xa1a1a0f4u,
+	0xc022f091u,
+	0xc021e12bu,
+	0xc221e10bu,
+	0xf091ad3bu,
+	0xacf8f01du,
+	0xf231d020u,
+	0xf091df73u,
+	0xd030f091u,
+	0xf031d020u,
+	0xf091d032u,
+	0xf091ad78u,
+	0xac9cf05du,
+	0x4100ad38u,
+	0xac6ef01du,
+	0xf091ad3cu,
+	0xac78f05du,
+	0xf091ad38u,
+	0xac82ca25u,
+	0xf11df635u,
+	0xad77acd4u,
+	0xf05d4100u,
+	0xb276c2f3u,
+	0xb076c6f1u,
+	0xf00f091u,
+	0xf231f323u,
+	0x220c2134u,
+	0x2003f091u,
+	0x2910d626u,
+	0xf091c101u,
+	0xc636f091u,
+	0xad38ac6eu,
+	0xf01df091u,
+	0xa3a2a200u,
+	0x4000a1a2u,
+	0xa004ea8bu,
+	0x4100a3a1u,
+	0xa2f0a1a1u,
+	0xa0f4ad3cu,
+	0xacd8e022u,
+	0xf091ca25u,
+	0xf11df091u,
+	0x294cad3cu,
+	0xacbef635u,
+	0xc326f091u,
+	0xc131f19du,
+	0xf091c3a6u,
+	0xf09129ceu,
+	0xad3cacd4u,
+	0xc331f11du,
+	0xf091ad3cu,
+	0xacd8e026u,
+	0xf091ca25u,
+	0xf11df091u,
+	0xad3cac9eu,
+	0xf01df091u,
+	0xf0d1ca25u,
+	0xf0d1ca25u,
+	0xad07ac34u,
+	0x3d0130u,
+	0xc03cf091u,
+	0x4400a9a1u,
+	0xa870e017u,
+	0xb01ad07u,
+	0xac30003du,
+	0x140c03cu,
+	0xf0914400u,
+	0xa9a1a830u,
+	0xb002702u,
+	0x6a006b00u,
+	0x100u,
+	0xcb38f091u,
+	0x13cu,
+	0xcbb8f091u,
+	0xad62acdeu,
+	0xf05df091u,
+	0xf0d1f091u,
+	0x0u,
+	0x0u,
+	0x4400a9a1u,
+	0xa870e011u,
+	0xb010000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8300b00u,
+	0xcba8f091u,
+	0xdb28f091u,
+	0xdf71e113u,
+	0x2701e207u,
+	0xdf73db38u,
+	0xf091cbb8u,
+	0xf091f0d1u,
+	0x2702cbb8u,
+	0xf091c523u,
+	0xe107f091u,
+	0xf0d12702u,
+	0xad3eac7au,
+	0xcf08f091u,
+	0x11384a8u,
+	0xf19df091u,
+	0x80f101cu,
+	0x17080a8u,
+	0x80b0e193u,
+	0xf091ad3cu,
+	0xacdcfa9du,
+	0xf091ad3cu,
+	0xacf2f01du,
+	0xf091ad3eu,
+	0xac00100bu,
+	0x8238f11du,
+	0x4ca98u,
+	0xf0910000u,
+	0x108cbb8u,
+	0xf0916a00u,
+	0x6b002702u,
+	0xad07ac30u,
+	0xea8d003du,
+	0x1f0c03cu,
+	0xf091f0d1u,
+	0xf091003du,
+	0x1e0c13cu,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x4400a9a1u,
+	0xa870e011u,
+	0xb010000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8300b00u,
+	0xad3dac74u,
+	0xf01d2701u,
+	0x1ca98u,
+	0xf0910000u,
+	0x101cbb8u,
+	0xf0916a00u,
+	0x6b002702u,
+	0xad07ac30u,
+	0xea8d003eu,
+	0x150c03cu,
+	0xf091f0d1u,
+	0xf091003eu,
+	0x140c13cu,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x4400a9a1u,
+	0xa870e011u,
+	0xb010000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8300b00u,
+	0x100b8238u,
+	0xe10bf091u,
+	0xad3dac74u,
+	0xf01df091u,
+	0xcba8f091u,
+	0xdf71cbb8u,
+	0xf091e107u,
+	0x2701f0d1u,
+	0x27020000u,
+	0x108cbb8u,
+	0xf0916a00u,
+	0x6b002702u,
+	0xcf08f091u,
+	0x11384a8u,
+	0xe1050210u,
+	0x218010fu,
+	0x80a88120u,
+	0x11481c48u,
+	0x5300ad08u,
+	0xac02f05du,
+	0xf091100bu,
+	0x1148ad07u,
+	0xac30ea8du,
+	0x3e01e0u,
+	0xc03cf091u,
+	0xf0d1f091u,
+	0x3e01d0u,
+	0xc13cf091u,
+	0xf0d1f091u,
+	0x0u,
+	0x4400a9a1u,
+	0xa870e011u,
+	0xb010000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8300b00u,
+	0xcf08f091u,
+	0x11384a8u,
+	0xe197f091u,
+	0x100b0102u,
+	0x84a8e18du,
+	0xf0914000u,
+	0xa13da074u,
+	0xf011f091u,
+	0xcba8f091u,
+	0xdf71cbb8u,
+	0xf091e107u,
+	0x2701f0d1u,
+	0x27020002u,
+	0xca98f091u,
+	0x103u,
+	0xcbb8f091u,
+	0xcf08f091u,
+	0x11384a8u,
+	0xe1050200u,
+	0x208010fu,
+	0x80a88120u,
+	0x11481c48u,
+	0x5300ad08u,
+	0xac02f05du,
+	0xf091100bu,
+	0x11480c01u,
+	0x5e000c01u,
+	0x5800ad08u,
+	0xac02f05du,
+	0xf0910c00u,
+	0x5800ad08u,
+	0xac02f05du,
+	0xf0910c04u,
+	0x5800ad08u,
+	0xac02f05du,
+	0xf091ad07u,
+	0xac30ea8du,
+	0x3f01b0u,
+	0xc03cf091u,
+	0xf0d12702u,
+	0x3f01a0u,
+	0xc13cf091u,
+	0xf0d12702u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x4400a9a1u,
+	0xa870e011u,
+	0xb010000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8300b00u,
+	0xcf08f091u,
+	0x11384a8u,
+	0xe197f091u,
+	0x100b0102u,
+	0x84a8e18du,
+	0xf0914000u,
+	0xa13da074u,
+	0xf011f091u,
+	0xcba8f091u,
+	0xdf71cbb8u,
+	0xf091e107u,
+	0x2701f0d1u,
+	0x2702ad45u,
+	0xacd4f05du,
+	0xf0912604u,
+	0xc025e00u,
+	0x105u,
+	0xcbb8f091u,
+	0x3ca98u,
+	0xf091ad07u,
+	0xac30ea8du,
+	0x400140u,
+	0xc03cf091u,
+	0xf0d12702u,
+	0x400130u,
+	0xc13cf091u,
+	0xf0d12702u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x4400a9a1u,
+	0xa870e011u,
+	0xb010000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8300b00u,
+	0xcf08f091u,
+	0x11384a8u,
+	0xe197f091u,
+	0x100b0102u,
+	0x84a8e00du,
+	0xf0914000u,
+	0xa13da074u,
+	0xf011f091u,
+	0x1022c239u,
+	0xad40ac98u,
+	0xf11d2701u,
+	0x48004904u,
+	0xad08ac02u,
+	0xf05df091u,
+	0x1022cba8u,
+	0xf091df71u,
+	0xcbb8f091u,
+	0xad3dac74u,
+	0xf11df091u,
+	0xf0d12702u,
+	0xca98u,
+	0xf091ad63u,
+	0xac08f01du,
+	0xf0910826u,
+	0x103c1022u,
+	0x140dad8u,
+	0xf0910006u,
+	0xc198f091u,
+	0xc031c238u,
+	0xf0910000u,
+	0x1fd7a68u,
+	0x9ca98u,
+	0xf0916c00u,
+	0x6d002700u,
+	0xad07ac30u,
+	0xea8d0041u,
+	0x100c03cu,
+	0xf091f0d1u,
+	0x27000040u,
+	0x1f0c13cu,
+	0xf091f0d1u,
+	0x27000000u,
+	0x4400a9a1u,
+	0xa870e011u,
+	0xb010000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8300b00u,
+	0xc228f091u,
+	0x12220400u,
+	0x5fcc62bu,
+	0xc131ad42u,
+	0xac6af19du,
+	0xf091f0d1u,
+	0xf091c031u,
+	0xc238f091u,
+	0x1f8u,
+	0x7a68000au,
+	0xca98f091u,
+	0x6c006d00u,
+	0xad07ac30u,
+	0xea8d0041u,
+	0x170c03cu,
+	0xf091f0d1u,
+	0x27000041u,
+	0x160c13cu,
+	0xf091f0d1u,
+	0x27000000u,
+	0x0u,
+	0x0u,
+	0x4400a9a1u,
+	0xa870e011u,
+	0xb010000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8300b00u,
+	0xc228f091u,
+	0x12220400u,
+	0x5fcc62bu,
+	0xc131ad42u,
+	0xac6af19du,
+	0xf091f0d1u,
+	0xf0911022u,
+	0x480e49fcu,
+	0xad08ac02u,
+	0xf05df091u,
+	0x1022c031u,
+	0xc238f091u,
+	0xc8d8f091u,
+	0xcf08f091u,
+	0x11384a8u,
+	0xc001fcu,
+	0xe107f091u,
+	0x1fcu,
+	0x7a68000bu,
+	0xca98f091u,
+	0xc198u,
+	0xf0914100u,
+	0xa302a280u,
+	0x4200a502u,
+	0xa480e028u,
+	0xf091f0a8u,
+	0xf091ad4eu,
+	0xac12f05du,
+	0xf0910000u,
+	0x105cfb8u,
+	0xf091ad4bu,
+	0xacc4f05du,
+	0xf0912605u,
+	0x6c806d00u,
+	0xad07ac30u,
+	0xea8d0042u,
+	0x130c03cu,
+	0xf091f0d1u,
+	0x27000042u,
+	0x120c13cu,
+	0xf091f0d1u,
+	0x27000000u,
+	0x4400a9a1u,
+	0xa870e011u,
+	0xb010000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8300b00u,
+	0xcf08f091u,
+	0x11384a8u,
+	0x47005fcu,
+	0xe107f091u,
+	0x40005fcu,
+	0x100b1148u,
+	0x80501222u,
+	0x8822c228u,
+	0xf091c62bu,
+	0xc131ad45u,
+	0xac06f19du,
+	0xf091f0d1u,
+	0xf091c33bu,
+	0xe1234800u,
+	0x49080000u,
+	0x110ad47u,
+	0xac2af05du,
+	0xf091c228u,
+	0xf0911222u,
+	0x40005f4u,
+	0xc62bc531u,
+	0xf0d1f091u,
+	0xd238f091u,
+	0xc23be19du,
+	0x7c53bu,
+	0xe1970002u,
+	0xc43be191u,
+	0x3c73bu,
+	0xe18b0005u,
+	0xc63be185u,
+	0x60004u,
+	0xd03ef091u,
+	0xffaff188u,
+	0xf091144bu,
+	0x8f438d80u,
+	0x8932a143u,
+	0xa08e4000u,
+	0x4100d581u,
+	0xf002f091u,
+	0x154bf198u,
+	0xf0918f43u,
+	0xd581c042u,
+	0xf0911c48u,
+	0x5900f0afu,
+	0xd02ef091u,
+	0x11489224u,
+	0xe11bf091u,
+	0x96a5e115u,
+	0xf091c23bu,
+	0xe10bf091u,
+	0xad3dac74u,
+	0xf01df091u,
+	0xf0d1f091u,
+	0x9224e18fu,
+	0xf091ad43u,
+	0xacd6f05du,
+	0xf091f0d1u,
+	0xf091ad45u,
+	0xacd4f05du,
+	0xf0910200u,
+	0x310ad43u,
+	0xac40f05du,
+	0xf0912605u,
+	0xad41ac22u,
+	0xf05df091u,
+	0xf0d1f091u,
+	0xd03ef091u,
+	0xffaf2303u,
+	0xad08ac0au,
+	0xf05dc031u,
+	0xf0afd02eu,
+	0xf091c031u,
+	0x2e0c0000u,
+	0x101ea87u,
+	0xf0910000u,
+	0x1000201u,
+	0x300c521u,
+	0x2d44cea8u,
+	0xf0912d22u,
+	0x10110u,
+	0xc5332e3cu,
+	0xad2dacacu,
+	0xf05d0001u,
+	0xea852301u,
+	0x2300f0d1u,
+	0xf0910000u,
+	0x2030007u,
+	0x4050104u,
+	0x2030107u,
+	0x4050206u,
+	0x2030007u,
+	0x4050300u,
+	0x2030007u,
+	0x4050402u,
+	0x2040407u,
+	0x4050508u,
+	0x5050507u,
+	0x4050602u,
+	0x2060607u,
+	0x4080704u,
+	0x2030707u,
+	0x4080808u,
+	0x5050807u,
+	0x408ad00u,
+	0xac54c02cu,
+	0xf091c171u,
+	0xc03cf091u,
+	0x7c198u,
+	0xf0910004u,
+	0xca98f091u,
+	0xad69acb4u,
+	0xf05df091u,
+	0xea8df091u,
+	0xad3cacf2u,
+	0xf05df091u,
+	0xe009ad3cu,
+	0xacdcf05du,
+	0xf0910c02u,
+	0x5600e907u,
+	0xf091e07bu,
+	0xf091ad45u,
+	0xacd4f05du,
+	0xf0916202u,
+	0xc015800u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xc005600u,
+	0x26040c02u,
+	0x5e000000u,
+	0x8230ad44u,
+	0xac8cf19du,
+	0xf0910200u,
+	0x311ad43u,
+	0xac40f05du,
+	0xf091ad55u,
+	0xac7af05du,
+	0xf091ad59u,
+	0xac4cf05du,
+	0xf091ad46u,
+	0xac7ef05du,
+	0xf091100bu,
+	0x8238e113u,
+	0xf0910000u,
+	0x108ad47u,
+	0xac2af05du,
+	0xf091e015u,
+	0xf0910026u,
+	0xc8d8f091u,
+	0xe00bf091u,
+	0xad55ac7au,
+	0xf05df091u,
+	0xc005800u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xcf71200u,
+	0xcf71300u,
+	0xc205900u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xc005900u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xc015c00u,
+	0xc0d5d00u,
+	0xcf08f091u,
+	0x11384a8u,
+	0xe1050200u,
+	0x208010fu,
+	0x80a88120u,
+	0x11481c48u,
+	0x5300ad08u,
+	0xac02f05du,
+	0xf091100bu,
+	0x11480c04u,
+	0x5800ad08u,
+	0xac02f05du,
+	0xf091f0d1u,
+	0xf0910826u,
+	0x103c100bu,
+	0x1148c23bu,
+	0xe18bc33bu,
+	0xad42ac6eu,
+	0xf19df091u,
+	0xd238f091u,
+	0xc188f091u,
+	0x8020e18fu,
+	0xf091ad43u,
+	0xacd6f05du,
+	0x1468f0d1u,
+	0xf091ad3du,
+	0xac74f01du,
+	0xf091ad07u,
+	0xac30ea95u,
+	0xf0910045u,
+	0x190c03cu,
+	0xf0914400u,
+	0xa9a1a830u,
+	0xe011f091u,
+	0x450180u,
+	0xc13cf091u,
+	0x4400a9a1u,
+	0xa8700006u,
+	0xca98f091u,
+	0xc025800u,
+	0x6a006b00u,
+	0x6c006d00u,
+	0xf0d12702u,
+	0x0u,
+	0x4400a9a1u,
+	0xa870e011u,
+	0xb010000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8300b00u,
+	0xe88d0101u,
+	0x80e101cu,
+	0x84b0e107u,
+	0xf091f0d1u,
+	0x2702c2c8u,
+	0xf0910008u,
+	0x1c485c00u,
+	0xc065800u,
+	0xcac8f091u,
+	0x14080b0u,
+	0xe10bf091u,
+	0xad41ac92u,
+	0xf01df091u,
+	0xad41ac22u,
+	0xf01df091u,
+	0xad46ac4au,
+	0xf05df091u,
+	0xc015e00u,
+	0x6301ad08u,
+	0xac02f05du,
+	0xf0916300u,
+	0xad08ac02u,
+	0xf05df091u,
+	0x48ff49ffu,
+	0x6304ad08u,
+	0xac02f05du,
+	0xf0916318u,
+	0xc005e00u,
+	0x2000304u,
+	0xd338f091u,
+	0x8c898u,
+	0xf0910000u,
+	0xc1d8f091u,
+	0x8030c2d8u,
+	0xf0910c01u,
+	0x5c000000u,
+	0x104c938u,
+	0xf0910000u,
+	0x102c9b8u,
+	0xf0910826u,
+	0x103c48ffu,
+	0x49ff0c90u,
+	0x5200f091u,
+	0xf091f0d1u,
+	0xf091c031u,
+	0xc5332e28u,
+	0x2e2c2d2au,
+	0x2d322d36u,
+	0x2d30b234u,
+	0x4100f133u,
+	0x22282110u,
+	0x2003f091u,
+	0x6201ad08u,
+	0xac02f05du,
+	0xf091ad08u,
+	0xac02f05du,
+	0xf091f0d1u,
+	0xf0914202u,
+	0xa500a400u,
+	0x6040700u,
+	0x4000580u,
+	0xea850220u,
+	0x200c084u,
+	0xf0918038u,
+	0xe10df091u,
+	0x12080a8u,
+	0x8130e117u,
+	0xf091df77u,
+	0xe10dda85u,
+	0xe1e51042u,
+	0x8170e05fu,
+	0x5248f0d1u,
+	0xf091c084u,
+	0xf09101bfu,
+	0x80a8c094u,
+	0xf091c124u,
+	0xf091c021u,
+	0xe113f031u,
+	0xc1a0f091u,
+	0xcf39e109u,
+	0xf091c031u,
+	0xc134f091u,
+	0xf135c03eu,
+	0xf091ffafu,
+	0xd03ef091u,
+	0xffafe03eu,
+	0xf091ffafu,
+	0xf03ef091u,
+	0xffafc031u,
+	0x2000311u,
+	0xad7bac6eu,
+	0xf05df091u,
+	0xf0aff02eu,
+	0xf091f0afu,
+	0xe02ef091u,
+	0xf0afd02eu,
+	0xf091f0afu,
+	0xc02ef091u,
+	0xf431ad46u,
+	0xaca6f01du,
+	0xf091a102u,
+	0xa058ea87u,
+	0x4000a102u,
+	0xa040d081u,
+	0xc020f091u,
+	0xd0a0f091u,
+	0xc173c079u,
+	0xc030f091u,
+	0xd0b0f091u,
+	0xf0d1f091u,
+	0xf0d1f091u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x4000a100u,
+	0xa0c0e011u,
+	0xb010000u,
+	0x0u,
+	0x4000a100u,
+	0xa0800b00u,
+	0xc820f091u,
+	0xca20f091u,
+	0xc021ad47u,
+	0xace0f11du,
+	0xf0910000u,
+	0x128d081u,
+	0xb2705140u,
+	0xc4f1c0f3u,
+	0xf01f091u,
+	0xf431c724u,
+	0xf091c021u,
+	0xe10bc031u,
+	0xc734f091u,
+	0xe00df091u,
+	0xf135ad78u,
+	0xac9cf05du,
+	0x4100c624u,
+	0xf091c021u,
+	0xe10bbc68u,
+	0xc6a4f091u,
+	0xf05df091u,
+	0xad47ac78u,
+	0xa100a0c0u,
+	0xfa9d4000u,
+	0xa100a080u,
+	0xf01df091u,
+	0xc820f091u,
+	0xc021ad48u,
+	0xac34f11du,
+	0xf0910208u,
+	0x3004200u,
+	0xa59fa438u,
+	0xc024f091u,
+	0xc511f29du,
+	0x120u,
+	0xd081b270u,
+	0x5140c4f1u,
+	0xc0f3c020u,
+	0xf091df71u,
+	0xe193f091u,
+	0xf01f091u,
+	0xad78ac9cu,
+	0xf05d4100u,
+	0xe00ff091u,
+	0x8c1ad78u,
+	0xacb8f05du,
+	0xf09108c2u,
+	0xf0d1610au,
+	0x296eb06au,
+	0x2965504bu,
+	0x9f71e439u,
+	0x9f70e419u,
+	0xf2212d30u,
+	0xb2702238u,
+	0x21082002u,
+	0xf0911340u,
+	0x2ce51270u,
+	0xf0d12d6eu,
+	0xdfa4f091u,
+	0xf433b074u,
+	0xc523e109u,
+	0x5ccf1u,
+	0xe05b2d30u,
+	0xad7cacc0u,
+	0xf05d00a3u,
+	0xad7cacc0u,
+	0xf05d00a4u,
+	0xc1a6f439u,
+	0xf1c4f091u,
+	0x28668c93u,
+	0x9f73e289u,
+	0x84a1ad48u,
+	0xac7cf41du,
+	0xb074e10bu,
+	0xf321f221u,
+	0xf221e005u,
+	0x2000202u,
+	0x2d700400u,
+	0x502114bu,
+	0x8030ca01u,
+	0x4100a39fu,
+	0xa238f022u,
+	0xf091ce17u,
+	0xe28b2238u,
+	0xad7cacc0u,
+	0xf05d00a1u,
+	0x2108b270u,
+	0x2002f091u,
+	0x11402c65u,
+	0x12702d6eu,
+	0x2aa8c325u,
+	0xe12b2a3cu,
+	0xcd17c81du,
+	0xe211f091u,
+	0x2ea8ad48u,
+	0xac38f05du,
+	0x2930e06du,
+	0x2a3c2aa8u,
+	0x2a38c703u,
+	0xc2092e38u,
+	0x2a3cc713u,
+	0xc2192e3cu,
+	0xee86f091u,
+	0x8172ee96u,
+	0xf0912827u,
+	0x8020e117u,
+	0x88520000u,
+	0x124c085u,
+	0x2d041342u,
+	0x89232c83u,
+	0x8030e017u,
+	0x2c24b076u,
+	0x112u,
+	0xc0812d04u,
+	0x13408923u,
+	0x2c830004u,
+	0x2c24ca35u,
+	0x2d982db2u,
+	0x2ab4c325u,
+	0xe1af2a3cu,
+	0x2932cab6u,
+	0xf091c1a6u,
+	0xf039c180u,
+	0xf0910103u,
+	0x80b0e195u,
+	0xf0912802u,
+	0x10284a8u,
+	0xe18bf091u,
+	0xad54ac2au,
+	0xf05df091u,
+	0xf0d1f091u,
+	0xc517c01du,
+	0xe20b2e8cu,
+	0x2abc2e8cu,
+	0xe0092e34u,
+	0xc031c533u,
+	0x2e342ab8u,
+	0x2e88c121u,
+	0x2e14e113u,
+	0x28a4ad4au,
+	0xaca8f01du,
+	0x2ab42ab4u,
+	0xcb25e185u,
+	0x80300040u,
+	0x89202c82u,
+	0xc0312d00u,
+	0x2d1cb076u,
+	0x140d081u,
+	0xc720f091u,
+	0xc021e10fu,
+	0x781ad77u,
+	0xacd4f05du,
+	0x4100e007u,
+	0x780f137u,
+	0x2d1c2a34u,
+	0xc023e18du,
+	0x2a20c021u,
+	0xe107f091u,
+	0x2e180781u,
+	0x104f2c07u,
+	0xb270b870u,
+	0xc126f039u,
+	0x2926c03eu,
+	0xf091ffafu,
+	0x2a0c2a94u,
+	0xc507c209u,
+	0xf2a0f091u,
+	0xe115ca35u,
+	0xc713c219u,
+	0x2da629b2u,
+	0xe10fc175u,
+	0x2db2e071u,
+	0x29a6c523u,
+	0xe10d29b2u,
+	0xc175c713u,
+	0xe205f091u,
+	0xe1f72db2u,
+	0xf0afc02eu,
+	0xf0912d26u,
+	0x290e2956u,
+	0xc5010003u,
+	0x81a8e11du,
+	0xf091e2a0u,
+	0xf091df75u,
+	0xc62b0000u,
+	0x104c013u,
+	0xe28bf091u,
+	0xad52ac2au,
+	0xf01df091u,
+	0x22002120u,
+	0x2003f091u,
+	0x8c1f139u,
+	0xb270ba70u,
+	0xf121d020u,
+	0xf091f123u,
+	0xf4230f00u,
+	0xc523e193u,
+	0xf13bdfaau,
+	0xf091b26au,
+	0x4100b072u,
+	0xf1210f10u,
+	0xe0008c2u,
+	0xad49ac50u,
+	0xf01df091u,
+	0xad48ac38u,
+	0xf05d2930u,
+	0x2a3cc517u,
+	0xc01de40bu,
+	0x2e942abcu,
+	0x2e94e009u,
+	0x2e34c031u,
+	0xc5332e34u,
+	0x2ab82e90u,
+	0x29a40580u,
+	0x92a4c121u,
+	0xad49acaeu,
+	0xf11d124cu,
+	0x50292a4u,
+	0x28a40321u,
+	0x89a22ca4u,
+	0xad48ac38u,
+	0xf05d2930u,
+	0xad49acaeu,
+	0xf01d124cu,
+	0xf0d1f091u,
+	0x23022d1au,
+	0x10702d18u,
+	0x4100a39fu,
+	0xa238e022u,
+	0xf0910000u,
+	0x102c211u,
+	0xe40bf091u,
+	0xad7cacc0u,
+	0xf05d00a2u,
+	0xb2760000u,
+	0x112d483u,
+	0x22202118u,
+	0x2002f091u,
+	0x2ce02df6u,
+	0xcf372df4u,
+	0x2dc02ddcu,
+	0x2dcc2dceu,
+	0x2c2c02u,
+	0x2c86b076u,
+	0x140u,
+	0xd081c720u,
+	0xf091c021u,
+	0xe10f0381u,
+	0xad77acd4u,
+	0xf05d4100u,
+	0xe0070380u,
+	0xf1372d1cu,
+	0x2918c021u,
+	0xe105f091u,
+	0x3812cc7u,
+	0x120u,
+	0xc0812d04u,
+	0x10402c03u,
+	0xb2702200u,
+	0x21382003u,
+	0xf091b270u,
+	0xc126fa39u,
+	0xcf2af039u,
+	0x8c1f133u,
+	0xb270ba70u,
+	0xf121d020u,
+	0xf091f023u,
+	0xf4230f00u,
+	0xc523e193u,
+	0xf13bdfaau,
+	0xf091b26au,
+	0x4100b072u,
+	0xf1210f10u,
+	0xe0008c2u,
+	0xf0d1f091u,
+	0x2302c031u,
+	0x14681668u,
+	0xf631c0c8u,
+	0xf0911748u,
+	0x4000a1a0u,
+	0xa0fac1d0u,
+	0xf091c0d0u,
+	0xf0910403u,
+	0xad4eacf6u,
+	0xf05df091u,
+	0xb87000a0u,
+	0x1fa2d04u,
+	0x2002c83u,
+	0xc0312d18u,
+	0x2d002d1cu,
+	0x2a10312u,
+	0x1008030u,
+	0x2e080200u,
+	0x3100003u,
+	0xad51ac58u,
+	0xf05df091u,
+	0xea852301u,
+	0x2300f0d1u,
+	0xf0912302u,
+	0x2d1a1070u,
+	0x2d180000u,
+	0x124d483u,
+	0x22202118u,
+	0x2002f091u,
+	0x812c20u,
+	0x92c29u,
+	0xff01ffu,
+	0x2d32c031u,
+	0x2d342d36u,
+	0x2c282d2eu,
+	0x2d002d1cu,
+	0x2d0c2d0eu,
+	0x402c02u,
+	0x2c86b076u,
+	0x140u,
+	0xd081c720u,
+	0xf091c021u,
+	0xe10f0381u,
+	0xad77acd4u,
+	0xf05d4100u,
+	0xe0070380u,
+	0xf1372d1cu,
+	0x2918c021u,
+	0xe105f091u,
+	0x3812cc7u,
+	0x120u,
+	0xc0812d04u,
+	0xee86f091u,
+	0x8172ee96u,
+	0xf0918852u,
+	0x10408120u,
+	0x2c03b270u,
+	0x22002138u,
+	0x2003f091u,
+	0xb270c126u,
+	0xf03908c1u,
+	0xf133b270u,
+	0xba70f121u,
+	0xd020f091u,
+	0xf023f423u,
+	0xf00c523u,
+	0xe193f13bu,
+	0xdfaaf091u,
+	0xb26a4100u,
+	0xb072f121u,
+	0xf100e00u,
+	0x8c20000u,
+	0x101cab6u,
+	0xf091c1a6u,
+	0xf039c180u,
+	0xf0910103u,
+	0x80b0e18bu,
+	0xf091ad54u,
+	0xac2af05du,
+	0xf091f0d1u,
+	0xf0912302u,
+	0x2c862d1au,
+	0x10702d18u,
+	0xb2760000u,
+	0x112d483u,
+	0x22202118u,
+	0x2002f091u,
+	0x842c20u,
+	0x192c29u,
+	0xff01ffu,
+	0x2d32c031u,
+	0x2d342d36u,
+	0x2c282d2eu,
+	0x2d1c2d00u,
+	0x4100a39fu,
+	0xa23ac8a6u,
+	0xf091c132u,
+	0xf0910200u,
+	0x30c0080u,
+	0x1002e0cu,
+	0x12721141u,
+	0x80302e08u,
+	0x242c02u,
+	0xb0760000u,
+	0x140d081u,
+	0xc720f091u,
+	0xc021e10fu,
+	0x381ad77u,
+	0xacd4f05du,
+	0x4100e007u,
+	0x380f137u,
+	0x2d1c2918u,
+	0xc021e105u,
+	0xf0910381u,
+	0x2cc70000u,
+	0x120c081u,
+	0x2d04ee86u,
+	0xf0918172u,
+	0xee96f091u,
+	0x88521040u,
+	0x81202c03u,
+	0xb2702200u,
+	0x21382003u,
+	0xf091b270u,
+	0xc126f039u,
+	0x8c1f133u,
+	0xb270ba70u,
+	0xf121d020u,
+	0xf091f023u,
+	0xf4230f00u,
+	0xc523e193u,
+	0xf13bdfaau,
+	0xf091b26au,
+	0x4100b072u,
+	0xf1210f10u,
+	0xe0008c2u,
+	0x101u,
+	0xcab6f091u,
+	0x28060103u,
+	0x80b0e18bu,
+	0xf091ad54u,
+	0xac2af05du,
+	0xf091f0d1u,
+	0xf091f0d1u,
+	0xf091f0d1u,
+	0xf091f0d1u,
+	0xf091f0d1u,
+	0xf0910902u,
+	0x4010000u,
+	0x120d483u,
+	0xd8850280u,
+	0xc002f091u,
+	0xd004f091u,
+	0x89288929u,
+	0xad4eac96u,
+	0xf11df091u,
+	0xf133c03eu,
+	0xf091ffafu,
+	0xad4eacf6u,
+	0xf05df091u,
+	0xc1a4f091u,
+	0x2080300u,
+	0xc511e407u,
+	0xf0910008u,
+	0x100c2b0u,
+	0xf091c2a4u,
+	0xf091c330u,
+	0xf091f0afu,
+	0xc02ef091u,
+	0xf231c1a0u,
+	0xf091cf39u,
+	0xe1a5f091u,
+	0x2800300u,
+	0xc121c1b0u,
+	0xf091f133u,
+	0xc03ef091u,
+	0xffafad4eu,
+	0xacacf05du,
+	0xf091f0afu,
+	0xc02ef091u,
+	0xf2310000u,
+	0x110d483u,
+	0xd8858174u,
+	0xad4eac1eu,
+	0xf59df091u,
+	0xf0d1f091u,
+	0x134cea8du,
+	0x8d434100u,
+	0xa39ea20eu,
+	0xe00b8932u,
+	0x4100a39eu,
+	0xa2168932u,
+	0xd583c022u,
+	0xf091c021u,
+	0xe18bf231u,
+	0x105u,
+	0xf0d1d021u,
+	0x8bb68935u,
+	0x31f8d2bu,
+	0x8932c543u,
+	0xd583c022u,
+	0xf091c0b0u,
+	0xf091c032u,
+	0xf931f0d1u,
+	0xc031134cu,
+	0xea8d8d43u,
+	0x4100a39eu,
+	0xa20ee00bu,
+	0x89324100u,
+	0xa39ea216u,
+	0x8932d583u,
+	0xc022f091u,
+	0xc021e18bu,
+	0xf2310000u,
+	0x105f0d1u,
+	0xc0218bb6u,
+	0x8935031fu,
+	0x8d2b8932u,
+	0xc543d583u,
+	0xc022f091u,
+	0xc021ad4fu,
+	0xac6af11du,
+	0xf031ad4fu,
+	0xac5ece20u,
+	0xf091dea0u,
+	0xf091c733u,
+	0xf19d86b1u,
+	0xf19df091u,
+	0xf131d220u,
+	0xf091f0d1u,
+	0xc031c0a0u,
+	0xf091ad4fu,
+	0xac36f01du,
+	0xc021ad77u,
+	0xacd4f05du,
+	0x4100e18bu,
+	0xba700000u,
+	0x118f0d1u,
+	0xf091b27au,
+	0x21402043u,
+	0xf091ad77u,
+	0xacd4f05du,
+	0x4100e18fu,
+	0xb270ad78u,
+	0xac9cf05du,
+	0x4100e05bu,
+	0xf091c23au,
+	0xf0912140u,
+	0x2043f091u,
+	0xff01ffu,
+	0xc030f091u,
+	0xc0b0f091u,
+	0xc130f091u,
+	0xc1b0f091u,
+	0xc230f091u,
+	0xc2b0f091u,
+	0xc330f091u,
+	0xc3b0f091u,
+	0xc430f091u,
+	0xc4b0f091u,
+	0xc530f091u,
+	0xc5b0f091u,
+	0xc630f091u,
+	0xc6b0f091u,
+	0xc730f091u,
+	0xc7b0f091u,
+	0x4400a9a1u,
+	0xa870ea89u,
+	0xf0914400u,
+	0xa9a1a830u,
+	0xcac8f091u,
+	0x14080b0u,
+	0xe131f091u,
+	0x100u,
+	0xc1baf091u,
+	0x104d8026u,
+	0xe119104fu,
+	0xc068f091u,
+	0x8035e18du,
+	0xf091c0a8u,
+	0xf0918036u,
+	0xe105104fu,
+	0xd0c8u,
+	0xf091c3bau,
+	0xf0918030u,
+	0x114dce3au,
+	0xf091febau,
+	0xf0910000u,
+	0x184c2bau,
+	0xf0910000u,
+	0x101c33au,
+	0xf0910000u,
+	0x1c8ea87u,
+	0xf0910000u,
+	0x188cfbau,
+	0xf091104cu,
+	0x9f70e12du,
+	0x9f70e129u,
+	0x9f70ad51u,
+	0xac26f11du,
+	0xf091c22au,
+	0xf091ad78u,
+	0xac9cf05du,
+	0x4100f13bu,
+	0xad78ac9cu,
+	0xf05d4100u,
+	0x105u,
+	0xf0d1d031u,
+	0xad77acd4u,
+	0xf05d4100u,
+	0xe1a1b270u,
+	0xc22af091u,
+	0xad78ac9cu,
+	0xf05d4100u,
+	0xf13bad78u,
+	0xac9cf05du,
+	0x41000000u,
+	0x118f0d1u,
+	0xd031cf3au,
+	0xf0912140u,
+	0x2043f091u,
+	0xc1aaf091u,
+	0x2000301u,
+	0xc121c1bau,
+	0xf0914400u,
+	0xa9a1a870u,
+	0xea89f091u,
+	0x4400a9a1u,
+	0xa830cac8u,
+	0xf0910140u,
+	0x80b0e111u,
+	0xc031104fu,
+	0xd0c8f091u,
+	0xc3b0f091u,
+	0x100u,
+	0xc1b0f091u,
+	0xc22af091u,
+	0xc230f091u,
+	0xcf30f93bu,
+	0x1c0u,
+	0xea87f091u,
+	0x180u,
+	0xcfb0f091u,
+	0xb07af0d1u,
+	0xc031b07au,
+	0xf0d1c031u,
+	0xcf24f091u,
+	0xc021e10bu,
+	0xf091ad78u,
+	0xac9cf05du,
+	0x4100c224u,
+	0xf091ad78u,
+	0xac9cf05du,
+	0x4100f135u,
+	0xad78ac9cu,
+	0xf05d4100u,
+	0xf0d1f091u,
+	0x2c060080u,
+	0x1002e0cu,
+	0xf1372d1cu,
+	0xc021e115u,
+	0x381b076u,
+	0x140u,
+	0xd081c720u,
+	0xf091c021u,
+	0xe111f131u,
+	0xc0312d1cu,
+	0xad77acd4u,
+	0xf05d4100u,
+	0x3802918u,
+	0xc021e105u,
+	0xc0310381u,
+	0x2cc72d00u,
+	0x2d142d16u,
+	0xf137c021u,
+	0xe1050020u,
+	0x104e2c02u,
+	0xb2702200u,
+	0x21202003u,
+	0xf091b270u,
+	0xb07808c1u,
+	0xf133b270u,
+	0xba70f121u,
+	0xd020f091u,
+	0xf023f423u,
+	0xf00c523u,
+	0xe193f13bu,
+	0xdfaaf091u,
+	0xb26a4100u,
+	0xb072f121u,
+	0xf100e00u,
+	0x8c2f137u,
+	0xc021e187u,
+	0xf091f0d1u,
+	0xf091c1c6u,
+	0xf0910103u,
+	0x80b0e11du,
+	0x28020101u,
+	0x84a80000u,
+	0x101e109u,
+	0xf091caa6u,
+	0xf091c171u,
+	0xcab6f091u,
+	0xe013f091u,
+	0x10284a8u,
+	0xe18bf091u,
+	0xad54ac2au,
+	0xf05df091u,
+	0xf0d1f091u,
+	0xad52u,
+	0xacda2a0cu,
+	0xc021f19du,
+	0x104u,
+	0xc911f21du,
+	0xf091ad53u,
+	0xac4ef11du,
+	0xf091ad52u,
+	0xac28c03cu,
+	0xf933fe2fu,
+	0x2802c01eu,
+	0xf0912918u,
+	0xc09ef091u,
+	0x291cc11eu,
+	0xf0912807u,
+	0xc19ef091u,
+	0x802c07u,
+	0xc0312d18u,
+	0x2d1c2a14u,
+	0xca350600u,
+	0x704c713u,
+	0xc2192e14u,
+	0xad77acd4u,
+	0xf05d4100u,
+	0xb2702200u,
+	0x21202003u,
+	0xf091c00eu,
+	0xf091017fu,
+	0x80a80121u,
+	0x80a02c02u,
+	0xc0aef091u,
+	0x2d18c12eu,
+	0xf0912d1cu,
+	0xc1aef091u,
+	0x2c07f22fu,
+	0x2a102a94u,
+	0xc703c209u,
+	0x2e08c031u,
+	0xc5332e14u,
+	0x3042e0cu,
+	0xc02cf239u,
+	0x22002120u,
+	0x2003f091u,
+	0xad53acb8u,
+	0xf01dad52u,
+	0xac28c03cu,
+	0xf9332a0cu,
+	0xca350600u,
+	0x704c713u,
+	0xc2192e0cu,
+	0x2a08c703u,
+	0xc2092e08u,
+	0x2802c01eu,
+	0xf0910121u,
+	0x80a02c02u,
+	0x22002120u,
+	0x2003f091u,
+	0xc00ef091u,
+	0x13f80a8u,
+	0x10280a0u,
+	0x2c020080u,
+	0x2c07ca35u,
+	0x2d982d9cu,
+	0xcf372e94u,
+	0x7042e8cu,
+	0x2a08c713u,
+	0xc2192e08u,
+	0xad77acd4u,
+	0xf05d4100u,
+	0xb2702200u,
+	0x21202003u,
+	0xf091ad53u,
+	0xacb8f01du,
+	0xf091ad52u,
+	0xac28c03cu,
+	0xf9332802u,
+	0xc01ef091u,
+	0x17f80a8u,
+	0x12180a0u,
+	0x2c022a14u,
+	0x2e0c2a10u,
+	0x2a882e08u,
+	0x2e90c031u,
+	0xc5332e14u,
+	0x22002120u,
+	0x2003f091u,
+	0xc00ef091u,
+	0x1c080a8u,
+	0x10280a0u,
+	0x2c02c031u,
+	0x2d182d1cu,
+	0x802c07u,
+	0x2a102e08u,
+	0xc031c533u,
+	0x2e140304u,
+	0x2e0cad77u,
+	0xacd4f05du,
+	0x4100b270u,
+	0x22002120u,
+	0x2003f091u,
+	0xb870c126u,
+	0xf03908c1u,
+	0xf139b270u,
+	0xba70f121u,
+	0xd020f091u,
+	0xf123f423u,
+	0xf00c523u,
+	0xe193f13bu,
+	0xdfaaf091u,
+	0xb26a4100u,
+	0xb072f121u,
+	0xf100e00u,
+	0x8c2ad52u,
+	0xac28c02cu,
+	0xf839c126u,
+	0xf03908c1u,
+	0xf139b270u,
+	0xba70f121u,
+	0xd020f091u,
+	0xf123f423u,
+	0xf00c523u,
+	0xe193f13bu,
+	0xdfaaf091u,
+	0xb26a4100u,
+	0xb072f121u,
+	0xf100e00u,
+	0x8c2ad49u,
+	0xac50f01du,
+	0xf091c0c6u,
+	0xf0918170u,
+	0xc0d6f091u,
+	0xc446f091u,
+	0x10280a0u,
+	0xc456f091u,
+	0xc031cb36u,
+	0xf091cbb6u,
+	0xf091c1a6u,
+	0xf439eb44u,
+	0xf0912827u,
+	0x8020e187u,
+	0xf091e6c6u,
+	0xf091803au,
+	0xe1850200u,
+	0x210c086u,
+	0xf09101efu,
+	0x80a88120u,
+	0xc096f091u,
+	0x8638e10fu,
+	0xf0910000u,
+	0x102cc36u,
+	0xf091f0d1u,
+	0xf091ff44u,
+	0xf0910207u,
+	0x8daa8932u,
+	0xc5434100u,
+	0xa354a2a4u,
+	0xd583d022u,
+	0xf091bc6au,
+	0xf01df091u,
+	0x5554550au,
+	0x555454b4u,
+	0x54ca54e2u,
+	0x55545554u,
+	0xc0c6f091u,
+	0x9f70ad55u,
+	0xac5af19du,
+	0xc031cc36u,
+	0xf091f0d1u,
+	0xf091c6c6u,
+	0xf0910110u,
+	0x84a8ad55u,
+	0xac5af19du,
+	0xc031cc36u,
+	0xf091f0d1u,
+	0xf091c0c6u,
+	0xf0910101u,
+	0x84a8e107u,
+	0x8170c0d6u,
+	0xf091c6c6u,
+	0xf0910110u,
+	0x84a8ad55u,
+	0xac5af19du,
+	0xc031cc36u,
+	0xf091f0d1u,
+	0xf091d124u,
+	0xf0910000u,
+	0x110c129u,
+	0xad55ac42u,
+	0xf11df091u,
+	0xc0c6f091u,
+	0x9f70f19du,
+	0xf091c224u,
+	0xf091d2a4u,
+	0xf0912302u,
+	0x2e340400u,
+	0x5000600u,
+	0x700ad25u,
+	0xacc4f01du,
+	0x100c031u,
+	0xcc36f091u,
+	0xcb44f091u,
+	0xc6d6f091u,
+	0xf0d1f091u,
+	0xf0d1f091u,
+	0xf631c086u,
+	0xf0914400u,
+	0xa9a1a870u,
+	0x8538e18bu,
+	0xb014400u,
+	0xa9a1a830u,
+	0xb00ad27u,
+	0xac68f01du,
+	0xf091a500u,
+	0xa4c0ea87u,
+	0x4200a500u,
+	0xa48008c1u,
+	0x2000318u,
+	0xd1855042u,
+	0xb2705140u,
+	0xc4f1c0f3u,
+	0xc020f091u,
+	0xc021e115u,
+	0xf091c022u,
+	0xf091c021u,
+	0xe19df091u,
+	0xad7cacc0u,
+	0xf05d00a5u,
+	0x108u,
+	0xc413e2d1u,
+	0xf091ad56u,
+	0xac4af01du,
+	0xf091f135u,
+	0xc03ef091u,
+	0xffafd03eu,
+	0xf091ffafu,
+	0xf11f091u,
+	0xf4310200u,
+	0x30cb074u,
+	0x5042b270u,
+	0x5140c4f1u,
+	0x110u,
+	0xd483d583u,
+	0xc020f091u,
+	0xc021e11bu,
+	0xf091c022u,
+	0xf091c021u,
+	0xe1a7f091u,
+	0x104u,
+	0xc413ad55u,
+	0xacdef29du,
+	0xf091f0afu,
+	0xd02ef091u,
+	0xf0afc02eu,
+	0xf091f431u,
+	0xad55ac8cu,
+	0xf01df091u,
+	0xf01f091u,
+	0xf031c720u,
+	0xf091c021u,
+	0xe18df091u,
+	0xf131ad78u,
+	0xac9cf05du,
+	0x4100ad55u,
+	0xacdef01du,
+	0xf091a100u,
+	0xa0c0ea87u,
+	0x4000a100u,
+	0xa080ca20u,
+	0xf091c021u,
+	0xad56aca8u,
+	0xf11df091u,
+	0x128u,
+	0xd081b270u,
+	0x5140c4f1u,
+	0xc0f30f01u,
+	0xf091f431u,
+	0xc724f091u,
+	0xc021e10bu,
+	0xc031c734u,
+	0xf091e00du,
+	0xf091f135u,
+	0xad78ac9cu,
+	0xf05d4100u,
+	0xad56ac56u,
+	0xa100a0c0u,
+	0xfa9d4000u,
+	0xa100a080u,
+	0xf01df091u,
+	0x8c2f0d1u,
+	0xf091f535u,
+	0x8c10901u,
+	0x4200a500u,
+	0xa4800200u,
+	0x318d185u,
+	0x5042c120u,
+	0xf091c021u,
+	0xad57ac08u,
+	0xf11df091u,
+	0xd03ef091u,
+	0xffafd120u,
+	0xf091c020u,
+	0xf091f231u,
+	0xc231e191u,
+	0xf091f0afu,
+	0xd02ef091u,
+	0xad57ac2cu,
+	0xf01df091u,
+	0xc022f091u,
+	0xdf73ad56u,
+	0xace0f19du,
+	0xf231f0afu,
+	0xd02ef091u,
+	0x108u,
+	0xc413ad56u,
+	0xacbef29du,
+	0xf0914200u,
+	0xa500a4c0u,
+	0xad56acbau,
+	0xf59df091u,
+	0xad57ac58u,
+	0xf01df091u,
+	0xb4705240u,
+	0xd120f091u,
+	0xdf73e10du,
+	0x106cc022u,
+	0xf091df73u,
+	0xe1f9f231u,
+	0xc0b0f091u,
+	0xe030f091u,
+	0xb2705140u,
+	0xc4f1c0f3u,
+	0xf11f091u,
+	0xf4350200u,
+	0x30cb074u,
+	0x5042b270u,
+	0x5140c4f1u,
+	0x110u,
+	0xd483d583u,
+	0xc020f091u,
+	0xc021e11bu,
+	0xf091c022u,
+	0xf091c021u,
+	0xe197f091u,
+	0x104u,
+	0xc413ad57u,
+	0xac5ef29du,
+	0xf09108c2u,
+	0xf0d1f091u,
+	0xf01f091u,
+	0xf031c720u,
+	0xf091c021u,
+	0xe18df091u,
+	0xf131ad78u,
+	0xac9cf05du,
+	0x4100ad57u,
+	0xac5ef01du,
+	0xf091f535u,
+	0x8c10901u,
+	0x4200a500u,
+	0xa4800200u,
+	0x318d185u,
+	0x5042c120u,
+	0xf091c021u,
+	0xad58ac14u,
+	0xf11df091u,
+	0xd03ef091u,
+	0xffafd120u,
+	0xf091c020u,
+	0xf091f231u,
+	0xc231e191u,
+	0xf091f0afu,
+	0xd02ef091u,
+	0xad58ac38u,
+	0xf01df091u,
+	0xc022f091u,
+	0xdf73ad57u,
+	0xacecf19du,
+	0xf231f0afu,
+	0xd02ef091u,
+	0x108u,
+	0xc413ad57u,
+	0xaccaf29du,
+	0xf0914200u,
+	0xa500a4c0u,
+	0xad57acc6u,
+	0xf59df091u,
+	0xad58ac64u,
+	0xf01df091u,
+	0xb4705240u,
+	0xd120f091u,
+	0xdf73e10du,
+	0x106cc022u,
+	0xf091df73u,
+	0xe1f9f231u,
+	0xc0b0f091u,
+	0xe030f091u,
+	0xb2705140u,
+	0xc4f1c0f3u,
+	0xf11f091u,
+	0x8c2f0d1u,
+	0xf091f135u,
+	0xf13708c1u,
+	0xe124f091u,
+	0xca25ad58u,
+	0xace8f11du,
+	0xf091cf37u,
+	0x200030cu,
+	0xb0745042u,
+	0xc4f1b274u,
+	0x51420000u,
+	0x110d483u,
+	0xd583c022u,
+	0xf091c021u,
+	0xad58acd8u,
+	0xf11df091u,
+	0xcf27e189u,
+	0xf0911668u,
+	0xe00df091u,
+	0xc331ad58u,
+	0xacd8f11du,
+	0xf091c022u,
+	0xf091ad58u,
+	0xaceef05du,
+	0xf091df75u,
+	0xad58ac8au,
+	0xf19df091u,
+	0xad58ace8u,
+	0xf01df091u,
+	0xcf370000u,
+	0x104c413u,
+	0xad58ac8au,
+	0xf29df091u,
+	0x8c2f0d1u,
+	0xf091f135u,
+	0xc03ef091u,
+	0xffafd03eu,
+	0xf091ffafu,
+	0xe03ef091u,
+	0xffaff537u,
+	0xf01f091u,
+	0xf631d726u,
+	0xf091c535u,
+	0xe121f091u,
+	0xd126f091u,
+	0xb46ae0c6u,
+	0xf091030fu,
+	0x89aa524au,
+	0xd424f091u,
+	0xc535e107u,
+	0xf0910f00u,
+	0xf091f635u,
+	0xf0afe02eu,
+	0xf091f0afu,
+	0xd02ef091u,
+	0xf0afc02eu,
+	0xf091f431u,
+	0xf0d1f091u,
+	0x2000306u,
+	0x4000a19eu,
+	0xa016ea89u,
+	0xf0914000u,
+	0xa19ea00eu,
+	0x5140d581u,
+	0xc022f091u,
+	0xc021e18fu,
+	0xf231df73u,
+	0xdf73e1edu,
+	0xf091f0d1u,
+	0xf091d03eu,
+	0xf091ffafu,
+	0x2000320u,
+	0xc022f091u,
+	0xc021e137u,
+	0xf431c0a4u,
+	0xf091c032u,
+	0xf0911072u,
+	0xc03ef091u,
+	0xffaf1041u,
+	0xc03ef091u,
+	0xffafad51u,
+	0xac2cf05du,
+	0xf091f0afu,
+	0xc02ef091u,
+	0x5148f0afu,
+	0xc02ef091u,
+	0xb268e045u,
+	0xf091f0a3u,
+	0xdf73ad59u,
+	0xac84f19du,
+	0xf091f0afu,
+	0xd02ef091u,
+	0x4000a19eu,
+	0xa016ea89u,
+	0xf0914000u,
+	0xa19ea00eu,
+	0xad59ac6eu,
+	0xf01df091u,
+	0x4100a39eu,
+	0xa2202140u,
+	0x2043f091u,
+	0x4100a39eu,
+	0xa2a02140u,
+	0x2043f091u,
+	0x4100a39eu,
+	0xa2602140u,
+	0x2043f091u,
+	0x4100a39eu,
+	0xa2e02140u,
+	0x2043f091u,
+	0x4100a39eu,
+	0xa20ec031u,
+	0xc533049eu,
+	0x520069eu,
+	0x76008d4u,
+	0xf0914100u,
+	0xa39ea216u,
+	0xc031c533u,
+	0x49e05a0u,
+	0x69e07e0u,
+	0x8d4f091u,
+	0xf0d1f091u,
+	0x0u,
+	0x1017du,
+	0x4000a15au,
+	0xa04ec030u,
+	0xf0910c00u,
+	0x54004000u,
+	0xa15aa04cu,
+	0xc030f091u,
+	0xf0d1f091u,
+	0x4000a15au,
+	0xa04cc020u,
+	0xf091df71u,
+	0xc005400u,
+	0xad5aace4u,
+	0xf11df091u,
+	0xc030f091u,
+	0x4000a1a1u,
+	0xa030c8c0u,
+	0xf0918020u,
+	0xe11df091u,
+	0x9f70c8d0u,
+	0xf0918020u,
+	0xe191f091u,
+	0xb000000u,
+	0x104ad47u,
+	0xac2af05du,
+	0xf0914000u,
+	0xa1a1a070u,
+	0xc8c0f091u,
+	0x8020e11du,
+	0xf0919f70u,
+	0xc8d0f091u,
+	0x8020e191u,
+	0xf0910b01u,
+	0x104u,
+	0xad47ac2au,
+	0xf05df091u,
+	0xf0d1f091u,
+	0x4400a9a1u,
+	0xa830cfa8u,
+	0xf091c021u,
+	0xe117f091u,
+	0xdf71cfb8u,
+	0xf091c021u,
+	0xe18b0b00u,
+	0xad69acceu,
+	0xf05d0407u,
+	0x4400a9a1u,
+	0xa870cfa8u,
+	0xf091c021u,
+	0xe117f091u,
+	0xdf71cfb8u,
+	0xf091c021u,
+	0xe18b0b01u,
+	0xad69acceu,
+	0xf05d0407u,
+	0x4100a35au,
+	0xa24ec022u,
+	0xf0914000u,
+	0xa15aa04cu,
+	0xc030f091u,
+	0x4202a500u,
+	0xa4000604u,
+	0x7000400u,
+	0x580c084u,
+	0xf0910109u,
+	0x84a8e133u,
+	0xf091dc24u,
+	0xf091c523u,
+	0xe18b8338u,
+	0xe125f091u,
+	0xe039f091u,
+	0xdf73dc34u,
+	0xf091e197u,
+	0x8338e1abu,
+	0x8638ad5bu,
+	0xacf4f11du,
+	0xf091ad5cu,
+	0xac44f01du,
+	0xf091df77u,
+	0xe111da85u,
+	0xad5bac4eu,
+	0xf19d1042u,
+	0x8170f01du,
+	0x5248f0d1u,
+	0xf0914400u,
+	0xa9a1a830u,
+	0xc084f091u,
+	0x11488538u,
+	0xe10b0b00u,
+	0x4400a9a1u,
+	0xa8700b01u,
+	0xcea8f091u,
+	0xc021e18bu,
+	0xf091ad7cu,
+	0xacc0f05du,
+	0x23df71u,
+	0xceb8f091u,
+	0xf135c03eu,
+	0xf091ffafu,
+	0xad7aac96u,
+	0xf05df091u,
+	0xf0afc02eu,
+	0xf091f431u,
+	0xad5bac8au,
+	0xf01df091u,
+	0x4000a100u,
+	0xa052c020u,
+	0xf091c171u,
+	0xc030f091u,
+	0xf135c03eu,
+	0xf091ffafu,
+	0xe03ef091u,
+	0xffaff03eu,
+	0xf091ffafu,
+	0x100u,
+	0x2000312u,
+	0xad7bac6eu,
+	0xf05db474u,
+	0xf0aff02eu,
+	0xf091f0afu,
+	0xe02ef091u,
+	0xf0afc02eu,
+	0xf091f431u,
+	0xad5bac8au,
+	0xf01df091u,
+	0x4400a9a1u,
+	0xa830c084u,
+	0xf0911148u,
+	0x8538e10bu,
+	0xb004400u,
+	0xa9a1a870u,
+	0xb01cea8u,
+	0xf091c021u,
+	0xe18bf091u,
+	0xad7cacc0u,
+	0xf05d0023u,
+	0xdf71ceb8u,
+	0xf091f135u,
+	0xc03ef091u,
+	0xffafe03eu,
+	0xf091ffafu,
+	0xf03ef091u,
+	0xffafc03eu,
+	0xf091ffafu,
+	0xc03ef091u,
+	0xffafc1a4u,
+	0xf639cf46u,
+	0xf091010du,
+	0x84b00200u,
+	0x331e107u,
+	0xc0310200u,
+	0x332ad7bu,
+	0xac6ef05du,
+	0xb474f0afu,
+	0xc02ef091u,
+	0xad7aac5au,
+	0xf05df091u,
+	0xf0afc02eu,
+	0xf091ad7au,
+	0xac96f05du,
+	0xf091f0afu,
+	0xf02ef091u,
+	0xf0afe02eu,
+	0xf091f0afu,
+	0xc02ef091u,
+	0xf431ad5bu,
+	0xac8af01du,
+	0xf091c03eu,
+	0xf091ffafu,
+	0xfad5cu,
+	0xacfa9f70u,
+	0xf19df091u,
+	0xf0afc02eu,
+	0xf091f0d1u,
+	0xf091ad5cu,
+	0xaceef05du,
+	0xf091ad5cu,
+	0xaceef05du,
+	0xf091ad5cu,
+	0xaceef05du,
+	0xf091ad5cu,
+	0xaceef05du,
+	0xf091ad5cu,
+	0xaceef05du,
+	0xf091f0d1u,
+	0xf091ad5du,
+	0xac0af05du,
+	0xf091ad5du,
+	0xac0af05du,
+	0xf091ad5du,
+	0xac0af05du,
+	0xf091ad5du,
+	0xac0af05du,
+	0xf091ad5du,
+	0xac0af05du,
+	0xf091f0d1u,
+	0xf091c03eu,
+	0xf091ffafu,
+	0xd03ef091u,
+	0xffaf0203u,
+	0x3e80003u,
+	0x1e8ad5cu,
+	0xaceef05du,
+	0xf091df71u,
+	0xe1f5f091u,
+	0xdf73e1ebu,
+	0xf091f0afu,
+	0xd02ef091u,
+	0xf0afc02eu,
+	0xf091f0d1u,
+	0xf091c03eu,
+	0xf091ffafu,
+	0xd03ef091u,
+	0xffaf0203u,
+	0x3e80003u,
+	0x1e8ad5du,
+	0xac0af05du,
+	0xf091df71u,
+	0xe1f5f091u,
+	0xdf73e1ebu,
+	0xf091f0afu,
+	0xd02ef091u,
+	0xf0afc02eu,
+	0xf091f0d1u,
+	0xf0910c02u,
+	0x5f000901u,
+	0xb004200u,
+	0xa504a400u,
+	0xc015e00u,
+	0x6301ad08u,
+	0xac02f05du,
+	0xf0916300u,
+	0xad08ac02u,
+	0xf05df091u,
+	0x48ff49ffu,
+	0x6304ad08u,
+	0xac02f05du,
+	0xf0916318u,
+	0xad08ac02u,
+	0xf05df091u,
+	0x62060c44u,
+	0x10000c00u,
+	0x5e004000u,
+	0xa15da0e0u,
+	0x26044200u,
+	0xa505a400u,
+	0xf5910b01u,
+	0x91f4000u,
+	0xa1a1a030u,
+	0x100u,
+	0xc030f091u,
+	0xf0a1e5f9u,
+	0xf0914100u,
+	0xa3a1a230u,
+	0x100u,
+	0xc132f091u,
+	0x106d192u,
+	0xf0910004u,
+	0xca92f091u,
+	0xcad2u,
+	0xf0910000u,
+	0x104c932u,
+	0xf0910000u,
+	0x102c9b2u,
+	0xf0910200u,
+	0x304d332u,
+	0xf0910008u,
+	0xc892f091u,
+	0xcf02f091u,
+	0x10080a0u,
+	0xcf12f091u,
+	0x91f4000u,
+	0xa1a1a070u,
+	0x100u,
+	0xc030f091u,
+	0xf0a1e5f9u,
+	0xf0914100u,
+	0xa3a1a270u,
+	0x101u,
+	0xc132f091u,
+	0x106d192u,
+	0xf0910004u,
+	0xca92f091u,
+	0xcad2u,
+	0xf0910000u,
+	0x104c932u,
+	0xf0910000u,
+	0x102c9b2u,
+	0xf0910200u,
+	0x304d332u,
+	0xf0910008u,
+	0xc892f091u,
+	0xcf02f091u,
+	0x10080a0u,
+	0xcf12f091u,
+	0xad3cacf2u,
+	0xf05df091u,
+	0xad3cacdcu,
+	0xf05df091u,
+	0xf0d1f091u,
+	0x4000a1a1u,
+	0xa030ad5fu,
+	0xac28f05du,
+	0xb004000u,
+	0xa1a1a070u,
+	0xad5fac28u,
+	0xf05d0b01u,
+	0xad59acecu,
+	0xf05df091u,
+	0xf0d1f091u,
+	0xca85a00u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xc285a00u,
+	0xc015800u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xcf00f091u,
+	0x11384a8u,
+	0xe1050200u,
+	0x208010fu,
+	0x80a88120u,
+	0x1c485300u,
+	0xc005800u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xcf71200u,
+	0xcf71300u,
+	0xc205900u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xc005900u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xc015c00u,
+	0xc0d5d00u,
+	0xc045800u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xc951100u,
+	0xb501b5u,
+	0x1c481200u,
+	0x1c491300u,
+	0xc205900u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xc011500u,
+	0xad08ac02u,
+	0xf05df091u,
+	0x6102091fu,
+	0xad00acc0u,
+	0xea87c031u,
+	0xad00ac80u,
+	0xc03cf091u,
+	0xe5fbf0adu,
+	0xf0d1f091u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x6000u,
+	0x60b06160u,
+	0x62100000u,
+	0x2200u,
+	0xef0000u,
+	0xef0138u,
+	0x0u,
+	0xffffu,
+	0xffff0000u,
+	0x71c0u,
+	0x71c0ad69u,
+	0xacb4f05du,
+	0xf0916e00u,
+	0x6f00ad07u,
+	0xac38ea8du,
+	0x640140u,
+	0xc03cf091u,
+	0xf0d1f091u,
+	0x640150u,
+	0xc13cf091u,
+	0xf0d1f091u,
+	0xcf71200u,
+	0xcf71300u,
+	0xc041600u,
+	0xad69acb4u,
+	0xf05df091u,
+	0xc025e00u,
+	0x26040c08u,
+	0x1400ad08u,
+	0xac02f05du,
+	0xf091005fu,
+	0x146cbb8u,
+	0xf0916e01u,
+	0x6f006a00u,
+	0x6b006c00u,
+	0x6d00ad07u,
+	0xac304500u,
+	0xab07aa38u,
+	0xea950063u,
+	0x180c03cu,
+	0xf0910064u,
+	0x140c03au,
+	0xf091f0d1u,
+	0x27020063u,
+	0x190c13cu,
+	0xf0910064u,
+	0x150c13au,
+	0xf091f0d1u,
+	0x27020000u,
+	0x0u,
+	0x0u,
+	0x4400a9a1u,
+	0xa830e011u,
+	0xb000000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8700b01u,
+	0x822103cu,
+	0x826103cu,
+	0xad64ac10u,
+	0xcf08f091u,
+	0x11384a8u,
+	0xe18ff091u,
+	0x100b1148u,
+	0x2058928u,
+	0xf19df091u,
+	0x10220200u,
+	0x304c529u,
+	0xf19df091u,
+	0xad75ac3eu,
+	0x826103cu,
+	0xc839f19du,
+	0x2701ad75u,
+	0xac4e1022u,
+	0xc839f19du,
+	0x2701cba8u,
+	0xf091df71u,
+	0xcbb8f091u,
+	0xe107f091u,
+	0xf0d12702u,
+	0xcac8f091u,
+	0x10884b0u,
+	0xe10bf091u,
+	0xad75ac26u,
+	0xf01d2701u,
+	0xad75ac26u,
+	0xf01d2701u,
+	0xad75ac26u,
+	0xf01d2701u,
+	0x6e006f00u,
+	0x40cad8u,
+	0xf0910c01u,
+	0x14000c00u,
+	0x5e00ad40u,
+	0xaca6f01du,
+	0xf0910000u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x4400a9a1u,
+	0xa830e011u,
+	0xb000000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8700b01u,
+	0xc025e00u,
+	0x26040cf7u,
+	0x12000cf7u,
+	0x13000c20u,
+	0x5900ad08u,
+	0xac02f05du,
+	0xf0910c02u,
+	0x1600ad08u,
+	0xac02f05du,
+	0xf091ad08u,
+	0xac02f05du,
+	0xf091ad08u,
+	0xac02f05du,
+	0xf0910c00u,
+	0x59006e00u,
+	0x6f002701u,
+	0x9cad8u,
+	0xf091c031u,
+	0xc038f091u,
+	0x1fec0b8u,
+	0xf091e003u,
+	0xf0911022u,
+	0x826103cu,
+	0xc939ad64u,
+	0xacaef11du,
+	0xf0910019u,
+	0xcad8f091u,
+	0x1b6u,
+	0xcbb8f091u,
+	0x6a006b00u,
+	0x6c006d00u,
+	0x6e006f00u,
+	0xad07ac30u,
+	0xea8ff091u,
+	0x650100u,
+	0xc03cf091u,
+	0xf0d12702u,
+	0x650110u,
+	0xc13cf091u,
+	0xf0d12702u,
+	0x0u,
+	0x0u,
+	0x4400a9a1u,
+	0xa830e011u,
+	0xb000000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8700b01u,
+	0x27011022u,
+	0xc239ad65u,
+	0xac42f19du,
+	0xf091c839u,
+	0xad65ac4au,
+	0xf11df091u,
+	0xcba8f091u,
+	0xdf71cbb8u,
+	0xf091e10fu,
+	0xf091f0d1u,
+	0x2702ad75u,
+	0xac26f01du,
+	0xf0911022u,
+	0xc239e191u,
+	0xf091c839u,
+	0xe113f091u,
+	0xad75ac4eu,
+	0xf01df091u,
+	0xad75ac26u,
+	0xf01df091u,
+	0xcf08f091u,
+	0x11384a8u,
+	0xc101fcu,
+	0xe107f091u,
+	0x101fcu,
+	0x7a686c80u,
+	0x6d002700u,
+	0x6e056f00u,
+	0xad07ac38u,
+	0x4500ab07u,
+	0xaa30ea97u,
+	0xf0910065u,
+	0x1d0c03cu,
+	0xf0910063u,
+	0x180c03au,
+	0xf091e013u,
+	0xf0910065u,
+	0x1e0c13cu,
+	0xf0910063u,
+	0x190c13au,
+	0xf091005fu,
+	0x146cbb8u,
+	0xf0912702u,
+	0xc011600u,
+	0xf0d1f091u,
+	0x0u,
+	0x4400a9a1u,
+	0xa830e011u,
+	0xb000000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8700b01u,
+	0x1022ad75u,
+	0xac26c239u,
+	0xf19df091u,
+	0xad64ac58u,
+	0x826103cu,
+	0xc839f19du,
+	0xf0910029u,
+	0xcad8f091u,
+	0x6901b0u,
+	0xc438f091u,
+	0xad45acd4u,
+	0xf05df091u,
+	0xc031600u,
+	0xad62acbau,
+	0xea87f091u,
+	0xad62acb6u,
+	0xc02cfa39u,
+	0xc0acf439u,
+	0x6d0100u,
+	0xad62acdcu,
+	0xea87f091u,
+	0xad62acdau,
+	0xc03cf091u,
+	0xad73ac82u,
+	0xf05df091u,
+	0x10cu,
+	0xc034f091u,
+	0x3c094u,
+	0xf091b074u,
+	0xf1a1ad62u,
+	0xacc20902u,
+	0xb27c08c4u,
+	0xf091bc72u,
+	0xb27008d4u,
+	0xf091e5f1u,
+	0xb0720011u,
+	0x101c7b4u,
+	0xf091c031u,
+	0xc834f091u,
+	0xb0740000u,
+	0x122d081u,
+	0x4100a303u,
+	0xa208ea89u,
+	0xf0914100u,
+	0xa303a200u,
+	0x8c4f091u,
+	0xb27008d4u,
+	0xf0916e09u,
+	0x6f006a00u,
+	0x6b00ad07u,
+	0xac38ea8du,
+	0x670130u,
+	0xc03cf091u,
+	0xe00bf091u,
+	0x670140u,
+	0xc13cf091u,
+	0xad62acc0u,
+	0xea87f091u,
+	0xad62acbeu,
+	0xc02cf091u,
+	0xc021e1afu,
+	0xf031107cu,
+	0xc03ef091u,
+	0xffaf0403u,
+	0x5000600u,
+	0x7efad4fu,
+	0xac6af05du,
+	0xf091f0afu,
+	0xc02ef091u,
+	0xbc68c03cu,
+	0xf9310200u,
+	0x302d1b0u,
+	0xf091c380u,
+	0xf09101efu,
+	0x84b0e18bu,
+	0xf091ad71u,
+	0xacecf01du,
+	0xf091ad7cu,
+	0xacc0f05du,
+	0x610000u,
+	0x0u,
+	0x0u,
+	0x4400a9a1u,
+	0xa830e011u,
+	0xb000000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8700b01u,
+	0xad75ac3eu,
+	0x826103cu,
+	0xc839f19du,
+	0xf0914800u,
+	0x49080039u,
+	0xcad8f091u,
+	0xcba8f091u,
+	0x5f0146u,
+	0xcbb8f091u,
+	0x6d01f0u,
+	0xad62acdcu,
+	0xea87f091u,
+	0xad62acdau,
+	0xc03cf091u,
+	0x6e016f01u,
+	0x6a006b00u,
+	0xad75ac62u,
+	0xf05df091u,
+	0xad07ac38u,
+	0xea8df091u,
+	0x6801d0u,
+	0xc03cf091u,
+	0xe0090068u,
+	0x1e0c13cu,
+	0xf091e8ffu,
+	0xf09100f0u,
+	0x1f00c94u,
+	0x11001c48u,
+	0x12001c49u,
+	0x13000c20u,
+	0x5900ad08u,
+	0xac02f05du,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x4400a9a1u,
+	0xa830e011u,
+	0xb000000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8700b01u,
+	0xad75ac3eu,
+	0x826103cu,
+	0xc839f19du,
+	0xf091cba8u,
+	0xf091005fu,
+	0x146cbb8u,
+	0xf091ad62u,
+	0xacbaea87u,
+	0xf091ad62u,
+	0xacb6c02cu,
+	0xfa39c0acu,
+	0xf4394800u,
+	0x49080c00u,
+	0x5900ad08u,
+	0xac02f05du,
+	0xf0910cf7u,
+	0x12000cf7u,
+	0x1300ad75u,
+	0xac62f05du,
+	0xf091006fu,
+	0x170ad62u,
+	0xacdcea87u,
+	0xf091ad62u,
+	0xacdac03cu,
+	0xf0916e01u,
+	0x6f016a00u,
+	0x6b00ad07u,
+	0xac38ea8du,
+	0x6801d0u,
+	0xc03cf091u,
+	0xe00bf091u,
+	0x6801e0u,
+	0xc13cf091u,
+	0x114u,
+	0xc034f091u,
+	0x3c094u,
+	0xf091b074u,
+	0xf1a1ad62u,
+	0xacc20902u,
+	0xb27c08c4u,
+	0xf091bc72u,
+	0xb27008d4u,
+	0xf091e5f1u,
+	0xb0720011u,
+	0x102c7b4u,
+	0xf091c031u,
+	0xc834f091u,
+	0xb0740000u,
+	0x122d081u,
+	0xc031c533u,
+	0xca35cf37u,
+	0x901b270u,
+	0x8d4f091u,
+	0xe5fbf091u,
+	0xad71acecu,
+	0xf01df091u,
+	0x0u,
+	0x0u,
+	0x4400a9a1u,
+	0xa830e011u,
+	0xb000000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8700b01u,
+	0xad75ac3eu,
+	0x826103cu,
+	0xc839f19du,
+	0x27010000u,
+	0xcad8f091u,
+	0xcf71200u,
+	0xcf71300u,
+	0xcc21400u,
+	0xad73acbcu,
+	0xf05df091u,
+	0xad62acc0u,
+	0xea87f091u,
+	0xad62acbeu,
+	0xc02cf439u,
+	0xc031c03cu,
+	0xf091ad51u,
+	0xac2cf05du,
+	0xf091ad75u,
+	0xacc8f05du,
+	0xf0916e01u,
+	0x6f00ad07u,
+	0xac38ea8du,
+	0x690180u,
+	0xc03cf091u,
+	0xe00bf091u,
+	0x690160u,
+	0xc13cf091u,
+	0xcba8f091u,
+	0xad41ac92u,
+	0xf01df091u,
+	0x4400a9a1u,
+	0xa870ad07u,
+	0xac380064u,
+	0x150c13cu,
+	0xf091e021u,
+	0xb010000u,
+	0x0u,
+	0x0u,
+	0x4400a9a1u,
+	0xa830ad07u,
+	0xac380064u,
+	0x140c03cu,
+	0xf0910b00u,
+	0x10220826u,
+	0x103cc188u,
+	0xf091ad6au,
+	0xac7af05du,
+	0x1448ad75u,
+	0xac3ef01du,
+	0xf0910000u,
+	0xf0d1f091u,
+	0x8cad8u,
+	0xf091c031u,
+	0xce38f091u,
+	0xc038f091u,
+	0x1fec0b8u,
+	0xf091f0d1u,
+	0xf091ad63u,
+	0xac08f05du,
+	0xf0910007u,
+	0xc198f091u,
+	0xca98u,
+	0xf091ad69u,
+	0xacb4f05du,
+	0xf0910c02u,
+	0x5600e907u,
+	0xf091e07bu,
+	0xf091ad45u,
+	0xacd4f05du,
+	0xf0916202u,
+	0xc015800u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xc005800u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xc015c00u,
+	0xc0d5d00u,
+	0xc045800u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xc005600u,
+	0x26040c02u,
+	0x5e000000u,
+	0x8230e1abu,
+	0xf0910200u,
+	0x311ad43u,
+	0xac40f05du,
+	0xf091ad55u,
+	0xac7af05du,
+	0xf091ad59u,
+	0xac4cf05du,
+	0xf091ad46u,
+	0xac7ef05du,
+	0xf091e013u,
+	0xf091ad55u,
+	0xac7af05du,
+	0xf091ad59u,
+	0xac4cf05du,
+	0xf091f0d1u,
+	0xf0910007u,
+	0xc198f091u,
+	0xca98u,
+	0xf091ad69u,
+	0xacb4f05du,
+	0xf0910c02u,
+	0x5600e907u,
+	0xf091e07bu,
+	0xf091ad45u,
+	0xacd4f05du,
+	0xf0916202u,
+	0xc005600u,
+	0x26040c02u,
+	0x5e000000u,
+	0x8230e1abu,
+	0xf0910200u,
+	0x311ad43u,
+	0xac40f05du,
+	0xf091ad55u,
+	0xac7af05du,
+	0xf091ad59u,
+	0xac4cf05du,
+	0xf091ad46u,
+	0xac7ef05du,
+	0xf091e013u,
+	0xf091ad55u,
+	0xac7af05du,
+	0xf091ad59u,
+	0xac4cf05du,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x4400a9a1u,
+	0xa870ad62u,
+	0xacba2301u,
+	0xe0110b01u,
+	0x4400a9a1u,
+	0xa830ad62u,
+	0xacb62300u,
+	0xb00c02cu,
+	0xfa3909ffu,
+	0xe707f091u,
+	0xe5fbf091u,
+	0xe70bf091u,
+	0xad7cacc0u,
+	0xf05d0062u,
+	0xad6bacdeu,
+	0xf99df091u,
+	0x826103cu,
+	0x2030380u,
+	0xc529ad6cu,
+	0xac02f19du,
+	0xf0918030u,
+	0x110c0207u,
+	0x85298541u,
+	0x4000a16bu,
+	0xa06ed081u,
+	0xc020f091u,
+	0xbc68f01du,
+	0xf0916c02u,
+	0x6c026c02u,
+	0x6b7e6b7eu,
+	0x6c026b7eu,
+	0x6c020003u,
+	0xc1d8f091u,
+	0xb07aad72u,
+	0xac84f05du,
+	0xf091ad28u,
+	0xacf4f05du,
+	0xf0910000u,
+	0xc1d8f091u,
+	0x103a0200u,
+	0x304c101u,
+	0xc1210200u,
+	0x300c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0xc338f091u,
+	0xc888f091u,
+	0x9f70c898u,
+	0xf0916310u,
+	0x2605ad62u,
+	0xacdcea87u,
+	0xf091ad62u,
+	0xacdac02cu,
+	0xf039f011u,
+	0xf091100du,
+	0x111f1022u,
+	0x103a2200u,
+	0x21043468u,
+	0x2008f091u,
+	0xe507f091u,
+	0xe07bf091u,
+	0x2a00ad75u,
+	0xac26f01du,
+	0xf091ad28u,
+	0xacf4f05du,
+	0xf0910000u,
+	0xc1d8f091u,
+	0x103a0200u,
+	0x304c101u,
+	0xc1210200u,
+	0x300c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0xc338f091u,
+	0xc888f091u,
+	0x9f70c898u,
+	0xf0916310u,
+	0x2605f0d1u,
+	0xf0910000u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x4000a100u,
+	0xa0c0e011u,
+	0xb010000u,
+	0x0u,
+	0x4000a100u,
+	0xa0800b00u,
+	0x826103cu,
+	0x20c0300u,
+	0xc529e109u,
+	0xf0910c00u,
+	0x5e002605u,
+	0x826103cu,
+	0x1022ca20u,
+	0xf091c021u,
+	0xad6caceeu,
+	0xf11df091u,
+	0x128u,
+	0xd081b270u,
+	0x5140c4f1u,
+	0xc0f30f01u,
+	0xf091f091u,
+	0xf091f431u,
+	0xc724f091u,
+	0xc021e10bu,
+	0xc031c734u,
+	0xf091e00du,
+	0xf091f135u,
+	0xad78ac9cu,
+	0xf05d4100u,
+	0xc624f091u,
+	0xc021e10du,
+	0xf091bc68u,
+	0xc6a4f091u,
+	0xf05df091u,
+	0xa100a0c0u,
+	0xea874000u,
+	0xa100a080u,
+	0xca20f091u,
+	0xc021e185u,
+	0xf091610au,
+	0xf0d1f091u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0xad62acbau,
+	0xea87f091u,
+	0xad62acb6u,
+	0x4100a36du,
+	0xa2944200u,
+	0xa56da49cu,
+	0x4000a16du,
+	0xa0dcc02cu,
+	0xfa39c7aau,
+	0xf0910211u,
+	0x301c433u,
+	0xf191f091u,
+	0xc34af091u,
+	0xd24af091u,
+	0x84b0f191u,
+	0x8020f113u,
+	0x1ef80b0u,
+	0xf1910000u,
+	0x122b67au,
+	0xdc87ad03u,
+	0xac08ea87u,
+	0xf091ad03u,
+	0xac000a00u,
+	0xc1a6f091u,
+	0xd1acf091u,
+	0xc111c126u,
+	0xf091d12cu,
+	0xf091c119u,
+	0xc0a6f091u,
+	0xd0acf091u,
+	0xc119c026u,
+	0xf091d02cu,
+	0xf091c119u,
+	0xf315f091u,
+	0xf213f091u,
+	0xc031600u,
+	0xf0d1f091u,
+	0xad71acc4u,
+	0xf01df091u,
+	0x39cad8u,
+	0xf091e8ffu,
+	0xf091ad07u,
+	0xac38ea8du,
+	0x6701d0u,
+	0xc03cf091u,
+	0xe00bf091u,
+	0x6701e0u,
+	0xc13cf091u,
+	0xc101400u,
+	0xc941100u,
+	0xf001f0u,
+	0x1c481200u,
+	0x1c491300u,
+	0xc205900u,
+	0xf0d1f091u,
+	0xad75ac4eu,
+	0xf01df091u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0xcba8f091u,
+	0x5f0146u,
+	0xcbb8f091u,
+	0xad62acbau,
+	0xea87f091u,
+	0xad62acb6u,
+	0xc005900u,
+	0xc02cfa39u,
+	0x4000a16fu,
+	0xa060c8aau,
+	0xf091c7aau,
+	0xf0910211u,
+	0x301c511u,
+	0xf4110211u,
+	0x307c413u,
+	0xf4110211u,
+	0x302c511u,
+	0xe41f0211u,
+	0x305c413u,
+	0xe417f091u,
+	0xe88af091u,
+	0x873ae10du,
+	0x301e288u,
+	0xf09189a2u,
+	0xe298f091u,
+	0x8030c001u,
+	0x4000a16eu,
+	0xa070d081u,
+	0xc020fc39u,
+	0x4000a171u,
+	0xa09ef01du,
+	0xf0910000u,
+	0x6f60u,
+	0x6e806ea0u,
+	0x6ec06ee0u,
+	0x6f006f40u,
+	0xad71ac08u,
+	0xf05df091u,
+	0x110102u,
+	0xc7baf091u,
+	0x100u,
+	0xc83af091u,
+	0xf011f091u,
+	0x0u,
+	0xad71ac14u,
+	0xf05df091u,
+	0x110103u,
+	0xc7baf091u,
+	0x100u,
+	0xc83af091u,
+	0xf011f091u,
+	0x0u,
+	0xad71ac26u,
+	0xf05df091u,
+	0x110104u,
+	0xc7baf091u,
+	0x100u,
+	0xc83af091u,
+	0xf011f091u,
+	0x0u,
+	0xad71ac6cu,
+	0xf05df091u,
+	0xc0c8f091u,
+	0x1c481700u,
+	0x110105u,
+	0xc7baf091u,
+	0xf011f091u,
+	0x0u,
+	0xb27a0000u,
+	0x122d483u,
+	0xd88af091u,
+	0x8171d89au,
+	0xf0918030u,
+	0xd483c0c8u,
+	0xf091c012u,
+	0xf0910011u,
+	0x106c7bau,
+	0xf0910000u,
+	0x100c83au,
+	0xf091f011u,
+	0xf0910000u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0xb27a0000u,
+	0x122c083u,
+	0xce38f091u,
+	0x110107u,
+	0xc7baf091u,
+	0x100u,
+	0xc83af091u,
+	0xf011f091u,
+	0xad75ac4eu,
+	0xf01df091u,
+	0x0u,
+	0x0u,
+	0xad62acbau,
+	0xea87f091u,
+	0xad62acb6u,
+	0xc02cfa39u,
+	0x4000a171u,
+	0xa000c8aau,
+	0xf091c7aau,
+	0xf0910211u,
+	0x301c511u,
+	0xf4110211u,
+	0x307c413u,
+	0xf4110211u,
+	0x302c511u,
+	0xe41f0211u,
+	0x305c413u,
+	0xe417f091u,
+	0xe88af091u,
+	0x873ae10du,
+	0x301e288u,
+	0xf09189a2u,
+	0xe298f091u,
+	0x8030c001u,
+	0x4000a16fu,
+	0xa0e0d081u,
+	0xc020fc39u,
+	0x4000a171u,
+	0xa09ef01du,
+	0xf0910000u,
+	0x7100u,
+	0x6ff07010u,
+	0x70307060u,
+	0x70b070d0u,
+	0xad71ac14u,
+	0xf05df091u,
+	0x110103u,
+	0xc7baf091u,
+	0x100u,
+	0xc83af091u,
+	0xf011f091u,
+	0x0u,
+	0xad71ac26u,
+	0xf05df091u,
+	0x110104u,
+	0xc7baf091u,
+	0x100u,
+	0xc83af091u,
+	0xf011f091u,
+	0x0u,
+	0xad71ac6cu,
+	0xf05df091u,
+	0xc0c8f091u,
+	0x1c481700u,
+	0x110105u,
+	0xc7baf091u,
+	0x10100u,
+	0xc83af091u,
+	0xf011f091u,
+	0xad70acdcu,
+	0xf01df091u,
+	0x0u,
+	0xc82af091u,
+	0x9f70e1edu,
+	0xf0910000u,
+	0x184c03au,
+	0xf091b27au,
+	0x122u,
+	0xd48300ffu,
+	0x1ff1268u,
+	0x14681668u,
+	0x90f08d4u,
+	0xf091e5fbu,
+	0xf091d0c8u,
+	0xf0910001u,
+	0xc8baf091u,
+	0x110106u,
+	0xc7baf091u,
+	0x100u,
+	0xc83af091u,
+	0xf011f091u,
+	0x0u,
+	0x110107u,
+	0xc7baf091u,
+	0x100u,
+	0xc83af091u,
+	0xf011f091u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0xb27a0000u,
+	0x122c083u,
+	0xce38f091u,
+	0xb501b5u,
+	0xc851100u,
+	0x1c481200u,
+	0x1c491300u,
+	0xc105900u,
+	0xf0d1f091u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0xad75ac4eu,
+	0xf01df091u,
+	0xc028f091u,
+	0xd0a8f091u,
+	0xf0d1f091u,
+	0xc028f091u,
+	0xd0a8f091u,
+	0x8020e183u,
+	0xf091f0d1u,
+	0xf091c028u,
+	0xf091d0a8u,
+	0xf0918020u,
+	0xe1b7f091u,
+	0xad03ac19u,
+	0xea87f091u,
+	0xad03ac18u,
+	0xf00cf091u,
+	0xad73acf6u,
+	0xf05df091u,
+	0x8020e119u,
+	0xf091ad74u,
+	0xac56f05du,
+	0xf0918020u,
+	0xe10bf091u,
+	0xc038f091u,
+	0xd0b8f091u,
+	0xf0d1f091u,
+	0xc028f091u,
+	0xd0a8f091u,
+	0x8020e1a3u,
+	0xf09103feu,
+	0xad74ac86u,
+	0xf05df091u,
+	0x8020e113u,
+	0xf091ad74u,
+	0xac56f05du,
+	0xf091c038u,
+	0xf091d0b8u,
+	0xf091f0d1u,
+	0xf091ad71u,
+	0xacc4f05du,
+	0xf091ad71u,
+	0xacecf05du,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0xe07ff091u,
+	0xe8fff091u,
+	0xad62acbau,
+	0xea87f091u,
+	0xad62acb6u,
+	0xc02cf091u,
+	0xd0acf091u,
+	0xd03cf091u,
+	0xc0bcf091u,
+	0xc031600u,
+	0xf0d1f091u,
+	0x4600ad62u,
+	0xacbcea89u,
+	0xf0914600u,
+	0xad62acb8u,
+	0xc02cf439u,
+	0x1074c7a4u,
+	0xf091c031u,
+	0xf6312302u,
+	0xb074f1a1u,
+	0x12701140u,
+	0x2c432d44u,
+	0xb074f7a1u,
+	0x12701140u,
+	0x2e08cac8u,
+	0xf0910129u,
+	0x84b00072u,
+	0x160e105u,
+	0xf091c031u,
+	0x2d18c084u,
+	0xf091d024u,
+	0xf091ad62u,
+	0xacc0ea87u,
+	0xf091ad62u,
+	0xacbe6102u,
+	0xc02cf839u,
+	0xad51ac58u,
+	0xf05df091u,
+	0xf0d1f091u,
+	0x0u,
+	0x4400a9a1u,
+	0xa870ea89u,
+	0xf0914400u,
+	0xa9a1a830u,
+	0xcac8f091u,
+	0x12984b0u,
+	0xad71acecu,
+	0xf11df091u,
+	0xf0d1f091u,
+	0xf131c03eu,
+	0xf091ffafu,
+	0xc328f091u,
+	0x2200211cu,
+	0x34682008u,
+	0xf091e507u,
+	0xf091e07bu,
+	0xf091103au,
+	0x103ad328u,
+	0xf091c111u,
+	0x22303e4u,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106a28d3u,
+	0x2038d2bu,
+	0x8932c111u,
+	0xc3b8f091u,
+	0x2000384u,
+	0xc511e407u,
+	0xf0910000u,
+	0x1841468u,
+	0xc030f091u,
+	0xf0a1b270u,
+	0x2200211cu,
+	0x2003f091u,
+	0xca25ad73u,
+	0xac5cf11du,
+	0xf091b072u,
+	0xc328f091u,
+	0x200031cu,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106a0440u,
+	0x8a94124cu,
+	0xe405f091u,
+	0x124d2200u,
+	0x314a3468u,
+	0x2008f091u,
+	0xe507f091u,
+	0xe07bf091u,
+	0xb2702200u,
+	0x314a2003u,
+	0xf0910200u,
+	0x340c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0x2000340u,
+	0xd1819615u,
+	0xe20bf091u,
+	0xad73ac10u,
+	0xf19df091u,
+	0xf0afc02eu,
+	0xf091f231u,
+	0xc082f091u,
+	0x10384a8u,
+	0x80304000u,
+	0xa112a06eu,
+	0xd081c000u,
+	0xf091c092u,
+	0xf091f0d1u,
+	0xf091ad07u,
+	0xac104500u,
+	0xab07aa40u,
+	0xc005d00u,
+	0xea97f091u,
+	0x6b0110u,
+	0xc03cf091u,
+	0x6c0160u,
+	0xc03af091u,
+	0xf0d12605u,
+	0x6b0100u,
+	0xc13cf091u,
+	0x6c0150u,
+	0xc13af091u,
+	0xf0d12605u,
+	0xad07ac10u,
+	0x4500ab07u,
+	0xaa400c0du,
+	0x5d00ea97u,
+	0xf0910009u,
+	0x130c03cu,
+	0xf0910047u,
+	0x170c03au,
+	0xf091f0d1u,
+	0x26070009u,
+	0x120c13cu,
+	0xf0910047u,
+	0x160c13au,
+	0xf091f0d1u,
+	0x260701feu,
+	0x84b3e11fu,
+	0xf091114bu,
+	0x4100a3a0u,
+	0xa27ab672u,
+	0x97ee002u,
+	0xf0918cb2u,
+	0xe115f091u,
+	0xc1f3e5f3u,
+	0xf091c031u,
+	0x20003feu,
+	0xca35e02fu,
+	0xf0911276u,
+	0xc993144du,
+	0x81740507u,
+	0x96ac9f75u,
+	0xe03ef091u,
+	0x194de409u,
+	0x5809465u,
+	0xe5fdf091u,
+	0x90649064u,
+	0x9064c533u,
+	0x1349c031u,
+	0xfff0d1u,
+	0xf091b27au,
+	0x6000722u,
+	0xd7830600u,
+	0x174cd783u,
+	0xd002f091u,
+	0x8aa9e191u,
+	0x86a1d012u,
+	0xf09100ffu,
+	0x1000200u,
+	0xf0d1f091u,
+	0x100u,
+	0x200f0d1u,
+	0xf091090fu,
+	0xb27a0600u,
+	0x722d783u,
+	0xd022f091u,
+	0xd03ef091u,
+	0xffaf04c0u,
+	0x500c623u,
+	0xd032f091u,
+	0x1272d03eu,
+	0xf091d022u,
+	0xf091c173u,
+	0xe113f091u,
+	0xd022f091u,
+	0x8172e19fu,
+	0xf091c1f3u,
+	0xe019f091u,
+	0xf0a3e5e3u,
+	0xf0910000u,
+	0x1000200u,
+	0x3fe0400u,
+	0x500e03bu,
+	0xf091d02eu,
+	0xf091c593u,
+	0x144b0580u,
+	0xe002f091u,
+	0x8db38942u,
+	0xe28bf091u,
+	0x94658173u,
+	0xe075f091u,
+	0x124c8b42u,
+	0x8d829f73u,
+	0x2004100u,
+	0xa3a0a27au,
+	0xd583f002u,
+	0xf09100ffu,
+	0x100f02eu,
+	0xf091bc6eu,
+	0xf0aff02eu,
+	0xf091f03cu,
+	0xf091f0d1u,
+	0xf091ad75u,
+	0xacc8f05du,
+	0xf091c188u,
+	0xf091ad43u,
+	0xacd6f05du,
+	0x1448f0d1u,
+	0xf091ad75u,
+	0xacc8f05du,
+	0xf091ad64u,
+	0xac58f01du,
+	0xf091ad75u,
+	0xacc8f05du,
+	0xf091ad63u,
+	0xac08f05du,
+	0xf091f0d1u,
+	0xf091e687u,
+	0xf091f0d1u,
+	0xf09109ffu,
+	0xe707f091u,
+	0xe5fbf091u,
+	0xe70ff091u,
+	0xad7cacc0u,
+	0xf05d0065u,
+	0xe065f091u,
+	0xad28acf4u,
+	0xf05df091u,
+	0xc1d8u,
+	0xf091103au,
+	0x2000304u,
+	0xc101c121u,
+	0x2000300u,
+	0xc1010224u,
+	0x300c511u,
+	0xe405f091u,
+	0x106ac338u,
+	0xf091c888u,
+	0xf0919f70u,
+	0xc898f091u,
+	0x63102605u,
+	0xad75ac62u,
+	0xf01df091u,
+	0xa100a0c0u,
+	0xea874000u,
+	0xa100a080u,
+	0x1070ca20u,
+	0xf091c021u,
+	0xad76ac28u,
+	0xf11df091u,
+	0x128u,
+	0xd081b270u,
+	0x5140c4f1u,
+	0xc0f30f01u,
+	0xf091f431u,
+	0xc724f091u,
+	0xc021e10bu,
+	0xc031c734u,
+	0xf091e00du,
+	0xf091f135u,
+	0xad78ac9cu,
+	0xf05d4100u,
+	0xad75acd4u,
+	0xa100a0c0u,
+	0xfa9d4000u,
+	0xa100a080u,
+	0xf01df091u,
+	0x1070c820u,
+	0xf091c021u,
+	0xad76ac6cu,
+	0xf11df091u,
+	0x120u,
+	0xd081b270u,
+	0x5140c4f1u,
+	0xc0f3c020u,
+	0xf091df71u,
+	0xe193f091u,
+	0xf01f091u,
+	0xad78ac9cu,
+	0xf05d4100u,
+	0xe00ff091u,
+	0x8c1ad78u,
+	0xacb8f05du,
+	0xf09108c2u,
+	0xf0d1f091u,
+	0x4400a9a1u,
+	0xa870e011u,
+	0xb010000u,
+	0x0u,
+	0x4400a9a1u,
+	0xa8300b00u,
+	0x826103cu,
+	0x100b1148u,
+	0x1022100du,
+	0x111f01dfu,
+	0x80a80105u,
+	0x84a8ad76u,
+	0xacd0f11du,
+	0xf0910104u,
+	0x84a8e115u,
+	0xf0910826u,
+	0x103c0203u,
+	0x300c529u,
+	0xad77ac5eu,
+	0xf19df091u,
+	0xc188f091u,
+	0xad43acd6u,
+	0xf05d1448u,
+	0xf0d1f091u,
+	0x1e784a8u,
+	0x84a1ad77u,
+	0xac56f19du,
+	0xf091101fu,
+	0x1f084a8u,
+	0x84a1f19du,
+	0xf091ca88u,
+	0xf0911148u,
+	0xad77ac3au,
+	0x10484b0u,
+	0xf11d0101u,
+	0x84b0f11du,
+	0x10284b0u,
+	0xf11d0103u,
+	0x84b0f11du,
+	0xf0911022u,
+	0x2000304u,
+	0xc529f11du,
+	0xf091cac8u,
+	0xf0910100u,
+	0xad75ac26u,
+	0x84b0f19du,
+	0xf091c188u,
+	0xf091ad43u,
+	0xacd6f05du,
+	0x1448f0d1u,
+	0xf0910cc0u,
+	0x1600ad08u,
+	0xac02f05du,
+	0xf091ad08u,
+	0xac02f05du,
+	0xf091100du,
+	0x111ff0d1u,
+	0xf091ad7cu,
+	0xacc0f05du,
+	0x510c03u,
+	0x5e00ad08u,
+	0xac02f05du,
+	0xf0910c02u,
+	0x5e00e687u,
+	0xf091f0d1u,
+	0x260409ffu,
+	0xe707f091u,
+	0xe5fbf091u,
+	0xe707f091u,
+	0xe06df091u,
+	0x103a100fu,
+	0x110cad28u,
+	0xacf4f05du,
+	0xf0910000u,
+	0xc1d8f091u,
+	0x103a0200u,
+	0x304c101u,
+	0xc1210200u,
+	0x300c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0xc338f091u,
+	0xc888f091u,
+	0x9f70c898u,
+	0xf0916310u,
+	0x2605ad77u,
+	0xac6ef01du,
+	0xf0914100u,
+	0xa234a39fu,
+	0xc022f091u,
+	0xc021e18bu,
+	0xf031ad77u,
+	0xacfaf01du,
+	0xf0914000u,
+	0xa19fa038u,
+	0xf01f091u,
+	0xf031f0d1u,
+	0xc021fe2fu,
+	0xb27ef0a3u,
+	0x8d4f091u,
+	0x10401141u,
+	0x12421343u,
+	0x14441545u,
+	0x1646fe2fu,
+	0xb27ef0a3u,
+	0x8d4f091u,
+	0x10741276u,
+	0x1478167au,
+	0xfe2fb27eu,
+	0xf0a308d4u,
+	0xf091107cu,
+	0xc03ef091u,
+	0x808101cu,
+	0xff2fc0beu,
+	0xf091ad47u,
+	0xac50f05du,
+	0xf091ad47u,
+	0xac60ea87u,
+	0xf091ad47u,
+	0xac70f05du,
+	0xf091f12fu,
+	0xc02ef091u,
+	0xbc68b27eu,
+	0xf0a308c4u,
+	0xf091f22fu,
+	0xb468b66au,
+	0xb86cba6eu,
+	0xb27ef0a3u,
+	0x8c4f091u,
+	0xf22f5048u,
+	0x5149524au,
+	0x534b544cu,
+	0x554d564eu,
+	0xb27ef0a3u,
+	0x8c4f091u,
+	0xf22fad77u,
+	0xacd4f01du,
+	0x41004100u,
+	0xa234a39fu,
+	0xc039e111u,
+	0xc139e18du,
+	0xf0914000u,
+	0xa19fa038u,
+	0xf00f091u,
+	0xf0d1f091u,
+	0x4200a59fu,
+	0xa438c024u,
+	0xf091d020u,
+	0xf091c101u,
+	0xc034f091u,
+	0xc533d030u,
+	0xf0914000u,
+	0xa19fa036u,
+	0xc020f439u,
+	0xc022f091u,
+	0xc0a2f091u,
+	0xc030f091u,
+	0xf031d030u,
+	0xf091f135u,
+	0xc021c022u,
+	0xf091e191u,
+	0xf0914000u,
+	0xa19fa034u,
+	0xc030f091u,
+	0xe007f091u,
+	0xc034f091u,
+	0xd032f091u,
+	0xd0b2f091u,
+	0xf0d1f091u,
+	0x4001a102u,
+	0xa0000400u,
+	0x5400203u,
+	0x3f45140u,
+	0xb2702140u,
+	0x2043f091u,
+	0xdf73e10fu,
+	0xd281e1f1u,
+	0x10408170u,
+	0x5048e069u,
+	0x51400603u,
+	0x7f44001u,
+	0xa102a000u,
+	0x4200a502u,
+	0xa4200901u,
+	0xc0a4f091u,
+	0xc039e12bu,
+	0x101u,
+	0x1270c423u,
+	0x1140c034u,
+	0xf091d0b4u,
+	0xf091d184u,
+	0xf0918030u,
+	0xc171cc17u,
+	0xc251d081u,
+	0xe289f091u,
+	0x10408170u,
+	0x5048e5cdu,
+	0xf2254100u,
+	0xa39fa238u,
+	0xf032f091u,
+	0x4100a39fu,
+	0xa234106eu,
+	0xc171d291u,
+	0xe289f091u,
+	0x12409f72u,
+	0x504adf71u,
+	0xe115d281u,
+	0xe289f091u,
+	0x12408172u,
+	0x504ac032u,
+	0xf931e06bu,
+	0xb270c031u,
+	0xc032f091u,
+	0x4000a19fu,
+	0xa036c030u,
+	0xf933f0d1u,
+	0xf0910002u,
+	0xff830400u,
+	0x6040700u,
+	0x4000580u,
+	0x4102a300u,
+	0xa2004000u,
+	0xa179a0d6u,
+	0xc030f933u,
+	0xc031b072u,
+	0x5041df77u,
+	0xe119d683u,
+	0xe1871241u,
+	0x8172514au,
+	0xc030f933u,
+	0xc090f091u,
+	0xe069b072u,
+	0x5041b270u,
+	0x5140c030u,
+	0xf091c090u,
+	0xf0914000u,
+	0xa179a0d8u,
+	0xc030f933u,
+	0xf0d1f091u,
+	0x4100a379u,
+	0xa2d6c022u,
+	0xf091c021u,
+	0xe187f031u,
+	0xf0d1f091u,
+	0x4000a179u,
+	0xa0da0f01u,
+	0xf091f031u,
+	0x201e090u,
+	0xf091f0d1u,
+	0xf091f031u,
+	0xd120f091u,
+	0xc523e12fu,
+	0xf433f337u,
+	0xd03ef091u,
+	0xffaff631u,
+	0xad58ac6au,
+	0xf05df091u,
+	0xd124f091u,
+	0xc523e18bu,
+	0xf091ad57u,
+	0xacbaf05du,
+	0xf091f0afu,
+	0xd02ef091u,
+	0xf633f0d1u,
+	0xf091f031u,
+	0xc120f439u,
+	0xc533e090u,
+	0xf0914000u,
+	0xa179a0dau,
+	0x4100a379u,
+	0xa2d60f00u,
+	0xf091ad7au,
+	0xace6f135u,
+	0xc021f11du,
+	0xf091c1a4u,
+	0xf091cf39u,
+	0xf19df091u,
+	0xc124f091u,
+	0xc021ad7au,
+	0xacdef11du,
+	0xf091ad56u,
+	0xacaef05du,
+	0xf091ad51u,
+	0xac2cf05du,
+	0xf091f0d1u,
+	0xf091f137u,
+	0xc086f091u,
+	0x15080a0u,
+	0xc096f091u,
+	0x101u,
+	0xcc36f091u,
+	0x8c1c126u,
+	0xf091c021u,
+	0xad7bac50u,
+	0xf11df031u,
+	0xc120f091u,
+	0xc520f091u,
+	0xc021ad7bu,
+	0xac50f11du,
+	0xf031c720u,
+	0xf091f337u,
+	0xc531e199u,
+	0xf091c031u,
+	0xc330f091u,
+	0xc3b0f091u,
+	0xc530f091u,
+	0xc5b0f091u,
+	0xc630f091u,
+	0xc020f091u,
+	0xad7bac18u,
+	0xf01df091u,
+	0x8c2c1a6u,
+	0xf039e180u,
+	0xf091a100u,
+	0xa000ad4cu,
+	0xac22f05du,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x4000u,
+	0xa17ba06au,
+	0xc030f091u,
+	0xd0b0f091u,
+	0xf1354400u,
+	0xa9a1a830u,
+	0xc084f091u,
+	0x11488538u,
+	0xe10b0b00u,
+	0x4400a9a1u,
+	0xa8700b01u,
+	0xc084f091u,
+	0x8638e195u,
+	0x12080a8u,
+	0x10880a0u,
+	0xc094f091u,
+	0xc928f091u,
+	0xcc34f091u,
+	0xc1a4f091u,
+	0xc021ad7cu,
+	0xac5af11du,
+	0xf631f335u,
+	0xd03ef091u,
+	0xffaf2303u,
+	0x112u,
+	0xd4852224u,
+	0x21182002u,
+	0xf0914000u,
+	0xa17ba06au,
+	0xc020f091u,
+	0xd0a0f091u,
+	0x2e0cb276u,
+	0x8c4f091u,
+	0x2e000000u,
+	0x101c82du,
+	0x142u,
+	0xc8259fb7u,
+	0x2e84c031u,
+	0xc5332e08u,
+	0x2e102e14u,
+	0xcea8f091u,
+	0x2d220600u,
+	0xad38acdeu,
+	0xf05db476u,
+	0xf0afc02eu,
+	0xf091f431u,
+	0xcca4f091u,
+	0xc021e12fu,
+	0xf631ff06u,
+	0xf091b276u,
+	0x9f73e10bu,
+	0xf091c0a2u,
+	0xf239e075u,
+	0xf091cfa2u,
+	0xf091ccb4u,
+	0xf091c031u,
+	0xcfb2f091u,
+	0x4000a17bu,
+	0xa0c2f011u,
+	0xf091f0d1u,
+	0xf091f0d1u,
+	0xf091f0d1u,
+	0xf091f0d1u,
+	0xf0910907u,
+	0x100f110cu,
+	0xc032f091u,
+	0x103ac0b2u,
+	0xf0916310u,
+	0xe5efc4f3u,
+	0xf0d1f091u,
+	0x98f0600u,
+	0x700f235u,
+	0x106e2200u,
+	0x21403468u,
+	0x2008f091u,
+	0xe507f091u,
+	0xe07bf091u,
+	0x22002140u,
+	0x2003f091u,
+	0x140u,
+	0xcf01e5ddu,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x0u,
+	0x0u,
+	0xc03ef091u,
+	0xffaf1070u,
+	0x4000a1a2u,
+	0xa0b0c030u,
+	0xf0911072u,
+	0xc0b0f091u,
+	0x1074c130u,
+	0xf0911076u,
+	0xc1b0f091u,
+	0x1078c230u,
+	0xf091107au,
+	0xc2b0f091u,
+	0x107cc330u,
+	0xf091107eu,
+	0xc3b0f091u,
+	0xf0afc02eu,
+	0xf091c430u,
+	0xf091d4b0u,
+	0xf091e530u,
+	0xf091f5b0u,
+	0xf0914100u,
+	0xa300a258u,
+	0xd002f091u,
+	0xc032f091u,
+	0x4100a3a2u,
+	0xa2d0ad7cu,
+	0xac66f05du,
+	0xf0914100u,
+	0xa3a3a250u,
+	0xad7cac6au,
+	0xf05d0b00u,
+	0x4100a3a3u,
+	0xa270ad7cu,
+	0xac6af05du,
+	0xb012300u,
+	0x4100a3a3u,
+	0xa2902200u,
+	0x21402003u,
+	0xf0912301u,
+	0x4100a3a3u,
+	0xa2d02200u,
+	0x21402003u,
+	0xf0912302u,
+	0x4100a3a4u,
+	0xa2102200u,
+	0x21402003u,
+	0xf0912303u,
+	0x4100a3a4u,
+	0xa2502200u,
+	0x21402003u,
+	0xf0910008u,
+	0xb001c48u,
+	0x53000b01u,
+	0x1c485300u,
+	0x10060108u,
+	0x80a01c48u,
+	0x57000c00u,
+	0x5500ad08u,
+	0xac02f05du,
+	0xf0910c02u,
+	0x5500ad08u,
+	0xac02f05du,
+	0xf0910c01u,
+	0x5500ad08u,
+	0xac02f05du,
+	0xf0910c03u,
+	0x5500ad08u,
+	0xac02f05du,
+	0xf0910c00u,
+	0x5500ad08u,
+	0xac02f05du,
+	0xf0910c02u,
+	0x5500ad08u,
+	0xac02f05du,
+	0xf0910c01u,
+	0x5500ad08u,
+	0xac02f05du,
+	0xf0910c03u,
+	0x5500ad08u,
+	0xac02f05du,
+	0xf091ad7cu,
+	0xac840410u,
+	0x500f05du,
+	0xb00ad7cu,
+	0xac840434u,
+	0x500f05du,
+	0xb01e07fu,
+	0xf0914000u,
+	0xa19fa050u,
+	0x300108u,
+	0xc030f091u,
+	0x4000a193u,
+	0xa09c0093u,
+	0x19ec030u,
+	0xf091b268u,
+	0x4100c022u,
+	0xf09102ffu,
+	0x3ffad7eu,
+	0xacbcc531u,
+	0xf11df091u,
+	0x4000a19fu,
+	0xa04cc020u,
+	0xf091d0a2u,
+	0xf091c023u,
+	0xc030f091u,
+	0x4000a19fu,
+	0xa04ec020u,
+	0xf091c023u,
+	0xc030f091u,
+	0xc022f091u,
+	0xbc68f05du,
+	0xf0914000u,
+	0xa193a09cu,
+	0xad7eacaau,
+	0xc021f19du,
+	0xf091c020u,
+	0xf091b268u,
+	0x4100c0a2u,
+	0xf0914100u,
+	0xa39fa24cu,
+	0xd022f091u,
+	0xc131c032u,
+	0xf091c020u,
+	0xf091c471u,
+	0xc030f091u,
+	0xad7eac3au,
+	0xf01df091u,
+	0x4000a19fu,
+	0xa0500030u,
+	0x100c030u,
+	0xf091f0d1u,
+	0xf091e03eu,
+	0xf091ffafu,
+	0xad7fac1au,
+	0x4000a19fu,
+	0xa050e020u,
+	0xf0910600u,
+	0x71fcb2du,
+	0xe18bf091u,
+	0xd030f091u,
+	0xe009f091u,
+	0xca33f19du,
+	0xf0914000u,
+	0xa19fa04au,
+	0xc030f091u,
+	0x4000a19fu,
+	0xa052f0afu,
+	0xe02ef091u,
+	0xe030f091u,
+	0x8030f0d1u,
+	0x8020f0afu,
+	0xe02ef091u,
+	0xe0750001u,
+	0x4000a19fu,
+	0xa04ac020u,
+	0xf091020eu,
+	0x383c129u,
+	0xad80ac68u,
+	0xc021f11du,
+	0xf0914000u,
+	0xa193a07eu,
+	0xc020f091u,
+	0xb2684100u,
+	0xc022f091u,
+	0x2ff03ffu,
+	0xad7fac74u,
+	0xc531f19du,
+	0xf0914000u,
+	0xa193a07eu,
+	0x930180u,
+	0xc030f091u,
+	0xad7fac48u,
+	0xf01df091u,
+	0x4200a59fu,
+	0xa44ac024u,
+	0xf091d0a2u,
+	0xf091ad80u,
+	0xac0cc129u,
+	0xf11df091u,
+	0x4000a19fu,
+	0xa04cc020u,
+	0xf091c023u,
+	0xc030f091u,
+	0xc022f091u,
+	0xbc68f05du,
+	0xf0914000u,
+	0xa193a07eu,
+	0xd020f091u,
+	0xb26a4100u,
+	0xd0a2f091u,
+	0xad7faceau,
+	0xc021f19du,
+	0xf0914100u,
+	0xa39fa24cu,
+	0xc022f091u,
+	0xc131c032u,
+	0xf0914200u,
+	0xa59fa450u,
+	0xc024f091u,
+	0x4030500u,
+	0xad80ac0cu,
+	0xc02df19du,
+	0xf0914200u,
+	0xa59fa450u,
+	0xc024f091u,
+	0x4fe05ffu,
+	0xc02dc034u,
+	0xf091a59fu,
+	0xa44ac024u,
+	0xf091c531u,
+	0xd034f091u,
+	0xc020f091u,
+	0xc471c030u,
+	0xf091ad7fu,
+	0xac484000u,
+	0xa193a09au,
+	0xc020f091u,
+	0xc171c030u,
+	0xf0914000u,
+	0xa19fa04au,
+	0xc020f091u,
+	0xad80ac68u,
+	0xc021f19du,
+	0xf0914000u,
+	0xa19fa052u,
+	0xc020f091u,
+	0xc021e11du,
+	0xbc68f05du,
+	0xf0914000u,
+	0xa19fa052u,
+	0xc031c030u,
+	0xf0914000u,
+	0xa193a09au,
+	0xc030f091u,
+	0xf0d1f091u,
+	0x4000a19fu,
+	0xa050c020u,
+	0xf0910600u,
+	0x71fc329u,
+	0xc231e18fu,
+	0xf0910633u,
+	0x700c72bu,
+	0xc121c030u,
+	0xf091f0d1u,
+	0xf0914000u,
+	0xa19fa050u,
+	0xc020f091u,
+	0xc229e109u,
+	0xf091c031u,
+	0xc030f091u,
+	0xf0d1f091u,
+	0x4300c026u,
+	0xf091b268u,
+	0x4100c0a6u,
+	0xf091d1a6u,
+	0xf091e022u,
+	0xf091c229u,
+	0xf0d1f091u,
+	0x4000a19fu,
+	0xa0560280u,
+	0x300d030u,
+	0xf091ad9au,
+	0xacaaf05du,
+	0xf091ad93u,
+	0xacb4f05du,
+	0xf091ad98u,
+	0xaca4f05du,
+	0xf091ad96u,
+	0xac26f05du,
+	0xf0914100u,
+	0xa39fa256u,
+	0xad8fac8cu,
+	0x27ff05du,
+	0x3ff4300u,
+	0xa79fa656u,
+	0xc026f091u,
+	0xc021f0d1u,
+	0xf0910000u,
+	0x1004000u,
+	0xa1a0a078u,
+	0xc030f091u,
+	0x4000a19fu,
+	0xa050d020u,
+	0xf091ad81u,
+	0xac88cc3bu,
+	0xf11df091u,
+	0xc0aaf091u,
+	0xb0684000u,
+	0x2800300u,
+	0xd030f091u,
+	0x127ad03eu,
+	0xf091ffafu,
+	0xb00ad8cu,
+	0xac44f05du,
+	0xf091e00au,
+	0xf091154au,
+	0xad84acf8u,
+	0xf05df091u,
+	0xf0afd02eu,
+	0xf091ba6au,
+	0x4500d0aau,
+	0xf091b06au,
+	0x4000c030u,
+	0xf0914100u,
+	0xa3a0a278u,
+	0xc032f091u,
+	0x4000a19fu,
+	0xa050d020u,
+	0xf091ad81u,
+	0xacf6cd3bu,
+	0xf11df091u,
+	0xc0aaf091u,
+	0xc271b068u,
+	0x40000280u,
+	0x300d030u,
+	0xf091127au,
+	0xd03ef091u,
+	0xffaf0b01u,
+	0xad8cac44u,
+	0xf05df091u,
+	0xe00af091u,
+	0x154aad84u,
+	0xacf8f05du,
+	0xf091f0afu,
+	0xd02ef091u,
+	0xba6a4500u,
+	0xd0aaf091u,
+	0xc273b06au,
+	0x4000c030u,
+	0xf0914100u,
+	0xa3a0a278u,
+	0xd022f091u,
+	0xc521d032u,
+	0xf091f0d1u,
+	0xc123aba0u,
+	0xaa50ad81u,
+	0xac16f05du,
+	0x4500f0d1u,
+	0xf091aba0u,
+	0xaa58ad81u,
+	0xac16f05du,
+	0x4500f0d1u,
+	0xf091aba0u,
+	0xaa60ad81u,
+	0xac16f05du,
+	0x4500f0d1u,
+	0xf091aaaau,
+	0x5555ffffu,
+	0x101u,
+	0x2020404u,
+	0x8081010u,
+	0x20204040u,
+	0x80800000u,
+	0x4000a19fu,
+	0xa0700080u,
+	0x100c030u,
+	0xf0910000u,
+	0x100c130u,
+	0xf0914000u,
+	0xa1a6a000u,
+	0x20100u,
+	0xad90ac4eu,
+	0xf05df091u,
+	0x8020e11bu,
+	0xf0914100u,
+	0xa39fa270u,
+	0xad8fac7eu,
+	0x200f05du,
+	0x303ad83u,
+	0xacc0f01du,
+	0xf0914000u,
+	0xa18ea000u,
+	0x103u,
+	0xc03ef091u,
+	0xffafc03eu,
+	0xf931ffafu,
+	0x4100a3a6u,
+	0xa2000002u,
+	0x100ad83u,
+	0xace0f05du,
+	0xf091f0afu,
+	0xc02ef039u,
+	0xc03ef931u,
+	0xffaf0002u,
+	0x100ad84u,
+	0xac4ef05du,
+	0xf091f0afu,
+	0xc02ef039u,
+	0xc03ef931u,
+	0xffaf0002u,
+	0x100ad84u,
+	0xac9ef05du,
+	0xf0914100u,
+	0xa382a22au,
+	0xf0afc02eu,
+	0xf039c03eu,
+	0xf931ffafu,
+	0x20100u,
+	0xad83acfeu,
+	0xf05df091u,
+	0xc2f30482u,
+	0x544cab3u,
+	0xe1dff091u,
+	0xf0afc02eu,
+	0xf239c03eu,
+	0xf933ffafu,
+	0x20100u,
+	0x4000a1a6u,
+	0xa000ad83u,
+	0xace0f05du,
+	0xf091f0afu,
+	0xc02ef039u,
+	0x2020300u,
+	0xd181f0afu,
+	0xc02ef091u,
+	0xdf71ad82u,
+	0xac94c021u,
+	0xf19df091u,
+	0x4100a39fu,
+	0xa270d022u,
+	0xf0910400u,
+	0x501ca2bu,
+	0xe11ff091u,
+	0x4000a19fu,
+	0xa0700400u,
+	0x502d020u,
+	0xf091ca23u,
+	0xe030f091u,
+	0xad83acc0u,
+	0xf01df091u,
+	0x4000a100u,
+	0xa0000000u,
+	0x180ad91u,
+	0xac20f05du,
+	0xf0914001u,
+	0xa100a000u,
+	0x180u,
+	0xad91ac20u,
+	0xf05df091u,
+	0x4002a100u,
+	0xa0000000u,
+	0x180ad91u,
+	0xac20f05du,
+	0xf0914003u,
+	0xa100a000u,
+	0x180u,
+	0xad91ac20u,
+	0xf05df091u,
+	0x4100a39fu,
+	0xa270ad8fu,
+	0xac8c027fu,
+	0xf05d03ffu,
+	0xad80acacu,
+	0xa79fa6a4u,
+	0xf05df091u,
+	0xf0d1f091u,
+	0xdc81d020u,
+	0xf091d032u,
+	0xf091c2f1u,
+	0xc2f31676u,
+	0xcfb1e1efu,
+	0xf091f0d1u,
+	0xf0910000u,
+	0xb870u,
+	0xdc81d022u,
+	0xf0910000u,
+	0x4500ab83u,
+	0xaafad030u,
+	0xf091c2f1u,
+	0x1670cfb7u,
+	0xe1f5f091u,
+	0xb078e020u,
+	0xf091ce33u,
+	0xe191f091u,
+	0xc2f11670u,
+	0xcfb7e1efu,
+	0xf091f0d1u,
+	0xf0914100u,
+	0xa39fa270u,
+	0xad8fac7eu,
+	0x200f05du,
+	0x303c0b2u,
+	0xf931e067u,
+	0x1b870u,
+	0xdc8102aau,
+	0x3aa0000u,
+	0xd030f091u,
+	0xc173c2f1u,
+	0x1670cfb7u,
+	0xe1f3f091u,
+	0xb07802aau,
+	0x3aae020u,
+	0xf091ce33u,
+	0xe191c173u,
+	0xc2f11670u,
+	0xcfb7e1efu,
+	0xf091f0d1u,
+	0xf0914100u,
+	0xa39fa270u,
+	0xad8fac7eu,
+	0x200f05du,
+	0x303c0b2u,
+	0xf931e067u,
+	0x1b870u,
+	0xdc8102aau,
+	0x3aa0455u,
+	0x5550000u,
+	0xd030f091u,
+	0xe0b0f091u,
+	0xc4f11670u,
+	0xcfb7e1f1u,
+	0xf091b078u,
+	0xf020f091u,
+	0xcf33e199u,
+	0xf091f0a0u,
+	0xf091cf35u,
+	0xe18fc4f1u,
+	0x1670cfb7u,
+	0xe1e7f091u,
+	0xf0d1f091u,
+	0x4100a39fu,
+	0xa270ad8fu,
+	0xac7e0200u,
+	0xf05d0303u,
+	0xc0b2f931u,
+	0xe0670001u,
+	0x104d4000u,
+	0xa1a8a016u,
+	0xc010f091u,
+	0x4000a1a8u,
+	0xa01ac031u,
+	0xc030f091u,
+	0x4000a1a8u,
+	0xa018a3a0u,
+	0xa2381072u,
+	0xc030f091u,
+	0xad85ac6eu,
+	0xc020f091u,
+	0xb068c020u,
+	0xf09102ffu,
+	0x3ffc531u,
+	0xf11d4000u,
+	0xa1a8a020u,
+	0xad8cacb6u,
+	0xf05d0440u,
+	0x4000a1a8u,
+	0xa016e000u,
+	0xf091154au,
+	0xad85ac98u,
+	0xf05d4000u,
+	0xa1a8a018u,
+	0xc021e19du,
+	0xf091c020u,
+	0xf091ad85u,
+	0xac1cf01du,
+	0xc2714000u,
+	0xa1a8a01au,
+	0xc020f091u,
+	0xf0d1c021u,
+	0x4100a3a8u,
+	0xa21ad022u,
+	0xf091c121u,
+	0xc032f091u,
+	0xa1a8a018u,
+	0xad85ac62u,
+	0xf01d4000u,
+	0x4000a1a0u,
+	0xa0360000u,
+	0xc010f091u,
+	0x100u,
+	0x4000a1a8u,
+	0xa008c030u,
+	0xf091c0b0u,
+	0xf091c130u,
+	0xf091c1b0u,
+	0xf091c230u,
+	0xf091a1a8u,
+	0xa012c010u,
+	0xf0914000u,
+	0xa19fa058u,
+	0xc030f091u,
+	0xc0b0f091u,
+	0xc015800u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xc015e00u,
+	0xad08ac02u,
+	0xf05df091u,
+	0x1c4d5300u,
+	0xad08ac02u,
+	0xf05df091u,
+	0xad8aac1au,
+	0xf05df091u,
+	0xc085900u,
+	0xad5caceeu,
+	0xf05df091u,
+	0x1022ad86u,
+	0xac32c239u,
+	0xf11df091u,
+	0x4000a1a8u,
+	0xa00e0200u,
+	0x340d030u,
+	0xf091ad89u,
+	0xac0cf01du,
+	0xf091ad5cu,
+	0xaceef05du,
+	0xf0910c02u,
+	0x5900ad5du,
+	0xac0af05du,
+	0xf091ad86u,
+	0xacc41022u,
+	0xad5caceeu,
+	0xf05df091u,
+	0xad86acc4u,
+	0xc739f11du,
+	0xf0910c08u,
+	0x5900ad5du,
+	0xac0af05du,
+	0xf0911022u,
+	0xad86acc4u,
+	0xc639f11du,
+	0xf0910c04u,
+	0x5900ad5du,
+	0xac0af05du,
+	0xf0911022u,
+	0xad86acc4u,
+	0xc539f11du,
+	0xf0910c06u,
+	0x5900ad5du,
+	0xac0af05du,
+	0xf0911022u,
+	0xad86acc4u,
+	0xc439f11du,
+	0xf0910c00u,
+	0x5900ad5du,
+	0xac0af05du,
+	0xf0911022u,
+	0x1f084a8u,
+	0x200ad86u,
+	0xacd88931u,
+	0xf11df091u,
+	0x4000a1a8u,
+	0xa00ec020u,
+	0xf0910200u,
+	0x304c121u,
+	0xc030f091u,
+	0x4030500u,
+	0xad4fac6au,
+	0xf05d0600u,
+	0xb8704300u,
+	0xa7a8a608u,
+	0xc036f931u,
+	0x100u,
+	0xc1b0f091u,
+	0xc015c00u,
+	0xc0d5d00u,
+	0x4000a1a8u,
+	0xa00a0000u,
+	0x100c030u,
+	0xf0912302u,
+	0x4300a79fu,
+	0xa6e0e026u,
+	0xf09102ffu,
+	0x3ffad87u,
+	0xac48c633u,
+	0xf11df091u,
+	0xb26ce0a6u,
+	0xf0914400u,
+	0xa9a8a808u,
+	0xc028f039u,
+	0xad8bac58u,
+	0xf05d4101u,
+	0xad87ac16u,
+	0xf01df127u,
+	0xc045800u,
+	0x8c24000u,
+	0xa1a8a00cu,
+	0x9f01e0u,
+	0xc030f091u,
+	0x826103cu,
+	0x4000a1a8u,
+	0xa0100010u,
+	0x100c030u,
+	0xf091ad5cu,
+	0xaceef05du,
+	0xf091ad87u,
+	0xace8e98fu,
+	0xf091f69du,
+	0xf091ad87u,
+	0xaca6f01du,
+	0xf0914000u,
+	0xa1a8a00eu,
+	0xc020f091u,
+	0x2000308u,
+	0xc121c030u,
+	0xf091ad89u,
+	0xac0cf01du,
+	0x1ad08u,
+	0xac02f05du,
+	0xf091ad87u,
+	0xac6e4000u,
+	0xa1a8a010u,
+	0xc020f091u,
+	0xdf71c030u,
+	0xf091c021u,
+	0xf19df091u,
+	0x826103cu,
+	0x4000a1a8u,
+	0xa00ec020u,
+	0xf0910200u,
+	0x302c121u,
+	0xc030f091u,
+	0xad89ac0cu,
+	0xf01df091u,
+	0x2301ad87u,
+	0xacf4fa9du,
+	0xf0912300u,
+	0x100c0243u,
+	0x8930e103u,
+	0xf0914000u,
+	0xa1a8a00cu,
+	0xe020f091u,
+	0xb06ce0a0u,
+	0xf0910000u,
+	0x120ca01u,
+	0xa1a8a00au,
+	0xc020f091u,
+	0x4000a1a6u,
+	0xa000ad1cu,
+	0xac7cf05du,
+	0xf091ad28u,
+	0xacf4f05du,
+	0xf0911030u,
+	0x1232c531u,
+	0xe105f091u,
+	0x62044000u,
+	0xa1a8a00cu,
+	0xc020f091u,
+	0xb068e0a0u,
+	0xf091c865u,
+	0xc020f091u,
+	0xb0684001u,
+	0x4100a3a6u,
+	0xa220c020u,
+	0xf091d022u,
+	0xf091ad89u,
+	0xacaecd31u,
+	0xf19df091u,
+	0xc2f1c2f3u,
+	0xdf75ad88u,
+	0xac5eca25u,
+	0xf19df091u,
+	0x103a0200u,
+	0x3040200u,
+	0x300c101u,
+	0x2240300u,
+	0xc511e405u,
+	0xf091106au,
+	0x4000a1a8u,
+	0xa00ad020u,
+	0xf091c030u,
+	0xf091ad88u,
+	0xacbcc511u,
+	0xf29df091u,
+	0x4000a1a8u,
+	0xa0120001u,
+	0xc010f091u,
+	0x6310ad5du,
+	0xac0af05du,
+	0xf0916302u,
+	0x4000a1a8u,
+	0xa00cc020u,
+	0xf091c471u,
+	0xc030f091u,
+	0xb068c020u,
+	0xf09102ffu,
+	0x3ffad87u,
+	0xac60c531u,
+	0xf19df091u,
+	0x4000a1a8u,
+	0xa008c020u,
+	0xf8394300u,
+	0xa7a8a612u,
+	0xc006f091u,
+	0xad87ac0eu,
+	0x8020f11du,
+	0xf0910000u,
+	0x6305ad8cu,
+	0xaca0f05du,
+	0xf091ad47u,
+	0xac60ea87u,
+	0xf091ad47u,
+	0xac70f05du,
+	0xf0910c00u,
+	0x53000c00u,
+	0x1400ad8cu,
+	0xac4cf05du,
+	0xf0910c01u,
+	0x5800ad08u,
+	0xac02f05du,
+	0xf091ad55u,
+	0xac7af05du,
+	0xf091ad59u,
+	0xac4cf05du,
+	0xf0914000u,
+	0xa1a8a008u,
+	0xc020f091u,
+	0xc021e10fu,
+	0xf091c020u,
+	0xf439ad51u,
+	0xac2cf05du,
+	0xf0910c00u,
+	0x5800ad08u,
+	0xac02f05du,
+	0xf0914000u,
+	0xa1a8a00eu,
+	0xc020f091u,
+	0xc021e119u,
+	0xf091ad89u,
+	0xacdef05du,
+	0xf091c021u,
+	0xe18bf091u,
+	0xad85aca4u,
+	0xf01df091u,
+	0x4000a1a8u,
+	0xa00ec020u,
+	0xf091f0d1u,
+	0xc0211470u,
+	0x1672147eu,
+	0x4000a19fu,
+	0xa058c030u,
+	0xf091d0b0u,
+	0xf0914000u,
+	0xa1a8a00eu,
+	0xc020f091u,
+	0x2000301u,
+	0xc121c030u,
+	0xf091ad89u,
+	0xac0cf01du,
+	0x102ffu,
+	0x3ffad8au,
+	0xac164000u,
+	0xa1a0a036u,
+	0xc000f091u,
+	0x8170c010u,
+	0xf0910203u,
+	0x8812f21du,
+	0xf0914000u,
+	0xa1a8a016u,
+	0xd000f091u,
+	0x1549ad8cu,
+	0xac44f05du,
+	0xf0910200u,
+	0x300f0d1u,
+	0xc123110du,
+	0x4000u,
+	0xa1a8a014u,
+	0x10au,
+	0xc030f091u,
+	0x4e0120u,
+	0xad5dac0au,
+	0xf05df091u,
+	0xe1f7df71u,
+	0x1082a0u,
+	0x1c485300u,
+	0x20100u,
+	0xad5caceeu,
+	0xf05df091u,
+	0xe1f7df71u,
+	0x1c4d5300u,
+	0x104d0c01u,
+	0x5e000964u,
+	0xad5caceeu,
+	0xf05df091u,
+	0xe5f7f091u,
+	0xad8cac5eu,
+	0xf05df091u,
+	0xc905200u,
+	0xad5caceeu,
+	0xf05df091u,
+	0xc041600u,
+	0xc011400u,
+	0xad5dac0au,
+	0xf05df091u,
+	0x826103cu,
+	0xc005800u,
+	0xad5dac0au,
+	0xf05df091u,
+	0xc005900u,
+	0xad5dac0au,
+	0xf05df091u,
+	0xc005e00u,
+	0xad5dac0au,
+	0xf05df091u,
+	0xad8aacd2u,
+	0x96a5f19du,
+	0xf0910c04u,
+	0x16000c01u,
+	0x1400ad5du,
+	0xac0af05du,
+	0xf091100bu,
+	0x102f091u,
+	0x826103cu,
+	0xad8bac20u,
+	0x2100300u,
+	0xc131f19du,
+	0xf09109c8u,
+	0xad5dac0au,
+	0xf05df091u,
+	0xe5f7f091u,
+	0x20003ffu,
+	0x1022ad8bu,
+	0xac54c239u,
+	0xf11df091u,
+	0x14684800u,
+	0x4904ad5du,
+	0xac0af05du,
+	0xf091ad8au,
+	0xacfcdf73u,
+	0xf19df091u,
+	0xad8cac4cu,
+	0xf05df091u,
+	0xad8bacdau,
+	0xf05df091u,
+	0x4000a1a8u,
+	0xa016c000u,
+	0xf0911548u,
+	0xad8aac2cu,
+	0x4000a1a8u,
+	0xa014c020u,
+	0xf091df71u,
+	0xc030f091u,
+	0xf19df091u,
+	0xf0d1f091u,
+	0xc03ef931u,
+	0xffafad08u,
+	0xac0af05du,
+	0xc031126cu,
+	0x800100u,
+	0x2e0c4200u,
+	0xa59fa4c0u,
+	0x12741142u,
+	0x2c432d44u,
+	0x12721141u,
+	0x2e08u,
+	0x22c06u,
+	0x202c02u,
+	0x3812cc7u,
+	0xad77acd4u,
+	0xf05d4100u,
+	0xb2702200u,
+	0x21202003u,
+	0xf091b270u,
+	0xf0afc02eu,
+	0xf03908c1u,
+	0xf133b270u,
+	0xba70f121u,
+	0xd020f091u,
+	0xf023f423u,
+	0xf00c523u,
+	0xe193f13bu,
+	0xdfaaf091u,
+	0xb26a4100u,
+	0xb072f121u,
+	0xf100e00u,
+	0x8c2f0d1u,
+	0xf0910ca8u,
+	0x5a00ad08u,
+	0xac02f05du,
+	0xf0910c28u,
+	0x5a000c01u,
+	0x5800ad5du,
+	0xac0af05du,
+	0xf0910c00u,
+	0x53000c00u,
+	0x5800ad08u,
+	0xac02f05du,
+	0xf091ad5du,
+	0xac0af05du,
+	0xf0910c00u,
+	0x5900ad08u,
+	0xac02f05du,
+	0xf0910c08u,
+	0x5c000c00u,
+	0x5d000c04u,
+	0x5800ad08u,
+	0xac02f05du,
+	0xf0910c04u,
+	0x16000c01u,
+	0x14000c01u,
+	0x15000c02u,
+	0x59006102u,
+	0xf0d1f091u,
+	0xad8bacdau,
+	0xf05df091u,
+	0xc025f00u,
+	0xad8cac5eu,
+	0xf05df091u,
+	0x2604f0d1u,
+	0xf091ad46u,
+	0xac4af05du,
+	0xf0910c01u,
+	0x5e006301u,
+	0xad08ac02u,
+	0xf05df091u,
+	0x6300ad08u,
+	0xac02f05du,
+	0xf09148ffu,
+	0x49ff6304u,
+	0xad08ac02u,
+	0xf05df091u,
+	0x6318ad08u,
+	0xac02f05du,
+	0xf0916206u,
+	0xc441000u,
+	0xf0d1f091u,
+	0x100u,
+	0x4000a1a6u,
+	0xa0000401u,
+	0x500ad8cu,
+	0xacb6f01du,
+	0xf091c030u,
+	0xf091c2f1u,
+	0x9f74e1f7u,
+	0xf091f0d1u,
+	0xf0912300u,
+	0xad8dac4eu,
+	0xf05df091u,
+	0xe113f091u,
+	0x4100a39fu,
+	0xa256ad8fu,
+	0xac7e0200u,
+	0xf05d0310u,
+	0x2301ad8du,
+	0xac4ef05du,
+	0xf091e113u,
+	0xf0914100u,
+	0xa39fa256u,
+	0xad8fac7eu,
+	0x200f05du,
+	0x3202302u,
+	0xad8dac4eu,
+	0xf05df091u,
+	0xe113f091u,
+	0x4100a39fu,
+	0xa256ad8fu,
+	0xac7e0200u,
+	0xf05d0340u,
+	0x2303ad8du,
+	0xac4ef05du,
+	0xf091e113u,
+	0xf0914100u,
+	0xa39fa256u,
+	0xad8fac7eu,
+	0x200f05du,
+	0x380ad80u,
+	0xacaca79fu,
+	0xa6aef05du,
+	0xf091f0d1u,
+	0xf0914100u,
+	0xa3a6a200u,
+	0x22002140u,
+	0x2003f091u,
+	0x4100a38fu,
+	0xa2a0ad8eu,
+	0xac5ef05du,
+	0xf091ad8du,
+	0xacc8f19du,
+	0xf091c2f3u,
+	0xa78fa6bau,
+	0x1276c5b3u,
+	0xe1e5f091u,
+	0x4000a18fu,
+	0xa0a0ad8du,
+	0xacf0f05du,
+	0xf091ad8du,
+	0xacc8f19du,
+	0xf091c2f1u,
+	0xa78fa6bau,
+	0x1276c5b1u,
+	0xe1e5f091u,
+	0x4000a19fu,
+	0xa056c020u,
+	0xf091c139u,
+	0xe197f091u,
+	0x80304100u,
+	0xa3a6a200u,
+	0x22002140u,
+	0x2002f091u,
+	0xf0d18020u,
+	0xe06d0001u,
+	0x4100a3a6u,
+	0xa2002200u,
+	0x21402003u,
+	0xf091f0d1u,
+	0xf0914100u,
+	0xa3a6a200u,
+	0x22002140u,
+	0x2002f091u,
+	0xf0d1f091u,
+	0xc020f091u,
+	0x4100a3a6u,
+	0xa2800200u,
+	0x340dd83u,
+	0xc032f091u,
+	0xc2f31272u,
+	0xc5b7e1f5u,
+	0xf0914100u,
+	0xa3a6a280u,
+	0x22002140u,
+	0x2002f091u,
+	0x4100a3a7u,
+	0xa2002200u,
+	0x21402003u,
+	0xf0914100u,
+	0xa3a6a280u,
+	0x4200a5a7u,
+	0xa4000000u,
+	0x140dc83u,
+	0xc022f091u,
+	0xd024f091u,
+	0xc131e193u,
+	0xf091c2f3u,
+	0xc2f51072u,
+	0xc0b7e1e9u,
+	0x8030f0d1u,
+	0xf091e07fu,
+	0x1c022u,
+	0xf0911268u,
+	0x2e002e04u,
+	0x2e082e0cu,
+	0x2e102e14u,
+	0x2e182e1cu,
+	0x2e202e24u,
+	0x2e282e2cu,
+	0x2e302e34u,
+	0x2e382e3cu,
+	0xad8eac90u,
+	0xf05df091u,
+	0xf0d1f091u,
+	0xad8fac7au,
+	0x2a80ca31u,
+	0xf19df091u,
+	0xcf33f19du,
+	0xf0912a84u,
+	0xca31f19du,
+	0xf091cf33u,
+	0xf19df091u,
+	0x2a88ca31u,
+	0xf19df091u,
+	0xcf33f19du,
+	0xf0912a8cu,
+	0xca31f19du,
+	0xf091cf33u,
+	0xf19df091u,
+	0x2a90ca31u,
+	0xf19df091u,
+	0xcf33f19du,
+	0xf0912a94u,
+	0xca31f19du,
+	0xf091cf33u,
+	0xf19df091u,
+	0x2a98ca31u,
+	0xf19df091u,
+	0xcf33f19du,
+	0xf0912a9cu,
+	0xca31f19du,
+	0xf091cf33u,
+	0xf19df091u,
+	0x2aa0ca31u,
+	0xf19df091u,
+	0xcf33f19du,
+	0xf0912aa4u,
+	0xca31f19du,
+	0xf091cf33u,
+	0xf19df091u,
+	0x2aa8ca31u,
+	0xf19df091u,
+	0xcf33f19du,
+	0xf0912aacu,
+	0xca31f19du,
+	0xf091cf33u,
+	0xf19df091u,
+	0x2ab0ca31u,
+	0xf19df091u,
+	0xcf33f19du,
+	0xf0912ab4u,
+	0xca31f19du,
+	0xf091cf33u,
+	0xf19df091u,
+	0x2ab8ca31u,
+	0xf19df091u,
+	0xcf33f19du,
+	0xf0912abcu,
+	0xca31f19du,
+	0xf091cf33u,
+	0xf19df091u,
+	0x8030f0d1u,
+	0xf091e07bu,
+	0x1e022u,
+	0xf091c525u,
+	0xd032f091u,
+	0xf0d1f091u,
+	0xe022f091u,
+	0xc52dd032u,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x0u,
+	0xcc33aaaau,
+	0x5555ffffu,
+	0x101u,
+	0x2020404u,
+	0x8081010u,
+	0x20204040u,
+	0x80800000u,
+	0x2000000u,
+	0x4100u,
+	0xa38fa2bcu,
+	0xc022f091u,
+	0xad90ac36u,
+	0xc021f11du,
+	0xf0914100u,
+	0xa39fa270u,
+	0x800100u,
+	0xc032f091u,
+	0x4100a38fu,
+	0xa2bac022u,
+	0xf0390000u,
+	0x101ad91u,
+	0xac20f05du,
+	0xf0914100u,
+	0xa38fa2bcu,
+	0xc022f091u,
+	0xdf71c032u,
+	0xf0914100u,
+	0xa38fa2bau,
+	0xc022f039u,
+	0x20100u,
+	0xd081e291u,
+	0xf0911040u,
+	0x81700104u,
+	0x8490e28fu,
+	0xf0915048u,
+	0xc032f931u,
+	0x1f0d1u,
+	0x80204100u,
+	0xa39fa270u,
+	0xad8fac8cu,
+	0x27ff05du,
+	0x3ffe06bu,
+	0x0u,
+	0x2ffu,
+	0x3fed1a9u,
+	0x4500ab90u,
+	0xaa4ac03au,
+	0xf931c0bau,
+	0xf091ad92u,
+	0xaca0f05du,
+	0xf091c02au,
+	0xf039c0aau,
+	0xf091ad93u,
+	0xac0af05du,
+	0xf0914100u,
+	0xa38fa2a0u,
+	0xc02af039u,
+	0xc0aaf091u,
+	0xad92ac3cu,
+	0xf05df091u,
+	0xc2f3048fu,
+	0x5baad90u,
+	0xac80cab3u,
+	0xf19df091u,
+	0x4100a39fu,
+	0xa270d022u,
+	0xf0910400u,
+	0x501ca2bu,
+	0xe1870000u,
+	0xf0d1f091u,
+	0xe07b0001u,
+	0xdc81d020u,
+	0xf091d032u,
+	0xf091c2f1u,
+	0xc2f31676u,
+	0xcfb1e1efu,
+	0xf091f0d1u,
+	0xf091dc81u,
+	0x4100a3a6u,
+	0xa200d020u,
+	0xf091d032u,
+	0xf091c2f1u,
+	0xc2f31676u,
+	0xcfb1e1e9u,
+	0xf091f0d1u,
+	0xf091dc81u,
+	0x4100a3a6u,
+	0xa200d022u,
+	0xf091d030u,
+	0xf091c2f1u,
+	0xc2f31676u,
+	0xcfb1e1e9u,
+	0xf091f0d1u,
+	0xf0910000u,
+	0x2578u,
+	0x2020006eu,
+	0x4500ab91u,
+	0xaa16c03au,
+	0xf931c0bau,
+	0xf091ad91u,
+	0xac4e4200u,
+	0xa5a6a400u,
+	0x12421340u,
+	0x8933f19du,
+	0xf091ad91u,
+	0xac981274u,
+	0xc5b1f11du,
+	0xf091ad91u,
+	0xac6e4200u,
+	0xa5a6a400u,
+	0x12421340u,
+	0x8933f19du,
+	0xf091ad91u,
+	0xac981274u,
+	0xc5b1f11du,
+	0xf0911240u,
+	0xad91aca6u,
+	0x8922f19du,
+	0xf0910202u,
+	0x300dd81u,
+	0xa593a47eu,
+	0x1274c591u,
+	0xe29df091u,
+	0xa58fa49au,
+	0x1276c595u,
+	0xe291f091u,
+	0x2020300u,
+	0xd181ad91u,
+	0xacfaf01du,
+	0xf0914100u,
+	0xa3a6a200u,
+	0x20100u,
+	0xad90acbcu,
+	0xf05df091u,
+	0x4500ab91u,
+	0xaa16c02au,
+	0xf0390002u,
+	0x100ad90u,
+	0xac4ef05du,
+	0xf0910002u,
+	0x1004000u,
+	0xa1a6a000u,
+	0x4500ab91u,
+	0xaa16c02au,
+	0xf239ad90u,
+	0xacbcf05du,
+	0xf0914500u,
+	0xab91aa16u,
+	0xc02af039u,
+	0x2020300u,
+	0xd1814500u,
+	0xab91aa16u,
+	0xc0aaf091u,
+	0xdf71c03au,
+	0xf931c0bau,
+	0xf091ad91u,
+	0xac2ec021u,
+	0xf19df091u,
+	0x4100a39fu,
+	0xa270d022u,
+	0xf0910400u,
+	0x501ad92u,
+	0xac34ca2bu,
+	0xf19d0000u,
+	0xf0d1f091u,
+	0xad92ac30u,
+	0xf01d0001u,
+	0xb8705440u,
+	0xdc81d022u,
+	0xf0910000u,
+	0xd030f091u,
+	0xc2f11670u,
+	0xcfb7e1f5u,
+	0xf091b078u,
+	0x5044e020u,
+	0xf091ce33u,
+	0xe191f091u,
+	0xc2f11670u,
+	0xcfb7e1efu,
+	0xf091f0d1u,
+	0xf0914200u,
+	0xa59fa470u,
+	0xf024f091u,
+	0x101u,
+	0xc027c034u,
+	0xf091c0b4u,
+	0xf931c124u,
+	0xf091c171u,
+	0xc134f091u,
+	0xd1b4f091u,
+	0xe234f091u,
+	0xe0510001u,
+	0xb8705440u,
+	0xdc8102aau,
+	0x3aa0000u,
+	0xd030f091u,
+	0xc173c2f1u,
+	0x1670cfb7u,
+	0xe1f3f091u,
+	0xb0785044u,
+	0x2aa03aau,
+	0xe020f091u,
+	0xce33e191u,
+	0xc173c2f1u,
+	0x1670cfb7u,
+	0xe1eff091u,
+	0xf0d1f091u,
+	0x4200a59fu,
+	0xa470f024u,
+	0xf0910000u,
+	0x101c027u,
+	0xc034f091u,
+	0xc0b4f931u,
+	0xc124f091u,
+	0xc171c134u,
+	0xf091d1b4u,
+	0xf091e234u,
+	0xf091e051u,
+	0x1b870u,
+	0x5440dc81u,
+	0x2aa03aau,
+	0x4550555u,
+	0xd030u,
+	0xf091e0b0u,
+	0xf091c4f1u,
+	0x1670cfb7u,
+	0xe1f1f091u,
+	0xb0785044u,
+	0xf020f091u,
+	0xcf33e199u,
+	0xf091f0a0u,
+	0xf091cf35u,
+	0xe18fc4f1u,
+	0x1670cfb7u,
+	0xe1e7f091u,
+	0xf0d1f091u,
+	0x4200a59fu,
+	0xa470f024u,
+	0xf0910000u,
+	0x101c027u,
+	0xc034f091u,
+	0xc0b4f931u,
+	0xc124f091u,
+	0xc171c134u,
+	0xf091d1b4u,
+	0xf091e234u,
+	0xf091e051u,
+	0x19380u,
+	0x80c80002u,
+	0x8cc60080u,
+	0x82440001u,
+	0x81fa0200u,
+	0x820a0400u,
+	0x821a0800u,
+	0xffff0000u,
+	0x80c8u,
+	0x28cc6u,
+	0x808244u,
+	0x181fau,
+	0x200820au,
+	0x400ffffu,
+	0x4000a196u,
+	0xa00c00abu,
+	0x1aa8f71u,
+	0x927188b0u,
+	0xf191f091u,
+	0xa5015bu,
+	0x2a5035au,
+	0xcf73d273u,
+	0xc931f191u,
+	0xf0910054u,
+	0x30001aau,
+	0x2aa8d01u,
+	0x91b0f191u,
+	0xf09100c6u,
+	0x1230600u,
+	0x70002a5u,
+	0x35a0420u,
+	0x5c9ce03u,
+	0xc731f191u,
+	0xf0910a08u,
+	0x601fcu,
+	0x897988b0u,
+	0xf191f091u,
+	0xa080000u,
+	0x10602ffu,
+	0x3fcc97bu,
+	0xc931f191u,
+	0xf0910a08u,
+	0x60300u,
+	0x1fc0209u,
+	0x8d0991b0u,
+	0xf191f091u,
+	0xa080000u,
+	0x1060600u,
+	0x70002ffu,
+	0x3fc0400u,
+	0x509ce0bu,
+	0xc731f191u,
+	0xf091005au,
+	0x40001a5u,
+	0x24b8d11u,
+	0x91b0f191u,
+	0xf091001bu,
+	0x1fe0600u,
+	0x70002a5u,
+	0x35a0489u,
+	0x55cce13u,
+	0xc731f191u,
+	0xf0910a08u,
+	0x5a0300u,
+	0x1a5024au,
+	0x8d1991b0u,
+	0xf191f091u,
+	0xa080055u,
+	0x1aa0600u,
+	0x70002aau,
+	0x3550454u,
+	0x5aace1bu,
+	0xc731f191u,
+	0xf09100a0u,
+	0x30001aau,
+	0x2f08d29u,
+	0x91b0f191u,
+	0xf09100a1u,
+	0x1400600u,
+	0x70002a5u,
+	0x35a04f9u,
+	0x560ce2bu,
+	0xc731f191u,
+	0xf09100fau,
+	0x30001aau,
+	0x2f08d21u,
+	0x91b0f191u,
+	0xf09100fdu,
+	0x17a0600u,
+	0x70002a5u,
+	0x35a04f9u,
+	0x560ce23u,
+	0xc731f191u,
+	0xf0910080u,
+	0x2000101u,
+	0x8b518d30u,
+	0xf191f091u,
+	0x10100u,
+	0x4000500u,
+	0x2000301u,
+	0xc843ce31u,
+	0xf191f091u,
+	0xae00080u,
+	0x2000101u,
+	0x8b598d30u,
+	0xf191f091u,
+	0xa080001u,
+	0x1008949u,
+	0x8530f191u,
+	0xf0910001u,
+	0x1000400u,
+	0x5000200u,
+	0x301c84bu,
+	0xce31f191u,
+	0xf0910a08u,
+	0x101u,
+	0x2000300u,
+	0xc94bc631u,
+	0xf191f091u,
+	0x400200u,
+	0x1808861u,
+	0x8d30f191u,
+	0xf0910000u,
+	0x1800400u,
+	0x5000201u,
+	0x300c863u,
+	0xce31f191u,
+	0xf0910a00u,
+	0x400200u,
+	0x1808869u,
+	0x8d30f191u,
+	0xf0910a08u,
+	0x800100u,
+	0x88698d30u,
+	0xf191f091u,
+	0xa000000u,
+	0x1800400u,
+	0x5000201u,
+	0x300c86bu,
+	0xce31f191u,
+	0xf0910a08u,
+	0x800100u,
+	0x4000500u,
+	0x2000300u,
+	0xc86bce31u,
+	0xf191f091u,
+	0x808738u,
+	0xf111f091u,
+	0x5a0300u,
+	0x1aa02f0u,
+	0x8d319190u,
+	0xf191f091u,
+	0x5c013au,
+	0x6000700u,
+	0x2a5035au,
+	0x4f90560u,
+	0xce33c711u,
+	0xf191f091u,
+	0xa5015bu,
+	0xa5a5a45au,
+	0xf7e5f8a5u,
+	0xc4b5f191u,
+	0xf0918030u,
+	0xf0d18020u,
+	0x4000a19fu,
+	0xa056c020u,
+	0xf0910202u,
+	0x300c121u,
+	0xc030f091u,
+	0xf091e065u,
+	0x14400u,
+	0xa9a8a802u,
+	0x4000504u,
+	0x2ff03e0u,
+	0xc005400u,
+	0x822103cu,
+	0xc129c131u,
+	0xe177f091u,
+	0xe003f091u,
+	0x822103cu,
+	0xc038f091u,
+	0xf091f091u,
+	0xf091f091u,
+	0xf091f091u,
+	0xf091f091u,
+	0xf091f091u,
+	0x822123cu,
+	0xd038f091u,
+	0xc111c038u,
+	0xf091e21fu,
+	0xf0910200u,
+	0x304c129u,
+	0xc231e113u,
+	0xf0914100u,
+	0xa39fa256u,
+	0xad8fac7eu,
+	0x210f05du,
+	0x300f091u,
+	0xc405000u,
+	0xad97acecu,
+	0x2bc03dau,
+	0x400aa1bcu,
+	0xa0def131u,
+	0xc531f19du,
+	0x410aa3bcu,
+	0xa2d0f031u,
+	0x10701272u,
+	0xc531f19du,
+	0x10401241u,
+	0x8930f19du,
+	0x4100a3a6u,
+	0xa2004206u,
+	0xa578a49au,
+	0xc032f935u,
+	0xc022f091u,
+	0x2780396u,
+	0xc531f19du,
+	0xf091c022u,
+	0xf4394306u,
+	0xa778a690u,
+	0x10741276u,
+	0xc131f19du,
+	0x10421243u,
+	0x8130f19du,
+	0x4100a3a6u,
+	0xa200a523u,
+	0xa4454201u,
+	0xa7cda6efu,
+	0x430ba912u,
+	0xa834440fu,
+	0xabedaac0u,
+	0x450f08d4u,
+	0xf9354000u,
+	0xa1a6a008u,
+	0x10701272u,
+	0xc131f19du,
+	0x10401241u,
+	0x8130f19du,
+	0x4100a3a6u,
+	0xa200c022u,
+	0xf0910223u,
+	0x341c531u,
+	0xf19df091u,
+	0xc0a2f091u,
+	0x2cd03ebu,
+	0xc531f19du,
+	0xf091c122u,
+	0xf0910212u,
+	0x33fc531u,
+	0xf19df091u,
+	0xc1a2f091u,
+	0x2ed03cfu,
+	0xc531f19du,
+	0xa500a400u,
+	0xa700a600u,
+	0xa900a800u,
+	0xab00aa00u,
+	0x8c4f439u,
+	0x4000a1a6u,
+	0xa0081070u,
+	0x1272c131u,
+	0xf19d4001u,
+	0xa123a040u,
+	0x10701274u,
+	0xc131f19du,
+	0x10401242u,
+	0x8130f19du,
+	0x400ba1cdu,
+	0xa0e01070u,
+	0x1276c131u,
+	0xf19d1040u,
+	0x12438130u,
+	0xf19d400fu,
+	0xa112a030u,
+	0x10701278u,
+	0xc131f19du,
+	0x10401244u,
+	0x8130f19du,
+	0x400fa1edu,
+	0xa0c01070u,
+	0x127ac131u,
+	0xf19d1040u,
+	0x12458130u,
+	0xe113f091u,
+	0x4100a39fu,
+	0xa256ad8fu,
+	0xac7e0220u,
+	0xf05d0300u,
+	0x4000a198u,
+	0xa08a0100u,
+	0xff0200u,
+	0x9076860u,
+	0x8d31f191u,
+	0xf0918140u,
+	0x8172e5f3u,
+	0xf09102ffu,
+	0x68608d31u,
+	0xf191f091u,
+	0x2000300u,
+	0xff01ffu,
+	0x4000500u,
+	0x90f6960u,
+	0xce33f191u,
+	0xf091c141u,
+	0xc175e5f3u,
+	0xf09104ffu,
+	0x5ff6960u,
+	0xce33f191u,
+	0xf0910100u,
+	0x201u,
+	0x9076840u,
+	0x8d31f191u,
+	0xf0918170u,
+	0x8942e5f3u,
+	0xf0910200u,
+	0x3000000u,
+	0x1000400u,
+	0x501090fu,
+	0x6940ce33u,
+	0xf191f091u,
+	0xc171c945u,
+	0xe5f3f091u,
+	0x8030f0d1u,
+	0x80204000u,
+	0xa19fa056u,
+	0xc020f091u,
+	0x2010300u,
+	0xc121c030u,
+	0xf091f091u,
+	0xe0650001u,
+	0x4000a19au,
+	0xa0920100u,
+	0x1a599u,
+	0xa42ef015u,
+	0xf0910102u,
+	0x88b0f191u,
+	0xf0910100u,
+	0x3e019u,
+	0xf0910104u,
+	0x88b0f191u,
+	0xf0910100u,
+	0x5a599u,
+	0xa4420a04u,
+	0xf115f091u,
+	0x10388b0u,
+	0xf191f091u,
+	0x1000004u,
+	0xe05df091u,
+	0x10688b0u,
+	0xf191f091u,
+	0x1000007u,
+	0xa599a458u,
+	0xa08f215u,
+	0xf0910108u,
+	0x88b0f191u,
+	0xf0910100u,
+	0x9a599u,
+	0xa46e0a02u,
+	0xf395f091u,
+	0x10a88b0u,
+	0xf191f091u,
+	0x100000bu,
+	0xa599a49au,
+	0xa01f415u,
+	0xf0910101u,
+	0x88b0f191u,
+	0xf0910100u,
+	0x2a598u,
+	0xa4b6f015u,
+	0xf0910105u,
+	0x88b0f191u,
+	0xf0910100u,
+	0x6a598u,
+	0xa4ec0a0au,
+	0xf195f091u,
+	0x10788b0u,
+	0xf191f091u,
+	0x1000008u,
+	0xa599a402u,
+	0xa07f295u,
+	0xf0910109u,
+	0x88b0f191u,
+	0xf0910100u,
+	0xaa599u,
+	0xa4180a0du,
+	0xf315f091u,
+	0x10c88b0u,
+	0xf191f091u,
+	0x90e0000u,
+	0x10fa599u,
+	0xa4acf015u,
+	0xf091010bu,
+	0x88b0f191u,
+	0xf0910100u,
+	0xc0a08u,
+	0xe25bf091u,
+	0x8170f595u,
+	0xf09188b0u,
+	0xf191f091u,
+	0x100u,
+	0x2ff037fu,
+	0x14704200u,
+	0xa5a8a402u,
+	0xe034f091u,
+	0xa199a0f2u,
+	0xf051f091u,
+	0xa5a8a402u,
+	0xe024f091u,
+	0xb06c9930u,
+	0xf191f091u,
+	0x99b1f191u,
+	0xf091ad9au,
+	0xac8af01du,
+	0xf0910601u,
+	0x8320a19au,
+	0xa006f051u,
+	0xf0910640u,
+	0x8721f0d1u,
+	0xf0910602u,
+	0x8320a19au,
+	0xa01af051u,
+	0xf0910620u,
+	0x8721f0d1u,
+	0xf0910604u,
+	0x8320a19au,
+	0xa02ef051u,
+	0xf0910610u,
+	0x8721f0d1u,
+	0xf0910608u,
+	0x8320a19au,
+	0xa042f051u,
+	0xf0910608u,
+	0x8721f0d1u,
+	0xf0910610u,
+	0x8320a19au,
+	0xa056f051u,
+	0xf0910604u,
+	0x8721f0d1u,
+	0xf0910620u,
+	0x8320a19au,
+	0xa06af051u,
+	0xf0910602u,
+	0x8721f0d1u,
+	0xf0910640u,
+	0x8320147cu,
+	0xad9aac80u,
+	0xf05df091u,
+	0x6018721u,
+	0xf0d1f091u,
+	0x6808320u,
+	0xbc6cf0d1u,
+	0xf091f091u,
+	0x8030f0d1u,
+	0x80204000u,
+	0xa19fa056u,
+	0xc020f091u,
+	0x2040300u,
+	0xc121c030u,
+	0xf091e06bu,
+	0x14000u,
+	0xa1a8a000u,
+	0x107ec030u,
+	0xf0914100u,
+	0xa39da2f6u,
+	0x4000a19du,
+	0xa0f61070u,
+	0x4200a5a8u,
+	0xa402c034u,
+	0xf091a055u,
+	0x10510155u,
+	0x88b0f193u,
+	0xf091a0aau,
+	0x105101aau,
+	0x88b0f193u,
+	0xf091a155u,
+	0x10500155u,
+	0x88b0f193u,
+	0xf091a1aau,
+	0x105001aau,
+	0x88b0f193u,
+	0xf091a15au,
+	0xa0a51070u,
+	0x25a03a5u,
+	0xc931f193u,
+	0xf091a1a5u,
+	0xa05a1070u,
+	0x2a5035au,
+	0xc931f193u,
+	0xf0914200u,
+	0xa5a8a402u,
+	0xe024f091u,
+	0xb06ca255u,
+	0xa455a655u,
+	0xa855aa55u,
+	0xac55ae55u,
+	0xa3aaa5aau,
+	0xa7aaa9aau,
+	0xabaaadaau,
+	0xafaa0155u,
+	0x105388b0u,
+	0xf191f091u,
+	0x105588b0u,
+	0xf191f091u,
+	0x105788b0u,
+	0xf191f091u,
+	0x105988b0u,
+	0xf191f091u,
+	0x105b88b0u,
+	0xf191f091u,
+	0x105d88b0u,
+	0xf191f091u,
+	0x105f88b0u,
+	0xf191f091u,
+	0x1aa1052u,
+	0x88b0f191u,
+	0xf0911054u,
+	0x88b0f191u,
+	0xf0911056u,
+	0x88b0f191u,
+	0xf0911058u,
+	0x88b0f191u,
+	0xf091105au,
+	0x88b0f191u,
+	0xf091105cu,
+	0x88b0f191u,
+	0xf091105eu,
+	0x88b0f191u,
+	0xf091a2aau,
+	0xa4aaa6aau,
+	0xa8aaaaaau,
+	0xacaaaeaau,
+	0xa355a555u,
+	0xa755a955u,
+	0xab55ad55u,
+	0xaf5501aau,
+	0x105388b0u,
+	0xf191f091u,
+	0x105588b0u,
+	0xf191f091u,
+	0x105788b0u,
+	0xf191f091u,
+	0x105988b0u,
+	0xf191f091u,
+	0x105b88b0u,
+	0xf191f091u,
+	0x105d88b0u,
+	0xf191f091u,
+	0x105f88b0u,
+	0xf191f091u,
+	0x1551052u,
+	0x88b0f191u,
+	0xf0911054u,
+	0x88b0f191u,
+	0xf0911056u,
+	0x88b0f191u,
+	0xf0911058u,
+	0x88b0f191u,
+	0xf091105au,
+	0x88b0f191u,
+	0xf091105cu,
+	0x88b0f191u,
+	0xf091105eu,
+	0x88b0a35au,
+	0xa2a5a55au,
+	0xa4a5a75au,
+	0xa6a5a95au,
+	0xa8a5ab5au,
+	0xaaa5ad5au,
+	0xaca5af5au,
+	0xaea5025au,
+	0x3a51072u,
+	0xc931f191u,
+	0xf0911074u,
+	0xc931f191u,
+	0xf0911076u,
+	0xc931f191u,
+	0xf0911078u,
+	0xc931f191u,
+	0xf091107au,
+	0xc931f191u,
+	0xf091107eu,
+	0xc931f191u,
+	0xf091a3a5u,
+	0xa25aa5a5u,
+	0xa45aa7a5u,
+	0xa65aa9a5u,
+	0xa85aaba5u,
+	0xaa5aada5u,
+	0xac5aafa5u,
+	0xae5a02a5u,
+	0x35a1072u,
+	0xc931f191u,
+	0xf0911074u,
+	0xc931f191u,
+	0xf0911076u,
+	0xc931f191u,
+	0xf0911078u,
+	0xc931f191u,
+	0xf091107au,
+	0xc931f191u,
+	0xf091107eu,
+	0xc931f191u,
+	0xf0910055u,
+	0x11481249u,
+	0x134a144bu,
+	0x154c164du,
+	0x174e80b0u,
+	0xf191f091u,
+	0x8531f191u,
+	0xf09189b2u,
+	0xf191f091u,
+	0x8e33f191u,
+	0xf09192b4u,
+	0xf191f091u,
+	0x9735f191u,
+	0xf0919bb6u,
+	0xf191f091u,
+	0xaa1148u,
+	0x1249134au,
+	0x144b154cu,
+	0x164d174eu,
+	0x80b0f191u,
+	0xf0918531u,
+	0xf191f091u,
+	0x89b2f191u,
+	0xf0918e33u,
+	0xf191f091u,
+	0x92b4f191u,
+	0xf0919735u,
+	0xf191f091u,
+	0x9bb6f191u,
+	0xf091005au,
+	0x1a51268u,
+	0x146a166cu,
+	0xc131f191u,
+	0xf091c633u,
+	0xf191f091u,
+	0xcb35f191u,
+	0xf09100a5u,
+	0x15a1268u,
+	0x146a166cu,
+	0xc131f191u,
+	0xf091c633u,
+	0xf191f091u,
+	0xcb35f191u,
+	0xf09109aau,
+	0x1aa080bu,
+	0x101c88b0u,
+	0xf191f091u,
+	0x9550155u,
+	0x80b101cu,
+	0x88b0f191u,
+	0xf0910808u,
+	0x101c4200u,
+	0xa5a8a402u,
+	0xc014f091u,
+	0xa0a010au,
+	0x808101cu,
+	0x88b0f191u,
+	0xf0910a05u,
+	0x1050808u,
+	0x101c88b0u,
+	0xf191f091u,
+	0x4200a5a8u,
+	0xa402c024u,
+	0xf0911a48u,
+	0x80304000u,
+	0xa1a8a000u,
+	0xd020f091u,
+	0xbe6af0d1u,
+	0x80204000u,
+	0xa19fa056u,
+	0xc020f091u,
+	0x2080300u,
+	0xc121c030u,
+	0xf091e05bu,
+	0x10000u,
+	0x9e20u,
+	0x9e600000u,
+	0x9ea0u,
+	0x9ee00000u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x20002u,
+	0x20002u,
+	0x20002u,
+	0x20002u,
+	0x202fau,
+	0x201fec1u,
+	0x3f40000u,
+	0x0u,
+	0xffff0000u,
+	0xffff0000u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x9f70ffffu,
+	0x0u,
+	0x9f56u,
+	0xf00000u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x4000102u,
+	0x506u,
+	0x8000000u,
+	0x2000000u,
+	0xbbccddeeu,
+	0x0u,
+	0x0u,
+	0x0u,
+	0xa8200080u,
+	0xa8200080u,
+	0xa8200080u,
+	0xa8200080u,
+	0xa8200080u,
+	0xa8200080u,
+	0xa8200080u,
+	0xa8200080u,
+	0xa8200080u,
+	0xffffa820u,
+	0x80a820u,
+	0x80a820u,
+	0x80a820u,
+	0x80a820u,
+	0x80a820u,
+	0x80a820u,
+	0x80a820u,
+	0x80a820u,
+	0x80a820u,
+	0x80a820u,
+	0x80a820u,
+	0x800000u,
+	0x7e7e1e1eu,
+	0xaa5500ffu,
+	0x3e3e9e9eu,
+	0x7e7effffu,
+	0x0u,
+	0x0u,
+	0x9009f5cu,
+	0x0u,
+	0xa009f60u,
+	0x0u,
+	0x9f64u,
+	0x0u,
+	0x8009f68u,
+	0x0u,
+	0x8009f6cu,
+	0x0u,
+	0x1u,
+	0x204080fu,
+	0x1017181bu,
+	0x1d1e1f23u,
+	0x25262729u,
+	0x2a2b2c2du,
+	0x2e313233u,
+	0x34353639u,
+	0x3a3c4345u,
+	0x4647494au,
+	0x4b4c4d4eu,
+	0x51525354u,
+	0x5556595au,
+	0x5c636566u,
+	0x67696a6bu,
+	0x6c6d6e71u,
+	0x72737475u,
+	0x76797a7cu,
+	0x80818284u,
+	0x888f9097u,
+	0x989b9d9eu,
+	0x9fa3a5a6u,
+	0xa7a9aaabu,
+	0xacadaeb1u,
+	0xb2b3b4b5u,
+	0xb6b9babcu,
+	0xc3c5c6c7u,
+	0xc9cacbccu,
+	0xcdced1d2u,
+	0xd3d4d5d6u,
+	0xd9dadce0u,
+	0xe1e2e4e8u,
+	0xefff8000u,
+	0x0u,
+	0x139u,
+	0x0u,
+	0xffffu,
+	0xffff0000u,
+	0x1u,
+	0x2030405u,
+	0x6070809u,
+	0xa0b0c0du,
+	0xe0f0000u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0xa1d0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0xa1e0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u,
+	0x0u
+};
+
+size_t	socal_ucode_size = sizeof (socal_ucode);
--- a/usr/src/uts/sun/sys/Makefile	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/uts/sun/sys/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -56,13 +56,11 @@
 promif.h		promimpl.h \
 ramdac.h 		ser_async.h		ser_zscc.h \
 socalio.h		socalreg.h \
+socal_cq_defs.h		socalmap.h		socalvar.h \
 stp4020_reg.h		stp4020_var.h \
 ttymux.h		ttymuxuser.h \
 zsdev.h
 
-CLOSED_HDRS= \
-socal_cq_defs.h		socalmap.h		socalvar.h
-
 AUDIOHDRS= \
 audio_4231.h \
 audio1575.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun/sys/socal_cq_defs.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,273 @@
+/*
+ * 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 1998 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_SOCAL_CQ_DEFS_H
+#define	_SYS_SOCAL_CQ_DEFS_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define	SOC_CQE_PAYLOAD 60
+
+/*
+ * define the CQ_HEADER for the soc command queue.
+ */
+
+typedef struct	cq_hdr {
+	uchar_t	cq_hdr_count;
+	uchar_t	cq_hdr_type;
+	uchar_t	cq_hdr_flags;
+	uchar_t	cq_hdr_seqno;
+} cq_hdr_t;
+
+/*
+ * Command Queue entry description.
+ */
+
+typedef struct cqe {
+	uchar_t		cqe_payload[SOC_CQE_PAYLOAD];
+	cq_hdr_t	cqe_hdr;
+} cqe_t;
+
+/*
+ * CQ Entry types.
+ */
+
+#define	CQ_TYPE_NOP		0x00
+#define	CQ_TYPE_OUTBOUND	0x01
+#define	CQ_TYPE_INBOUND		0x02
+#define	CQ_TYPE_SIMPLE		0x03
+#define	CQ_TYPE_IO_WRITE	0x04
+#define	CQ_TYPE_IO_READ		0x05
+#define	CQ_TYPE_UNSOLICITED	0x06
+#define	CQ_TYPE_BYPASS_DEV	0x06	/* supercedes unsolicited in SOC+ */
+#define	CQ_TYPE_DIAGNOSTIC	0x07
+#define	CQ_TYPE_OFFLINE		0x08
+#define	CQ_TYPE_ADD_POOL	0x09	/* SOC+ enhancement */
+#define	CQ_TYPE_DELETE_POOL	0x0a	/* SOC+ enhancement */
+#define	CQ_TYPE_ADD_BUFFER	0x0b	/* SOC+ enhancement */
+#define	CQ_TYPE_ADD_POOL_BUFFER	0x0c	/* SOC+ enhancement */
+#define	CQ_TYPE_REQUEST_ABORT	0x0d	/* SOC+ enhnacement */
+#define	CQ_TYPE_REQUEST_LIP	0x0e	/* SOC+ enhancement */
+#define	CQ_TYPE_REPORT_MAP	0x0f	/* SOC+ enhancement */
+#define	CQ_TYPE_RESPONSE	0x10
+#define	CQ_TYPE_INLINE		0x20
+
+/*
+ * CQ Entry Flags
+ */
+
+#define	CQ_FLAG_CONTINUATION	0x01
+#define	CQ_FLAG_FULL		0x02
+#define	CQ_FLAG_BADHEADER	0x04
+#define	CQ_FLAG_BADPACKET	0x08
+
+/*
+ * CQ Descriptor Definition.
+ */
+
+typedef	struct cq {
+	uint32_t	cq_address;
+	uchar_t		cq_in;
+	uchar_t		cq_out;
+	uchar_t		cq_last_index;
+	uchar_t		cq_seqno;
+} soc_cq_t;
+
+/*
+ * SOC header definition.
+ */
+
+typedef struct soc_hdr {
+	uint_t		sh_request_token;
+	ushort_t	sh_flags;
+	uchar_t		sh_class;
+	uchar_t		sh_seg_cnt;
+	uint_t		sh_byte_cnt;
+} soc_header_t;
+
+/*
+ * SOC header request packet definition.
+ */
+
+typedef struct soc_request {
+	soc_header_t		sr_soc_hdr;
+	fc_dataseg_t		sr_dataseg[3];
+	fc_frame_header_t	sr_fc_frame_hdr;
+	cq_hdr_t		sr_cqhdr;
+} soc_request_t;
+
+typedef	soc_request_t soc_header_request_t;
+
+/*
+ * SOC header response packet definition.
+ */
+
+typedef struct soc_response {
+	soc_header_t		sr_soc_hdr;
+	uint_t			sr_soc_status;
+	fc_dataseg_t		sr_dataseg;
+	uchar_t			sr_reserved[10];
+	ushort_t 		sr_ncmds;
+	fc_frame_header_t	sr_fc_frame_hdr;
+	cq_hdr_t		sr_cqhdr;
+} soc_response_t;
+
+/*
+ * SOC data request packet definition.
+ */
+
+typedef struct soc_data_request {
+	soc_header_t		sdr_soc_hdr;
+	fc_dataseg_t		sdr_dataseg[6];
+	cq_hdr_t		sdr_cqhdr;
+} soc_data_request_t;
+
+/*
+ * SOC+ (only) command-only packet definitiion
+ */
+
+typedef	struct soc_cmdonly_request {
+	soc_header_t	scr_soc_hdr;
+	uchar_t		reserved[48];
+	cq_hdr_t	scr_cqhdr;
+} soc_cmdonly_request_t;
+
+/*
+ * SOC+ (only) diagnostic request packet definition
+ */
+
+typedef	struct soc_diag_request {
+	soc_header_t	sdr_soc_hdr;
+	uint_t		sdr_diag_cmd;
+	uchar_t		reserved[44];
+	cq_hdr_t	sdr_cqhdr;
+} soc_diag_request_t;
+
+#define	SOC_DIAG_NOP		0x00
+#define	SOC_DIAG_INT_LOOP	0x01
+#define	SOC_DIAG_EXT_LOOP	0x02
+#define	SOC_DIAG_REM_LOOP	0x03
+#define	SOC_DIAG_XRAM_TEST	0x04
+#define	SOC_DIAG_SOC_TEST	0x05
+#define	SOC_DIAG_HCB_TEST	0x06
+#define	SOC_DIAG_SOCLB_TEST	0x07
+#define	SOC_DIAG_SRDSLB_TEST	0x08
+#define	SOC_DIAG_EXTOE_TEST	0x09
+
+/*
+ * SOC+ (only) pool request packet definition
+ */
+
+typedef	struct soc_pool_request {
+	soc_header_t		spr_soc_hdr;
+	uint_t		spr_pool_id;
+	uint_t		spr_header_mask;
+	uint_t		spr_buf_size;
+	uint_t		spr_n_entries;
+	uchar_t			reserved[8];
+	fc_frame_header_t	spr_fc_frame_hdr;
+	cq_hdr_t		spr_cqhdr;
+} soc_pool_request_t;
+
+#define	SOCPR_MASK_RCTL		0x800000
+#define	SOCPR_MASK_DID		0x700000
+#define	SOCPR_MASK_SID		0x070000
+#define	SOCPR_MASK_TYPE		0x008000
+#define	SOCPR_MASK_F_CTL	0x007000
+#define	SOCPR_MASK_SEQ_ID	0x000800
+#define	SOCPR_MASK_D_CTL	0x000400
+#define	SOCPR_MASK_SEQ_CNT	0x000300
+#define	SOCPR_MASK_OX_ID	0x0000f0
+#define	SOCPR_MASK_PARAMETER	0x0000f0
+
+
+/*
+ * Macros for flags field
+ *
+ * values used in both RSP's and REQ's
+ */
+#define	SOC_PORT_B	0x0001	/* entry to/from SOC Port B */
+#define	SOC_FC_HEADER	0x0002	/* this entry contains an FC_HEADER */
+/*
+ *	REQ: this request is supplying buffers
+ *	RSP: this pkt is unsolicited
+ */
+#define	SOC_UNSOLICITED	0x0080
+
+/*
+ * values used only for REQ's
+ */
+#define	SOC_NO_RESPONSE	0x0004 /* generate niether RSP nor INT */
+#define	SOC_NO_INTR	0x0008 /* generate RSP only */
+#define	SOC_XFER_RDY	0x0010 /* issue a XFRRDY packet for this cmd */
+#define	SOC_IGNORE_RO	0x0020 /* ignore FC_HEADER relative offset */
+#define	SOC_RESP_HEADER	0x0200	/* return frame header regardless of status */
+
+/*
+ * values used only for RSP's
+ */
+#define	SOC_COMPLETE	0x0040 /* previous CMD completed. */
+#define	SOC_STATUS	0x0100 /* a SOC status change has occurred */
+
+#define	CQ_SUCCESS	0x0
+#define	CQ_FAILURE	0x1
+#define	CQ_FULL		0x2
+
+#define	CQ_REQUEST_0	0
+#define	CQ_REQUEST_1	1
+#define	CQ_REQUEST_2	2
+#define	CQ_REQUEST_3	3
+
+#define	CQ_RESPONSE_0	0
+#define	CQ_RESPONSE_1	1
+#define	CQ_RESPONSE_2	2
+#define	CQ_RESPONSE_3	3
+
+#define	CQ_SOLICITED_OK		CQ_RESPONSE_0
+#define	CQ_SOLICITED_BAD	CQ_RESPONSE_1
+#define	CQ_UNSOLICITED		CQ_RESPONSE_2
+
+
+typedef struct soc_request_descriptor {
+	soc_request_t	*srd_sp;
+	uint_t		srd_sp_count;
+
+	caddr_t		srd_cmd;
+	uint_t		srd_cmd_count;
+
+	caddr_t		srd_data;
+	uint_t		srd_data_count;
+} soc_request_desc_t;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_SYS_SOCAL_CQ_DEFS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun/sys/socalmap.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,71 @@
+/*
+ * 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 1995 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_SOCALMAP_H
+#define	_SYS_SOCALMAP_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ *	SOC EEPROM Map
+ */
+#define	SOCAL_PROM_4TH_SELF_TST	0x00000 /* 0x05000 thru 0x05fff forth code */
+#define	SOCAL_PROM_4TH_OBP_DRV	0x01000	/* thru 0x09fff forth OBP driver */
+#define	SOCAL_PROM_OBP_HDR	0x05000	/* thru 0x002ff */
+#define	SOCAL_PROM_FW_DATE_CODE	0x05300	/* thru 0x00303 FW date code */
+#define	SOCAL_PROM_SRVC_PARM	0x05304	/* thru 0x00343 SOC+ Service params */
+#define	SOCAL_PROM_LA_BIT_MASK	0x05344	/* thru 0x0034b link app bit mask */
+#define	SOCAL_PROM_RSRV1	0x0534c	/* thru 0x00fff */
+#define	SOCAL_PROM_SOCAL_CODE	0x06000	/* thru 0x04fff SOC+ code */
+#define	SOCAL_PROM_RSRV2	0x0f000	/* thru 0x0ffff */
+
+/*
+ *	SOC XRam Map
+ */
+#define	SOCAL_XRAM_REQ_DESC	0x00200	/* req circular que descriptors */
+#define	SOCAL_XRAM_RSP_DESC	0x00220	/* req circular que descriptors */
+#define	SOCAL_XRAM_LESB_P0	0x00240
+#define	SOCAL_XRAM_LESB_P1	0x00258 /* thru 0x1026f */
+#define	SOCAL_XRAM_SERV_PARAMS	0x00280
+#define	SOCAL_XRAM_FW_DATE_STR	0x002dc	/* ctime() format date code */
+#define	SOCAL_XRAM_FW_DATE_CODE	0x002f8	/* thru 0x002fb FW date code */
+#define	SOCAL_XRAM_HW_REV	0x002fc	/* thru 0x002ff HW revision */
+#define	SOCAL_XRAM_UCODE	0x00300	/* thru 0x03fff SOC+ microcode */
+#define	SOCAL_XRAM_PORTA_WWN	0x00300	/* thru 0x00307, port A wwn */
+#define	SOCAL_XRAM_PORTB_WWN	0x00308	/* thru 0x0030f, port B wwn */
+#define	SOCAL_XRAM_NODE_WWN	0x00310	/* thru 0x00317, Node worldwide name */
+#define	SOCAL_XRAM_PORTA_HRDA	0x00318 /* store port's hard address */
+#define	SOCAL_XRAM_BUF_POOL	0x04000	/* thru 0x0bfff	soc+ buffer pool */
+#define	SOCAL_XRAM_EXCH_POOL	0x0c000	/* thru 0x0ffff soc+ exchange pool */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_SYS_SOCALMAP_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun/sys/socalvar.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,277 @@
+/*
+ * 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 2001 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_SOCALVAR_H
+#define	_SYS_SOCALVAR_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/id32.h>
+
+/*
+ * socalvar.h - SOC+ Driver data struct definitions
+ */
+
+/*
+ * Define default name and # of SOC+s to allocate to the system
+ */
+
+#define	SOCAL_PORTA_NAME	"0"	/* node for port a */
+#define	SOCAL_PORTB_NAME	"1"	/* node for port b */
+#define	SOCAL_NT_PORT		NULL
+#define	SOCAL_INIT_ITEMS	5
+
+/*
+ * Defines for the Circular Queues
+ */
+#define	SOCAL_MAX_CQ_ENTRIES	256	/* Maximum number of CQ entries. */
+#define	SOCAL_CQ_SIZE (sizeof (cqe_t) * SOC_MAX_CQ_ENTRIES)
+
+#define	SOCAL_SMALL_CQ_ENTRIES	8	/* Number of CQ entries for a small Q */
+
+#define	SOCAL_N_CQS		4	/* Number of queues we use */
+#define	SOCAL_HW_N_CQS		4	/* Number of queues the hardware has */
+#define	SOCAL_CQ_ALIGN		64	/* alignment boundary */
+
+#define	SOCAL_TAKE_CORE		0x1
+#define	SOCAL_FAILED_LIP	0x2
+
+/*
+ * Misc. Macros
+ */
+#define	SOCAL_POOL_SIZE		2112
+#define	SOCAL_SVC_LENGTH	80
+
+#define	FABRIC_FLAG	1
+#define	NPORT_FLAG	2
+
+#define	FCIO_DIAG_LBTFQ		(FIOC|203)
+#define	SOC_DIAG_LBTFQ		0x0a
+#define	PORT_LBF_PENDING	0x00100000
+#define	SOCAL_LBF_TIMEOUT	15000000 /* usec */
+
+/* Macros to speed handling of 32-bit IDs */
+#define	SOCAL_ID_GET(x, w)	id32_alloc((x), (w))
+#define	SOCAL_ID_LOOKUP(x)	id32_lookup((x))
+#define	SOCAL_ID_FREE(x)	id32_free((x))
+
+typedef	struct flb_hdr {
+	uint_t max_length;
+	uint_t length;
+} flb_hdr_t;
+
+struct socal_state;
+
+/*
+ * SOC UNIX circular queue descriptor.
+ */
+
+typedef struct socal_kernel_cq {
+	kmutex_t	skc_mtx;	/* MT lock for CQ manipulation  */
+	kcondvar_t	skc_cv;		/* cond var for CQ manipulation. */
+	ddi_dma_handle_t skc_dhandle;	/* DDI DMA handle to CQ. */
+	ddi_dma_cookie_t skc_dcookie;	/* DDI DMA Cookie. */
+	ddi_acc_handle_t skc_acchandle;	/* DDI DMA access handle */
+	soc_cq_t	*skc_xram_cqdesc; /* Pointer to XRAM CQ desc */
+	caddr_t		skc_cq_raw;	/* Pointer to unaligned CQ mem pool */
+	cqe_t		*skc_cq;	/* Pointer to CQ memory pool. */
+	uchar_t		skc_in;		/* Current Input pointer. */
+	uchar_t		skc_out;	/* Current Input pointer. */
+	uchar_t		skc_last_index;	/* Last cq index. */
+	uchar_t		skc_seqno;	/* Current Go Around in CQ. */
+	uchar_t		skc_full;	/* Indication of full. */
+	uchar_t		skc_saved_out;	/* Current Input pointer. */
+	uchar_t		skc_saved_seqno;	/* Current Go Around in CQ. */
+	timeout_id_t	deferred_intr_timeoutid;
+	struct fcal_packet	*skc_overflowh; /* cq overflow list */
+	struct fcal_packet	*skc_overflowt;
+	struct socal_state	*skc_socalp;
+} socal_kcq_t;
+
+/*
+ * Values for skc_full
+ */
+#define	SOCAL_SKC_FULL	1
+#define	SOCAL_SKC_SLEEP	2
+
+/*
+ * State change callback routine descriptor
+ *
+ * There is one entry in this list for each hba that is attached
+ * to this port.
+ * This structure will need to be mutex protected when parallel
+ * attaches are supported.
+ */
+typedef struct socal_unsol_cb {
+	struct socal_unsol_cb	*next;
+	uchar_t			type;
+	void			(*statec_cb)(void *, uint32_t);
+	void			(*els_cb)(void *, cqe_t *, caddr_t);
+	void			(*data_cb)(void *, cqe_t *, caddr_t);
+	void			*arg;
+} socal_unsol_cb_t;
+
+/*
+ * SOC+ port status decriptor.
+ */
+typedef struct socal_port {
+	uint32_t		sp_status;	/* port status */
+	struct socal_state	*sp_board;	/* hardware for instance */
+
+	uint32_t		sp_src_id;	/* Our nport id */
+	uint32_t		sp_port;	/* Our physical port (0, 1) */
+	la_wwn_t		sp_p_wwn;	/* Our Port WorldWide Name */
+
+	socal_unsol_cb_t	*sp_unsol_cb;	/* Callback for state change */
+
+	uint32_t		sp_open;	/* open count */
+
+	kmutex_t		sp_mtx;		/* Per port mutex */
+	kcondvar_t		sp_cv;		/* Per port condvariable */
+	fcal_transport_t	*sp_transport;	/* transport structure */
+
+	uint32_t		sp_hard_alpa;	/* Our optional Hard AL_PA */
+
+	uint32_t		sp_lilpmap_valid;  /* lilp map cache valid  */
+	fcal_lilp_map_t		sp_lilpmap;  /* lilp map cache */
+} socal_port_t;
+
+#define	PORT_FABRIC_PRESENT	0x00000001
+#define	PORT_OFFLINE		0x00000002
+#define	NPORT_LOGIN_SUCCESS	0x00000004
+#define	PORT_LOGIN_ACTIVE	0x00000008
+#define	PORT_LOGIN_RECOVERY	0x00000010
+#define	PORT_ONLINE_LOOP	0x00000020
+#define	PORT_ONLINE		0x00000040
+#define	PORT_STATUS_FLAG	0x00000080
+#define	PORT_STATUS_MASK	0x000000ff
+#define	PORT_OPEN		0x00000100
+#define	PORT_CHILD_INIT		0x00000200
+#define	PORT_TARGET_MODE	0x00000400
+#define	PORT_LILP_PENDING	0x00001000
+#define	PORT_LIP_PENDING	0x00002000
+#define	PORT_ABORT_PENDING	0x00004000
+#define	PORT_ELS_PENDING	0x00008000
+#define	PORT_BYPASS_PENDING	0x00010000
+#define	PORT_OFFLINE_PENDING	0x00020000
+#define	PORT_ADISC_PENDING	0x00040000
+#define	PORT_RLS_PENDING	0x00080000
+#define	PORT_DISABLED		0x00100000
+
+
+#define	SOC_TIMEOUT_DELAY(secs, delay)  (secs * (1000000 / delay))
+#define	SOCAL_NOINTR_POLL_DELAY_TIME	1000    /* usec */
+
+#define	SOCAL_LILP_TIMEOUT		10000000 /* usec */
+#define	SOCAL_LIP_TIMEOUT		30000000 /* usec */
+#define	SOCAL_ABORT_TIMEOUT		10000000 /* usec */
+#define	SOCAL_BYPASS_TIMEOUT		5000000	/* usec */
+#define	SOCAL_OFFLINE_TIMEOUT		5000000	/* usec */
+#define	SOCAL_ADISC_TIMEOUT		15000000 /* usec */
+#define	SOCAL_RLS_TIMEOUT		15000000 /* usec */
+#define	SOCAL_DIAG_TIMEOUT		15000000 /* usec */
+
+/*
+ * We wait for up to SOC_INITIAL_ONLINE seconds for the first
+ * soc to come on line. The timeout in the soc firmware is 10 seconds.
+ * The timeout is to let any outstanding commands drain before
+ * coming back on line, after going off-line.
+ */
+#define	SOC_INITIAL_ONLINE	30	/* secs for first online from soc */
+
+/*
+ * SOC state structure
+ */
+
+typedef struct socal_state {
+	dev_info_t	*dip;
+	caddr_t 	socal_eeprom;		/* pointer to soc+ eeprom */
+	caddr_t 	socal_xrp;		/* pointer to soc+ xram */
+	socal_reg_t	*socal_rp;		/* pointer to soc+ registers */
+
+	soc_cq_t	*xram_reqp;	/* addr of request descriptors */
+	soc_cq_t	*xram_rspp;	/* addr of response descriptors */
+
+	socal_kcq_t	request[SOCAL_N_CQS];	/* request queues */
+	socal_kcq_t	response[SOCAL_N_CQS];	/* response queues */
+
+	int32_t		socal_busy;		/* busy flag */
+	uint32_t	socal_shutdown;
+	uint32_t	socal_cfg;		/* copy of the config reg */
+
+	kmutex_t	k_imr_mtx;	/* mutex for interrupt masks */
+	uint32_t	socal_k_imr;	/* copy of soc+'s mask register */
+
+	kmutex_t	abort_mtx;	/* Abort mutex. */
+	kmutex_t	board_mtx;	/* Per board mutex */
+	kmutex_t	ioctl_mtx;	/* mutex to serialize ioctls */
+	kcondvar_t	board_cv;	/* Per board condition variable */
+
+	ddi_iblock_cookie_t	iblkc;	/* interrupt cookies */
+	ddi_idevice_cookie_t	idevc;
+
+	uchar_t		*pool;	/* unsolicited buffer pool resources */
+	ddi_dma_handle_t	pool_dhandle;
+	ddi_dma_cookie_t	pool_dcookie;
+	ddi_acc_handle_t	pool_acchandle;
+
+					/* handles to soc+ ports */
+	socal_port_t	port_state[N_SOCAL_NPORTS];
+	la_wwn_t	socal_n_wwn;	/* Our Node WorldWide Name */
+	char		socal_service_params[SOCAL_SVC_LENGTH];	/* for login */
+
+	char			socal_name[MAXPATHLEN];
+	kstat_t			*socal_ksp;
+	struct socal_stats	socal_stats;	/* kstats */
+	int		socal_on_intr;
+} socal_state_t;
+
+/*
+ * Structure used when the soc driver needs to issue commands of its own
+ */
+
+typedef struct socal_priv_cmd {
+	void			*fapktp;
+	uint32_t		flags;
+	caddr_t			cmd;
+	caddr_t			rsp;
+	ddi_dma_handle_t	cmd_handle;
+	ddi_acc_handle_t	cmd_acchandle;
+	ddi_dma_handle_t	rsp_handle;
+	ddi_acc_handle_t	rsp_acchandle;
+	void 			(*callback)();	/* callback to ULP, if any */
+	void			*arg;		/* callback arg */
+	caddr_t			*payload;	/* payload callback or stash */
+} socal_priv_cmd_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_SYS_SOCALVAR_H */
--- a/usr/src/uts/sun4u/Makefile.files	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/uts/sun4u/Makefile.files	Thu Jun 29 14:43:12 2006 -0700
@@ -91,6 +91,8 @@
 			pci_cb.o pci_ib.o pci_ecc.o pci_pbm.o pci_intr.o \
 			pci_space.o pci_counters.o pci_axq.o \
 			pci_fm.o pci_reloc.o pci_tools.o pci_asm.o
+RMCLOMV_OBJS	+= rmclomv.o
+WRSMD_OBJS	+= wrsmd.o
 
 PSYCHO_PCI_OBJS	+= $(PCI_COMMON_OBJS) pcipsy.o
 SCHIZO_PCI_OBJS	+= $(PCI_COMMON_OBJS) pcisch_asm.o pcisch.o pcix.o
--- a/usr/src/uts/sun4u/Makefile.sun4u.shared	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/uts/sun4u/Makefile.sun4u.shared	Thu Jun 29 14:43:12 2006 -0700
@@ -180,10 +180,10 @@
 IMPLEMENTATIONS		+= lw8 .WAIT
 IMPLEMENTATIONS		+= makaha .WAIT
 IMPLEMENTATIONS		+= opl .WAIT
+IMPLEMENTATIONS		+= lw2plus .WAIT
 
 $(CLOSED_BUILD)CLOSED_IMPLEMENTATIONS	= chalupa .WAIT
 $(CLOSED_BUILD)CLOSED_IMPLEMENTATIONS	+= ents .WAIT
-$(CLOSED_BUILD)CLOSED_IMPLEMENTATIONS	+= lw2plus .WAIT
 
 #
 #	machine specific optimization, override default in Makefile.master
@@ -392,17 +392,17 @@
 DRV_KMODS	+= dmfe
 DRV_KMODS	+= rmc_comm
 DRV_KMODS	+= rmcadm
+DRV_KMODS	+= rmclomv
+DRV_KMODS	+= wrsmd
 
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= ctsmc
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= i2bsc 
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= m1535ppm
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= memtest
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= mi2cv
-$(CLOSED_BUILD)CLOSED_DRV_KMODS	+= rmclomv
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= scmi2c
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= sf
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= smbus_ara
-$(CLOSED_BUILD)CLOSED_DRV_KMODS	+= wrsmd
 
 #
 #	Exec Class Modules (/kernel/exec):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/io/rmclomv.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,3507 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/callb.h>
+#include <sys/strlog.h>
+#include <sys/cyclic.h>
+#include <sys/rmc_comm_dp.h>
+#include <sys/rmc_comm_dp_boot.h>
+#include <sys/rmc_comm_drvintf.h>
+#include <sys/rmc_comm.h>
+#include <sys/machsystm.h>
+#include <sys/sysevent.h>
+#include <sys/sysevent/dr.h>
+#include <sys/sysevent/env.h>
+#include <sys/sysevent/eventdefs.h>
+#include <sys/file.h>
+#include <sys/disp.h>
+#include <sys/reboot.h>
+#include <sys/envmon.h>
+#include <sys/rmclomv_impl.h>
+#include <sys/cpu_sgnblk_defs.h>
+#include <sys/utsname.h>
+#include <sys/systeminfo.h>
+#include <sys/ddi.h>
+#include <sys/time.h>
+#include <sys/promif.h>
+
+#define	offsetof(s, m)	(size_t)(&(((s *)0)->m))
+#define	RMCRESBUFLEN	1024
+#define	DATE_TIME_MSG_SIZE	78
+#define	RMCLOMV_WATCHDOG_MODE	"rmclomv-watchdog-mode"
+
+extern void	pmugpio_watchdog_pat();
+static clock_t	timesync_interval;
+
+extern int	watchdog_activated;
+static int	last_watchdog_msg = 1;
+extern int	watchdog_enable;
+extern int	boothowto;
+
+int		rmclomv_watchdog_mode;
+
+/*
+ * functions local to this driver.
+ */
+static int	rmclomv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
+    void **resultp);
+static int	rmclomv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
+static int	rmclomv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
+static uint_t	rmclomv_break_intr(caddr_t arg);
+static int	rmclomv_add_intr_handlers(void);
+static int	rmclomv_remove_intr_handlers(void);
+static uint_t	rmclomv_event_data_handler(char *);
+static void	rmclomv_dr_data_handler(const char *, int);
+static int	rmclomv_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
+static int	rmclomv_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
+static int	rmclomv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
+    cred_t *cred_p, int *rval_p);
+static void	rmclomv_checkrmc_start(void);
+static void	rmclomv_checkrmc_destroy(void);
+static void	rmclomv_checkrmc_wakeup(void *);
+static void	rmclomv_refresh_start(void);
+static void	rmclomv_refresh_destroy(void);
+static void	rmclomv_refresh_wakeup(void);
+static void	rmclomv_reset_cache(rmclomv_cache_section_t *new_chain,
+    rmclomv_cache_section_t *new_subchain, dp_get_sysinfo_r_t *sysinfo);
+static rmclomv_cache_section_t *rmclomv_find_section(
+    rmclomv_cache_section_t *start, uint16_t sensor);
+static rmclomv_cache_section_t *create_cache_section(int sensor_type, int num);
+static int	get_sensor_by_name(const rmclomv_cache_section_t *section,
+    const char *name, int *index);
+static int	validate_section_entry(rmclomv_cache_section_t *section,
+    int index);
+static int	add_names_to_section(rmclomv_cache_section_t *section);
+static void	free_section(rmclomv_cache_section_t *section);
+static void	add_section(rmclomv_cache_section_t **head,
+    rmclomv_cache_section_t *section);
+static int	rmclomv_do_cmd(int req_cmd, int resp_cmd, int resp_len,
+    intptr_t arg_req, intptr_t arg_res);
+static void	refresh_name_cache(int force_fail);
+static void	set_val_unav(envmon_sensor_t *sensor);
+static void	set_fan_unav(envmon_fan_t *fan);
+static int	do_psu_cmd(intptr_t arg, int mode, envmon_indicator_t *env_ind,
+    dp_get_psu_status_t *rmc_psu, dp_get_psu_status_r_t *rmc_psu_r,
+    int detector_type);
+static uint_t rmc_set_watchdog_timer(uint_t timeoutval);
+static uint_t rmc_clear_watchdog_timer(void);
+static void send_watchdog_msg(int msg);
+static void plat_timesync(void *arg);
+
+/*
+ * Driver entry points
+ */
+static struct cb_ops rmclomv_cb_ops = {
+	rmclomv_open,	/* open */
+	rmclomv_close,	/* close */
+	nodev,		/* strategy() */
+	nodev,		/* print() */
+	nodev,		/* dump() */
+	nodev,		/* read() */
+	nodev,		/* write() */
+	rmclomv_ioctl,	/* ioctl() */
+	nodev,		/* devmap() */
+	nodev,		/* mmap() */
+	ddi_segmap,	/* segmap() */
+	nochpoll,	/* poll() */
+	ddi_prop_op,    /* prop_op() */
+	NULL,		/* cb_str */
+	D_NEW | D_MP	/* cb_flag */
+};
+
+
+static struct dev_ops rmclomv_ops = {
+	DEVO_REV,
+	0,			/* ref count */
+	rmclomv_getinfo,	/* getinfo() */
+	nulldev,		/* identify() */
+	nulldev,		/* probe() */
+	rmclomv_attach,		/* attach() */
+	rmclomv_detach,		/* detach */
+	nodev,			/* reset */
+	&rmclomv_cb_ops,		/* pointer to cb_ops structure */
+	(struct bus_ops *)NULL,
+	nulldev			/* power() */
+};
+
+/*
+ * Loadable module support.
+ */
+extern struct mod_ops mod_driverops;
+
+static struct modldrv modldrv = {
+	&mod_driverops,			/* Type of module. This is a driver */
+	"rmclomv control driver v%I%",	/* Name of the module */
+	&rmclomv_ops			/* pointer to the dev_ops structure */
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1,
+	&modldrv,
+	NULL
+};
+
+/*
+ * Device info
+ */
+static dev_info_t		*rmclomv_dip = NULL;
+static int			rmclomv_break_requested = B_FALSE;
+static ddi_softintr_t		rmclomv_softintr_id;
+static ddi_iblock_cookie_t	rmclomv_soft_iblock_cookie;
+
+extern void (*abort_seq_handler)();
+/* key_position is effective key-position. Set to locked if unknown */
+static rsci8 key_position = RMC_KEYSWITCH_POS_LOCKED;
+/* real_key_position starts off as unknown and records value actually seen */
+static rsci8 real_key_position = RMC_KEYSWITCH_POS_UNKNOWN;
+static void rmclomv_abort_seq_handler(char *msg);
+
+/*
+ * mutexes which protect the interrupt handlers.
+ */
+static kmutex_t		rmclomv_event_hdlr_lock;
+static kmutex_t		rmclomv_refresh_lock;
+static kcondvar_t	rmclomv_refresh_sig_cv;
+static kmutex_t		rmclomv_checkrmc_lock;
+static kcondvar_t	rmclomv_checkrmc_sig_cv;
+
+/*
+ * mutex to protect the handle_name cache
+ */
+static kmutex_t		rmclomv_cache_lock;
+
+/*
+ * mutex to protect the RMC state
+ */
+static kmutex_t		rmclomv_state_lock;
+
+/*
+ * Payloads of the event handlers.
+ */
+static dp_event_notification_t	rmclomv_event_payload;
+static rmc_comm_msg_t	rmclomv_event_payload_msg;
+
+/*
+ * Checkrmc commands..
+ */
+#define	RMCLOMV_CHECKRMC_EXITNOW	(-1)
+#define	RMCLOMV_CHECKRMC_WAIT		0
+#define	RMCLOMV_CHECKRMC_PROCESSNOW	1
+
+/*
+ * Checkrmc thread state
+ */
+static int rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT;
+static kt_did_t rmclomv_checkrmc_tid = 0;
+
+/*
+ * RMC state data
+ */
+#define	RMCLOMV_RMCSTATE_UNKNOWN	0
+#define	RMCLOMV_RMCSTATE_OK		1
+#define	RMCLOMV_RMCSTATE_FAILED		2
+#define	RMCLOMV_RMCSTATE_DOWNLOAD	3
+
+/*
+ * RMC error indicator values (status from last RMC command)
+ */
+#define	RMCLOMV_RMCERROR_NONE		0
+
+/* fail RMC after 5 minutes without a good response */
+#define	RMCLOMV_RMCFAILTHRESHOLD	5
+
+/*
+ * rmclomv_rmc_state is the state reported in OperationalStatus.
+ * rmclomv_rmc_error reflects the result of the last RMC interaction.
+ * rmclomv_rmcfailcount is used by the rmclomv_checkrmc thread to count
+ * failures in its regular status polls. Once RMCLOMV_RMCFAILTHRESHOLD
+ * is reached, rmclomv_rmc_state is marked as RMCLOMV_RMCSTATE_FAILED.
+ */
+static int	rmclomv_rmc_state = RMCLOMV_RMCSTATE_UNKNOWN;
+static int	rmclomv_rmc_error = RMCLOMV_RMCERROR_NONE;
+static int	rmclomv_rmcfailcount;
+
+/*
+ * Refresh commands..
+ */
+#define	RMCLOMV_REFRESH_EXITNOW		(-1)
+#define	RMCLOMV_REFRESH_WAIT		0
+#define	RMCLOMV_REFRESH_PROCESSNOW	1
+
+/*
+ * Refresh thread state
+ */
+static int rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT;
+static kt_did_t rmclomv_refresh_tid = 0;
+
+/*
+ * timeout id
+ */
+static timeout_id_t	timer_id;
+
+/*
+ * Handle-name cache
+ */
+#define	LOCK_CACHE		mutex_enter(&rmclomv_cache_lock);
+#define	RELEASE_CACHE		mutex_exit(&rmclomv_cache_lock);
+static rmclomv_cache_section_t	*rmclomv_cache;		/* main handle-names */
+static rmclomv_cache_section_t	*rmclomv_subcache;	/* derived names */
+static dp_get_sysinfo_r_t	rmclomv_sysinfo_data;
+static boolean_t		rmclomv_sysinfo_valid;
+static int			rmclomv_cache_valid;
+
+extern pri_t maxclsyspri;
+
+/*
+ * static strings
+ */
+static const char	str_percent[]		= "%";
+static const char	str_rpm[]		= " rpm";
+static const char	str_ip_volts_ind[]	= "P_PWR";
+static const char	str_ip2_volts_ind[]	= "P_PWR2";
+static const char	str_ff_pok_ind[]	= "FF_POK";
+static const char	str_vlo_volts_ind[]	= "FF_UV";
+static const char	str_vhi_volts_ind[]	= "FF_OV";
+static const char	str_chi_amps_ind[]	= "FF_OC";
+static const char	str_chi_nr_ind[]	= "FF_NR";
+static const char	str_ot_tmpr_ind[]	= "FF_OT";
+static const char	str_fan_ind[]		= "FF_FAN";
+static const char	str_pdct_fan_ind[]	= "FF_PDCT_FAN";
+static const char	str_sc[]		= "SC";
+
+int
+_init(void)
+{
+	int	error = 0;
+
+	mutex_init(&rmclomv_event_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
+	mutex_init(&rmclomv_checkrmc_lock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&rmclomv_refresh_lock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&rmclomv_cache_lock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&rmclomv_state_lock, NULL, MUTEX_DRIVER, NULL);
+	cv_init(&rmclomv_checkrmc_sig_cv, NULL, CV_DRIVER, NULL);
+	cv_init(&rmclomv_refresh_sig_cv, NULL, CV_DRIVER, NULL);
+
+	error = mod_install(&modlinkage);
+	if (error) {
+		cv_destroy(&rmclomv_refresh_sig_cv);
+		cv_destroy(&rmclomv_checkrmc_sig_cv);
+		mutex_destroy(&rmclomv_state_lock);
+		mutex_destroy(&rmclomv_cache_lock);
+		mutex_destroy(&rmclomv_refresh_lock);
+		mutex_destroy(&rmclomv_checkrmc_lock);
+		mutex_destroy(&rmclomv_event_hdlr_lock);
+	}
+	return (error);
+}
+
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+
+int
+_fini(void)
+{
+	int	error = 0;
+
+	error = mod_remove(&modlinkage);
+	if (error)
+		return (error);
+	cv_destroy(&rmclomv_refresh_sig_cv);
+	cv_destroy(&rmclomv_checkrmc_sig_cv);
+	mutex_destroy(&rmclomv_state_lock);
+	mutex_destroy(&rmclomv_cache_lock);
+	mutex_destroy(&rmclomv_refresh_lock);
+	mutex_destroy(&rmclomv_checkrmc_lock);
+	mutex_destroy(&rmclomv_event_hdlr_lock);
+	return (error);
+}
+
+
+/* ARGSUSED */
+static int
+rmclomv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
+{
+	minor_t m = getminor((dev_t)arg);
+
+	switch (cmd) {
+	case DDI_INFO_DEVT2DEVINFO:
+		if ((m != 0) || (rmclomv_dip == NULL)) {
+			*resultp = NULL;
+			return (DDI_FAILURE);
+		}
+		*resultp = rmclomv_dip;
+		return (DDI_SUCCESS);
+	case DDI_INFO_DEVT2INSTANCE:
+		*resultp = (void *)(uintptr_t)m;
+		return (DDI_SUCCESS);
+	default:
+		return (DDI_FAILURE);
+	}
+}
+
+
+static int
+rmclomv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	int			instance;
+	int			err;
+	char			*wdog_state;
+	int			attaching = 1;
+
+	switch (cmd) {
+	case DDI_ATTACH:
+		/*
+		 * only allow one instance
+		 */
+		instance = ddi_get_instance(dip);
+		if (instance != 0)
+			return (DDI_FAILURE);
+
+		err = ddi_create_minor_node(dip, "rmclomv", S_IFCHR,
+			instance, DDI_PSEUDO, NULL);
+		if (err != DDI_SUCCESS)
+			return (DDI_FAILURE);
+
+		/*
+		 * Register with rmc_comm to prevent it being detached
+		 * (in the unlikely event that its attach succeeded on a
+		 * platform whose platmod doesn't lock it down).
+		 */
+		err = rmc_comm_register();
+		if (err != DDI_SUCCESS) {
+			ddi_remove_minor_node(dip, NULL);
+			return (DDI_FAILURE);
+		}
+
+		/* Remember the dev info */
+		rmclomv_dip = dip;
+
+		/*
+		 * Add the handlers which watch for unsolicited messages
+		 * and post event to Sysevent Framework.
+		 */
+		err = rmclomv_add_intr_handlers();
+		if (err != DDI_SUCCESS) {
+			rmc_comm_unregister();
+			ddi_remove_minor_node(dip, NULL);
+			rmclomv_dip = NULL;
+			return (DDI_FAILURE);
+		}
+
+		rmclomv_checkrmc_start();
+		rmclomv_refresh_start();
+
+		abort_seq_handler = rmclomv_abort_seq_handler;
+		ddi_report_dev(dip);
+
+		/*
+		 * Check whether we have an application watchdog
+		 */
+		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
+			DDI_PROP_DONTPASS, RMCLOMV_WATCHDOG_MODE,
+			&wdog_state) == DDI_PROP_SUCCESS) {
+			if (strcmp(wdog_state, "app") == 0) {
+				rmclomv_watchdog_mode = 1;
+				watchdog_enable = 0;
+			}
+			else
+				rmclomv_watchdog_mode = 0;
+			ddi_prop_free(wdog_state);
+		}
+
+		tod_ops.tod_set_watchdog_timer = rmc_set_watchdog_timer;
+		tod_ops.tod_clear_watchdog_timer = rmc_clear_watchdog_timer;
+
+		/*
+		 * Now is a good time to activate hardware watchdog
+		 * (if one exists).
+		 */
+		mutex_enter(&tod_lock);
+		if (watchdog_enable && tod_ops.tod_set_watchdog_timer != NULL)
+			err = tod_ops.tod_set_watchdog_timer(0);
+		mutex_exit(&tod_lock);
+		if (err != 0)
+			printf("Hardware watchdog enabled\n");
+
+		/*
+		 * Set time interval and start timesync routine.
+		 * Also just this once set the Solaris clock
+		 * to the RMC clock.
+		 */
+		timesync_interval = drv_usectohz(5*60 * MICROSEC);
+		plat_timesync((void *) &attaching);
+
+		return (DDI_SUCCESS);
+	case DDI_RESUME:
+		return (DDI_SUCCESS);
+	default:
+		return (DDI_FAILURE);
+	}
+}
+
+
+static int
+rmclomv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+	int	instance;
+	int	err;
+
+	switch (cmd) {
+	case DDI_DETACH:
+		instance = ddi_get_instance(dip);
+		if (instance != 0)
+			return (DDI_FAILURE);
+
+		/*
+		 * Remove the handlers which watch for unsolicited messages
+		 * and post event to Sysevent Framework.
+		 */
+		err = rmclomv_remove_intr_handlers();
+		if (err != DDI_SUCCESS) {
+			cmn_err(CE_WARN, "Failed to remove event handlers");
+			return (DDI_FAILURE);
+		}
+		rmclomv_checkrmc_destroy();
+		rmclomv_refresh_destroy();
+		rmclomv_reset_cache(NULL, NULL, NULL);
+		ddi_remove_minor_node(dip, NULL);
+
+		/* Forget the dev info */
+		rmclomv_dip = NULL;
+		rmc_comm_unregister();
+		return (DDI_SUCCESS);
+	case DDI_SUSPEND:
+		return (DDI_SUCCESS);
+	default:
+		return (DDI_FAILURE);
+	}
+}
+
+static int
+rmclomv_add_intr_handlers()
+{
+	int	err;
+
+	if (ddi_get_soft_iblock_cookie(rmclomv_dip, DDI_SOFTINT_HIGH,
+	    &rmclomv_soft_iblock_cookie) != DDI_SUCCESS) {
+		return (DDI_FAILURE);
+	}
+	err = ddi_add_softintr(rmclomv_dip, DDI_SOFTINT_HIGH,
+	    &rmclomv_softintr_id, &rmclomv_soft_iblock_cookie, NULL,
+	    rmclomv_break_intr, NULL);
+	if (err != DDI_SUCCESS)
+		return (DDI_FAILURE);
+	rmclomv_event_payload_msg.msg_buf = (caddr_t)&rmclomv_event_payload;
+	rmclomv_event_payload_msg.msg_len = sizeof (rmclomv_event_payload);
+	err = rmc_comm_reg_intr(DP_RMC_EVENTS, rmclomv_event_data_handler,
+	    &rmclomv_event_payload_msg, NULL, &rmclomv_event_hdlr_lock);
+	if (err != 0) {
+		ddi_remove_softintr(rmclomv_softintr_id);
+		return (DDI_FAILURE);
+	}
+	return (DDI_SUCCESS);
+}
+
+static int
+rmclomv_remove_intr_handlers(void)
+{
+	int err = rmc_comm_unreg_intr(DP_RMC_EVENTS,
+	    rmclomv_event_data_handler);
+	if (err != 0) {
+		cmn_err(CE_WARN, "Failed to unregister DP_RMC_EVENTS "
+			"handler. Err=%d", err);
+		return (DDI_FAILURE);
+	}
+	ddi_remove_softintr(rmclomv_softintr_id);
+	return (DDI_SUCCESS);
+}
+
+static void
+rmclomv_abort_seq_handler(char *msg)
+{
+	if (key_position == RMC_KEYSWITCH_POS_LOCKED)
+		cmn_err(CE_CONT, "KEY in LOCKED position, "
+			"ignoring debug enter sequence");
+	else  {
+		rmclomv_break_requested = B_TRUE;
+		if (msg != NULL)
+			prom_printf("%s\n", msg);
+
+		ddi_trigger_softintr(rmclomv_softintr_id);
+	}
+}
+
+/* ARGSUSED */
+static uint_t
+rmclomv_break_intr(caddr_t arg)
+{
+	if (rmclomv_break_requested) {
+		rmclomv_break_requested = B_FALSE;
+		debug_enter(NULL);
+		return (DDI_INTR_CLAIMED);
+	}
+
+	return (DDI_INTR_UNCLAIMED);
+}
+
+/*
+ * Create a cache section structure
+ */
+static rmclomv_cache_section_t *
+create_cache_section(int sensor_type, int num)
+{
+	size_t len = offsetof(rmclomv_cache_section_t, entry[0]) +
+	    num * sizeof (rmclomv_cache_entry_t);
+	rmclomv_cache_section_t *ptr = kmem_zalloc(len, KM_SLEEP);
+	ptr->next_section = NULL;
+	ptr->sensor_type = sensor_type;
+	ptr->num_entries = num;
+	ptr->section_len = len;
+	return (ptr);
+}
+
+/*
+ * Free a cache_section.
+ */
+static void
+free_section(rmclomv_cache_section_t *section)
+{
+	size_t len = section->section_len;
+	kmem_free(section, len);
+}
+
+/*
+ * adds supplied section to end of cache chain
+ * must be called with cache locked
+ */
+static void
+add_section(rmclomv_cache_section_t **head, rmclomv_cache_section_t *section)
+{
+	section->next_section = *head;
+	*head = section;
+}
+
+/*
+ * This function releases all cache sections and exchanges the two
+ * chain heads for new values.
+ */
+static void
+rmclomv_reset_cache(rmclomv_cache_section_t *new_chain,
+    rmclomv_cache_section_t *new_subchain, dp_get_sysinfo_r_t *sysinfo)
+{
+	rmclomv_cache_section_t	*first;
+	rmclomv_cache_section_t	*sub_first;
+	rmclomv_cache_section_t	*next;
+
+	LOCK_CACHE
+
+	rmclomv_cache_valid = (new_chain != NULL);
+	first = rmclomv_cache;
+	rmclomv_cache = new_chain;
+	sub_first = rmclomv_subcache;
+	rmclomv_subcache = new_subchain;
+
+	if (sysinfo == NULL)
+		bzero(&rmclomv_sysinfo_data, sizeof (rmclomv_sysinfo_data));
+	else
+		bcopy(sysinfo, &rmclomv_sysinfo_data,
+		    sizeof (rmclomv_sysinfo_data));
+
+	rmclomv_sysinfo_valid = (sysinfo != NULL);
+
+	RELEASE_CACHE
+
+	while (first != NULL) {
+		next = first->next_section;
+		free_section(first);
+		first = next;
+	}
+
+	while (sub_first != NULL) {
+		next = sub_first->next_section;
+		free_section(sub_first);
+		sub_first = next;
+	}
+}
+
+/*
+ * cache must be locked before calling rmclomv_find_section
+ */
+static rmclomv_cache_section_t *
+rmclomv_find_section(rmclomv_cache_section_t *start, uint16_t sensor)
+{
+	rmclomv_cache_section_t	*next = start;
+
+	while ((next != NULL) && (next->sensor_type != sensor))
+		next = next->next_section;
+
+	return (next);
+}
+
+/*
+ * Return a string presenting the keyswitch position
+ * For unknown values returns "Unknown"
+ */
+static char *
+rmclomv_key_position(enum rmc_keyswitch_pos pos)
+{
+	switch (pos) {
+
+	case RMC_KEYSWITCH_POS_NORMAL:
+		return ("NORMAL");
+	case RMC_KEYSWITCH_POS_DIAG:
+		return ("DIAG");
+	case RMC_KEYSWITCH_POS_LOCKED:
+		return ("LOCKED");
+	case RMC_KEYSWITCH_POS_OFF:
+		return ("STBY");
+	default:
+		return ("UNKNOWN");
+	}
+}
+
+/*
+ * The sensor id name is sought in the supplied section and if found
+ * its index within the section is written to *index.
+ * Return value is zero for success, otherwise -1.
+ * The cache must be locked before calling get_sensor_by_name
+ */
+static int
+get_sensor_by_name(const rmclomv_cache_section_t *section,
+    const char *name, int *index)
+{
+	int i;
+
+	for (i = 0; i < section->num_entries; i++) {
+		if (strcmp(name, section->entry[i].handle_name.name) == 0) {
+			*index = i;
+			return (0);
+		}
+	}
+
+	*index = 0;
+	return (-1);
+}
+
+/*
+ * fills in the envmon_handle name
+ * if it is unknown (not cached), the dp_handle_t is returned as a hex-digit
+ * string
+ */
+static void
+rmclomv_hdl_to_envhdl(dp_handle_t hdl, envmon_handle_t *envhdl)
+{
+	rmclomv_cache_section_t *next;
+	int			i;
+
+	LOCK_CACHE
+
+	for (next = rmclomv_cache; next != NULL; next = next->next_section) {
+		for (i = 0; i < next->num_entries; i++) {
+			if (next->entry[i].handle == hdl) {
+				    *envhdl = next->entry[i].handle_name;
+				    RELEASE_CACHE
+				    return;
+			}
+		}
+	}
+
+	/*
+	 * Sought handle not currently cached.
+	 */
+	RELEASE_CACHE
+
+	(void) snprintf(envhdl->name, sizeof (envhdl->name),
+	    "Unknown SC node 0x%x", hdl);
+}
+
+static void
+rmclomv_dr_data_handler(const char *fru_name, int hint)
+{
+	int				err = 0;
+	nvlist_t			*attr_list;
+	char				attach_pnt[MAXPATHLEN];
+
+	(void) snprintf(attach_pnt, sizeof (attach_pnt), "%s", fru_name);
+
+	err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
+	if (err != 0) {
+		cmn_err(CE_WARN,
+		    "Failed to allocate name-value list for %s event", EC_DR);
+		return;
+	}
+
+	err = nvlist_add_string(attr_list, DR_AP_ID, attach_pnt);
+	if (err != 0) {
+		cmn_err(CE_WARN, "Failed to add attr [%s] for %s event",
+		    DR_AP_ID, EC_DR);
+		nvlist_free(attr_list);
+		return;
+	}
+
+	/*
+	 * Add the hint
+	 */
+	err = nvlist_add_string(attr_list, DR_HINT, SE_HINT2STR(hint));
+	if (err != 0) {
+		cmn_err(CE_WARN, "Failed to add attr [%s] for %s event",
+		    DR_HINT, EC_DR);
+		nvlist_free(attr_list);
+		return;
+	}
+
+	err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_DR,
+	    ESC_DR_AP_STATE_CHANGE, attr_list, NULL, DDI_NOSLEEP);
+	if (err != 0) {
+		cmn_err(CE_WARN, "Failed to log %s/%s event",
+		    DR_AP_ID, EC_DR);
+	}
+
+	nvlist_free(attr_list);
+}
+
+static void
+fan_sysevent(char *fru_name, char *sensor_name, int sub_event)
+{
+	nvlist_t		*attr_list;
+	char			fan_str[MAXNAMELEN];
+	int			err;
+
+	err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
+	if (err != 0) {
+		cmn_err(CE_WARN,
+		    "Failed to allocate name-value list for %s/%s event",
+		    EC_ENV, ESC_ENV_FAN);
+		return;
+	}
+
+	err = nvlist_add_string(attr_list, ENV_FRU_ID, fru_name);
+	if (err != 0) {
+		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
+		    ENV_FRU_ID, EC_ENV, ESC_ENV_FAN);
+		nvlist_free(attr_list);
+		return;
+	}
+
+	err = nvlist_add_string(attr_list, ENV_FRU_RESOURCE_ID, sensor_name);
+	if (err != 0) {
+		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
+		    ENV_FRU_RESOURCE_ID, EC_ENV, ESC_ENV_FAN);
+		nvlist_free(attr_list);
+		return;
+	}
+
+	err = nvlist_add_string(attr_list, ENV_FRU_DEVICE, ENV_RESERVED_ATTR);
+	if (err != 0) {
+		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
+		    ENV_FRU_DEVICE, EC_ENV, ESC_ENV_FAN);
+		nvlist_free(attr_list);
+		return;
+	}
+
+	err = nvlist_add_int32(attr_list, ENV_FRU_STATE,
+	    (sub_event == RMC_ENV_FAULT_EVENT) ? ENV_FAILED : ENV_OK);
+	if (err != 0) {
+		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
+		    ENV_FRU_STATE, EC_ENV, ESC_ENV_FAN);
+		nvlist_free(attr_list);
+		return;
+	}
+
+	if (sub_event == RMC_ENV_FAULT_EVENT) {
+		(void) snprintf(fan_str, sizeof (fan_str),
+		    "fan %s/%s is now failed", fru_name, sensor_name);
+	} else {
+		(void) snprintf(fan_str, sizeof (fan_str),
+		    "fan %s/%s is now ok", fru_name, sensor_name);
+	}
+	err = nvlist_add_string(attr_list, ENV_MSG, fan_str);
+	if (err != 0) {
+		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
+		    ENV_MSG, EC_ENV, ESC_ENV_FAN);
+		nvlist_free(attr_list);
+		return;
+	}
+
+	err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_ENV,
+	    ESC_ENV_FAN, attr_list, NULL, DDI_NOSLEEP);
+	if (err != 0) {
+		cmn_err(CE_WARN, "Failed to log %s/%s event",
+		    EC_ENV, ESC_ENV_FAN);
+	}
+
+	cmn_err(CE_NOTE, "%s", fan_str);
+	nvlist_free(attr_list);
+}
+
+static void
+threshold_sysevent(char *fru_name, char *sensor_name, int sub_event,
+	char event_type)
+{
+	nvlist_t		*attr_list;
+	int			err;
+	char			*subclass;
+	char			sensor_str[MAXNAMELEN];
+
+	subclass = (event_type == 'T') ? ESC_ENV_TEMP : ESC_ENV_POWER;
+
+	err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
+	if (err != 0) {
+		cmn_err(CE_WARN,
+		    "Failed to allocate name-value list for %s/%s event",
+		    EC_ENV, subclass);
+		return;
+	}
+
+	err = nvlist_add_string(attr_list, ENV_FRU_ID, fru_name);
+	if (err != 0) {
+		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
+		    ENV_FRU_ID, EC_ENV, subclass);
+		nvlist_free(attr_list);
+		return;
+	}
+
+	err = nvlist_add_string(attr_list, ENV_FRU_RESOURCE_ID, sensor_name);
+	if (err != 0) {
+		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
+		    ENV_FRU_RESOURCE_ID, EC_ENV, subclass);
+		nvlist_free(attr_list);
+		return;
+	}
+
+	err = nvlist_add_string(attr_list, ENV_FRU_DEVICE, ENV_RESERVED_ATTR);
+	if (err != 0) {
+		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
+		    ENV_FRU_DEVICE, EC_ENV, subclass);
+		nvlist_free(attr_list);
+		return;
+	}
+
+	switch (sub_event) {
+	case RMC_ENV_OK_EVENT:
+		err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_OK);
+		break;
+	case RMC_ENV_WARNING_THRESHOLD_EVENT:
+		err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_WARNING);
+		break;
+	case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT:
+		err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_FAILED);
+		break;
+	}
+	if (err != 0) {
+		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
+		    ENV_FRU_STATE, EC_ENV, subclass);
+		nvlist_free(attr_list);
+		return;
+	}
+
+	switch (sub_event) {
+	case RMC_ENV_OK_EVENT:
+		(void) snprintf(sensor_str, sizeof (sensor_str),
+		    "sensor %s/%s is now ok", fru_name,
+		    sensor_name);
+		break;
+	case RMC_ENV_WARNING_THRESHOLD_EVENT:
+		(void) snprintf(sensor_str, sizeof (sensor_str),
+		    "sensor %s/%s is now outside warning thresholds", fru_name,
+		    sensor_name);
+		break;
+	case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT:
+		(void) snprintf(sensor_str, sizeof (sensor_str),
+		    "sensor %s/%s is now outside shutdown thresholds", fru_name,
+		    sensor_name);
+		break;
+	}
+	err = nvlist_add_string(attr_list, ENV_MSG, sensor_str);
+	if (err != 0) {
+		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
+		    ENV_MSG, EC_ENV, subclass);
+		nvlist_free(attr_list);
+		return;
+	}
+
+	err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_ENV,
+	    subclass, attr_list, NULL, DDI_NOSLEEP);
+	if (err != 0) {
+		cmn_err(CE_WARN, "Failed to log %s/%s event",
+		    EC_ENV, subclass);
+	}
+
+	cmn_err(CE_NOTE, "%s", sensor_str);
+	nvlist_free(attr_list);
+}
+
+static uint_t
+rmclomv_event_data_handler(char *arg)
+{
+	dp_event_notification_t	*payload;
+	rmc_comm_msg_t	*msg;
+	envmon_handle_t envhdl;
+	int hint;
+	char *ptr, *save_ptr;
+
+	if (arg == NULL) {
+		return (DDI_INTR_CLAIMED);
+	}
+
+	msg = (rmc_comm_msg_t *)arg;
+	if (msg->msg_buf == NULL) {
+		return (DDI_INTR_CLAIMED);
+	}
+
+	payload = (dp_event_notification_t *)msg->msg_buf;
+	switch (payload->event) {
+
+	case RMC_KEYSWITCH_EVENT:
+		real_key_position = payload->event_info.ev_keysw.key_position;
+		cmn_err(CE_NOTE, "keyswitch change event - state = %s",
+		    rmclomv_key_position(real_key_position));
+		if ((real_key_position != RMC_KEYSWITCH_POS_UNKNOWN) &&
+		    (real_key_position <= RMC_KEYSWITCH_POS_OFF)) {
+			key_position = real_key_position;
+		} else {
+			/* treat unknown key position as locked */
+			key_position = RMC_KEYSWITCH_POS_LOCKED;
+		}
+		break;
+
+	case RMC_HPU_EVENT:
+		/*
+		 * send appropriate sysevent
+		 */
+		switch (payload->event_info.ev_hpunot.sub_event) {
+		case RMC_HPU_REMOVE_EVENT:
+			hint = SE_HINT_REMOVE;
+			break;
+		case RMC_HPU_INSERT_EVENT:
+			hint = SE_HINT_INSERT;
+			break;
+		default:
+			hint = SE_NO_HINT;
+			break;
+		}
+		rmclomv_hdl_to_envhdl(payload->event_info.ev_hpunot.hpu_hdl,
+		    &envhdl);
+		rmclomv_dr_data_handler(envhdl.name, hint);
+		break;
+
+	case RMC_INIT_EVENT:
+		/*
+		 * Wake up the refresh thread.
+		 */
+		rmclomv_refresh_wakeup();
+
+		/*
+		 * Wake up the checkrmc thread for an early indication to PICL
+		 */
+		rmclomv_checkrmc_wakeup(NULL);
+		break;
+
+	case RMC_ENV_EVENT:
+		rmclomv_hdl_to_envhdl(payload->event_info.ev_envnot.env_hdl,
+		    &envhdl);
+
+		/* split name into fru name and sensor name */
+		ptr = strchr(envhdl.name, '.');
+
+		/* must have at least one '.' */
+		if (ptr == NULL)
+			break;
+
+		/* find last '.' - convert the others to '/' */
+		for (;;) {
+			save_ptr = ptr;
+			ptr = strchr(ptr, '.');
+			if (ptr == NULL) {
+				ptr = save_ptr;
+				break;
+			}
+			*save_ptr = '/';
+		}
+		*ptr = '\0';
+		ptr++;
+		/* is it a voltage or temperature sensor? */
+		if ((*ptr == 'V' || *ptr == 'T') && *(ptr + 1) == '_') {
+			switch (payload->event_info.ev_envnot.sub_event) {
+			case RMC_ENV_WARNING_THRESHOLD_EVENT:
+			case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT:
+			case RMC_ENV_OK_EVENT:
+				threshold_sysevent(envhdl.name, ptr,
+				    payload->event_info.ev_envnot.sub_event,
+				    *ptr);
+				break;
+			default:
+				break;
+			}
+		}
+
+		/*
+		 * is it a fan sensor?
+		 * Fan sensor names end either in RS, F0 or F1
+		 */
+		if ((*ptr == 'R' && *(ptr + 1) == 'S' && *(ptr + 2) == '\0') ||
+		    (*ptr == 'F' && *(ptr + 1) == '0' && *(ptr + 2) == '\0') ||
+		    (*ptr == 'F' && *(ptr + 1) == '1' && *(ptr + 2) == '\0')) {
+			switch (payload->event_info.ev_envnot.sub_event) {
+			case RMC_ENV_FAULT_EVENT:
+			case RMC_ENV_OK_EVENT:
+				fan_sysevent(envhdl.name, ptr,
+				    payload->event_info.ev_envnot.sub_event);
+				break;
+			default:
+				break;
+			}
+		}
+		break;
+
+	case RMC_LOG_EVENT:
+	{
+		int level = 10;
+		int flags = SL_NOTE | SL_CONSOLE;
+		char *message =
+		    (char *)payload->event_info.ev_rmclog.log_record;
+
+		message[ payload->event_info.ev_rmclog.log_record_size] = '\0';
+
+		/*
+		 * Logs have a 10 character prefix - specifying the severity of
+		 * the event being logged. Thus all the magic number 10s down
+		 * here
+		 */
+		if (0 == strncmp("CRITICAL: ", message, 10)) {
+			message += 10;
+			level = 0;
+			flags = SL_FATAL | SL_ERROR | SL_CONSOLE;
+		} else if (0 == strncmp("MAJOR:    ", message, 10)) {
+			message += 10;
+			level = 5;
+			flags = SL_WARN | SL_ERROR | SL_CONSOLE;
+		} else if (0 == strncmp("MINOR:    ", message, 10)) {
+			message += 10;
+			level = 10;
+			flags = SL_NOTE | SL_CONSOLE;
+		}
+
+		(void) strlog(0, 0, level, flags, message);
+		break;
+	}
+
+	default:
+		return (DDI_INTR_CLAIMED);
+	}
+
+	return (DDI_INTR_CLAIMED);
+}
+
+/*ARGSUSED*/
+static int
+rmclomv_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
+{
+	int error = 0;
+	int instance = getminor(*dev_p);
+
+	if (instance != 0)
+		return (ENXIO);
+
+	if ((flag & FWRITE) != 0 && (error = drv_priv(cred_p)) != 0)
+		return (error);
+
+	return (0);
+}
+
+/*ARGSUSED*/
+static int
+rmclomv_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
+{
+	return (DDI_SUCCESS);
+}
+
+static int
+rmclomv_do_cmd(int req_cmd, int resp_cmd, int resp_len, intptr_t arg_req,
+    intptr_t arg_res)
+{
+	rmc_comm_msg_t request, *reqp = &request;
+	rmc_comm_msg_t response, *resp = &response;
+	int rv = 0;
+
+	bzero((caddr_t)&request, sizeof (request));
+	reqp->msg_type = req_cmd;
+	reqp->msg_buf = (caddr_t)arg_req;
+	bzero((caddr_t)&response, sizeof (response));
+	resp->msg_type = resp_cmd;
+	resp->msg_buf = (caddr_t)arg_res;
+	resp->msg_len = resp_len;
+
+	switch (req_cmd) {
+	case DP_GET_SYSINFO:
+		resp->msg_len = sizeof (dp_get_sysinfo_r_t);
+		break;
+	case DP_GET_EVENT_LOG:
+		resp->msg_len = sizeof (dp_get_event_log_r_t);
+		break;
+	case DP_GET_VOLTS:
+		reqp->msg_len = sizeof (dp_get_volts_t);
+		break;
+	case DP_GET_TEMPERATURES:
+		reqp->msg_len = sizeof (dp_get_temperatures_t);
+		break;
+	case DP_GET_CIRCUIT_BRKS:
+		reqp->msg_len = sizeof (dp_get_circuit_brks_t);
+		break;
+	case DP_GET_FAN_STATUS:
+		reqp->msg_len = sizeof (dp_get_fan_status_t);
+		break;
+	case DP_GET_PSU_STATUS:
+		reqp->msg_len = sizeof (dp_get_psu_status_t);
+		break;
+	case DP_GET_LED_STATE:
+		reqp->msg_len = sizeof (dp_get_led_state_t);
+		break;
+	case DP_SET_LED_STATE:
+		reqp->msg_len = sizeof (dp_set_led_state_t);
+		break;
+	case DP_GET_FRU_STATUS:
+		reqp->msg_len = sizeof (dp_get_fru_status_t);
+		break;
+	case DP_GET_HANDLE_NAME:
+		reqp->msg_len = sizeof (dp_get_handle_name_t);
+		break;
+	case DP_GET_ALARM_STATE:
+		reqp->msg_len = sizeof (dp_get_alarm_state_t);
+		break;
+	case DP_SET_ALARM_STATE:
+		reqp->msg_len = sizeof (dp_set_alarm_state_t);
+		break;
+	case DP_GET_SDP_VERSION:
+		resp->msg_len = sizeof (dp_get_sdp_version_r_t);
+		break;
+	case DP_GET_CHASSIS_SERIALNUM:
+		reqp->msg_len = 0;
+		break;
+	case DP_GET_DATE_TIME:
+		reqp->msg_len = 0;
+		break;
+	default:
+		return (EINVAL);
+	}
+
+	rv = rmc_comm_request_response(reqp, resp,
+	    RMCLOMV_DEFAULT_MAX_MBOX_WAIT_TIME);
+
+	if (rv != RCNOERR) {
+		/*
+		 * RMC returned an error or failed to respond.
+		 * Where the RMC itself is implicated, rmclomv_rmc_error
+		 * is set non-zero. It is cleared after an error free exchange.
+		 * Two failure cases are distinguished:
+		 * RMCLOMV_RMCSTATE_FAILED and RMCLOMV_RMCSTATE_DOWNLOAD.
+		 */
+		switch (rv) {
+		case RCENOSOFTSTATE:
+			/* invalid/NULL soft state structure */
+			return (EIO);
+		case RCENODATALINK:
+			/*
+			 * firmware download in progress,
+			 * can you come back later?
+			 */
+			rmclomv_rmc_error = RMCLOMV_RMCSTATE_DOWNLOAD;
+			rmclomv_rmc_state = RMCLOMV_RMCSTATE_DOWNLOAD;
+			return (EAGAIN);
+		case RCENOMEM:
+			/* memory problems */
+			return (ENOMEM);
+		case RCECANTRESEND:
+			/* resend failed */
+			rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
+			return (EIO);
+		case RCEMAXRETRIES:
+			/* reply not received - retries exceeded */
+			rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
+			return (EINTR);
+		case RCETIMEOUT:
+			/* reply not received - command has timed out */
+			rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
+			return (EINTR);
+		case RCEINVCMD:
+			/* data protocol cmd not supported */
+			return (ENOTSUP);
+		case RCEINVARG:
+			/* invalid argument(s) */
+			return (ENOTSUP);
+		case RCEGENERIC:
+			/* generic error */
+			rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
+			return (EIO);
+		default:
+			rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
+			return (EIO);
+		}
+	}
+
+	rmclomv_rmc_error = RMCLOMV_RMCERROR_NONE;
+	return (0);
+}
+
+/*
+ * validate_section_entry checks that the entry at the specified index
+ * is valid and not duplicated by an entry above. If these tests fail
+ * the entry is removed and B_FALSE returned. Otherwise returns B_TRUE.
+ */
+static int
+validate_section_entry(rmclomv_cache_section_t *section, int index)
+{
+	int			i;
+	rmclomv_cache_entry_t	*entry;
+
+	for (i = index; i < section->num_entries; i++) {
+		entry = &section->entry[i];
+		if (entry->handle_name.name[0] == '\0') {
+			cmn_err(CE_WARN,
+			    "rmclomv: empty handle_name, handle 0x%x type %x",
+			    entry->handle, section->sensor_type);
+		} else if (entry->ind_mask != 0) {
+			continue;	/* skip special entries */
+		} else if (entry->handle == DP_NULL_HANDLE) {
+			cmn_err(CE_WARN,
+			    "rmclomv: null handle id for \"%s\" type %x",
+			    entry->handle_name.name, section->sensor_type);
+		} else if (i == index) {
+			continue;
+		} else if (section->entry[index].handle == entry->handle) {
+			cmn_err(CE_WARN,
+			    "rmclomv: duplicate handle 0x%x type %x",
+			    entry->handle, section->sensor_type);
+		} else if (strcmp(entry->handle_name.name,
+		    section->entry[index].handle_name.name) == 0) {
+			cmn_err(CE_WARN,
+			    "rmclomv: duplicate handle_name \"%s\", "
+			    "handle 0x%x type %x", entry->handle_name.name,
+			    entry->handle, section->sensor_type);
+		} else
+			continue;
+
+		/*
+		 * need to remove the entry at index
+		 */
+		section->num_entries--;
+
+		for (i = index; i < section->num_entries; i++) {
+			section->entry[i] = section->entry[i + 1];
+		}
+
+		return (B_FALSE);
+	}
+
+	return (B_TRUE);
+}
+
+/*
+ * Populate a section containing handles with corresponding names
+ * The supplied section structure must not be publically visible and the
+ * name cache must not be locked either (because RMC i/o is required).
+ *
+ * This is the place where a sanity check is applied. Entries containing
+ * duplicate handles, duplicate names or empty names are removed and the
+ * structure is compacted. As a result num_entries may be reduced.
+ */
+static int
+add_names_to_section(rmclomv_cache_section_t *section)
+{
+	int			retval = 0;
+	int			ditched = B_FALSE;
+	int			index;
+	dp_get_handle_name_r_t	handle_name_r;
+	rmclomv_cache_entry_t	*entry;
+
+	for (index = 0; index < section->num_entries; index++) {
+		entry = &section->entry[index];
+		if (entry->ind_mask != 0)
+			continue;	/* skip special entries */
+		handle_name_r.handle = entry->handle;
+		retval = rmclomv_do_cmd(DP_GET_HANDLE_NAME,
+		    DP_GET_HANDLE_NAME_R, sizeof (handle_name_r),
+		    (intptr_t)&handle_name_r, (intptr_t)&handle_name_r);
+		if (retval == 0)
+			bcopy(handle_name_r.name,
+			    entry->handle_name.name, DP_MAX_HANDLE_NAME);
+	}
+
+	/*
+	 * now ditch invalid and duplicate entries
+	 */
+	for (index = 0; index < section->num_entries; index++) {
+		while (validate_section_entry(section, index) == B_FALSE)
+			ditched = B_TRUE;
+	}
+
+	if (ditched)
+		cmn_err(CE_WARN, "Retaining %d nodes of type %d",
+		    section->num_entries, section->sensor_type);
+
+	return (retval);
+}
+
+/*
+ * The supplied (PSU) cache section is traversed and entries are created
+ * for the individual indicators belonging to a PSU. These entries are
+ * placed in a private chain. The caller, subsequently acquires the
+ * cache lock and copies the chain head to make it public.
+ * The handle-names for PSU indicators are derived from the parent PSU
+ * handle-name.
+ * NOTE: add_names_to_section() may have reduced psu_section->num_entries
+ *       so DON'T USE psu_resp->num_psus
+ */
+static void
+make_psu_subsections(rmclomv_cache_section_t *psu_section,
+    rmclomv_cache_section_t **chain_head, dp_get_psu_status_r_t *psu_resp)
+{
+	int			index;
+	int			subindex = 0;
+	rmclomv_cache_section_t	*subsection;
+	rmclomv_cache_entry_t	*src_entry;
+	rmclomv_cache_entry_t	*dst_entry;
+
+	subsection = create_cache_section(RMCLOMV_VOLT_IND,
+	    RMCLOMV_MAX_VI_PER_PSU * psu_section->num_entries);
+	for (index = 0; index < psu_section->num_entries; index++) {
+		src_entry = &psu_section->entry[index];
+		if ((psu_resp->psu_status[index].mask &
+		    DP_PSU_INPUT_STATUS) != 0) {
+			dst_entry = &subsection->entry[subindex++];
+			dst_entry->handle = src_entry->handle;
+			dst_entry->ind_mask = DP_PSU_INPUT_STATUS;
+			(void) snprintf(dst_entry->handle_name.name,
+			    ENVMON_MAXNAMELEN, "%s.%s",
+			    src_entry->handle_name.name,
+			    str_ip_volts_ind);
+		}
+
+		if ((psu_resp->psu_status[index].mask &
+		    DP_PSU_SEC_INPUT_STATUS) != 0) {
+			dst_entry = &subsection->entry[subindex++];
+			dst_entry->handle = src_entry->handle;
+			dst_entry->ind_mask = DP_PSU_SEC_INPUT_STATUS;
+			(void) snprintf(dst_entry->handle_name.name,
+			    ENVMON_MAXNAMELEN, "%s.%s",
+			    src_entry->handle_name.name,
+			    str_ip2_volts_ind);
+		}
+
+		if ((psu_resp->psu_status[index].mask &
+		    DP_PSU_OUTPUT_STATUS) != 0) {
+			dst_entry = &subsection->entry[subindex++];
+			dst_entry->handle = src_entry->handle;
+			dst_entry->ind_mask = DP_PSU_OUTPUT_STATUS;
+			(void) snprintf(dst_entry->handle_name.name,
+			    ENVMON_MAXNAMELEN, "%s.%s",
+			    src_entry->handle_name.name,
+			    str_ff_pok_ind);
+		}
+
+		if ((psu_resp->psu_status[index].mask &
+		    DP_PSU_OUTPUT_VLO_STATUS) != 0) {
+			dst_entry = &subsection->entry[subindex++];
+			dst_entry->handle = src_entry->handle;
+			dst_entry->ind_mask = DP_PSU_OUTPUT_VLO_STATUS;
+			(void) snprintf(dst_entry->handle_name.name,
+			    ENVMON_MAXNAMELEN, "%s.%s",
+			    src_entry->handle_name.name,
+			    str_vlo_volts_ind);
+		}
+
+		if ((psu_resp->psu_status[index].mask &
+		    DP_PSU_OUTPUT_VHI_STATUS) != 0) {
+			dst_entry = &subsection->entry[subindex++];
+			dst_entry->handle = src_entry->handle;
+			dst_entry->ind_mask = DP_PSU_OUTPUT_VHI_STATUS;
+			(void) snprintf(dst_entry->handle_name.name,
+			    ENVMON_MAXNAMELEN, "%s.%s",
+			    src_entry->handle_name.name,
+			    str_vhi_volts_ind);
+		}
+	}
+	/*
+	 * Adjust number of entries value in cache section
+	 * to match the facts.
+	 */
+	subsection->num_entries = subindex;
+	add_section(chain_head, subsection);
+
+	subsection = create_cache_section(RMCLOMV_AMP_IND,
+	    RMCLOMV_MAX_CI_PER_PSU * psu_section->num_entries);
+	subindex = 0;
+	for (index = 0; index < psu_section->num_entries; index++) {
+		int mask = psu_resp->psu_status[index].mask;
+		src_entry = &psu_section->entry[index];
+		if ((mask & DP_PSU_OUTPUT_AHI_STATUS) != 0) {
+			dst_entry = &subsection->entry[subindex++];
+			dst_entry->handle = src_entry->handle;
+			dst_entry->ind_mask = DP_PSU_OUTPUT_AHI_STATUS;
+			(void) snprintf(dst_entry->handle_name.name,
+			    ENVMON_MAXNAMELEN, "%s.%s",
+			    src_entry->handle_name.name,
+			    str_chi_amps_ind);
+		}
+		if ((mask & DP_PSU_NR_WARNING) != 0) {
+			dst_entry = &subsection->entry[subindex++];
+			dst_entry->handle = src_entry->handle;
+			dst_entry->ind_mask = DP_PSU_NR_WARNING;
+			(void) snprintf(dst_entry->handle_name.name,
+			    ENVMON_MAXNAMELEN, "%s.%s",
+			    src_entry->handle_name.name,
+			    str_chi_nr_ind);
+		}
+	}
+	subsection->num_entries = subindex;
+	add_section(chain_head, subsection);
+
+	subsection = create_cache_section(RMCLOMV_TEMP_IND,
+	    psu_section->num_entries);
+	subindex = 0;
+	for (index = 0; index < psu_section->num_entries; index++) {
+		if ((psu_resp->psu_status[index].mask &
+		    DP_PSU_OVERTEMP_FAULT) != 0) {
+			src_entry = &psu_section->entry[index];
+			dst_entry = &subsection->entry[subindex++];
+			dst_entry->handle = src_entry->handle;
+			dst_entry->ind_mask = DP_PSU_OVERTEMP_FAULT;
+			(void) snprintf(dst_entry->handle_name.name,
+			    ENVMON_MAXNAMELEN, "%s.%s",
+			    src_entry->handle_name.name,
+			    str_ot_tmpr_ind);
+		}
+	}
+	subsection->num_entries = subindex;
+	add_section(chain_head, subsection);
+
+	subsection = create_cache_section(RMCLOMV_FAN_IND,
+	    RMCLOMV_MAX_FI_PER_PSU * psu_section->num_entries);
+	subindex = 0;
+	for (index = 0; index < psu_section->num_entries; index++) {
+		int mask = psu_resp->psu_status[index].mask;
+		src_entry = &psu_section->entry[index];
+		if ((mask & DP_PSU_FAN_FAULT) != 0) {
+			dst_entry = &subsection->entry[subindex++];
+			dst_entry->handle = src_entry->handle;
+			dst_entry->ind_mask = DP_PSU_FAN_FAULT;
+			(void) snprintf(dst_entry->handle_name.name,
+			    ENVMON_MAXNAMELEN, "%s.%s",
+			    src_entry->handle_name.name, str_fan_ind);
+		}
+		if ((mask & DP_PSU_PDCT_FAN) != 0) {
+			dst_entry = &subsection->entry[subindex++];
+			dst_entry->handle = src_entry->handle;
+			dst_entry->ind_mask = DP_PSU_PDCT_FAN;
+			(void) snprintf(dst_entry->handle_name.name,
+			    ENVMON_MAXNAMELEN, "%s.%s",
+			    src_entry->handle_name.name, str_pdct_fan_ind);
+		}
+	}
+	subsection->num_entries = subindex;
+	add_section(chain_head, subsection);
+}
+
+static void
+refresh_name_cache(int force_fail)
+{
+	union {
+		dp_get_volts_t		u_volts_cmd;
+		dp_get_temperatures_t	u_temp_cmd;
+		dp_get_circuit_brks_t	u_ampi_cmd;
+		dp_get_fan_status_t	u_fan_cmd;
+		dp_get_psu_status_t	u_psu_cmd;
+		dp_get_fru_status_t	u_fru_cmd;
+		dp_get_led_state_t	u_led_cmd;
+		dp_set_led_state_t	u_setled_cmd;
+		dp_get_alarm_state_t	u_alarm_cmd;
+		dp_set_alarm_state_t	u_setalarm_cmd;
+	} rmc_cmdbuf;
+
+/* defines for accessing union fields */
+#define	volts_cmd	rmc_cmdbuf.u_volts_cmd
+#define	temp_cmd	rmc_cmdbuf.u_temp_cmd
+#define	ampi_cmd	rmc_cmdbuf.u_ampi_cmd
+#define	fan_cmd		rmc_cmdbuf.u_fan_cmd
+#define	psu_cmd		rmc_cmdbuf.u_psu_cmd
+#define	fru_cmd		rmc_cmdbuf.u_fru_cmd
+#define	led_cmd		rmc_cmdbuf.u_led_cmd
+#define	setled_cmd	rmc_cmdbuf.u_setled_cmd
+#define	alarm_cmd	rmc_cmdbuf.u_alarm_cmd
+#define	setalarm_cmd	rmc_cmdbuf.u_setalarm_cmd
+
+	/*
+	 * Data area to read sensor data into
+	 */
+	static union {
+		char			reservation[RMCRESBUFLEN];
+		dp_get_volts_r_t	u_volts_r;
+		dp_get_temperatures_r_t	u_temp_r;
+		dp_get_circuit_brks_r_t	u_ampi_r;
+		dp_get_fan_status_r_t	u_fan_r;
+		dp_get_psu_status_r_t	u_psu_r;
+		dp_get_fru_status_r_t	u_fru_r;
+		dp_get_led_state_r_t	u_led_r;
+		dp_set_led_state_r_t	u_setled_r;
+		dp_get_alarm_state_r_t	u_alarm_r;
+		dp_set_alarm_state_r_t	u_setalarm_r;
+	} rmc_sensbuf;
+
+/* defines for accessing union fields */
+#define	volts_r		rmc_sensbuf.u_volts_r
+#define	temp_r		rmc_sensbuf.u_temp_r
+#define	ampi_r		rmc_sensbuf.u_ampi_r
+#define	fan_r		rmc_sensbuf.u_fan_r
+#define	psu_r		rmc_sensbuf.u_psu_r
+#define	fru_r		rmc_sensbuf.u_fru_r
+#define	led_r		rmc_sensbuf.u_led_r
+#define	setled_r	rmc_sensbuf.u_setled_r
+#define	alarm_r		rmc_sensbuf.u_alarm_r
+#define	setalarm_r	rmc_sensbuf.u_setalarm_r
+
+	int			retval = force_fail;
+	int			retval1 = retval;
+	int			index;
+	rmclomv_cache_section_t	*my_chain = NULL;
+	rmclomv_cache_section_t	*derived_chain = NULL;
+	rmclomv_cache_section_t	*section;
+	rmclomv_cache_section_t	*psu_section;
+	rmclomv_cache_section_t	*fru_section;
+	dp_get_sysinfo_r_t	sysinfo;
+	rmclomv_cache_entry_t	*entry;
+
+	if (retval == 0) {
+		retval = rmclomv_do_cmd(DP_GET_SYSINFO, DP_GET_SYSINFO_R,
+		    sizeof (sysinfo), NULL, (intptr_t)&sysinfo);
+	}
+	if (retval == 0) {
+		fru_cmd.handle = DP_NULL_HANDLE;
+		retval = rmclomv_do_cmd(DP_GET_FRU_STATUS, DP_GET_FRU_STATUS_R,
+		    RMCRESBUFLEN, (intptr_t)&fru_cmd, (intptr_t)&fru_r);
+	}
+	if (retval != 0)
+		fru_r.num_frus = 0;
+
+	/*
+	 * Reserve space for special additional entries in the FRU section
+	 */
+	fru_section = create_cache_section(RMCLOMV_HPU_IND,
+	    RMCLOMV_NUM_SPECIAL_FRUS + fru_r.num_frus);
+
+	/*
+	 * add special entry for RMC itself
+	 */
+	entry = &fru_section->entry[0];
+	(void) snprintf(entry->handle_name.name, sizeof (envmon_handle_t),
+	    "SC");
+	entry->handle = 0;
+	entry->ind_mask = 1;	/* flag as a special entry */
+
+	/*
+	 * populate any other FRU entries
+	 */
+	for (index = 0; index < fru_r.num_frus; index++) {
+		fru_section->entry[RMCLOMV_NUM_SPECIAL_FRUS + index].handle =
+		    fru_r.fru_status[index].handle;
+		fru_section->entry[RMCLOMV_NUM_SPECIAL_FRUS + index].ind_mask =
+		    0;
+	}
+
+	my_chain = fru_section;
+
+	if (retval == 0) {
+		volts_cmd.handle = DP_NULL_HANDLE;
+		retval = rmclomv_do_cmd(DP_GET_VOLTS, DP_GET_VOLTS_R,
+		    RMCRESBUFLEN, (intptr_t)&volts_cmd, (intptr_t)&volts_r);
+	}
+	if (retval == 0) {
+		section = create_cache_section(RMCLOMV_VOLT_SENS,
+		    volts_r.num_volts);
+		for (index = 0; index < volts_r.num_volts; index++) {
+			section->entry[index].handle =
+			    volts_r.volt_status[index].handle;
+		}
+		add_section(&my_chain, section);
+	}
+	if (retval == 0) {
+		temp_cmd.handle = DP_NULL_HANDLE;
+		retval = rmclomv_do_cmd(DP_GET_TEMPERATURES,
+		    DP_GET_TEMPERATURES_R, RMCRESBUFLEN,
+		    (intptr_t)&temp_cmd, (intptr_t)&temp_r);
+	}
+	if (retval == 0) {
+		section = create_cache_section(RMCLOMV_TEMP_SENS,
+		    temp_r.num_temps);
+		for (index = 0; index < temp_r.num_temps; index++) {
+			section->entry[index].handle =
+			    temp_r.temp_status[index].handle;
+		}
+		add_section(&my_chain, section);
+	}
+	if (retval == 0) {
+		fan_cmd.handle = DP_NULL_HANDLE;
+		retval = rmclomv_do_cmd(DP_GET_FAN_STATUS, DP_GET_FAN_STATUS_R,
+		    RMCRESBUFLEN, (intptr_t)&fan_cmd, (intptr_t)&fan_r);
+	}
+	if (retval == 0) {
+		section = create_cache_section(RMCLOMV_FAN_SENS,
+		    fan_r.num_fans);
+		for (index = 0; index < fan_r.num_fans; index++) {
+			section->entry[index].handle =
+			    fan_r.fan_status[index].handle;
+		}
+		add_section(&my_chain, section);
+	}
+	if (retval == 0) {
+		ampi_cmd.handle = DP_NULL_HANDLE;
+		retval = rmclomv_do_cmd(DP_GET_CIRCUIT_BRKS,
+		    DP_GET_CIRCUIT_BRKS_R, RMCRESBUFLEN,
+		    (intptr_t)&ampi_cmd, (intptr_t)&ampi_r);
+	}
+	if (retval == 0) {
+		section = create_cache_section(RMCLOMV_AMP_IND,
+		    ampi_r.num_circuit_brks);
+		for (index = 0; index < ampi_r.num_circuit_brks; index++) {
+			section->entry[index].handle =
+			    ampi_r.circuit_brk_status[index].handle;
+		}
+		add_section(&my_chain, section);
+	}
+	if (retval == 0) {
+		led_cmd.handle = DP_NULL_HANDLE;
+		retval = rmclomv_do_cmd(DP_GET_LED_STATE, DP_GET_LED_STATE_R,
+		    RMCRESBUFLEN, (intptr_t)&led_cmd, (intptr_t)&led_r);
+	}
+	if (retval == 0) {
+		section = create_cache_section(RMCLOMV_LED_IND,
+		    led_r.num_leds);
+		for (index = 0; index < led_r.num_leds; index++) {
+			section->entry[index].handle =
+			    led_r.led_state[index].handle;
+		}
+		add_section(&my_chain, section);
+	}
+	/*
+	 * The command DP_GET_ALARM_STATE may not be valid on
+	 * some RMC versions, so we ignore the return value
+	 * and proceed
+	 */
+	if (retval == 0) {
+		alarm_cmd.handle = DP_NULL_HANDLE;
+		retval1 = rmclomv_do_cmd(DP_GET_ALARM_STATE,
+			DP_GET_ALARM_STATE_R, RMCRESBUFLEN,
+			(intptr_t)&alarm_cmd, (intptr_t)&alarm_r);
+		if ((retval1 == 0) && alarm_r.num_alarms) {
+			section = create_cache_section(RMCLOMV_ALARM_IND,
+				alarm_r.num_alarms);
+			for (index = 0; index < alarm_r.num_alarms; index++) {
+				section->entry[index].handle =
+					alarm_r.alarm_state[index].handle;
+			}
+			add_section(&my_chain, section);
+		}
+	}
+	if (retval == 0) {
+		psu_cmd.handle = DP_NULL_HANDLE;
+		retval = rmclomv_do_cmd(DP_GET_PSU_STATUS, DP_GET_PSU_STATUS_R,
+		    RMCRESBUFLEN, (intptr_t)&psu_cmd, (intptr_t)&psu_r);
+	}
+	if (retval == 0) {
+		/*
+		 * WARNING:
+		 * =======
+		 * The PSUs must be probed last so that the response data
+		 * (psu_r) is available for make_psu_subsections() below.
+		 * Note that all the responses share the same data area
+		 * which is declared as a union.
+		 */
+		psu_section = create_cache_section(RMCLOMV_PSU_IND,
+		    psu_r.num_psus);
+		for (index = 0; index < psu_r.num_psus; index++) {
+			psu_section->entry[index].handle =
+			    psu_r.psu_status[index].handle;
+		}
+		add_section(&my_chain, psu_section);
+	}
+	if (retval == 0) {
+		for (section = my_chain;
+		    section != NULL;
+		    section = section->next_section) {
+			retval = add_names_to_section(section);
+			if (retval != 0) {
+				break;
+			}
+		}
+	}
+
+	/*
+	 * now add nodes derived from PSUs
+	 */
+	if (retval == 0) {
+		make_psu_subsections(psu_section, &derived_chain, &psu_r);
+		/*
+		 * name cache sections all set, exchange new for old
+		 */
+		rmclomv_reset_cache(my_chain, derived_chain, &sysinfo);
+	} else {
+		/*
+		 * RMC is not responding, ditch any existing cache
+		 * and just leave the special SC FRU node
+		 */
+		rmclomv_reset_cache(my_chain, NULL, NULL);
+	}
+}
+
+static void
+set_val_unav(envmon_sensor_t *sensor)
+{
+	sensor->value = ENVMON_VAL_UNAVAILABLE;
+	sensor->lowthresholds.warning = ENVMON_VAL_UNAVAILABLE;
+	sensor->lowthresholds.shutdown = ENVMON_VAL_UNAVAILABLE;
+	sensor->lowthresholds.poweroff = ENVMON_VAL_UNAVAILABLE;
+	sensor->highthresholds.warning = ENVMON_VAL_UNAVAILABLE;
+	sensor->highthresholds.shutdown = ENVMON_VAL_UNAVAILABLE;
+	sensor->highthresholds.poweroff = ENVMON_VAL_UNAVAILABLE;
+}
+
+static void
+set_fan_unav(envmon_fan_t *fan)
+{
+	fan->speed = ENVMON_VAL_UNAVAILABLE;
+	fan->units[0] = '\0';
+	fan->lowthresholds.warning = ENVMON_VAL_UNAVAILABLE;
+	fan->lowthresholds.shutdown = ENVMON_VAL_UNAVAILABLE;
+	fan->lowthresholds.poweroff = ENVMON_VAL_UNAVAILABLE;
+}
+
+static int
+do_psu_cmd(intptr_t arg, int mode, envmon_indicator_t *env_ind,
+    dp_get_psu_status_t *rmc_psu, dp_get_psu_status_r_t *rmc_psu_r,
+    int detector_type)
+{
+	int			index;
+	uint16_t		sensor_status;
+	rmclomv_cache_section_t	*section;
+	uint16_t		indicator_mask;
+
+	if (ddi_copyin((caddr_t)arg, (caddr_t)env_ind,
+	    sizeof (envmon_indicator_t), mode) != 0)
+		return (EFAULT);
+
+	/* ensure we've got PSU handles cached */
+	LOCK_CACHE
+
+	sensor_status = ENVMON_SENSOR_OK;
+	section = rmclomv_find_section(rmclomv_subcache, detector_type);
+	if (env_ind->id.name[0] == '\0') {
+		/* request for first handle */
+		if ((section == NULL) || (section->num_entries == 0))
+			env_ind->next_id.name[0] = '\0';
+		else
+			env_ind->next_id = section->entry[0].handle_name;
+		sensor_status = ENVMON_NOT_PRESENT;
+	} else {
+		/* ensure name is properly terminated */
+		env_ind->id.name[ENVMON_MAXNAMELEN - 1] = '\0';
+		if ((section == NULL) || (get_sensor_by_name(section,
+		    env_ind->id.name, &index)) != 0) {
+			env_ind->next_id.name[0] = '\0';
+			sensor_status = ENVMON_NOT_PRESENT;
+		} else if (index + 1 < section->num_entries)
+			env_ind->next_id =
+			    section->entry[index + 1].handle_name;
+		else
+			env_ind->next_id.name[0] = '\0';
+	}
+	if (sensor_status == ENVMON_SENSOR_OK) {
+		/*
+		 * user correctly identified a sensor, note its
+		 * handle value and request the indicator status
+		 */
+		rmc_psu->handle = section->entry[index].handle;
+		indicator_mask = section->entry[index].ind_mask;
+	}
+
+	RELEASE_CACHE
+
+	if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
+	    rmclomv_do_cmd(DP_GET_PSU_STATUS, DP_GET_PSU_STATUS_R,
+	    sizeof (dp_get_psu_status_r_t), (intptr_t)rmc_psu,
+	    (intptr_t)rmc_psu_r) != 0)) {
+		sensor_status = ENVMON_INACCESSIBLE;
+	}
+	if ((env_ind->sensor_status = sensor_status) == ENVMON_SENSOR_OK) {
+		/*
+		 * copy results into buffer for user
+		 */
+		if ((rmc_psu_r->psu_status[0].flag & DP_PSU_PRESENCE) == 0)
+			env_ind->sensor_status |= ENVMON_NOT_PRESENT;
+		if (rmc_psu_r->psu_status[0].sensor_status !=
+		    DP_SENSOR_DATA_AVAILABLE)
+			env_ind->sensor_status |= ENVMON_INACCESSIBLE;
+		env_ind->condition =
+		    (rmc_psu_r->psu_status[0].flag & indicator_mask) == 0 ?
+		    0 : 1;
+	}
+
+	if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE)
+	    env_ind->sensor_status = ENVMON_INACCESSIBLE;
+
+	if (ddi_copyout((caddr_t)env_ind, (caddr_t)arg,
+	    sizeof (envmon_indicator_t), mode) != 0)
+		return (EFAULT);
+
+	return (0);
+}
+
+/*ARGSUSED*/
+static int
+rmclomv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
+    int *rval_p)
+{
+	int instance = getminor(dev);
+	envmon_sysinfo_t lomv_sysinfo;
+	union {
+		envmon_sensor_t		u_env_sensor;
+		envmon_indicator_t	u_env_ind;
+		envmon_fan_t		u_env_fan;
+		envmon_led_info_t	u_env_ledinfo;
+		envmon_led_ctl_t	u_env_ledctl;
+		envmon_hpu_t		u_env_hpu;
+		envmon_alarm_info_t	u_env_alarminfo;
+		envmon_alarm_ctl_t	u_env_alarmctl;
+	} env_buf;
+#define	env_sensor	env_buf.u_env_sensor
+#define	env_ind		env_buf.u_env_ind
+#define	env_fan		env_buf.u_env_fan
+#define	env_ledinfo	env_buf.u_env_ledinfo
+#define	env_ledctl	env_buf.u_env_ledctl
+#define	env_hpu		env_buf.u_env_hpu
+#define	env_alarminfo	env_buf.u_env_alarminfo
+#define	env_alarmctl	env_buf.u_env_alarmctl
+
+	union {
+		dp_get_volts_t		u_rmc_volts;
+		dp_get_temperatures_t	u_rmc_temp;
+		dp_get_circuit_brks_t	u_rmc_ampi;
+		dp_get_fan_status_t	u_rmc_fan;
+		dp_get_psu_status_t	u_rmc_psu;
+		dp_get_fru_status_t	u_rmc_fru;
+		dp_get_led_state_t	u_rmc_led;
+		dp_set_led_state_t	u_rmc_setled;
+		dp_get_alarm_state_t	u_rmc_alarm;
+		dp_set_alarm_state_t	u_rmc_setalarm;
+	} rmc_reqbuf;
+#define	rmc_volts	rmc_reqbuf.u_rmc_volts
+#define	rmc_temp	rmc_reqbuf.u_rmc_temp
+#define	rmc_ampi	rmc_reqbuf.u_rmc_ampi
+#define	rmc_fan		rmc_reqbuf.u_rmc_fan
+#define	rmc_psu		rmc_reqbuf.u_rmc_psu
+#define	rmc_fru		rmc_reqbuf.u_rmc_fru
+#define	rmc_led		rmc_reqbuf.u_rmc_led
+#define	rmc_setled	rmc_reqbuf.u_rmc_setled
+#define	rmc_alarm	rmc_reqbuf.u_rmc_alarm
+#define	rmc_setalarm	rmc_reqbuf.u_rmc_setalarm
+
+	union {
+		dp_get_volts_r_t	u_rmc_volts_r;
+		dp_get_temperatures_r_t	u_rmc_temp_r;
+		dp_get_circuit_brks_r_t	u_rmc_ampi_r;
+		dp_get_fan_status_r_t	u_rmc_fan_r;
+		dp_get_psu_status_r_t	u_rmc_psu_r;
+		dp_get_fru_status_r_t	u_rmc_fru_r;
+		dp_get_led_state_r_t	u_rmc_led_r;
+		dp_set_led_state_r_t	u_rmc_setled_r;
+		dp_get_alarm_state_r_t	u_rmc_alarm_r;
+		dp_set_alarm_state_r_t	u_rmc_setalarm_r;
+		dp_get_sdp_version_r_t	u_rmc_sdpversion_r;
+		dp_get_serialnum_r_t	u_rmc_serialnum_r;
+	} rmc_resbuf;
+#define	rmc_volts_r	rmc_resbuf.u_rmc_volts_r
+#define	rmc_temp_r	rmc_resbuf.u_rmc_temp_r
+#define	rmc_ampi_r	rmc_resbuf.u_rmc_ampi_r
+#define	rmc_fan_r	rmc_resbuf.u_rmc_fan_r
+#define	rmc_psu_r	rmc_resbuf.u_rmc_psu_r
+#define	rmc_fru_r	rmc_resbuf.u_rmc_fru_r
+#define	rmc_led_r	rmc_resbuf.u_rmc_led_r
+#define	rmc_setled_r	rmc_resbuf.u_rmc_setled_r
+#define	rmc_alarm_r	rmc_resbuf.u_rmc_alarm_r
+#define	rmc_setalarm_r	rmc_resbuf.u_rmc_setalarm_r
+#define	rmc_sdpver_r	rmc_resbuf.u_rmc_sdpversion_r
+#define	rmc_serialnum_r	rmc_resbuf.u_rmc_serialnum_r
+
+	int			retval = 0;
+	int			special = 0;
+	int			index;
+	uint16_t		sensor_status;
+	rmclomv_cache_section_t	*section;
+	envmon_chassis_t chassis;
+
+	if (instance != 0)
+		return (ENXIO);
+
+	switch (cmd) {
+	case ENVMONIOCSYSINFO:
+
+		LOCK_CACHE
+
+		/*
+		 * A number of OK/not_OK indicators are supported by PSUs
+		 * (voltage, current, fan, temperature). So the maximum
+		 * number of such indicators relates to the maximum number
+		 * of power-supplies.
+		 */
+		if (rmclomv_sysinfo_valid) {
+			lomv_sysinfo.maxVoltSens = rmclomv_sysinfo_data.maxVolt;
+			lomv_sysinfo.maxVoltInd =
+			    RMCLOMV_MAX_VI_PER_PSU *
+			    rmclomv_sysinfo_data.maxPSU;
+			/*
+			 * the ALOM-Solaris interface does not include
+			 * amp sensors, so we can hard code this value
+			 */
+			lomv_sysinfo.maxAmpSens = 0;
+			lomv_sysinfo.maxAmpInd =
+			    rmclomv_sysinfo_data.maxCircuitBrks +
+			    (RMCLOMV_MAX_CI_PER_PSU *
+			    rmclomv_sysinfo_data.maxPSU);
+			lomv_sysinfo.maxTempSens = rmclomv_sysinfo_data.maxTemp;
+			lomv_sysinfo.maxTempInd =
+			    (RMCLOMV_MAX_TI_PER_PSU *
+			    rmclomv_sysinfo_data.maxPSU);
+			lomv_sysinfo.maxFanSens = rmclomv_sysinfo_data.maxFan;
+			lomv_sysinfo.maxFanInd =
+			    RMCLOMV_MAX_FI_PER_PSU *
+			    rmclomv_sysinfo_data.maxPSU;
+			lomv_sysinfo.maxLED = rmclomv_sysinfo_data.maxLED;
+			lomv_sysinfo.maxHPU = RMCLOMV_NUM_SPECIAL_FRUS +
+			    rmclomv_sysinfo_data.maxFRU;
+		} else {
+			bzero(&lomv_sysinfo, sizeof (lomv_sysinfo));
+			lomv_sysinfo.maxHPU = 1;	/* just the SC node */
+		}
+
+		RELEASE_CACHE
+
+		if (ddi_copyout((caddr_t)&lomv_sysinfo, (caddr_t)arg,
+		    sizeof (lomv_sysinfo), mode) != 0)
+			return (EFAULT);
+		break;
+
+	case ENVMONIOCVOLTSENSOR:
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor,
+		    sizeof (envmon_sensor_t), mode) != 0)
+			return (EFAULT);
+
+		/* see if we've got volts handles cached */
+		LOCK_CACHE
+		sensor_status = ENVMON_SENSOR_OK;
+
+		if ((rmclomv_cache_valid == B_FALSE) ||
+		    ((section = rmclomv_find_section(rmclomv_cache,
+		    RMCLOMV_VOLT_SENS)) == NULL)) {
+			env_sensor.next_id.name[0] = '\0';
+			sensor_status = ENVMON_NOT_PRESENT;
+		} else if (env_sensor.id.name[0] == '\0') {
+			/* request for first handle */
+			if (section->num_entries == 0)
+				env_sensor.next_id.name[0] = '\0';
+			else
+				env_sensor.next_id =
+				    section->entry[0].handle_name;
+			sensor_status = ENVMON_NOT_PRESENT;
+		} else {
+			/* ensure name is properly terminated */
+			env_sensor.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
+			if (get_sensor_by_name(section, env_sensor.id.name,
+			    &index) != 0) {
+				env_sensor.next_id.name[0] = '\0';
+				sensor_status = ENVMON_NOT_PRESENT;
+			} else if (index + 1 < section->num_entries)
+				env_sensor.next_id =
+				    section->entry[index + 1].handle_name;
+			else
+				env_sensor.next_id.name[0] = '\0';
+		}
+		if (sensor_status == ENVMON_SENSOR_OK) {
+			/*
+			 * user correctly identified a sensor, note its
+			 * handle value and request the sensor value
+			 */
+			rmc_volts.handle = section->entry[index].handle;
+		}
+		RELEASE_CACHE
+		if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
+		    rmclomv_do_cmd(DP_GET_VOLTS, DP_GET_VOLTS_R,
+		    sizeof (rmc_volts_r), (intptr_t)&rmc_volts,
+		    (intptr_t)&rmc_volts_r) != 0)) {
+			sensor_status = ENVMON_INACCESSIBLE;
+		}
+		if ((sensor_status == ENVMON_SENSOR_OK) &&
+		    (rmc_volts_r.volt_status[0].sensor_status ==
+		    DP_SENSOR_NOT_PRESENT)) {
+			sensor_status = ENVMON_NOT_PRESENT;
+		}
+		if ((env_sensor.sensor_status = sensor_status) ==
+		    ENVMON_SENSOR_OK) {
+			/*
+			 * copy results into buffer for user
+			 */
+			if (rmc_volts_r.volt_status[0].sensor_status !=
+			    DP_SENSOR_DATA_AVAILABLE)
+				env_sensor.sensor_status = ENVMON_INACCESSIBLE;
+			env_sensor.value =
+			    rmc_volts_r.volt_status[0].reading;
+			env_sensor.lowthresholds.warning =
+			    rmc_volts_r.volt_status[0].low_warning;
+			env_sensor.lowthresholds.shutdown =
+			    rmc_volts_r.volt_status[0].low_soft_shutdown;
+			env_sensor.lowthresholds.poweroff =
+			    rmc_volts_r.volt_status[0].low_hard_shutdown;
+			env_sensor.highthresholds.warning =
+			    rmc_volts_r.volt_status[0].high_warning;
+			env_sensor.highthresholds.shutdown =
+			    rmc_volts_r.volt_status[0].high_soft_shutdown;
+			env_sensor.highthresholds.poweroff =
+			    rmc_volts_r.volt_status[0].high_hard_shutdown;
+		}
+		if (env_sensor.sensor_status != ENVMON_SENSOR_OK ||
+		    rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE)
+			set_val_unav(&env_sensor);
+
+		if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg,
+		    sizeof (envmon_sensor_t), mode) != 0)
+			return (EFAULT);
+		break;
+
+	case ENVMONIOCVOLTIND:
+		return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r,
+		    RMCLOMV_VOLT_IND));
+
+	case ENVMONIOCTEMPIND:
+		return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r,
+		    RMCLOMV_TEMP_IND));
+
+	case ENVMONIOCFANIND:
+		return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r,
+		    RMCLOMV_FAN_IND));
+
+	case ENVMONIOCAMPSENSOR:
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor,
+		    sizeof (envmon_sensor_t), mode) != 0)
+			return (EFAULT);
+
+		env_sensor.sensor_status = ENVMON_NOT_PRESENT;
+		env_sensor.next_id.name[0] = '\0';
+
+		if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg,
+		    sizeof (envmon_sensor_t), mode) != 0)
+			return (EFAULT);
+		break;
+
+	case ENVMONIOCTEMPSENSOR:
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor,
+		    sizeof (envmon_sensor_t), mode) != 0)
+			return (EFAULT);
+
+		/* see if we've got temperature handles cached */
+		LOCK_CACHE
+		sensor_status = ENVMON_SENSOR_OK;
+
+		if ((rmclomv_cache_valid == B_FALSE) ||
+		    ((section = rmclomv_find_section(rmclomv_cache,
+		    RMCLOMV_TEMP_SENS)) == NULL)) {
+			env_sensor.next_id.name[0] = '\0';
+			sensor_status = ENVMON_NOT_PRESENT;
+		} else if (env_sensor.id.name[0] == '\0') {
+			/* request for first handle */
+			if (section->num_entries == 0)
+				env_sensor.next_id.name[0] = '\0';
+			else
+				env_sensor.next_id =
+				    section->entry[0].handle_name;
+			sensor_status = ENVMON_NOT_PRESENT;
+		} else {
+			/* ensure name is properly terminated */
+			env_sensor.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
+			if (get_sensor_by_name(section, env_sensor.id.name,
+			    &index) != 0) {
+				env_sensor.next_id.name[0] = '\0';
+				sensor_status = ENVMON_NOT_PRESENT;
+			} else if (index + 1 < section->num_entries)
+				env_sensor.next_id =
+				    section->entry[index + 1].handle_name;
+			else
+				env_sensor.next_id.name[0] = '\0';
+		}
+		if (sensor_status == ENVMON_SENSOR_OK) {
+			/*
+			 * user correctly identified a sensor, note its
+			 * handle value and request the sensor value
+			 */
+			rmc_temp.handle = section->entry[index].handle;
+		}
+		RELEASE_CACHE
+		if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
+		    rmclomv_do_cmd(DP_GET_TEMPERATURES, DP_GET_TEMPERATURES_R,
+		    sizeof (rmc_temp_r), (intptr_t)&rmc_temp,
+		    (intptr_t)&rmc_temp_r) != 0)) {
+			sensor_status = ENVMON_INACCESSIBLE;
+		}
+		if ((sensor_status == ENVMON_SENSOR_OK) &&
+		    (rmc_temp_r.temp_status[0].sensor_status ==
+		    DP_SENSOR_NOT_PRESENT)) {
+			sensor_status = ENVMON_NOT_PRESENT;
+		}
+		if ((env_sensor.sensor_status = sensor_status) ==
+		    ENVMON_SENSOR_OK) {
+			/*
+			 * copy results into buffer for user
+			 */
+			if (rmc_temp_r.temp_status[0].sensor_status !=
+			    DP_SENSOR_DATA_AVAILABLE)
+				env_sensor.sensor_status = ENVMON_INACCESSIBLE;
+			env_sensor.value =
+			    rmc_temp_r.temp_status[0].value;
+			env_sensor.lowthresholds.warning =
+			    rmc_temp_r.temp_status[0].low_warning;
+			env_sensor.lowthresholds.shutdown =
+			    rmc_temp_r.temp_status[0].low_soft_shutdown;
+			env_sensor.lowthresholds.poweroff =
+			    rmc_temp_r.temp_status[0].low_hard_shutdown;
+			env_sensor.highthresholds.warning =
+			    rmc_temp_r.temp_status[0].high_warning;
+			env_sensor.highthresholds.shutdown =
+			    rmc_temp_r.temp_status[0].high_soft_shutdown;
+			env_sensor.highthresholds.poweroff =
+			    rmc_temp_r.temp_status[0].high_hard_shutdown;
+		}
+		if (env_sensor.sensor_status != ENVMON_SENSOR_OK ||
+		    rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE)
+			set_val_unav(&env_sensor);
+
+		if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg,
+		    sizeof (envmon_sensor_t), mode) != 0)
+			return (EFAULT);
+		break;
+
+
+	case ENVMONIOCFAN:
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_fan,
+		    sizeof (envmon_fan_t), mode) != 0)
+			return (EFAULT);
+
+		/* see if we've got fan handles cached */
+		LOCK_CACHE
+		sensor_status = ENVMON_SENSOR_OK;
+
+		if ((rmclomv_cache_valid == B_FALSE) ||
+		    ((section = rmclomv_find_section(rmclomv_cache,
+		    RMCLOMV_FAN_SENS)) == NULL)) {
+			env_fan.next_id.name[0] = '\0';
+			sensor_status = ENVMON_NOT_PRESENT;
+		} else if (env_fan.id.name[0] == '\0') {
+			/* request for first handle */
+			if (section->num_entries == 0)
+				env_fan.next_id.name[0] = '\0';
+			else
+				env_fan.next_id =
+				    section->entry[0].handle_name;
+			sensor_status = ENVMON_NOT_PRESENT;
+		} else {
+			/* ensure name is properly terminated */
+			env_fan.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
+			if (get_sensor_by_name(section, env_fan.id.name,
+			    &index) != 0) {
+				env_fan.next_id.name[0] = '\0';
+				sensor_status = ENVMON_NOT_PRESENT;
+			} else if (index + 1 < section->num_entries)
+				env_fan.next_id =
+				    section->entry[index + 1].handle_name;
+			else
+				env_fan.next_id.name[0] = '\0';
+		}
+		if (sensor_status == ENVMON_SENSOR_OK) {
+			/*
+			 * user correctly identified a sensor, note its
+			 * handle value and request the sensor value
+			 */
+			rmc_fan.handle = section->entry[index].handle;
+		}
+		RELEASE_CACHE
+		if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
+		    rmclomv_do_cmd(DP_GET_FAN_STATUS, DP_GET_FAN_STATUS_R,
+		    sizeof (rmc_fan_r), (intptr_t)&rmc_fan,
+		    (intptr_t)&rmc_fan_r) != 0)) {
+			sensor_status = ENVMON_INACCESSIBLE;
+		}
+		if ((sensor_status == ENVMON_SENSOR_OK) &&
+		    (rmc_fan_r.fan_status[0].sensor_status ==
+		    DP_SENSOR_NOT_PRESENT)) {
+			sensor_status = ENVMON_NOT_PRESENT;
+		}
+		if ((env_fan.sensor_status = sensor_status) ==
+		    ENVMON_SENSOR_OK) {
+			if ((rmc_fan_r.fan_status[0].flag &
+			    DP_FAN_PRESENCE) == 0)
+				env_fan.sensor_status = ENVMON_NOT_PRESENT;
+			if (rmc_fan_r.fan_status[0].sensor_status !=
+			    DP_SENSOR_DATA_AVAILABLE)
+				env_fan.sensor_status |= ENVMON_INACCESSIBLE;
+			if (env_fan.sensor_status == ENVMON_SENSOR_OK) {
+				/*
+				 * copy results into buffer for user
+				 */
+				env_fan.speed =
+				    rmc_fan_r.fan_status[0].speed;
+				env_fan.lowthresholds.warning =
+				    rmc_fan_r.fan_status[0].minspeed;
+				env_fan.lowthresholds.shutdown =
+				    ENVMON_VAL_UNAVAILABLE;
+				env_fan.lowthresholds.poweroff =
+				    ENVMON_VAL_UNAVAILABLE;
+				if ((rmc_fan_r.fan_status[0].flag &
+				    DP_FAN_SPEED_VAL_UNIT) == 0)
+					bcopy(str_rpm, env_fan.units,
+					    sizeof (str_rpm));
+				else
+					bcopy(str_percent, env_fan.units,
+					    sizeof (str_percent));
+			}
+		}
+		if (env_fan.sensor_status != ENVMON_SENSOR_OK ||
+		    rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE)
+			set_fan_unav(&env_fan);
+
+		if (ddi_copyout((caddr_t)&env_fan, (caddr_t)arg,
+		    sizeof (envmon_fan_t), mode) != 0)
+			return (EFAULT);
+		break;
+
+	case ENVMONIOCAMPIND:
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ind,
+		    sizeof (envmon_indicator_t), mode) != 0)
+			return (EFAULT);
+
+		/* see if we've got amp indicator handles cached */
+		LOCK_CACHE
+		sensor_status = ENVMON_SENSOR_OK;
+
+		if ((rmclomv_cache_valid == B_FALSE) ||
+		    ((section = rmclomv_find_section(rmclomv_cache,
+		    RMCLOMV_AMP_IND)) == NULL)) {
+			RELEASE_CACHE
+			return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu,
+			    &rmc_psu_r, RMCLOMV_AMP_IND));
+		} else if (env_ind.id.name[0] == '\0') {
+			/* request for first handle */
+			if (section->num_entries == 0) {
+				RELEASE_CACHE
+				return (do_psu_cmd(arg, mode, &env_ind,
+				    &rmc_psu, &rmc_psu_r, RMCLOMV_AMP_IND));
+			}
+			env_ind.next_id = section->entry[0].handle_name;
+			sensor_status = ENVMON_NOT_PRESENT;
+		} else {
+			/* ensure name is properly terminated */
+			env_ind.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
+			if (get_sensor_by_name(section, env_ind.id.name,
+			    &index) != 0) {
+				RELEASE_CACHE
+				return (do_psu_cmd(arg, mode, &env_ind,
+				    &rmc_psu, &rmc_psu_r, RMCLOMV_AMP_IND));
+			}
+			if (index + 1 < section->num_entries) {
+				env_ind.next_id =
+				    section->entry[index + 1].handle_name;
+			} else {
+				rmclomv_cache_section_t	*sub_section =
+				    rmclomv_find_section(rmclomv_subcache,
+				    RMCLOMV_AMP_IND);
+				if ((sub_section == NULL) ||
+				    (sub_section->num_entries == 0))
+					env_ind.next_id.name[0] = '\0';
+				else
+					env_ind.next_id =
+					    sub_section->entry[0].handle_name;
+			}
+		}
+		if (sensor_status == ENVMON_SENSOR_OK) {
+			/*
+			 * user correctly identified an indicator, note its
+			 * handle value and request the indicator status
+			 */
+			rmc_ampi.handle = section->entry[index].handle;
+		}
+		RELEASE_CACHE
+		if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
+		    rmclomv_do_cmd(DP_GET_CIRCUIT_BRKS, DP_GET_CIRCUIT_BRKS_R,
+		    sizeof (rmc_ampi_r), (intptr_t)&rmc_ampi,
+		    (intptr_t)&rmc_ampi_r) != 0)) {
+			sensor_status = ENVMON_INACCESSIBLE;
+		}
+		if ((sensor_status == ENVMON_SENSOR_OK) &&
+		    (rmc_ampi_r.circuit_brk_status[0].sensor_status ==
+		    DP_SENSOR_NOT_PRESENT)) {
+			sensor_status = ENVMON_NOT_PRESENT;
+		}
+		if ((env_ind.sensor_status = sensor_status) ==
+		    ENVMON_SENSOR_OK) {
+			/*
+			 * copy results into buffer for user
+			 */
+			if (rmc_ampi_r.circuit_brk_status[0].sensor_status !=
+			    DP_SENSOR_DATA_AVAILABLE)
+				env_ind.sensor_status = ENVMON_INACCESSIBLE;
+			env_ind.condition =
+			    rmc_ampi_r.circuit_brk_status[0].status;
+		}
+
+		/*
+		 * If rmclomv_rmc_error is set there is no way
+		 * that we read information from RSC. Just copy
+		 * out an inaccessible evironmental.
+		 */
+		if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) {
+		    env_ind.sensor_status = ENVMON_INACCESSIBLE;
+		    env_ind.condition = ENVMON_INACCESSIBLE;
+		}
+
+		if (ddi_copyout((caddr_t)&env_ind, (caddr_t)arg,
+		    sizeof (envmon_indicator_t), mode) != 0)
+			return (EFAULT);
+		break;
+
+	case ENVMONIOCHPU:
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_hpu,
+		    sizeof (envmon_hpu_t), mode) != 0)
+			return (EFAULT);
+
+		/* see if we've got hpu handles cached */
+		LOCK_CACHE
+
+		if ((rmclomv_cache_valid == B_FALSE) ||
+		    ((section = rmclomv_find_section(rmclomv_cache,
+		    RMCLOMV_HPU_IND)) == NULL)) {
+			RELEASE_CACHE
+			return (EAGAIN);
+		}
+
+		/*
+		 * At this point the cache is locked and section points to
+		 * the section relating to hpus.
+		 */
+		sensor_status = ENVMON_SENSOR_OK;
+		if (env_hpu.id.name[0] == '\0') {
+			/* request for first handle */
+			if (section->num_entries == 0)
+				env_hpu.next_id.name[0] = '\0';
+			else
+				env_hpu.next_id =
+				    section->entry[0].handle_name;
+			sensor_status = ENVMON_NOT_PRESENT;
+		} else {
+			/* ensure name is properly terminated */
+			env_hpu.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
+			if (get_sensor_by_name(section, env_hpu.id.name,
+			    &index) != 0) {
+				env_hpu.next_id.name[0] = '\0';
+				sensor_status = ENVMON_NOT_PRESENT;
+			} else if (index + 1 < section->num_entries)
+				env_hpu.next_id =
+				    section->entry[index + 1].handle_name;
+			else
+				env_hpu.next_id.name[0] = '\0';
+		}
+		if (sensor_status == ENVMON_SENSOR_OK) {
+			/*
+			 * user correctly identified an hpu, note its
+			 * handle value and request the hpu status
+			 */
+			rmc_fru.handle = section->entry[index].handle;
+			special = section->entry[index].ind_mask;
+		}
+		RELEASE_CACHE
+		if ((env_hpu.sensor_status = sensor_status) ==
+		    ENVMON_SENSOR_OK) {
+			env_hpu.fru_status = ENVMON_FRU_PRESENT;
+
+			if (special != 0) {
+				/* this is the pseudo SC node */
+				mutex_enter(&rmclomv_state_lock);
+				switch (rmclomv_rmc_state) {
+				case RMCLOMV_RMCSTATE_OK:
+					break;
+				case RMCLOMV_RMCSTATE_FAILED:
+					env_hpu.fru_status = ENVMON_FRU_FAULT;
+					break;
+				case RMCLOMV_RMCSTATE_DOWNLOAD:
+					env_hpu.fru_status =
+					    ENVMON_FRU_DOWNLOAD;
+					break;
+				default:
+					env_hpu.sensor_status =
+					    ENVMON_INACCESSIBLE;
+					break;
+				}
+				mutex_exit(&rmclomv_state_lock);
+			} else if (rmclomv_rmc_error ||
+			    rmclomv_do_cmd(DP_GET_FRU_STATUS,
+			    DP_GET_FRU_STATUS_R, sizeof (rmc_fru_r),
+			    (intptr_t)&rmc_fru, (intptr_t)&rmc_fru_r) != 0) {
+				env_hpu.sensor_status = ENVMON_INACCESSIBLE;
+			} else {
+				/*
+				 * copy results into buffer for user
+				 */
+				if (rmc_fru_r.fru_status[0].presence == 0) {
+					env_hpu.sensor_status =
+					    ENVMON_NOT_PRESENT;
+					env_hpu.fru_status =
+					    ENVMON_FRU_NOT_PRESENT;
+				} else if (rmc_fru_r.fru_status[0].sensor_status
+				    != DP_SENSOR_DATA_AVAILABLE) {
+					env_hpu.sensor_status =
+					    ENVMON_INACCESSIBLE;
+				} else {
+					uint8_t status =
+					    rmc_fru_r.fru_status[0].status;
+					if (status == DP_FRU_STATUS_UNKNOWN) {
+						env_hpu.sensor_status =
+						    ENVMON_INACCESSIBLE;
+					} else if (status != DP_FRU_STATUS_OK) {
+						env_hpu.fru_status =
+						    ENVMON_FRU_FAULT;
+					}
+				}
+			}
+		}
+
+		/*
+		 * If rmclomv_rmc_error is set there is no way
+		 * that we read information from RSC. Just copy
+		 * out an inaccessible environmental.
+		 */
+		if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) {
+		    env_hpu.sensor_status = ENVMON_INACCESSIBLE;
+		    env_hpu.fru_status = ENVMON_INACCESSIBLE;
+		}
+
+		if (ddi_copyout((caddr_t)&env_hpu, (caddr_t)arg,
+		    sizeof (envmon_hpu_t), mode) != 0)
+			return (EFAULT);
+		break;
+
+	case ENVMONIOCGETLED:
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ledinfo,
+		    sizeof (envmon_led_info_t), mode) != 0)
+			return (EFAULT);
+
+		/* see if we've got LED handles cached */
+		LOCK_CACHE
+		sensor_status = ENVMON_SENSOR_OK;
+
+		if ((rmclomv_cache_valid == B_FALSE) ||
+		    ((section = rmclomv_find_section(rmclomv_cache,
+		    RMCLOMV_LED_IND)) == NULL)) {
+			env_ledinfo.next_id.name[0] = '\0';
+			sensor_status = ENVMON_NOT_PRESENT;
+		} else if (env_ledinfo.id.name[0] == '\0') {
+			/* request for first handle */
+			if (section->num_entries == 0)
+				env_ledinfo.next_id.name[0] = '\0';
+			else
+				env_ledinfo.next_id =
+				    section->entry[0].handle_name;
+			sensor_status = ENVMON_NOT_PRESENT;
+		} else {
+			/* ensure name is properly terminated */
+			env_ledinfo.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
+			if (get_sensor_by_name(section, env_ledinfo.id.name,
+			    &index) != 0) {
+				env_ledinfo.next_id.name[0] = '\0';
+				sensor_status = ENVMON_NOT_PRESENT;
+			} else if (index + 1 < section->num_entries)
+				env_ledinfo.next_id =
+				    section->entry[index + 1].handle_name;
+			else
+				env_ledinfo.next_id.name[0] = '\0';
+		}
+		if (sensor_status == ENVMON_SENSOR_OK) {
+			/*
+			 * user correctly identified a LED, note its
+			 * handle value and request the LED status
+			 */
+			rmc_led.handle = section->entry[index].handle;
+		}
+		RELEASE_CACHE
+		if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
+		    rmclomv_do_cmd(DP_GET_LED_STATE, DP_GET_LED_STATE_R,
+		    sizeof (rmc_led_r), (intptr_t)&rmc_led,
+		    (intptr_t)&rmc_led_r) != 0)) {
+			sensor_status = ENVMON_INACCESSIBLE;
+		}
+		if ((sensor_status == ENVMON_SENSOR_OK) &&
+		    (rmc_led_r.led_state[0].sensor_status ==
+		    DP_SENSOR_NOT_PRESENT)) {
+			sensor_status = ENVMON_NOT_PRESENT;
+		}
+		if ((env_ledinfo.sensor_status = sensor_status) ==
+		    ENVMON_SENSOR_OK) {
+			/*
+			 * copy results into buffer for user
+			 * start with some defaults then override
+			 */
+			env_ledinfo.sensor_status = ENVMON_SENSOR_OK;
+			env_ledinfo.led_state = ENVMON_LED_OFF;
+			env_ledinfo.led_color = ENVMON_LED_CLR_NONE;
+
+			if (rmc_led_r.led_state[0].sensor_status !=
+			    DP_SENSOR_DATA_AVAILABLE)
+				env_ledinfo.sensor_status = ENVMON_INACCESSIBLE;
+			else {
+				dp_led_state_t ledState;
+				ledState = rmc_led_r.led_state[0];
+				env_ledinfo.led_color = (int8_t)ledState.colour;
+
+				switch (ledState.state) {
+				case (rsci8)DP_LED_OFF:
+					break;
+				case (rsci8)DP_LED_ON:
+					env_ledinfo.led_state = ENVMON_LED_ON;
+					break;
+				case (rsci8)DP_LED_BLINKING:
+					env_ledinfo.led_state =
+					    ENVMON_LED_BLINKING;
+					break;
+				case (rsci8)DP_LED_FLASHING:
+					env_ledinfo.led_state =
+					    ENVMON_LED_FLASHING;
+					break;
+				default:
+					break;
+				}
+			}
+		}
+
+		/*
+		 * If rmclomv_rmc_error is set there is no way
+		 * that we read information from RSC. Just copy
+		 * out an inaccessible environmental.
+		 */
+		if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) {
+		    env_ledinfo.sensor_status = ENVMON_INACCESSIBLE;
+		    env_ledinfo.led_state = ENVMON_INACCESSIBLE;
+		}
+
+		if (ddi_copyout((caddr_t)&env_ledinfo, (caddr_t)arg,
+		    sizeof (envmon_led_info_t), mode) != 0)
+			return (EFAULT);
+		break;
+
+	case ENVMONIOCSETLED:
+		if ((mode & FWRITE) == 0)
+			return (EACCES);
+		if (drv_priv(cred_p) != 0)
+			return (EPERM);
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ledctl,
+		    sizeof (envmon_led_ctl_t), mode) != 0)
+			return (EFAULT);
+		if (env_ledctl.led_state < RMCLOMV_MIN_LED_STATE ||
+		    env_ledctl.led_state > RMCLOMV_MAX_LED_STATE)
+			return (EINVAL);
+		/*
+		 * Ensure name is properly terminated.
+		 */
+		env_ledctl.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
+
+		/* see if we've got LED handles cached */
+		LOCK_CACHE
+
+		if ((rmclomv_cache_valid == B_FALSE) ||
+		    ((section = rmclomv_find_section(rmclomv_cache,
+		    RMCLOMV_LED_IND)) == NULL) ||
+		    (get_sensor_by_name(section, env_ledctl.id.name,
+		    &index) != 0)) {
+			RELEASE_CACHE
+			return (EINVAL);	/* no such LED */
+		}
+		/*
+		 * user correctly identified a LED, note its handle value
+		 */
+		rmc_setled.handle = section->entry[index].handle;
+		RELEASE_CACHE
+		switch (env_ledctl.led_state) {
+		case ENVMON_LED_ON:
+			rmc_setled.state = DP_LED_ON;
+			break;
+		case ENVMON_LED_BLINKING:
+			rmc_setled.state = DP_LED_BLINKING;
+			break;
+		case ENVMON_LED_FLASHING:
+			rmc_setled.state = DP_LED_FLASHING;
+			break;
+		default:
+			rmc_setled.state = DP_LED_OFF;
+			break;
+		}
+		retval = rmclomv_do_cmd(DP_SET_LED_STATE, DP_SET_LED_STATE_R,
+		    sizeof (rmc_setled_r), (intptr_t)&rmc_setled,
+		    (intptr_t)&rmc_setled_r);
+
+		if (retval != 0) {
+			break;
+		}
+
+		if (rmc_setled_r.status != 0) {
+			cmn_err(CE_WARN, "ENVMONIOCSETLED: \"%s\" status: 0x%x",
+			    env_ledctl.id.name, rmc_setled_r.status);
+			return (EIO);
+		}
+		break;
+
+	case ENVMONIOCGETKEYSW:
+	{
+		enum rmc_keyswitch_pos	rmc_pos = real_key_position;
+		envmon_keysw_pos_t	envmon_pos;
+
+		/*
+		 * Yes, I know this is ugly, but the V210 has no keyswitch,
+		 * even though the ALOM returns a value for it
+		 */
+		if (strcmp(platform, "SUNW,Sun-Fire-V210") == 0) {
+			return (ENOTSUP);
+		}
+
+		switch (rmc_pos) {
+
+		case RMC_KEYSWITCH_POS_NORMAL:
+			envmon_pos = ENVMON_KEYSW_POS_NORMAL;
+			break;
+		case RMC_KEYSWITCH_POS_DIAG:
+			envmon_pos = ENVMON_KEYSW_POS_DIAG;
+			break;
+		case RMC_KEYSWITCH_POS_LOCKED:
+			envmon_pos = ENVMON_KEYSW_POS_LOCKED;
+			break;
+		case RMC_KEYSWITCH_POS_OFF:
+			envmon_pos = ENVMON_KEYSW_POS_OFF;
+			break;
+		default:
+			envmon_pos = ENVMON_KEYSW_POS_UNKNOWN;
+			break;
+		}
+
+		if (ddi_copyout((caddr_t)&envmon_pos, (caddr_t)arg,
+		    sizeof (envmon_pos), mode) != 0)
+			return (EFAULT);
+		break;
+	}
+
+	case ENVMONIOCGETALARM:
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_alarminfo,
+		    sizeof (envmon_alarm_info_t), mode) != 0)
+			return (EFAULT);
+
+		/* see if we've got ALARM handles cached */
+		LOCK_CACHE
+		sensor_status = ENVMON_SENSOR_OK;
+
+		if ((rmclomv_cache_valid == B_FALSE) ||
+		    ((section = rmclomv_find_section(rmclomv_cache,
+		    RMCLOMV_ALARM_IND)) == NULL)) {
+			env_alarminfo.next_id.name[0] = '\0';
+			sensor_status = ENVMON_NOT_PRESENT;
+		} else if (env_alarminfo.id.name[0] == '\0') {
+			/* request for first handle */
+			if (section->num_entries == 0)
+				env_alarminfo.next_id.name[0] = '\0';
+			else
+				env_alarminfo.next_id =
+				    section->entry[0].handle_name;
+			sensor_status = ENVMON_NOT_PRESENT;
+		} else {
+			/* ensure name is properly terminated */
+			env_alarminfo.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
+			if (get_sensor_by_name(section, env_alarminfo.id.name,
+			    &index) != 0) {
+				env_alarminfo.next_id.name[0] = '\0';
+				sensor_status = ENVMON_NOT_PRESENT;
+			} else if (index + 1 < section->num_entries)
+				env_alarminfo.next_id =
+				    section->entry[index + 1].handle_name;
+			else
+				env_alarminfo.next_id.name[0] = '\0';
+		}
+		if (sensor_status == ENVMON_SENSOR_OK) {
+			/*
+			 * user correctly identified a ALARM, note its
+			 * handle value and request the ALARM status
+			 */
+			rmc_alarm.handle = section->entry[index].handle;
+		}
+		RELEASE_CACHE
+		if ((sensor_status == ENVMON_SENSOR_OK) &&
+			(rmclomv_rmc_error ||
+		    rmclomv_do_cmd(DP_GET_ALARM_STATE, DP_GET_ALARM_STATE_R,
+		    sizeof (rmc_alarm_r), (intptr_t)&rmc_alarm,
+		    (intptr_t)&rmc_alarm_r) != 0)) {
+			sensor_status = ENVMON_INACCESSIBLE;
+		}
+		if ((env_alarminfo.sensor_status = sensor_status) ==
+		    ENVMON_SENSOR_OK) {
+			/*
+			 * copy results into buffer for user
+			 * start with some defaults then override
+			 */
+			env_alarminfo.sensor_status = ENVMON_SENSOR_OK;
+			env_alarminfo.alarm_state = ENVMON_ALARM_OFF;
+
+			if (rmc_alarm_r.alarm_state[0].sensor_status !=
+			    DP_SENSOR_DATA_AVAILABLE)
+				env_alarminfo.sensor_status =
+					ENVMON_INACCESSIBLE;
+			else {
+				dp_alarm_state_t alarmState;
+				alarmState = rmc_alarm_r.alarm_state[0];
+
+				switch (alarmState.state) {
+				case DP_ALARM_OFF:
+					break;
+				case DP_ALARM_ON:
+					env_alarminfo.alarm_state =
+						ENVMON_ALARM_ON;
+					break;
+				default:
+					break;
+				}
+			}
+		}
+
+		/*
+		 * If rmclomv_rmc_error is set there is no way
+		 * that we read information from RSC. Just copy
+		 * out an inaccessible environmental.
+		 */
+		if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) {
+		    env_alarminfo.sensor_status = ENVMON_INACCESSIBLE;
+		    env_alarminfo.alarm_state = ENVMON_INACCESSIBLE;
+		}
+
+		if (ddi_copyout((caddr_t)&env_alarminfo, (caddr_t)arg,
+		    sizeof (envmon_alarm_info_t), mode) != 0)
+			return (EFAULT);
+		break;
+
+	case ENVMONIOCSETALARM:
+		if ((mode & FWRITE) == 0)
+			return (EACCES);
+		if (drv_priv(cred_p) != 0)
+			return (EPERM);
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_alarmctl,
+		    sizeof (envmon_alarm_ctl_t), mode) != 0)
+			return (EFAULT);
+		if (env_alarmctl.alarm_state < RMCLOMV_MIN_ALARM_STATE ||
+		    env_alarmctl.alarm_state > RMCLOMV_MAX_ALARM_STATE)
+			return (EINVAL);
+		/*
+		 * Ensure name is properly terminated.
+		 */
+		env_alarmctl.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
+
+		/* see if we've got ALARM handles cached */
+		LOCK_CACHE
+
+		if ((rmclomv_cache_valid == B_FALSE) ||
+		    ((section = rmclomv_find_section(rmclomv_cache,
+		    RMCLOMV_ALARM_IND)) == NULL) ||
+		    (get_sensor_by_name(section, env_alarmctl.id.name,
+		    &index) != 0)) {
+			RELEASE_CACHE
+			return (EINVAL);	/* no such ALARM */
+		}
+		/*
+		 * user correctly identified a ALARM, note its handle value
+		 */
+		rmc_setalarm.handle = section->entry[index].handle;
+		RELEASE_CACHE
+		rmc_setalarm.state = (rsci8)env_alarmctl.alarm_state;
+		retval = rmclomv_do_cmd(DP_SET_ALARM_STATE,
+					DP_SET_ALARM_STATE_R,
+					sizeof (rmc_setalarm_r),
+					(intptr_t)&rmc_setalarm,
+					(intptr_t)&rmc_setalarm_r);
+
+		if (retval != 0) {
+			break;
+		}
+
+		if (rmc_setalarm_r.status != 0) {
+			cmn_err(CE_WARN, "ENVMONIOCSETALARM: \"%s\" status: "
+				"0x%x", env_alarmctl.id.name,
+				rmc_setalarm_r.status);
+			return (EIO);
+		}
+		break;
+
+	case ENVMONIOCCHASSISSERIALNUM:
+		retval = rmclomv_do_cmd(DP_GET_SDP_VERSION,
+		    DP_GET_SDP_VERSION_R, sizeof (rmc_sdpver_r),
+		    NULL, (intptr_t)&rmc_sdpver_r);
+
+		if (retval != 0) {
+			cmn_err(CE_WARN, "DP_GET_SDP_VERSION failed, ret=%d\n",
+			    retval);
+			break;
+		} else if (rmc_sdpver_r.version < SDP_RESPONDS_TO_ALL_CMDS) {
+			retval = ENOTSUP;
+			break;
+		}
+		retval = rmclomv_do_cmd(DP_GET_CHASSIS_SERIALNUM,
+		    DP_GET_CHASSIS_SERIALNUM_R, sizeof (rmc_serialnum_r),
+		    NULL, (intptr_t)&rmc_serialnum_r);
+
+		if (retval != 0) {
+			break;
+		}
+		bcopy(rmc_serialnum_r.chassis_serial_number,
+		    chassis.serial_number,
+		    sizeof (rmc_serialnum_r.chassis_serial_number));
+
+		if (ddi_copyout((caddr_t)&chassis, (caddr_t)arg,
+		    sizeof (chassis), mode) != 0) {
+			return (EFAULT);
+		}
+		sensor_status = ENVMON_SENSOR_OK;
+		break;
+
+	default:
+		retval = ENOTSUP;
+		break;
+	}
+
+	return (retval);
+}
+
+/* ARGSUSED */
+static void
+rmclomv_checkrmc(caddr_t arg)
+{
+	callb_cpr_t		cprinfo;
+	int			err;
+	int			retries;
+	int			state;
+	dp_get_sysinfo_r_t 	sysinfo;
+
+	CALLB_CPR_INIT(&cprinfo, &rmclomv_checkrmc_lock, callb_generic_cpr,
+	    "rmclomv_checkrmc");
+
+	mutex_enter(&rmclomv_checkrmc_lock);
+	for (;;) {
+		/*
+		 * Initial entry to this for loop is made with
+		 * rmclomv_checkrmc_sig set to RMCLOMV_PROCESS_NOW. So the
+		 * following while loop drops through the first time. A
+		 * timeout call is made just before polling the RMC. Its
+		 * interrupt routine sustains this loop by injecting additional
+		 * state changes and cv events.
+		 */
+		/*
+		 * Wait for someone to tell me to continue.
+		 */
+		while (rmclomv_checkrmc_sig == RMCLOMV_CHECKRMC_WAIT) {
+			CALLB_CPR_SAFE_BEGIN(&cprinfo);
+			cv_wait(&rmclomv_checkrmc_sig_cv,
+			    &rmclomv_checkrmc_lock);
+			CALLB_CPR_SAFE_END(&cprinfo, &rmclomv_checkrmc_lock);
+		}
+
+		mutex_exit(&rmclomv_checkrmc_lock);
+		/*
+		 * mustn't hold same lock as timeout called with
+		 * when cancelling timer
+		 */
+		if (timer_id != 0) {
+			(void) untimeout(timer_id);
+			timer_id = 0;
+		}
+		mutex_enter(&rmclomv_checkrmc_lock);
+
+		/* RMCLOMV_CHECKRMC_EXITNOW implies signal by _detach(). */
+		if (rmclomv_checkrmc_sig == RMCLOMV_CHECKRMC_EXITNOW) {
+			rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT;
+
+			/* rmclomv_checkrmc_lock is held at this point! */
+			CALLB_CPR_EXIT(&cprinfo);
+
+			thread_exit();
+			/* NOTREACHED */
+		}
+
+		rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT;
+
+		/*
+		 * If the RMC is not responding, rmclomv_do_cmd() takes a
+		 * long time and eventually times out. We conclude that the
+		 * RMC is broken if it doesn't respond to a number of polls
+		 * made 60 secs apart. So that the rmclomv_do_cmd() time-out
+		 * period isn't added to our 60 second timer, make the
+		 * timeout() call before calling rmclomv_do_cmd().
+		 */
+		if (timer_id == 0) {
+			timer_id = timeout(rmclomv_checkrmc_wakeup, NULL,
+			    60 * drv_usectohz(1000000));
+		}
+
+		mutex_exit(&rmclomv_checkrmc_lock);
+
+		err = rmclomv_do_cmd(DP_GET_SYSINFO, DP_GET_SYSINFO_R,
+		    sizeof (sysinfo), NULL, (intptr_t)&sysinfo);
+		if (err == 0) {
+			mutex_enter(&rmclomv_state_lock);
+			state = rmclomv_rmc_state;
+			/* successful poll, reset fail count */
+			rmclomv_rmcfailcount = 0;
+			mutex_exit(&rmclomv_state_lock);
+
+			if (state != RMCLOMV_RMCSTATE_OK) {
+				rmclomv_refresh_wakeup();
+			}
+		}
+		if ((err != 0) &&
+		    (rmclomv_rmc_error != RMCLOMV_RMCSTATE_DOWNLOAD)) {
+			/*
+			 * Failed response or no response from RMC.
+			 * Count the failure.
+			 * If threshold exceeded, send a DR event.
+			 */
+			mutex_enter(&rmclomv_state_lock);
+			retries = rmclomv_rmcfailcount;
+			state = rmclomv_rmc_state;
+			if (retries == RMCLOMV_RMCFAILTHRESHOLD)
+				rmclomv_rmc_state = RMCLOMV_RMCSTATE_FAILED;
+			if (rmclomv_rmcfailcount <= RMCLOMV_RMCFAILTHRESHOLD)
+				rmclomv_rmcfailcount++;
+			mutex_exit(&rmclomv_state_lock);
+
+			if (retries == RMCLOMV_RMCFAILTHRESHOLD) {
+				cmn_err(CE_WARN, "SC %s responding",
+				    state == RMCLOMV_RMCSTATE_OK ?
+				    "has stopped" : "is not");
+				refresh_name_cache(B_TRUE);
+				rmclomv_dr_data_handler(str_sc, SE_NO_HINT);
+			}
+		}
+
+		/*
+		 * Re-enter the lock to prepare for another iteration.
+		 * We must have the lock here to protect rmclomv_checkrmc_sig.
+		 */
+		mutex_enter(&rmclomv_checkrmc_lock);
+	}
+}
+
+static void
+rmclomv_checkrmc_start(void)
+{
+	kthread_t *tp;
+
+	mutex_enter(&rmclomv_checkrmc_lock);
+
+	if (rmclomv_checkrmc_tid == 0) {
+		rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_PROCESSNOW;
+
+		tp = thread_create(NULL, 0, rmclomv_checkrmc, NULL, 0,
+		    &p0, TS_RUN, maxclsyspri);
+		rmclomv_checkrmc_tid = tp->t_did;
+	}
+
+	mutex_exit(&rmclomv_checkrmc_lock);
+}
+
+static void
+rmclomv_checkrmc_destroy(void)
+{
+	kt_did_t tid;
+
+	mutex_enter(&rmclomv_checkrmc_lock);
+	tid = rmclomv_checkrmc_tid;
+	if (tid != 0) {
+		rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_EXITNOW;
+		cv_signal(&rmclomv_checkrmc_sig_cv);
+		rmclomv_checkrmc_tid = 0;
+	}
+	mutex_exit(&rmclomv_checkrmc_lock);
+
+	/*
+	 * Wait for rmclomv_checkrmc() to finish
+	 */
+	if (tid != 0)
+		thread_join(tid);
+}
+
+/*ARGSUSED*/
+static void
+rmclomv_checkrmc_wakeup(void *arg)
+{
+	mutex_enter(&rmclomv_checkrmc_lock);
+
+	if (rmclomv_checkrmc_sig != RMCLOMV_CHECKRMC_EXITNOW)
+		rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_PROCESSNOW;
+	cv_signal(&rmclomv_checkrmc_sig_cv);
+
+	mutex_exit(&rmclomv_checkrmc_lock);
+}
+
+/* ARGSUSED */
+static void
+rmclomv_refresh(caddr_t arg)
+{
+	void			(*plat_nodename_set_fun)(void);
+	sig_state_t		*current_sgn_p;
+	callb_cpr_t		cprinfo;
+	int			state;
+
+	CALLB_CPR_INIT(&cprinfo, &rmclomv_refresh_lock, callb_generic_cpr,
+	    "rmclomv_refresh");
+
+	delay(drv_usectohz(5000000));
+	mutex_enter(&rmclomv_refresh_lock);
+	for (;;) {
+
+		/*
+		 * Wait for someone to tell me to continue.
+		 */
+		while (rmclomv_refresh_sig == RMCLOMV_REFRESH_WAIT) {
+			CALLB_CPR_SAFE_BEGIN(&cprinfo);
+			cv_wait(&rmclomv_refresh_sig_cv, &rmclomv_refresh_lock);
+			CALLB_CPR_SAFE_END(&cprinfo, &rmclomv_refresh_lock);
+		}
+
+		/* RMCLOMV_REFRESH_EXITNOW implies signal by _detach(). */
+		if (rmclomv_refresh_sig == RMCLOMV_REFRESH_EXITNOW) {
+			rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT;
+
+			/* rmclomv_refresh_lock is held at this point! */
+			CALLB_CPR_EXIT(&cprinfo);
+
+			thread_exit();
+			/* NOTREACHED */
+		}
+
+		ASSERT(rmclomv_refresh_sig == RMCLOMV_REFRESH_PROCESSNOW);
+		rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT;
+
+		mutex_exit(&rmclomv_refresh_lock);
+
+		refresh_name_cache(B_FALSE);
+
+		/*
+		 * We're not going to access rmclomv_sysinfo_data here,
+		 * so there's no point in locking it before reading
+		 * rmclomv_sysinfo_valid. Also this avoids holding two
+		 * locks at once and the concommitant worry about deadlocks.
+		 */
+		if (rmclomv_sysinfo_valid) {
+			/*
+			 * We've just successfully read the RMC sysinfo
+			 * so the RMC must be operational. Update its
+			 * state and if it was previously not OK, refresh
+			 * nodename, CPU signatures and watchdog settings.
+			 */
+			mutex_enter(&rmclomv_state_lock);
+			rmclomv_rmcfailcount = 0;
+			state = rmclomv_rmc_state;
+			rmclomv_rmc_state = RMCLOMV_RMCSTATE_OK;
+			mutex_exit(&rmclomv_state_lock);
+
+			if (state != RMCLOMV_RMCSTATE_OK) {
+				rmclomv_dr_data_handler(str_sc, SE_NO_HINT);
+				if (state == RMCLOMV_RMCSTATE_FAILED) {
+					cmn_err(CE_NOTE, "SC recovered");
+				}
+			}
+
+			if (utsname.nodename[0] != 0) {
+				plat_nodename_set_fun =
+				    (void (*)(void))modgetsymvalue(
+				    "plat_nodename_set", 0);
+				if (plat_nodename_set_fun != NULL)
+					plat_nodename_set_fun();
+			}
+
+			current_sgn_p = (sig_state_t *)modgetsymvalue(
+			    "current_sgn", 0);
+
+			if ((current_sgn_p != NULL) &&
+			    (current_sgn_p->state_t.sig != 0)) {
+				CPU_SIGNATURE(current_sgn_p->state_t.sig,
+				    current_sgn_p->state_t.state,
+				    current_sgn_p->state_t.sub_state, -1);
+
+				if (!(boothowto & RB_DEBUG)) {
+					send_watchdog_msg(last_watchdog_msg);
+				}
+			}
+		}
+
+		/*
+		 * update keyswitch value in case it changed while the
+		 * RMC was out of action
+		 */
+		LOCK_CACHE
+		if (rmclomv_sysinfo_valid) {
+			real_key_position = rmclomv_sysinfo_data.keyswitch;
+			if ((real_key_position != RMC_KEYSWITCH_POS_UNKNOWN) &&
+			    (real_key_position <= RMC_KEYSWITCH_POS_OFF)) {
+				key_position = real_key_position;
+			} else {
+				/* treat unknown key position as locked */
+				key_position = RMC_KEYSWITCH_POS_LOCKED;
+			}
+		} else {
+			/* treat unreadable key position as locked */
+			key_position = RMC_KEYSWITCH_POS_LOCKED;
+			real_key_position = RMC_KEYSWITCH_POS_UNKNOWN;
+		}
+		RELEASE_CACHE
+
+		/*
+		 * Re-enter the lock to prepare for another iteration.
+		 * We must have the lock here to protect rmclomv_refresh_sig.
+		 */
+		mutex_enter(&rmclomv_refresh_lock);
+	}
+}
+
+static void
+rmclomv_refresh_start(void)
+{
+	kthread_t *tp;
+
+	mutex_enter(&rmclomv_refresh_lock);
+
+	if (rmclomv_refresh_tid == 0) {
+		rmclomv_refresh_sig = RMCLOMV_REFRESH_PROCESSNOW;
+
+		tp = thread_create(NULL, 0, rmclomv_refresh, NULL, 0,
+		    &p0, TS_RUN, maxclsyspri);
+		rmclomv_refresh_tid = tp->t_did;
+	}
+
+	mutex_exit(&rmclomv_refresh_lock);
+}
+
+static void
+rmclomv_refresh_destroy(void)
+{
+	kt_did_t tid;
+
+	mutex_enter(&rmclomv_refresh_lock);
+	tid = rmclomv_refresh_tid;
+	if (tid != 0) {
+		rmclomv_refresh_sig = RMCLOMV_REFRESH_EXITNOW;
+		cv_signal(&rmclomv_refresh_sig_cv);
+		rmclomv_refresh_tid = 0;
+	}
+	mutex_exit(&rmclomv_refresh_lock);
+
+	/*
+	 * Wait for rmclomv_refresh() to finish
+	 */
+	if (tid != 0)
+		thread_join(tid);
+}
+
+static void
+rmclomv_refresh_wakeup(void)
+{
+	mutex_enter(&rmclomv_refresh_lock);
+
+	if (rmclomv_refresh_sig != RMCLOMV_REFRESH_EXITNOW)
+		rmclomv_refresh_sig = RMCLOMV_REFRESH_PROCESSNOW;
+	cv_signal(&rmclomv_refresh_sig_cv);
+
+	mutex_exit(&rmclomv_refresh_lock);
+}
+
+static void
+send_watchdog_msg(int msg)
+{
+	rmc_comm_msg_t request;
+	dp_set_host_watchdog_t watchdog_msg;
+
+	if (rmclomv_watchdog_mode)
+		return;
+
+	watchdog_msg.enable = msg;
+	request.msg_type = DP_SET_HOST_WATCHDOG;
+	request.msg_len = sizeof (watchdog_msg);
+	request.msg_buf = (caddr_t)&watchdog_msg;
+	(void) rmc_comm_request_nowait(&request, (msg == 1) ?
+	    RMC_COMM_DREQ_URGENT : 0);
+}
+
+/*ARGSUSED*/
+static uint_t
+rmc_set_watchdog_timer(uint_t timeoutval)
+{
+	ASSERT(MUTEX_HELD(&tod_lock));
+
+	if ((watchdog_enable == 0) || (watchdog_available == 0)) {
+		return (0);
+	}
+
+	/*
+	 * If boothowto has RB_DEBUG set we never want to set the watchdog
+	 * support on.
+	 */
+	if (boothowto & RB_DEBUG) {
+		return (0);
+	}
+
+	/*
+	 * When the watchdog is shut off last_watchdog_msg goes from a
+	 * 0 to a 1. So we must test to see that last_watchdog_msg is
+	 * set to 1 indicating that watchdog was shut off and
+	 * After which we set last_watchdog_msg back to 0 so that we do not
+	 * run this code
+	 * again.
+	 */
+	if (last_watchdog_msg == 1) {
+		send_watchdog_msg(0);
+		last_watchdog_msg = 0;
+	}
+
+	pmugpio_watchdog_pat();
+
+	watchdog_activated = 1;
+
+	return (1);
+}
+
+static uint_t
+rmc_clear_watchdog_timer(void)
+{
+	ASSERT(MUTEX_HELD(&tod_lock));
+	if ((watchdog_activated == 0) || (boothowto & RB_DEBUG))
+		return (0);
+
+	send_watchdog_msg(1);
+	last_watchdog_msg = 1;
+	watchdog_activated = 0;
+
+	return (0);
+}
+
+static void
+plat_timesync(void *arg)
+{
+	timestruc_t now;
+	todinfo_t tod;
+	rmc_comm_msg_t request;
+	dp_set_date_time_t set_time_msg;
+	int retval;
+	timestruc_t ts;
+	dp_get_date_time_r_t *date_and_time_info;
+	int buffer[DATE_TIME_MSG_SIZE];
+
+	/* Is the system coming up? */
+	if (arg != NULL) {
+		/* Request the time from the RMC clock. */
+		retval = rmclomv_do_cmd(DP_GET_DATE_TIME, DP_GET_DATE_TIME_R,
+		    DATE_TIME_MSG_SIZE, NULL, (intptr_t)&buffer);
+
+		/*
+		 * If we were able to get the time lets set the local clock.
+		 * The time returned from RMC is in Unix time format.
+		 *
+		 * If we couldn't get the time we'll accept the drift so as not
+		 * to cause congestion on the I2C bus or cause boot
+		 * performance regressions.
+		 */
+		if (retval == RCNOERR) {
+			date_and_time_info = (dp_get_date_time_r_t *)buffer;
+			ts.tv_sec = date_and_time_info->current_datetime;
+			ts.tv_nsec = 0;
+			mutex_enter(&tod_lock);
+			tod_set(ts);
+			set_hrestime(&ts);
+			mutex_exit(&tod_lock);
+		}
+	}
+
+	gethrestime(&now);
+	mutex_enter(&tod_lock);
+	tod = utc_to_tod(now.tv_sec);
+	mutex_exit(&tod_lock);
+
+	set_time_msg.year	= tod.tod_year;
+	set_time_msg.month	= tod.tod_month - 1;
+	set_time_msg.day	= tod.tod_day;
+	set_time_msg.hour	= tod.tod_hour;
+	set_time_msg.minute	= tod.tod_min;
+	set_time_msg.second	= tod.tod_sec;
+
+	request.msg_type = DP_SET_DATE_TIME;
+	request.msg_len = sizeof (set_time_msg);
+	request.msg_buf = (caddr_t)&set_time_msg;
+
+	(void) rmc_comm_request_nowait(&request, 0);
+
+	(void) timeout(plat_timesync, NULL, timesync_interval);
+}
+
+/*
+ * Interfaces to get/set alarm relays from outside
+ */
+int
+rmclomv_alarm_get(int alarm_type, int *alarm_state)
+{
+	rmclomv_cache_section_t	*section;
+	int			index;
+	uint16_t		sensor_status;
+	dp_get_alarm_state_t	u_rmc_alarm;
+	dp_get_alarm_state_r_t	u_rmc_alarm_r;
+
+	/* see if we've got ALARM handles cached */
+	LOCK_CACHE
+	sensor_status = ENVMON_SENSOR_OK;
+
+	if ((rmclomv_cache_valid == B_FALSE) ||
+		((section = rmclomv_find_section(rmclomv_cache,
+		RMCLOMV_ALARM_IND)) == NULL)) {
+		sensor_status = ENVMON_NOT_PRESENT;
+	}
+	if (sensor_status == ENVMON_SENSOR_OK) {
+		/*
+		 * user correctly identified a ALARM, note its
+		 * handle value and request the ALARM status
+		 */
+		index = alarm_type;
+		if (index >= section->num_entries)
+			sensor_status = ENVMON_INACCESSIBLE;
+		else
+			u_rmc_alarm.handle = section->entry[index].handle;
+	}
+	RELEASE_CACHE
+	if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
+		rmclomv_do_cmd(DP_GET_ALARM_STATE, DP_GET_ALARM_STATE_R,
+		sizeof (u_rmc_alarm_r), (intptr_t)&u_rmc_alarm,
+		(intptr_t)&u_rmc_alarm_r) != 0)) {
+		sensor_status = ENVMON_INACCESSIBLE;
+	}
+	if (sensor_status == ENVMON_SENSOR_OK) {
+		/*
+		 * copy results into buffer for user
+		 * start with some defaults then override
+		 */
+		*alarm_state = 0;
+
+		if (u_rmc_alarm_r.alarm_state[0].sensor_status !=
+			DP_SENSOR_DATA_AVAILABLE)
+			return (ENXIO);
+		else {
+			dp_alarm_state_t alarmState;
+			alarmState = u_rmc_alarm_r.alarm_state[0];
+
+			switch (alarmState.state) {
+			case DP_ALARM_OFF:
+				break;
+			case DP_ALARM_ON:
+				*alarm_state = 1;
+				break;
+			default:
+				break;
+			}
+		}
+	} else
+		return (ENXIO);
+
+	return (0);
+}
+
+int
+rmclomv_alarm_set(int alarm_type, int new_state)
+{
+	rmclomv_cache_section_t	*section;
+	int			index;
+	uint16_t		sensor_status;
+	dp_set_alarm_state_t	u_rmc_setalarm;
+	dp_set_alarm_state_r_t	u_rmc_setalarm_r;
+
+	/* see if we've got ALARM handles cached */
+	LOCK_CACHE
+	sensor_status = ENVMON_SENSOR_OK;
+
+	if ((rmclomv_cache_valid == B_FALSE) ||
+		((section = rmclomv_find_section(rmclomv_cache,
+		RMCLOMV_ALARM_IND)) == NULL)) {
+		sensor_status = ENVMON_NOT_PRESENT;
+	}
+	if (sensor_status == ENVMON_SENSOR_OK) {
+		/*
+		 * user correctly identified a ALARM, note its
+		 * handle value and request the ALARM status
+		 */
+		index = alarm_type;
+		if (index >= section->num_entries)
+			sensor_status = ENVMON_INACCESSIBLE;
+		else {
+			u_rmc_setalarm.handle = section->entry[index].handle;
+			u_rmc_setalarm.state = new_state;
+		}
+	}
+	RELEASE_CACHE
+	if ((sensor_status == ENVMON_SENSOR_OK) &&
+		(rmclomv_rmc_error ||
+		rmclomv_do_cmd(DP_SET_ALARM_STATE, DP_SET_ALARM_STATE_R,
+		sizeof (u_rmc_setalarm_r), (intptr_t)&u_rmc_setalarm,
+		(intptr_t)&u_rmc_setalarm_r) != 0)) {
+		sensor_status = ENVMON_INACCESSIBLE;
+	}
+
+	if (u_rmc_setalarm_r.status != DP_SET_ALARM_OK) {
+		return (EIO);
+	}
+
+	if (sensor_status != ENVMON_SENSOR_OK) {
+		return (ENXIO);
+	}
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/io/rmclomv.conf	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,28 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+name="rmclomv" parent="pseudo" instance=0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/io/wrsmd.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,7922 @@
+/*
+ * 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 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * DLPI driver for RSMPI
+ *
+ * Based on scid.c 1.39 98/10/28 - from the SCI group/Sun Cluster code base.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/debug.h>
+#include <sys/stropts.h>
+#include <sys/stream.h>
+#include <sys/strlog.h>
+#include <sys/cmn_err.h>
+#include <sys/kmem.h>
+#include <sys/conf.h>
+#include <sys/ksynch.h>
+#include <sys/stat.h>
+#include <sys/dlpi.h>
+#include <sys/modctl.h>
+#include <sys/kstat.h>
+#include <sys/note.h>
+#include <sys/disp.h>
+#include <sys/callb.h>
+
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/strsun.h>
+
+#include <sys/rsm/rsm_common.h>
+#include <sys/rsm/rsmpi.h>
+
+
+#include <sys/tnf_probe.h>
+
+#ifdef DEBUG
+#define	DEBUG_WRSMD 1
+#define	DEBUG_PRINTF 1
+#define	DEBUG_LOG 1
+#endif
+
+
+#include <sys/wrsmd.h>			/* This driver's data structures */
+#define	WRSM_NAME "wrsm"
+
+/*
+ * Lock hierarchy:
+ *
+ * ssp->ss_lock
+ * wrsmdp->wrsmd_lock
+ * wrsmddevlock
+ *
+ *	rd->rd_lock
+ *	rd->rd_xmit_lock
+ *	rd->rd_net_lock
+ *
+ *	wrsmd->wrsmd_dest_lock
+ *	wrsmd->wrsmd_runq_lock
+ *
+ * wrsmdp->wrsmd_ipq_rwlock
+ * wrsmdp->event_lock;
+ * wrsmdstruplock
+ * rd->rd_nlb_lock -- currently never taken while another lock is held
+ * wrsmdattlock
+ * wrsmddbglock
+ */
+
+
+/*
+ * Defining DEBUG_WRSMD on the compile line (-DDEBUG_WRSMD) will compile
+ * debugging code into the driver.  Whether any debug output actually gets
+ * printed depends on the value of wrsmddbg, which determines the class of
+ * messages that the user is interested in, and wrsmddbgmode, which
+ * determines how the user wants the messages to be produced.
+ *
+ * See the #defines for D1(), D2(), etc.  below for which bits in wrsmddbg
+ * cause which messages to get printed.
+ *
+ * There are two ways debug output may be produced.  The code to produce
+ * these various types is also conditionally compiled, using the following
+ * symbols:
+ *
+ * DEBUG_LOG		If this is defined, support for an internal circular
+ * 			buffer of log entries is compiled in. The buffer may
+ *			be dumped out by using the wrsmddumplog utility.
+ *			This is currently the preferred trace method.
+ *
+ * DEBUG_PRINTF		If this is defined, support for kernel debug printfs
+ *			is compiled in.  In many cases, this is not very
+ *			useful since the sheer volume of tracing information
+ *			overwhelms the console driver.  In particular, if a
+ *			problem causes a panic, you will very often not see
+ *			the last few debugging messages produced before the
+ *			panic, which are probably the ones you really wanted
+ *			to see.
+ *
+ * The various types of output are controlled by bits in wrsmddbgmode, as
+ * follows.  Multiple types of output may be used at once, if desired.
+ *
+ * (wrsmddbgmode & 1)	Use debugging log.
+ * (wrsmddbgmode & 2)	Use kernel printfs.
+ */
+
+#ifndef lint
+
+#ifdef DEBUG_WRSMD
+
+int wrsmddbg = 0x100;
+int wrsmddbgmode = 0x3;
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmddbg))
+
+/* Always print -- at least for now */
+#define	D0	wrsmddebug
+
+
+/* wrsmd function enter/exit, parameters, return values. */
+#define	D1								\
+	_NOTE(CONSTCOND)						\
+	if (wrsmddbg & 0x01)						\
+	    wrsmddebug
+
+/* Additional function debugging. */
+#define	D2								\
+	_NOTE(CONSTCOND)						\
+	if (wrsmddbg & 0x02) 						\
+	    wrsmddebug
+
+/* rsmpi interface routine enter/exit, parameters, return */
+#define	D4								\
+	_NOTE(CONSTCOND)						\
+	if (wrsmddbg & 0x08) 						\
+	    wrsmddebug
+
+/* Latency timing output. */
+#define	D5								\
+	_NOTE(CONSTCOND)						\
+	if (wrsmddbg & 0x10) 						\
+	    wrsmddebug
+
+/* Excessive debugging output */
+#define	D6								\
+	_NOTE(CONSTCOND)						\
+	if (wrsmddbg & 0x20) 						\
+	    wrsmddebug
+
+/* outgoing packet tossed due to queue overflow */
+#define	DERR								\
+	_NOTE(CONSTCOND)						\
+	if (wrsmddbg & 0x100) 						\
+	    wrsmddebug
+
+/* Dumps of incoming packets */
+#define	D3D								\
+	_NOTE(CONSTCOND)						\
+	if (wrsmddbg & 0x04) wrsmdump
+
+#else /* DEBUG_WRSMD */
+
+#define	D0	if (0) printf
+#define	D1	if (0) printf
+#define	D2	if (0) printf
+#define	D4	if (0) printf
+#define	D5	if (0) printf
+#define	D6	if (0) printf
+#define	DERR	if (0) printf
+#define	D3D(a, b)
+
+#endif /* DEBUG_WRSMD */
+
+#else /* lint */
+
+#ifdef DEBUG_WRSMD
+int wrsmddbg;
+int wrsmddbgmode;
+#endif
+
+#define	D0	printf
+#define	D1	printf
+#define	D2	printf
+#define	D4	printf
+#define	D5	printf
+#define	D6	printf
+#define	DERR	printf
+#define	D3D	wrsmdump
+#endif /* lint */
+
+
+
+/*
+ * Function prototypes.
+ */
+
+static int	wrsmdprobe(dev_info_t *);
+static int	wrsmdattach(dev_info_t *, ddi_attach_cmd_t);
+static int	wrsmddetach(dev_info_t *, ddi_detach_cmd_t);
+static int	wrsmdopen(queue_t *, dev_t *, int, int, cred_t *);
+static int	wrsmdclose(queue_t *, int, cred_t *);
+static int	wrsmdwput(queue_t *, mblk_t *);
+static int	wrsmdwsrv(queue_t *);
+static void	wrsmddumpqueue(wrsmd_t *, wrsmd_dest_t *);
+static int	wrsmdcrexfer(wrsmd_t *, wrsmd_dest_t *);
+static int	wrsmdsconn(wrsmd_t *, wrsmd_dest_t *, int);
+static int	wrsmdconnxfer(wrsmd_t *, wrsmd_dest_t *);
+static int	wrsmdsack(wrsmd_t *, wrsmd_dest_t *);
+static int	wrsmdsaccept(wrsmd_t *wrsmdp, wrsmd_dest_t *rd);
+static void	wrsmdproto(queue_t *, mblk_t *);
+static void	wrsmdioctl(queue_t *, mblk_t *);
+static int	wrsmdioctlimmediate(queue_t *, mblk_t *);
+static void	wrsmd_dl_ioc_hdr_info(queue_t *, mblk_t *);
+static void	wrsmdareq(queue_t *, mblk_t *);
+static void	wrsmddreq(queue_t *, mblk_t *);
+static void	wrsmddodetach(wrsmdstr_t *);
+static void	wrsmdbreq(queue_t *, mblk_t *);
+static void	wrsmdubreq(queue_t *, mblk_t *);
+static void	wrsmdireq(queue_t *, mblk_t *);
+static void	wrsmdponreq(queue_t *, mblk_t *);
+static void	wrsmdpoffreq(queue_t *, mblk_t *);
+static void	wrsmdpareq(queue_t *, mblk_t *);
+static void	wrsmdudreq(queue_t *, mblk_t *);
+static mblk_t	*wrsmdstrip(mblk_t *, dl_rsm_addr_t *, ushort_t *);
+static void	wrsmdstart(wrsmd_t *, mblk_t *, dl_rsm_addr_t, ushort_t, int);
+static wrsmd_dest_t *wrsmdmkdest(wrsmd_t *, rsm_addr_t);
+static void	wrsmdsetupfqewait(wrsmd_t *, wrsmd_dest_t *);
+static void	wrsmdxfer(wrsmd_t *, wrsmd_dest_t *);
+static void	wrsmdfqetmo(void *);
+static void	wrsmdsconntmo(void *);
+static void	wrsmdacktmo(void *);
+static void	wrsmdaccepttmo(void * arg);
+static void	wrsmdfreedestevt(void *);
+static void	wrsmdteardown_tmo(void * arg);
+
+static void	wrsmd_event_thread(void *);
+static void	wrsmd_process_event(wrsmd_t *);
+static void	wrsmd_add_event(wrsmd_t *, int, void *);
+
+static void	wrsmdmsghdlr_req_connect(wrsmd_dest_t *, wrsmd_msg_t *);
+static void	wrsmdmsghdlr_con_accept(wrsmd_dest_t *, wrsmd_msg_t *);
+static void	wrsmdmsghdlr_syncdqe(wrsmd_dest_t *, wrsmd_msg_t *);
+static void 	wrsmdmsghdlr_syncdqe_evt(wrsmd_dest_t *rd);
+static void	wrsmdmsghdlr_default(wrsmd_dest_t *, wrsmd_msg_t *);
+
+static int	wrsmdisstate(wrsmd_dest_t *, int);
+static int	wrsmdgetstate(wrsmd_dest_t *);
+static void	wrsmdsetstate(wrsmd_dest_t *, int);
+static void	wrsmdsetstate_nosrv(wrsmd_dest_t *, int);
+static int	wrsmdmovestate(wrsmd_dest_t *, int, int newstate);
+static int	wrsmdread(wrsmd_dest_t *, int, int, int, ushort_t sap);
+static void	wrsmdsendup(wrsmd_t *, mblk_t *, dl_rsm_addr_t, dl_rsm_addr_t,
+    ushort_t);
+static void	wrsmdpromsendup(wrsmd_t *, mblk_t *, dl_rsm_addr_t,
+    dl_rsm_addr_t, ushort_t);
+static mblk_t	*wrsmdaddudind(wrsmd_t *, mblk_t *, dl_rsm_addr_t,
+    dl_rsm_addr_t, ushort_t);
+static mblk_t	*wrsmdaddhdr(wrsmd_t *, mblk_t *, dl_rsm_addr_t, dl_rsm_addr_t,
+    ushort_t);
+static int	wrsmdinit(wrsmd_t *);
+static int	wrsmduninit(wrsmd_t *wrsmdp);
+static boolean_t	wrsmddest_refcnt_0(wrsmd_dest_t *);
+static void	wrsmdfreedest(wrsmd_t *, rsm_addr_t);
+
+/* LINTED: E_STATIC_FUNC_CALLD_NOT_DEFINED */
+static void	wrsmddebug(const char *, ...);
+static void	wrsmderror(dev_info_t *,  const char *, ...);
+static void	wrsmdkstatinit(wrsmd_t *);
+static void	wrsmdkstatremove(wrsmd_t *wrsmdp);
+static void	wrsmdgetparam(dev_info_t *, wrsmd_t *);
+static void	wrsmdtakedown(wrsmd_t *, int);
+static void	wrsmdsetipq(wrsmd_t *);
+
+static void	wrsmdfreebuf(wrsmdbuf_t *);
+static void	wrsmdputfqe(wrsmd_dest_t *, int);
+static void	wrsmdsyncfqe(wrsmd_dest_t *);
+static void	wrsmdputdqe(wrsmd_dest_t *, int, int, uint_t, ushort_t sap);
+static void	wrsmdsyncdqe(wrsmd_dest_t *);
+static int	wrsmdavailfqe(wrsmd_dest_t *);
+static int	wrsmdgetfqe(wrsmd_dest_t *, int *);
+static void	wrsmdungetfqe(wrsmd_dest_t *, int);
+static int	wrsmdgetdqe(wrsmd_dest_t *, int *, int *, int *, ushort_t *);
+static int	wrsmdsendmsg(wrsmd_dest_t *, uint8_t, wrsmd_msg_t *);
+/* LINTED: E_STATIC_FUNC_CALLD_NOT_DEFINED */
+static void	wrsmdump(uchar_t *, int);
+
+static rsm_intr_hand_ret_t wrsmd_rsm_intr_handler(rsm_controller_object_t *,
+    rsm_intr_q_op_t, rsm_addr_t, void *, size_t, rsm_intr_hand_arg_t);
+
+
+#ifdef	_DDICT
+#define	ENOSR	63	/* out of streams resources		*/
+#endif
+
+
+/*
+ * The wrsmd driver implements a reference count scheme for destination
+ * structures.  The idea behind the scheme is to prevent the driver from
+ * deleting a destination structure while it is being used elsewhere, for
+ * example in a message handling routine.  (Failures to protect against
+ * this occurrence have led to a fair array of baffling bugs over the
+ * lifetime of the driver.)
+ *
+ * The following set of macros implement the reference count scheme,
+ * translation from RSM address to destination structure, and removal of
+ * destinations from the run queue.  All must be intertwined, since
+ * otherwise it would be possible to get a destination pointer from an RSM
+ * address , or from the run queue, but have some other part of the driver
+ * delete the destination before you could bump its reference count.  The
+ * incorporation of reference count code in FINDDEST/MAKEDEST/GETRUNQ
+ * solves this race condition.
+ */
+
+/*
+ * FINDDEST attempts to find the destination with RSM address rsm_addr.  If the
+ * destination exists, rd is set to point to it.  If the destination exists,
+ * isdel is set to indicate whether the destination is currently being deleted
+ * (nonzero implies a delete is in progress).  If the destination exists and
+ * is not being deleted, its reference count is increased by one.
+ */
+#define	FINDDEST(rd, isdel, wrsmd, rsm_addr) {				\
+	mutex_enter(&wrsmd->wrsmd_dest_lock);			\
+	(rd) = (((rsm_addr) >= RSM_MAX_DESTADDR) ? NULL :		\
+	    (wrsmd)->wrsmd_desttbl[(rsm_addr)]);			\
+	if (rd)							\
+		if (((isdel) = (rd)->rd_dstate) == 0) {		\
+			(rd)->rd_refcnt++;			\
+			D6("FINDDEST ctlr %d addr %ld refcnt++ is %d\n", \
+			    wrsmd->wrsmd_ctlr_id, rsm_addr,	\
+			    (rd)->rd_refcnt);			\
+		}						\
+	mutex_exit(&(wrsmd)->wrsmd_dest_lock);			\
+	_NOTE(CONSTCOND);					\
+}
+
+
+/*
+ * MAKEDEST attempts to find the destination with RSM address rsm_addr.  If the
+ * destination exists, rd and isdel are set as in the description of FINDDEST,
+ * above.  If the destination does not exist, a new destination structure is
+ * allocated and installed, rd is set to point to it, and isnew is set to 1.
+ */
+#define	MAKEDEST(rd, isdel, isnew, wrsmd, rsm_addr) {		\
+	mutex_enter(&(wrsmd)->wrsmd_dest_lock);			\
+	(rd) = ((wrsmd)->wrsmd_desttbl[(rsm_addr)]);		\
+	if (!(rd)) {						\
+		(rd) = wrsmdmkdest((wrsmd), (rsm_addr));	\
+		(isnew) = 1;					\
+	}							\
+	if (rd)							\
+		if (((isdel) = (rd)->rd_dstate) == 0) {		\
+			(rd)->rd_refcnt++;			\
+			D6("MAKEDEST ctlr %d addr %ld refcnt++ is %d\n", \
+			    wrsmd->wrsmd_ctlr_id, (uint64_t)rsm_addr,	\
+			    (rd)->rd_refcnt);			\
+		}						\
+	mutex_exit(&(wrsmd)->wrsmd_dest_lock);			\
+	_NOTE(CONSTCOND);					\
+}
+
+
+/*
+ * GETRUNQ attempts to return the destination which is at the head of wrsmd's
+ * run queue.  If the run queue is non-empty, the head of the queue is removed,
+ * and rd is set to point to it; otherwise, rd is set to NULL.  If rd is
+ * nonzero, isdel is set to 1 if the destination pointed to by rd is being
+ * deleted, or to 0 otherwise.  Finally, if rd is nonzero, and isdel is zero,
+ * then rd's reference count is increased by one.
+ */
+#define	GETRUNQ(rd, isdel, wrsmd) {				\
+	mutex_enter(&(wrsmd)->wrsmd_dest_lock);			\
+	mutex_enter(&(wrsmd)->wrsmd_runq_lock);			\
+	rd = (wrsmd)->wrsmd_runq;				\
+	if (rd) {						\
+		(wrsmd)->wrsmd_runq = rd->rd_next;		\
+		if (((isdel) = (rd)->rd_dstate) == 0) {		\
+			(rd)->rd_refcnt++;			\
+			D6("GETRUNQ ctlr %d addr %ld refcnt++ is %d\n", \
+			    wrsmd->wrsmd_ctlr_id,		\
+			    (rd)->rd_rsm_addr,			\
+			    (rd)->rd_refcnt);			\
+		}						\
+	}							\
+	mutex_exit(&(wrsmd)->wrsmd_runq_lock);			\
+	mutex_exit(&(wrsmd)->wrsmd_dest_lock);			\
+	_NOTE(CONSTCOND);					\
+}
+
+
+/*
+ * REFDEST checks to see if the destination pointed to by rd is currently being
+ * deleted.  If so, isdel is set to a nonzero value; otherwise, it is set to
+ * zero, and the destination's reference count is incremented.
+ */
+#define	REFDEST(rd, isdel) {					\
+	mutex_enter(&(rd)->rd_wrsmdp->wrsmd_dest_lock);		\
+	if (((isdel) = (rd)->rd_dstate) == 0) {			\
+		(rd)->rd_refcnt++;				\
+		D6("REFDEST ctlr %d addr %ld refcnt++ is %d\n",	\
+		    wrsmd->wrsmd_ctlr_id, rsm_addr,		\
+		    (rd)->rd_refcnt);				\
+	}							\
+	mutex_exit(&(rd)->rd_wrsmdp->wrsmd_dest_lock);		\
+	_NOTE(CONSTCOND);					\
+}
+
+
+/*
+ * UNREFDEST decrements the reference count of the destination pointed to by
+ * rd.  If the reference count becomes zero, we start the deletion process for
+ * the destination.
+ */
+#define	UNREFDEST(rd) {						\
+	mutex_enter(&(rd)->rd_wrsmdp->wrsmd_dest_lock);		\
+	D6("UNREFDEST ctlr %d addr %ld refcnt-- is %d\n",	\
+	    (rd)->rd_wrsmdp->wrsmd_ctlr_id, (rd)->rd_rsm_addr,	\
+	    (rd)->rd_refcnt - 1);				\
+	if (--(rd)->rd_refcnt <= 0) {				\
+		mutex_exit(&(rd)->rd_wrsmdp->wrsmd_dest_lock);	\
+		if (wrsmddest_refcnt_0(rd)) { rd = NULL; }	\
+	} else							\
+		mutex_exit(&(rd)->rd_wrsmdp->wrsmd_dest_lock);	\
+	_NOTE(CONSTCOND);					\
+}
+
+
+
+/* Local Static def's */
+
+/*
+ * Lock and variable to allow attach routines to initialize global mutexes
+ */
+
+static kmutex_t wrsmdattlock;	/* Protects wrsmddbginit  */
+
+/*
+ * Linked list of "wrsmd" structures - one per physical device.
+ */
+static wrsmd_t *wrsmddev = NULL;	/* Head of list */
+static kmutex_t wrsmddevlock;	/* Protects list contents */
+static uint_t wrsmdminbuflen = 0; /* Smallest buf length we've seen; updated */
+				/*  when we add a device to the list */
+_NOTE(MUTEX_PROTECTS_DATA(wrsmddevlock,
+    wrsmddev wrsmdminbuflen wrsmd::wrsmd_nextp))
+
+/*
+ * Linked list of active (inuse) driver Streams.
+ */
+static wrsmdstr_t *wrsmdstrup = NULL;	/* Head of list */
+static krwlock_t wrsmdstruplock;		/* Protects list of streams */
+_NOTE(RWLOCK_PROTECTS_DATA(wrsmdstruplock, wrsmdstrup wrsmdstr::ss_nextp))
+
+/*
+ * Our DL_INFO_ACK template.
+ */
+static dl_info_ack_t wrsmdinfoack = {
+	DL_INFO_ACK,			/* dl_primitive */
+	MEDIUM_MTU,			/* dl_max_sdu */
+	0,				/* dl_min_sdu */
+	WRSMD_DEVICE_ADDRL,		/* dl_addr_length */
+	DL_ETHER,			/* dl_mac_type */
+	0,				/* dl_reserved */
+	0,				/* dl_current_state */
+	-2,				/* dl_sap_length  - 2 bytes (short), */
+					/* second component in DLSAP address */
+	DL_CLDLS,			/* dl_service_mode */
+	0,				/* dl_qos_length */
+	0,				/* dl_qos_offset */
+	0,				/* dl_range_length */
+	0,				/* dl_range_offset */
+	DL_STYLE2,			/* dl_provider_style */
+	sizeof (dl_info_ack_t),		/* dl_addr_offset */
+	DL_VERSION_2,			/* dl_version */
+	WRSMD_BCAST_ADDRL,		/* dl_brdcst_addr_length */
+	sizeof (dl_info_ack_t) + WRSMD_DEVICE_ADDRL, /* dl_brdcst_addr_offset */
+	0				/* dl_growth */
+};
+
+/*
+ * use standard ethernet broadcast address - all 1's
+ */
+static	struct ether_addr wrsmdbcastaddr = {
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static	struct ether_addr wrsmdbadaddr = {
+	0xB, 0xAD, 0xB, 0xAD, 0xB, 0xAD
+};
+
+
+_NOTE(READ_ONLY_DATA(wrsmdinfoack))
+_NOTE(READ_ONLY_DATA(wrsmdbcastaddr))
+
+static void *wrsmd_state;	/* opaque handle for soft state structs */
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * B E G I N   BASIC MODULE BOILERPLATE                          *
+ *                                                               *
+ * ****************************************************************
+ */
+
+/* Standard Streams declarations */
+
+static struct module_info wrsmdminfo = {
+	WRSMDIDNUM,	/* mi_idnum */
+	WRSMDNAME,	/* mi_idname */
+	WRSMDMINPSZ,	/* mi_minpsz */
+	WRSMDMAXPSZ,	/* mi_minpsz */
+	WRSMDHIWAT,	/* mi_hiwat */
+	WRSMDLOWAT,	/* mi_lowat */
+};
+
+static struct qinit wrsmdrinit = {
+	0,		/* qi_putp */
+	0,		/* qi_srvp */
+	wrsmdopen,	/* qi_qopen */
+	wrsmdclose,	/* qi_qclose */
+	0,		/* qi_qadmin */
+	&wrsmdminfo,	/* qi_minfo */
+	NULL,		/* qi_mstat */
+};
+
+static struct qinit wrsmdwinit = {
+	wrsmdwput,	/* qi_putp */
+	wrsmdwsrv,	/* qi_srvp */
+	0,		/* qi_qopen */
+	0,		/* qi_qclose */
+	0,		/* qi_qadmin */
+	&wrsmdminfo,	/* qi_minfo */
+	NULL,		/* qi_mstat */
+};
+
+static struct streamtab wrsmd_info = {
+	&wrsmdrinit,	/* st_rdinit */
+	&wrsmdwinit,	/* st_wrinit */
+	NULL,		/* st_muxrinit */
+	NULL,		/* st_muxwrinit */
+};
+
+
+/* Module Loading/Unloading and Autoconfiguration declarations */
+
+/*
+ * cb_ops contains the driver entry points and is roughly equivalent
+ * to the cdevsw and bdevsw  structures in previous releases.
+ *
+ * dev_ops contains, in addition to the pointer to cb_ops, the routines
+ * that support loading and unloading our driver.
+ *
+ * Unsupported entry points are set to nodev, except for the poll
+ * routine , which is set to nochpoll(), a routine that returns ENXIO.
+ */
+
+static struct cb_ops wrsmd_cb_ops = {
+	nodev,			/* cb_open */
+	nodev,			/* cb_close */
+	nodev,			/* cb_strategy */
+	nodev,			/* cb_print */
+	nodev,			/* cb_dump */
+	nodev,			/* cb_read */
+	nodev,			/* cb_write */
+	nodev,			/* cb_ioctl */
+	nodev,			/* cb_devmap */
+	nodev,			/* cb_mmap */
+	nodev,			/* cb_segmap */
+	nochpoll,		/* cb_chpoll */
+	ddi_prop_op,		/* cb_prop_op */
+	&wrsmd_info,		/* cb_stream */
+	D_MP,			/* cb_flag */
+};
+
+static struct dev_ops wrsmd_ops = {
+	DEVO_REV,		/* devo_rev */
+	0,			/* devo_refcnt */
+	ddi_no_info,		/* devo_getinfo */
+	nulldev,		/* devo_identify */
+	wrsmdprobe,		/* devo_probe */
+	wrsmdattach,		/* devo_attach */
+	wrsmddetach,		/* devo_detach */
+	nodev,			/* devo_reset */
+	&wrsmd_cb_ops,		/* devo_cb_ops */
+	(struct bus_ops *)NULL	/* devo_bus_ops */
+};
+
+
+/*
+ * Module linkage information for the kernel.
+ */
+static struct modldrv modldrv = {
+	&mod_driverops,		 /* Type of module.  This one is a driver */
+	"RSMPI DLPI %I% %E%",	/* Description */
+	&wrsmd_ops,		 /* driver ops */
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1, &modldrv, NULL
+};
+
+/*
+ * Module Loading and Installation Routines.
+ */
+
+/*
+ * Module Installation
+ * Install the driver, initialize soft state system, initialize wrsmdattlock
+ */
+
+int
+_init(void)
+{
+	int status;
+
+	_NOTE(COMPETING_THREADS_NOW)
+	_NOTE(NO_COMPETING_THREADS_NOW)
+	status = ddi_soft_state_init(&wrsmd_state, sizeof (wrsmd_t), 1);
+	if (status != 0) {
+		_NOTE(CONSTCOND)
+		D1("wrsmd:_init - soft_state_init failed: 0x%x\n", status);
+		cmn_err(CE_CONT,
+		    "wrsmd:_init - soft_state_init failed: 0x%x\n", status);
+		return (status);
+	}
+
+	/* initialize global locks here */
+
+	mutex_init(&wrsmdattlock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&wrsmddevlock, NULL, MUTEX_DRIVER, NULL);
+	rw_init(&wrsmdstruplock, NULL, RW_DRIVER, NULL);
+
+	status = mod_install(&modlinkage);
+	if (status != DDI_SUCCESS) {
+		mutex_destroy(&wrsmdattlock);
+		mutex_destroy(&wrsmddevlock);
+		rw_destroy(&wrsmdstruplock);
+	}
+	return (status);
+}
+
+/*
+ * Module Removal
+ */
+
+int
+_fini(void)
+{
+	int status;
+
+	/* LINTED possibly invalid annotation name */
+	_NOTE(COMPETING_THREADS_NOW)
+	_NOTE(NO_COMPETING_THREADS_NOW)
+
+	if ((status = mod_remove(&modlinkage)) != 0) {
+		D1("wrsmd_fini - mod_remove failed: 0x%x\n", status);
+		return (status);
+	}
+
+	ddi_soft_state_fini(&wrsmd_state);
+
+	mutex_destroy(&wrsmdattlock);
+	mutex_destroy(&wrsmddevlock);
+	rw_destroy(&wrsmdstruplock);
+
+	return (status);
+}
+
+/*
+ * Return Module Info.
+ */
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+
+
+/*
+ * Autoconfiguration Routines
+ */
+
+
+/*
+ * Probe to see if device exists.
+ */
+static int
+wrsmdprobe(dev_info_t *dip)
+{
+	int inst = ddi_get_instance(dip);
+
+	D1("wrsmdprobe: dip 0x%p, inst %d", (void *)dip, inst);
+
+	return (DDI_PROBE_SUCCESS);
+}
+
+/*
+ * Attach the device, create and fill in the device-specific structure.
+ */
+
+static int
+wrsmdattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	wrsmd_t *wrsmdp;
+	int instance;
+	int progress = 0;
+
+	D1("wrsmdattach: dip 0x%p, cmd %d", (void *)dip, cmd);
+	TNF_PROBE_2(wrsmdattach_start, "RSMPI", "wrsmdattach start",
+	    tnf_long, dip, (tnf_long_t)dip, tnf_long, command, cmd);
+
+	if (cmd != DDI_ATTACH) {
+		TNF_PROBE_2(wrsmdattach_end, "RSMPI",
+		    "wrsmdattach end; failure 'cmd != DDI_ATTACH'",
+		    tnf_string, failure, "cmd != DDI_ATTACH",
+		    tnf_long, cmd, DDI_FAILURE);
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Allocate soft data structure
+	 */
+
+	instance = ddi_get_instance(dip);
+
+	if (ddi_soft_state_zalloc(wrsmd_state, instance) != DDI_SUCCESS) {
+		D1("wrsmdattach: bad state zalloc, returning DDI_FAILURE");
+		TNF_PROBE_2(wrsmdattach_end, "RSMPI",
+		    "wrsmdattach end; failure 'ddi_soft_state_zalloc'",
+		    tnf_string, failure, "ddi_soft_state_zalloc",
+		    tnf_long, rval, DDI_FAILURE);
+		return (DDI_FAILURE);
+	}
+
+	wrsmdp = ddi_get_soft_state(wrsmd_state, instance);
+	if (wrsmdp == NULL) {
+		TNF_PROBE_2(wrsmdattach_end, "RSMPI",
+		    "wrsmdattach end; failure get_soft_state",
+		    tnf_string, failure, "get_soft_state",
+		    tnf_long, cmd, DDI_FAILURE);
+		return (DDI_FAILURE);
+	}
+	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wrsmdp))
+
+	/*
+	 * Stuff private info into dip.
+	 */
+	rw_init(&wrsmdp->wrsmd_ipq_rwlock, NULL, RW_DRIVER, NULL);
+	wrsmdp->wrsmd_dip = dip;
+	ddi_set_driver_private(dip, wrsmdp);
+	wrsmdp->wrsmd_ctlr_id = instance;
+
+	/*
+	 * Get device parameters from the device tree and save them in our
+	 * per-device structure for later use.
+	 */
+	wrsmdgetparam(dip, wrsmdp);
+
+
+	/*
+	 * Initialize mutexes for this device.
+	 */
+	mutex_init(&wrsmdp->wrsmd_lock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&wrsmdp->wrsmd_dest_lock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&wrsmdp->wrsmd_runq_lock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&wrsmdp->event_lock, NULL, MUTEX_DRIVER, NULL);
+	cv_init(&wrsmdp->event_cv, NULL, CV_DEFAULT, NULL);
+	cv_init(&wrsmdp->event_thread_exit_cv, NULL, CV_DEFAULT, NULL);
+	progress |= WRSMD_ATT_MUTEX;
+
+	/*
+	 * Initialize kernel statistics.
+	 */
+	wrsmdkstatinit(wrsmdp);
+	progress |= WRSMD_ATT_KSTAT;
+
+	/*
+	 * Create the filesystem device node.
+	 */
+	if (ddi_create_minor_node(dip, "wrsmd", S_IFCHR,
+	    ddi_get_instance(dip),
+	    DDI_PSEUDO, CLONE_DEV) != DDI_SUCCESS) {
+		D1("wrsmdattach: bad create_minor_node, returning "
+		    "DDI_FAILURE");
+		wrsmdtakedown(wrsmdp, progress);
+		TNF_PROBE_2(wrsmdattach_end, "RSMPI",
+		    "wrsmdattach end; failure 'ddi_create_minor_node'",
+		    tnf_string, failure, "ddi_create_minor_node",
+		    tnf_long, rval, DDI_FAILURE);
+		return (DDI_FAILURE);
+	}
+	progress |= WRSMD_ATT_MINOR;
+
+	/*
+	 * Link this per-device structure in with the rest.
+	 */
+	mutex_enter(&wrsmddevlock);
+	wrsmdp->wrsmd_nextp = wrsmddev;
+
+	/*
+	 * Update our idea of the smallest buffer size seen so far.  We do this
+	 * because many clients do a get_info request before they've attached
+	 * to a particular piece of hardware (ie, PPA).  We need to have
+	 * something to give them for the MTU, and giving them a value that's
+	 * bigger than the one used by the device they eventually attach to
+	 * causes problems.
+	 */
+	if (wrsmddev == NULL)
+		wrsmdminbuflen = wrsmdp->wrsmd_param.wrsmd_buffer_size;
+	else if (wrsmdminbuflen > wrsmdp->wrsmd_param.wrsmd_buffer_size)
+		wrsmdminbuflen = wrsmdp->wrsmd_param.wrsmd_buffer_size;
+
+	wrsmddev = wrsmdp;
+	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wrsmdp))
+	mutex_exit(&wrsmddevlock);
+	progress |= WRSMD_ATT_LINKED;
+
+	/*
+	 * Start up event thread for this wrsmd device.
+	 * This seems like as good a place as any...
+	 */
+	wrsmdp->stop_events = B_FALSE;
+	wrsmdp->events = (wrsmd_event_t *)NULL;
+	wrsmdp->event_thread = thread_create(NULL, 0, wrsmd_event_thread,
+	    (void *)wrsmdp, 0, &p0, TS_RUN, maxclsyspri - 1);
+	progress |= WRSMD_ATT_EVT_THREAD;
+
+	ddi_report_dev(dip);
+
+	D1("wrsmdattach: returning DDI_SUCCESS");
+	TNF_PROBE_2(wrsmdattach_end, "RSMPI", "wrsmdattach end",
+	    tnf_string, success, "",
+	    tnf_long, rval, DDI_SUCCESS);
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Detach - Free resources allocated in attach
+ */
+
+/*ARGSUSED*/
+static int
+wrsmddetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+	int instance;
+	wrsmd_t *wrsmdp;
+	timeout_id_t tmoid, tmoid_orig;
+
+	D1("wrsmddetach: dip 0x%p, cmd %d", (void *)dip, cmd);
+	TNF_PROBE_2(wrsmddetach_start, "RSMPI", "wrsmddetach start",
+	    tnf_long, dip, (tnf_long_t)dip, tnf_long, command, cmd);
+
+	if (cmd != DDI_DETACH) {
+		TNF_PROBE_1(wrsmddetach_end, "RSMPI",
+		    "wrsmddetach end; failure 'cmd != DDI_DETACH'",
+		    tnf_long, rval, DDI_FAILURE);
+		return (DDI_FAILURE);
+	}
+
+	instance = ddi_get_instance(dip);
+	wrsmdp = ddi_get_soft_state(wrsmd_state, instance);
+	if (wrsmdp == NULL) {
+		TNF_PROBE_2(wrsmddetach_end, "RSMPI",
+		    "wrsmddetach end; failure get_soft_state",
+		    tnf_string, failure, "get_soft_state",
+		    tnf_long, cmd, DDI_FAILURE);
+		return (DDI_FAILURE);
+	}
+
+
+	mutex_enter(&wrsmdp->wrsmd_lock);
+
+	/*
+	 * The teardown timeout now reschedules itself, so we
+	 * have to go to great lengths to kill it.
+	 */
+	tmoid_orig = tmoid = wrsmdp->wrsmd_teardown_tmo_id;
+
+	while (tmoid) {
+		/*
+		 * A timeout is scheduled to teardown the
+		 * device.  Cancel, as we intend to do this now.
+		 */
+		mutex_exit(&wrsmdp->wrsmd_lock);
+
+		(void) untimeout(tmoid);
+		/*
+		 * untimeout guarantees the either the function was
+		 * cancelled, or it has completed.  If timeout was
+		 * cancelled before the function ran, the timout id will
+		 * not have changed.
+		 */
+		mutex_enter(&wrsmdp->wrsmd_lock);
+
+		if (tmoid == wrsmdp->wrsmd_teardown_tmo_id)
+			wrsmdp->wrsmd_teardown_tmo_id = 0;
+		tmoid = wrsmdp->wrsmd_teardown_tmo_id;
+	}
+
+	/*
+	 * If we can't release all destination and RSMPI resources, we can't
+	 * detach.  The user will have to try later to unload the driver.
+	 */
+	mutex_exit(&wrsmdp->wrsmd_lock);
+	if (wrsmduninit(wrsmdp) != 0) {
+		TNF_PROBE_1(wrsmddetach_end, "RSMPI",
+		    "wrsmddettach end; failure 'wrsmduninit'",
+		    tnf_long, rval, DDI_FAILURE);
+		if (tmoid_orig) {
+			/* restart cancelled timeout */
+			mutex_enter(&wrsmdp->wrsmd_lock);
+			wrsmdp->wrsmd_teardown_tmo_id =
+			    timeout(wrsmdteardown_tmo,
+			    (caddr_t)wrsmdp,
+			    wrsmdp->wrsmd_param.wrsmd_teardown_tmo);
+			mutex_exit(&wrsmdp->wrsmd_lock);
+		}
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Release all our resources. At this point, all attachment
+	 * setup must have completed, so must all be torn down.
+	 */
+	wrsmdtakedown(wrsmdp, WRSMD_ATT_ALL);
+
+	TNF_PROBE_0(wrsmddetach_end, "RSMPI", "wrsmddettach end");
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Undo tasks done by wrsmdattach(), either because we're detaching or because
+ * attach() got partly done then failed.  progress is a bitmap that tells
+ * us what has been done so far.
+ */
+static void
+wrsmdtakedown(
+	wrsmd_t *wrsmdp,	/* WRSMD device (RSM controller) pointer */
+	int progress)	/* Mask of RSMPI_ATT_xxx values */
+{
+	int instance;
+	dev_info_t *dip;
+
+	D1("wrsmdtakedown: wrsmdp 0x%p (ctlr %d), progress 0x%x",
+	    (void *)wrsmdp, wrsmdp->wrsmd_ctlr_id, progress);
+	TNF_PROBE_2(wrsmdtakedown_start, "RSMPI", "wrsmdtakedown start",
+	    tnf_long, wrsmdp, (tnf_long_t)wrsmdp, tnf_long, progress, progress);
+
+	ASSERT(wrsmdp);
+
+	if (progress & WRSMD_ATT_EVT_THREAD) {
+		mutex_enter(&wrsmdp->event_lock);
+		wrsmdp->stop_events = B_TRUE;
+		cv_broadcast(&wrsmdp->event_cv);
+		cv_wait(&wrsmdp->event_thread_exit_cv, &wrsmdp->event_lock);
+		wrsmdp->event_thread = (kthread_t *)NULL;
+		mutex_exit(&wrsmdp->event_lock);
+
+		progress &= ~WRSMD_ATT_EVT_THREAD;
+	}
+
+	if (progress & WRSMD_ATT_LINKED) {
+		mutex_enter(&wrsmddevlock);
+
+		if (wrsmddev == wrsmdp)
+			wrsmddev = wrsmdp->wrsmd_nextp;
+		else {
+			wrsmd_t *ptr;
+
+			for (ptr = wrsmddev; ptr->wrsmd_nextp; ptr =
+			    ptr->wrsmd_nextp)
+				if (ptr->wrsmd_nextp == wrsmdp) {
+					ptr->wrsmd_nextp = wrsmdp->wrsmd_nextp;
+					break;
+				}
+		}
+		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wrsmdp))
+		mutex_exit(&wrsmddevlock);
+		progress &= ~WRSMD_ATT_LINKED;
+	}
+
+	dip = wrsmdp->wrsmd_dip;
+	instance = ddi_get_instance(dip);
+
+
+	if (progress & WRSMD_ATT_KSTAT) {
+		wrsmdkstatremove(wrsmdp);
+		progress &= ~WRSMD_ATT_KSTAT;
+	}
+
+	if (progress & WRSMD_ATT_MINOR) {
+		ddi_remove_minor_node(dip, NULL);
+		progress &= ~WRSMD_ATT_MINOR;
+	}
+
+	if (progress & WRSMD_ATT_MUTEX) {
+		mutex_destroy(&wrsmdp->wrsmd_lock);
+		mutex_destroy(&wrsmdp->wrsmd_dest_lock);
+		mutex_destroy(&wrsmdp->wrsmd_runq_lock);
+		mutex_destroy(&wrsmdp->event_lock);
+		cv_destroy(&wrsmdp->event_cv);
+		cv_destroy(&wrsmdp->event_thread_exit_cv);
+		progress &= ~WRSMD_ATT_MUTEX;
+	}
+
+	ASSERT(progress == 0);
+
+	ddi_soft_state_free(wrsmd_state, instance);
+
+	D1("wrsmdtakedown: returning DDI_SUCCESS");
+	TNF_PROBE_1(wrsmdtakedown_end, "RSMPI", "wrsmdtakedown end",
+	    tnf_long, rval, DDI_SUCCESS);
+}
+
+/*
+ * Determine the device ipq pointer after a state change.  The device ipq
+ * pointer is basically a performance hack; it is set to one of our attached
+ * queues if, and only if, (a) that queue is the only one which has bound to
+ * IP's SAP, i.e., has expressed interest in getting IP packets; and (b) there
+ * is no stream attached to us which has gone into any sort of promiscuous mode,
+ * i.e., has expressed interest in getting all packets.  The performance win
+ * comes when ipq is set; if it is, we can just send all incoming IP packets
+ * to that queue without having to traverse the entire list of queues attached
+ * to us.
+ */
+static void
+wrsmdsetipq(wrsmd_t *wrsmdp)	/* WRSMD device (RSM controller) pointer */
+{
+	struct	wrsmdstr	*ssp;
+	queue_t	*ipq = NULL;
+
+	/*
+	 * Take ipq writer lock to prevent the fastpath from using the
+	 * wrong ipq.  Note:  must take prior to taking struplock.
+	 */
+	rw_enter(&wrsmdp->wrsmd_ipq_rwlock, RW_WRITER);
+
+	rw_enter(&wrsmdstruplock, RW_READER);
+
+	for (ssp = wrsmdstrup; ssp; ssp = ssp->ss_nextp)
+		if (ssp->ss_wrsmdp == wrsmdp) {
+			if (ssp->ss_flags & WRSMD_SLALLSAP) {
+				ipq = NULL;
+				break;
+			} else if (ssp->ss_sap == WRSMD_IP_SAP) {
+				if ((ssp->ss_flags & WRSMD_SLFAST) == 0) {
+					ipq = NULL;
+					break;
+				} else if (ipq == NULL) {
+					ipq = ssp->ss_rq;
+				} else {
+					ipq = NULL;
+					break;
+				}
+			}
+		}
+
+	wrsmdp->wrsmd_ipq = ipq;
+
+	rw_exit(&wrsmdstruplock);
+	rw_exit(&wrsmdp->wrsmd_ipq_rwlock);
+}
+
+/*
+ * Hook a new stream onto the driver.  We create a wrsmdstr structure for the
+ * new stream, and, if this is a clone open, allocate an unused minor device
+ * number for it.
+ */
+
+/*ARGSUSED*/
+static int
+wrsmdopen(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
+{
+	wrsmdstr_t *ssp;
+	wrsmdstr_t **prevssp;
+	minor_t	minordev;
+	int rc = 0;
+
+	D1("wrsmdopen: rq 0x%p, *dev 0x%lx, flag %d, sflag %d",
+	    (void *)rq, *devp, flag, sflag);
+	TNF_PROBE_4(wrsmdopen_start, "RSMPI", "wrsmdopen start",
+	    tnf_long, rq, (tnf_long_t)rq, tnf_long, device, (tnf_long_t)devp,
+	    tnf_long, flags, flag, tnf_long, sflags, sflag);
+
+	ASSERT(sflag != MODOPEN);
+
+	/*
+	 * Serialize all driver open and closes.
+	 */
+	rw_enter(&wrsmdstruplock, RW_WRITER);
+
+	/*
+	 * Determine minor device number.
+	 */
+	prevssp = &wrsmdstrup;
+	if (sflag == CLONEOPEN) {
+		minordev = 0;
+		for (; ((ssp = *prevssp) != NULL); prevssp = &ssp->ss_nextp) {
+			if (minordev < ssp->ss_minor)
+				break;
+			minordev++;
+		}
+		*devp = makedevice(getmajor(*devp), minordev);
+	} else
+		minordev = getminor(*devp);
+
+	if (rq->q_ptr == NULL) {
+		ssp = (wrsmdstr_t *)kmem_zalloc(sizeof (wrsmdstr_t), KM_SLEEP);
+
+		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ssp))
+
+		ssp->ss_minor = minordev;
+		ssp->ss_rq = rq;
+		ssp->ss_state = DL_UNATTACHED;
+		ssp->ss_sap = 0;
+		ssp->ss_flags = 0;
+		ssp->ss_wrsmdp = NULL;
+		mutex_init(&ssp->ss_lock, NULL, MUTEX_DRIVER, NULL);
+
+		/*
+		 * Link new entry into the list of active entries.
+		 */
+		ssp->ss_nextp = *prevssp;
+		*prevssp = ssp;
+		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ssp))
+
+		rq->q_ptr = WR(rq)->q_ptr = ssp;
+	}
+
+	rw_exit(&wrsmdstruplock);
+	qprocson(rq);
+	D1("wrsmdopen: returning %d", rc);
+	TNF_PROBE_1(wrsmdopen_end, "RSMPI", "wrsmdopen end", tnf_long,
+	    rval, rc);
+
+	(void) qassociate(rq, -1);
+	return (rc);
+}
+
+/*
+ * Unhook a stream from the driver.  If it was attached to a specific physical
+ * device, detach it from the device, then remove it from our list of streams.
+ */
+
+/*ARGSUSED*/
+static int
+wrsmdclose(queue_t *rq, int flag, cred_t *credp)
+{
+	wrsmdstr_t *ssp;
+	wrsmdstr_t **prevssp;
+
+	D1("wrsmdclose: rq 0x%p, flag %d", (void *)rq, flag);
+	TNF_PROBE_2(wrsmdclose_start, "RSMPI", "wrsmdclose start",
+	    tnf_long, rq, (tnf_long_t)rq, tnf_long, flags, flag);
+
+	ASSERT(rq);
+
+	/* Disable put/service routines */
+
+	qprocsoff(rq);
+
+	ASSERT(rq->q_ptr);
+
+	ssp = (wrsmdstr_t *)rq->q_ptr;
+
+	/* Detach Stream from interface */
+
+	mutex_enter(&ssp->ss_lock);
+	if (ssp->ss_wrsmdp)
+		wrsmddodetach(ssp);
+	mutex_exit(&ssp->ss_lock);
+
+	rw_enter(&wrsmdstruplock, RW_WRITER);
+
+	/* Unlink the per-Stream entry from the active list and free it */
+
+	for (prevssp = &wrsmdstrup; ((ssp = *prevssp) != NULL);
+	    prevssp = &ssp->ss_nextp)
+		if (ssp == (wrsmdstr_t *)rq->q_ptr)
+			break;
+	ASSERT(ssp);
+	*prevssp = ssp->ss_nextp;
+	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ssp))
+
+	mutex_destroy(&ssp->ss_lock);
+	kmem_free(ssp, sizeof (wrsmdstr_t));
+
+	rq->q_ptr = WR(rq)->q_ptr = NULL;
+
+	rw_exit(&wrsmdstruplock);
+	D1("wrsmdclose: returning 0");
+	TNF_PROBE_1(wrsmdclose_end, "RSMPI", "wrsmdclose end",
+	    tnf_long, rval, 0);
+
+	(void) qassociate(rq, -1);
+	return (0);
+}
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * E N D   BASIC MODULE BOILERPLATE                              *
+ *                                                               *
+ * ****************************************************************
+ */
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * B E G I N   STATUS REPORTING STUFF                            *
+ *                                                               *
+ * ****************************************************************
+ */
+
+/*
+ * This routine makes the data in our kernel statistics structure reflect
+ * the current state of the device; it's called whenever a user requests
+ * the kstat data.  Basically, all we do is copy the stats from the RSMPI
+ * controller structure, where they're maintained, to the kstat's data
+ * portion.
+ */
+static int
+wrsmdstat_kstat_update(
+	kstat_t *ksp,	/* Pointer to kstat that will be updated */
+	int rw)		/* Indicates read or write (we don't support write) */
+{
+	wrsmd_t *wrsmdp;
+	wrsmd_stat_t *wrsmdsp;
+
+	if (rw == KSTAT_WRITE)
+		return (EACCES);
+
+	wrsmdp = (wrsmd_t *)ksp->ks_private;
+	wrsmdsp = (wrsmd_stat_t *)ksp->ks_data;
+
+	wrsmdsp->rsm_ipackets.value.ul =	(uint_t)wrsmdp->wrsmd_ipackets;
+	wrsmdsp->rsm_ipackets64.value.ui64 =	wrsmdp->wrsmd_ipackets;
+	wrsmdsp->rsm_ierrors.value.ul =		wrsmdp->wrsmd_ierrors;
+	wrsmdsp->rsm_opackets.value.ul =	(uint_t)wrsmdp->wrsmd_opackets;
+	wrsmdsp->rsm_opackets64.value.ui64 =	wrsmdp->wrsmd_opackets;
+	wrsmdsp->rsm_oerrors.value.ul =		wrsmdp->wrsmd_oerrors;
+	wrsmdsp->rsm_collisions.value.ul =	wrsmdp->wrsmd_collisions;
+
+	wrsmdsp->rsm_xfers.value.ul =		wrsmdp->wrsmd_xfers;
+	wrsmdsp->rsm_xfer_pkts.value.ul =	wrsmdp->wrsmd_xfer_pkts;
+	wrsmdsp->rsm_syncdqes.value.ul =	wrsmdp->wrsmd_syncdqes;
+	wrsmdsp->rsm_lbufs.value.ul =		wrsmdp->wrsmd_lbufs;
+	wrsmdsp->rsm_nlbufs.value.ul =		wrsmdp->wrsmd_nlbufs;
+	wrsmdsp->rsm_pullup.value.ul =		wrsmdp->wrsmd_pullup;
+	wrsmdsp->rsm_pullup_fail.value.ul =	wrsmdp->wrsmd_pullup_fail;
+	wrsmdsp->rsm_starts.value.ul =		wrsmdp->wrsmd_starts;
+	wrsmdsp->rsm_start_xfers.value.ul =	wrsmdp->wrsmd_start_xfers;
+	wrsmdsp->rsm_fqetmo_hint.value.ul =	wrsmdp->wrsmd_fqetmo_hint;
+	wrsmdsp->rsm_fqetmo_drops.value.ul =	wrsmdp->wrsmd_fqetmo_drops;
+	wrsmdsp->rsm_maxq_drops.value.ul =	wrsmdp->wrsmd_maxq_drops;
+	wrsmdsp->rsm_errs.value.ul =		wrsmdp->wrsmd_errs;
+	wrsmdsp->rsm_in_bytes.value.ul =	(uint_t)wrsmdp->wrsmd_in_bytes;
+	wrsmdsp->rsm_in_bytes64.value.ui64 =	wrsmdp->wrsmd_in_bytes;
+	wrsmdsp->rsm_out_bytes.value.ul =	(uint_t)wrsmdp->wrsmd_out_bytes;
+	wrsmdsp->rsm_out_bytes64.value.ui64 =	wrsmdp->wrsmd_out_bytes;
+
+	return (0);
+}
+
+/*
+ * This routine initializes the kernel statistics structures for an
+ * WRSMD device.
+ */
+static void
+wrsmdkstatinit(
+	wrsmd_t *wrsmdp)	/* WRSMD device (RSM controller) pointer */
+{
+	struct kstat *ksp;
+	wrsmd_stat_t *wrsmdsp;
+
+	/*
+	 * We create a kstat for the device, then create a whole bunch of
+	 * named stats inside that first kstat.
+	 */
+	if ((ksp = kstat_create("wrsmd", ddi_get_instance(wrsmdp->wrsmd_dip),
+	    NULL, "net", KSTAT_TYPE_NAMED, sizeof (wrsmd_stat_t) /
+	    sizeof (kstat_named_t), 0)) == NULL) {
+		wrsmderror(wrsmdp->wrsmd_dip, "kstat_create failed");
+		return;
+	}
+	wrsmdsp = (wrsmd_stat_t *)(ksp->ks_data);
+	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wrsmdsp))
+
+	/*
+	 * The first five named stats we create have well-known names, and are
+	 * used by standard SunOS utilities (e.g., netstat).  (There is actually
+	 * a sixth well-known stat, called "queue", which we don't support.)
+	 */
+	kstat_named_init(&wrsmdsp->rsm_ipackets, "ipackets", KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_ierrors, "ierrors", KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_opackets, "opackets", KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_oerrors, "oerrors", KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_collisions, "collisions",
+	    KSTAT_DATA_ULONG);
+
+	/*
+	 * MIB II kstat variables
+	 */
+	kstat_named_init(&wrsmdsp->rsm_in_bytes, "rbytes", KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_out_bytes, "obytes", KSTAT_DATA_ULONG);
+
+	/*
+	 * PSARC 1997/198
+	 */
+	kstat_named_init(&wrsmdsp->rsm_ipackets64, "ipackets64",
+		KSTAT_DATA_ULONGLONG);
+	kstat_named_init(&wrsmdsp->rsm_opackets64, "opackets64",
+		KSTAT_DATA_ULONGLONG);
+	kstat_named_init(&wrsmdsp->rsm_in_bytes64, "rbytes64",
+		KSTAT_DATA_ULONGLONG);
+	kstat_named_init(&wrsmdsp->rsm_out_bytes64, "obytes64",
+		KSTAT_DATA_ULONGLONG);
+
+
+	/*
+	 * The remainder of the named stats are specific to our driver, and
+	 * are extracted using the kstat utility.
+	 */
+	kstat_named_init(&wrsmdsp->rsm_xfers, "xfers", KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_xfer_pkts, "xfer_pkts",
+	    KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_syncdqes, "syncdqes", KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_lbufs, "lbufs", KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_nlbufs, "nlbufs", KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_pullup, "pullup", KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_pullup_fail, "pullup_fail",
+	    KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_starts, "starts", KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_start_xfers, "start_xfers",
+	    KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_fqetmo_hint, "fqetmo_hint",
+	    KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_fqetmo_drops, "fqetmo_drops",
+	    KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_maxq_drops, "maxq_drops",
+	    KSTAT_DATA_ULONG);
+	kstat_named_init(&wrsmdsp->rsm_errs, "errs", KSTAT_DATA_ULONG);
+
+	ksp->ks_update = wrsmdstat_kstat_update;
+	ksp->ks_private = (void *) wrsmdp;
+	wrsmdp->wrsmd_ksp = ksp;
+	kstat_install(ksp);
+
+	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wrsmdsp))
+}
+
+/*
+ * This routine removes any kstats we might have created.
+ */
+static void
+wrsmdkstatremove(
+	wrsmd_t *wrsmdp)	/* WRSMD device (RSM controller) pointer */
+{
+	_NOTE(ASSUMING_PROTECTED(wrsmdp->wrsmd_ksp))
+
+	if (wrsmdp->wrsmd_ksp)
+		kstat_delete(wrsmdp->wrsmd_ksp);
+}
+
+static void
+print_fqe(volatile wrsmd_fqe_t *fqep)
+{
+	D0("%02x %04x   ", fqep->s.fq_seqnum, fqep->s.fq_bufnum);
+}
+
+static void
+print_dqe(volatile wrsmd_dqe_t *dqep)
+{
+	D0("%02x %04x   ", dqep->s.dq_seqnum, dqep->s.dq_bufnum);
+}
+
+/* Dump detailed information about the destination entry */
+static void
+dump_dest(rsm_addr_t rsm_addr)
+{
+	int found;
+	wrsmd_t *wrsmd_dp;
+	wrsmd_dest_t *rd, *nrd;
+	volatile wrsmd_fqe_t *fqep;
+	volatile wrsmd_dqe_t *dqep;
+	int isdel;
+
+	found = 0;
+	mutex_enter(&wrsmddevlock);
+	for (wrsmd_dp = wrsmddev; wrsmd_dp; wrsmd_dp = wrsmd_dp->wrsmd_nextp) {
+		FINDDEST(rd, isdel, wrsmd_dp, rsm_addr);
+		if (rd == NULL) continue;
+
+		found = 1;
+		D0("\nwrsmd: 0x%p\n", (void *) wrsmd_dp);
+		D0("rsmaddr %ld\n",
+		    wrsmd_dp->wrsmd_rsm_addr.m.rsm);
+		D0("wrsmd_runq: ");
+		for (nrd = wrsmd_dp->wrsmd_runq; nrd; nrd = nrd->rd_next)
+			D0("(%ld, %d) ", nrd->rd_rsm_addr,
+			nrd->rd_state);
+
+		D0("sd 0x%p (%ld, %ld): state (%d, 0x%x, %d)  ref %d "
+		    "nlb %d nlb_del %d\n",
+		    (void *)rd, rsm_addr, rd->rd_rsm_addr, rd->rd_state,
+		    rd->rd_sstate, rd->rd_dstate, rd->rd_refcnt,
+		    rd->rd_nlb, rd->rd_nlb_del);
+
+		D0("  numlbufs %d   nlb_del %d   rbuflen %d   "
+		    "numrbuf %d, queueh %lx  tail %lx\n",
+			rd->rd_numlbufs, rd->rd_nlb_del,
+			rd->rd_rbuflen, rd->rd_numrbuf,
+			(uintptr_t)rd->rd_queue_h, (uintptr_t)rd->rd_queue_t);
+
+		D0("  stopq %d\n", rd->rd_stopq);
+
+		if (isdel) continue; /* No need to UNREFDEST */
+
+		mutex_enter(&rd->rd_xmit_lock);
+
+		D0("  XMT: queue_len %d (max %d), tmo_int %d  tmo_tot %d "
+		    "(max %d) tmo_id %lx\n",
+		    rd->rd_queue_len,
+		    wrsmd_dp->wrsmd_param.wrsmd_max_queued_pkts,
+		    rd->rd_tmo_int, rd->rd_tmo_tot,
+		    wrsmd_dp->wrsmd_param.wrsmd_nobuf_drop_tmo,
+		    (uintptr_t)rd->rd_tmo_id);
+
+		mutex_enter(&rd->rd_net_lock);
+
+		D0("    FQR: cached %d  fqr_seq %04x  size %d, fqr f/l/n "
+		    "= %lx %lx %lx\n",
+		    rd->rd_cached_fqr_cnt, rd->rd_fqr_seq, rd->rd_num_fqrs,
+		    (uintptr_t)rd->rd_fqr_f, (uintptr_t)rd->rd_fqr_l,
+		    (uintptr_t)rd->rd_fqr_n);
+
+		if ((fqep = rd->rd_fqr_n) != NULL) {
+			do {
+				print_fqe(fqep);
+				if (fqep == rd->rd_fqr_l)
+					D0("* ");
+				fqep = (fqep == rd->rd_fqr_l) ?
+				    rd->rd_fqr_f : fqep + 1;
+			} while (fqep != rd->rd_fqr_n);
+		}
+
+		D0("\n    shadow DQ: dqeq f/l/i/o = %lx %lx %lx %lx\n",
+			(uintptr_t)rd->rd_shdwdqw_f,
+			(uintptr_t)rd->rd_shdwdqw_l,
+			(uintptr_t)rd->rd_shdwdqw_i,
+			(uintptr_t)rd->rd_shdwdqw_o);
+
+		if ((dqep = rd->rd_shdwdqw_o) != NULL) {
+			do {
+				print_dqe(dqep);
+				if (dqep == rd->rd_shdwdqw_l)
+					D0("* ");
+				dqep = (dqep == rd->rd_shdwdqw_l) ?
+				    rd->rd_shdwdqw_f : dqep + 1;
+			} while (dqep != rd->rd_shdwdqw_o);
+		}
+
+		D0("\n    remote DQ: dqw_seq %04x  size %d, "
+		    "dqw f_off = %lx\n",
+		    rd->rd_dqw_seq, rd->rd_num_dqws, rd->rd_dqw_f_off);
+
+		D0("\n\n  RCV: rd_rbufoff %08lx, rbuflen %d, numrbuf %d\n",
+			rd->rd_rbufoff, rd->rd_rbuflen, rd->rd_numrbuf);
+
+		D0("    DQR: dqr_seq = %04x  size = %d, dqr f/l/n = "
+		    "%lx %lx %lx\n",
+		    rd->rd_dqr_seq, rd->rd_num_dqrs,
+		    (uintptr_t)rd->rd_dqr_f, (uintptr_t)rd->rd_dqr_l,
+		    (uintptr_t)rd->rd_dqr_n);
+
+		if ((dqep = rd->rd_dqr_n) != NULL) {
+			do {
+				print_dqe(dqep);
+				if (dqep == rd->rd_dqr_l)
+					D0("* ");
+				dqep = (dqep == rd->rd_dqr_l) ?
+				    rd->rd_dqr_f : dqep + 1;
+			} while (dqep != rd->rd_dqr_n);
+		}
+
+		D0("\n    shadow FQE: shdwfqw f/l/i/o = %lx %lx %lx %lx\n",
+			(uintptr_t)rd->rd_shdwfqw_f,
+			(uintptr_t)rd->rd_shdwfqw_l,
+			(uintptr_t)rd->rd_shdwfqw_i,
+			(uintptr_t)rd->rd_shdwfqw_o);
+
+		if ((fqep = rd->rd_shdwfqw_o) != NULL) {
+			do {
+				print_fqe(fqep);
+				if (fqep == rd->rd_shdwfqw_l)
+					D0("* ");
+				fqep = (fqep == rd->rd_shdwfqw_l) ?
+				    rd->rd_shdwfqw_f : fqep + 1;
+			} while (fqep != rd->rd_shdwfqw_o);
+		}
+
+		D0("\n    remote FQ: fqw_seq %04x  size %d, fqw f = %lx\n",
+		    rd->rd_fqw_seq, rd->rd_num_fqws, rd->rd_fqw_f_off);
+
+		mutex_exit(&rd->rd_net_lock);
+
+		mutex_exit(&rd->rd_xmit_lock);
+
+		UNREFDEST(rd);
+	}
+	mutex_exit(&wrsmddevlock);
+	if (found == 0) D0("Sorry - entry for %ld not found\n",
+	    rsm_addr);
+}
+
+/* Dump summary information about all destination entries */
+static void
+dump_ioctl(void)
+{
+	wrsmd_t *wrsmd_np;
+	wrsmd_dest_t *rd;
+	int dest;
+
+	D0("..head of wrsmd structure list, wrsmddev: 0x%lx\n",
+	    (uintptr_t)wrsmddev);
+
+	mutex_enter(&wrsmddevlock);
+	for (wrsmd_np = wrsmddev; wrsmd_np; wrsmd_np = wrsmd_np->wrsmd_nextp) {
+		D0("\n    wrsmd: 0x%lx\n", (uintptr_t)wrsmd_np);
+		D0("    next wrsmd pointer, wrsmd_nextp: 0x%lx\n",
+			(uintptr_t)wrsmd_np->wrsmd_nextp);
+		D0("    dev info pointer, wrsmd_dip: 0x%lx, ipq 0x%lx\n",
+			(uintptr_t)wrsmd_np->wrsmd_dip,
+			(uintptr_t)wrsmd_np->wrsmd_ipq);
+		D0("    rsmaddr %ld\n",
+			wrsmd_np->wrsmd_rsm_addr.m.rsm);
+
+		mutex_enter(&wrsmd_np->wrsmd_dest_lock);
+		for (dest = 0; dest < RSM_MAX_DESTADDR; dest++) {
+			if ((rd = wrsmd_np->wrsmd_desttbl[dest]) == NULL)
+				continue;
+			D0("      rd 0x%p (%d, %ld): state (%d, "
+			    "0x%x, %d)  ref %d  nlb %d nlb_del %d\n",
+			    (void *)rd, dest, rd->rd_rsm_addr,
+			    rd->rd_state, rd->rd_sstate, rd->rd_dstate,
+			    rd->rd_refcnt, rd->rd_nlb, rd->rd_nlb_del);
+		}
+		mutex_exit(&wrsmd_np->wrsmd_dest_lock);
+	}
+	mutex_exit(&wrsmddevlock);
+}
+
+/*
+ * Print an error message to the console.
+ */
+static void
+wrsmderror(
+	dev_info_t *dip,	/* Dev info for the device in question */
+	const char *fmt,	/* Format of output */
+	...)			/* Parameters for output */
+{
+	char name[16];
+	char buf[1024];
+	va_list ap;
+
+	if (dip) {
+		(void) sprintf(name, "%s%d", ddi_get_name(dip),
+			ddi_get_instance(dip));
+	} else {
+		(void) sprintf(name, "wrsmd");
+	}
+
+	va_start(ap, fmt);
+	(void) vsprintf(buf, fmt, ap);
+	va_end(ap);
+
+	D1("%s:\t%s", name, buf);
+	cmn_err(CE_CONT, "%s:\t%s", name, buf);
+}
+
+
+#ifdef DEBUG_WRSMD
+
+#ifdef DEBUG_LOG
+
+/*
+ * The following variables support the debug log buffer scheme.
+ */
+
+char wrsmddbgbuf[0x80000];	/* The log buffer */
+int wrsmddbgsize = sizeof (wrsmddbgbuf);	/* Size of the log buffer */
+int wrsmddbgnext;		/* Next byte to write in buffer (note */
+				/*  this is an index, not a pointer */
+int wrsmddbginit = 0;		/* Nonzero if wrsmddbglock's inited */
+kmutex_t wrsmddbglock;
+
+_NOTE(MUTEX_PROTECTS_DATA(wrsmdattlock, wrsmddbginit))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmddbginit))
+
+_NOTE(MUTEX_PROTECTS_DATA(wrsmddbglock, wrsmddbgbuf wrsmddbgnext))
+
+/*
+ * Add the string str to the end of the debug log, followed by a newline.
+ */
+static void
+wrsmddbglog(char *str)
+{
+	int length, remlen;
+
+	/*
+	 * If this is the first time we've written to the log, initialize it.
+	 */
+	if (!wrsmddbginit) {
+		mutex_enter(&wrsmdattlock);
+		if (!wrsmddbginit) {
+			mutex_init(&wrsmddbglock, NULL, MUTEX_DRIVER,
+			    NULL);
+			bzero(wrsmddbgbuf, sizeof (wrsmddbgbuf));
+			wrsmddbgnext = 0;
+			wrsmddbginit = 1;
+		}
+		mutex_exit(&wrsmdattlock);
+	}
+
+	mutex_enter(&wrsmddbglock);
+
+	/*
+	 * Note the log is circular; if this string would run over the end,
+	 * we copy the first piece to the end and then the last piece to
+	 * the beginning of the log.
+	 */
+	length = strlen(str);
+
+	remlen = sizeof (wrsmddbgbuf) - wrsmddbgnext;
+
+	if (length > remlen) {
+		if (remlen)
+			bcopy(str, wrsmddbgbuf + wrsmddbgnext, remlen);
+		str += remlen;
+		length -= remlen;
+		wrsmddbgnext = 0;
+	}
+
+	bcopy(str, wrsmddbgbuf + wrsmddbgnext, length);
+	wrsmddbgnext += length;
+
+	if (wrsmddbgnext >= sizeof (wrsmddbgbuf))
+		wrsmddbgnext = 0;
+	wrsmddbgbuf[wrsmddbgnext++] = '\n';
+
+	mutex_exit(&wrsmddbglock);
+}
+
+#endif
+
+
+/*
+ * Add a printf-style message to whichever debug logs we're currently using.
+ */
+static void
+wrsmddebug(const char *fmt, ...)
+{
+	char buf[512];
+	va_list ap;
+
+	va_start(ap, fmt);
+	(void) vsprintf(buf, fmt, ap);
+	va_end(ap);
+
+#ifdef DEBUG_LOG
+	if (wrsmddbgmode & 0x1)
+		wrsmddbglog(buf);
+#endif
+
+#ifdef DEBUG_PRINTF
+	if (wrsmddbgmode & 0x2)
+		cmn_err(CE_CONT, "%s\n", buf);
+#endif
+}
+
+/*
+ * Debugging routine, dumps data in hex.
+ */
+static void
+wrsmdump(
+	uchar_t *data,	/* Start of data */
+	int length)	/* Bytes to dump */
+{
+	int bytesonline;
+	int offset;
+	char *lineptr;
+	char line[80];
+
+	lineptr = line;
+	bytesonline = 0;
+	offset = 0;
+
+
+	wrsmddebug("wrsmdump: dump of %d bytes at 0x%p", length, (void *)data);
+
+	while (length) {
+		if (bytesonline == 0) {
+			(void) sprintf(line, "%8x: ", offset);
+			lineptr = line + strlen(line);
+		}
+
+		(void) sprintf(lineptr, "%2x ", *data++);
+		length--;
+		lineptr += 3;
+		bytesonline++;
+
+		if (bytesonline >= 16) {
+			*lineptr = '\0';
+			wrsmddebug("%s", line);
+			bytesonline = 0;
+			offset += 16;
+		}
+
+	}
+
+	if (bytesonline) {
+		*lineptr = '\0';
+		wrsmddebug("%s", line);
+	}
+}
+
+#endif
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * E N D   STATUS REPORTING STUFF                                *
+ *                                                               *
+ * ****************************************************************
+ */
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * B E G I N   BASIC STREAMS OPERATIONS                          *
+ *                                                               *
+ * ****************************************************************
+ */
+
+/*
+ * Process a new message being sent down one of our streams.
+ */
+static int
+wrsmdwput(
+	queue_t *wq,	/* Queue message was written on */
+	mblk_t *mp)	/* The message itself */
+{
+	wrsmdstr_t *ssp =	/* Pointer to this stream's structure */
+		(wrsmdstr_t *)wq->q_ptr;
+	wrsmd_t *wrsmdp;	/* WRSMD device (RSM controller) pointer */
+
+	D1("wrsmdwput: wq 0x%p, mp 0x%p, ssp 0x%p", (void *)wq,
+	    (void *)mp, (void *)ssp);
+	D5("wrsmdwput: time 0x%llx", gethrtime());
+	TNF_PROBE_1(wrsmdwput_start, "RSMPI", "wrsmdwput start",
+		tnf_long, length, msgdsize(mp));
+
+	switch (DB_TYPE(mp)) {
+		case M_DATA:
+			/*
+			 * This message is a raw data item.  Most messages
+			 * end up in this case.
+			 */
+
+			/*
+			 * It is possible that an interrupt thread handling
+			 * incoming packets has taken wrsmdstruplock or
+			 * ipq_rwlock, sent a packet upstream (usually to
+			 * ar), then looped back down to here.  Meanwhile,
+			 * a separate thread could be attempting to modify
+			 * the ipq shortcut, which first takes
+			 * ssp->ss_lock, then takes wrsmdstriplock.  This
+			 * causes a deadlock.  Avoid this by enqueueing the
+			 * message if the ssp->ss_lock can't be taken
+			 * immediately.
+			 */
+			if (!mutex_tryenter(&ssp->ss_lock)) {
+				(void) putq(wq, mp);
+				break;
+			}
+
+			wrsmdp = ssp->ss_wrsmdp;
+
+			/* If we're not supposed to get raw data, toss it. */
+
+			if (((ssp->ss_flags &
+			    (WRSMD_SLRAW | WRSMD_SLFAST)) == 0) ||
+			    (ssp->ss_state != DL_IDLE) || (wrsmdp == NULL)) {
+				merror(wq, mp, EPROTO);
+				mutex_exit(&ssp->ss_lock);
+				TNF_PROBE_1(wrsmdwput_end, "RSMPI",
+				    "wrsmdwput end; type M_DATA",
+				    tnf_string, type, "M_DATA");
+				break;
+			}
+
+			/*
+			 * If any msgs already enqueued or the interface will
+			 * loop back up the message (due to wrsmd_promisc),
+			 * then enqueue the msg.  (Can't handle promiscuous
+			 * here because it takes wrsmdstruplock, which might
+			 * cause a recursive rw_enter.) Otherwise just xmit it
+			 * directly.
+			 */
+			if (wq->q_first || wrsmdp->wrsmd_promisc) {
+				(void) putq(wq, mp);
+			} else {
+				dl_rsm_addr_t addr;
+				ushort_t sap;
+
+				if (mp = wrsmdstrip(mp, &addr, &sap))
+					wrsmdstart(wrsmdp, mp, addr,
+					    sap, 1);
+			}
+
+			mutex_exit(&ssp->ss_lock);
+			TNF_PROBE_1(wrsmdwput_end, "RSMPI",
+			    "wrsmdwput end; type M_DATA",
+			    tnf_string, type, "M_DATA");
+			break;
+
+		case M_PROTO:
+		case M_PCPROTO:
+			/*
+			 * This message is a DLPI control message.  In
+			 * almost all cases, we just put this on the queue
+			 * for the service routine to process.  Why?
+			 * Basically, because processing of some of the
+			 * M_PROTO/M_PCPROTO requests involves acquiring
+			 * internal locks that are also held across
+			 * upstream putnext calls.  For instance,
+			 * wrsmdread() holds wrsmdstruplock and may
+			 * hold wrsmdp->wrsmd_ipq_rwlock when it
+			 * calls putnext().  In some cases, IP's or
+			 * TCP's put routine, which was called from
+			 * putnext() could immediately loop back, do a
+			 * downward putnext() of a M_PROTO message, and end
+			 * up right here.  If we were then to try and
+			 * process that message, we could try to obtain
+			 * wrsmdstruplock or wrsmd_ipq_rwlock, which we
+			 * already have, thus leading to a recursive
+			 * mutex_enter panic.
+			 *
+			 * To prevent this, we put the M_PROTO message on
+			 * the service routine's queue.  When the service
+			 * routine runs, it will be in a different context
+			 * which can safely acquire the appropriate locks.
+			 */
+
+			(void) putq(wq, mp);
+			TNF_PROBE_1(wrsmdwput_end, "RSMPI",
+			    "wrsmdwput end; type M_PROTO",
+			    tnf_string, type, "M_PROTO");
+			break;
+
+		case M_IOCTL:
+			/*
+			 * ARP may do a downward putnext() of an M_IOCTL
+			 * stream in response to an ack sent upstream
+			 * by this module while holding internal locks.
+			 * As described above, we avoid a recursive mutex
+			 * enter by handling it in the service routine.
+			 * We do an immediate nak for unrecognized ioctls.
+			 */
+			if (!wrsmdioctlimmediate(wq, mp))
+				(void) putq(wq, mp);
+
+			TNF_PROBE_1(wrsmdwput_end, "RSMPI",
+			    "wrsmdwput end; type M_IOCTL",
+			    tnf_string, type, "M_IOCTL");
+			break;
+
+		case M_FLUSH:
+			/*
+			 * This message is asking us to flush our queues,
+			 * probably in preparation for taking down the
+			 * stream.
+			 */
+			if (*mp->b_rptr & FLUSHW) {
+				flushq(wq, FLUSHALL);
+				*mp->b_rptr &= ~FLUSHW;
+			}
+			if (*mp->b_rptr & FLUSHR)
+				qreply(wq, mp);
+			else
+				freemsg(mp);
+			TNF_PROBE_1(wrsmdwput_end, "RSMPI",
+			    "wrsmdwput end; type M_FLUSH",
+			    tnf_string, type, "M_FLUSH");
+			break;
+
+		default:
+			freemsg(mp);
+			TNF_PROBE_1(wrsmdwput_end, "RSMPI",
+			    "wrsmdwput end; type unknown",
+			    tnf_string, type, "UNKNOWN");
+			break;
+	}
+
+	D1("wrsmdwput: returning 0");
+	TNF_PROBE_1(wrsmdwput_end, "RSMPI", "wrsmdwput end",
+	    tnf_long, rval, 0);
+	return (0);
+}
+
+/*
+ * Write service routine.  This routine processes any messages put on the queue
+ * via a putq() in the write put routine.  It also handles any destinations put
+ * on the destination run queue.
+ */
+static int
+wrsmdwsrv(queue_t *wq)	/* Queue we should service */
+{
+	mblk_t *mp;
+	wrsmdstr_t *ssp;
+	wrsmd_t *wrsmdp;
+	wrsmd_dest_t *rd;
+	int isdel;
+
+	D1("wrsmdwsrv: wq 0x%p", (void *)wq);
+	D5("wrsmdwsrv: time 0x%llx", gethrtime());
+
+	ssp = (wrsmdstr_t *)wq->q_ptr;
+	wrsmdp = ssp->ss_wrsmdp;
+
+	D1("wrsmdwsrv: ssp 0x%p, wrsmdp 0x%p (cltr %d)", (void *)ssp,
+	    (void *)wrsmdp, wrsmdp ? wrsmdp->wrsmd_ctlr_id : -1);
+	TNF_PROBE_0(wrsmdwsrv_start, "RSMPI", "wrsmdwsrv start");
+
+	/*
+	 * Process message queue.
+	 */
+	while (mp = getq(wq)) {
+		switch (DB_TYPE(mp)) {
+			case M_DATA:
+				D5("wrsmdwsrv: got data time 0x%llx",
+				    gethrtime());
+				if (wrsmdp) {
+					dl_rsm_addr_t addr;
+					ushort_t sap;
+
+					if (mp = wrsmdstrip(mp, &addr, &sap))
+						wrsmdstart(wrsmdp, mp,
+						    addr, sap, 0);
+				} else
+					freemsg(mp);
+				TNF_PROBE_1(wrsmdwsrv_msg, "RSMPI",
+				    "wrsmdwsrv qcount; type M_DATA",
+				    tnf_string, type, "M_DATA");
+				break;
+
+			case M_PROTO:
+			case M_PCPROTO:
+				D5("wrsmdwsrv: got proto time 0x%llx",
+				    gethrtime());
+				wrsmdproto(wq, mp);
+				wrsmdp = ssp->ss_wrsmdp;
+				TNF_PROBE_1(wrsmdwsrv_msg, "RSMPI",
+				    "wrsmdwsrv qcount; type M_PROTO",
+				    tnf_string, type, "M_PROTO");
+				break;
+
+			case M_IOCTL:
+				/*
+				 * This message is an ioctl.
+				 * We do not hold locks around the whole ioctl
+				 * processing, as the holding of locks across a
+				 * qreply() of ack or nak is a violation of the
+				 * SVR4 DDI/DKI
+				 */
+				wrsmdioctl(wq, mp);
+
+				TNF_PROBE_1(wrsmdwsrv_msg, "RSMPI",
+				    "wrsmdwsrv msg; type M_IOCTL",
+				    tnf_string, type, "M_IOCTL");
+				break;
+
+
+			default: /* nothing is working at ths point */
+				TNF_PROBE_1(wrsmdwsrv_msg, "RSMPI",
+				    "wrsmdwsrv qcount; type unknown",
+				    tnf_string, type, "UNKNOWN");
+				ASSERT(0);
+				break;
+		}
+	}
+
+	/*
+	 * Traverse list of scheduled destinations, looking for work to do
+	 */
+
+	if (wrsmdp == NULL) {
+		D1("wrsmdwsrv: wrsmdp NULL, returning 0");
+		TNF_PROBE_0(wrsmdwsrv_end, "RSMPI", "wrsmdwsrv end");
+		return (0);
+	}
+
+	/*
+	 * rd's refcnt is incremented by GETRUNQ
+	 */
+	GETRUNQ(rd, isdel, wrsmdp);
+	while (rd) {
+		int oldstate, delete;
+
+		if (isdel) {
+			D2("wrsmdwsrv: dest 0x%p being deleted, ignored",
+			    (void *)rd);
+			GETRUNQ(rd, isdel, wrsmdp);
+			continue;
+		}
+
+		mutex_enter(&rd->rd_lock);
+		delete = 0;
+
+		oldstate = wrsmdgetstate(rd);
+		D5("wrsmdwsrv: running state %s time 0x%llx",
+		    WRSMD_STATE_STR(oldstate), gethrtime());
+		switch (oldstate) {
+
+		case WRSMD_STATE_S_XFER: {
+			mutex_enter(&rd->rd_xmit_lock);
+			if (rd->rd_queue_h)
+				wrsmdxfer(wrsmdp, rd);
+			else
+				wrsmdsetstate(rd, WRSMD_STATE_W_READY);
+			mutex_exit(&rd->rd_xmit_lock);
+
+			break;
+		}
+
+		case WRSMD_STATE_S_REQ_CONNECT: {
+			if (wrsmdcrexfer(wrsmdp, rd) != 0 ||
+			    wrsmdsconn(wrsmdp, rd, 0) != 0) {
+				wrsmdsetstate(rd, WRSMD_STATE_DELETING);
+				delete = 1;
+			}
+			break;
+		}
+
+		case WRSMD_STATE_S_NEWCONN: {
+			if (wrsmdcrexfer(wrsmdp, rd) != 0 ||
+			    wrsmdconnxfer(wrsmdp, rd) != 0 ||
+			    wrsmdsaccept(wrsmdp, rd) != 0) {
+				wrsmdsetstate(rd, WRSMD_STATE_DELETING);
+				delete = 1;
+			}
+			break;
+		}
+
+		case WRSMD_STATE_S_CONNXFER_ACCEPT: {
+			if (wrsmdconnxfer(wrsmdp, rd) != 0 ||
+			    wrsmdsaccept(wrsmdp, rd) != 0) {
+				wrsmdsetstate(rd, WRSMD_STATE_DELETING);
+				delete = 1;
+			}
+			break;
+		}
+
+		case WRSMD_STATE_S_CONNXFER_ACK: {
+			if (wrsmdconnxfer(wrsmdp, rd) != 0 ||
+			    wrsmdsack(wrsmdp, rd) != 0) {
+				wrsmdsetstate(rd, WRSMD_STATE_DELETING);
+				delete = 1;
+			}
+			break;
+		}
+
+		/*
+		 * Delete this connection.  This causes a message
+		 * to be sent to the remote side when RSM_SENDQ_DESTROY
+		 * is called, so there is no need to send an additional
+		 * message.
+		 */
+		case WRSMD_STATE_S_DELETE: {
+			wrsmdsetstate(rd, WRSMD_STATE_DELETING);
+			delete = 1;
+
+			break;
+		}
+
+		/*
+		 * Retry the SCONN.
+		 */
+		case WRSMD_STATE_S_SCONN: {
+			if (wrsmdsconn(wrsmdp, rd, 1) != 0) {
+				wrsmdsetstate(rd, WRSMD_STATE_DELETING);
+				delete = 1;
+			}
+			break;
+		}
+
+		default:
+			D1("wrsmd: bad state %s in wsrv "
+			    " for dest 0x%lx", WRSMD_STATE_STR(oldstate),
+			    (uintptr_t)rd);
+			cmn_err(CE_PANIC, "wrsmd: bad state %s in wsrv "
+			    " for dest 0x%lx", WRSMD_STATE_STR(oldstate),
+			    (uintptr_t)rd);
+			break;
+		}
+
+		mutex_exit(&rd->rd_lock);
+
+		if (delete)
+			wrsmdfreedest(wrsmdp, rd->rd_rsm_addr);
+
+		UNREFDEST(rd);
+
+		GETRUNQ(rd, isdel, wrsmdp);
+	}
+
+	D1("wrsmdwsrv: returning 0");
+	TNF_PROBE_0(wrsmdwsrv_end, "RSMPI", "wrsmdwsrv end");
+	return (0);
+}
+
+
+/*
+ * Discard all messages queued for output to this destination, updating
+ * error statistics as appropriate.
+ */
+static void
+wrsmddumpqueue(wrsmd_t *wrsmdp,	/* WRSMD device (RSM controller) pointer */
+	wrsmd_dest_t *rd)	/* Destination pointer */
+{
+	mblk_t *mp, *nmp;
+
+	ASSERT(MUTEX_HELD(&rd->rd_xmit_lock));
+
+	D1("wrsmddumpqueue: wrsmdp 0x%p (ctlr %d), rd 0x%p (addr %ld)",
+	    (void *)wrsmdp,
+	    wrsmdp ? wrsmdp->wrsmd_ctlr_id : -1, (void *)rd, rd->rd_rsm_addr);
+	TNF_PROBE_2(wrsmddumpqueue_start, "RSMPI",
+	    "wrsmddumpqueue start",
+	    tnf_long, wrsmdp, (tnf_long_t)wrsmdp, tnf_long, rd, (tnf_long_t)rd);
+
+	mp = rd->rd_queue_h;
+	rd->rd_queue_h = NULL;
+	rd->rd_queue_len = 0;
+
+	while (mp) {
+		nmp = mp->b_next;
+		mp->b_next = mp->b_prev = NULL;
+		freemsg(mp);
+		wrsmdp->wrsmd_oerrors++;
+		mp = nmp;
+	}
+	D1("wrsmddumpqueue: done");
+	TNF_PROBE_0(wrsmddumpqueue_end, "RSMPI", "wrsmddumpqueue end");
+}
+
+/*
+ * Execute an ioctl request from the service routine.
+ */
+static void
+wrsmdioctl(queue_t *wq, mblk_t *mp)
+{
+
+	struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
+	wrsmdstr_t *ssp = (wrsmdstr_t *)wq->q_ptr;
+	rsm_addr_t dest;
+
+	D1("wrsmdioctl: wq 0x%p, mp 0x%p", (void *)wq, (void *)mp);
+
+	switch (iocp->ioc_cmd) {
+	case DLIOCRAW:		/* raw M_DATA mode */
+		D1("wrsmdioctl: DLIOCRAW");
+		mutex_enter(&ssp->ss_lock);
+		ssp->ss_flags |= WRSMD_SLRAW;
+		mutex_exit(&ssp->ss_lock);
+		miocack(wq, mp, 0, 0);
+		break;
+
+	case DL_IOC_HDR_INFO:	/* M_DATA "fastpath" info request */
+		D1("wrsmdioctl: DL_IOC_HDR_INFO");
+		wrsmd_dl_ioc_hdr_info(wq, mp);
+		break;
+
+	case WRSMD_DUMP_IOCTL:
+		mutex_enter(&ssp->ss_lock);
+		dump_ioctl();
+		mutex_exit(&ssp->ss_lock);
+		miocack(wq, mp, 0, 0);
+		break;
+
+	case WRSMD_DUMP_DEST:
+		if ((mp->b_cont == NULL) ||
+			((mp->b_cont->b_wptr - mp->b_cont->b_rptr) !=
+			    sizeof (dest))) {
+			miocnak(wq, mp, 0, EINVAL);
+			break;
+		}
+
+		bcopy(mp->b_cont->b_rptr, &dest, sizeof (dest));
+		mutex_enter(&ssp->ss_lock);
+		dump_dest(dest);
+		mutex_exit(&ssp->ss_lock);
+		miocack(wq, mp, 0, 0);
+		break;
+
+	default:
+		D1("wrsmdioctl: unknown ioctl 0x%x", iocp->ioc_cmd);
+		miocnak(wq, mp, 0, EINVAL);
+		break;
+	}
+	D1("wrsmdioctl: done");
+}
+
+/*
+ * Execute an immediate ioctl request from the put routine.
+ * Does not take any locks.  Returns FALSE if not handled immediately.
+ */
+static int
+wrsmdioctlimmediate(queue_t *wq, mblk_t *mp)
+{
+	struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
+
+	D1("wrsmdioctlimmediate: wq 0x%p, mp 0x%p", (void *)wq, (void *)mp);
+
+	switch (iocp->ioc_cmd) {
+	case DLIOCRAW:		/* raw M_DATA mode */
+	case DL_IOC_HDR_INFO:	/* M_DATA "fastpath" info request */
+	case WRSMD_DUMP_IOCTL:
+	case WRSMD_DUMP_DEST:
+		/* handle from the service routine */
+		return (B_FALSE);
+
+	default:
+		D1("wrsmdioctlimmediate: unknown ioctl 0x%x", iocp->ioc_cmd);
+		miocnak(wq, mp, 0, EINVAL);
+		break;
+	}
+	D1("wrsmdioctlimmediate: done");
+
+	return (B_TRUE);
+}
+
+/*
+ * M_DATA "fastpath" info request.
+ * Following the M_IOCTL mblk should come a DL_UNITDATA_REQ mblk.  We ack with
+ * an M_IOCACK pointing to the original DL_UNITDATA_REQ mblk, followed by an
+ * mblk containing the raw medium header corresponding to the destination
+ * address.  Subsequently, we may receive M_DATA msgs which start with this
+ * header and may send up M_DATA msgs containing the network-layer data.
+ * This is all selectable on a per-Stream basis.
+ */
+static void
+wrsmd_dl_ioc_hdr_info(queue_t *wq, mblk_t *mp)
+{
+	mblk_t *nmp;
+	wrsmdstr_t *ssp;
+	wrsmddladdr_t *dlap;
+	dl_unitdata_req_t *dludp;
+	struct ether_header *headerp;
+	wrsmd_t *wrsmdp;
+	uint32_t off, len;
+	int minsize;
+
+	D1("wrsmd_dl_ioc_hdr_info: wq 0x%p, mp 0x%p", (void *)wq, (void *)mp);
+
+	ssp = (wrsmdstr_t *)wq->q_ptr;
+	minsize = sizeof (dl_unitdata_req_t) + WRSMD_DEVICE_ADDRL;
+
+	mutex_enter(&ssp->ss_lock);
+
+	/*
+	 * Sanity check the request.
+	 */
+	if ((mp->b_cont == NULL) ||
+	    (MBLKL(mp->b_cont) < minsize) ||
+		(((union DL_primitives *)mp->b_cont->b_rptr)->dl_primitive !=
+		    DL_UNITDATA_REQ) ||
+	    ((wrsmdp = ssp->ss_wrsmdp) == NULL)) {
+		mutex_exit(&ssp->ss_lock);
+		miocnak(wq, mp, 0, EINVAL);
+		D1("wrsmd_dl_ioc_hdr_info: bad req, done");
+		return;
+	}
+
+	/*
+	 * Sanity check the DL_UNITDATA_REQ destination address
+	 * offset and length values.
+	 */
+	dludp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
+	off = dludp->dl_dest_addr_offset;
+	len = dludp->dl_dest_addr_length;
+	if (!MBLKIN(mp->b_cont, off, len) || (len != WRSMD_DEVICE_ADDRL)) {
+		mutex_exit(&ssp->ss_lock);
+		miocnak(wq, mp, 0, EINVAL);
+		D1("wrsmd_dl_ioc_hdr_info: bad addr, done");
+		return;
+	}
+
+	dlap = (wrsmddladdr_t *)(mp->b_cont->b_rptr + off);
+
+	/*
+	 * Allocate a new mblk to hold the medium header.
+	 */
+	if ((nmp = allocb(sizeof (struct ether_header), BPRI_MED))
+	    == NULL) {
+		mutex_exit(&ssp->ss_lock);
+		miocnak(wq, mp, 0, ENOMEM);
+		D1("wrsmd_dl_ioc_hdr_info: ENOMEM, done");
+		return;
+	}
+	nmp->b_wptr += sizeof (struct ether_header);
+
+	/*
+	 * Fill in the medium header.
+	 */
+	headerp = (struct ether_header *)nmp->b_rptr;
+
+	ether_copy(&(dlap->dl_addr), &(headerp->ether_dhost));
+	ether_copy(&(wrsmdp->wrsmd_rsm_addr.m.ether.addr),
+	    &(headerp->ether_shost));
+	headerp->ether_type = dlap->dl_sap;
+
+	/*
+	 * Link new mblk in after the "request" mblks.
+	 */
+	linkb(mp, nmp);
+
+	ssp->ss_flags |= WRSMD_SLFAST;
+
+	wrsmdsetipq(wrsmdp);
+
+	mutex_exit(&ssp->ss_lock);
+
+	miocack(wq, mp, MBLKL(mp->b_cont)+MBLKL(nmp), 0);
+
+	D1("wrsmd_dl_ioc_hdr_info: done");
+}
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * E N D       BASIC STREAMS OPERATIONS                          *
+ *                                                               *
+ * ****************************************************************
+ */
+
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * B E G I N   DLPI OPERATIONS                                   *
+ *                                                               *
+ * ****************************************************************
+ */
+
+/*
+ * Parse and execute a DLPI request.
+ */
+static void
+wrsmdproto(
+	queue_t *wq,	/* Queue the request came in on */
+	mblk_t *mp)	/* The request message itself */
+{
+	union DL_primitives *dlp;
+	wrsmdstr_t *ssp;
+	uint32_t prim;
+
+	D1("wrsmdproto: wq 0x%p, mp 0x%p", (void *)wq, (void *)mp);
+	TNF_PROBE_2(wrsmdproto_start, "RSMPI", "wrsmdproto start",
+	    tnf_long, wq, (tnf_long_t)wq, tnf_long, mp, (tnf_long_t)mp);
+
+	ssp = (wrsmdstr_t *)wq->q_ptr;
+	dlp = (union DL_primitives *)mp->b_rptr;
+	/* Make sure we at least have dlp->dl_primitive */
+	if ((caddr_t)mp->b_wptr <
+	    (caddr_t)&dlp->dl_primitive + sizeof (dlp->dl_primitive)) {
+		dlerrorack(wq, mp, 0xffff, DL_BADPRIM, 0);
+		return;
+	}
+	prim = dlp->dl_primitive;
+
+	mutex_enter(&ssp->ss_lock);
+
+	switch (prim) {
+		case DL_UNITDATA_REQ:
+			TNF_PROBE_1(wrsmdproto_prim, "RSMPI",
+			    "wrsmdproto prim",
+			    tnf_string, DL_UNITDATA_REQ, "");
+			wrsmdudreq(wq, mp);
+			break;
+
+		case DL_ATTACH_REQ:
+			TNF_PROBE_1(wrsmdproto_prim, "RSMPI",
+			    "wrsmdproto prim",
+			    tnf_string, DL_ATTACH_REQ, "");
+			wrsmdareq(wq, mp);
+			break;
+
+		case DL_DETACH_REQ:
+			TNF_PROBE_1(wrsmdproto_prim, "RSMPI",
+			    "wrsmdproto prim",
+			    tnf_string, DL_DETACH_REQ, "");
+			wrsmddreq(wq, mp);
+			break;
+
+		case DL_ENABMULTI_REQ:
+			TNF_PROBE_1(wrsmdproto_prim, "RSMPI",
+			    "wrsmdproto prim",
+			    tnf_string, DL_ENABMULTI_REQ, "");
+			/* Accept enable-multicast-request */
+			dlokack(wq, mp, DL_ENABMULTI_REQ);
+			break;
+
+		case DL_DISABMULTI_REQ:
+			TNF_PROBE_1(wrsmdproto_prim, "RSMPI",
+			    "wrsmdproto prim",
+			    tnf_string, DL_DISABMULTI_REQ, "");
+			/* Accept disable-multicast-request */
+			dlokack(wq, mp, DL_DISABMULTI_REQ);
+			break;
+
+		case DL_BIND_REQ:
+			TNF_PROBE_1(wrsmdproto_prim, "RSMPI",
+			    "wrsmdproto prim",
+			    tnf_string, DL_BIND_REQ, "");
+			wrsmdbreq(wq, mp);
+			break;
+
+		case DL_UNBIND_REQ:
+			TNF_PROBE_1(wrsmdproto_prim, "RSMPI",
+			    "wrsmdproto prim",
+			    tnf_string, DL_UNBIND_REQ, "");
+			wrsmdubreq(wq, mp);
+			break;
+
+		case DL_INFO_REQ:
+			TNF_PROBE_1(wrsmdproto_prim, "RSMPI",
+			    "wrsmdproto prim",
+			    tnf_string, DL_INFO_REQ, "");
+			wrsmdireq(wq, mp);
+			break;
+
+		case DL_PROMISCON_REQ:
+			TNF_PROBE_1(wrsmdproto_prim, "RSMPI",
+			    "wrsmdproto prim",
+			    tnf_string, DL_PROMISCON_REQ, "");
+			wrsmdponreq(wq, mp);
+			break;
+
+		case DL_PROMISCOFF_REQ:
+			TNF_PROBE_1(wrsmdproto_prim, "RSMPI",
+			    "wrsmdproto prim",
+			    tnf_string, DL_PRIMISCOFF_REQ, "");
+			wrsmdpoffreq(wq, mp);
+			break;
+
+		case DL_PHYS_ADDR_REQ:
+			TNF_PROBE_1(wrsmdproto_prim, "RSMPI",
+			    "wrsmdproto prim",
+			    tnf_string, DL_PHYS_ADDR_REQ, "");
+			wrsmdpareq(wq, mp);
+			break;
+
+		default:
+			TNF_PROBE_1(wrsmdproto_prim, "RSMPI",
+			    "wrsmdproto prim",
+			    tnf_string, DL_UNSUPPORTED, "");
+			dlerrorack(wq, mp, prim, DL_UNSUPPORTED, 0);
+			break;
+	}
+
+	mutex_exit(&ssp->ss_lock);
+
+	D1("wrsmdproto: done");
+	TNF_PROBE_1(wrsmdproto_end, "RSMPI", "wrsmdproto end",
+	    tnf_string, completed, "");
+}
+
+/*
+ * START OF GENERIC DLPI INTERFACE ROUTINES
+ */
+
+/*
+ * DLPI attach request (attach stream to physical device)
+ *
+ * The PPA is the RSM controller id, which equals the DLPI device instance
+ * number.
+ */
+static void
+wrsmdareq(queue_t *wq, mblk_t *mp)
+{
+	wrsmdstr_t *ssp;
+	union DL_primitives *dlp;
+	wrsmd_t *wrsmdp;
+	uint32_t ppa;
+	timeout_id_t tmoid;
+
+	D1("wrsmdareq: wq 0x%p, mp 0x%p", (void *)wq, (void *)mp);
+
+	ssp = (wrsmdstr_t *)wq->q_ptr;
+	dlp = (union DL_primitives *)mp->b_rptr;
+
+	if (MBLKL(mp) < DL_ATTACH_REQ_SIZE) {
+		dlerrorack(wq, mp, DL_ATTACH_REQ, DL_BADPRIM, 0);
+		D1("wrsmdareq: bad size, done");
+		return;
+	}
+
+	if (ssp->ss_state != DL_UNATTACHED) {
+		dlerrorack(wq, mp, DL_ATTACH_REQ, DL_OUTSTATE, 0);
+		D1("wrsmdareq: bad state, done");
+		return;
+	}
+
+	ppa = dlp->attach_req.dl_ppa;
+
+	/*
+	 * Valid ppa?
+	 */
+	if (ppa == -1 || qassociate(wq, ppa) != 0) {
+		dlerrorack(wq, mp, dlp->dl_primitive, DL_BADPPA, 0);
+		D1("wrsmdareq: bad ppa, done");
+		return;
+	}
+	mutex_enter(&wrsmddevlock);
+	for (wrsmdp = wrsmddev; wrsmdp;
+	    wrsmdp = wrsmdp->wrsmd_nextp) {
+		if (ppa == wrsmdp->wrsmd_ctlr_id) {
+			break;
+		}
+	}
+	mutex_exit(&wrsmddevlock);
+	/* when qassociate() succeeds, ppa must be present */
+	ASSERT(wrsmdp);
+
+	/*
+	 * The teardown timeout now reschedules itself, so we
+	 * have to go to great lengths to kill it.
+	 */
+	mutex_enter(&wrsmdp->wrsmd_lock);
+	tmoid = wrsmdp->wrsmd_teardown_tmo_id;
+
+	while (tmoid) {
+		/*
+		 * A timeout is scheduled to teardown the device -
+		 * cancel it, as device is once again in use.
+		 */
+		mutex_exit(&wrsmdp->wrsmd_lock);
+
+		(void) untimeout(tmoid);
+		/*
+		 * untimeout guarantees the either the function was
+		 * cancelled, or it has completed.  If timeout was
+		 * cancelled before the function ran, the timout id will
+		 * not have changed.
+		 */
+		mutex_enter(&wrsmdp->wrsmd_lock);
+
+		if (tmoid == wrsmdp->wrsmd_teardown_tmo_id)
+			wrsmdp->wrsmd_teardown_tmo_id = 0;
+		tmoid = wrsmdp->wrsmd_teardown_tmo_id;
+	}
+
+	/*
+	 * Has WRSMD device (RSM controller) been initialized?  Do so if
+	 * necessary.
+	 */
+	if ((wrsmdp->wrsmd_flags & WRSMDREGHANDLER) == 0) {
+		if (wrsmdinit(wrsmdp)) {
+			mutex_exit(&wrsmdp->wrsmd_lock);
+			dlerrorack(wq, mp, dlp->dl_primitive,
+				DL_INITFAILED, 0);
+			D1("wrsmdareq: init failed, done");
+			/* dissociate on failure */
+			(void) qassociate(wq, -1);
+			return;
+		}
+	}
+	if (ssp->ss_flags & WRSMD_SLALLPHYS)
+		wrsmdp->wrsmd_promisc++;
+
+	wrsmdp->wrsmd_attached_streams++;
+	mutex_exit(&wrsmdp->wrsmd_lock);
+
+
+	/*
+	 * Save pointer to this queue if this destination doesn't already
+	 * have one
+	 */
+
+	mutex_enter(&wrsmdp->wrsmd_runq_lock);
+	if (wrsmdp->wrsmd_wq == NULL)
+		wrsmdp->wrsmd_wq = wq;
+	mutex_exit(&wrsmdp->wrsmd_runq_lock);
+
+	/*
+	 * Set link to WRSMD device (RSM controller) and update our state.
+	 */
+	ssp->ss_wrsmdp = wrsmdp;
+	ssp->ss_state = DL_UNBOUND;
+
+	dlokack(wq, mp, DL_ATTACH_REQ);
+
+	D1("wrsmdareq: done");
+}
+
+/*
+ * DLPI detach request (detach stream from physical device)
+ */
+static void
+wrsmddreq(queue_t *wq, mblk_t *mp)
+{
+	wrsmdstr_t *ssp;
+
+	D1("wrsmddreq: wq 0x%p, mp 0x%p", (void *)wq, (void *)mp);
+
+	ssp = (wrsmdstr_t *)wq->q_ptr;
+
+	if (MBLKL(mp) < DL_DETACH_REQ_SIZE) {
+		dlerrorack(wq, mp, DL_DETACH_REQ, DL_BADPRIM, 0);
+		D1("wrsmddreq: bad size, done");
+		return;
+	}
+
+	if (ssp->ss_state != DL_UNBOUND) {
+		dlerrorack(wq, mp, DL_DETACH_REQ, DL_OUTSTATE, 0);
+		D1("wrsmddreq: bad state, done");
+		return;
+	}
+
+	wrsmddodetach(ssp);
+	(void) qassociate(wq, -1);
+	dlokack(wq, mp, DL_DETACH_REQ);
+
+	D1("wrsmddreq: done");
+}
+
+/*
+ * Detach a Stream from an interface.
+ */
+static void
+wrsmddodetach(wrsmdstr_t *ssp)
+{
+	wrsmdstr_t *tslp;
+	wrsmd_t *wrsmdp;
+
+	D1("wrsmddodetach: ssp 0x%p", (void *)ssp);
+
+	ASSERT(MUTEX_HELD(&ssp->ss_lock));
+	ASSERT(ssp->ss_wrsmdp);
+
+	wrsmdp = ssp->ss_wrsmdp;
+
+	mutex_enter(&wrsmdp->wrsmd_lock);
+
+	/*
+	 * Need to protect this assignment with wrsmd_lock mutex in case
+	 * of concurrent execution of detach for different streams, to avoid
+	 * detaching device structure until all streams detached.
+	 */
+	ssp->ss_wrsmdp = NULL;
+
+	wrsmdp->wrsmd_attached_streams--;
+
+	if (ssp->ss_flags & WRSMD_SLALLPHYS)
+		wrsmdp->wrsmd_promisc--;
+
+	/*
+	 * Detach from device structure.
+	 * Uninit the device when no other streams are attached to it.
+	 */
+	rw_enter(&wrsmdstruplock, RW_READER);
+
+	for (tslp = wrsmdstrup; tslp; tslp = tslp->ss_nextp)
+		if (tslp->ss_wrsmdp == wrsmdp)
+			break;
+
+	mutex_enter(&wrsmdp->wrsmd_runq_lock);
+	if (tslp)
+		wrsmdp->wrsmd_wq = WR(tslp->ss_rq);
+	else
+		wrsmdp->wrsmd_wq = NULL;
+	mutex_exit(&wrsmdp->wrsmd_runq_lock);
+
+	/* Make sure teardown only scheduled once. */
+	if (wrsmdp->wrsmd_attached_streams == 0) {
+		/*
+		 * Schedule a teardown.  This allows queues to destinations
+		 * through this controller to drain, and keeps the data
+		 * structures around in case a new connection to this
+		 * device is about to occur.
+		 */
+		ASSERT(tslp == NULL);
+		wrsmdp->wrsmd_teardown_tmo_id = timeout(wrsmdteardown_tmo,
+		    (caddr_t)wrsmdp, wrsmdp->wrsmd_param.wrsmd_teardown_tmo);
+	}
+
+	rw_exit(&wrsmdstruplock);
+
+	mutex_exit(&wrsmdp->wrsmd_lock);
+
+	ssp->ss_state = DL_UNATTACHED;
+
+	wrsmdsetipq(wrsmdp);
+
+	D1("wrsmddodetach: done");
+}
+
+/*
+ * DLPI bind request (register interest in a particular address & SAP)
+ */
+static void
+wrsmdbreq(queue_t *wq, mblk_t *mp)
+{
+	wrsmdstr_t *ssp;
+	union DL_primitives *dlp;
+	wrsmd_t *wrsmdp;
+	wrsmddladdr_t wrsmdaddr;
+	ushort_t sap;
+	uint32_t xidtest;
+
+	D1("wrsmdbreq: wq 0x%p, mp 0x%p", (void *)wq, (void *)mp);
+
+	ssp = (wrsmdstr_t *)wq->q_ptr;
+
+	if (MBLKL(mp) < DL_BIND_REQ_SIZE) {
+		dlerrorack(wq, mp, DL_BIND_REQ, DL_BADPRIM, 0);
+		D1("wrsmdbreq: bad size, done");
+		return;
+	}
+
+	if (ssp->ss_state != DL_UNBOUND) {
+		dlerrorack(wq, mp, DL_BIND_REQ, DL_OUTSTATE, 0);
+		D1("wrsmdbreq: bad state, done");
+		return;
+	}
+
+	dlp = (union DL_primitives *)mp->b_rptr;
+	wrsmdp = ssp->ss_wrsmdp;
+	xidtest = dlp->bind_req.dl_xidtest_flg;
+
+	ASSERT(wrsmdp);
+
+	if (xidtest) {
+		dlerrorack(wq, mp, DL_BIND_REQ, DL_NOAUTO, 0);
+		D1("wrsmdbreq: bad xidtest, done");
+		return;
+	}
+
+	if (dlp->bind_req.dl_service_mode != DL_CLDLS) {
+		dlerrorack(wq, mp, DL_BIND_REQ, DL_UNSUPPORTED, 0);
+		return;
+	}
+
+	if (dlp->bind_req.dl_sap > MEDIUMSAP_MAX) {
+		dlerrorack(wq, mp, dlp->dl_primitive, DL_BADSAP, 0);
+		D1("wrsmdbreq: bad sap, done");
+		return;
+	}
+	sap = (ushort_t)dlp->bind_req.dl_sap;
+
+	/*
+	 * Save SAP value for this Stream and change state.
+	 */
+	ssp->ss_sap = sap;
+	ssp->ss_state = DL_IDLE;
+
+	wrsmdaddr.dl_sap = sap;
+	wrsmdaddr.dl_addr = wrsmdp->wrsmd_rsm_addr.m.ether.addr;
+	dlbindack(wq, mp, (t_scalar_t)sap, (caddr_t)&wrsmdaddr,
+	    WRSMD_DEVICE_ADDRL, 0, 0);
+
+	wrsmdsetipq(wrsmdp);
+
+	D1("wrsmdbreq: done");
+}
+
+/*
+ * DLPI unbind request (cancel interest in a particular local address & SAP)
+ */
+static void
+wrsmdubreq(queue_t *wq, mblk_t *mp)
+{
+	wrsmdstr_t *ssp;
+
+	D1("wrsmdubreq: wq 0x%p, mp 0x%p", (void *)wq, (void *)mp);
+
+	ssp = (wrsmdstr_t *)wq->q_ptr;
+
+	if (MBLKL(mp) < DL_UNBIND_REQ_SIZE) {
+		dlerrorack(wq, mp, DL_UNBIND_REQ, DL_BADPRIM, 0);
+		D1("wrsmdubreq: bad size, done");
+		return;
+	}
+
+	if (ssp->ss_state != DL_IDLE) {
+		dlerrorack(wq, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0);
+		D1("wrsmdubreq: bad state, done");
+		return;
+	}
+
+	ssp->ss_state = DL_UNBOUND;
+	ssp->ss_sap = 0;
+
+	(void) putnextctl1(RD(wq), M_FLUSH, FLUSHRW);
+
+	dlokack(wq, mp, DL_UNBIND_REQ);
+
+	wrsmdsetipq(ssp->ss_wrsmdp);
+
+	D1("wrsmdubreq: done");
+}
+
+/*
+ * DLPI device information request
+ */
+static void
+wrsmdireq(queue_t *wq, mblk_t *mp)
+{
+	wrsmdstr_t *ssp;
+	dl_info_ack_t *dlip;
+	wrsmddladdr_t *dlap;
+	void *dlbcastap;
+	size_t size;
+
+	D1("wrsmdireq: wq 0x%p, mp 0x%p", (void *)wq, (void *)mp);
+
+	ssp = (wrsmdstr_t *)wq->q_ptr;
+
+	if (MBLKL(mp) < DL_INFO_REQ_SIZE) {
+		dlerrorack(wq, mp, DL_INFO_REQ, DL_BADPRIM, 0);
+		D1("wrsmdireq: bad size, done");
+		return;
+	}
+
+	/*
+	 * Exchange current msg for a DL_INFO_ACK.
+	 */
+	size = sizeof (dl_info_ack_t) + WRSMD_DEVICE_ADDRL + WRSMD_BCAST_ADDRL;
+	if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_INFO_ACK)) == NULL) {
+		D1("wrsmdireq: bad mexchange, done");
+		return;
+	}
+
+	/*
+	 * Fill in the DL_INFO_ACK fields and reply.
+	 */
+	dlip = (dl_info_ack_t *)mp->b_rptr;
+	*dlip = wrsmdinfoack;
+	dlip->dl_current_state = ssp->ss_state;
+
+	/*
+	 * fill in the local DLSAP address, if connected to a controller
+	 */
+	dlap = (wrsmddladdr_t *)(mp->b_rptr + dlip->dl_addr_offset);
+	if (ssp->ss_wrsmdp) {
+		ether_copy(&(ssp->ss_wrsmdp->wrsmd_rsm_addr.m.ether.addr),
+		    &(dlap->dl_addr));
+		dlip->dl_max_sdu =
+		    ssp->ss_wrsmdp->wrsmd_param.wrsmd_buffer_size -
+		    WRSMD_CACHELINE_SIZE;
+	} else {
+		ether_copy(&wrsmdbadaddr, &(dlap->dl_addr));
+		mutex_enter(&wrsmddevlock);
+		ASSERT(wrsmdminbuflen != 0);
+		dlip->dl_max_sdu = wrsmdminbuflen - WRSMD_CACHELINE_SIZE;
+		mutex_exit(&wrsmddevlock);
+	}
+	dlap->dl_sap = ssp->ss_sap;
+
+	/*
+	 * fill in the broadcast address; it's at least short aligned
+	 */
+	dlbcastap = (void *)(mp->b_rptr + dlip->dl_brdcst_addr_offset);
+	ether_copy(&wrsmdbcastaddr, dlbcastap);
+
+	ASSERT(((unsigned char *)dlbcastap + WRSMD_BCAST_ADDRL) ==
+	    (mp->b_rptr + size));
+
+	qreply(wq, mp);
+
+	D1("wrsmdireq: done");
+}
+
+/*
+ * DLPI enable promiscuous mode request
+ *
+ * We only snoop and deliver messages that are generated by this node
+ * or received by this mode.  Unlike promiscuous mode on a bus-based
+ * network, we do not see (and therefore cannot deliver) messages
+ * destined for other nodes.
+ */
+static void
+wrsmdponreq(queue_t *wq, mblk_t *mp)
+{
+	wrsmdstr_t *ssp;
+
+	D1("wrsmdponreq: wq 0x%p, mp 0x%p", (void *)wq, (void *)mp);
+
+	ssp = (wrsmdstr_t *)wq->q_ptr;
+
+	if (MBLKL(mp) < DL_PROMISCON_REQ_SIZE) {
+		dlerrorack(wq, mp, DL_PROMISCON_REQ, DL_BADPRIM, 0);
+		D1("wrsmdponreq: bad size, done");
+		return;
+	}
+
+	switch (((dl_promiscon_req_t *)mp->b_rptr)->dl_level) {
+		case DL_PROMISC_PHYS:
+			if (!(ssp->ss_flags & WRSMD_SLALLPHYS)) {
+				ssp->ss_flags |= WRSMD_SLALLPHYS;
+				if (ssp->ss_wrsmdp) {
+					mutex_enter(
+					    &ssp->ss_wrsmdp->wrsmd_lock);
+					ssp->ss_wrsmdp->wrsmd_promisc++;
+					mutex_exit(&ssp->ss_wrsmdp->wrsmd_lock);
+				}
+			}
+			break;
+
+		case DL_PROMISC_SAP:
+			ssp->ss_flags |= WRSMD_SLALLSAP;
+			break;
+
+		default:
+			dlerrorack(wq, mp, DL_PROMISCON_REQ,
+				DL_NOTSUPPORTED, 0);
+			D1("wrsmdponreq: option not supported, done");
+			return;
+	}
+
+	if (ssp->ss_wrsmdp)
+		wrsmdsetipq(ssp->ss_wrsmdp);
+
+	dlokack(wq, mp, DL_PROMISCON_REQ);
+
+	D1("wrsmdponreq: done");
+}
+
+/*
+ * DLPI disable promiscuous mode request
+ */
+static void
+wrsmdpoffreq(queue_t *wq, mblk_t *mp)
+{
+	wrsmdstr_t *ssp;
+	int flag;
+
+	D1("wrsmdpoffreq: wq 0x%p, mp 0x%p", (void *)wq, (void *)mp);
+
+	ssp = (wrsmdstr_t *)wq->q_ptr;
+
+	if (MBLKL(mp) < DL_PROMISCOFF_REQ_SIZE) {
+		dlerrorack(wq, mp, DL_PROMISCOFF_REQ, DL_BADPRIM, 0);
+		D1("wrsmdpoffreq: bad size, done");
+		return;
+	}
+
+	switch (((dl_promiscoff_req_t *)mp->b_rptr)->dl_level) {
+		case DL_PROMISC_PHYS:
+			flag = WRSMD_SLALLPHYS;
+			break;
+
+		case DL_PROMISC_SAP:
+			flag = WRSMD_SLALLSAP;
+			break;
+
+		default:
+			dlerrorack(wq, mp, DL_PROMISCOFF_REQ,
+				DL_NOTSUPPORTED, 0);
+			D1("wrsmdpoffreq: option not supported, done");
+			return;
+	}
+
+	if ((ssp->ss_flags & flag) == 0) {
+		dlerrorack(wq, mp, DL_PROMISCOFF_REQ, DL_NOTENAB, 0);
+		D1("wrsmdpoffreq: mode not on, done");
+		return;
+	}
+
+	ssp->ss_flags &= ~flag;
+
+	if ((flag & WRSMD_SLALLPHYS) && ssp->ss_wrsmdp) {
+		mutex_enter(&ssp->ss_wrsmdp->wrsmd_lock);
+		ssp->ss_wrsmdp->wrsmd_promisc--;
+		mutex_exit(&ssp->ss_wrsmdp->wrsmd_lock);
+	}
+
+	if (ssp->ss_wrsmdp)
+		wrsmdsetipq(ssp->ss_wrsmdp);
+
+	dlokack(wq, mp, DL_PROMISCOFF_REQ);
+
+	D1("wrsmdpoffreq: done");
+}
+
+/*
+ * DLPI get physical address request
+ *
+ * Return the PPA (RSM hardware address) of the WRSMD device (RSM controller)
+ * to which this stream is attached.
+ */
+static void
+wrsmdpareq(queue_t *wq, mblk_t *mp)
+{
+	wrsmdstr_t *ssp;
+	union DL_primitives *dlp;
+	uint32_t type;
+	wrsmd_t *wrsmdp;
+
+	D1("wrsmdpareq: wq 0x%p, mp 0x%p", (void *)wq, (void *)mp);
+
+	ssp = (wrsmdstr_t *)wq->q_ptr;
+
+	if (MBLKL(mp) < DL_PHYS_ADDR_REQ_SIZE) {
+		dlerrorack(wq, mp, DL_PHYS_ADDR_REQ, DL_BADPRIM, 0);
+		D1("wrsmdpareq: bad size, done");
+		return;
+	}
+
+	dlp = (union DL_primitives *)mp->b_rptr;
+	type = dlp->physaddr_req.dl_addr_type;
+	wrsmdp = ssp->ss_wrsmdp;
+
+	if (wrsmdp == NULL) {
+		dlerrorack(wq, mp, DL_PHYS_ADDR_REQ, DL_OUTSTATE, 0);
+		D1("wrsmdpareq: bad state, done");
+		return;
+	}
+
+	switch (type) {
+		case DL_FACT_PHYS_ADDR:
+		case DL_CURR_PHYS_ADDR:
+			dlphysaddrack(wq, mp,
+			    (void *)&(wrsmdp->wrsmd_rsm_addr.m.ether.addr),
+			    sizeof (wrsmdp->wrsmd_rsm_addr.m.ether.addr));
+			D1("wrsmdpareq: done");
+			return;
+
+		default:
+			dlerrorack(wq, mp, DL_PHYS_ADDR_REQ,
+				DL_NOTSUPPORTED, 0);
+			D1("wrsmdpoffreq: option not supported, done");
+			return;
+	}
+}
+
+/*
+ * DLPI unit data send request
+ */
+static void
+wrsmdudreq(queue_t *wq, mblk_t *mp)
+{
+	wrsmdstr_t *ssp;
+	register wrsmd_t *wrsmdp;
+	register dl_unitdata_req_t *dludp;
+	mblk_t *nmp;
+	wrsmddladdr_t *dlap;
+	uint32_t off, len;
+
+	ushort_t sap;
+	dl_rsm_addr_t addr;
+
+	D1("wrsmdudreq: wq 0x%p, mp 0x%p", (void *)wq, (void *)mp);
+
+	ssp = (wrsmdstr_t *)wq->q_ptr;
+	wrsmdp = ssp->ss_wrsmdp;
+
+	if (wrsmdp == NULL) {
+		dlerrorack(wq, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
+		D1("wrsmdudreq: bad state, done");
+		return;
+	}
+
+	dludp = (dl_unitdata_req_t *)mp->b_rptr;
+
+	off = dludp->dl_dest_addr_offset;
+	len = dludp->dl_dest_addr_length;
+
+	/*
+	 * Validate destination address format.
+	 */
+	if (!MBLKIN(mp, off, len) || (len != WRSMD_DEVICE_ADDRL)) {
+		dluderrorind(wq, mp, (uchar_t *)(mp->b_rptr + off), len,
+		    DL_BADADDR, 0);
+#ifdef DEBUG_WRSMD
+		dlap = (wrsmddladdr_t *)(mp->b_rptr + off);
+		ether_copy(&(dlap->dl_addr), &(addr.m.ether.addr));
+		addr.m.ether.zero = 0;
+		sap = (uint16_t)((((uchar_t *)(&dlap->dl_sap))[0] << 8) |
+					((uchar_t *)(&dlap->dl_sap))[1]);
+		D2("wrsmdudreq bad addr: ADDRL %ld addr len %d, rsm addr 0x%lx "
+		    "sap 0x%x",
+		    WRSMD_DEVICE_ADDRL, len, addr.m.rsm, sap);
+		D1("wrsmdudreq: bad addr, done");
+#endif
+		return;
+	}
+
+	/*
+	 * Error if no M_DATA follows.
+	 */
+	nmp = mp->b_cont;
+	if (nmp == NULL) {
+		dluderrorind(wq, mp, (uchar_t *)(mp->b_rptr + off), len,
+			DL_BADDATA, 0);
+		D1("wrsmdudreq: bad data, done");
+		return;
+	}
+
+	/* Extract address information. */
+
+	dlap = (wrsmddladdr_t *)(mp->b_rptr + off);
+
+	ether_copy(&(dlap->dl_addr), &(addr.m.ether.addr));
+	addr.m.ether.zero = 0;
+	sap = (uint16_t)((((uchar_t *)(&dlap->dl_sap))[0] << 8) |
+				((uchar_t *)(&dlap->dl_sap))[1]);
+
+	/* Discard DLPI header. */
+
+	freeb(mp);
+
+	/*
+	 * Transmit message.
+	 */
+	wrsmdstart(wrsmdp, nmp, addr, sap, 0);
+
+	D1("wrsmdudreq: done");
+}
+
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * E N D       DLPI OPERATIONS                                   *
+ *                                                               *
+ * ****************************************************************
+ */
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * B E G I N   HIGH LEVEL PROTOCOL INTERFACE AND UTILITIES       *
+ *                                                               *
+ * ****************************************************************
+ */
+
+
+/*
+ * An outgoing raw packet has a header at the beginning, telling us the
+ * destination address and SAP.  Since this header is not used by the
+ * Wildcat hardware in this form, we call it the "fake hardware header".
+ *
+ * This routine parses the fake hardware header at the start of mp, strips
+ * the header from mp then returns address and sap.  It returns a pointer
+ * to the stripped mblk, which may or may not be the same pointer which was
+ * passed in, or NULL if there's no data to send.
+ */
+
+static mblk_t *
+wrsmdstrip(
+	mblk_t *mp,		/* Packet to parse & strip header from */
+	dl_rsm_addr_t *addrp,	/* Address packet addressed to (returned) */
+	ushort_t *sapp)		/* SAP packet addressed to (returned) */
+{
+	D1("wrsmdstrip: mp 0x%p", (void *)mp);
+
+	if (MBLKIN(mp, 0, sizeof (struct ether_header))) {
+		struct ether_header *mh = (struct ether_header *)mp->b_rptr;
+
+		/*
+		 * Parse header; it's at least short aligned.
+		 */
+
+		ether_copy(&(mh->ether_dhost), &(addrp->m.ether.addr));
+		addrp->m.ether.zero = 0;
+		*sapp = mh->ether_type;
+
+		/* Strip off header */
+
+		mp->b_rptr += sizeof (struct ether_header);
+
+		/*
+		 * If there's nothing left in this mblk, and there are more
+		 * following, get rid of it.  If there's nothing left, and
+		 * there aren't more following, we have a zero-length
+		 * message; return an error.  (A following mblk might
+		 * conceivably be empty, giving us a zero-length message as
+		 * well; we don't check for this.)
+		 */
+		if (mp->b_rptr == mp->b_wptr) {
+			if (mp->b_cont != NULL) {
+				mblk_t *nmp;
+
+				nmp = mp->b_cont;
+				freeb(mp);
+				D1("wrsmdstrip: returning 1");
+				return (nmp);
+			} else {
+				freemsg(mp);
+				D1("wrsmdstrip: returning 0");
+				return (NULL);
+			}
+		} else {
+			D1("wrsmdstrip: returning 1");
+			return (mp);
+		}
+	} else {
+		D1("wrsmdstrip: returning 0");
+		freemsg(mp);
+		return (NULL);
+	}
+}
+
+
+
+/*
+ * Queue the message to the proper destination structure, creating the
+ * destination if necessary.  Discard the message if required.
+ * If from_put is true, and there are no other messages queued to this
+ * destination or being transmitted, start this message transmitting.
+ * Schedule destination for service, if necessary. The function returns
+ * true is message was successfully queued.
+ */
+boolean_t
+wrsmdqueuemsg(wrsmd_t *wrsmdp, mblk_t *orig_mp, dl_rsm_addr_t addr,
+    ushort_t sap, int from_put, boolean_t copy)
+{
+	wrsmd_dest_t *rd;
+	int isdel = 0;
+	int isnew = 0;
+	timeout_id_t tmoid;
+	mblk_t *mp;
+
+	if (copy) {
+		mp = dupmsg(orig_mp);
+		if (!mp)
+			return (B_FALSE);
+	} else {
+		mp = orig_mp;
+	}
+
+	/* Find destination structure for this message */
+	D1("wrsmdqueuemsg: ctlr %d\n", wrsmdp->wrsmd_ctlr_id);
+
+	MAKEDEST(rd, isdel, isnew, wrsmdp, addr.m.wrsm.addr);
+
+	if (isdel) {
+		wrsmdp->wrsmd_oerrors++;
+		if (copy) {
+			freemsg(mp);
+		}
+		DERR("wrsmdqueuemsg: TOSS!!! dest being deleted, "
+		    "toss packet, done");
+		TNF_PROBE_1(wrsmdqueuemsg_end, "RSMPI",
+		    "wrsmdqueuemsg end; failure destbeingdel",
+		    tnf_string, failure, "destbeingdel");
+		return (B_FALSE);
+	} else if (isnew) {
+		if (rd == NULL) {
+			wrsmdp->wrsmd_oerrors++;
+			if (copy) {
+				freemsg(mp);
+			}
+			DERR("wrsmdqueuemsg: TOSS!!! can't mkdest, "
+			    "toss packet, done");
+			TNF_PROBE_1(wrsmdqueuemsg_end, "RSMPI",
+			    "wrsmdqueuemsg end; failure cantmkdest",
+			    tnf_string, failure, "cantmkdest");
+			return (B_FALSE);
+		}
+	}
+
+	/* if state was new, move to req_connect */
+	(void) wrsmdmovestate(rd, WRSMD_STATE_NEW, WRSMD_STATE_S_REQ_CONNECT);
+
+	mutex_enter(&rd->rd_xmit_lock);
+
+	/* Make sure we don't have too many queued already */
+
+	if (rd->rd_queue_len >=
+	    wrsmdp->wrsmd_param.wrsmd_max_queued_pkts) {
+		if (copy) {
+			freemsg(mp);
+		}
+		wrsmdp->wrsmd_oerrors++;
+		wrsmdp->wrsmd_maxq_drops++;
+		DERR("wrsmdqueuemsg: TOSS!!! too many queued (%d), "
+		    "toss packet, done",
+		    rd->rd_queue_len);
+		mutex_exit(&rd->rd_xmit_lock);
+		UNREFDEST(rd);
+		TNF_PROBE_1(wrsmdqueuemsg_end, "RSMPI",
+		    "wrsmdqueuemsg end; failure 2manyqueued",
+		    tnf_string, failure, "2manyqueued");
+		return (B_FALSE);
+	}
+
+	if (rd->rd_queue_h == NULL)
+		rd->rd_queue_h = mp;
+	else
+		rd->rd_queue_t->b_next = mp;
+	rd->rd_queue_t = mp;
+	rd->rd_queue_len++;
+
+	/*
+	 * Since we're making a singly-linked list of mblks hanging off the
+	 * destination structure, we can get away with stashing the destination
+	 * SAP in the b_prev pointer of the mblk.  This is pretty disgusting,
+	 * but is much more efficient than the alternative: allocating a new
+	 * structure with space for the SAP and a pointer to the mblk, and
+	 * making a list of those instead.
+	 */
+
+	mp->b_prev = (mblk_t *)(uintptr_t)sap;
+
+	wrsmdp->wrsmd_starts++;
+
+	if (wrsmdisstate(rd, WRSMD_STATE_W_READY)) {
+		if (from_put) {
+			wrsmdp->wrsmd_start_xfers++;
+			wrsmdxfer(wrsmdp, rd);
+		} else
+			wrsmdsetstate_nosrv(rd, WRSMD_STATE_S_XFER);
+
+	} else if (wrsmdisstate(rd, WRSMD_STATE_W_FQE)) {
+		if (wrsmdavailfqe(rd)) {
+			tmoid = rd->rd_fqe_tmo_id;
+			rd->rd_fqe_tmo_id = 0;
+			rd->rd_tmo_int = 0;
+			mutex_exit(&rd->rd_xmit_lock);
+			if (tmoid)
+				(void) untimeout(tmoid);
+			mutex_enter(&rd->rd_xmit_lock);
+
+			if (from_put) {
+				wrsmdp->wrsmd_start_xfers++;
+				wrsmdxfer(wrsmdp, rd);
+			} else
+				wrsmdsetstate_nosrv(rd, WRSMD_STATE_S_XFER);
+		} else {
+			/*
+			 * no FQEs available, return to waiting state
+			 */
+			wrsmdsetstate(rd, WRSMD_STATE_W_FQE);
+		}
+	}
+
+	mutex_exit(&rd->rd_xmit_lock);
+
+	UNREFDEST(rd);
+
+	return (B_TRUE);
+}
+
+
+/*
+ * Verify whether this is a valid message.  Determine whether this is a
+ * broadcast message; send message to each recipient.  Handle promiscuous
+ * mode.
+ */
+static void
+wrsmdstart(wrsmd_t *wrsmdp, mblk_t *mp, dl_rsm_addr_t addr, ushort_t sap,
+    int from_put)
+{
+	int i;
+	boolean_t retval;
+
+	D1("wrsmdstart: wrsmdp 0x%p (cltr %d), mp 0x%p, rsmaddr %ld, sap 0x%x, "
+	    "from_put %d", (void *)wrsmdp, wrsmdp ? wrsmdp->wrsmd_ctlr_id : -1,
+	    (void *)mp, addr.m.rsm, sap, from_put);
+	TNF_PROBE_5(wrsmdstart_start, "RSMPI", "wrsmdstart start",
+	    tnf_ulong, wrsmdp, (ulong_t)wrsmdp, tnf_ulong, mp,
+	    (ulong_t)mp, tnf_uint, addr.m.rsm, addr.m.rsm, tnf_uint,
+	    sap, sap, tnf_int, from_put, from_put);
+
+	/* Make sure we're not sending to ourselves */
+
+	if (addr.m.rsm == wrsmdp->wrsmd_rsm_addr.m.rsm) {
+		wrsmdp->wrsmd_oerrors++;
+		freemsg(mp);
+		DERR("wrsmdstart: TOSS!!! sending to ourselves, toss packet, "
+		    "done");
+		TNF_PROBE_1(wrsmdstart_end, "RSMPI",
+		    "wrsmdstart end; failure sendtoself",
+		    tnf_string, failure, "sendtoself");
+		return;
+	}
+
+	/* Make sure message is contiguous in memory */
+
+	if (mp->b_cont) {
+		mblk_t *nmp;
+
+		nmp = msgpullup(mp, -1);
+		freemsg(mp);
+
+		if (nmp == NULL) {
+			wrsmdp->wrsmd_pullup_fail++;
+			wrsmdp->wrsmd_oerrors++;
+			DERR("wrsmdstart: TOSS!!! can't pullup message, "
+			    "toss packet, "
+			    "done");
+			return;
+		}
+		wrsmdp->wrsmd_pullup++;
+		mp = nmp;
+	}
+
+	/* Make sure message isn't too big */
+
+	if (MBLKL(mp) > (wrsmdp->wrsmd_param.wrsmd_buffer_size -
+	    WRSMD_CACHELINE_SIZE)) {
+		wrsmdp->wrsmd_oerrors++;
+		freemsg(mp);
+		DERR("wrsmdstart: TOSS!!! message too big, toss packet, done");
+		TNF_PROBE_1(wrsmdstart_end, "RSMPI",
+		    "wrsmdstart end; failure msgtoobig",
+		    tnf_string, failure, "msgtoobig");
+		return;
+	}
+
+	/*
+	 * Send message to each addressee (normally there is just one).
+	 */
+
+	/* Loop message back up if we're in promiscuous mode */
+	if (wrsmdp->wrsmd_promisc) {
+		mblk_t *nmp;
+
+		if (nmp = dupmsg(mp))
+			wrsmdpromsendup(wrsmdp, nmp, addr,
+			    wrsmdp->wrsmd_rsm_addr, sap);
+	}
+
+	if (addr.m.rsm > RSM_MAX_DESTADDR) {
+		/*
+		 * handle broadcast and multicast messages
+		 */
+		rsm_addr_t addr_list[RSM_MAX_DESTADDR];
+		uint_t num_addrs;
+		boolean_t copy;
+
+		D1("wrsmdstart: broadcast message; collect peers");
+
+		if (RSM_GET_PEERS(wrsmdp->wrsmd_ctlr,
+		    addr_list, RSM_MAX_DESTADDR, &num_addrs) != RSM_SUCCESS) {
+			D1("wrsmdstart: cannot collect list of peers "
+			    "for broadcast");
+			wrsmdp->wrsmd_oerrors++;
+			freemsg(mp);
+			return;
+		}
+
+		ASSERT(num_addrs <= RSM_MAX_DESTADDR);
+
+		/*
+		 * Make a copy of the message for all but the last
+		 * recipient.  Don't broadcast to the local node.
+		 */
+		for (i = 0; i < num_addrs; i++) {
+			if (addr_list[i] == wrsmdp->wrsmd_rsm_addr.m.rsm)
+				continue;
+			/*
+			 * If this is the last node or if this is the
+			 * second to last and the last is ourselves,
+			 * don't make a copy of the message.
+			 */
+			if ((i == (num_addrs - 1)) ||
+			    ((i == (num_addrs - 2)) &&
+			    addr_list[i+1] == wrsmdp->wrsmd_rsm_addr.m.rsm)) {
+				copy = B_FALSE;
+			} else {
+				copy = B_TRUE;
+			}
+			addr.m.rsm = addr_list[i];
+			retval = wrsmdqueuemsg(wrsmdp, mp, addr, sap,
+			    from_put, copy);
+			if (copy == B_FALSE && retval == B_FALSE) {
+				freemsg(mp);
+			}
+		}
+
+	} else {
+		retval = wrsmdqueuemsg(wrsmdp, mp, addr, sap,
+		    from_put, B_FALSE);
+		if (retval == B_FALSE) {
+			freemsg(mp);
+		}
+	}
+
+	D1("wrsmdstart: done");
+	TNF_PROBE_1(wrsmdstart_end, "RSMPI", "wrsmdstart end",
+	    tnf_string, completed, "");
+}
+
+
+/*
+ * These macros are used in several places in wrsmdsendup().
+ */
+
+/*
+ * Return 1 if the stream pointed to by wrsmdstr is connected to wrsmdp and
+ * interested in this sap.
+ */
+#define	WRSMDSAPMATCH(wrsmdp, wrsmdstr, sap)	\
+	(((wrsmdstr)->ss_wrsmdp == wrsmdp) &&	\
+	((wrsmdstr)->ss_sap == (sap) ||		\
+	    ((wrsmdstr)->ss_flags & WRSMD_SLALLSAP)))
+
+/*
+ * Return 1 if the stream pointed to by wrsmdstr is connected to wrsmdp,
+ * interested in all saps, and in physical promiscuous mode.
+ */
+#define	WRSMDPROMMATCH(wrsmdp, wrsmdstr)		\
+	(((wrsmdstr)->ss_wrsmdp == wrsmdp) &&		\
+	    ((wrsmdstr)->ss_flags & WRSMD_SLALLSAP) &&	\
+	    ((wrsmdstr)->ss_flags & WRSMD_SLALLPHYS))
+/*
+ * Do appropriate processing to send message msg up stream wrsmdstr.
+ * "name" is the name of the calling routine, used for debugging messages;
+ * to, from and sap are the packet's to address, from address, and SAP.
+ */
+#define	WRSMDMSGPROC(wrsmdp, wrsmdstr, msg, name, to, from, sap) {	\
+	D2(name " : checking msg 0x%p queue 0x%p",			\
+	    (void *)(msg), (void *)(wrsmdstr)->ss_rq);			\
+	if ((wrsmdstr)->ss_flags & WRSMD_SLFAST) {			\
+		(void) putnext((wrsmdstr)->ss_rq, (msg));		\
+	} else if ((wrsmdstr)->ss_flags & WRSMD_SLRAW) {		\
+		if ((msg) = wrsmdaddhdr(wrsmdp, (msg), (to),		\
+		    (from), (sap)))					\
+			(void) putnext((wrsmdstr)->ss_rq,		\
+			    (msg));					\
+	} else if ((msg) = wrsmdaddudind(wrsmdp, (msg), (to),		\
+	    (from), (sap))) {						\
+		D2(name " : sending msg 0x%p up queue 0x%p",		\
+		    (void *)(msg), (void *)(wrsmdstr)->ss_rq);		\
+		(void) putnext((wrsmdstr)->ss_rq, (msg));		\
+	}								\
+}
+
+/*
+ * Send packet upstream.
+ */
+static void
+wrsmdsendup(
+	wrsmd_t *wrsmdp,	/* WRSMD device (RSM controller) pointer */
+	mblk_t *mp,	/* Message to send up */
+	dl_rsm_addr_t to,	/* Address packet was sent to */
+	dl_rsm_addr_t from,	/* Address packet was received from */
+	ushort_t sap)	/* Packet's SAP */
+{
+	wrsmdstr_t *ssp, *nssp;
+	mblk_t *nmp;
+
+	D1("wrsmdsendup: wrsmdp 0x%p (cltr %d), mp 0x%p, to %ld, from %ld, "
+	    "sap 0x%x", (void *)wrsmdp, wrsmdp->wrsmd_ctlr_id, (void *)mp,
+	    to.m.rsm, from.m.rsm, sap);
+	TNF_PROBE_5(wrsmdsendup_start, "RSMPI", "wrsmdsendup start",
+	    tnf_ulong, wrsmdp, (ulong_t)wrsmdp, tnf_ulong, mp, (ulong_t)mp,
+	    tnf_long, to.m.rsm, to.m.rsm, tnf_long, from.m.rsm, from.m.rsm,
+	    tnf_long, sap, sap);
+
+	/*
+	 * While holding a reader lock on the linked list of streams
+	 * structures, attempt to match the address criteria for each stream
+	 * and pass up the DL_UNITDATA_IND.
+	 */
+
+	rw_enter(&wrsmdstruplock, RW_READER);
+
+	/*
+	 * This is pretty tricky.  If there are multiple streams that want
+	 * this packet, we have to make a new copy for all but one of them
+	 * (we can send the original packet up one of the streams).  However,
+	 * if we do things the straightforward way:
+	 *
+	 *	while (stream wants packet)
+	 *		newmsg = copy (msg);
+	 *		send newmsg up stream
+	 *		go to next stream
+	 *	free oldmsg
+	 *
+	 * we end up always doing a copy, even if (as is usually the case)
+	 * the packet only goes to one stream.  This is bad.  Thus what we do
+	 * is the following:
+	 *
+	 *	Find a stream that wants this packet.  If there aren't any,
+	 *		we're done.
+	 *	For each other stream that wants this packet, make a copy of
+	 *		it and send it up.
+	 *	Finally, send the original packet up the first stream we found.
+	 */
+
+	for (ssp = wrsmdstrup; ssp; ssp = ssp->ss_nextp) {
+		D1("wrsmdsendup ssp->ss_sap 0x%x flags 0x%x", ssp->ss_sap,
+		    ssp->ss_flags);
+		if (WRSMDSAPMATCH(wrsmdp, ssp, sap))
+			break;
+	}
+
+	if (ssp) {
+		TNF_PROBE_3(wrsmdsendup_SMPfor, "RSMPI",
+		    "wrsmdsendup SMPfor", tnf_long, to.m.rsm, to.m.rsm,
+		    tnf_long, from.m.rsm, from.m.rsm, tnf_long, sap, sap);
+		for (nssp = ssp->ss_nextp; nssp; nssp = nssp->ss_nextp) {
+			D1("wrsmdsendup nssp->ss_sap 0x%x flags 0x%x",
+			    nssp->ss_sap, ssp->ss_flags);
+			if (WRSMDSAPMATCH(wrsmdp, nssp, sap) &&
+			    canputnext((queue_t *)nssp->ss_rq) &&
+			    (nmp = dupmsg(mp))) {
+				WRSMDMSGPROC(wrsmdp, nssp, nmp, "wrsmdsendup",
+				    to, from, sap);
+			}
+		}
+		TNF_PROBE_1(wrsmdsendup_SMPforend, "RSMPI",
+		    "wrsmdsendup SMPforend", tnf_string, completed, "");
+		/*
+		 * Do the last one.
+		 */
+		if (canputnext((queue_t *)ssp->ss_rq)) {
+			TNF_PROBE_5(wrsmdsendup_SMPlast, "RSMPI",
+			    "wrsmdsendup SMPlast", tnf_ulong, ssp, (ulong_t)ssp,
+			    tnf_ulong, mp, (ulong_t)mp, tnf_long, to.m.rsm,
+			    to.m.rsm, tnf_long, from.m.rsm, from.m.rsm,
+			    tnf_long, sap, sap);
+			WRSMDMSGPROC(wrsmdp, ssp, mp, "wrsmdsendup", to, from,
+			    sap);
+			TNF_PROBE_1(wrsmdsendup_SMPlastend, "RSMPI",
+			    "wrsmdsendup SMPlastend", tnf_string, completed,
+			    "");
+		} else
+			freemsg(mp);
+	} else
+		freemsg(mp);
+
+	rw_exit(&wrsmdstruplock);
+
+	D1("wrsmdsendup: done");
+	TNF_PROBE_1(wrsmdsendup_end, "RSMPI", "wrsmdsendup end",
+	    tnf_string, completed, "");
+}
+
+/*
+ * Send outgoing packet upstream to promiscuous mode readers.  This routine
+ * is an exact duplicate of wrsmdsendup(), above, except that we use
+ * WRSMDPROMMATCH instead of WRSMDSAPMATCH.  (The difference is that
+ * the latter only selects streams which are in promiscuous mode; this
+ * keeps IP from getting its own packets back, since we don't check the
+ * destination addresses when sending packets upstream.)
+ */
+static void
+wrsmdpromsendup(
+	wrsmd_t *wrsmdp,	/* WRSMD device (RSM controller) pointer */
+	mblk_t *mp,	/* Message to send up */
+	dl_rsm_addr_t to,	/* Address packet was sent to */
+	dl_rsm_addr_t from,	/* Address packet was received from */
+	ushort_t sap)	/* Packet's SAP */
+{
+	wrsmdstr_t *ssp, *nssp;
+	mblk_t *nmp;
+
+	D1("wrsmdpromsendup: wrsmdp 0x%p (cltr %d), mp 0x%p, to %ld, from %ld, "
+	    "sap 0x%x", (void *)wrsmdp, wrsmdp ? wrsmdp->wrsmd_ctlr_id : -1,
+	    (void *)mp, to.m.rsm,
+	    from.m.rsm, sap);
+
+	/*
+	 * While holding a reader lock on the linked list of streams structures,
+	 * attempt to match the address criteria for each stream
+	 * and pass up the DL_UNITDATA_IND.
+	 */
+
+	rw_enter(&wrsmdstruplock, RW_READER);
+
+	/*
+	 * See explanation above of why this is somewhat less than
+	 * straightforward.
+	 */
+
+	for (ssp = wrsmdstrup; ssp; ssp = ssp->ss_nextp) {
+		if (WRSMDPROMMATCH(wrsmdp, ssp))
+			break;
+	}
+
+	if (ssp) {
+		for (nssp = ssp->ss_nextp; nssp; nssp = nssp->ss_nextp)
+			if (WRSMDPROMMATCH(wrsmdp, nssp) &&
+			    canputnext((queue_t *)nssp->ss_rq) &&
+			    (nmp = dupmsg(mp)))
+				WRSMDMSGPROC(wrsmdp, nssp, nmp,
+				    "wrsmdpromsendup", to, from, sap);
+		/*
+		 * Do the last one.
+		 */
+		if (canputnext((queue_t *)ssp->ss_rq)) {
+			WRSMDMSGPROC(wrsmdp, ssp, mp, "wrsmdpromsendup",
+			    to, from, sap);
+		} else
+			freemsg(mp);
+	} else
+		freemsg(mp);
+
+	rw_exit(&wrsmdstruplock);
+
+	D1("wrsmdpromsendup: done");
+}
+
+/*
+ * Prefix msg with a DL_UNITDATA_IND mblk and return the new msg.  If we
+ * can't, free the msg and return NULL.
+ */
+static mblk_t *
+wrsmdaddudind(
+	wrsmd_t *wrsmdp,	/* WRSMD device (RSM controller) pointer */
+	mblk_t *mp,		/* Message to add indication to */
+	dl_rsm_addr_t to,	/* Address packet was sent to */
+	dl_rsm_addr_t from,	/* Address packet was received from */
+	ushort_t sap)	/* Packet's SAP */
+{
+	dl_unitdata_ind_t *dludindp;
+	wrsmddladdr_t *dlap;
+	mblk_t *nmp;
+	size_t size;
+
+	D1("wrsmdaddudind: wrsmdp 0x%p (cltr %d), mp 0x%p, to %ld, from %ld, "
+	    "sap 0x%x", (void *)wrsmdp, wrsmdp->wrsmd_ctlr_id, (void *)mp,
+	    to.m.rsm, from.m.rsm, sap);
+
+	/*
+	 * Allocate an M_PROTO mblk for the DL_UNITDATA_IND.
+	 * Allocate enough room in mblk that IP/TCP can prepend their
+	 * own headers as well.
+	 */
+	size = sizeof (dl_unitdata_ind_t) + WRSMD_DEVICE_ADDRL +
+	    WRSMD_DEVICE_ADDRL;
+	if ((nmp = allocb(WRSMDHEADROOM + size, BPRI_LO)) == NULL) {
+		wrsmdp->wrsmd_ierrors++;
+		freemsg(mp);
+		D1("wrsmdaddudind: bad allocb, returning NULL");
+		return (NULL);
+	}
+	DB_TYPE(nmp) = M_PROTO;
+	nmp->b_wptr = nmp->b_datap->db_lim;
+	nmp->b_rptr = nmp->b_wptr - size;
+
+	/*
+	 * Construct a DL_UNITDATA_IND primitive.
+	 */
+	dludindp = (dl_unitdata_ind_t *)nmp->b_rptr;
+	dludindp->dl_primitive = DL_UNITDATA_IND;
+	dludindp->dl_dest_addr_length = WRSMD_DEVICE_ADDRL;
+	dludindp->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t);
+	dludindp->dl_src_addr_length = WRSMD_DEVICE_ADDRL;
+	dludindp->dl_src_addr_offset = sizeof (dl_unitdata_ind_t) +
+	    WRSMD_DEVICE_ADDRL;
+
+	dludindp->dl_group_address = 0;
+
+	/* plug in dest addr */
+	dlap = (wrsmddladdr_t *)(nmp->b_rptr + sizeof (dl_unitdata_ind_t));
+	ether_copy(&(to.m.ether.addr), &(dlap->dl_addr));
+	dlap->dl_sap = sap;
+
+	/* plug in src addr */
+	dlap = (wrsmddladdr_t *)
+	    (nmp->b_rptr + sizeof (dl_unitdata_ind_t) + WRSMD_DEVICE_ADDRL);
+	ether_copy(&(from.m.ether.addr), &(dlap->dl_addr));
+	dlap->dl_sap = 0; /* we don't have this info */
+
+	/*
+	 * Link the M_PROTO and M_DATA together.
+	 */
+	linkb(nmp, mp);
+
+	D1("wrsmdaddudind: new header follows");
+
+	D3D(nmp->b_rptr, MBLKL(nmp));
+	D1("wrsmdaddudind: returning 0x%p", (void *)nmp);
+
+	return (nmp);
+}
+
+/*
+ * Prefix msg with a "fake hardware header" (either in-place, or in a
+ * separate mblk)and return the new msg.  If we can't, free the msg and
+ * return NULL.
+ */
+static mblk_t *
+wrsmdaddhdr(
+	wrsmd_t *wrsmdp,	/* WRSMD device (RSM controller) pointer */
+	mblk_t *mp,		/* Message to add indication to */
+	dl_rsm_addr_t to,	/* Address packet was sent to */
+	dl_rsm_addr_t from,	/* Address packet was received from */
+	ushort_t sap)		/* Packet's SAP */
+{
+	mblk_t *nmp;
+	struct ether_header *headerp;
+
+	D1("wrsmdaddhdr: wrsmdp 0x%p (cltr %d), mp 0x%p, to %ld, from %ld, "
+	    "sap 0x%x", (void *)wrsmdp, wrsmdp ? wrsmdp->wrsmd_ctlr_id : -1,
+	    (void *)mp, to.m.rsm, from.m.rsm, sap);
+
+	/*
+	 * Create link-level header by either prepending it onto the
+	 * data if possible, or allocating a new mblk if not.
+	 */
+	if ((DB_REF(mp) == 1) &&
+	    (MBLKHEAD(mp) >= sizeof (struct ether_header)) &&
+	    (((uintptr_t)mp->b_rptr & 0x1) == 0)) {
+		mp->b_rptr -= sizeof (struct ether_header);
+		headerp = (struct ether_header *)mp->b_rptr;
+	} else {
+		/* Allocate an M_DATA mblk for the header. */
+		if ((nmp = allocb(sizeof (struct ether_header),
+		    BPRI_LO)) == NULL) {
+			wrsmdp->wrsmd_ierrors++;
+			freemsg(mp);
+			D1("wrsmdaddhdr: bad allocb, returning NULL");
+			return (NULL);
+		}
+		DB_TYPE(nmp) = M_DATA;
+		linkb(nmp, mp);
+		mp = nmp;
+		headerp = (struct ether_header *)mp->b_rptr;
+		mp->b_wptr += sizeof (*headerp);
+	}
+
+	/*
+	 * Fill in header.  It is at least short aligned.
+	 */
+
+	ether_copy(&(to.m.ether.addr), &(headerp->ether_dhost));
+	ether_copy(&(from.m.ether.addr), &(headerp->ether_shost));
+	headerp->ether_type = sap;
+
+	D1("wrsmdaddhdr: returning 0x%p", (void *)mp);
+
+	return (mp);
+}
+
+
+
+/*
+ * Callback routine, called when an desballoc'ed buffer is eventually freed.
+ */
+static void
+wrsmdfreebuf(
+	wrsmdbuf_t *rbp)	/* Structure describing freed buffer */
+{
+	wrsmd_dest_t *rd = rbp->rb_rd;
+	int delflg, zerflg;
+
+	D1("wrsmdfreebuf: rbp 0x%p", (void *)rbp);
+
+	/*
+	 * Find out if this is the last outstanding buffer, and whether we're
+	 * being deleted.
+	 */
+	mutex_enter(&rd->rd_nlb_lock);
+
+	rd->rd_nlb--;
+	delflg = rd->rd_nlb_del;
+	zerflg = (rd->rd_nlb == 0);
+
+	mutex_exit(&rd->rd_nlb_lock);
+
+	/*
+	 * If we're being deleted, we don't put this buffer on the free queue.
+	 * Also, if we're being deleted, and this was the last outstanding
+	 * buffer, we do an UNREF.  Otherwise we send this buffer to the other
+	 * system for reuse.
+	 */
+	if (delflg) {
+		if (zerflg)
+			UNREFDEST(rd);
+	} else {
+		wrsmdputfqe(rd, rbp->rb_bufnum);
+		mutex_enter(&rd->rd_net_lock);
+		wrsmdsyncfqe(rd);
+		mutex_exit(&rd->rd_net_lock);
+	}
+
+	D1("wrsmdfreebuf: done");
+}
+
+/*
+ * wrsmdread() takes the packet described by the arguments and sends it
+ * upstream.
+ */
+static int
+wrsmdread(
+	wrsmd_dest_t *rd,	/* Destination pointer */
+	int bufnum,	/* Index of buffer containing packet */
+	int offset,	/* Offset of packet within buffer */
+	int length,	/* Length of packet */
+	ushort_t sap)	/* SAP for packet */
+{
+	wrsmd_t *wrsmdp = rd->rd_wrsmdp;
+	mblk_t *mp;
+	dl_rsm_addr_t from;
+	int canloan = B_FALSE;
+	caddr_t bufptr;
+	queue_t *ipq;
+	int buffree = 0;
+
+	D1("wrsmdread: rd 0x%p, bufnum %d, offset %d, length %d, sap 0x%x",
+	    (void *)rd, bufnum, offset, length, sap);
+
+	TNF_PROBE_5(wrsmdread_start, "RSMPI", "wrsmdread start",
+	    tnf_long, rd, (tnf_long_t)rd, tnf_long, bufnum, bufnum,
+	    tnf_long, offset, offset, tnf_long, length, length,
+	    tnf_long, sap, sap);
+
+	bufptr = (caddr_t)rd->rd_lbuf + (bufnum * rd->rd_lbuflen);
+	from.m.rsm = rd->rd_rsm_addr;
+
+	/* Figure out if we can loan this buffer up or not */
+
+	mutex_enter(&rd->rd_nlb_lock);
+	if (rd->rd_nlb < (wrsmdp->wrsmd_param.wrsmd_buffers -
+	    wrsmdp->wrsmd_param.wrsmd_buffers_retained)) {
+		rd->rd_nlb++;
+		canloan = B_TRUE;
+	}
+	mutex_exit(&rd->rd_nlb_lock);
+
+
+	if (canloan) {
+		/*
+		 * We make the mblk cover the whole buffer in case anybody
+		 * wants the leading/trailing space; below we adjust the
+		 * rptr/wptr to describe the actual packet.
+		 */
+		mp = desballoc((uchar_t *)bufptr, rd->rd_lbuflen,
+		    BPRI_LO, &(rd->rd_bufbase+bufnum)->rb_frtn);
+
+		if (mp == NULL) {
+			mutex_enter(&rd->rd_nlb_lock);
+			rd->rd_nlb--;
+			mutex_exit(&rd->rd_nlb_lock);
+
+			wrsmdputfqe(rd, bufnum);
+			buffree = 1;
+
+			wrsmdp->wrsmd_ierrors++;
+			D1("wrsmdread: can't desballoc, done");
+			TNF_PROBE_1(wrsmdread_end, "RSMPI",
+			    "wrsmdread end; failure desballoc",
+			    tnf_string, failure, "desballoc");
+			return (1);
+		}
+		mp->b_rptr += offset;
+		mp->b_wptr = mp->b_rptr + length;
+
+		wrsmdp->wrsmd_lbufs++;
+		D3D(mp->b_rptr, length);
+	} else {
+		/*
+		 * We make the destination (within the new mblk) have the
+		 * same address mod 64 as our source, so that the kernel
+		 * bcopy is as efficient as possible.  (This is a sun4u
+		 * bcopy optimization, not a Wildcat/RSM optimization.)
+		 */
+		mp = allocb(length + 0x40, BPRI_LO);
+		if (mp) {
+			intptr_t dstoffset = (intptr_t)mp->b_rptr;
+
+			dstoffset = offset - (dstoffset & 0x3f);
+			if (dstoffset < 0)
+				dstoffset += 0x40;
+
+			mp->b_rptr += dstoffset;
+			mp->b_wptr = mp->b_rptr + length;
+			bcopy((void *)(bufptr + offset), (void *)mp->b_rptr,
+			    length);
+
+			D3D(mp->b_rptr, length);
+
+			wrsmdp->wrsmd_nlbufs++;
+			wrsmdputfqe(rd, bufnum);
+			buffree = 1;
+		} else {
+			wrsmdputfqe(rd, bufnum);
+			buffree = 1;
+			wrsmdp->wrsmd_ierrors++;
+			D1("wrsmdread: can't allocb, done");
+			TNF_PROBE_1(wrsmdread_end, "RSMPI",
+			    "wrsmdread end; failure allocb",
+			    tnf_string, failure, "allocb");
+			return (1);
+		}
+	}
+
+	wrsmdp->wrsmd_ipackets++;
+	wrsmdp->wrsmd_in_bytes += length;
+
+
+	/*
+	 * IP shortcut
+	 */
+	rw_enter(&wrsmdp->wrsmd_ipq_rwlock, RW_READER);
+	ipq = wrsmdp->wrsmd_ipq;
+
+	if (ipq && (sap == WRSMD_IP_SAP)) {
+		if (canputnext(ipq)) {
+			TNF_PROBE_2(wrsmdread_IPscut, "RSMPI",
+			    "wrsmdread IPscut", tnf_long, ipq, (tnf_long_t)ipq,
+			    tnf_long, mp, (tnf_long_t)mp);
+			putnext(ipq, mp);
+			TNF_PROBE_1(wrsmdread_IPscutend, "RSMPI",
+			    "wrsmdread IPscutend", tnf_string, completed, "");
+		} else
+			freemsg(mp);
+	} else
+		wrsmdsendup(wrsmdp, mp, wrsmdp->wrsmd_rsm_addr, from,
+		    sap);
+
+	rw_exit(&wrsmdp->wrsmd_ipq_rwlock);
+
+	D1("wrsmdread: canloan was %d, done", canloan);
+	TNF_PROBE_1(wrsmdread_end, "RSMPI", "wrsmdread end",
+	    tnf_string, completed, "");
+
+	return (buffree);
+}
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * E N D       HIGH LEVEL PROTOCOL INTERFACE AND UTILITIES       *
+ *                                                               *
+ * ****************************************************************
+ */
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * B E G I N   RSM SETUP/TAKEDOWN                                *
+ *                                                               *
+ * ****************************************************************
+ */
+
+/*
+ * Initialize WRSMD resources.  Return 0 on success, nonzero on error.
+ */
+static int
+wrsmdinit(wrsmd_t *wrsmdp)	/* WRSMD device (RSM controller) pointer */
+{
+	int stat;
+
+	D1("wrsmdinit: wrsmdp 0x%p (cltr %d)", (void *)wrsmdp,
+	    wrsmdp->wrsmd_ctlr_id);
+
+	ASSERT(MUTEX_HELD(&wrsmdp->wrsmd_lock));
+
+	/* LINTED: E_TRUE_LOGICAL_EXPR */
+	ASSERT(sizeof (dl_rsm_addr_t) == sizeof (rsm_addr_t));
+
+	wrsmdp->wrsmd_flags = 0;
+
+	/*
+	 * Preceding teardown may not have released controller.
+	 * If so, do so now to avoid multiple reference counts.
+	 */
+	if (wrsmdp->wrsmd_flags & WRSMDGOTCTLR) {
+		D1("wrsmdinit: controller still held, "
+		    "call rsm_release_controller()");
+		rsm_release_controller(WRSM_NAME, wrsmdp->wrsmd_ctlr_id,
+		    &(wrsmdp->wrsmd_ctlr));
+		wrsmdp->wrsmd_ctlr.handle = NULL;
+		wrsmdp->wrsmd_flags &= ~WRSMDGOTCTLR;
+	}
+
+	if ((stat = rsm_get_controller(WRSM_NAME, wrsmdp->wrsmd_ctlr_id,
+	    &(wrsmdp->wrsmd_ctlr), RSM_VERSION)) != RSM_SUCCESS) {
+		D1("wrsmdinit: bad get_controller error %d", stat);
+		return (1);
+	}
+	if ((stat = rsm_get_controller_attr(wrsmdp->wrsmd_ctlr.handle,
+	    &(wrsmdp->wrsmd_ctlr_attr))) != RSM_SUCCESS) {
+		D1("wrsmdinit: bad get_controller_attr error %d", stat);
+		rsm_release_controller(WRSM_NAME, wrsmdp->wrsmd_ctlr_id,
+		    &(wrsmdp->wrsmd_ctlr));
+		wrsmdp->wrsmd_ctlr.handle = NULL;
+		return (1);
+	}
+
+	/*
+	 * We only support RSM addresses that fit into 6 bytes.  This
+	 * will always be the case on Wildcat.  (Address range is 0-255.)
+	 */
+	ASSERT(wrsmdp->wrsmd_ctlr_attr->attr_controller_addr <=
+	    (rsm_addr_t)0xffffffffffffLL);
+	wrsmdp->wrsmd_rsm_addr.m.rsm =
+	    wrsmdp->wrsmd_ctlr_attr->attr_controller_addr;
+	/*
+	 * Since this address is locally generated, turn on the locally
+	 * administered bit in the ethernet address to comply with IEEE 802.
+	 */
+	wrsmdp->wrsmd_rsm_addr.m.ether.addr.ether_addr_octet[0] |= 0x02;
+
+	wrsmdp->wrsmd_flags |= WRSMDGOTCTLR;
+
+	if ((stat = RSM_REGISTER_HANDLER(wrsmdp->wrsmd_ctlr,
+	    RSM_INTR_T_SUN_BASE, wrsmd_rsm_intr_handler,
+	    (rsm_intr_hand_arg_t)wrsmdp, NULL, 0)) !=
+	    RSM_SUCCESS) {
+		D1("wrsmdinit: cannot register interrupt handler: %d", stat);
+		rsm_release_controller(WRSM_NAME, wrsmdp->wrsmd_ctlr_id,
+		    &(wrsmdp->wrsmd_ctlr));
+		wrsmdp->wrsmd_ctlr.handle = NULL;
+		wrsmdp->wrsmd_flags &= ~WRSMDGOTCTLR;
+		return (1);
+	}
+
+	wrsmdp->wrsmd_flags |= WRSMDREGHANDLER;
+
+	/*
+	 * Clear any leftover junk from run queue.  (We could have destinations
+	 * here if the user detached from a device, then reattached before
+	 * the destinations got deleted.)  These destination structures will
+	 * eventually be freed when the deletion process completes.
+	 */
+	mutex_enter(&wrsmdp->wrsmd_runq_lock);
+	wrsmdp->wrsmd_runq = NULL;
+	mutex_exit(&wrsmdp->wrsmd_runq_lock);
+
+	D1("wrsmdinit: returning 0");
+
+	return (0);
+}
+
+/*
+ * Un-initialize WRSMD resources.  Returns 0 if completely successful.
+ * Returns -1 if not in a state where uninitialize makes sense.  Returns >0
+ * if uninitialize was started, but hasn't completed because not all
+ * connections have been torn down yet.
+ */
+static int
+wrsmduninit(wrsmd_t *wrsmdp)
+{
+	int dests_not_cleaned_up;
+	int i;
+	rsm_controller_object_t ctlr;
+
+	D1("wrsmduninit: wrsmdp 0x%p (cltr %d)", (void *)wrsmdp,
+	    wrsmdp->wrsmd_ctlr_id);
+
+	mutex_enter(&wrsmdp->wrsmd_lock);
+
+	if (wrsmdp->wrsmd_attached_streams) {
+		/*
+		 * don't uninitialize device while streams are attached to it
+		 */
+		D1("wrsmduninit: %d streams still attached, failing",
+		    wrsmdp->wrsmd_attached_streams);
+		mutex_exit(&wrsmdp->wrsmd_lock);
+		return (-1);
+	}
+
+	if (wrsmdp->wrsmd_flags & WRSMDREGHANDLER) {
+		/*
+		 * Must release the mutex here to avoid a potential deadlock.
+		 * The wrsm_unregister_handler() code acquires the wrsm
+		 * service->handler_mutex.  If an inbound interrupt occurs,
+		 * the wrsm service_callback grabs the service->handler_mutex,
+		 * and calls back into the wrsmd_rsm_intr_handler() routine,
+		 * which attempts to grab the wrsmdp->wrsmd_lock.  If at the
+		 * time we invoke RSM_UNREGISTER_HANDLER() while holding the
+		 * wrsmdp->wrsmd_lock, we get a circular lock deadlock.
+		 */
+		ctlr = wrsmdp->wrsmd_ctlr;
+		mutex_exit(&wrsmdp->wrsmd_lock);
+		RSM_UNREGISTER_HANDLER(ctlr, RSM_INTR_T_SUN_BASE,
+		    wrsmd_rsm_intr_handler, (rsm_intr_hand_arg_t)wrsmdp);
+		mutex_enter(&wrsmdp->wrsmd_lock);
+		wrsmdp->wrsmd_flags &= ~WRSMDREGHANDLER;
+	}
+
+	for (i = 0; i < RSM_MAX_DESTADDR; i++)
+		wrsmdfreedest(wrsmdp, i);
+
+	mutex_enter(&wrsmdp->wrsmd_dest_lock);
+	dests_not_cleaned_up = wrsmdp->wrsmd_numdest;
+	mutex_exit(&wrsmdp->wrsmd_dest_lock);
+
+	if ((wrsmdp->wrsmd_flags & WRSMDGOTCTLR) &&
+	    (dests_not_cleaned_up == 0)) {
+		/*
+		 * there will be no more RSMPI calls, so
+		 * it's safe to release the controller
+		 */
+		D1("wrsmduninit: call rsm_release_controller()");
+		rsm_release_controller(WRSM_NAME, wrsmdp->wrsmd_ctlr_id,
+		    &(wrsmdp->wrsmd_ctlr));
+		wrsmdp->wrsmd_ctlr.handle = NULL;
+		wrsmdp->wrsmd_flags &= ~WRSMDGOTCTLR;
+	}
+	mutex_exit(&wrsmdp->wrsmd_lock);
+
+	D1("wrsmduninit: returning %d",
+	    dests_not_cleaned_up);
+
+	return (dests_not_cleaned_up);
+}
+
+/*
+ * Get all the wrsmd parameters out of the device tree and store them in a
+ * WRSMD device (RSM controller) structure.
+ */
+static void
+wrsmdgetparam(
+	dev_info_t *dip,	/* Device's info pointer */
+	wrsmd_t *wrsmdp)	/* WRSMD device (RSM controller) pointer */
+{
+	struct wrsmd_param *sp = &wrsmdp->wrsmd_param;
+	boolean_t modified_bufsize = B_FALSE;
+
+	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sp))
+
+	/* Get parameters */
+
+	sp->wrsmd_buffers = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-buffers", WRSMD_BUFFERS_DFLT);
+	sp->wrsmd_buffer_size = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-buffer-size", WRSMD_BUFFER_SIZE_DFLT);
+	sp->wrsmd_queue_size = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-queue-size", WRSMD_QUEUE_SIZE_DFLT);
+	sp->wrsmd_buffers_retained = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-buffers-retained", WRSMD_BUFFERS_RETAINED_DFLT);
+	sp->wrsmd_idle_reclaim_time = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-idle-reclaim-time", WRSMD_IDLE_RECLAIM_TIME_DFLT);
+	sp->wrsmd_err_retries = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-err-retries", WRSMD_ERR_RETRIES_DFLT);
+	sp->wrsmd_max_queued_pkts = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-max-queued-pkts", WRSMD_MAX_QUEUED_PKTS_DFLT);
+	sp->wrsmd_nobuf_init_tmo = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-nobuf-init-tmo", WRSMD_NOBUF_INIT_TMO_DFLT);
+	sp->wrsmd_nobuf_max_tmo = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-nobuf-max-tmo", WRSMD_NOBUF_MAX_TMO_DFLT);
+	sp->wrsmd_nobuf_drop_tmo = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-nobuf-drop-tmo", WRSMD_NOBUF_DROP_TMO_DFLT);
+	sp->wrsmd_msg_init_tmo = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-msg-init-tmo", WRSMD_MSG_INIT_TMO_DFLT);
+	sp->wrsmd_msg_max_tmo = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-msg-max-tmo", WRSMD_MSG_MAX_TMO_DFLT);
+	sp->wrsmd_msg_drop_tmo = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-msg-drop-tmo", WRSMD_MSG_DROP_TMO_DFLT);
+	sp->wrsmd_ack_tmo = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-ack-tmo", WRSMD_ACK_TMO_DFLT);
+	sp->wrsmd_sync_tmo = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-sync-tmo", WRSMD_SYNC_TMO_DFLT);
+	sp->wrsmd_teardown_tmo = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-teardown-tmo", WRSMD_TEARDOWN_TMO_DFLT);
+	sp->wrsmd_train_size = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-train-size", WRSMD_TRAIN_SIZE_DFLT);
+	sp->wrsmd_fqe_sync_size = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+	    "wrsmd-fqe-sync-size", WRSMD_FQE_SYNC_SIZE_DFLT);
+
+	/*
+	 * Sanity check parameters, modify if needed.  Note that we mainly
+	 * check to make sure parameters won't make the driver malfunction;
+	 * we don't necessarily prevent them from being stupid.
+	 */
+
+	/* Need to have at least one buffer. */
+
+	if (sp->wrsmd_buffers == 0)
+		sp->wrsmd_buffers = 1;
+
+#ifdef RESTRICT_MAX_BUFFER_SIZE
+	/* Can't put more than 64K in a buffer (IP max packet length). */
+
+	if (sp->wrsmd_buffer_size > (64 * 1024)) {
+		sp->wrsmd_buffer_size = (64 * 1024);
+		modified_bufsize = B_TRUE;
+	}
+#endif
+
+	/*
+	 * Have to be able to send at least a 576-byte packet (IP reqmnt).
+	 * Add 2 cachelines so that packet will fit no matter how it is
+	 * aligned.
+	 */
+
+	if (sp->wrsmd_buffer_size <
+	    (576+WRSMD_CACHELINE_SIZE+WRSMD_CACHELINE_SIZE)) {
+		sp->wrsmd_buffer_size =
+		    576+WRSMD_CACHELINE_SIZE+WRSMD_CACHELINE_SIZE;
+		modified_bufsize = B_TRUE;
+	}
+
+	/* Buffer length must be multiple of 64 (0x40). */
+
+	if (sp->wrsmd_buffer_size & ~WRSMD_CACHELINE_MASK) {
+		sp->wrsmd_buffer_size &= WRSMD_CACHELINE_MASK;
+		modified_bufsize = B_TRUE;
+	}
+
+	if (modified_bufsize) {
+		cmn_err(CE_NOTE, "adjusted wrsmd-buffer-size value from "
+		    "wrsmd.conf to 0x%x", sp->wrsmd_buffer_size);
+	}
+
+	/*
+	 * Must have at least one more queue element then the number of
+	 * buffers.  This is so that we can track when all queue elements
+	 * need to be flushed to remote.
+	 */
+
+	if (sp->wrsmd_queue_size <= sp->wrsmd_buffers) {
+		sp->wrsmd_queue_size = sp->wrsmd_buffers + 1;
+		cmn_err(CE_NOTE, "adjusted wrsmd-queue-size value from "
+		    "wrsmd.conf to 0x%x", sp->wrsmd_queue_size);
+	}
+
+	/* Can't retain more buffers than we have. */
+
+	if (sp->wrsmd_buffers_retained > sp->wrsmd_buffers) {
+		sp->wrsmd_buffers_retained = sp->wrsmd_buffers;
+		cmn_err(CE_NOTE, "adjusted wrsmd-buffers-retained value "
+		    "from wrsmd.conf to 0x%x", sp->wrsmd_buffers_retained);
+	}
+
+	/* Have to be able to send at least 1 packet at a time. */
+
+	if (sp->wrsmd_train_size < 1) {
+		sp->wrsmd_train_size = 1;
+		cmn_err(CE_NOTE, "adjusted wrsmd-train-size value "
+		    "from wrsmd.conf to 0x%x", sp->wrsmd_train_size);
+	}
+
+	/* Have to be able to queue at least 1 packet. */
+
+	if (sp->wrsmd_max_queued_pkts < 1) {
+		sp->wrsmd_max_queued_pkts = 1;
+		cmn_err(CE_NOTE, "adjusted wrsmd-max-queued-packets "
+		    "value from wrsmd.conf to 0x%x",
+		    sp->wrsmd_max_queued_pkts);
+	}
+
+	/*
+	 * Convert timeout parameters in milliseconds to
+	 * absolute clock ticks, depending on clock hertz.
+	 */
+	sp->wrsmd_idle_reclaim_time = WRSMD_TICKS(sp->wrsmd_idle_reclaim_time);
+	sp->wrsmd_nobuf_init_tmo = WRSMD_TICKS(sp->wrsmd_nobuf_init_tmo);
+	sp->wrsmd_nobuf_max_tmo = WRSMD_TICKS(sp->wrsmd_nobuf_max_tmo);
+	sp->wrsmd_nobuf_drop_tmo = WRSMD_TICKS(sp->wrsmd_nobuf_drop_tmo);
+	sp->wrsmd_msg_init_tmo = WRSMD_TICKS(sp->wrsmd_msg_init_tmo);
+	sp->wrsmd_msg_max_tmo = WRSMD_TICKS(sp->wrsmd_msg_max_tmo);
+	sp->wrsmd_msg_drop_tmo = WRSMD_TICKS(sp->wrsmd_msg_drop_tmo);
+	sp->wrsmd_ack_tmo = WRSMD_TICKS(sp->wrsmd_ack_tmo);
+	sp->wrsmd_sync_tmo = WRSMD_TICKS(sp->wrsmd_sync_tmo);
+	sp->wrsmd_teardown_tmo = WRSMD_TICKS(sp->wrsmd_teardown_tmo);
+
+	/* Can't sleep for less than 1 tick. */
+
+	if (sp->wrsmd_nobuf_init_tmo < 1) {
+		sp->wrsmd_nobuf_init_tmo = 1;
+		cmn_err(CE_NOTE, "adjusted wrsm-nobuf-init-tmo "
+		    "value from wrsmd.conf to 0x%x",
+		    sp->wrsmd_nobuf_init_tmo);
+	}
+	if (sp->wrsmd_nobuf_max_tmo < 1) {
+		sp->wrsmd_nobuf_max_tmo = 1;
+		cmn_err(CE_NOTE, "adjusted wrsm-nobuf-max-tmo "
+		    "value from wrsmd.conf to 0x%x",
+		    sp->wrsmd_nobuf_max_tmo);
+	}
+	if (sp->wrsmd_msg_init_tmo < 1) {
+		sp->wrsmd_msg_init_tmo = 1;
+		cmn_err(CE_NOTE, "adjusted wrsm-msg-init-tmo "
+		    "value from wrsmd.conf to 0x%x",
+		    sp->wrsmd_msg_init_tmo);
+	}
+	if (sp->wrsmd_msg_max_tmo < 1) {
+		sp->wrsmd_msg_max_tmo = 1;
+		cmn_err(CE_NOTE, "adjusted wrsm-msg-max-tmo "
+		    "value from wrsmd.conf to 0x%x",
+		    sp->wrsmd_msg_max_tmo);
+	}
+	if (sp->wrsmd_ack_tmo < 1) {
+		sp->wrsmd_ack_tmo = 1;
+		cmn_err(CE_NOTE, "adjusted wrsm-ack-tmo "
+		    "value from wrsmd.conf to 0x%x",
+		    sp->wrsmd_ack_tmo);
+	}
+	if (sp->wrsmd_sync_tmo < 1) {
+		sp->wrsmd_sync_tmo = 1;
+		cmn_err(CE_NOTE, "adjusted wrsm-sync-tmo "
+		    "value from wrsmd.conf to 0x%x",
+		    sp->wrsmd_sync_tmo);
+	}
+
+	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*sp))
+}
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * E N D       RSM SETUP/TAKEDOWN                                *
+ *                                                               *
+ * ****************************************************************
+ */
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * B E G I N   CONNECTION DATA STRUCTURE MANAGEMENT              *
+ *                                                               *
+ * ****************************************************************
+ */
+
+
+/*
+ * Create the indicated destination structure, and return a pointer to it.
+ * NOTE:  this should never be called directly; use the MAKEDEST macro
+ * instead.  The macro checks that the destination structure does not yet
+ * exist before calling this function.
+ */
+static wrsmd_dest_t *
+wrsmdmkdest(wrsmd_t *wrsmdp,	/* WRSMD device (RSM controller) pointer */
+    rsm_addr_t rsm_addr)	/* Address of destination to find/create */
+{
+	wrsmd_dest_t *rd;
+	clock_t lbolt;
+
+	D1("wrsmdmkdest: wrsmdp 0x%p (cltr %d), rsmaddr %ld", (void *)wrsmdp,
+	    wrsmdp->wrsmd_ctlr_id, rsm_addr);
+
+	/* Is the destination reasonable? */
+
+	if (rsm_addr >= RSM_MAX_DESTADDR) {
+		D1("wrsmdmkdest: too big, returning NULL");
+		return (NULL);
+	}
+
+	if ((rd = wrsmdp->wrsmd_desttbl[rsm_addr]) != NULL) {
+		return (rd);
+	}
+
+	ASSERT(MUTEX_HELD(&wrsmdp->wrsmd_dest_lock));
+
+	if ((rd = kmem_zalloc(sizeof (*rd), KM_NOSLEEP)) == NULL) {
+		D1("wrsmdmkdest: can't alloc, returning NULL");
+		return (NULL);
+	}
+
+	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rd));
+	rd->rd_wrsmdp = wrsmdp;
+	rd->rd_rsm_addr = rsm_addr;
+
+	mutex_init(&rd->rd_net_lock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&rd->rd_xmit_lock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&rd->rd_lock, NULL, MUTEX_DRIVER, NULL);
+
+	/*
+	 * Use the time to generate a pseudo-random initial sequence
+	 * number.
+	 */
+	(void) drv_getparm(LBOLT, &lbolt);
+	rd->rd_nseq = (ushort_t)lbolt;
+
+	rd->rd_state = WRSMD_STATE_NEW;
+	rd->rd_refcnt = 1;
+
+	wrsmdp->wrsmd_desttbl[rsm_addr] = rd;
+	wrsmdp->wrsmd_numdest++;
+
+	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rd))
+
+	D1("wrsmdmkdest: created new dest, returning 0x%p", (void *)rd);
+
+	return (rd);
+}
+
+/*
+ * Destination deletion
+ *
+ * As mentioned above (way above), we maintain a reference count on all
+ * destinations, which is incremented and decremented around uses of the
+ * destination structure.  When this reference count goes to zero, we delete
+ * the destination.
+ *
+ * Because of the possibility of other threads trying to use the destination
+ * while we're deleting it, deletion is actually a multiple-step process,
+ * which works as follows.
+ *
+ * 1. When a destination is created, its dstate (deletion state) is set to
+ *    zero, and its reference count is set to one.
+ *
+ * 2. When the service routine or some other routine decides that a destination
+ *    should be deleted, it calls wrsmdfreedest().  That routine sets dstate
+ *    to 1 and cancels any pending sync timeouts.  It then decrements the
+ *    destination's reference count.  This deletes the reference set in
+ *    wrsmdmkdest. (Note that since dstate is now 1, the FINDDEST and REFDEST
+ *    macros will now note that the destination is being deleted; thus, any
+ *    interrupt referring to the destination will no longer modify the
+ *    reference count.)
+ *
+ * 3. Soon after this, wrsmddest_refcnt_0 is called.  (This may either be
+ *    directly from wrsmdfreedest(), or perhaps from another routine if it
+ *    was running concurrently with freedest() and its UNREF happened last).
+ *    This routine sees that dstate is 1, and immediately queues an event
+ *    which will execute wrsmdfreedestevt().  (This is necessary because we
+ *    may not be able to do everything in the phase 1 deletion from the routine
+ *    that we're currently in.)
+ *
+ * 4. wrsmdfreedestevt() runs, it checks if there are any outstanding
+ *    loaned-up buffers.  If so, it sets a flag to cause the loan returning
+ *    code to decrement the refcnt, and returns without performing cleanup.
+ *    When all loaned buffers are returned and the refcnt is decremented, we
+ *    go back to step 3, above.  When wrsmdfreedestevt() finally runs with
+ *    no loaned buffers, gets rid of most of the WRSMD resources attached
+ *    to the destination.  It also throws away any queued packets, gets
+ *    rid of any allocated DVMA resources.  It changes dstate to 2, takes
+ *    this destination structure out of the base-ID => destination table.
+ *    It then decrements the reference count that had been added by
+ *    wrsmddest_refcnt_0().
+ *
+ * 5. When the reference count becomes 0, wrsmddest_refcnt_0 is again called.
+ *    It notices that dstate is 2, and frees the destination structure.
+ */
+
+/*
+ * A destination's reference count went to 0, deal with it.
+ */
+static boolean_t
+wrsmddest_refcnt_0(
+	wrsmd_dest_t *rd)	/* Destination pointer */
+{
+	wrsmd_t *wrsmdp = rd->rd_wrsmdp;
+	boolean_t freed = B_FALSE;
+
+	mutex_enter(&wrsmdp->wrsmd_dest_lock);
+
+	D1("wrsmddest_refcnt_0: rd 0x%p (addr %ld ctlr %d), refcnt %d, "
+	    "dstate %d",
+	    (void *)rd, rd->rd_rsm_addr, wrsmdp->wrsmd_ctlr_id,
+	    rd->rd_refcnt, rd->rd_dstate);
+
+	if (rd->rd_dstate == 1) {
+		rd->rd_refcnt++;	/* Inline REFDEST */
+
+		/*
+		 * We may be called from a routine that can't actually do the
+		 * work that needs to be done, so we schedule an event
+		 * to do the rest of the work.  This can not be a timeout.
+		 */
+
+		wrsmd_add_event(wrsmdp, WRSMD_EVT_FREEDEST, (void *)rd);
+
+	} else if (rd->rd_dstate == 2) {
+
+		/* Destroy all the mutexes */
+
+		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rd))
+
+		mutex_destroy(&rd->rd_lock);
+		mutex_destroy(&rd->rd_net_lock);
+		mutex_destroy(&rd->rd_xmit_lock);
+		mutex_destroy(&rd->rd_nlb_lock);
+
+		/*
+		 * Free any allocated memory hanging off the dest structure.
+		 */
+
+		if (rd->rd_cached_fqr) {
+			kmem_free(rd->rd_cached_fqr,
+			    sizeof (*rd->rd_cached_fqr) * rd->rd_num_fqrs);
+		}
+		if (rd->rd_shdwfqw_f_addr) {
+			kmem_free(rd->rd_shdwfqw_f_addr,
+			(sizeof (*rd->rd_shdwfqw_f_addr) * rd->rd_num_fqws) +
+				WRSMD_CACHELINE_SIZE);
+		}
+		if (rd->rd_shdwdqw_f_addr) {
+			kmem_free(rd->rd_shdwdqw_f_addr,
+			(sizeof (*rd->rd_shdwdqw_f_addr) * rd->rd_num_dqws) +
+				WRSMD_CACHELINE_SIZE);
+		}
+		if (rd->rd_bufbase) {
+			kmem_free(rd->rd_bufbase,
+			    wrsmdp->wrsmd_param.wrsmd_buffers *
+			    sizeof (*rd->rd_bufbase));
+		}
+		if (rd->rd_rawmem_base_addr) {
+			kmem_free(rd->rd_rawmem_base_addr,
+			    rd->rd_rawmem_base_size);
+		}
+
+		/* Finally free the dest structure */
+
+		kmem_free(rd, sizeof (*rd));
+		freed = B_TRUE;
+
+		wrsmdp->wrsmd_numdest--;
+
+		D1("wrsmddest_refcnt_0: freed rd data structures");
+	}
+
+	mutex_exit(&wrsmdp->wrsmd_dest_lock);
+
+	D1("wrsmddest_refcnt_0: done");
+
+	return (freed);
+}
+
+/*
+ * Do deletion work.
+ */
+static void
+wrsmdfreedestevt(void * arg)
+{
+	wrsmd_dest_t *rd = (wrsmd_dest_t *)arg;
+	wrsmd_t *wrsmdp = rd->rd_wrsmdp;
+	mblk_t *mp, *nmp;
+	int err;
+	int count = 0, tmpmask;
+
+	D1("wrsmdfreedestevt: rd 0x%p (addr %ld ctlr %d)", (void *)rd,
+	    rd->rd_rsm_addr, wrsmdp->wrsmd_ctlr_id);
+
+	/* Get rid of any queued outgoing buffers */
+
+	mutex_enter(&rd->rd_xmit_lock);
+
+	mp = rd->rd_queue_h;
+	rd->rd_queue_h = NULL;
+
+	while (mp) {
+		nmp = mp->b_next;
+		mp->b_next = mp->b_prev = NULL;
+		wrsmdp->wrsmd_oerrors++;
+		freemsg(mp);
+		mp = nmp;
+	}
+	rd->rd_queue_len = 0;
+
+	mutex_exit(&rd->rd_xmit_lock);
+
+	/*
+	 * See if there are any more outstanding loaned buffers.  If so,
+	 * set flag so that freebuf will eventually do an UNREF when it
+	 * frees the last buffer.  This removes the reference added in
+	 * wrsmddest_refcnt_0(), causing the count to again go to 0.
+	 * wrsmddest_refcnt_0() will again be called, increment the refcnt
+	 * and cause this routine to be called to complete cleanup.
+	 */
+
+	mutex_enter(&rd->rd_nlb_lock);
+
+	rd->rd_nlb_del = 1;
+	if (rd->rd_nlb != 0) {
+		DERR("wrsmdfreedestevt: loaned buffers outstanding %d, dest "
+		    "%ld", rd->rd_nlb, rd->rd_rsm_addr);
+		mutex_exit(&rd->rd_nlb_lock);
+		return;
+	}
+
+	mutex_exit(&rd->rd_nlb_lock);
+
+	/*
+	 * Retry for up to 10 times to clean up, pausing slightly each
+	 * iteration.  This gives the remote side a chance to clean up
+	 * in the case of unpublish, and allows us to catch other errors
+	 * now as well.
+	 */
+
+	tmpmask = WRSMD_RSMS_RXFER_S | WRSMD_RSMS_RXFER_C |
+		WRSMD_RSMS_LXFER_P | WRSMD_RSMS_LXFER_C;
+	while ((count < 10) && (rd->rd_sstate & tmpmask)) {
+		/*
+		 * Perform the sendq destroy first -- this notifies the
+		 * remote side that the connection is going away, so
+		 * it can immediately start cleaning up.  This helps
+		 * to avoid a situation where a segment is unpublished
+		 * while there is still a connection to it (which is legal,
+		 * but causes overhead in the Wildcat RSM driver).
+		 */
+		if (rd->rd_sstate & WRSMD_RSMS_RXFER_S) {
+			ASSERT(rd->rsm_sendq);
+			D1("wrsmdfreedestevt: destroying sendq\n");
+				err = RSM_SENDQ_DESTROY(wrsmdp->wrsmd_ctlr,
+							rd->rsm_sendq);
+			if (err) {
+				D1("RSM_SENDQ_DESTROY failed! err %d\n", err);
+			} else {
+				rd->rd_sstate &= ~WRSMD_RSMS_RXFER_S;
+			}
+		}
+
+		if (rd->rd_sstate & WRSMD_RSMS_RXFER_C) {
+			ASSERT(rd->rd_rxferhand);
+			D1("wrsmdfreedestevt: disconn from remote segment\n");
+			err = RSM_DISCONNECT(wrsmdp->wrsmd_ctlr,
+				rd->rd_rxferhand);
+			if (err) {
+				D1("RSM_DISCONNECT failed! err %d\n", err);
+			} else {
+				rd->rd_sstate &= ~WRSMD_RSMS_RXFER_C;
+			}
+		}
+
+		if (rd->rd_sstate & WRSMD_RSMS_LXFER_P) {
+			ASSERT(rd->rd_lxferhand);
+			D1("wrsmdfreedestevt: unpublishing local segment\n");
+			err = RSM_UNPUBLISH(wrsmdp->wrsmd_ctlr,
+					    rd->rd_lxferhand);
+			if (err) {
+				D1("RSM_UNPUBLISH failed! err %d\n", err);
+			} else {
+				rd->rd_sstate &= ~WRSMD_RSMS_LXFER_P;
+			}
+		}
+
+		if (rd->rd_sstate & WRSMD_RSMS_LXFER_C) {
+			ASSERT(rd->rd_lxferhand);
+			D1("wrsmdfreedestevt: destroying local segment\n");
+			err = RSM_SEG_DESTROY(wrsmdp->wrsmd_ctlr,
+						rd->rd_lxferhand);
+			if (err) {
+				D1("RSM_SEG_DESTROY failed! err %d\n", err);
+			} else {
+				rd->rd_sstate &= ~WRSMD_RSMS_LXFER_C;
+			}
+		}
+
+		count++;
+
+		if (rd->rd_sstate & tmpmask) {
+			D1("freedestevt: Pass %d, (sstate & mask)=0x%x\n",
+				count, (rd->rd_sstate & tmpmask));
+
+			/* Busy wait for a few microseconds */
+			drv_usecwait(5000);
+		}
+	}
+
+	if (count >= 10) {
+		D1("freedestevt: sstate&mask !0 after %d tries. 0x%x\n",
+			count, (rd->rd_sstate & tmpmask));
+		D0("freedestevt: Clearing state but status != 0, stat=%x\n",
+			(rd->rd_sstate & tmpmask));
+		rd->rd_sstate &= ~tmpmask;
+	}
+
+	/* Take out of desttbl */
+
+	mutex_enter(&wrsmdp->wrsmd_dest_lock);
+
+	rd->rd_wrsmdp->wrsmd_desttbl[rd->rd_rsm_addr] = NULL;
+
+	ASSERT(rd->rd_dstate == 1);
+	rd->rd_dstate = 2;
+
+	mutex_exit(&wrsmdp->wrsmd_dest_lock);
+
+
+	/* Make sure dest isn't on service queue */
+
+	mutex_enter(&wrsmdp->wrsmd_runq_lock);
+
+	if (wrsmdp->wrsmd_runq == rd)
+		wrsmdp->wrsmd_runq = rd->rd_next;
+	else {
+		wrsmd_dest_t *lastrd = wrsmdp->wrsmd_runq;
+
+		while (lastrd) {
+			if (lastrd->rd_next == rd) {
+				lastrd->rd_next = rd->rd_next;
+				break;
+			}
+			lastrd = lastrd->rd_next;
+		}
+	}
+
+	mutex_exit(&wrsmdp->wrsmd_runq_lock);
+
+
+	ASSERT(rd->rd_sstate == 0);
+
+	/*
+	 * Removes the reference added in wrsmddest_refcnt_0().
+	 */
+	UNREFDEST(rd);
+
+	D1("wrsmdfreedestevt: done");
+}
+
+
+/*
+ * Start the deletion process for a destination.
+ */
+static void
+wrsmdfreedest(wrsmd_t *wrsmdp, rsm_addr_t rsm_addr)
+{
+	wrsmd_dest_t *rd;
+	timeout_id_t tmoid, fqe_tmoid;
+
+	D1("wrsmdfreedest: ctlr %d remote rsmaddr %ld",
+	    wrsmdp->wrsmd_ctlr_id, rsm_addr);
+
+	mutex_enter(&wrsmdp->wrsmd_dest_lock);
+
+	rd = wrsmdp->wrsmd_desttbl[rsm_addr];
+	if (rd == NULL || rd->rd_dstate != 0) {
+		mutex_exit(&wrsmdp->wrsmd_dest_lock);
+		return;
+	}
+
+	ASSERT((wrsmdp->wrsmd_attached_streams == 0) ||
+	    (rd->rd_state == WRSMD_STATE_DELETING));
+
+	D1("wrsmdfreedest: wrsmdp 0x%p (cltr %d) rsmaddr %ld", (void *)wrsmdp,
+	    wrsmdp->wrsmd_ctlr_id, rsm_addr);
+
+	rd->rd_dstate = 1;
+
+	mutex_exit(&wrsmdp->wrsmd_dest_lock);
+
+	/*
+	 * Turn off any timeouts.  The sync timeout reschedules itself, so we
+	 * have to go to great lengths to kill it.
+	 */
+
+	mutex_enter(&rd->rd_xmit_lock);
+	tmoid = rd->rd_tmo_id;
+	rd->rd_tmo_id = 0;
+
+	fqe_tmoid = rd->rd_fqe_tmo_id;
+	rd->rd_fqe_tmo_id = 0;
+
+	mutex_exit(&rd->rd_xmit_lock);
+	if (tmoid)
+		(void) untimeout(tmoid);
+
+	if (fqe_tmoid)
+		(void) untimeout(fqe_tmoid);
+
+	mutex_enter(&rd->rd_net_lock);
+
+	/*
+	 * Flush any outstanding events from the event thread.  Since the
+	 * freedestevt() will be queued after any pending syncs, we
+	 * should be OK; but will start the ball rolling just in case.
+	 */
+
+	mutex_enter(&wrsmdp->event_lock);
+	cv_broadcast(&wrsmdp->event_cv);
+	mutex_exit(&wrsmdp->event_lock);
+
+	mutex_exit(&rd->rd_net_lock);
+
+	D1("wrsmdfreedest: done");
+
+	/* remove reference added in wrsmdmkdest() */
+	UNREFDEST(rd);
+}
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * E N D       CONNECTION DATA STRUCTURE MANAGEMENT              *
+ *                                                               *
+ * ****************************************************************
+ */
+
+
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * B E G I N   MAIN STATE MACHINE                                *
+ *                                                               *
+ * ****************************************************************
+ */
+
+
+/*
+ * We change a destination's state in a number of routines; we define these
+ * macros to make sure it gets done the same way every time.
+ */
+#define	WRSMD_SETSTATE(rd, wrsmdp, routine, newstate)			\
+	rd->rd_state = (ushort_t)newstate; 			\
+		if (WRSMD_SCHED_STATE(newstate)) {		\
+			rd->rd_next = wrsmdp->wrsmd_runq;		\
+			wrsmdp->wrsmd_runq = rd;			\
+			D1(routine ": added to runq");	        \
+			if (wrsmdp->wrsmd_wq) {			\
+				qenable(wrsmdp->wrsmd_wq);	\
+				D1(routine ": enabled 0x%p",	\
+				    (void *)wrsmdp->wrsmd_wq);	\
+			}				        \
+		}						\
+  	_NOTE(CONSTCOND);
+
+
+#define	WRSMD_SETSTATE_NOSRV(rd, wrsmdp, routine, newstate)	\
+		rd->rd_state = (ushort_t)newstate;		\
+		if (WRSMD_SCHED_STATE(newstate)) {		\
+			rd->rd_next = wrsmdp->wrsmd_runq;		\
+			wrsmdp->wrsmd_runq = rd;			\
+			D1(routine ": added to runq");		\
+		}       				        \
+	_NOTE(CONSTCOND);
+
+
+/*
+ * This routine processes a notification that a destination has become
+ * unreachable.  Delete our record of it, so that when it comes back up we
+ * will re-establish our association.  We do this by changing its state to
+ * S_DELETE; the service routine will then start the deletion
+ * process.
+ *
+ * Since other parts of the driver may have operations in progress that
+ * involve this destination, most of the time we cannot just whack the
+ * state to the new value.  Instead, we record (in rd_estate) that the
+ * connection was lost.  The next time someone else attempts to change the
+ * state, the state change routines recognize that there is a pending event
+ * and change the state to the one we wanted instead.  (There are
+ * exceptions in cases where the new state indicates that we've enabled
+ * some sort of timeout; in this case, we may wait until the following
+ * state change to take note of the event.)
+ */
+static void
+wrsmd_lostconn(wrsmd_dest_t *rd)
+{
+	wrsmd_t *wrsmdp = rd->rd_wrsmdp;
+
+	D1("wrsmd_lostconn: rd 0x%p (addr %ld ctlr %d)", (void *)rd,
+	    rd->rd_rsm_addr, wrsmdp->wrsmd_ctlr_id);
+
+	mutex_enter(&wrsmdp->wrsmd_runq_lock);
+	if ((rd->rd_state == WRSMD_STATE_W_READY) ||
+	    (rd->rd_state == WRSMD_STATE_NEW) ||
+	    (rd->rd_state == WRSMD_STATE_W_ACCEPT) ||
+	    (rd->rd_state == WRSMD_STATE_W_ACK) ||
+	    (rd->rd_state == WRSMD_STATE_W_FQE)) {
+		/* LINTED: E_CONSTANT_CONDITION */
+		WRSMD_SETSTATE(rd, wrsmdp, "wrsmd_lostconn",
+		    WRSMD_STATE_S_DELETE);
+	} else {
+		rd->rd_estate = WRSMD_STATE_S_DELETE;
+	}
+	D1("wrsmd_lostconn: state now %s, estate now %s",
+	    WRSMD_STATE_STR(rd->rd_state), WRSMD_STATE_STR(rd->rd_estate));
+
+	mutex_exit(&wrsmdp->wrsmd_runq_lock);
+
+	/*
+	 * Stop trying to flush queue entries to the other side.
+	 *
+	 * stopq doesn't really need a lock to protect its state, as the
+	 * only thing that happens to it is that it is set to true just
+	 * prior to deleting rd, and the only purpose of this is to avoid
+	 * unnecessary work.  Other threads can read the state of this
+	 * variable at any time, without taking a special lock.
+	 *
+	 * Note that rd itself is protected from going away from the
+	 * REFDEST/FINDDEST performed by the caller of this routine.
+	 */
+	rd->rd_stopq = B_TRUE;
+
+	D1("wrsmd_lostconn: done");
+}
+
+
+/*
+ * Figure out what state transition should actually occur after an event
+ * has happened.
+ */
+static int
+wrsmdestate_newstate(wrsmd_dest_t *rd, int newstate)
+{
+	int retval = newstate;
+
+	/*
+	 * If we're going to a state where we've just set a timeout, don't
+	 * mess with the state.  When the timeout happens, it will change
+	 * state again, and we'll nab 'em there.  If we're about to delete
+	 * rd, don't bother worrying about the event.
+	 */
+	switch (newstate) {
+	case WRSMD_STATE_W_SCONNTMO:
+	case WRSMD_STATE_W_ACCEPT:
+	case WRSMD_STATE_W_ACK:
+	case WRSMD_STATE_W_FQE:
+	case WRSMD_STATE_DELETING:
+	case WRSMD_STATE_S_DELETE:
+		return (retval);
+	}
+
+	if (rd->rd_estate) {
+		retval = rd->rd_estate;
+		rd->rd_estate = WRSMD_STATE_NEW; /* clear event state */
+	}
+
+	D1("wrsmdestate_newstate: %d %d -> %d", rd->rd_estate,
+	    newstate, retval);
+
+	return (retval);
+}
+
+
+/*
+ * If this destination's state is equal to state, set its state to INPROGRESS
+ * and return 1, otherwise return 0.
+ */
+static int
+wrsmdisstate(
+	wrsmd_dest_t *rd,	/* Destination pointer */
+	int state)	/* State to check for */
+{
+	wrsmd_t *wrsmdp = rd->rd_wrsmdp;
+	int retval;
+
+	D1("wrsmdisstate: rd 0x%p, state %s", (void *)rd,
+	    WRSMD_STATE_STR(state));
+
+	/*
+	 * We check first without the lock to save time in a common case,
+	 * namely, we're called from the wrsmdmsghdlr_syncdqe() routine and
+	 * we want to know if we're waiting for an FQE.
+	 */
+
+#ifndef __lock_lint
+	if (state != rd->rd_state) {
+		D1("wrsmdisstate: state was %s, returning 0",
+		    WRSMD_STATE_STR(rd->rd_state));
+		return (0);
+	}
+#endif /* __lock_lint */
+
+	mutex_enter(&wrsmdp->wrsmd_runq_lock);
+
+	if (state == rd->rd_state) {
+		rd->rd_state = WRSMD_STATE_INPROGRESS;
+		retval = 1;
+		D1("wrsmdisstate: returning 1");
+	} else {
+		retval = 0;
+		D1("wrsmdisstate: state was %s, returning 0",
+		    WRSMD_STATE_STR(rd->rd_state));
+	}
+
+	mutex_exit(&wrsmdp->wrsmd_runq_lock);
+
+	return (retval);
+}
+
+/*
+ * Return destination's state, then set its state to INPROGRESS.
+ */
+static int
+wrsmdgetstate(
+	wrsmd_dest_t *rd)	/* Destination pointer */
+{
+	wrsmd_t *wrsmdp = rd->rd_wrsmdp;
+	int state;
+
+	D1("wrsmdgetstate: rd 0x%p", (void *)rd);
+
+	mutex_enter(&wrsmdp->wrsmd_runq_lock);
+
+	state = rd->rd_state;
+	rd->rd_state = WRSMD_STATE_INPROGRESS;
+
+	mutex_exit(&wrsmdp->wrsmd_runq_lock);
+
+	D1("wrsmdgetstate: returning %s", WRSMD_STATE_STR(state));
+
+	return (state);
+}
+
+/*
+ * Set destination's state; must be preceded by a getstate call.  (i.e.,
+ * destination's current state must be INPROGRESS.)
+ */
+static void
+wrsmdsetstate(
+	wrsmd_dest_t *rd,	/* Destination pointer */
+	int newstate)	/* State to set */
+{
+	wrsmd_t *wrsmdp = rd->rd_wrsmdp;
+
+	D1("wrsmdsetstate: rd 0x%p, newstate %s", (void *)rd,
+	    WRSMD_STATE_STR(newstate));
+
+	mutex_enter(&wrsmdp->wrsmd_runq_lock);
+
+	if (rd->rd_state == WRSMD_STATE_INPROGRESS) {
+		if (rd->rd_estate)
+			newstate = wrsmdestate_newstate(rd, newstate);
+		WRSMD_SETSTATE(rd, wrsmdp, "wrsmdsetstate", newstate);
+	} else {
+		D1("wrsmd: setstate without getstate");
+		cmn_err(CE_PANIC, "wrsmd: setstate without getstate");
+	}
+
+	mutex_exit(&wrsmdp->wrsmd_runq_lock);
+
+	D1("wrsmdsetstate: done");
+}
+
+/*
+ * Special case of wrsmdsetstate, designed to be called from the service
+ * routine. Does everything wrsmdsetstate does _except_ qenable the service
+ * routine.
+ */
+static void
+wrsmdsetstate_nosrv(
+	wrsmd_dest_t *rd,	/* Destination pointer */
+	int newstate)	/* State to set */
+{
+	wrsmd_t *wrsmdp = rd->rd_wrsmdp;
+
+	D1("wrsmdsetstate_nosrv: rd 0x%p, newstate %s", (void *)rd,
+	    WRSMD_STATE_STR(newstate));
+
+	mutex_enter(&wrsmdp->wrsmd_runq_lock);
+
+	if (rd->rd_state == WRSMD_STATE_INPROGRESS) {
+		if (rd->rd_estate)
+			newstate = wrsmdestate_newstate(rd, newstate);
+		WRSMD_SETSTATE_NOSRV(rd, wrsmdp, "wrsmdsetstate_nosrv",
+		    newstate);
+	} else {
+		D1("wrsmd: setstate without getstate");
+		cmn_err(CE_PANIC, "wrsmd: setstate without getstate");
+	}
+
+	mutex_exit(&wrsmdp->wrsmd_runq_lock);
+
+	D1("wrsmdsetstate_nosrv: done");
+}
+
+/*
+ * Set state to newstate iff state is oldstate.  Return 1 if move happened,
+ * else 0.
+ */
+static int
+wrsmdmovestate(
+	wrsmd_dest_t *rd,	/* Destination pointer */
+	int oldstate,	/* State to check against */
+	int newstate)	/* State to set if check succeeds */
+{
+	wrsmd_t *wrsmdp = rd->rd_wrsmdp;
+	int retval;
+
+	D1("wrsmdmovestate: rd 0x%p, oldstate %s, newstate %s",
+	    (void *)rd, WRSMD_STATE_STR(oldstate), WRSMD_STATE_STR(newstate));
+
+	mutex_enter(&wrsmdp->wrsmd_runq_lock);
+
+	if (rd->rd_state == oldstate) {
+		if (rd->rd_estate)
+			newstate = wrsmdestate_newstate(rd, newstate);
+		WRSMD_SETSTATE(rd, wrsmdp, "wrsmdmovestate", newstate);
+		retval = 1;
+		D1("wrsmdmovestate: state changed, returning 1");
+	} else {
+		retval = 0;
+		D1("wrsmdmovestate: oldstate really %s, returning 0",
+		    WRSMD_STATE_STR(rd->rd_state));
+	}
+
+	mutex_exit(&wrsmdp->wrsmd_runq_lock);
+
+	return (retval);
+}
+
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * E N D       MAIN STATE MACHINE                                *
+ *                                                               *
+ * ****************************************************************
+ */
+
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * B E G I N      HANDLERS FOR INCOMING RSM MESSAGES             *
+ *                                                               *
+ * ****************************************************************
+ */
+
+
+/*
+ * Handlers for the various messages that may arrive.  All of these happen
+ * during interrupt handling, and will not actually use RSMPI calls.
+ * Rather, they will schedule actions to happen.
+ */
+
+
+/*
+ * Received CONNECT REQUEST message.  Cause this side to set up
+ * connection to xfer segment and send back an ACCEPT message.
+ *
+ * We must have everything set up before sending the ACCEPT.
+ * However, we must not transmit any data until we receive the ACK
+ * of the ACCEPT.
+ */
+static void
+wrsmdmsghdlr_req_connect(wrsmd_dest_t *rd, wrsmd_msg_t *msg)
+{
+	wrsmd_t *wrsmdp = rd->rd_wrsmdp;
+	boolean_t utmo = B_FALSE;
+	timeout_id_t tmoid;
+
+	D1("wrsmdmsghdlr_req_connect: rd 0x%p (addr %ld ctlr %d)",
+	    (void *)rd, rd->rd_rsm_addr, rd->rd_wrsmdp->wrsmd_ctlr_id);
+
+	/*
+	 * xmit lock guarantees that timeout has really been set
+	 * for any wait conditions.
+	 */
+	mutex_enter(&rd->rd_xmit_lock);
+	mutex_enter(&wrsmdp->wrsmd_runq_lock);
+
+	if (rd->rd_segid_valid) {
+		/*
+		 * Another connect message - is it a duplicate?
+		 * If so, just ignore.  Otherwise, there is a
+		 * problem, so force a connection teardown.
+		 */
+
+		mutex_exit(&wrsmdp->wrsmd_runq_lock);
+		mutex_exit(&rd->rd_xmit_lock);
+
+		if ((rd->rd_rxfersegid != msg->p.m.con_request.send_segid) ||
+		    (rd->rd_lastconnmsg_seq != msg->p.hdr.seqno)) {
+			/* Not the same connect request, drop connection */
+			wrsmd_lostconn(rd);
+		}
+
+		return;
+	}
+
+	/* remember the message sequence number of this connection request */
+	rd->rd_lastconnmsg_seq = msg->p.hdr.seqno;
+
+	if (rd->rd_state == WRSMD_STATE_W_ACCEPT) {
+		/*
+		 * Crossed connection requests.  If we're the higher
+		 * numbered address, cancel the ACCEPT timeout and accept
+		 * the remote request.  If we're the lower numbered
+		 * address, ignore this request because the remote side
+		 * will accept ours.  If the W_ACCEPT timeout expires prior
+		 * to cancelling the timeout, the timeout function will
+		 * notice the state is no longer W_ACCEPT, and will not
+		 * cause the connection to be torn down.  If the timeout
+		 * has already occurred (and the rd state is S_DELETE),
+		 * we're out of luck, and will have to wait for a new
+		 * connection request from the remote side.
+		 */
+		if (rd->rd_rsm_addr > wrsmdp->wrsmd_rsm_addr.m.rsm) {
+			rd->rd_segid_valid = B_TRUE;
+			rd->rd_rxfersegid = msg->p.m.con_request.send_segid;
+			/* LINTED: E_CONSTANT_CONDITION */
+			WRSMD_SETSTATE(rd, wrsmdp, "wrsmdmsghdlr_req_connect",
+			    WRSMD_STATE_S_CONNXFER_ACCEPT);
+			utmo = B_TRUE;
+			tmoid = rd->rd_tmo_id;
+			rd->rd_tmo_id = 0;
+			rd->rd_tmo_int = 0;
+		}
+	} else {
+
+		/*
+		 * Save away the connection information.  If possible,
+		 * change the state to cause the request to be immediately
+		 * acted upon.  If the state is currently INPROGRESS
+		 * in the early stages of connection (during crexfer
+		 * or the start of sconn), then this request will
+		 * eventually be noticed when sconn() is called.  The
+		 * sconn() function will notice that the segid is valid,
+		 * and perform the CONNXER_ACCEPT tasks instead.
+		 *
+		 * If this rd's state was in a later stage of the
+		 * connection dance (or after a connection exists), a
+		 * previous connection request should have been received,
+		 * the new connection request will not be expected, and
+		 * this will have been caught by noticing the segid was
+		 * already valid, and cause a failure, above.
+		 */
+
+		rd->rd_segid_valid = B_TRUE;
+		rd->rd_rxfersegid = msg->p.m.con_request.send_segid;
+
+		if (rd->rd_state == WRSMD_STATE_NEW) {
+			/*
+			 * No connection was in progress.  Start a new
+			 * connection setup process.
+			 */
+			/* LINTED: E_CONSTANT_CONDITION */
+			WRSMD_SETSTATE(rd, wrsmdp, "wrsmdmsghdlr_req_connect",
+			    WRSMD_STATE_S_NEWCONN);
+
+		} else if (rd->rd_state == WRSMD_STATE_W_SCONNTMO) {
+			/*
+			 * Accept this request instead of resending our
+			 * connect request.  Cancel the timeout.  If the
+			 * SCONNTMO timeout function is called prior to
+			 * cancelling the timeout, it will notice the state
+			 * is no longer W_SCONNTMO, and will not cause a
+			 * new connection request to be sent.  If the
+			 * timeout already occurred (and rd is in the
+			 * S_SCONN state), the sconn() function will notice
+			 * that the segid is valid, and perform the
+			 * CONNXER_ACCEPT tasks instead.
+			 */
+			/* LINTED: E_CONSTANT_CONDITION */
+			WRSMD_SETSTATE(rd, wrsmdp, "wrsmdmsghdlr_req_connect",
+			    WRSMD_STATE_S_CONNXFER_ACCEPT);
+			utmo = B_TRUE;
+			tmoid = rd->rd_tmo_id;
+			rd->rd_tmo_id = 0;
+			rd->rd_tmo_int = 0;
+		}
+	}
+
+	mutex_exit(&wrsmdp->wrsmd_runq_lock);
+	mutex_exit(&rd->rd_xmit_lock);
+
+	if (utmo)
+		(void) untimeout(tmoid);
+}
+
+
+
+/*
+ * Received ACCEPT message.  Cause this side to set up a connection
+ * to the remote transfer segment and send back an ACK message.
+ */
+static void
+wrsmdmsghdlr_con_accept(wrsmd_dest_t *rd, wrsmd_msg_t *msg)
+{
+	wrsmd_t *wrsmdp = rd->rd_wrsmdp;
+	boolean_t utmo = B_FALSE;
+	timeout_id_t tmoid;
+
+	D1("wrsmdmsghdlr_con_accept: rd 0x%p (addr %ld ctlr %d)",
+	    (void *)rd, rd->rd_rsm_addr, rd->rd_wrsmdp->wrsmd_ctlr_id);
+
+	/*
+	 * xmit lock protects segid field
+	 */
+	mutex_enter(&rd->rd_xmit_lock);
+	mutex_enter(&wrsmdp->wrsmd_runq_lock);
+
+	if (rd->rd_state == WRSMD_STATE_W_ACCEPT &&
+	    rd->rd_lxfersegid == msg->p.m.con_accept.rcv_segid) {
+		rd->rd_segid_valid = B_TRUE;
+		rd->rd_rxfersegid = msg->p.m.con_accept.send_segid;
+		utmo = B_TRUE;
+		tmoid = rd->rd_tmo_id;
+		rd->rd_tmo_id = 0;
+		/* LINTED: E_CONSTANT_CONDITION */
+		WRSMD_SETSTATE(rd, wrsmdp, "wrsmdmsghdlr_con_accept",
+		    WRSMD_STATE_S_CONNXFER_ACK);
+		mutex_exit(&wrsmdp->wrsmd_runq_lock);
+		mutex_exit(&rd->rd_xmit_lock);
+
+		if (utmo)
+			(void) untimeout(tmoid);
+	} else {
+		mutex_exit(&wrsmdp->wrsmd_runq_lock);
+		mutex_exit(&rd->rd_xmit_lock);
+		wrsmd_lostconn(rd);
+		return;
+	}
+
+}
+
+
+/*
+ * Received ACK message.  Now ok to proceed with DLPI data transfer.
+ */
+static void
+wrsmdmsghdlr_con_ack(wrsmd_dest_t *rd, wrsmd_msg_t *msg)
+{
+	wrsmd_t *wrsmdp = rd->rd_wrsmdp;
+	boolean_t utmo = B_FALSE;
+	timeout_id_t tmoid;
+
+	D1("wrsmdmsghdlr_con_ack: rd 0x%p (addr %ld ctlr %d)",
+	    (void *)rd, rd->rd_rsm_addr, rd->rd_wrsmdp->wrsmd_ctlr_id);
+
+	mutex_enter(&wrsmdp->wrsmd_runq_lock);
+
+	if (rd->rd_state == WRSMD_STATE_W_ACK &&
+		msg->p.m.con_ack.rcv_segid == rd->rd_lxfersegid &&
+		msg->p.m.con_ack.send_segid == rd->rd_rxfersegid) {
+		utmo = B_TRUE;
+		tmoid = rd->rd_tmo_id;
+		rd->rd_tmo_id = 0;
+		/* LINTED: E_CONSTANT_CONDITION */
+		WRSMD_SETSTATE(rd, wrsmdp, "wrsmdmsghdlr_con_ack",
+		    WRSMD_STATE_S_XFER);
+		mutex_exit(&wrsmdp->wrsmd_runq_lock);
+
+		if (utmo)
+			(void) untimeout(tmoid);
+	} else {
+		mutex_exit(&wrsmdp->wrsmd_runq_lock);
+		wrsmd_lostconn(rd);
+		return;
+	}
+}
+
+
+/*
+ * Remote side has just sync'ed up the local DQE with its copy, so there
+ * may be buffers to deliver.
+ */
+static void
+wrsmdmsghdlr_syncdqe(wrsmd_dest_t *rd, wrsmd_msg_t *msg)
+{
+
+
+	D1("wrsmdmsghdlr_syncdqe: rd 0x%p (addr %ld ctlr %d)",
+	    (void *)rd, rd->rd_rsm_addr, rd->rd_wrsmdp->wrsmd_ctlr_id);
+
+	TNF_PROBE_1(wrsmdmsghdlr_syncdqe_start, "RSMPI",
+	    "wrsmdmsghdlr_syncdqe start",
+	    tnf_long, rd, (tnf_long_t)rd);
+
+	ASSERT(rd->rd_sstate == WRSMD_RSMS_ALL);
+
+	/*
+	 * message sanity check
+	 */
+	if (msg->p.m.syncdqe.rcv_segid != rd->rd_lxfersegid) {
+		D1("wrsmdmsghdlr_syncdqe: bad rcv_segid");
+		TNF_PROBE_1(wrsmdmsghdlr_syncdqe_end, "RSMPI",
+		    "wrsmdmsghdlr_syncdqe end; failure bad msg",
+		    tnf_string, failure, "bad msg");
+		wrsmd_lostconn(rd);
+		return;
+	}
+
+	/*
+	 * Since we'll eventually call RSM_PUT, and we're
+	 * in interrupt context, we need to process this
+	 * from the event thread
+	 */
+
+	wrsmd_add_event(rd->rd_wrsmdp, WRSMD_EVT_SYNC_DQE, (void *)rd);
+
+}
+
+
+static void
+wrsmdmsghdlr_syncdqe_evt(wrsmd_dest_t *rd)
+{
+	int bufnum, offset, length;
+	ushort_t sap;
+	timeout_id_t tmoid;
+	int freebufs = 0;
+
+
+	/* Loop through all valid DQE's and process their packets. */
+
+	D5("msghdlr_syncdqe 1: time 0x%llx", gethrtime());
+	while (wrsmdgetdqe(rd, &bufnum, &offset, &length, &sap)) {
+
+		D5("msghdlr_syncdqe 2: time 0x%llx", gethrtime());
+
+		/* Don't try to send up DQE with zero length */
+
+		if (length)
+			freebufs += wrsmdread(rd, bufnum, offset, length, sap);
+		else {
+			wrsmdputfqe(rd, bufnum);
+			freebufs++;
+		}
+		D5("msghdlr_syncdqe 3: time 0x%llx", gethrtime());
+
+		if (freebufs ==
+		    rd->rd_wrsmdp->wrsmd_param.wrsmd_fqe_sync_size) {
+			freebufs = 0;
+			mutex_enter(&rd->rd_net_lock);
+			wrsmdsyncfqe(rd);
+			mutex_exit(&rd->rd_net_lock);
+		}
+
+	}
+	if (freebufs) {
+		mutex_enter(&rd->rd_net_lock);
+		wrsmdsyncfqe(rd);
+		mutex_exit(&rd->rd_net_lock);
+	}
+
+	mutex_enter(&rd->rd_xmit_lock);
+
+	if (wrsmdisstate(rd, WRSMD_STATE_W_FQE)) {
+		int avail = wrsmdavailfqe(rd);
+
+		/*
+		 * We hold xmit_lock to keep wrsmdfqetmo() from running while
+		 * we're deciding what to do.  In the case where we're waiting
+		 * for FQE's but don't have any, if we let fqetmo run before we
+		 * set the state back to W_FQE, it won't do anything and we
+		 * could hang in that state until another packet came in
+		 * (which could be forever).
+		 */
+
+		if (avail) {
+			tmoid = rd->rd_fqe_tmo_id;
+			rd->rd_fqe_tmo_id = 0;
+			rd->rd_tmo_int = 0;
+			rd->rd_wrsmdp->wrsmd_fqetmo_hint++;
+			mutex_exit(&rd->rd_xmit_lock);
+			/*
+			 * Note: since the fqetmo gets xmit_lock, we have
+			 * to release it before we call untimeout() to prevent
+			 * a deadlock from occurring.
+			 */
+			(void) untimeout(tmoid);
+			wrsmdsetstate(rd, WRSMD_STATE_S_XFER);
+		} else {
+			wrsmdsetstate(rd, WRSMD_STATE_W_FQE);
+			mutex_exit(&rd->rd_xmit_lock);
+		}
+	} else {
+		mutex_exit(&rd->rd_xmit_lock);
+	}
+
+	D1("wrsmdmsghdlr_syncdqe: success");
+	TNF_PROBE_0(wrsmd_msg_hdlr_syncdqe_end, "RSMPI",
+	    "wrsmd_msg_hdlr_syncdqe end: success");
+}
+
+
+static void
+wrsmdmsghdlr_default(wrsmd_dest_t *rd, wrsmd_msg_t *msg)
+{
+	wrsmderror(rd->rd_wrsmdp->wrsmd_dip, "Unknown message type %d",
+	    msg->p.hdr.reqtype);
+}
+
+
+/*
+ * Handler for connection-related RSMPI messages from remote WRSMD drivers
+ */
+/* ARGSUSED */
+static rsm_intr_hand_ret_t
+wrsmd_rsm_intr_handler(rsm_controller_object_t *controller,
+    rsm_intr_q_op_t operation,
+    rsm_addr_t sender,
+    void *data,
+    size_t size,
+    rsm_intr_hand_arg_t handler_arg)
+{
+	wrsmd_t *wrsmdp = (wrsmd_t *)handler_arg;
+	wrsmd_dest_t *rd;
+	wrsmd_msg_t *msg;
+	int isdel = 0;
+	/* LINTED E_FUNC_SET_NOT_USED */
+	int isnew = 0;
+	dl_rsm_addr_t addr;
+
+
+	/*
+	 * We only handle RSM addresses that fit in 48 bits.
+	 * This is no problem for Wildcat.
+	 */
+	ASSERT(sender <= (rsm_addr_t)0xffffffffffffLL);
+	addr.m.rsm = sender;
+
+	D1("wrsmd_intr_handle: wrsmdp 0x%p (cltr %d) sender-addr %ld",
+	    (void *)wrsmdp,
+	    wrsmdp ? wrsmdp->wrsmd_ctlr_id : -1, sender);
+	TNF_PROBE_0(wrsmdintrhdlr_start, "RSMPI", "wrsmdintrhdlr start");
+
+	/* Is this our interrupt? */
+	mutex_enter(&wrsmdp->wrsmd_lock);
+	if (controller->handle != wrsmdp->wrsmd_ctlr.handle) {
+		mutex_exit(&wrsmdp->wrsmd_lock);
+		D1("wrsmd_intr_handle: bad controller handle");
+		return (RSM_INTR_HAND_UNCLAIMED);
+	}
+	mutex_exit(&wrsmdp->wrsmd_lock);
+
+	/*
+	 * We don't really care about anything but a received packet
+	 * or a queue destroy
+	 */
+	switch (operation) {
+
+	case RSM_INTR_Q_OP_CREATE: {
+		/*
+		 * Create a dest structure, on the assumption that
+		 * somebody's about to communicate with us.
+		 */
+		MAKEDEST(rd, isdel, isnew, wrsmdp, addr.m.wrsm.addr);
+		if (isdel || !rd) {
+			TNF_PROBE_1(wrsmdintrhdlr_end, "RSMPI",
+			    "wrsmdintrhdlr end; failure cantfindormkdest",
+			    tnf_string, failure, "cantfindormkdest");
+			return (RSM_INTR_HAND_CLAIMED_EXCLUSIVE);
+		}
+		UNREFDEST(rd);
+		D1("wrsmd_intr_handle: op-create/config mkdset for addr %ld",
+		    addr.m.rsm);
+		TNF_PROBE_2(wrsmdintrhdlr_end, "RSMPI", "wrsmdintrhdlr end",
+		    tnf_string, success, "queue created",
+		    tnf_long, rval, DDI_SUCCESS);
+		return (RSM_INTR_HAND_CLAIMED_EXCLUSIVE);
+	}
+
+	case RSM_INTR_Q_OP_CONFIGURE:
+		/* ignore configure messages */
+		return (RSM_INTR_HAND_CLAIMED_EXCLUSIVE);
+
+	case RSM_INTR_Q_OP_DROP:
+	case RSM_INTR_Q_OP_DESTROY: {
+		/*
+		 * The remote side has shut down the connection.  We need
+		 * to shut local side of the connection down as well.
+		 */
+		FINDDEST(rd, isdel, wrsmdp, addr.m.rsm);
+		if (isdel || !rd) {
+			TNF_PROBE_1(wrsmdintrhdlr_end, "RSMPI",
+			    "wrsmdintrhdlr end; failure cantfinddest",
+			    tnf_string, failure, "cantfinddest");
+			return (RSM_INTR_HAND_CLAIMED_EXCLUSIVE);
+		}
+		D1("wrsmd_intr_handle: op-destroy for addr %ld", addr.m.rsm);
+		wrsmd_lostconn(rd);
+		UNREFDEST(rd);
+		TNF_PROBE_2(wrsmdintrhdlr_end, "RSMPI", "wrsmdintrhdlr end",
+		    tnf_string, success, "queue destroyed",
+		    tnf_long, rval, DDI_SUCCESS);
+		return (RSM_INTR_HAND_CLAIMED_EXCLUSIVE);
+	}
+
+	case RSM_INTR_Q_OP_RECEIVE:
+		/*
+		 * A DLPI message from the remote node.  Handle in the main
+		 * body.
+		 */
+		break;
+
+	default:
+		/* ignore */
+		TNF_PROBE_0(wrsmdintrhdlr_end, "RSMPI",
+		    "wrsmdintrhdlr end; unknown message type");
+		return (RSM_INTR_HAND_UNCLAIMED);
+	}
+
+	/*
+	 * Dest should already exist, having been created by the
+	 * RSM_INTR_Q_OP_CREATE, above.
+	 */
+
+	FINDDEST(rd, isdel, wrsmdp, addr.m.rsm);
+	if (isdel) {
+		TNF_PROBE_1(wrsmdintrhdlr_end, "RSMPI",
+		    "wrsmdintrhdlr end; failure dest deleting",
+		    tnf_string, failure, "deleting");
+		return (RSM_INTR_HAND_CLAIMED_EXCLUSIVE);
+	} else if (rd == NULL) {
+		D1("wrsmd_rsm_intr_handler: can't finddest");
+		TNF_PROBE_1(wrsmdintrhdlr_end, "RSMPI",
+		    "wrsmdintrhdlr end; failure cantfinddest",
+		    tnf_string, failure, "cantfinddest");
+		return (RSM_INTR_HAND_CLAIMED_EXCLUSIVE);
+	}
+
+
+	msg = (wrsmd_msg_t *)data;
+
+	if (msg->p.hdr.wrsmd_version != WRSMD_VERSION) {
+		/*
+		 * Non-matching driver version!
+		 * Toss message.
+		 */
+		wrsmderror(wrsmdp->wrsmd_dip,
+		    "non-matching wrsmd version (%d) in "
+		    "message", msg->p.hdr.wrsmd_version);
+		UNREFDEST(rd);
+		return (RSM_INTR_HAND_CLAIMED_EXCLUSIVE);
+	}
+
+	switch (msg->p.hdr.reqtype) {
+
+	case WRSMD_MSG_REQ_CONNECT:
+		wrsmdmsghdlr_req_connect(rd, msg);
+		break;
+
+	case WRSMD_MSG_CON_ACCEPT:
+		wrsmdmsghdlr_con_accept(rd, msg);
+		break;
+
+	case WRSMD_MSG_CON_ACK:
+		wrsmdmsghdlr_con_ack(rd, msg);
+		break;
+
+		/*
+		 * Maybe scan the incoming queue at this time?
+		 */
+	case WRSMD_MSG_SYNC_DQE:
+		wrsmdmsghdlr_syncdqe(rd, msg);
+		break;
+
+	default:
+		wrsmdmsghdlr_default(rd, msg);
+		break;
+	}
+
+	UNREFDEST(rd);
+
+	TNF_PROBE_2(wrsmdintrhdlr_end, "RSMPI", "wrsmdintrhdlr end",
+	    tnf_string, success, "",
+	    tnf_long, rval, DDI_SUCCESS);
+	return (RSM_INTR_HAND_CLAIMED_EXCLUSIVE);
+}
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * E N D       HANDLERS FOR INCOMING RSM MESSAGES                *
+ *                                                               *
+ * ****************************************************************
+ */
+
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * B E G I N   CONNECTION MANAGEMENT                             *
+ *                                                               *
+ * ****************************************************************
+ */
+
+/*
+ * Create and initialize a transfer segment for the remote destination.  If
+ * successful, return 0, else 1.  The destination's state must be
+ * INPROGRESS.  In remains INPROGRESS during this function.
+ */
+static int
+wrsmdcrexfer(wrsmd_t *wrsmdp, wrsmd_dest_t *rd)
+{
+	volatile wrsmd_xfer_hdr_t *xfer;
+	wrsmd_fqe_t fqe;
+	volatile wrsmd_fqe_t *fqep;
+	wrsmd_dqe_t dqe;
+	volatile wrsmd_dqe_t *dqep;
+	wrsmdbuf_t *rbp;
+	uint_t bufsize;
+	int i, stat;
+	uint32_t buf_offset, fq_offset, dq_offset;
+	size_t xfer_size;
+	caddr_t xfer_start;
+	size_t roundup;
+	size_t transport_pgsize = 0;
+	rsm_access_entry_t perms;
+
+	D1("wrsmdcrexfer: rd 0x%p (addr %ld ctlr %d)",
+	    (void *)rd, rd->rd_rsm_addr, wrsmdp->wrsmd_ctlr_id);
+	TNF_PROBE_2(wrsmdcrexfer_start, "RSMPI", "wrsmdcrexfer start",
+	    tnf_long, wrsmdp, (tnf_long_t)wrsmdp, tnf_long, rd, (tnf_long_t)rd);
+
+	ASSERT(rd->rd_rawmem_base_addr == NULL);
+	ASSERT(rd->rd_rawmem_base_size == 0);
+
+	bufsize = wrsmdp->wrsmd_param.wrsmd_buffer_size;
+
+	for (i = 0; i <  (sizeof (size_t) * 8); i++) {
+		if (wrsmdp->wrsmd_ctlr_attr->attr_page_size &
+		    ((size_t)1 << i)) {
+			transport_pgsize = 1024 << i;
+			break;
+		}
+	}
+	if (transport_pgsize == 0) {
+		cmn_err(CE_CONT, "?wrsmd: crexfer, invalid transport "
+		    "page sizes (attr_page_size is 0x%lx)",
+		    wrsmdp->wrsmd_ctlr_attr->attr_page_size);
+		return (1);
+	}
+
+
+	/*
+	 * Make sure the remote side is responding before setting
+	 * up the local xfer segment.
+	 */
+	stat = RSM_SENDQ_CREATE(wrsmdp->wrsmd_ctlr, rd->rd_rsm_addr,
+	    RSM_INTR_T_SUN_BASE, RSM_DLPI_QPRI, RSM_DLPI_QDEPTH,
+	    RSM_DLPI_QFLAGS, RSM_RESOURCE_DONTWAIT, 0, &(rd->rsm_sendq));
+
+	if (stat != RSM_SUCCESS) {
+		D1("wrsmdcrexfer: can't create send queue, stat 0x%x, "
+		    "returning 1", stat);
+		TNF_PROBE_2(wrsmdcrexfer_end, "RSMPI",
+		    "wrsmdcrexfer end; failure RSM_SENDQ_CREATE",
+		    tnf_string, failure, "RSM_SENDQ_CREATE",
+		    tnf_long, stat, stat);
+		cmn_err(CE_CONT, "?wrsmd: crexfer create send queue, "
+		    "stat 0x%x", stat);
+		return (1);
+	}
+	rd->rd_sstate |= WRSMD_RSMS_RXFER_S;
+
+
+	/*
+	 * Allocate memory for segment.  Allow for alignment of DQE list
+	 * and FQE list.  Also allow buffers to be aligned on
+	 * RSM-page-sized boundaries.
+	 */
+	xfer_size = sizeof (*xfer) + 64 +
+	    (sizeof (wrsmd_dqe_t) * wrsmdp->wrsmd_param.wrsmd_queue_size)
+	    + 64 +
+	    (sizeof (wrsmd_fqe_t) * wrsmdp->wrsmd_param.wrsmd_queue_size)
+	    + 64 +
+	    (bufsize * wrsmdp->wrsmd_param.wrsmd_buffers)
+	    + (transport_pgsize -1);
+
+	xfer_start = kmem_alloc(xfer_size, KM_NOSLEEP);
+	if (!xfer_start) {
+		D1("wrsmdcrexfer: can't allocate memory, returning 1");
+		TNF_PROBE_1(wrsmdcrexfer_end, "RSMPI",
+		    "wrsmdcrexfer end; failure kmem_alloc",
+		    tnf_string, failure, "kmem_alloc");
+		cmn_err(CE_CONT, "?wrsmd: crexfer, failed to alloc");
+		return (1);
+	}
+	rd->rd_rawmem_base_addr = xfer_start;
+	rd->rd_rawmem_base_size = xfer_size;
+
+	/*
+	 * Round up memory pointer and round down size to allow alignment
+	 * within the transport's supported page size.
+	 */
+	roundup = transport_pgsize - ((uint64_t)xfer_start &
+	    (transport_pgsize -1));
+	if (roundup != transport_pgsize) {
+		xfer_size -= roundup;
+		xfer_start += roundup;
+	}
+	xfer_size = xfer_size & ~(transport_pgsize - 1);
+	rd->rd_memory.ms_type = RSM_MEM_VADDR;
+	rd->rd_memory.ms_memory.vr.length = xfer_size;
+	rd->rd_memory.ms_memory.vr.as = NULL;	/* kas */
+	rd->rd_memory.ms_memory.vr.vaddr = xfer_start;
+
+	D2("wrsmdcrexfer: rawsize 0x%lx rawmem 0x%p xfersize 0x%lx "
+	    "xfermem 0x%p pgsize 0x%lx\n",
+	    rd->rd_rawmem_base_size,
+	    (void *)rd->rd_rawmem_base_addr,
+	    xfer_size,
+	    (void *)xfer_start,
+	    transport_pgsize);
+
+	xfer = (volatile struct wrsmd_xfer_hdr *)xfer_start;
+
+	/* Force FQ to start on a 64-byte boundary. */
+	fq_offset = sizeof (struct wrsmd_xfer_hdr);
+	fq_offset = WRSMD_CACHELINE_ROUNDUP(fq_offset);
+
+	/* Force DQ to start on a 64-byte boundary. */
+	dq_offset = fq_offset + (sizeof (wrsmd_fqe_t) *
+	    wrsmdp->wrsmd_param.wrsmd_queue_size);
+	dq_offset = WRSMD_CACHELINE_ROUNDUP(dq_offset);
+
+	/* Force buffers to start on a 64-byte boundary. */
+	buf_offset = dq_offset + (sizeof (wrsmd_dqe_t) *
+	    wrsmdp->wrsmd_param.wrsmd_queue_size);
+	buf_offset = WRSMD_CACHELINE_ROUNDUP(buf_offset);
+
+	/*
+	 * Note that while we set the _f and _n queue pointers and the
+	 * queue lengths here, the _l pointers will be set (and the lengths
+	 * may be adjusted) when we connect to the remote xfer segment (see
+	 * connxfer).
+	 */
+	mutex_enter(&rd->rd_net_lock);
+
+	rd->rd_fqr_f = rd->rd_fqr_n = (volatile wrsmd_fqe_t *) (xfer_start +
+	    fq_offset);
+	rd->rd_fqr_seq = 1;
+	rd->rd_num_fqrs = wrsmdp->wrsmd_param.wrsmd_queue_size;
+
+	rd->rd_dqr_f = rd->rd_dqr_n = (volatile wrsmd_dqe_t *) (xfer_start +
+	    dq_offset);
+	rd->rd_dqr_seq = 1;
+	rd->rd_num_dqrs = wrsmdp->wrsmd_param.wrsmd_queue_size;
+
+	rd->rd_lbuf = xfer_start + buf_offset;
+	rd->rd_lbuflen = bufsize;
+	rd->rd_numlbufs = wrsmdp->wrsmd_param.wrsmd_buffers;
+
+	/*
+	 * Initialize the delivery and free queues:  elements in the free
+	 * queue are valid, and elements in the delivery queue are invalid
+	 * (seqno == 0).
+	 */
+	fqep = rd->rd_fqr_f;
+	dqep = rd->rd_dqr_f;
+
+	dqe.s.dq_seqnum = 0;
+	dqe.s.dq_bufnum = (ushort_t)~0;
+
+	fqe.s.fq_seqnum = 1;
+
+	for (i = 0; i < wrsmdp->wrsmd_param.wrsmd_queue_size; i++) {
+		fqe.s.fq_bufnum = (ushort_t)i;
+
+		*fqep++ = fqe;
+		*dqep++ = dqe;
+	}
+
+	mutex_exit(&rd->rd_net_lock);
+
+	/*
+	 * Allocate and init our structures to describe loaned-up buffers.
+	 */
+
+	rbp = rd->rd_bufbase = kmem_zalloc(wrsmdp->wrsmd_param.wrsmd_buffers *
+	    sizeof (*rd->rd_bufbase), KM_NOSLEEP);
+
+	if (rbp == NULL) {
+		D1("wrsmdcrexfer: can't alloc rbp structs, returning 1");
+		TNF_PROBE_2(wrsmdcrexfer_end, "RSMPI",
+		    "wrsmdcrexfer end; failure kmem_zalloc bufbase",
+		    tnf_string, failure, "kmem_zalloc",
+		    tnf_long, stat, (tnf_long_t)rbp);
+		cmn_err(CE_CONT, "?wrsmd: abuf");
+		return (1);
+	}
+
+	for (i = 0; i < rd->rd_numlbufs; i++) {
+		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rbp))
+		rbp->rb_rd = rd;
+		rbp->rb_frtn.free_func = wrsmdfreebuf;
+		rbp->rb_frtn.free_arg = (char *)rbp;
+		rbp->rb_bufnum = i;
+		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rbp))
+		rbp++;
+	}
+
+	mutex_init(&rd->rd_nlb_lock, NULL, MUTEX_DRIVER, NULL);
+	mutex_enter(&rd->rd_nlb_lock);
+	rd->rd_nlb = 0;
+	mutex_exit(&rd->rd_nlb_lock);
+
+	/*
+	 * Set everything in the header of the segment.
+	 */
+
+	xfer->rx_segsize = xfer_size;
+	xfer->rx_buf_offset = buf_offset;
+	xfer->rx_fq_offset = fq_offset;
+	xfer->rx_dq_offset = dq_offset;
+	xfer->rx_numbufs = rd->rd_numlbufs;
+	xfer->rx_bufsize = rd->rd_lbuflen;
+	xfer->rx_numfqes = rd->rd_num_fqrs;
+	xfer->rx_numdqes = rd->rd_num_dqrs;
+
+	D1("wrsmdcrexfer: rx_buf_offset 0x%x fq_offset 0x%x dq_offset 0x%x "
+	    "rd_numlbufs 0x%x rd_lbuflen 0x%x rd_num_fqrs 0x%x "
+	    "rd_num_dqrs 0x%x\n",
+	    buf_offset,
+	    fq_offset,
+	    dq_offset,
+	    rd->rd_numlbufs,
+	    rd->rd_lbuflen,
+	    rd->rd_num_fqrs,
+	    rd->rd_num_dqrs);
+
+	xfer->rx_cookie = WRSMD_XFER_COOKIE;
+
+	/*
+	 * Local xfer segment is now initialized; make it available to the
+	 * remote node.
+	 */
+
+	stat = RSM_SEG_CREATE(wrsmdp->wrsmd_ctlr, &(rd->rd_lxferhand),
+	    xfer_size, 0, &(rd->rd_memory), RSM_RESOURCE_DONTWAIT, 0);
+
+	if (stat != RSM_SUCCESS) {
+		D1("wrsmdcrexfer: can't create RSM segment, stat 0x%x, "
+		    "return 1", stat);
+		TNF_PROBE_2(wrsmdcrexfer_end, "RSMPI",
+		    "wrsmdcrexfer end; failure RSM_SEG_CREATE",
+		    tnf_string, failure, "RSM_SEG_CREATE",
+		    tnf_long, stat, stat);
+		cmn_err(CE_CONT, "?wrsmd: crexfer, stat 0x%x", stat);
+		return (1);
+	}
+	rd->rd_sstate |= WRSMD_RSMS_LXFER_C;
+
+
+	/*
+	 * Publish this segment.  First try using an id that is likely
+	 * to be unique.
+	 */
+	perms.ae_addr = rd->rd_rsm_addr;
+	perms.ae_permission = RSM_PERM_RDWR;
+	stat = RSMERR_SEGID_IN_USE;
+	if (rd->rd_rsm_addr <= (RSM_DLPI_ID_END - RSM_DLPI_ID_BASE)) {
+		rd->rd_lxfersegid = RSM_DLPI_ID_BASE +
+		    (uint32_t)rd->rd_rsm_addr;
+		stat = (RSM_PUBLISH(wrsmdp->wrsmd_ctlr, rd->rd_lxferhand,
+		    &perms, 1, rd->rd_lxfersegid, NULL, 0));
+	}
+	if (stat == RSMERR_SEGID_IN_USE) {
+		/* Couldn't use default id; try other ids in allowed range  */
+		rd->rd_lxfersegid = RSM_DLPI_ID_BASE;
+		while ((stat = (RSM_PUBLISH(wrsmdp->wrsmd_ctlr,
+		    rd->rd_lxferhand,
+		    &perms, 1, rd->rd_lxfersegid, NULL, 0))) ==
+		    RSMERR_SEGID_IN_USE && rd->rd_lxfersegid < RSM_DLPI_ID_END)
+			rd->rd_lxfersegid++;
+	}
+
+	if (stat != RSM_SUCCESS) {
+		D1("wrsmdcrexfer: can't publish, stat 0x%x, returning 1",
+		    stat);
+		TNF_PROBE_2(wrsmdcrexfer_end, "RSMPI",
+		    "wrsmdcrexfer end; failure wrsmd_export_segment",
+		    tnf_string, failure, "wrsmd_export_segment",
+		    tnf_long, stat, stat);
+		cmn_err(CE_CONT, "?wrsmd: expxfer, stat 0x%x", stat);
+		return (1);
+	}
+	rd->rd_sstate |= WRSMD_RSMS_LXFER_P;
+
+	D1("wrsmdcrexfer: returning 0");
+	TNF_PROBE_2(wrsmdcrexfer_end, "RSMPI", "wrsmdcrexfer end",
+	    tnf_string, completed, "",
+	    tnf_long, stat, 0);
+	return (0);
+}
+
+/*
+ * Send a connect request to the remote.
+ *
+ * If we've received a Connect message from the destination, connect to the
+ * remote transfer segment.  Otherwise, send them a Connect Request
+ * message.  On success, return 0.  If the connect fails return 1.  A
+ * failure in sending a Connect Request message will result in a retry
+ * timeout being scheduled, but will not return 1 unless the total timeout
+ * period has expired.  Destination's state must be INPROGRESS when called.
+ * Destination's state is set to a new state prior to returning.
+ */
+static int
+wrsmdsconn(
+	wrsmd_t *wrsmdp,	/* WRSMD device (RSM controller) pointer */
+	wrsmd_dest_t *rd,	/* Destination pointer */
+	int fromtmo)	/* 0 if this is our first attempt; nonzero if this */
+			/*  is a retry, requested by a timeout routine. */
+{
+	int stat;
+
+	D1("wrsmdsconn: rd 0x%p (addr %ld ctlr %d)",
+	    (void *)rd, rd->rd_rsm_addr, wrsmdp->wrsmd_ctlr_id);
+	TNF_PROBE_3(wrsmdsconn_start, "RSMPI", "wrsmdsconn start",
+	    tnf_long, wrsmdp, (tnf_long_t)wrsmdp, tnf_long, rd, (tnf_long_t)rd,
+	    tnf_long, fromtmo, fromtmo);
+
+	if (rd->rd_segid_valid) {
+		/*
+		 * We've gotten a Connect Request from the remote side
+		 * while in INPROGRESS state.  Don't send our request;
+		 * instead, connect to the remote transfer segment.
+		 */
+
+		if ((stat = wrsmdconnxfer(wrsmdp, rd)) != 0) {
+			return (stat);
+		}
+		return (wrsmdsaccept(wrsmdp, rd));
+	}
+
+	/*
+	 * We haven't gotten a Connect Request from them, so we
+	 * need to send one of our own.
+	 */
+
+	/*
+	 * If this is a timeout retry, send the same Connect Request
+	 * message we sent the first time.
+	 */
+	if (fromtmo) {
+		stat = wrsmdsendmsg(rd, WRSMD_REXMIT, 0);
+	} else {
+		wrsmd_msg_t msg;
+		msg.p.m.con_request.send_segid = rd->rd_lxfersegid;
+		stat = wrsmdsendmsg(rd, WRSMD_MSG_REQ_CONNECT, &msg);
+	}
+
+	/*
+	 * xmit lock guarantees new state and timeout setup both occur
+	 * without an intervening state change.  See
+	 * wrsmdmsghdlr_req_connect().
+	 */
+	mutex_enter(&rd->rd_xmit_lock);
+
+	if (stat == RSM_SUCCESS) {	/* Success */
+		/*
+		 * Set up a timeout to remind us if an ACCEPT never
+		 * shows up.  This is only a 1-time timeout, no
+		 * backoff is needed.
+		 */
+
+		wrsmdsetstate(rd, WRSMD_STATE_W_ACCEPT);
+
+		rd->rd_tmo_int = wrsmdp->wrsmd_param.wrsmd_ack_tmo;
+		rd->rd_tmo_tot = 0;
+		rd->rd_tmo_id = timeout(wrsmdaccepttmo, (caddr_t)rd,
+		    rd->rd_tmo_int);
+	} else {
+		/*
+		 * We couldn't send the message, set up a timeout to
+		 * try again a little later.
+		 */
+
+		wrsmdsetstate(rd, WRSMD_STATE_W_SCONNTMO);
+
+		if (!fromtmo) {
+			rd->rd_tmo_int =
+			    wrsmdp->wrsmd_param.wrsmd_msg_init_tmo;
+			rd->rd_tmo_tot = 0;
+			D2("wrsmdsconn: !fromtmo, tmo_int %d, "
+			    "tmo_tot %d", rd->rd_tmo_int,
+			    rd->rd_tmo_tot);
+		} else {
+			/* Do exponential backoff */
+
+			rd->rd_tmo_tot += rd->rd_tmo_int;
+			rd->rd_tmo_int *= 2;
+
+			/* If we've waited too long, fail */
+
+			if (rd->rd_tmo_tot >=
+			    wrsmdp->wrsmd_param.wrsmd_msg_drop_tmo) {
+				TNF_PROBE_2(wrsmdsconn_end, "RSMPI",
+				    "wrsmdsconn end; failure timeout",
+				    tnf_string, failure, "timeout",
+				    tnf_long, stat, rd->rd_tmo_tot);
+				mutex_exit(&rd->rd_xmit_lock);
+				(void) wrsmdgetstate(rd);
+				D1("wrsmdsconn: tmo limit reached, "
+				    "returning 1");
+				return (1);
+			}
+
+			/* Clip timeout to maximum */
+
+			if (rd->rd_tmo_int >
+			    wrsmdp->wrsmd_param.wrsmd_msg_max_tmo)
+				rd->rd_tmo_int =
+				    wrsmdp->wrsmd_param.wrsmd_msg_max_tmo;
+
+			D2("wrsmdsconn: tmo_int %d, tmo_tot %d",
+			    rd->rd_tmo_int, rd->rd_tmo_tot);
+		}
+
+		rd->rd_tmo_id = timeout(wrsmdsconntmo, (caddr_t)rd,
+		    rd->rd_tmo_int);
+	}
+
+	mutex_exit(&rd->rd_xmit_lock);
+
+	D1("wrsmdsconn: returning 0");
+	TNF_PROBE_2(wrsmdsconn_end, "RSMPI", "wrsmdsconn end",
+	    tnf_string, completed, "",
+	    tnf_long, stat, 0);
+	return (0);
+}
+
+
+/*
+ * Connect to the transfer segment on the destination machine.  If an error
+ * occurs, return 1.  Destination state must be INPROGRESS.  It remains
+ * INPROGRESS during this function.
+ */
+static int
+wrsmdconnxfer(wrsmd_t *wrsmdp, wrsmd_dest_t *rd)
+{
+	uint_t num_rbufs;
+	int stat;
+	int i;
+	wrsmd_fqe_t fqe;
+	volatile wrsmd_fqe_t *fqep;
+	wrsmd_dqe_t dqe;
+	volatile wrsmd_dqe_t *dqep;
+	size_t segsize;
+
+	D1("wrsmdconnxfer: rd 0x%p (addr %ld ctlr %d)",
+	    (void *)rd, rd->rd_rsm_addr, wrsmdp->wrsmd_ctlr_id);
+	TNF_PROBE_2(wrsmdconnxfer_start, "RSMPI", "wrsmdconnxfer start",
+	    tnf_long, wrsmdp, (tnf_long_t)wrsmdp, tnf_long, rd, (tnf_long_t)rd);
+
+	mutex_enter(&rd->rd_xmit_lock);
+
+	stat = RSM_CONNECT(wrsmdp->wrsmd_ctlr, rd->rd_rsm_addr,
+	    rd->rd_rxfersegid, &(rd->rd_rxferhand));
+	if (stat != RSM_SUCCESS) {
+		D1("wrsmdconnxfer: can't connxfer, stat 0x%x, returning 1",
+		    stat);
+		cmn_err(CE_CONT, "?wrsmd: connxfer, stat 0x%x", stat);
+		TNF_PROBE_2(wrsmdconnxfer_end, "RSMPI",
+		    "wrsmdconnxfer end; failure RSM_CONNECT",
+		    tnf_string, failure, "RSM_CONNECT",
+		    tnf_long, stat, stat);
+		mutex_exit(&rd->rd_xmit_lock);
+		return (1);
+	}
+
+	rd->rd_sstate |= WRSMD_RSMS_RXFER_C;
+
+
+	/*
+	 * Copy entire header struct into local memory
+	 */
+
+	stat = RSM_GET(wrsmdp->wrsmd_ctlr, rd->rd_rxferhand, 0,
+	    &(rd->rd_rxferhdr), sizeof (wrsmd_xfer_hdr_t));
+	if (stat != RSM_SUCCESS) {
+		D1("wrsmdconnxfer: can't read xfer header, returning 1");
+		TNF_PROBE_2(wrsmdconnxfer, "RSMPI",
+		    "wrsmdconnxfer end; failure timeout",
+		    tnf_string, failure, "timeout",
+		    tnf_long, stat, 1);
+		cmn_err(CE_CONT, "?wrsmd: read xfer header failed, err=%d",
+			stat);
+		mutex_exit(&rd->rd_xmit_lock);
+		return (1);
+	}
+
+
+
+	/*
+	 * Validate header structure, extract some values from it
+	 */
+	if (rd->rd_rxferhdr.rx_cookie != WRSMD_XFER_COOKIE) {
+		D1("wrsmdconnxfer: badxfer, cookie 0x%x, returning 1",
+		    rd->rd_rxferhdr.rx_cookie);
+		TNF_PROBE_1(wrsmdconnxfer, "RSMPI",
+		    "wrsmdconnxfer end; failure 'bad xfer'",
+		    tnf_string, failure, "bad xfer");
+		cmn_err(CE_CONT, "?wrsmd: badxfer, cookie 0x%x",
+		    (uint_t)rd->rd_rxferhdr.rx_cookie);
+		mutex_exit(&rd->rd_xmit_lock);
+		return (1);
+	}
+
+	D1("wrsmdconnxfer: remote buf_offset 0x%x fq_offset 0x%x "
+	    "dq_offset 0x%x rd_numbufs 0x%x rd_lbuflen 0x%x "
+	    "rd_numfqes 0x%x rd_numdqes 0x%x\n",
+		rd->rd_rxferhdr.rx_buf_offset,
+		rd->rd_rxferhdr.rx_fq_offset,
+		rd->rd_rxferhdr.rx_dq_offset,
+		rd->rd_rxferhdr.rx_numbufs,
+		rd->rd_rxferhdr.rx_bufsize,
+		rd->rd_rxferhdr.rx_numfqes,
+		rd->rd_rxferhdr.rx_numdqes);
+
+	segsize = rd->rd_rxferhdr.rx_segsize;
+
+	num_rbufs = rd->rd_rxferhdr.rx_numbufs;
+
+	D1("num_rbufs 0x%x wrsmd_queue_size 0x%x\n", num_rbufs,
+		wrsmdp->wrsmd_param.wrsmd_queue_size);
+	/*
+	 * Must be at least one more element in queue than the
+	 * number of buffers, so that we can track when all queue
+	 * elements need to be flushed to remote side.
+	 */
+	if (num_rbufs >= wrsmdp->wrsmd_param.wrsmd_queue_size)
+		num_rbufs = wrsmdp->wrsmd_param.wrsmd_queue_size - 1;
+
+	mutex_enter(&rd->rd_net_lock);
+
+	rd->rd_rbufoff = rd->rd_rxferhdr.rx_buf_offset;
+	rd->rd_rbuflen = rd->rd_rxferhdr.rx_bufsize;
+	rd->rd_numrbuf = num_rbufs;
+	if ((rd->rd_rbufoff + (rd->rd_rbuflen * num_rbufs)) > segsize) {
+		D1("wrsmd: badxfer, rbufoff too big");
+		cmn_err(CE_CONT, "?wrsmd: badxfer, rbufoff too big");
+		mutex_exit(&rd->rd_net_lock);
+		mutex_exit(&rd->rd_xmit_lock);
+		return (1);
+	}
+
+	rd->rd_fqw_f_off = rd->rd_rxferhdr.rx_fq_offset;
+	rd->rd_num_fqws = rd->rd_rxferhdr.rx_numfqes;
+
+	if ((rd->rd_fqw_f_off + (sizeof (wrsmd_fqe_t) * rd->rd_num_fqws))
+	    > segsize) {
+		D1("wrsmd: badxfer, fqw_f_off too big");
+		cmn_err(CE_CONT, "?wrsmd: badxfer, fqw_f_off too big");
+		mutex_exit(&rd->rd_net_lock);
+		mutex_exit(&rd->rd_xmit_lock);
+		return (1);
+	}
+
+	rd->rd_dqw_f_off = rd->rd_rxferhdr.rx_dq_offset;
+	rd->rd_num_dqws = rd->rd_rxferhdr.rx_numdqes;
+
+	if ((rd->rd_dqw_f_off + (sizeof (wrsmd_dqe_t) * rd->rd_num_dqws))
+	    > segsize) {
+		D1("wrsmd: badxfer, dqw_f_off too big");
+		cmn_err(CE_CONT, "?wrsmd: badxfer, dqw_f_off too big");
+		mutex_exit(&rd->rd_net_lock);
+		mutex_exit(&rd->rd_xmit_lock);
+		return (1);
+	}
+
+	/*
+	 * Now that we know the number of remote buffers and queue elements,
+	 * shrink everything to fit and calculate the ends of all queues.
+	 */
+
+
+	D1("rd_numlbufs 0x%x rd_num_fqws 0x%x rd_num_dqrs 0x%x\n",
+	    rd->rd_numlbufs, rd->rd_num_fqws, rd->rd_num_dqrs);
+	rd->rd_numlbufs =
+		min(rd->rd_numlbufs, min(rd->rd_num_fqws - 1,
+		rd->rd_num_dqrs - 1));
+	rd->rd_num_fqws = rd->rd_num_dqrs =
+		min(rd->rd_numlbufs + 1, min(rd->rd_num_fqws, rd->rd_num_dqrs));
+
+	D1("rd_numrbuf 0x%x rd_num_fqrs 0x%x rd_num_dqws 0x%x\n",
+	    rd->rd_numrbuf, rd->rd_num_fqrs, rd->rd_num_dqws);
+	rd->rd_numrbuf =
+		min(rd->rd_numrbuf, min(rd->rd_num_fqrs - 1,
+		rd->rd_num_dqws - 1));
+	rd->rd_num_fqrs = rd->rd_num_dqws =
+		min(rd->rd_numrbuf + 1, min(rd->rd_num_fqrs, rd->rd_num_dqws));
+
+	rd->rd_fqr_l = rd->rd_fqr_f + rd->rd_num_fqrs - 1;
+	/* mark last entry of free queue as invalid */
+	rd->rd_fqr_l->s.fq_seqnum = 0;
+	rd->rd_fqr_l->s.fq_bufnum = (ushort_t)~0;
+	rd->rd_dqr_l = rd->rd_dqr_f + rd->rd_num_dqrs - 1;
+
+	/* Create FQE cache, outgoing FQE/DQE queues */
+
+	D1("wrsmdconnxfer: num_fqrs 0x%x num_fqws 0x%x num_dqws 0x%x",
+	    rd->rd_num_fqrs, rd->rd_num_fqws, rd->rd_num_dqws);
+
+	if ((rd->rd_rbufoff + (rd->rd_rbuflen * num_rbufs)) > segsize) {
+		D1("wrsmd: badxfer, bufsize * num buf too big");
+		cmn_err(CE_CONT, "?wrsmd: badxfer, bufsize * num buf too big");
+		mutex_exit(&rd->rd_net_lock);
+		mutex_exit(&rd->rd_xmit_lock);
+		return (1);
+	}
+	if ((rd->rd_fqw_f_off + (sizeof (wrsmd_fqe_t) * rd->rd_num_fqws))
+	    > segsize) {
+		D1("wrsmd: badxfer, fqesize * num fqe too big");
+		cmn_err(CE_CONT, "?wrsmd: badxfer, fqesize * num fqe too big");
+		mutex_exit(&rd->rd_net_lock);
+		mutex_exit(&rd->rd_xmit_lock);
+		return (1);
+	}
+	if ((rd->rd_dqw_f_off + (sizeof (wrsmd_dqe_t) * rd->rd_num_dqws))
+	    > segsize) {
+		D1("wrsmd: badxfer, dqesize * num dqe too big");
+		cmn_err(CE_CONT, "?wrsmd: badxfer, dqesize * num dqe too big");
+		mutex_exit(&rd->rd_net_lock);
+		mutex_exit(&rd->rd_xmit_lock);
+		return (1);
+	}
+
+	rd->rd_cached_fqr = kmem_alloc(sizeof (*rd->rd_cached_fqr) *
+		rd->rd_num_fqrs, KM_NOSLEEP);
+
+	/*
+	 * Make sure any local queue that will be transferred or sync'd is
+	 * WRSMD_CACHLINE_SIZE'd aligned. This means that when the data is
+	 * loaded into the FPU registers for transfer,it is already aligned.
+	 * This is a minor optimisation. For FireLink, only the remote
+	 * (destination) side needs to be aligned for interconnect
+	 * performance.
+	 */
+
+	rd->rd_shdwfqw_f_addr = kmem_alloc((sizeof (wrsmd_fqe_t) *
+		rd->rd_num_fqws) + WRSMD_CACHELINE_SIZE, KM_NOSLEEP);
+
+	rd->rd_shdwdqw_f_addr = kmem_alloc((sizeof (wrsmd_dqe_t) *
+		rd->rd_num_dqws) + WRSMD_CACHELINE_SIZE, KM_NOSLEEP);
+
+	if (rd->rd_cached_fqr == NULL || rd->rd_shdwfqw_f_addr == NULL ||
+	    rd->rd_shdwdqw_f_addr == NULL) {
+		D1("wrsmdconnxfer: can't alloc memory for shadow queues, "
+		    "returning 1");
+		TNF_PROBE_2(wrsmdconnxfer, "RSMPI",
+		    "wrsmdconnxfer end; failure kmem_alloc",
+		    tnf_string, failure, "kmem_alloc",
+		    tnf_long, stat, 1);
+		cmn_err(CE_CONT, "?wrsmd: can't get memory in connxfer");
+		mutex_exit(&rd->rd_net_lock);
+		mutex_exit(&rd->rd_xmit_lock);
+		return (1);
+	}
+
+	rd->rd_shdwfqw_f = (wrsmd_fqe_t *)
+		WRSMD_CACHELINE_ROUNDUP(rd->rd_shdwfqw_f_addr);
+	rd->rd_shdwdqw_f = (wrsmd_dqe_t *)
+		WRSMD_CACHELINE_ROUNDUP(rd->rd_shdwdqw_f_addr);
+
+	/*
+	 * Initialize the shadow delivery and free queues:  all elements in
+	 * the free queue are valid except the last entry, and all elements in
+	 * the delivery queue are invalid.  It is necessary to initialize
+	 * because when we do an wrsmdsyncfqe() or wrsmdsyncdqe(), we may do
+	 * an RSM_PUT of more than the newly changed entries (because we
+	 * round up/down to 64 byte boundaries).
+	 */
+
+	rd->rd_shdwfqw_l = rd->rd_shdwfqw_f + rd->rd_num_fqws - 1;
+	rd->rd_shdwfqw_i = rd->rd_shdwfqw_o = rd->rd_shdwfqw_l;
+	/* still in first round, on last element */
+	rd->rd_fqw_seq = 1;
+
+	fqep = rd->rd_shdwfqw_f;
+	fqe.s.fq_seqnum = 1;
+	i = 0;
+	while (fqep <= rd->rd_shdwfqw_l - 1) {
+		fqe.s.fq_bufnum = (ushort_t)i++;
+		*fqep++ = fqe;
+	}
+	/* last entry is not valid */
+	fqep->s.fq_seqnum = 0;
+	fqep->s.fq_bufnum = (ushort_t)~0;
+
+	rd->rd_shdwfqw_errflag = 0;
+
+	D1("wrsmdconnxfer: initialized %d fqe shadow entries", i);
+
+
+	rd->rd_shdwdqw_l = rd->rd_shdwdqw_f + rd->rd_num_dqws - 1;
+	rd->rd_shdwdqw_i = rd->rd_shdwdqw_o = rd->rd_shdwdqw_f;
+	/* in first round, on first element */
+	rd->rd_dqw_seq = 1;
+
+	dqep = rd->rd_shdwdqw_f;
+	dqe.s.dq_seqnum = 0;
+	dqe.s.dq_bufnum = (ushort_t)~0;
+	while (dqep <= rd->rd_shdwdqw_l) {
+		*dqep++ = dqe;
+	}
+
+	rd->rd_shdwdqw_errflag = 0;
+
+	mutex_exit(&rd->rd_net_lock);
+
+
+	D1("wrsmdconnxfer: returning 0");
+	TNF_PROBE_2(wrsmdconnxfer_end, "RSMPI", "wrsmdconnxfer end",
+	    tnf_string, completed, "", tnf_long, stat, 0);
+
+	mutex_exit(&rd->rd_xmit_lock);
+	return (0);
+}
+
+
+
+/*
+ * Send an ACCEPT message to the destination.
+ * Return 1 if this send fails, else set state to W_ACK and return 0.
+ * Destination's state must be INPROGRESS.
+ * Destination's state is set to a new state on success.
+ */
+static int
+wrsmdsaccept(
+	wrsmd_t *wrsmdp,	/* WRSMD device (RSM controller) pointer */
+	wrsmd_dest_t *rd)	/* Destination pointer */
+{
+	int stat;
+	wrsmd_msg_t msg;
+	int retval = 0;
+
+	D1("wrsmdsaccept: rd 0x%p (addr %ld ctlr %d)",
+	    (void *)rd, rd->rd_rsm_addr, wrsmdp->wrsmd_ctlr_id);
+	TNF_PROBE_2(wrsmdsaccept_start, "RSMPI", "wrsmdsaccept start",
+	    tnf_long, wrsmdp, (tnf_long_t)wrsmdp, tnf_long, rd, (tnf_long_t)rd);
+
+	msg.p.m.con_accept.send_segid = rd->rd_lxfersegid;
+	msg.p.m.con_accept.rcv_segid = rd->rd_rxfersegid;
+	stat = wrsmdsendmsg(rd, WRSMD_MSG_CON_ACCEPT, &msg);
+
+	mutex_enter(&rd->rd_xmit_lock);
+
+	if (stat == RSM_SUCCESS) {	/* Success */
+		wrsmdsetstate(rd, WRSMD_STATE_W_ACK);
+
+		rd->rd_tmo_int =
+		    wrsmdp->wrsmd_param.wrsmd_ack_tmo;
+		rd->rd_tmo_tot = 0;
+		rd->rd_tmo_id = timeout(wrsmdacktmo, (caddr_t)rd,
+			    rd->rd_tmo_int);
+
+	} else {		/* Failure */
+		retval = 1;
+	}
+	mutex_exit(&rd->rd_xmit_lock);
+
+	D1("wrsmdsaccept: returning %d", retval);
+	TNF_PROBE_2(wrsmdsaccept_end, "RSMPI", "wrsmdaccept end",
+	    tnf_string, completed, "", tnf_long, stat, retval);
+	return (retval);
+}
+
+
+/*
+ * Send an ACK response to the destination.
+ * Return 1 if this send fails, else set state to READY and return 0.
+ * Destination's state must be INPROGRESS.
+ * Destination's state is set to a new state on success.
+ */
+static int
+wrsmdsack(
+	wrsmd_t *wrsmdp,	/* WRSMD device (RSM controller) pointer */
+	wrsmd_dest_t *rd)	/* Destination pointer */
+{
+	int stat;
+	wrsmd_msg_t msg;
+	int retval = 0;
+
+	D1("wrsmdsack: rd 0x%p (addr %ld ctlr %d)",
+	    (void *)rd, rd->rd_rsm_addr, wrsmdp->wrsmd_ctlr_id);
+	TNF_PROBE_2(wrsmdsack_start, "RSMPI", "wrsmdsack start",
+	    tnf_long, wrsmdp, (tnf_long_t)wrsmdp, tnf_long, rd, (tnf_long_t)rd);
+
+	msg.p.m.con_ack.send_segid = rd->rd_lxfersegid;
+	msg.p.m.con_ack.rcv_segid = rd->rd_rxfersegid;
+	stat = wrsmdsendmsg(rd, WRSMD_MSG_CON_ACK, &msg);
+
+	mutex_enter(&rd->rd_xmit_lock);
+
+	if (stat == RSM_SUCCESS) {	/* Success */
+
+		if (rd->rd_queue_h)
+			wrsmdxfer(wrsmdp, rd);
+		else
+			wrsmdsetstate(rd, WRSMD_STATE_W_READY);
+
+	} else {		/* Failure */
+		retval = 1;
+	}
+
+	mutex_exit(&rd->rd_xmit_lock);
+
+	D1("wrsmdsack: returning %d", retval);
+	TNF_PROBE_2(wrsmdsack_end, "RSMPI", "wrsmdsack end",
+	    tnf_string, completed, "", tnf_long, stat, retval);
+	return (retval);
+}
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * E N D       CONNECTION MANAGEMENT                             *
+ *                                                               *
+ * ****************************************************************
+ */
+
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * B E G I N   FREE/DELIVERY QUEUE MANAGEMENT                    *
+ *                                                               *
+ * ****************************************************************
+ */
+
+/*
+ * Queue an FQE with the specified buffer number onto the shadow FQ for
+ * transmission to the remote system.
+ */
+static void
+wrsmdputfqe(
+	wrsmd_dest_t *rd,	/* Destination pointer */
+	int bufnum)	/* Number of free buffer */
+{
+	wrsmd_fqe_t fqe;
+
+	mutex_enter(&rd->rd_net_lock);
+
+	D1("wrsmdputfqe: rd 0x%p (addr %ld ctlr %d), bufnum %d", (void *)rd,
+	    rd->rd_rsm_addr, rd->rd_wrsmdp->wrsmd_ctlr_id, bufnum);
+	D2("wrsmdputfqe: start shdwfqw_i 0x%p (index %ld) shdwfqw_f 0x%p "
+	    "shdwfqw_l 0x%p",
+	    (void *)rd->rd_shdwfqw_i,
+	    ((char *)rd->rd_shdwfqw_i - (char *)rd->rd_shdwfqw_f)
+	    / sizeof (fqe),
+	    (void *)rd->rd_shdwfqw_f, (void *)rd->rd_shdwfqw_l);
+
+	fqe.s.fq_filler = 0;
+	fqe.s.fq_bufnum = (ushort_t)bufnum;
+
+	*rd->rd_shdwfqw_i = fqe;
+
+	rd->rd_shdwfqw_i = (rd->rd_shdwfqw_i == rd->rd_shdwfqw_l) ?
+	    rd->rd_shdwfqw_f : rd->rd_shdwfqw_i + 1;
+
+	ASSERT(rd->rd_shdwfqw_i != rd->rd_shdwfqw_o);
+
+	D1("wrsmdputfqe: done");
+	D2("wrsmdputfqe: end shdwfqw_i 0x%p shdwfqw_f 0x%p shdwfqw_l 0x%p",
+	    (void *)rd->rd_shdwfqw_i, (void *)rd->rd_shdwfqw_f,
+	    (void *)rd->rd_shdwfqw_l);
+
+	mutex_exit(&rd->rd_net_lock);
+}
+
+/*
+ * Flush any queued FQEs (free queue entries) from the local shadow copy to
+ * the remote system's copy.
+ */
+static void
+wrsmdsyncfqe(
+	wrsmd_dest_t *rd)	/* Destination pointer */
+{
+	wrsmd_t *wrsmdp = rd->rd_wrsmdp;
+	uint64_t start_offset, end_offset;
+	int stat = RSM_SUCCESS;
+
+	ASSERT(MUTEX_HELD(&rd->rd_net_lock));
+
+	D1("wrsmdsyncfqe: rd 0x%p (addr %ld ctlr %d) index %ld to %ld",
+	    (void *)rd,
+	    rd->rd_rsm_addr, rd->rd_wrsmdp->wrsmd_ctlr_id,
+	    ((char *)rd->rd_shdwfqw_o - (char *)rd->rd_shdwfqw_f) /
+	    sizeof (*(rd->rd_shdwfqw_o)),
+	    ((char *)rd->rd_shdwfqw_i - (char *)rd->rd_shdwfqw_f) /
+	    sizeof (*(rd->rd_shdwfqw_i)));
+	D2("wrsmdsyncfqe: shdwfqw_i 0x%p shdwfqw_f 0x%p shdwfqw_l 0x%p",
+	    (void *)rd->rd_shdwfqw_i, (void *)rd->rd_shdwfqw_f,
+	    (void *)rd->rd_shdwfqw_l);
+
+	/* If nothing's queued, nothing to do */
+
+	if (rd->rd_shdwfqw_i == rd->rd_shdwfqw_o) {
+		D1("wrsmdsyncfqe: no work, done");
+		return;
+	}
+
+	/* If network down, nothing to do either */
+
+	if (rd->rd_stopq) {
+		D1("wrsmdsyncfqe: stopq on, done");
+		return;
+	}
+
+	/*
+	 * Send each element in the queue separately.  Since each
+	 * element is WRSMD_CACHELINE_SIZE, then we know that
+	 * each PUT is atomic, and we won't corrupt the remote
+	 * side's free queue if we get a transient error and retry.
+	 *
+	 * If we try to put more then one element at a time, then it is
+	 * possible for some elements to succeed while others fail.
+	 * If this is the case then the remote side could possibly consume
+	 * those new buffers before the local side retries the put, and
+	 * thus the FQ could get corrupted (buffer listed as free when
+	 * it really isn't).
+	 *
+	 */
+	while (rd->rd_shdwfqw_o != rd->rd_shdwfqw_i) {
+
+		/* Set the sequence number for this FQE */
+		rd->rd_shdwfqw_o->s.fq_seqnum =
+			rd->rd_fqw_seq & WRSMD_FQE_SEQ_MASK;
+
+		/*
+		 * Set the offset to transfer one fqe at a time.
+		 *
+		 * NOTE: We already know we are aligned because
+		 * we allocated the remote buffer on a WRSMD_CACHELINE_SIZE'd
+		 * boundary, and each fqe is WRSMD_CACHELINE_SIZE long.
+		 */
+		start_offset = (char *)rd->rd_shdwfqw_o -
+		    (char *)rd->rd_shdwfqw_f;
+		end_offset = start_offset + sizeof (wrsmd_fqe_t);
+
+		/* Push FQE to remote side */
+		stat = RSM_PUT(wrsmdp->wrsmd_ctlr, rd->rd_rxferhand,
+		    rd->rd_fqw_f_off + start_offset,
+		    (char *)rd->rd_shdwfqw_o, end_offset - start_offset);
+
+		if (stat == RSM_SUCCESS) {
+			/* Write was sucessful */
+			if (rd->rd_shdwfqw_o == rd->rd_shdwfqw_l) {
+				/*
+				 * Wrap, and update sequence number if
+				 * this the is the last fqe
+				 */
+				rd->rd_shdwfqw_o = rd->rd_shdwfqw_f;
+
+				rd->rd_fqw_seq++;
+				if (rd->rd_fqw_seq == 0)
+					rd->rd_fqw_seq++;
+
+			} else {
+				rd->rd_shdwfqw_o ++;
+			}
+
+			rd->rd_shdwfqw_errflag = 0;
+
+		} else {
+
+			wrsmdp->wrsmd_errs++;
+			D0("wrsmdsyncfqe: RSM_PUT failed error %d", stat);
+
+			if (stat == RSMERR_CONN_ABORTED) {
+				/* permanent connection loss */
+				wrsmd_lostconn(rd);
+			} else {
+				/*
+				 * Schedule an event to retry.  Can't do a
+				 * timeout here because it would require
+				 * calling RSM_PUT from a callback.
+				 */
+
+				wrsmd_add_event(wrsmdp, WRSMD_EVT_SYNC,
+								(void *)rd);
+
+				rd->rd_shdwfqw_errflag = 1;
+			}
+
+			return;
+		}
+
+	}
+
+	D1("wrsmdsyncfqe: done");
+	D2("wrsmdsyncfqe: shdwfqw_i 0x%p shdwfqw_f 0x%p shdwfqw_l 0x%p",
+	    (void *)rd->rd_shdwfqw_i, (void *)rd->rd_shdwfqw_f,
+	    (void *)rd->rd_shdwfqw_l);
+}
+
+/*
+ * Queue a DQE with the specified buffer description onto the shadow DQ for
+ * transmission to the remote system.
+ */
+static void
+wrsmdputdqe(
+	wrsmd_dest_t *rd,	/* Destination pointer */
+	int bufnum,	/* Number of full buffer */
+	int offset,	/* Offset of packet from start of buffer */
+	uint_t length,	/* Length of packet */
+	ushort_t sap)	/* Packet's SAP */
+{
+	wrsmd_dqe_t dqe;
+
+	mutex_enter(&rd->rd_net_lock);
+
+	D1("wrsmdputdqe: rd 0x%p (ctlr %d addr %ld), bufnum %d, offset %d, "
+	    "length %d, sap 0x%x index %ld",
+	    (void *)rd, rd->rd_wrsmdp->wrsmd_ctlr_id, rd->rd_rsm_addr,
+	    bufnum, offset, length, sap,
+	    ((char *)rd->rd_shdwdqw_i - (char *)rd->rd_shdwdqw_f) /
+	    sizeof (dqe));
+	D2("wrsmdputdqe: start shdwdqw_i 0x%p (index %ld) shdwdqw_f 0x%p "
+	    "shdwdqw_l 0x%p",
+	    (void *)rd->rd_shdwdqw_i,
+	    ((char *)rd->rd_shdwdqw_i - (char *)rd->rd_shdwdqw_f) /
+	    sizeof (dqe),
+	    (void *)rd->rd_shdwdqw_f,
+	    (void *)rd->rd_shdwdqw_l);
+
+	dqe.s.dq_offset = (uchar_t)offset;
+	dqe.s.dq_bufnum = (ushort_t)bufnum;
+	dqe.s.dq_length = (ushort_t)length;
+	dqe.s.dq_sap = sap;
+
+	*rd->rd_shdwdqw_i = dqe;
+
+	rd->rd_shdwdqw_i = (rd->rd_shdwdqw_i == rd->rd_shdwdqw_l) ?
+	    rd->rd_shdwdqw_f : rd->rd_shdwdqw_i + 1;
+
+	ASSERT(rd->rd_shdwdqw_i != rd->rd_shdwdqw_o);
+
+	D1("wrsmdputdqe: done");
+	D2("wrsmdputdqe: end shdwdqw_i 0x%p shdwdqw_o 0x%p shdwdqw_f 0x%p "
+	    "shdwdqw_l 0x%p",
+	    (void *)rd->rd_shdwdqw_i,
+	    (void *)rd->rd_shdwdqw_o,
+	    (void *)rd->rd_shdwdqw_f,
+	    (void *)rd->rd_shdwdqw_l);
+
+	mutex_exit(&rd->rd_net_lock);
+}
+
+/*
+ * Flush any queued DQEs from local shadow copy to the remote system.
+ */
+static void
+wrsmdsyncdqe(wrsmd_dest_t *rd)
+{
+	wrsmd_t *wrsmdp = rd->rd_wrsmdp;
+	uint64_t start_offset, end_offset;
+	int stat = RSM_SUCCESS;
+	int any_transfers = 0;
+	int old_error_flag;
+
+	ASSERT(MUTEX_HELD(&rd->rd_net_lock));
+
+	old_error_flag = rd->rd_shdwdqw_errflag;
+
+	D1("wrsmdsyncdqe: rd 0x%p (addr %ld ctlr %d) index %ld to %ld",
+	    (void *)rd, rd->rd_rsm_addr,
+	    rd->rd_wrsmdp->wrsmd_ctlr_id,
+	    ((char *)rd->rd_shdwdqw_o - (char *)rd->rd_shdwdqw_f) /
+	    sizeof (*(rd->rd_shdwdqw_o)),
+	    ((char *)rd->rd_shdwdqw_i - (char *)rd->rd_shdwdqw_f) /
+	    sizeof (*(rd->rd_shdwdqw_i)));
+
+	D2("wrsmdsyncdqe: shdwdqw_i 0x%p shdwdqw_o 0x%p shdwdqw_f 0x%p "
+	    "shdwdqw_l 0x%p",
+	    (void *)rd->rd_shdwdqw_i,
+	    (void *)rd->rd_shdwdqw_o,
+	    (void *)rd->rd_shdwdqw_f,
+	    (void *)rd->rd_shdwdqw_l);
+
+	/* If nothing's queued, nothing to do */
+
+	if (rd->rd_shdwdqw_i == rd->rd_shdwdqw_o) {
+		D1("wrsmdsyncdqe: no work, done");
+		return;
+	}
+
+	/* If network down, nothing to do either */
+
+	if (rd->rd_stopq) {
+		D1("wrsmdsyncdqe: stopq on, done");
+		return;
+	}
+
+	/*
+	 * Send each element in the queue separately.  Since each
+	 * element is WRSMD_CACHELINE_SIZE, then we know that
+	 * each PUT is atomic, and we won't corrupt the remote
+	 * side's free queue if we get a transient error and retry.
+	 *
+	 * (see explination in wrsmdsyncfqe() )
+	 *
+	 * This is needed on the DQ as well as the FQ because even though
+	 * DQ sends an interrupt when it's complete, there is a small window
+	 * of opportunity if the local side adds more DQ's with the same
+	 * sequence number while the remote side is still consuming them.
+	 *
+	 */
+	while (rd->rd_shdwdqw_o != rd->rd_shdwdqw_i) {
+
+		/* Set the sequence number for this DQE */
+		rd->rd_shdwdqw_o->s.dq_seqnum =
+			rd->rd_dqw_seq & WRSMD_DQE_SEQ_MASK;
+
+		/*
+		 * Set the offset to transfer one dqe at a time.
+		 *
+		 * NOTE: We already know we are aligned because
+		 * we allocated the remote buffer on a WRSMD_CACHELINE_SIZE'd
+		 * boundary, and each dqe is WRSMD_CACHELINE_SIZE long.
+		 */
+		start_offset = (char *)rd->rd_shdwdqw_o -
+		    (char *)rd->rd_shdwdqw_f;
+		end_offset = start_offset + sizeof (wrsmd_dqe_t);
+
+		/* Push FQE to remote side */
+		stat = RSM_PUT(wrsmdp->wrsmd_ctlr, rd->rd_rxferhand,
+		    rd->rd_dqw_f_off + start_offset,
+		    (char *)rd->rd_shdwdqw_o, end_offset - start_offset);
+
+		if (stat == RSM_SUCCESS) {
+			/* Write was sucessful */
+
+			any_transfers++;
+
+			if (rd->rd_shdwdqw_o == rd->rd_shdwdqw_l) {
+				/*
+				 * Wrap, and update sequence number if
+				 * this the is the last dqe
+				 */
+				rd->rd_shdwdqw_o = rd->rd_shdwdqw_f;
+
+				rd->rd_dqw_seq++;
+				if (rd->rd_dqw_seq == 0)
+					rd->rd_dqw_seq++;
+
+			} else {
+				rd->rd_shdwdqw_o ++;
+			}
+
+			rd->rd_shdwdqw_errflag = 0;
+
+		} else {
+
+			wrsmdp->wrsmd_errs++;
+			D0("wrsmdsyncdqe: RSM_PUT failed error %d", stat);
+
+			if (stat == RSMERR_CONN_ABORTED) {
+				/* permanent connection loss */
+				wrsmd_lostconn(rd);
+			} else {
+				/*
+				 * Schedule an event to retry.  Can't do a
+				 * timeout here because it would require
+				 * calling RSM_PUT from a callback.
+				 */
+
+				wrsmd_add_event(wrsmdp, WRSMD_EVT_SYNC,
+								(void *)rd);
+
+				rd->rd_shdwdqw_errflag = 1;
+			}
+
+			if (!any_transfers)
+				return;
+		}
+
+	}
+
+	/* If error flag was previously set, retry the interrupt */
+	if (any_transfers || old_error_flag) {
+		wrsmd_msg_t msg;
+		msg.p.m.syncdqe.rcv_segid = rd->rd_rxfersegid;
+		stat = wrsmdsendmsg(rd, WRSMD_MSG_SYNC_DQE, &msg);
+		if (stat != RSM_SUCCESS) {	/* Failure */
+			/* send failed */
+			wrsmdp->wrsmd_errs++;
+
+			if (stat == RSMERR_CONN_ABORTED) {
+				/* permanent connection loss */
+				wrsmd_lostconn(rd);
+			} else {
+				/*
+				 * Schedule an event to retry.  Can't do a
+				 * timeout here because it would require
+				 * calling RSM_PUT from a callback.
+				 */
+
+				wrsmd_add_event(wrsmdp, WRSMD_EVT_SYNC,
+								(void *)rd);
+
+				rd->rd_shdwdqw_errflag = 1;
+			}
+
+		} else {
+			wrsmdp->wrsmd_syncdqes++;
+		}
+	}
+	D1("wrsmdsyncdqe: done");
+	D2("wrsmdsyncdqe: shdwdqw_i 0x%p shdwdqw_o 0x%p shdwdqw_f 0x%p "
+	    "shdwdqw_l 0x%p",
+	    (void *)rd->rd_shdwdqw_i,
+	    (void *)rd->rd_shdwdqw_o,
+	    (void *)rd->rd_shdwdqw_f,
+	    (void *)rd->rd_shdwdqw_l);
+}
+
+/*
+ * Determine whether there are any available FQEs.  If so, return 1; if none
+ * are available, return 0.
+ */
+static int
+wrsmdavailfqe(
+	wrsmd_dest_t *rd)	/* Destination pointer */
+{
+	wrsmd_fqe_t fqe;
+
+	mutex_enter(&rd->rd_net_lock);
+
+	D1("wrsmdavailfqe: rd 0x%p", (void *)rd);
+
+	if (rd->rd_cached_fqr_cnt) {
+		D1("wrsmdavailfqe: (cached) returning 1");
+
+		mutex_exit(&rd->rd_net_lock);
+		return (1);
+	}
+
+	fqe = *rd->rd_fqr_n;
+
+	if (fqe.s.fq_seqnum == (rd->rd_fqr_seq & WRSMD_FQE_SEQ_MASK)) {
+		D1("wrsmdavailfqe: returning 1");
+
+		mutex_exit(&rd->rd_net_lock);
+		return (1);
+	} else {
+		D1("wrsmdavailfqe: seq %d, expecting %d, returning 0",
+		    fqe.s.fq_seqnum, rd->rd_fqr_seq & WRSMD_FQE_SEQ_MASK);
+
+		mutex_exit(&rd->rd_net_lock);
+		return (0);
+	}
+}
+
+/*
+ * Attempt to retrieve the next available FQE from the queue.  If successful,
+ * return 1; if none are available, return 0.
+ */
+static int
+wrsmdgetfqe(
+	wrsmd_dest_t *rd,	/* Destination pointer */
+	int *bufnum)	/* Set to number of free buffer, if we got one */
+{
+	wrsmd_fqe_t fqe;
+
+	mutex_enter(&rd->rd_net_lock);
+
+	D1("wrsmdgetfqe: rd 0x%p (addr %ld ctlr %d) index %ld", (void *)rd,
+	    rd->rd_rsm_addr, rd->rd_wrsmdp->wrsmd_ctlr_id,
+	    ((char *)rd->rd_fqr_n - (char *)rd->rd_fqr_f) / sizeof (fqe));
+
+	/* If we have FQE's cached, return one of those */
+
+	if (rd->rd_cached_fqr_cnt) {
+		*bufnum = rd->rd_cached_fqr[--rd->rd_cached_fqr_cnt];
+		D1("wrsmdgetfqe: (cached) returning 1, *bufnum %d",
+		    *bufnum);
+
+		mutex_exit(&rd->rd_net_lock);
+		return (1);
+	}
+
+	D2("wrsmdgetfqe: start fqr_n 0x%p (index %ld) fqr_f 0x%p fqr_l 0x%p "
+	    "fqr_seq %d",
+	    (void *)rd->rd_fqr_n,
+	    ((char *)rd->rd_fqr_n - (char *)rd->rd_fqr_f) / sizeof (fqe),
+	    (void *)rd->rd_fqr_f, (void *)rd->rd_fqr_l,
+	    rd->rd_fqr_seq & WRSMD_FQE_SEQ_MASK);
+
+	/* Get next FQE */
+
+	fqe = *rd->rd_fqr_n;
+
+	/* Is it valid? */
+
+	if (fqe.s.fq_seqnum == (rd->rd_fqr_seq & WRSMD_FQE_SEQ_MASK)) {
+		/* Yup, return number */
+
+		*bufnum = fqe.s.fq_bufnum;
+
+		/* Bump pointer, wrap if needed */
+
+		if (rd->rd_fqr_n == rd->rd_fqr_l) {
+			rd->rd_fqr_n = rd->rd_fqr_f;
+			rd->rd_fqr_seq++;
+			if (rd->rd_fqr_seq == 0)
+				rd->rd_fqr_seq++;
+		} else
+			rd->rd_fqr_n++;
+
+		/* Exercise some paranoia */
+
+		if (*bufnum >= rd->rd_numrbuf) {
+			D1("wrsmdgetfqe: bogus buffer %d in FQE "
+			    "at 0x%lx (max %d)", *bufnum,
+			    (uintptr_t)rd->rd_fqr_n, rd->rd_numrbuf);
+			cmn_err(CE_NOTE,
+			    "wrsmdgetfqe: bogus buffer %d in FQE "
+			    "at 0x%lx (max %d)", *bufnum,
+			    (uintptr_t)rd->rd_fqr_n, rd->rd_numrbuf);
+			mutex_exit(&rd->rd_net_lock);
+			return (0);
+		}
+
+		D1("wrsmdgetfqe: returning 1, *bufnum %d", *bufnum);
+		D2("wrsmdgetfqe: end fqr_n 0x%p fqr_f 0x%p fqr_l 0x%p "
+		    "fqr_seq %d", (void *)rd->rd_fqr_n, (void *)rd->rd_fqr_f,
+		    (void *)rd->rd_fqr_l, rd->rd_fqr_seq & WRSMD_FQE_SEQ_MASK);
+
+		mutex_exit(&rd->rd_net_lock);
+		return (1);
+	} else {
+		D1("wrsmdgetfqe: seq %d, expecting %d, returning 0",
+		    fqe.s.fq_seqnum, rd->rd_fqr_seq & WRSMD_FQE_SEQ_MASK);
+		D2("wrsmdgetfqe: end fqr_n 0x%p fqr_f 0x%p fqr_l 0x%p "
+		    "fqr_seq %d", (void *)rd->rd_fqr_n, (void *)rd->rd_fqr_f,
+		    (void *)rd->rd_fqr_l, rd->rd_fqr_seq);
+
+
+		mutex_exit(&rd->rd_net_lock);
+		return (0);
+	}
+}
+
+/*
+ * Unget an FQE, making it available to be gotten again.  Unlike the C
+ * ungetc, there is guaranteed to be enough buffering to unget all of the
+ * FQE's that the remote system can have available.  (We do this if we
+ * get an FQE and then later find that we can't transmit the packet we wanted
+ * to use it for; for example, if we can't get DMA resources.)
+ */
+static void
+wrsmdungetfqe(
+	wrsmd_dest_t *rd,	/* Destination pointer */
+	int bufnum)	/* Number of buffer we want to save for later */
+{
+	mutex_enter(&rd->rd_net_lock);
+
+	D1("wrsmdungetfqe: rd 0x%p, bufnum %d", (void *)rd, bufnum);
+
+	rd->rd_cached_fqr[rd->rd_cached_fqr_cnt++] = (ushort_t)bufnum;
+
+	D1("wrsmdungetfqe: done");
+
+	mutex_exit(&rd->rd_net_lock);
+}
+
+/*
+ * Attempt to retrieve the next available DQE from the queue.  If successful,
+ * return 1; if none are available, return 0.
+ */
+static int
+wrsmdgetdqe(
+	wrsmd_dest_t *rd,	/* Destination pointer */
+	int *bufnum,	/* Buffer number, set if we find a DQE */
+	int *offset,	/* Packet offset, set if we find a DQE */
+	int *length,	/* Packet length, set if we find a DQE */
+	ushort_t *sap)	/* Packet SAP, set if we find a DQE */
+{
+	wrsmd_dqe_t dqe;
+
+
+	mutex_enter(&rd->rd_net_lock);
+
+	D1("wrsmdgetdqe: rd 0x%p (addr %ld ctlr %d) index %ld", (void *)rd,
+	    rd->rd_rsm_addr, rd->rd_wrsmdp->wrsmd_ctlr_id,
+	    ((char *)rd->rd_dqr_n - (char *)rd->rd_dqr_f) / sizeof (dqe));
+	D2("wrsmdgetdqe: dqr_n 0x%p (index %ld) dqr_f 0x%p dqr_l 0x%p seq %d",
+	    (void *)rd->rd_dqr_n,
+	    ((char *)rd->rd_dqr_n - (char *)rd->rd_dqr_f) / sizeof (dqe),
+	    (void *)rd->rd_dqr_f, (void *)rd->rd_dqr_l,
+	    rd->rd_dqr_seq & WRSMD_DQE_SEQ_MASK);
+
+
+	/* Get next DQE */
+
+	dqe = *rd->rd_dqr_n;
+
+	/* Is it valid? */
+
+	if (dqe.s.dq_seqnum == (rd->rd_dqr_seq & WRSMD_DQE_SEQ_MASK)) {
+		*bufnum = dqe.s.dq_bufnum;
+		*offset = dqe.s.dq_offset;
+		*length = dqe.s.dq_length;
+		*sap = dqe.s.dq_sap;
+
+		/* Exercise some paranoia */
+
+		if (*bufnum >= rd->rd_numlbufs) {
+			D1("wrsmdgetdqe: bogus buffer %d "
+			    "in DQE at 0x%p (max %d)", *bufnum,
+			    (void *) &dqe, rd->rd_numlbufs);
+			cmn_err(CE_NOTE, "wrsmdgetdqe: bogus buffer %d "
+			    "in DQE at 0x%p (max %d)", *bufnum,
+			    (void *) &dqe, rd->rd_numlbufs);
+			mutex_exit(&rd->rd_net_lock);
+			return (0);
+		}
+
+		if (*offset > WRSMD_CACHELINE_OFFSET) {
+			D1("wrsmdgetdqe: bogus offset %d "
+			    "in DQE at 0x%lx (max %d)", *offset,
+			    (uintptr_t)&dqe, WRSMD_CACHELINE_OFFSET);
+			cmn_err(CE_NOTE, "wrsmdgetdqe: bogus offset %d "
+			    "in DQE at 0x%lx (max %d)", *offset,
+			    (uintptr_t)&dqe, WRSMD_CACHELINE_OFFSET);
+			mutex_exit(&rd->rd_net_lock);
+			return (0);
+		}
+
+		if (*offset + *length >= rd->rd_lbuflen) {
+			D1("wrsmdgetdqe: bogus "
+			    "offset+length %d+%d in DQE at 0x%lx (max %d)",
+			    *offset, *length, (uintptr_t)&dqe,
+			    rd->rd_lbuflen);
+			cmn_err(CE_NOTE, "wrsmdgetdqe: bogus "
+			    "offset+length %d+%d in DQE at 0x%lx (max %d)",
+			    *offset, *length, (uintptr_t)&dqe,
+			    rd->rd_lbuflen);
+			mutex_exit(&rd->rd_net_lock);
+			return (0);
+		}
+
+		if (rd->rd_dqr_n == rd->rd_dqr_l) {
+			rd->rd_dqr_n = rd->rd_dqr_f;
+			rd->rd_dqr_seq++;
+			if (rd->rd_dqr_seq == 0)
+				rd->rd_dqr_seq++;
+		} else
+			rd->rd_dqr_n++;
+
+		D1("wrsmdgetdqe: returning 1, *bufnum %d, *offset %d, "
+		    "*length %d, *sap 0x%x", *bufnum, *offset, *length, *sap);
+
+		mutex_exit(&rd->rd_net_lock);
+		return (1);
+	} else {
+		D1("wrsmdgetdqe: seq %d, expecting %d, returning 0",
+		    dqe.s.dq_seqnum, rd->rd_dqr_seq & WRSMD_DQE_SEQ_MASK);
+
+		mutex_exit(&rd->rd_net_lock);
+		return (0);
+	}
+}
+
+/*
+ * We've tried to get an FQE and failed.  Set this destination up to retry
+ * on a timeout.  Destination's state must be INPROGRESS.
+ */
+static void
+wrsmdsetupfqewait(
+	wrsmd_t *wrsmdp,	/* WRSMD device (RSM controller) pointer */
+	wrsmd_dest_t *rd)	/* Destination pointer */
+{
+	wrsmdsetstate(rd, WRSMD_STATE_W_FQE);
+
+	/* Do exponential backoff */
+
+	if (rd->rd_tmo_int <= 0) {
+		rd->rd_tmo_int =
+		    wrsmdp->wrsmd_param.wrsmd_nobuf_init_tmo;
+		rd->rd_tmo_tot = 0;
+	} else {
+		rd->rd_tmo_tot += rd->rd_tmo_int;
+		rd->rd_tmo_int *= 2;
+	}
+
+	/* If we've waited too long, dump queue and drop connection */
+
+	if (rd->rd_tmo_tot >= wrsmdp->wrsmd_param.wrsmd_nobuf_drop_tmo) {
+		wrsmddumpqueue(wrsmdp, rd);
+
+		wrsmdp->wrsmd_collisions++;
+
+		wrsmd_lostconn(rd);
+
+		/*
+		 * If lostconn() couldn't go to S_DELETE directly,
+		 * then this movestate call will get it noticed.
+		 */
+		(void) wrsmdmovestate(rd, WRSMD_STATE_W_FQE,
+		    WRSMD_STATE_S_DELETE);
+
+		return;
+	}
+
+	/* Clip timeout to maximum */
+
+	if (rd->rd_tmo_int > wrsmdp->wrsmd_param.wrsmd_nobuf_max_tmo)
+		rd->rd_tmo_int = wrsmdp->wrsmd_param.wrsmd_nobuf_max_tmo;
+
+	/*
+	 * Only schedule a timeout if there isn't one already.
+	 * We hold rd_xmit_lock, so if the timeout has fired,
+	 * it's blocked on the lock.
+	 */
+	if (rd->rd_fqe_tmo_id == 0)
+		rd->rd_fqe_tmo_id = timeout(wrsmdfqetmo,
+					    (caddr_t)rd, rd->rd_tmo_int);
+
+	wrsmdp->wrsmd_collisions++;
+}
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * E N D       FREE/DELIVERY QUEUE MANAGEMENT                    *
+ *                                                               *
+ * ****************************************************************
+ */
+
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * B E G I N   COMMUNICATION                                     *
+ *                                                               *
+ * ****************************************************************
+ */
+
+/*
+ * Attempt to send one or more packets, currently queued on a destination
+ * structure, to their actual destination.  Destination's state must be
+ * INPROGRESS.
+ *
+ * This function gets called holding rd_xmit_lock.
+ * This code assumes implicit barriers for puts and gets.
+ */
+static void
+wrsmdxfer(
+	wrsmd_t *wrsmdp,	/* WRSMD device (RSM controller) pointer */
+	wrsmd_dest_t *rd)	/* Destination pointer */
+{
+	int bufnum;
+	int write_err;
+	mblk_t *mp;
+	uint_t pktlen;
+	uint_t start_offset, end_offset;
+	int pkts_queued = 0;
+
+	D1("wrsmdxfer: rd 0x%p (addr %ld ctlr %d)",
+	    (void *)rd, rd->rd_rsm_addr, wrsmdp->wrsmd_ctlr_id);
+	D5("wrsmdxfer 1: time 0x%llx", gethrtime());
+	TNF_PROBE_2(wrsmdxfer_start, "RSMPI", "wrsmdxfer start",
+	    tnf_long, wrsmdp, (tnf_long_t)wrsmdp, tnf_long, rd, (tnf_long_t)rd);
+
+	ASSERT(MUTEX_HELD(&rd->rd_xmit_lock));
+
+
+	do {
+		while ((mp = rd->rd_queue_h) != NULL) {
+			ushort_t sap;
+			uchar_t *srcaddr, *endaddr;
+			int retries;
+			pktlen = MBLKL(mp);
+
+			/*
+			 * Try to get an FQE.  If we can't, and this is the
+			 * first packet we've tried to send on this
+			 * invocation of wrsmdxfer then set up a timeout to
+			 * try again.  If we've successfully prepped some
+			 * packets for sending, then go ahead and finish
+			 * the job, on the theory that when they're done
+			 * there may be more FQEs available.
+			 */
+			if (wrsmdgetfqe(rd, &bufnum) == 0) {
+				if (pkts_queued == 0) {
+					wrsmdsetupfqewait(wrsmdp, rd);
+					D1("wrsmdxfer: no FQEs, start timeout, "
+					    "done");
+					TNF_PROBE_1(wrsmdxfer_end, "RSMPI",
+					    "wrsmdxfer end; failure noFQEs",
+					    tnf_string, failure, "noFQEs");
+					return;
+				} else
+					break;
+			}
+
+			/* Take packet off the queue. */
+
+			rd->rd_queue_h = mp->b_next;
+			rd->rd_queue_len--;
+			sap = (ushort_t)(uintptr_t)mp->b_prev;
+			mp->b_next = mp->b_prev = NULL;
+
+			/*
+			 * Adjust the start pointer and packet length so
+			 * we're copying to and from a 64 byte aligned
+			 * address, if it'll fit in the buffer that way.
+			 * (Note -- this means we may actually be copying
+			 * data that doesn't belong to us!!!)
+			 */
+			srcaddr = mp->b_rptr;
+			start_offset = (uint_t)
+			    ((uint64_t)srcaddr & WRSMD_CACHELINE_OFFSET);
+			endaddr = srcaddr + pktlen;
+			end_offset = (uint_t)
+			    (WRSMD_CACHELINE_ROUNDUP(endaddr) -
+			    (uint64_t)endaddr);
+
+			if ((pktlen + start_offset + end_offset) >
+			    rd->rd_rbuflen) {
+				start_offset = 0;
+			}
+			ASSERT((pktlen + start_offset + end_offset) <=
+			    rd->rd_rbuflen);
+
+			D6("wrsmdxfer: srcaddr 0x%p endaddr 0x%p "
+			    "start_offset 0x%x end_offset 0x%x pktlen 0x%x",
+			    (void *)srcaddr, (void *)endaddr, start_offset,
+			    end_offset, pktlen);
+			TNF_PROBE_3(wrsmdxfer_XFERstart, "RSMPI",
+			    "wrsmdxfer XFERstart",
+			    tnf_long, srcaddr, (tnf_long_t)srcaddr,
+			    tnf_long, pktlen, pktlen,
+			    tnf_long, sap, sap);
+
+
+			/* Do the packet copy, check for errors. */
+			ASSERT(((rd->rd_rbufoff + (bufnum * rd->rd_rbuflen)) &
+			    WRSMD_CACHELINE_OFFSET) == 0);
+
+			for (retries = wrsmdp->wrsmd_param.wrsmd_err_retries,
+			    write_err = ~RSM_SUCCESS;
+			    retries >= 0 && write_err != RSM_SUCCESS;
+			    retries--) {
+				D6("wrsmdxfer: put 0x%x bytes at "
+				    "segoffset 0x%lx from addr 0x%p",
+				    pktlen + start_offset + end_offset,
+				    rd->rd_rbufoff + (bufnum * rd->rd_rbuflen),
+				    (void *)(srcaddr - start_offset));
+				write_err = RSM_PUT(wrsmdp->wrsmd_ctlr,
+				    rd->rd_rxferhand,
+				    rd->rd_rbufoff + (bufnum * rd->rd_rbuflen),
+				    srcaddr - start_offset,
+				    pktlen + start_offset + end_offset);
+				if (write_err != RSM_SUCCESS)
+					wrsmdp->wrsmd_errs++;
+				if (write_err == RSMERR_CONN_ABORTED)
+					break;
+			}
+
+			if (write_err != RSM_SUCCESS) {
+				wrsmdungetfqe(rd, bufnum);
+				freemsg(mp);
+				wrsmdp->wrsmd_oerrors++;
+				TNF_PROBE_1(wrsmdxfer_XFERend,
+				    "RSMPI", "wrsmdxfer XFERend",
+				    tnf_string, failure, "XFER failed");
+				D1("wrsmdxfer: RSM_PUT failed error %d",
+				    write_err);
+
+				if (write_err == RSMERR_CONN_ABORTED) {
+					wrsmd_lostconn(rd);
+					wrsmdsetstate(rd, WRSMD_STATE_S_DELETE);
+					return;
+				}
+			} else {
+				/*
+				 * Ditch the spent packet, send a DQE,
+				 * adjust stats.
+				 */
+
+				freemsg(mp);
+
+				wrsmdputdqe(rd, bufnum, start_offset, pktlen,
+				    sap);
+
+				pkts_queued++;
+
+				if (pkts_queued ==
+				    wrsmdp->wrsmd_param.wrsmd_train_size) {
+					pkts_queued = 0;
+					mutex_enter(&rd->rd_net_lock);
+					wrsmdsyncdqe(rd);
+					mutex_exit(&rd->rd_net_lock);
+				}
+
+				wrsmdp->wrsmd_xfer_pkts++;
+				wrsmdp->wrsmd_opackets++;
+				wrsmdp->wrsmd_out_bytes += pktlen;
+
+				TNF_PROBE_1(wrsmdxfer_XFERend, "RSMPI",
+				    "wrsmdxfer XFERend", tnf_string,
+				    completed, "");
+			}
+		}
+
+		/*
+		 * We've prepped all the packets we're going to, now finish
+		 * up.
+		 */
+		if (pkts_queued) {
+			mutex_enter(&rd->rd_net_lock);
+			wrsmdsyncdqe(rd);
+			mutex_exit(&rd->rd_net_lock);
+		}
+
+		/*
+		 * If there are more packets to send, and FQE's have become
+		 * available during wrsmdsyncdqe(), try sending them now.
+		 */
+	} while ((rd->rd_queue_h != NULL) && wrsmdavailfqe(rd));
+
+	if (rd->rd_queue_h != NULL) {
+		/*
+		 * We weren't able to send all packets.
+		 * Schedule a timeout to retry sending them.
+		 */
+		wrsmdsetupfqewait(wrsmdp, rd);
+		D1("wrsmdxfer: no FQEs, start timeout, done");
+		TNF_PROBE_1(wrsmdxfer_end, "RSMPI",
+		    "wrsmdxfer end; failure noFQEs",
+		    tnf_string, failure, "noFQEs");
+	} else {
+		wrsmdsetstate(rd, WRSMD_STATE_W_READY);
+	}
+
+	wrsmdp->wrsmd_xfers++;
+
+	D1("wrsmdxfer: done");
+	TNF_PROBE_1(wrsmdxfer_end, "RSMPI", "wrsmdxfer",
+	    tnf_string, complete, "");
+}
+
+
+/*
+ * Send a message to a remote system.  Returns the sequence number of the
+ * message if one was successfully sent, or -1 if the caller needs to retry
+ * later.  The special message type WRSMD_REXMIT causes us to retransmit the
+ * last message we sent (unsuccessfully or successfully), without
+ * incrementing the sequence number.  This cannot be called from an
+ * interrupt.
+ */
+static int
+wrsmdsendmsg(wrsmd_dest_t *rd, uint8_t msg_type, wrsmd_msg_t *msg)
+{
+	rsm_send_t send_obj;
+	int status;
+
+	if (msg_type == WRSMD_REXMIT) {
+		if (rd->rsm_previous_msg_valid) {
+			msg = &rd->rsm_previous_msg;
+		} else {
+			return (-2);
+		}
+	} else {
+		bcopy(msg, &rd->rsm_previous_msg,
+		    sizeof (rd->rsm_previous_msg));
+		rd->rsm_previous_msg.p.hdr.reqtype = msg_type;
+		/* rd_nseq is a ushort, and will wrap when it gets too big. */
+		rd->rsm_previous_msg.p.hdr.seqno = rd->rd_nseq++;
+		rd->rsm_previous_msg.p.hdr.wrsmd_version = WRSMD_VERSION;
+	}
+
+	/*
+	 * Send fails immediately if message can't be queued.
+	 * On Wildcat, message is sent as soon as it is queued, so
+	 * network failures are reported immediately.
+	 */
+	send_obj.is_data = &rd->rsm_previous_msg;
+	send_obj.is_size = sizeof (wrsmd_msg_t);
+	send_obj.is_flags = (RSM_INTR_SEND_QUEUE | RSM_INTR_SEND_POLL);
+	send_obj.is_wait = 1;
+
+	status = RSM_SEND(rd->rd_wrsmdp->wrsmd_ctlr, rd->rsm_sendq,
+	    &send_obj, NULL);
+
+#ifdef DEBUG
+	if (status != RSM_SUCCESS) {
+		D1("wrsmdsendmsg RSM_SEND FAILED!! status %d\n", status);
+	} else {
+		D2("wrsmdsendmsg: succeeded\n");
+	}
+#endif
+
+	return (status);
+}
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * E N D       COMMUNICATION                                     *
+ *                                                               *
+ * ****************************************************************
+ */
+
+
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * B E G I N   TIMEOUT-FUNCTIONS                                 *
+ *                                                               *
+ * ****************************************************************
+ */
+
+/*
+ * Timeout functions
+ */
+
+/*
+ * FQE timeout expired.  Try sending any packets that were waiting
+ * for Free Queue Entries.
+ */
+static void
+wrsmdfqetmo(void * arg)
+{
+	wrsmd_dest_t *rd = (wrsmd_dest_t *)arg;
+
+	D1("wrsmdfqetmo: rd 0x%p (addr %ld ctlr %d)", (void *)rd,
+	    rd->rd_rsm_addr, rd->rd_wrsmdp->wrsmd_ctlr_id);
+
+	/*
+	 * This mutex doesn't really protect a particular data item in this
+	 * case, it just keeps the movestate from running while we have the
+	 * state messed up in wrsmdmsghdlr_syncdqe().  See that routine for
+	 * more explanation.
+	 */
+	mutex_enter(&rd->rd_xmit_lock);
+
+	(void) wrsmdmovestate(rd, WRSMD_STATE_W_FQE, WRSMD_STATE_S_XFER);
+
+	rd->rd_fqe_tmo_id = 0;
+
+	mutex_exit(&rd->rd_xmit_lock);
+
+
+	D1("wrsmdfqetmo: done");
+}
+
+/*
+ * Connect retransmit backoff timer has expired.  Retransmit the connect
+ * request.
+ */
+static void
+wrsmdsconntmo(void * arg)
+{
+	wrsmd_dest_t *rd = (wrsmd_dest_t *)arg;
+
+	D1("wrsmdsconntmo: rd 0x%p (addr %ld ctlr %d)", (void *)rd,
+	    rd->rd_rsm_addr, rd->rd_wrsmdp->wrsmd_ctlr_id);
+
+	rd->rd_tmo_id = 0;
+
+	/*
+	 * If the timeout was cancelled, the state will have also change
+	 * from W_SCONNTMO, and wrsmdmovestate() will have no effect.
+	 */
+	(void) wrsmdmovestate(rd, WRSMD_STATE_W_SCONNTMO,
+	    WRSMD_STATE_S_SCONN);
+
+	D1("wrsmdsconntmo: done");
+}
+
+
+/*
+ * Timer to wait for ACCEPT message from remote has expired.
+ * This indicates the remote side is not reachable, so tear
+ * down the WRSMD device (controller).
+ */
+static void
+wrsmdaccepttmo(void * arg)
+{
+	wrsmd_dest_t *rd = (wrsmd_dest_t *)arg;
+
+	D1("wrsmdaccepttmo: rd 0x%p (addr %ld ctlr %d)", (void *)rd,
+	    rd->rd_rsm_addr, rd->rd_wrsmdp->wrsmd_ctlr_id);
+
+	rd->rd_tmo_id = 0;
+
+	/*
+	 * If the timeout was cancelled, the state will have also changed
+	 * from W_ACCEPT, and wrsmdmovestate() will have no effect.
+	 */
+	(void) wrsmdmovestate(rd, WRSMD_STATE_W_ACCEPT,
+	    WRSMD_STATE_S_DELETE);
+
+	D1("wrsmdaccepttmo: done");
+}
+
+
+
+/*
+ * Timer to wait for ACK message from remote expired.
+ * This indicates the remote side is not reachable, so tear
+ * down the WRSMD device (controller).
+ */
+static void
+wrsmdacktmo(void * arg)
+{
+	wrsmd_dest_t *rd = (wrsmd_dest_t *)arg;
+
+	D1("wrsmdacktmo: rd 0x%p (addr %ld ctlr %d)", (void *)rd,
+	    rd->rd_rsm_addr, rd->rd_wrsmdp->wrsmd_ctlr_id);
+
+	rd->rd_tmo_id = 0;
+
+	/*
+	 * If the timeout was cancelled, the state will have also changed
+	 * from W_ACK, and wrsmdmovestate() will have no effect.
+	 */
+	(void) wrsmdmovestate(rd, WRSMD_STATE_W_ACK,
+	    WRSMD_STATE_S_DELETE);
+
+	D1("wrsmdacktmo: done");
+}
+
+
+/*
+ * Timer to teardown the WRSMD device (RSM controller) has expired.
+ * Tear down the connection.
+ */
+static void
+wrsmdteardown_tmo(void * arg)
+{
+	wrsmd_t *wrsmdp = (wrsmd_t *)arg;
+
+	D1("wrsmdteardown_tmo:  wrsmd 0x%p (ctlr %d)", (void *)wrsmdp,
+	    wrsmdp->wrsmd_ctlr_id);
+
+	mutex_enter(&wrsmdp->wrsmd_lock);
+	if (wrsmdp->wrsmd_teardown_tmo_id != 0) {
+		mutex_exit(&wrsmdp->wrsmd_lock);
+		if (wrsmduninit(wrsmdp) != 0) {
+			/*
+			 * If wrsmduninit() does not complete,
+			 * reschedule timeout to retry later.
+			 */
+			mutex_enter(&wrsmdp->wrsmd_lock);
+			wrsmdp->wrsmd_teardown_tmo_id =
+			    timeout(wrsmdteardown_tmo,
+			    (caddr_t)wrsmdp,
+			    wrsmdp->wrsmd_param.wrsmd_teardown_tmo);
+		} else {
+			mutex_enter(&wrsmdp->wrsmd_lock);
+			wrsmdp->wrsmd_teardown_tmo_id = 0;
+		}
+	}
+	mutex_exit(&wrsmdp->wrsmd_lock);
+
+	D1("wrsmdteardown_tmo: done");
+}
+
+
+/*
+ * ****************************************************************
+ *                                                               *
+ * E N D       TIMEOUT-FUNCTIONS                                 *
+ *                                                               *
+ * ****************************************************************
+ */
+
+/*
+ * ****************************************************************
+ *                                                                *
+ * B E G I N   EVENT-FUNCTIONS                                    *
+ *                                                                *
+ * ****************************************************************
+ */
+
+/*
+ * The wrsmd event thread.  We can't make RSM_ calls that can block
+ * from either callbacks (timeouts) or interrupts.  Use this thread
+ * (one thread/wrsmd device) to make those calls for us.  Currently
+ * handles freedest and sync events
+ */
+static void
+wrsmd_event_thread(void *arg)
+{
+	wrsmd_t *wrsmdp = (wrsmd_t *)arg;
+	callb_cpr_t cprinfo;
+
+	CALLB_CPR_INIT(&cprinfo, &wrsmdp->event_lock,
+			callb_generic_cpr, "wrsmd_event_thread");
+
+	/* LINTED: E_CONSTANT_CONDITION */
+	while (1) {
+		wrsmd_process_event(wrsmdp);
+
+		mutex_enter(&wrsmdp->event_lock);
+		CALLB_CPR_SAFE_BEGIN(&cprinfo);
+		cv_wait(&wrsmdp->event_cv, &wrsmdp->event_lock);
+		CALLB_CPR_SAFE_END(&cprinfo, &wrsmdp->event_lock);
+		mutex_exit(&wrsmdp->event_lock);
+
+		if (wrsmdp->stop_events) {
+			wrsmd_process_event(wrsmdp);
+
+			mutex_enter(&wrsmdp->event_lock);
+			cv_broadcast(&wrsmdp->event_thread_exit_cv);
+
+			/*
+			 * CALLB_CPR_EXIT() calls mutex_exit() on the
+			 * lock passed into CALLB_CPR_INIT() above, therefore
+			 * we don't want to call mutex_exit() here. See
+			 * common/sys/callb.h and common/sys/cpr.h.
+			 */
+			CALLB_CPR_EXIT(&cprinfo);
+
+			thread_exit();
+			return;
+		}
+	}
+}
+
+/*
+ * Helper thread to process events off of the queue.  Handles both sync and
+ * freedest events.
+ */
+static void
+wrsmd_process_event(wrsmd_t *wrsmdp)
+{
+	wrsmd_event_t	*evt;
+	wrsmd_dest_t	*rd;
+
+	mutex_enter(&wrsmdp->event_lock);
+
+	while (wrsmdp->events) {
+		evt = wrsmdp->events;
+		mutex_exit(&wrsmdp->event_lock);
+
+		switch (evt->type) {
+			case WRSMD_EVT_SYNC:
+				rd = (wrsmd_dest_t *)evt->arg;
+
+				mutex_enter(&rd->rd_net_lock);
+				/* Try sync'ing again */
+				wrsmdsyncdqe(rd);
+				wrsmdsyncfqe(rd);
+				mutex_exit(&rd->rd_net_lock);
+
+				break;
+
+			case WRSMD_EVT_SYNC_DQE:
+				rd = (wrsmd_dest_t *)evt->arg;
+				wrsmdmsghdlr_syncdqe_evt(rd);
+				break;
+
+			case WRSMD_EVT_FREEDEST:
+
+				wrsmdfreedestevt(evt->arg);
+
+				break;
+			default:
+				break;
+		}
+
+		mutex_enter(&wrsmdp->event_lock);
+		wrsmdp->events = evt->next;
+		kmem_free(evt, sizeof (wrsmd_event_t));
+	}
+
+	mutex_exit(&wrsmdp->event_lock);
+}
+
+/* Allocates and adds an event to the event queue */
+static void
+wrsmd_add_event(wrsmd_t *wrsmdp, int type, void *arg)
+{
+	wrsmd_event_t *evt, *newevt;
+
+	mutex_enter(&wrsmdp->event_lock);
+
+	if (wrsmdp->stop_events) {
+		mutex_exit(&wrsmdp->event_lock);
+		return;
+	}
+
+	newevt = kmem_alloc(sizeof (wrsmd_event_t), KM_SLEEP);
+	newevt->type = type;
+	newevt->arg = arg;
+	newevt->next = (wrsmd_event_t *)NULL;
+
+	evt = wrsmdp->events;
+	if (evt) {
+		while (evt->next)
+			evt = evt->next;
+
+		evt->next = newevt;
+	} else {
+		wrsmdp->events = newevt;
+	}
+
+	cv_broadcast(&wrsmdp->event_cv);
+	mutex_exit(&wrsmdp->event_lock);
+}
+
+/*
+ * ****************************************************************
+ *                                                                *
+ * E N D       EVENT-FUNCTIONS                                    *
+ *                                                                *
+ * ****************************************************************
+ */
+
+
+#ifdef __lock_lint
+
+void
+freemsg(mblk_t *mp)
+{
+	freeb(mp);
+}
+
+void
+freeb(mblk_t *bp)
+{
+	wrsmdbuf_t z;
+
+	wrsmdfreebuf(&z);
+}
+
+#endif	/* __lock_lint */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/io/wrsmd.conf	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,80 @@
+#
+# 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 2001 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+#
+# For each Wildcat RSM network controller, you must have a corresponding
+# instance of the wrsmd driver with the same instance number as the
+# network controller id.
+#
+
+name="wrsmd" parent="pseudo" instance=0;
+name="wrsmd" parent="pseudo" instance=1;
+name="wrsmd" parent="pseudo" instance=2;
+name="wrsmd" parent="pseudo" instance=3;
+name="wrsmd" parent="pseudo" instance=4;
+name="wrsmd" parent="pseudo" instance=5;
+name="wrsmd" parent="pseudo" instance=6;
+name="wrsmd" parent="pseudo" instance=7;
+name="wrsmd" parent="pseudo" instance=8;
+name="wrsmd" parent="pseudo" instance=9;
+name="wrsmd" parent="pseudo" instance=10;
+name="wrsmd" parent="pseudo" instance=11;
+name="wrsmd" parent="pseudo" instance=12;
+name="wrsmd" parent="pseudo" instance=13;
+name="wrsmd" parent="pseudo" instance=14;
+name="wrsmd" parent="pseudo" instance=15;
+
+#
+# Number of packet buffers exported to each communicating peer
+#
+wrsmd-buffers = 32;
+
+#
+# Size of packet buffers (must be multiple of 64 bytes).  For best performance,
+# this should be slightly larger than the normal amount of data your network
+# application reads or writes in one system call (your "application data
+# transfer size").  If it's more than two times your application data transfer
+# size, the driver will end up doing internal data copying to coalesce writes
+# together, which will reduce performance.  Note also that your TCP window
+# size should be set to at least twice this buffer size for best performance.
+#
+# Note:  (wrsmd-buffers * wrsmd-buffer-size) is allocated by the driver for
+# each remote node with which communication takes place.
+#
+wrsmd-buffer-size = 16384;
+
+#
+# Size of communications queues (must be at least as large as wrsmd-buffers).
+#
+wrsmd-queue-size = 64;
+
+#
+# Maximum number of packets which will be queued for a remote destination
+# before we start throwing them away.  This should be something like
+# (# of concurrent tcp connections) * (tcp window size) / (interface mtu).
+#
+wrsmd-max-queued-pkts = 100;
--- a/usr/src/uts/sun4u/javelin/Makefile.files	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/uts/sun4u/javelin/Makefile.files	Thu Jun 29 14:43:12 2006 -0700
@@ -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,9 +18,9 @@
 #
 # CDDL HEADER END
 #
+
 #
-# uts/sun4u/javelin/Makefile.files
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -36,6 +35,7 @@
 #
 # Javelin specific driver relate modules
 #
+ENVCTRLTWO_OBJS = envctrltwo.o
 
 #
 # Miscellaneous
--- a/usr/src/uts/sun4u/javelin/Makefile.javelin.shared	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/uts/sun4u/javelin/Makefile.javelin.shared	Thu Jun 29 14:43:12 2006 -0700
@@ -18,9 +18,9 @@
 #
 # CDDL HEADER END
 #
+
 #
-# uts/sun4u/javelin/Makefile.javelin
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -74,5 +74,5 @@
 # Define modules (must come after Makefile.sun4u, for CLOSED_BUILD)
 #
 JAVELIN_KMODS	= platmod
+JAVELIN_KMODS	+= envctrltwo
 
-$(CLOSED_BUILD)CLOSED_JAVELIN_KMODS	= envctrltwo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/javelin/envctrltwo/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,95 @@
+#
+# 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.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of the envctrltwo driver kernel
+#	module in the sun4u javelin systems.
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	  = ../../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= envctrltwo
+OBJECTS		= $(ENVCTRLTWO_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(ENVCTRLTWO_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_JAVELIN_DRV_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sun4u/javelin/Makefile.javelin
+
+#
+#       Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+# lint pass one enforcement
+#
+CFLAGS += $(CCVERBOSE)
+
+#
+# Turn on doubleword alignment for 64 bit registers
+#
+CFLAGS += -dalign
+
+LDFLAGS         += -dy -Ndrv/pcipsy
+
+#
+#	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)
+
+LINT_LIB_DIR	= $(JAVELIN_LINT_LIB_DIR)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/sun4u/javelin/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/javelin/io/envctrltwo.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,2898 @@
+/*
+ * 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 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * ENVCTRLTWO_ Environment Monitoring driver for i2c on Javelin
+ *
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <sys/errno.h>
+#include <sys/file.h>
+#include <sys/termio.h>
+#include <sys/termios.h>
+#include <sys/cmn_err.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/stropts.h>
+#include <sys/strtty.h>
+#include <sys/debug.h>
+#include <sys/eucioctl.h>
+#include <sys/cred.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/kmem.h>
+
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/obpdefs.h>
+#include <sys/conf.h>		/* req. by dev_ops flags MTSAFE etc. */
+#include <sys/modctl.h>		/* for modldrv */
+#include <sys/stat.h>		/* ddi_create_minor_node S_IFCHR */
+#include <sys/open.h>		/* for open params.	 */
+#include <sys/uio.h>		/* for read/write */
+#include <sys/envctrl_gen.h>	/* user level generic visible definitions */
+#include <sys/envctrl_ue250.h>	/* user level UE250 visible definitions */
+#include <javelin/sys/envctrltwo.h> /* definitions for Javelin */
+#include <io/envctrl_targets.c>
+#include <sys/priv_names.h>
+
+/* driver entry point fn definitions */
+static int 	envctrl_open(dev_t *, int, int, cred_t *);
+static int	envctrl_close(dev_t, int, int, cred_t *);
+static int	envctrl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+static uint_t 	envctrl_bus_isr(caddr_t);
+static uint_t 	envctrl_dev_isr(caddr_t);
+
+/* configuration entry point fn definitions */
+static int 	envctrl_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static int	envctrl_attach(dev_info_t *, ddi_attach_cmd_t);
+static int	envctrl_detach(dev_info_t *, ddi_detach_cmd_t);
+
+/* Driver private routines */
+#ifdef GET_CPU_TEMP
+static int	envctrl_get_cpu_temp(struct envctrlunit *, int);
+#endif
+static void	envctrl_fan_fail_service(struct envctrlunit *);
+static void	envctrl_PS_intr_service(struct envctrlunit *);
+static void	envctrl_ps_probe(struct envctrlunit *);
+static void	envctrl_tempr_poll(void *);
+static void	envctrl_pshotplug_poll(void *);
+static void	envctrl_led_blink(void *);
+static void	envctrl_init_bus(struct envctrlunit *);
+static void	envctrl_reset_dflop(struct envctrlunit *);
+static void	envctrl_enable_devintrs(struct envctrlunit *);
+static void	envctrl_intr_latch_clr(struct envctrlunit *);
+static void	envctrl_abort_seq_handler(char *msg);
+static int	envctrl_get_fpm_status(struct envctrlunit *, uint8_t *);
+static int	envctrl_set_fsp(struct envctrlunit *, uint8_t *);
+static int	envctrl_set_dskled(struct envctrlunit *,
+				struct envctrl_chip *);
+static int	envctrl_get_dskled(struct envctrlunit *,
+				struct envctrl_chip *);
+static int	envctrl_set_fanspeed(struct envctrlunit *,
+			struct envctrl_chip *);
+static void	envctrl_probe_cpus(struct envctrlunit *);
+static int	envctrl_match_cpu(dev_info_t *, void *);
+static int	envctrl_isother_fault_led(struct envctrlunit *,
+		    uint8_t, uint8_t);
+static int	envctrl_check_sys_temperatures(struct envctrlunit *);
+static void	envctrl_check_disk_kstats(struct envctrlunit *);
+static void	envctrl_update_disk_kstats(struct envctrlunit *,
+			uint8_t, uint8_t);
+static int	envctrl_read_chip(struct envctrlunit *, int, int, int,
+			uint8_t *, int);
+static int	envctrl_write_chip(struct envctrlunit *, int, int, int,
+			uint8_t *, int);
+static int	envctrl_check_tempr_levels(struct envctrlunit *,
+		int, uint8_t *, int);
+static void	envctrl_update_fanspeed(struct envctrlunit *);
+
+/* Kstat routines */
+static void	envctrl_add_kstats(struct envctrlunit *);
+static int	envctrl_ps_kstat_update(kstat_t *, int);
+static int	envctrl_fanstat_kstat_update(kstat_t *, int);
+static int	envctrl_encl_kstat_update(kstat_t *, int);
+static int	envctrl_temp_kstat_update(kstat_t *, int);
+static int	envctrl_disk_kstat_update(kstat_t *, int);
+static void	envctrl_init_encl_kstats(struct envctrlunit *);
+
+extern void power_down(const char *);
+extern int prom_getprop();
+extern int prom_getproplen();
+extern	void	prom_printf(const char *fmt, ...);
+extern void (*abort_seq_handler)();
+
+static void    *envctrlsoft_statep;
+
+static char driver_name[] = "envctrltwo";
+static uchar_t _cpu_temps[256];
+static uchar_t _cpu_fan_speeds[256];
+static int psok[2] = {-1, -1};
+static int pspr[2] = {-1, -1};
+static uint8_t idle_fanspeed;
+
+static int power_flt_led_lit = 0;
+
+extern void pci_thermal_rem_intr(dev_info_t *, uint_t);
+
+/* Local Variables */
+/* Indicates whether or not the overtemp thread has been started */
+static int envctrl_debug_flags = 0;
+static int envctrl_power_off_overide = 0;
+static int envctrl_max_retries = 200;
+static int envctrl_allow_detach = 0;
+static int envctrl_numcpus = 1;
+static int envctrl_handler = 1; /* 1 is the default */
+static clock_t overtemp_timeout_hz;
+static clock_t blink_timeout_hz;
+static clock_t pshotplug_timeout_hz;
+static clock_t warning_timeout_hz;
+/*
+ * Temperature levels :
+ * green = OK  - no action needed
+ * yellow = warning - display warning message and poll faster
+ * red = critical - shutdown system
+ */
+enum levels {green, yellow, red};
+
+#define	DPRINTF1 if (envctrl_debug_flags && (envctrl_debug_flags & 0x1)) printf
+#define	DPRINTF2 if (envctrl_debug_flags && (envctrl_debug_flags & 0x2)) printf
+#define	DPRINTF3 if (envctrl_debug_flags && (envctrl_debug_flags & 0x4)) printf
+
+#define	JAV_FAN_SPEED_SF_NUM	107
+#define	JAV_FAN_SPEED_SF_DEN	100
+#define	JAV_MAX_TEMP_SENSORS	6
+#define	JAV_FSP_MASK		0xC0
+#define	FAN_DRIFT		25
+#define	MAX_FAN_SPEED		255
+#define	MAX_DEVS		16
+
+#define	ENVCTRL_UE250_INTR_LATCH_INIT0 0xFE
+#define	ENVCTRL_UE250_INTR_LATCH_INIT1 0xFF
+
+static int t_scale_num[8];
+static int t_scale_den[8];
+static uint8_t t_addr[8];
+static uint8_t t_port[8];
+static int sensor_types[] = { ENVCTRL_UE250_CPU0_SENSOR,
+			ENVCTRL_UE250_CPU1_SENSOR, ENVCTRL_UE250_MB0_SENSOR,
+			ENVCTRL_UE250_MB1_SENSOR, ENVCTRL_UE250_PDB_SENSOR,
+			ENVCTRL_UE250_SCSI_SENSOR };
+
+static struct cb_ops envctrl_cb_ops = {
+	envctrl_open,		/* cb_open */
+	envctrl_close,		/* cb_close */
+	nodev,			/* cb_strategy */
+	nodev,			/* cb_print */
+	nodev,			/* cb_dump */
+	nodev,			/* cb_read */
+	nodev,			/* cb_write */
+	envctrl_ioctl,		/* cb_ioctl */
+	nodev,			/* cb_devmap */
+	nodev,			/* cb_mmap */
+	nodev,			/* cb_segmap */
+	nochpoll,		/* cb_chpoll */
+	ddi_prop_op,		/* cb_prop_op */
+	NULL,			/* cb_stream */
+	(int)(D_NEW | D_MP)	/* cb_flag */
+};
+
+/*
+ * Declare ops vectors for auto configuration.
+ */
+struct dev_ops  envctrltwo_ops = {
+	DEVO_REV,		/* devo_rev */
+	0,			/* devo_refcnt */
+	envctrl_getinfo,		/* devo_getinfo */
+	nulldev,		/* devo_identify */
+	nulldev,		/* devo_probe */
+	envctrl_attach,		/* devo_attach */
+	envctrl_detach,		/* devo_detach */
+	nodev,			/* devo_reset */
+	&envctrl_cb_ops,		/* devo_cb_ops */
+	(struct bus_ops *)NULL,	/* devo_bus_ops */
+	nulldev			/* devo_power */
+};
+
+extern struct mod_ops mod_driverops;
+
+static struct modldrv envctrlmodldrv = {
+	&mod_driverops,		/* type of module - driver */
+	"I2C ENVCTRLTWO_driver: %I%",
+	&envctrltwo_ops,
+};
+
+static struct modlinkage envctrlmodlinkage = {
+	MODREV_1,
+	&envctrlmodldrv,
+	0
+};
+
+int
+_init(void)
+{
+	register int    error;
+
+	if ((error = mod_install(&envctrlmodlinkage)) == 0) {
+		(void) ddi_soft_state_init(&envctrlsoft_statep,
+			sizeof (struct envctrlunit), 1);
+	}
+
+	return (error);
+}
+
+int
+_fini(void)
+{
+	register int    error;
+
+	if ((error = mod_remove(&envctrlmodlinkage)) == 0)
+		ddi_soft_state_fini(&envctrlsoft_statep);
+
+	return (error);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&envctrlmodlinkage, modinfop));
+}
+
+static int
+envctrl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	register int	instance;
+	char		name[16];
+	uint8_t fspval;
+	register struct	envctrlunit *unitp;
+	struct ddi_device_acc_attr attr;
+	uchar_t *creg_prop;
+	uint_t len, tblsz;
+	int i, j, k, status;
+	uint8_t fanspeed;
+
+	status = len = tblsz = 0;
+
+	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+
+	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
+
+	instance = ddi_get_instance(dip);
+
+	switch (cmd) {
+	case DDI_ATTACH:
+		break;
+	case DDI_RESUME:
+		if (!(unitp = ddi_get_soft_state(envctrlsoft_statep, instance)))
+			return (DDI_FAILURE);
+		mutex_enter(&unitp->umutex);
+		if (!unitp->suspended) {
+			mutex_exit(&unitp->umutex);
+			return (DDI_FAILURE);
+		}
+		unitp->suspended = 0;
+		unitp->initting = B_TRUE;
+		envctrl_init_bus(unitp);
+		unitp->initting = B_FALSE;
+
+		envctrl_ps_probe(unitp);
+		envctrl_probe_cpus(unitp);
+		mutex_exit(&unitp->umutex);
+
+		return (DDI_SUCCESS);
+
+	default:
+		return (DDI_FAILURE);
+	}
+
+	/* Set up timer values */
+	overtemp_timeout_hz = drv_usectohz(ENVCTRL_UE250_OVERTEMP_TIMEOUT_USEC);
+	blink_timeout_hz = drv_usectohz(ENVCTRL_UE250_BLINK_TIMEOUT_USEC);
+	pshotplug_timeout_hz =
+		drv_usectohz(ENVCTRL_UE250_BLINK_TIMEOUT_USEC * 2);
+	/*
+	 * On a cooling failure, either a fan failure or temperature
+	 * exceeding a WARNING level, the temperature poll thread
+	 * will run every 6 seconds.
+	 */
+	warning_timeout_hz =
+		drv_usectohz(ENVCTRL_UE250_OVERTEMP_TIMEOUT_USEC / 6);
+
+	if (ddi_soft_state_zalloc(envctrlsoft_statep, instance) != 0) {
+		cmn_err(CE_WARN, "%s%d: failed to zalloc softstate\n",
+			ddi_get_name(dip), instance);
+		goto failed;
+	}
+
+	unitp = ddi_get_soft_state(envctrlsoft_statep, instance);
+
+	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&unitp->bus_ctl_regs, 0,
+			sizeof (struct ehc_pcd8584_regs), &attr,
+			&unitp->ctlr_handle) != DDI_SUCCESS) {
+		cmn_err(CE_WARN, "%s%d: failed to map in bus_control regs\n",
+			ddi_get_name(dip), instance);
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * If the PCI nexus has added a thermal interrupt, we first need
+	 * to remove that interrupt handler.
+	 *
+	 * WARNING: Removing another driver's interrupt handler is not
+	 * allowed. The pci_thermal_rem_intr() call below is needed to retain
+	 * the legacy behavior on Javelin systems.
+	 */
+
+	pci_thermal_rem_intr(dip, (uint_t)0);
+
+	/* add interrupts */
+
+	if (ddi_get_iblock_cookie(dip, 1,
+			&unitp->ic_trap_cookie) != DDI_SUCCESS)  {
+		cmn_err(CE_WARN, "%s%d: ddi_get_iblock_cookie FAILED \n",
+			ddi_get_name(dip), instance);
+		goto failed;
+	}
+
+	mutex_init(&unitp->umutex, NULL, MUTEX_DRIVER,
+		(void *)unitp->ic_trap_cookie);
+
+
+	if (ddi_add_intr(dip, 0, &unitp->ic_trap_cookie, NULL, envctrl_bus_isr,
+			(caddr_t)unitp) != DDI_SUCCESS) {
+		cmn_err(CE_WARN, "%s%d: failed to add hard intr \n",
+			ddi_get_name(dip), instance);
+		goto remlock;
+	}
+
+
+	if (ddi_add_intr(dip, 1, &unitp->ic_trap_cookie, NULL, envctrl_dev_isr,
+			(caddr_t)unitp) != DDI_SUCCESS) {
+		cmn_err(CE_WARN, "%s%d: failed to add hard intr \n",
+			ddi_get_name(dip), instance);
+		goto remhardintr;
+	}
+
+
+	(void) sprintf(name, "envctrltwo%d", instance);
+
+	if (ddi_create_priv_minor_node(dip, name, S_IFCHR, instance,
+	    DDI_PSEUDO, 0, PRIV_SYS_CONFIG, PRIV_SYS_CONFIG, 0666) ==
+	    DDI_FAILURE) {
+		goto remhardintr1;
+	}
+
+	mutex_enter(&unitp->umutex);
+
+	/*
+	 * Javelin will not have a workstation configuration so activity
+	 * LED will always blink.
+	 */
+	unitp->activity_led_blink = B_TRUE;
+	unitp->shutdown = B_FALSE;
+	unitp->num_ps_present = 0;
+	unitp->num_encl_present = 1;
+	unitp->current_mode = ENVCTRL_NORMAL_MODE;
+	if (envctrl_numcpus > 1) {
+		unitp->num_cpus_present = envctrl_numcpus;
+	}
+	envctrl_probe_cpus(unitp);
+	if ((unitp->cpu_pr_location[ENVCTRL_CPU0] == B_FALSE) ||
+		(unitp->cpu_pr_location[ENVCTRL_CPU1] == B_FALSE))
+		/* Only one CPU in the system */
+		unitp->num_temps_present = 5;
+	else
+		unitp->num_temps_present = 6;
+	unitp->num_fans_present = 1;
+	unitp->dip = dip;
+
+	mutex_exit(&unitp->umutex);
+
+	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "cpu-temp-factors", &creg_prop, &len) != DDI_PROP_SUCCESS) {
+		cmn_err(CE_WARN,
+			"%s%d: Unable to read cpu-temp-factors property",
+			ddi_get_name(dip), instance);
+		return (DDI_NOT_WELL_FORMED);
+	}
+	tblsz = (sizeof (_cpu_temps) / sizeof (uchar_t));
+
+	if (len <= tblsz && status == DDI_PROP_SUCCESS) {
+		for (i = 0; i < len; i++) {
+			_cpu_temps[i+2] = creg_prop[i];
+		}
+	}
+	_cpu_temps[0] = _cpu_temps[1] = _cpu_temps[2];
+
+	ddi_prop_free((void *)creg_prop);
+
+	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "cpu-fan-speeds", &creg_prop, &len) != DDI_PROP_SUCCESS) {
+		cmn_err(CE_WARN,
+			"%s%d: Unable to read cpu-fan-speeds property",
+			ddi_get_name(dip), instance);
+		return (DDI_NOT_WELL_FORMED);
+	}
+	tblsz = (sizeof (_cpu_fan_speeds) / sizeof (uchar_t));
+
+	if (len <= tblsz && status == DDI_PROP_SUCCESS) {
+		for (i = 0; i < len; i++) {
+			_cpu_fan_speeds[i+2] = creg_prop[i];
+		}
+	}
+	_cpu_fan_speeds[0] = _cpu_fan_speeds[1] = _cpu_fan_speeds[2];
+
+	ddi_prop_free((void *)creg_prop);
+
+	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "thermisters", &creg_prop, &len) != DDI_PROP_SUCCESS) {
+		cmn_err(CE_WARN,
+			"%s%d: Unable to read thermisters property",
+			ddi_get_name(dip), instance);
+		return (DDI_NOT_WELL_FORMED);
+	}
+
+	mutex_enter(&unitp->umutex);
+
+	j = 0; k = 0;
+	for (i = 0; i < JAV_MAX_TEMP_SENSORS; i++) {
+		/* Type */
+		unitp->temp_kstats[k].type = sensor_types[i];
+		/* Address */
+		t_addr[k] = creg_prop[j] << 24 | creg_prop[j+1] << 16 |
+			creg_prop[j+2] << 8 | creg_prop[j+3];
+		j += 4;
+		/* Port */
+		t_port[k] = creg_prop[j] << 24 | creg_prop[j+1] << 16 |
+			creg_prop[j+2] << 8 | creg_prop[j+3];
+		j += 4;
+		/* Min */
+		unitp->temp_kstats[k].min =
+			creg_prop[j] << 24 | creg_prop[j+1] << 16 |
+			creg_prop[j+2] << 8 | creg_prop[j+3];
+		j += 4;
+		/* Warning threshold */
+		unitp->temp_kstats[k].warning_threshold =
+			creg_prop[j] << 24 | creg_prop[j+1] << 16 |
+			creg_prop[j+2] << 8 | creg_prop[j+3];
+		j += 4;
+		/* Shutdown threshold */
+		unitp->temp_kstats[k].shutdown_threshold =
+			creg_prop[j] << 24 | creg_prop[j+1] << 16 |
+			creg_prop[j+2] << 8 | creg_prop[j+3];
+		j += 4;
+		/* Numerator of scale factor */
+		t_scale_num[k] = creg_prop[j] << 24 | creg_prop[j+1] << 16 |
+			creg_prop[j+2] << 8 | creg_prop[j+3];
+		j += 4;
+		/* Denominator of scale factor */
+		t_scale_den[k] = creg_prop[j] << 24 | creg_prop[j+1] << 16 |
+			creg_prop[j+2] << 8 | creg_prop[j+3];
+		j += 4;
+		bcopy((caddr_t)&creg_prop[j], unitp->temp_kstats[k].label,
+			(size_t)sizeof (&creg_prop[j]));
+		while (creg_prop[j] != '\0') j++;
+		j++;
+		if (t_addr[k] == ENVCTRL_UE250_CPU_TEMP_DEV) {
+			if (((t_port[k] == ENVCTRL_UE250_CPU0_PORT) &&
+			(unitp->cpu_pr_location[ENVCTRL_CPU0] == B_FALSE)) ||
+			    ((t_port[k] == ENVCTRL_UE250_CPU1_PORT) &&
+			    (unitp->cpu_pr_location[ENVCTRL_CPU1] == B_FALSE)))
+				/* Don't increment the kstat line count */
+#ifdef lint
+				k = k;
+#else
+				;
+#endif
+			else
+				k++;
+		} else
+			k++;
+	}
+
+	ddi_prop_free((void *)creg_prop);
+
+	/* initialize the envctrl bus controller */
+
+	unitp->initting = B_TRUE;
+	envctrl_init_bus(unitp);
+	DPRINTF1("envctrl_attach(): Completed initialization of PCF8584");
+	unitp->initting = B_FALSE;
+	drv_usecwait(1000);
+
+	unitp->timeout_id = 0;
+	unitp->blink_timeout_id = 0;
+
+	unitp->fan_failed = 0;
+	unitp->fan_kstats.fans_ok = B_TRUE;
+	unitp->tempr_warning = 0;
+
+	envctrl_ps_probe(unitp);
+
+	unitp->initting = B_TRUE;
+	envctrl_fan_fail_service(unitp);
+	unitp->initting = B_FALSE;
+
+	/*
+	 * Fans could be blasting, turn them down.
+	 */
+	fanspeed = 0x0;
+	status = envctrl_write_chip(unitp, ENVCTRL_PCF8591, EHC_DEV2, 0,
+			&fanspeed, 1);
+	if (status == DDI_FAILURE)
+		cmn_err(CE_WARN, "%s%d: Write to PCF8591 (SETFAN) failed\n",
+			ddi_get_name(dip), instance);
+
+	/*
+	 * we need to init the fan kstats before the tempr_poll
+	 */
+	envctrl_add_kstats(unitp);
+	envctrl_init_encl_kstats(unitp);
+	envctrl_check_disk_kstats(unitp);
+
+	envctrl_update_fanspeed(unitp);
+	idle_fanspeed = unitp->fan_kstats.fanspeed;
+
+	if (unitp->activity_led_blink == B_TRUE) {
+		unitp->present_led_state = B_FALSE;
+		mutex_exit(&unitp->umutex);
+		envctrl_led_blink((void *)unitp);
+		mutex_enter(&unitp->umutex);
+	} else {
+		fspval = ENVCTRL_UE250_FSP_ACTIVE;
+		(void) envctrl_set_fsp(unitp, &fspval);
+	}
+
+	mutex_exit(&unitp->umutex);
+
+	envctrl_tempr_poll((void *)unitp);
+
+	/*
+	 * interpose envctrl's abort sequence handler
+	 */
+	if (envctrl_handler) {
+		abort_seq_handler = envctrl_abort_seq_handler;
+	}
+
+	ddi_report_dev(dip);
+
+	return (DDI_SUCCESS);
+
+remhardintr1:
+	ddi_remove_intr(dip, (uint_t)1, unitp->ic_trap_cookie);
+remhardintr:
+	ddi_remove_intr(dip, (uint_t)0, unitp->ic_trap_cookie);
+
+remlock:
+	mutex_destroy(&unitp->umutex);
+
+failed:
+	if (unitp->ctlr_handle)
+		ddi_regs_map_free(&unitp->ctlr_handle);
+
+	cmn_err(CE_WARN, "%s%d: attach failed\n", ddi_get_name(dip), instance);
+
+	return (DDI_FAILURE);
+
+}
+
+static int
+envctrl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+	int		instance;
+	register struct envctrlunit *unitp;
+
+	instance = ddi_get_instance(dip);
+	unitp = ddi_get_soft_state(envctrlsoft_statep, instance);
+
+	switch (cmd) {
+	case DDI_DETACH:
+		if (envctrl_allow_detach) {
+
+			if (unitp->psksp != NULL) {
+				kstat_delete(unitp->psksp);
+			}
+			if (unitp->fanksp != NULL) {
+				kstat_delete(unitp->fanksp);
+			}
+			if (unitp->enclksp != NULL) {
+				kstat_delete(unitp->enclksp);
+			}
+			if (unitp->tempksp != NULL) {
+				kstat_delete(unitp->tempksp);
+			}
+			if (unitp->diskksp != NULL) {
+				kstat_delete(unitp->diskksp);
+			}
+
+			if (unitp->timeout_id != 0) {
+				(void) untimeout(unitp->timeout_id);
+				unitp->timeout_id = 0;
+			}
+			if (unitp->blink_timeout_id != 0) {
+				(void) untimeout(unitp->blink_timeout_id);
+				unitp->blink_timeout_id = 0;
+			}
+
+			ddi_remove_minor_node(dip, NULL);
+
+			ddi_remove_intr(dip, (uint_t)0, unitp->ic_trap_cookie);
+			ddi_remove_intr(dip, (uint_t)1, unitp->ic_trap_cookie);
+
+			ddi_regs_map_free(&unitp->ctlr_handle);
+
+			mutex_destroy(&unitp->umutex);
+
+			return (DDI_SUCCESS);
+		} else {
+			return (DDI_FAILURE);
+		}
+
+	case DDI_SUSPEND:
+		if (!(unitp = ddi_get_soft_state(envctrlsoft_statep, instance)))
+		    return (DDI_FAILURE);
+		mutex_enter(&unitp->umutex);
+		if (unitp->suspended) {
+			cmn_err(CE_WARN, "%s%d: envctrltwo already suspended\n",
+				ddi_get_name(dip), instance);
+			mutex_exit(&unitp->umutex);
+			return (DDI_FAILURE);
+		}
+		unitp->suspended = 1;
+		mutex_exit(&unitp->umutex);
+		return (DDI_SUCCESS);
+
+	default:
+		cmn_err(CE_WARN, "%s%d: suspend general fault\n",
+			ddi_get_name(dip), instance);
+		return (DDI_FAILURE);
+	}
+
+
+}
+int
+envctrl_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
+    void **result)
+{
+	dev_t	dev = (dev_t)arg;
+	struct envctrlunit *unitp;
+	int	instance, ret;
+
+	instance = getminor(dev);
+
+#ifdef lint
+	dip = dip;
+#endif
+
+
+	switch (infocmd) {
+		case DDI_INFO_DEVT2DEVINFO:
+			if ((unitp = (struct envctrlunit *)
+				ddi_get_soft_state(envctrlsoft_statep,
+				    instance)) != NULL) {
+				*result = unitp->dip;
+				ret = DDI_SUCCESS;
+			} else {
+				*result = NULL;
+				ret = DDI_FAILURE;
+			}
+			break;
+		case DDI_INFO_DEVT2INSTANCE:
+			*result = (void *)(uintptr_t)instance;
+			ret = DDI_SUCCESS;
+			break;
+		default:
+			ret = DDI_FAILURE;
+			break;
+	}
+
+	return (ret);
+}
+
+/* ARGSUSED1 */
+static int
+envctrl_open(dev_t *dev, int flag, int otyp, cred_t *cred_p)
+{
+	struct envctrlunit *unitp;
+	int status = 0;
+	register int	instance;
+
+	instance = getminor(*dev);
+	if (instance < 0)
+		return (ENXIO);
+	unitp = (struct envctrlunit *)
+		    ddi_get_soft_state(envctrlsoft_statep, instance);
+
+	if (unitp == NULL)
+		return (ENXIO);
+
+	if (otyp != OTYP_CHR)
+		return (EINVAL);
+
+	mutex_enter(&unitp->umutex);
+
+	if (flag & FWRITE) {
+		if ((unitp->oflag & FWRITE)) {
+			mutex_exit(&unitp->umutex);
+			return (EBUSY);
+		} else {
+			unitp->oflag |= FWRITE;
+		}
+	}
+
+	mutex_exit(&unitp->umutex);
+	return (status);
+}
+
+/*ARGSUSED1*/
+static int
+envctrl_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
+{
+	struct envctrlunit *unitp;
+	register int    instance;
+
+	instance = getminor(dev);
+	if (instance < 0)
+		return (ENXIO);
+	unitp = (struct envctrlunit *)
+		ddi_get_soft_state(envctrlsoft_statep, instance);
+	if (unitp == NULL)
+		return (ENXIO);
+
+	mutex_enter(&unitp->umutex);
+
+	unitp->oflag = B_FALSE;
+	unitp->current_mode = ENVCTRL_NORMAL_MODE;
+
+	mutex_exit(&unitp->umutex);
+	return (DDI_SUCCESS);
+}
+
+
+/*
+ * standard put procedure for envctrl
+ */
+static int
+envctrl_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
+	int *rvalp)
+{
+	struct envctrlunit *unitp;
+	register int	instance;
+	uint8_t wdval, tempr;
+	struct envctrl_chip fanspeed;
+	struct envctrl_chip ledchip, envcchip;
+	struct envctrl_chip temp, a_fanspeed;
+	int rval = 0, status, tfanspeed;
+
+#ifdef lint
+	cred_p = cred_p;
+	rvalp = rvalp;
+#endif
+	instance = getminor(dev);
+	unitp = (struct envctrlunit *)
+		    ddi_get_soft_state(envctrlsoft_statep, instance);
+
+	if ((cmd == ENVCTRL_IOC_SETFAN2) ||
+	    (cmd == ENVCTRL_IOC_GETFAN2) ||
+	    (cmd == ENVCTRL_IOC_SETMODE) ||
+	    (cmd == ENVCTRL_IOC_GETMODE) ||
+	    (cmd == ENVCTRL_IOC_GETTEMP2) ||
+	    (cmd == ENVCTRL_IOC_SETFSP2) ||
+	    (cmd == ENVCTRL_IOC_GETFSP2) ||
+	    (cmd == ENVCTRL_IOC_RESETTMPR) ||
+	    (cmd == ENVCTRL_IOC_SETDSKLED2) ||
+	    (cmd == ENVCTRL_IOC_GETDSKLED2))
+		if ((caddr_t)arg == NULL)
+			return (EFAULT);
+
+	switch (cmd) {
+	case ENVCTRL_IOC_SETMODE:
+		/* Set mode */
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&wdval, sizeof (uint8_t),
+			flag)) {
+			rval = EFAULT;
+			break;
+		}
+		if (wdval == ENVCTRL_DIAG_MODE ||
+			wdval == ENVCTRL_NORMAL_MODE) {
+			mutex_enter(&unitp->umutex);
+			unitp->current_mode = wdval;
+			if (unitp->timeout_id != 0 &&
+			    wdval == ENVCTRL_DIAG_MODE) {
+				(void) untimeout(unitp->timeout_id);
+				unitp->timeout_id =
+				    (timeout(envctrl_tempr_poll,
+				    (caddr_t)unitp, overtemp_timeout_hz));
+			}
+			if (wdval == ENVCTRL_NORMAL_MODE) {
+				/*
+				 * Fans could be blasting, turn them down.
+				 */
+				tempr = 0x0;
+				status = envctrl_write_chip(unitp,
+					ENVCTRL_PCF8591, EHC_DEV2, 0,
+					&tempr, 1);
+				if (status == DDI_FAILURE)
+				cmn_err(CE_WARN,
+				"%s%d: Write to PCF8591 (SETMODE) failed\n",
+				driver_name, unitp->instance);
+
+				/*
+				 * This delay allows the fans to time to
+				 * change speed
+				 */
+				drv_usecwait(100000);
+				(void) envctrl_check_sys_temperatures(unitp);
+				unitp->current_mode = ENVCTRL_DIAG_MODE;
+				envctrl_fan_fail_service(unitp);
+				unitp->current_mode = ENVCTRL_NORMAL_MODE;
+			}
+			mutex_exit(&unitp->umutex);
+		} else {
+			rval = EINVAL;
+		}
+		break;
+	case ENVCTRL_IOC_GETMODE:
+		wdval = unitp->current_mode;
+		if (ddi_copyout((caddr_t)&wdval, (caddr_t)arg,
+			sizeof (uint8_t), flag)) {
+			rval = EFAULT;
+		}
+		break;
+	case ENVCTRL_IOC_RESETTMPR:
+		/*
+		 * For diags, cancel the curent temp poll
+		 * and reset it for a new one.
+		 */
+		if (unitp->current_mode == ENVCTRL_DIAG_MODE) {
+			if (unitp->timeout_id != 0) {
+				(void) untimeout(unitp->timeout_id);
+				unitp->timeout_id = 0;
+			}
+			envctrl_tempr_poll((void *)unitp);
+		} else {
+			rval = EINVAL;
+		}
+		break;
+	case ENVCTRL_IOC_GETTEMP2:
+		/* Get the user buffer address */
+
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&temp,
+			sizeof (struct envctrl_chip), flag)) {
+			rval = EFAULT;
+			break;
+		}
+		if (((temp.chip_num != ENVCTRL_DEV2) &&
+			(temp.chip_num != ENVCTRL_DEV7)) ||
+			(temp.index > EHC_PCF8591_CH_3)) {
+			rval = EINVAL;
+			break;
+		}
+		mutex_enter(&unitp->umutex);
+		status = envctrl_read_chip(unitp, ENVCTRL_PCF8591,
+			temp.chip_num, temp.index, &temp.val, 1);
+		mutex_exit(&unitp->umutex);
+		if (status == DDI_FAILURE) {
+			cmn_err(CE_WARN,
+				"%s%d: Read from PCF8591 (IOC_GETTEMP) failed",
+				driver_name, unitp->instance);
+			rval = EINVAL;
+			break;
+		}
+		if (ddi_copyout((caddr_t)&temp, (caddr_t)arg,
+			sizeof (struct envctrl_chip), flag)) {
+			rval = EFAULT;
+		}
+		break;
+	case ENVCTRL_IOC_SETTEMP:
+		rval = EINVAL;
+		break;
+	case ENVCTRL_IOC_SETWDT:
+		rval = EINVAL;
+		break;
+	case ENVCTRL_IOC_SETFAN2:
+		/* NOTE: need to sanity check values coming from userland */
+		if (unitp->current_mode == ENVCTRL_DIAG_MODE) {
+			if (ddi_copyin((caddr_t)arg, (caddr_t)&fanspeed,
+				sizeof (struct envctrl_chip), flag)) {
+				rval = EFAULT;
+				break;
+			}
+			if ((fanspeed.type != ENVCTRL_PCF8591) ||
+				(fanspeed.chip_num != ENVCTRL_DEV2) ||
+				(fanspeed.index > EHC_PCF8591_CH_3)) {
+				rval = EINVAL;
+				break;
+			}
+			mutex_enter(&unitp->umutex);
+			status = envctrl_set_fanspeed(unitp, &fanspeed);
+			if (status == DDI_FAILURE) {
+				cmn_err(CE_WARN,
+				"%s%d: Write to PCF8591 (IOC_SETFAN) failed",
+				driver_name, unitp->instance);
+				rval = EINVAL;
+			}
+			mutex_exit(&unitp->umutex);
+		} else {
+			rval = EINVAL;
+		}
+		break;
+	case ENVCTRL_IOC_GETFAN2:
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&a_fanspeed,
+			sizeof (struct envctrl_chip), flag)) {
+			rval = EFAULT;
+			break;
+		}
+		if ((a_fanspeed.type != ENVCTRL_PCF8591) ||
+			(a_fanspeed.chip_num != ENVCTRL_DEV2) ||
+			(a_fanspeed.index != EHC_PCF8591_CH_1)) {
+			rval = EINVAL;
+			break;
+		}
+		mutex_enter(&unitp->umutex);
+		status = envctrl_read_chip(unitp, ENVCTRL_PCF8591,
+			a_fanspeed.chip_num, a_fanspeed.index,
+			&a_fanspeed.val, 1);
+		mutex_exit(&unitp->umutex);
+		if (status == DDI_FAILURE) {
+			cmn_err(CE_WARN,
+			"%s%d: Read of PCF8591 (IOC_GETFAN) failed",
+			driver_name, unitp->instance);
+			rval = EINVAL;
+			break;
+		}
+		/*
+		 * Due to hardware limitation, the actual fan speed
+		 * is always a little less than what it was set to by
+		 * software. Hence, we scale up the read fan speed value
+		 * to more closely match the set value.
+		 */
+		if ((tfanspeed = ((int)a_fanspeed.val * JAV_FAN_SPEED_SF_NUM) /
+				JAV_FAN_SPEED_SF_DEN) > 255)
+			a_fanspeed.val = 255;
+		else
+			a_fanspeed.val = tfanspeed & 0xFF;
+		unitp->fan_kstats.fanspeed = a_fanspeed.val;
+		if (ddi_copyout((caddr_t)&a_fanspeed, (caddr_t)arg,
+			sizeof (struct envctrl_chip), flag)) {
+			rval = EFAULT;
+		}
+		break;
+	case ENVCTRL_IOC_SETFSP2:
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&envcchip,
+			sizeof (struct envctrl_chip), flag)) {
+			rval = EFAULT;
+			break;
+		}
+		if ((envcchip.type != ENVCTRL_PCF8574A) ||
+			(envcchip.chip_num != ENVCTRL_DEV6)) {
+			rval = EINVAL;
+			break;
+		}
+		wdval = envcchip.val;
+		mutex_enter(&unitp->umutex);
+		/*
+		 * If a user is in normal mode and they try
+		 * to set anything other than a disk fault or
+		 * a gen fault it is an invalid operation.
+		 * in diag mode we allow everything to be
+		 * twiddled.
+		 */
+		if (unitp->current_mode == ENVCTRL_NORMAL_MODE) {
+			if (wdval & ~ENVCTRL_UE250_FSP_USRMASK) {
+				mutex_exit(&unitp->umutex);
+				rval = EINVAL;
+				break;
+			}
+		}
+		if (wdval & ENVCTRL_UE250_FSP_PS_ERR)
+			power_flt_led_lit = 1;
+		status = envctrl_set_fsp(unitp, &wdval);
+		mutex_exit(&unitp->umutex);
+		if (status == DDI_FAILURE) {
+			cmn_err(CE_WARN,
+				"%s%d: Read of PCF8574A (IOC_SETFSP) failed",
+				driver_name, unitp->instance);
+			rval = EINVAL;
+		}
+		break;
+	case ENVCTRL_IOC_GETFSP2:
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&envcchip,
+			sizeof (struct envctrl_chip), flag)) {
+			rval = EFAULT;
+			break;
+		}
+		if ((envcchip.type != ENVCTRL_PCF8574A) ||
+			(envcchip.chip_num != ENVCTRL_DEV6)) {
+			rval = EINVAL;
+			break;
+		}
+		mutex_enter(&unitp->umutex);
+		status = envctrl_get_fpm_status(unitp, &wdval);
+		mutex_exit(&unitp->umutex);
+		if (status == DDI_FAILURE) {
+			cmn_err(CE_WARN,
+				"%s%d: Read of PCF8574A (IOC_GETFSP) failed",
+				driver_name, unitp->instance);
+			rval = EINVAL;
+		} else {
+			envcchip.val = wdval;
+			if (ddi_copyout((caddr_t)&envcchip, (caddr_t)arg,
+				sizeof (struct envctrl_chip), flag)) {
+				rval = EFAULT;
+			}
+		}
+		break;
+	case ENVCTRL_IOC_SETDSKLED2:
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&ledchip,
+			sizeof (struct envctrl_chip), flag)) {
+			rval = EFAULT;
+			break;
+		}
+		if ((ledchip.type != ENVCTRL_PCF8574A) ||
+			(ledchip.chip_num != ENVCTRL_DEV7)) {
+			rval = EINVAL;
+			break;
+		}
+		mutex_enter(&unitp->umutex);
+		if (envctrl_set_dskled(unitp, &ledchip)) {
+			rval = EINVAL;
+		}
+		mutex_exit(&unitp->umutex);
+		break;
+	case ENVCTRL_IOC_GETDSKLED2:
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&ledchip,
+			sizeof (struct envctrl_chip), flag)) {
+			rval = EFAULT;
+			break;
+		}
+		if ((ledchip.type != ENVCTRL_PCF8574A) ||
+			(ledchip.chip_num != ENVCTRL_DEV7)) {
+			rval = EINVAL;
+			break;
+		}
+		mutex_enter(&unitp->umutex);
+		if (envctrl_get_dskled(unitp, &ledchip)) {
+			rval = EINVAL;
+		} else {
+			if (ddi_copyout((caddr_t)&ledchip, (caddr_t)arg,
+				sizeof (struct envctrl_chip), flag)) {
+				rval = EFAULT;
+			}
+		}
+		mutex_exit(&unitp->umutex);
+		break;
+	case ENVCTRL_IOC_SETRAW:
+		if (unitp->current_mode != ENVCTRL_DIAG_MODE) {
+			rval = EINVAL;
+			break;
+		}
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&temp,
+			sizeof (struct envctrl_chip), flag)) {
+			rval = EFAULT;
+			break;
+		}
+		mutex_enter(&unitp->umutex);
+		status = envctrl_write_chip(unitp, temp.type, temp.chip_num,
+			temp.index, &temp.val, 1);
+		if (status == DDI_FAILURE) {
+			cmn_err(CE_WARN,
+				"%s%d: Write to chip (IOC_SETRAW) failed",
+				driver_name, unitp->instance);
+			rval = EINVAL;
+		}
+		mutex_exit(&unitp->umutex);
+		break;
+	case ENVCTRL_IOC_GETRAW:
+		if (ddi_copyin((caddr_t)arg, (caddr_t)&temp,
+			sizeof (struct envctrl_chip), flag)) {
+			rval = EFAULT;
+			break;
+		}
+		mutex_enter(&unitp->umutex);
+		status = envctrl_read_chip(unitp, temp.type, temp.chip_num,
+			temp.index, &temp.val, 1);
+		if (status == DDI_FAILURE) {
+			cmn_err(CE_WARN,
+				"%s%d: Read of chip (IOC_GETRAW) failed",
+				driver_name, unitp->instance);
+			rval = EINVAL;
+		}
+		mutex_exit(&unitp->umutex);
+		if (ddi_copyout((caddr_t)&temp, (caddr_t)arg,
+			sizeof (struct envctrl_chip), flag)) {
+			rval = EFAULT;
+		}
+		break;
+	default:
+		rval = EINVAL;
+	}
+
+	return (rval);
+}
+
+uint_t
+envctrl_bus_isr(caddr_t arg)
+{
+	struct envctrlunit *unitp = (struct envctrlunit *)(void *)arg;
+	int ic = DDI_INTR_UNCLAIMED;
+
+	mutex_enter(&unitp->umutex);
+
+	/*
+	 * NOT USED
+	 */
+
+	mutex_exit(&unitp->umutex);
+	return (ic);
+}
+
+uint_t
+envctrl_dev_isr(caddr_t arg)
+{
+	struct envctrlunit *unitp = (struct envctrlunit *)(void *)arg;
+	uint8_t recv_data;
+	int ic;
+	int retrys = 0;
+	int status;
+	static int spurious_intr_count = 0;
+
+	ic = DDI_INTR_UNCLAIMED;
+
+	mutex_enter(&unitp->umutex);
+
+
+	/*
+	 * First check to see if it is an interrupt for us by
+	 * looking at the "ganged" interrupt and vector
+	 * according to the major type
+	 * 0x70 is the addr of the ganged interrupt controller.
+	 * Address map for the port byte read is as follows
+	 * MSB
+	 * -------------------------
+	 * |  |  |  |  |  |  |  |  |
+	 * -------------------------
+	 *  P7 P6 P5 P4 P3 P2 P1 P0
+	 * P0 = Spare
+	 * P1 = Thermal Interrupt
+	 * P2 = Disk Interrupt
+	 * P3 = Interrupt clock enable
+	 * P4 = Fan Fail Interrupt
+	 * P5 =	Front Panel Interrupt
+	 * P6 = Power Supply Interrupt
+	 * P7 = Enable Interrupts
+	 */
+
+	do {
+		status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
+			ENVCTRL_UE250_PCF8574A_BASE_ADDR | EHC_DEV0,
+			&recv_data, 1);
+
+		/*
+		 * This extra read is needed since the first read is discarded
+		 * and the second read seems to return 0xFF.
+		 */
+		if (recv_data == 0xFF) {
+			status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
+				ENVCTRL_UE250_PCF8574A_BASE_ADDR | EHC_DEV0,
+				&recv_data, 1);
+		}
+
+		/*
+		 * if the i2c bus is hung it is imperative that this
+		 * be cleared on an interrupt or else it will
+		 * hang the system with continuous interrupts
+		 */
+
+		if (status == DDI_FAILURE) {
+			drv_usecwait(1000);
+			if (retrys < envctrl_max_retries) {
+				retrys++;
+			} else {
+				cmn_err(CE_WARN,
+					"%s%d: Read of PCF8574A (INT) failed\n",
+					driver_name, unitp->instance);
+				ehc_init_pcf8584((struct ehc_envcunit *)unitp);
+				mutex_exit(&unitp->umutex);
+				ic = DDI_INTR_CLAIMED;
+				return (ic);
+			}
+		}
+	} while (status != DDI_SUCCESS);
+
+	DPRINTF1("Interrupt routine called, interrupt = %X\n", recv_data);
+	if (!(recv_data & EHC_PCF8574_PORT0)) {
+		ic = DDI_INTR_CLAIMED;
+	}
+
+	if (!(recv_data & EHC_PCF8574_PORT1)) {
+		DPRINTF1("Temperature interrupt detected\n");
+		(void) envctrl_check_sys_temperatures(unitp);
+
+		/*
+		 * Clear the interrupt latches
+		 */
+		envctrl_intr_latch_clr(unitp);
+
+		ic = DDI_INTR_CLAIMED;
+	}
+
+	if (!(recv_data & EHC_PCF8574_PORT2)) {
+		DPRINTF1("Disk interrupt detected\n");
+		envctrl_check_disk_kstats(unitp);
+		ic = DDI_INTR_CLAIMED;
+	}
+
+	if (!(recv_data & EHC_PCF8574_PORT3)) {
+		ic = DDI_INTR_CLAIMED;
+	}
+
+	if (!(recv_data & EHC_PCF8574_PORT4)) {
+		/*
+		 * Check for a fan fail
+		 */
+		DPRINTF1("Fan interrupt detected\n");
+		envctrl_fan_fail_service(unitp);
+
+		/*
+		 * Clear the interrupt latches
+		 */
+		envctrl_intr_latch_clr(unitp);
+
+		ic = DDI_INTR_CLAIMED;
+	}
+
+	if (!(recv_data & EHC_PCF8574_PORT5)) {
+		DPRINTF1("Keyswitch interrupt detected\n");
+		(void) envctrl_get_fpm_status(unitp, (uint8_t *)NULL);
+		ic = DDI_INTR_CLAIMED;
+	}
+
+	if (!(recv_data & EHC_PCF8574_PORT6)) {
+		DPRINTF1("Power supply interrupt detected\n");
+		envctrl_PS_intr_service(unitp);
+		ic = DDI_INTR_CLAIMED;
+	}
+
+	if (!(recv_data & EHC_PCF8574_PORT7)) {
+		ic = DDI_INTR_CLAIMED;
+	}
+
+	/*
+	 * The interrupt routine got called but the interrupt chip
+	 * shows no interrupt present. If this happens more than 256
+	 * times in a row, there is probably some hardware problem so
+	 * send a warning message to the console.
+	 */
+	if ((recv_data == 0xFF)) {
+		if (spurious_intr_count == 255)
+			cmn_err(CE_WARN,
+				"%s%d: Received 256 spurious interrupts\n",
+					driver_name, unitp->instance);
+		spurious_intr_count++;
+		ic = DDI_INTR_CLAIMED;
+	} else
+		spurious_intr_count = 0;
+
+	mutex_exit(&unitp->umutex);
+	return (ic);
+
+}
+
+
+static int
+envctrl_read_chip(struct envctrlunit *unitp, int type, int chip_num, int port,
+	uint8_t *data, int num)
+{
+	int retrys = 0, autoincr = 0;
+	int status;
+
+	/*
+	 * If more than one read is requested, set auto-increment bit
+	 */
+	if (num > 1)
+		autoincr = 1;
+
+	do {
+		if (type == ENVCTRL_PCF8574A) {
+			status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
+				ENVCTRL_UE250_PCF8574A_BASE_ADDR | chip_num,
+				data, num);
+		} else if (type == ENVCTRL_PCF8574) {
+			status = ehc_read_pcf8574((struct ehc_envcunit *)unitp,
+				ENVCTRL_UE250_PCF8574_BASE_ADDR | chip_num,
+				data, num);
+		} else if (type == ENVCTRL_PCF8591) {
+			status = ehc_read_pcf8591((struct ehc_envcunit *)unitp,
+				ENVCTRL_UE250_PCF8591_BASE_ADDR | chip_num,
+				port, autoincr, 0, 1, data, num);
+		}
+		/*
+		 * If the bus hangs, attempt a recovery
+		 */
+		if (status == DDI_FAILURE) {
+			drv_usecwait(1000);
+			if (retrys < envctrl_max_retries) {
+				retrys++;
+			} else {
+				ehc_init_pcf8584((struct ehc_envcunit *)unitp);
+				break;
+			}
+		}
+	} while (status != DDI_SUCCESS);
+
+	return (status);
+}
+
+static int
+envctrl_write_chip(struct envctrlunit *unitp, int type, int chip_num, int port,
+	uint8_t *data, int num)
+{
+	int retrys = 0, autoincr = 0;
+	int status;
+
+	/*
+	 * Incase some applications mistakenly include the chips base addr
+	 */
+	chip_num = chip_num & 0xF;
+
+	/*
+	 * If more than one write is requested, set auto-increment bit
+	 */
+	if (num > 1)
+		autoincr = 1;
+
+	do {
+		if (type == ENVCTRL_PCF8574A) {
+			status = ehc_write_pcf8574a(
+				(struct ehc_envcunit *)unitp,
+				ENVCTRL_UE250_PCF8574A_BASE_ADDR | chip_num,
+				data, num);
+		} else if (type == ENVCTRL_PCF8574) {
+			status = ehc_write_pcf8574((struct ehc_envcunit *)unitp,
+				ENVCTRL_UE250_PCF8574_BASE_ADDR | chip_num,
+				data, num);
+		} else if (type == ENVCTRL_PCF8591) {
+			status = ehc_write_pcf8591((struct ehc_envcunit *)unitp,
+				ENVCTRL_UE250_PCF8591_BASE_ADDR | chip_num,
+				port, autoincr, 0, 1, data, num);
+		}
+
+		/*
+		 * If the bus hangs, attempt a recovery
+		 */
+		if (status == DDI_FAILURE) {
+			drv_usecwait(1000);
+			if (retrys < envctrl_max_retries) {
+				retrys++;
+			} else {
+				ehc_init_pcf8584((struct ehc_envcunit *)unitp);
+				break;
+			}
+		}
+	} while (status != DDI_SUCCESS);
+
+	return (status);
+}
+
+#ifdef GET_CPU_TEMP
+static int
+envctrl_get_cpu_temp(struct envctrlunit *unitp, int cpunum)
+{
+	uint8_t recv_data;
+	int status;
+
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	/*
+	 * This routine takes in the number of the port that
+	 * we want to read in the 8591. This should be the
+	 * location of the CPU thermistor for one of the 2
+	 * cpu's. It will return a normalized value
+	 * to the caller.
+	 */
+
+	status = envctrl_read_chip(unitp, ENVCTRL_PCF8591, EHC_DEV7, cpunum,
+			&recv_data, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: CPU TEMP read failed\n",
+			driver_name, unitp->instance);
+		return (ENVCTRL_UE250_MAX_CPU_TEMP - 10);
+	}
+
+	return (_cpu_temps[recv_data]);
+}
+#endif
+
+static void
+envctrl_tempr_poll(void *arg)
+{
+	int diag_flag = 0, status;
+	struct envctrlunit *unitp = (struct envctrlunit *)arg;
+
+	mutex_enter(&unitp->umutex);
+
+	if (unitp->shutdown == B_TRUE) {
+		(void) power_down("Fatal System Environmental Control Error");
+	}
+
+	/*
+	 * Clear the interrupt latches
+	 */
+	envctrl_intr_latch_clr(unitp);
+
+	envctrl_reset_dflop(unitp);
+	envctrl_enable_devintrs(unitp);
+	/*
+	 * if we are in diag mode and the temp poll thread goes off,
+	 * this means that the system is too heavily loaded and the 60 second
+	 * window to execute the test is failing.
+	 */
+	if (unitp->current_mode == ENVCTRL_DIAG_MODE) {
+		diag_flag++;
+		if (envctrl_debug_flags) {
+			cmn_err(CE_WARN, "%s%d: "
+			    "Tempr poll went off while in DIAG MODE\n",
+				driver_name, unitp->instance);
+		}
+	}
+	unitp->current_mode = ENVCTRL_NORMAL_MODE;
+	DPRINTF1("envctrl_tempr_poll(): Checking system temps\n");
+	status = envctrl_check_sys_temperatures(unitp);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN,
+			"%s%d: Failure detected during temperature poll",
+			driver_name, unitp->instance);
+	}
+
+	if (diag_flag == 0) {
+		envctrl_fan_fail_service(unitp);
+	}
+
+	/* Turn of the power fault LED if ps_ok is asserted */
+	envctrl_ps_probe(unitp);
+
+	/* now have this thread sleep for a while */
+	if ((unitp->fan_failed == B_TRUE) || (unitp->tempr_warning == B_TRUE)) {
+		/*
+		 * A thermal warning or fan failure condition exists.
+		 * Temperature poll thread will run every 10 seconds.
+		 */
+		if (unitp->timeout_id != 0)
+			(void) untimeout(unitp->timeout_id);
+		unitp->timeout_id = (timeout(envctrl_tempr_poll,
+			(caddr_t)unitp, warning_timeout_hz));
+	} else {
+		/*
+		 * No thermal warning or fan failure condition exists.
+		 * This thread is set to run every 60 seconds.
+		 */
+		unitp->timeout_id = (timeout(envctrl_tempr_poll,
+			(caddr_t)unitp, overtemp_timeout_hz));
+	}
+
+	mutex_exit(&unitp->umutex);
+}
+
+static void
+envctrl_led_blink(void *arg)
+{
+	uint8_t val, tmpval;
+	int status;
+	struct envctrlunit *unitp = (struct envctrlunit *)arg;
+
+	mutex_enter(&unitp->umutex);
+
+	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
+		0, &val, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Failed to read FSP LEDs",
+			driver_name, unitp->instance);
+		/* now have this thread sleep for a while */
+		unitp->blink_timeout_id = (timeout(envctrl_led_blink,
+			(caddr_t)unitp, blink_timeout_hz));
+		mutex_exit(&unitp->umutex);
+		return;
+	}
+
+	if (unitp->present_led_state == B_TRUE) {
+		/*
+		 * Now we need to "or" in fault bits of the FSP
+		 * module for the mass storage fault led.
+		 * and set it.
+		 */
+		val = (val & ~(EHC_PCF8574_PORT4) | JAV_FSP_MASK);
+		unitp->present_led_state = B_FALSE;
+	} else {
+		val = (val | EHC_PCF8574_PORT4 | JAV_FSP_MASK);
+		unitp->present_led_state = B_TRUE;
+	}
+
+	/*
+	 * A static global variable, power_flt_led_lit, is used to keep
+	 * track of periods when the software has lit the power fault LED.
+	 * Whenever the power fault LED is lit and this variable is not set,
+	 * then the power fault LED has been lit by hardware. In this case
+	 * mask out the power fault LED in the byte. This is a fix for
+	 * bug 4144872.
+	 */
+	tmpval = ~val;
+	if (tmpval & ENVCTRL_UE250_FSP_PS_ERR) {
+		if (power_flt_led_lit == 0) {
+			/*
+			 * Turn off power fault bit in the FSP byte.
+			 */
+			tmpval &= ~(ENVCTRL_UE250_FSP_PS_ERR);
+		}
+	}
+	val = ~tmpval;
+
+	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
+		0, &val, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Failed to blink activity LED",
+			driver_name, unitp->instance);
+		/* now have this thread sleep for a while */
+		unitp->blink_timeout_id = (timeout(envctrl_led_blink,
+			(caddr_t)unitp, blink_timeout_hz));
+		mutex_exit(&unitp->umutex);
+		return;
+	}
+
+	/* now have this thread sleep for a while */
+	unitp->blink_timeout_id = (timeout(envctrl_led_blink,
+	    (caddr_t)unitp, blink_timeout_hz));
+
+	mutex_exit(&unitp->umutex);
+}
+
+static int
+envctrl_check_sys_temperatures(struct envctrlunit *unitp)
+{
+	uint8_t buf[8];
+	enum levels warning_level, level;
+	uint8_t fspval;
+	int status, warning_count = 0;
+
+retrytemp1:
+	status = envctrl_read_chip(unitp, ENVCTRL_PCF8591, EHC_DEV2,
+		0, buf, 4);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Temperature read failed (PDB)",
+			driver_name, unitp->instance);
+		return (status);
+	}
+
+	warning_level = envctrl_check_tempr_levels(unitp, EHC_DEV2,
+				buf, warning_count);
+	level = warning_level;
+
+	if (warning_level != green) {
+		if (warning_count == 0) {
+			warning_count++;
+			drv_usecwait(1000);
+			goto retrytemp1;
+		}
+		if (warning_level == yellow)
+			unitp->tempr_warning = B_TRUE;
+		else if (warning_level == red) {
+				unitp->tempr_warning = B_TRUE;
+				if (!envctrl_power_off_overide)
+					unitp->shutdown = B_TRUE;
+		}
+	}
+
+	warning_count = 0;
+retrytemp2:
+	status = envctrl_read_chip(unitp, ENVCTRL_PCF8591, EHC_DEV7,
+		0, buf+4, 4);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Temperature read failed (MBD)",
+			driver_name, unitp->instance);
+		return (status);
+	}
+
+	warning_level = envctrl_check_tempr_levels(unitp, EHC_DEV7,
+				buf+4, warning_count);
+
+	if (warning_level != green) {
+		if (warning_count == 0) {
+			warning_count++;
+			drv_usecwait(1000);
+			goto retrytemp2;
+		}
+		if ((warning_level == yellow) && (unitp->shutdown == B_FALSE))
+			unitp->tempr_warning = B_TRUE;
+		else if (warning_level == red) {
+				unitp->tempr_warning = B_TRUE;
+				if (!envctrl_power_off_overide)
+					unitp->shutdown = B_TRUE;
+		}
+	} else if ((level == green) && (unitp->tempr_warning == B_TRUE)) {
+		/*
+		 * Current tempr. poll shows all levels normal.
+		 * If the previous poll showed warning levels, we need
+		 * to clear that status
+		 */
+		cmn_err(CE_NOTE,
+		"TEMPERATURE NORMAL: all sensors back to normal readings");
+		unitp->tempr_warning = B_FALSE;
+	}
+
+	status = envctrl_get_fpm_status(unitp, &fspval);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN,
+			"%s%d: Read of Front Status Panel LEDs failed",
+			driver_name, unitp->instance);
+	}
+
+	if ((unitp->tempr_warning == B_TRUE) || (unitp->shutdown == B_TRUE))
+		fspval |= (ENVCTRL_UE250_FSP_TEMP_ERR |
+				ENVCTRL_UE250_FSP_GEN_ERR);
+	else {
+		if (envctrl_isother_fault_led(unitp, fspval,
+			ENVCTRL_UE250_FSP_TEMP_ERR)) {
+			fspval &= ~(ENVCTRL_UE250_FSP_TEMP_ERR);
+		} else {
+			fspval &= ~(ENVCTRL_UE250_FSP_TEMP_ERR |
+					ENVCTRL_UE250_FSP_GEN_ERR);
+		}
+	}
+	status = envctrl_set_fsp(unitp, &fspval);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN,
+			"%s%d: Setting of Front Status Panel LEDs failed",
+			driver_name, unitp->instance);
+	}
+
+	/*
+	 * Have this thread run again in about 10 seconds
+	 */
+	if (unitp->tempr_warning == B_TRUE) {
+		if (unitp->timeout_id != 0) {
+			(void) untimeout(unitp->timeout_id);
+			unitp->timeout_id = (timeout(envctrl_tempr_poll,
+			(caddr_t)unitp, warning_timeout_hz));
+		}
+	}
+
+	return (status);
+}
+
+static int
+envctrl_check_tempr_levels(struct envctrlunit *unitp, int chip_num,
+	uint8_t *data, int count)
+{
+	uint_t temp_degree_c;
+	uint8_t buf[8];
+	enum levels warning_level = green;
+	int i, j;
+	int status;
+	uint8_t fanspeed;
+	int tval;
+
+	for (i = 0; i < 4; i++) {
+		if (chip_num == EHC_DEV2) {
+			if (i == 1) {
+				tval = ((int)data[i] * JAV_FAN_SPEED_SF_NUM) /
+					JAV_FAN_SPEED_SF_DEN;
+				if (tval > 255)
+					unitp->fan_kstats.fanspeed = 255;
+				else
+					unitp->fan_kstats.fanspeed = tval;
+				DPRINTF1("device %X, fan = %d %d\n", chip_num,
+					unitp->fan_kstats.fanspeed, data[i]);
+				continue;
+			} else if (i == 2)
+				continue;
+		}
+		if ((chip_num == EHC_DEV7) && ((i == ENVCTRL_UE250_CPU0_PORT) ||
+			(i == ENVCTRL_UE250_CPU1_PORT)))
+			if (unitp->cpu_pr_location[i] == B_FALSE)
+				continue;
+
+		j = 0;
+		while ((((t_addr[j] & 0xF) != chip_num) || (t_port[j] != i)) &&
+				(j < unitp->num_temps_present))
+			j++;
+		if ((chip_num == EHC_DEV7) && ((i == ENVCTRL_UE250_CPU0_PORT) ||
+			(i == ENVCTRL_UE250_CPU1_PORT)))
+			temp_degree_c = _cpu_temps[data[i]];
+		else
+			temp_degree_c = ((int)data[i] * t_scale_num[j]) /
+				t_scale_den[j];
+
+		/*
+		 * Javelin hardware will not control fan speeds based on
+		 * cpu temperature values because the voltages corresponding
+		 * to the cpu temperatures are based on an inverted scale
+		 * compared to the ambient temperatures and thus can be
+		 * fed to the same fan control circuit. As a result, it
+		 * has been decided that software will control fan speed
+		 * if cpu temperatures rise.
+		 */
+		if ((chip_num == EHC_DEV7) && ((i == ENVCTRL_UE250_CPU0_PORT) ||
+			(i == ENVCTRL_UE250_CPU1_PORT)) &&
+			(unitp->current_mode == ENVCTRL_NORMAL_MODE)) {
+			if (_cpu_fan_speeds[data[ENVCTRL_UE250_CPU0_PORT]] >
+				_cpu_fan_speeds[data[ENVCTRL_UE250_CPU1_PORT]])
+				fanspeed =
+				_cpu_fan_speeds[data[ENVCTRL_UE250_CPU0_PORT]];
+			else
+				fanspeed =
+				_cpu_fan_speeds[data[ENVCTRL_UE250_CPU1_PORT]];
+			status = envctrl_write_chip(unitp, ENVCTRL_PCF8591,
+				EHC_DEV2, 0, &fanspeed, 1);
+			if (status == DDI_FAILURE)
+				cmn_err(CE_WARN,
+				"%s%d: Write to PCF8591 (SETFAN) failed\n",
+				driver_name, unitp->instance);
+			status = envctrl_read_chip(unitp, ENVCTRL_PCF8591,
+				EHC_DEV2, 0, buf, 4);
+			if (status == DDI_FAILURE)
+				cmn_err(CE_WARN,
+					"%s%d: Fan speed read failed (PDB)",
+					driver_name, unitp->instance);
+			tval = ((int)buf[1] * JAV_FAN_SPEED_SF_NUM) /
+				JAV_FAN_SPEED_SF_DEN;
+			if (tval > 255)
+				unitp->fan_kstats.fanspeed = 255;
+			else
+				unitp->fan_kstats.fanspeed = tval;
+		}
+
+		DPRINTF1("device %X, temp = %d %d loc = %s\n", chip_num,
+			temp_degree_c, data[i], unitp->temp_kstats[j].label);
+
+		unitp->temp_kstats[j].value = temp_degree_c;
+		if ((temp_degree_c >=
+			unitp->temp_kstats[j].warning_threshold) ||
+			(temp_degree_c < unitp->temp_kstats[j].min)) {
+			if (warning_level < yellow)
+				warning_level = yellow;
+			if (count != 0)
+				cmn_err(CE_WARN,
+		"TEMPERATURE WARNING: %d degrees celsius at location %s",
+				temp_degree_c, unitp->temp_kstats[j].label);
+		}
+		if (temp_degree_c >=
+			unitp->temp_kstats[j].shutdown_threshold) {
+			if (warning_level < red)
+				warning_level = red;
+			if (count != 0) {
+				cmn_err(CE_WARN,
+		"TEMPERATURE CRITICAL: %d degrees celsius at location %s",
+				temp_degree_c, unitp->temp_kstats[j].label);
+				if (!envctrl_power_off_overide)
+					cmn_err(CE_WARN,
+					"System shutdown in 10 seconds ...");
+			}
+		}
+	}
+	return (warning_level);
+}
+
+static void
+envctrl_update_fanspeed(struct envctrlunit *unitp)
+{
+	uint8_t buf[8];
+	int tval;
+	int status;
+
+	status = envctrl_read_chip(unitp, ENVCTRL_PCF8591, EHC_DEV2,
+		0, buf, 4);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Fan speed read failed ",
+			driver_name, unitp->instance);
+	}
+
+	tval = ((int)buf[ENVCTRL_PORT1] * JAV_FAN_SPEED_SF_NUM) /
+		JAV_FAN_SPEED_SF_DEN;
+	if (tval > 255)
+		unitp->fan_kstats.fanspeed = 255;
+	else
+		unitp->fan_kstats.fanspeed = tval;
+}
+
+/* called with mutex held */
+static void
+envctrl_fan_fail_service(struct envctrlunit *unitp)
+{
+	uint8_t recv_data, fpmstat;
+	int retrys = 0;
+	int status;
+
+	/*
+	 * The fan fail interrupt is read from address 0x70
+	 * on the envctrl bus.
+	 */
+
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	/*
+	 * Clear the interrupt latches to handle spurious interrupts
+	 */
+	envctrl_intr_latch_clr(unitp);
+
+	do {
+		status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
+			ENVCTRL_UE250_PCF8574A_BASE_ADDR | EHC_DEV0,
+			&recv_data, 1);
+		/*
+		 * This extra read is needed since the first read is discarded
+		 * and the second read seems to return 0xFF.
+		 */
+		if (recv_data == 0xFF) {
+			status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
+				ENVCTRL_UE250_PCF8574A_BASE_ADDR | EHC_DEV0,
+				&recv_data, 1);
+		}
+
+		if (status == DDI_FAILURE) {
+			drv_usecwait(1000);
+			if (retrys < envctrl_max_retries) {
+				retrys++;
+			} else {
+				cmn_err(CE_WARN,
+				"%s%d: Read of PCF8574A (INTFAN) failed",
+					driver_name, unitp->instance);
+				ehc_init_pcf8584((struct ehc_envcunit *)unitp);
+				return;
+			}
+		}
+	} while (status != DDI_SUCCESS);
+
+	/* If the fan fail interrupt is now absent */
+	if (recv_data & EHC_PCF8574_PORT4) {
+		if (unitp->fan_failed == B_TRUE) {
+			if (unitp->current_mode == ENVCTRL_NORMAL_MODE)
+				cmn_err(CE_CONT,
+					"Fan failure has been cleared\n");
+			unitp->fan_kstats.fans_ok = B_TRUE;
+			/*
+			 * Clear general fault LED if no other faults
+			 */
+			status = envctrl_get_fpm_status(unitp, &fpmstat);
+			if (status == DDI_FAILURE) {
+				cmn_err(CE_WARN,
+				"%s%d: Read of Front Status Panel LEDs failed",
+				driver_name, unitp->instance);
+			}
+			if (!(envctrl_isother_fault_led(unitp, fpmstat, 0))) {
+				fpmstat &= ~(ENVCTRL_UE250_FSP_GEN_ERR);
+			}
+			if (unitp->shutdown != B_TRUE) {
+				status = envctrl_set_fsp(unitp, &fpmstat);
+				if (status == DDI_FAILURE) {
+					cmn_err(CE_WARN, "%s%d: "
+				"Setting of Front Status Panel LEDs failed",
+					driver_name, unitp->instance);
+				}
+			}
+			/*
+			 * This should be set after envctrl_isother_fault_led()
+			 * is called
+			 */
+			unitp->fan_failed = B_FALSE;
+		}
+	} else {
+		if (unitp->fan_failed == B_FALSE) {
+			if (unitp->current_mode == ENVCTRL_NORMAL_MODE)
+				cmn_err(CE_WARN,
+					"Fan failure has been detected");
+			unitp->fan_failed = B_TRUE;
+			unitp->fan_kstats.fans_ok = B_FALSE;
+			/*
+			 * Set general fault LED
+			 */
+			status = envctrl_get_fpm_status(unitp, &fpmstat);
+			if (status == DDI_FAILURE) {
+				cmn_err(CE_WARN,
+				"%s%d: Read of Front Status Panel LEDs failed",
+				driver_name, unitp->instance);
+				return;
+			}
+			fpmstat |= ENVCTRL_UE250_FSP_GEN_ERR;
+			status = envctrl_set_fsp(unitp, &fpmstat);
+			if (status == DDI_FAILURE) {
+				cmn_err(CE_WARN, "%s%d: "
+				"Setting of Front Status Panel LEDs failed",
+				driver_name, unitp->instance);
+			}
+			/*
+			 * A fan failure condition exists.
+			 * Temperature poll thread should run every 10 seconds.
+			 */
+			if (unitp->timeout_id != 0) {
+				(void) untimeout(unitp->timeout_id);
+				unitp->timeout_id = (timeout(envctrl_tempr_poll,
+				(caddr_t)unitp, warning_timeout_hz));
+			}
+		}
+	}
+}
+
+/*
+ * Check for power supply insertion and failure.
+ * This is a bit tricky, because a power supply insertion will
+ * cause the ps_ok line to go active as well as PS present in the
+ * new supply. If we detect an insertion clear
+ * interrupts, disable interrupts, wait for a couple of seconds
+ * come back and see if the PSOK bit is set, PS_PRESENT is set
+ * and the share fail interrupts are gone. If not this is a
+ * real load share fail event.
+ * Called with mutex held
+ */
+
+static void
+envctrl_PS_intr_service(struct envctrlunit *unitp)
+{
+
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	if (unitp->current_mode == ENVCTRL_DIAG_MODE) {
+		return;
+	}
+
+	/*
+	 * setup a timeout thread to poll the ps after a
+	 * couple of seconds. This allows for the PS to settle
+	 * and doesn't report false errors on a hotplug
+	 */
+
+	unitp->pshotplug_id = (timeout(envctrl_pshotplug_poll,
+	    (caddr_t)unitp, pshotplug_timeout_hz));
+
+}
+
+static void
+envctrl_init_bus(struct envctrlunit *unitp)
+{
+	ehc_init_pcf8584((struct ehc_envcunit *)unitp);
+
+	/*
+	 * Clear the interrupt latches
+	 */
+	envctrl_intr_latch_clr(unitp);
+
+	envctrl_reset_dflop(unitp);
+
+	envctrl_enable_devintrs(unitp);
+}
+
+/* called with mutex held */
+static void
+envctrl_reset_dflop(struct envctrlunit *unitp)
+{
+	int status;
+	uint8_t value;
+
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	value = ENVCTRL_UE250_DFLOP_INIT0;
+	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
+		0, &value, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (DFLOP_INIT0) failed",
+			driver_name, unitp->instance);
+	}
+
+	value = ENVCTRL_UE250_DFLOP_INIT1;
+	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
+		0, &value, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (DFLOP_INIT1) failed",
+			driver_name, unitp->instance);
+	}
+}
+
+/* called with mutex held */
+static void
+envctrl_enable_devintrs(struct envctrlunit *unitp)
+{
+	int status;
+	uint8_t value;
+
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	value = ENVCTRL_UE250_DEVINTR_INIT0;
+	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
+		0, &value, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (INTR_INIT0) failed",
+			driver_name, unitp->instance);
+	}
+
+	value = ENVCTRL_UE250_DEVINTR_INIT1;
+	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
+		0, &value, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (INTR_INIT1) failed",
+			driver_name, unitp->instance);
+	}
+}
+
+static void
+envctrl_intr_latch_clr(struct envctrlunit *unitp)
+{
+	int status;
+	uint8_t value;
+
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	value = ENVCTRL_UE250_INTR_LATCH_INIT0;
+	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
+		0, &value, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (INTR_LATCH0) failed",
+			driver_name, unitp->instance);
+	}
+
+	value = ENVCTRL_UE250_INTR_LATCH_INIT1;
+	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
+		0, &value, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (INTR_LATCH1) failed",
+			driver_name, unitp->instance);
+	}
+}
+
+/* Called with unitp mutex held */
+static void
+envctrl_ps_probe(struct envctrlunit *unitp)
+{
+
+	uint8_t recv_data, fpmstat;
+	int i, j;
+	int ps_error = 0, ps_present_port, power_ok_port;
+	int status;
+
+
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	unitp->num_ps_present = 0;
+
+	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV1,
+		0, &recv_data, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Read of PCF8574 (PS) failed",
+			driver_name, unitp->instance);
+		return;
+	}
+
+	for (i = 0, j = 0; i < ENVCTRL_UE250_MAXPS; i++) {
+		unitp->ps_kstats[i].slot = -1;
+
+		/*
+		 * Port 0 = PS0 Present
+		 * Port 1 = PS1 Present
+		 * Port 2 = SPARE
+		 * Port 3 = SPARE
+		 * Port 4 = PS0 OK
+		 * Port 5 = PS1 OK
+		 * Port 6 = SPARE
+		 * Port 7 = SPARE
+		 */
+
+		/*
+		 * Port 0 = PS Present
+		 * Port is pulled LOW "0" to indicate
+		 * present.
+		 */
+
+		switch (i) {
+		case 0:
+			ps_present_port = EHC_PCF8574_PORT0;
+			power_ok_port = EHC_PCF8574_PORT4;
+			break;
+		case 1:
+			ps_present_port = EHC_PCF8574_PORT1;
+			power_ok_port = EHC_PCF8574_PORT5;
+			break;
+		}
+
+		if (!(recv_data & ps_present_port)) {
+			/* update unit kstat array */
+			unitp->ps_kstats[j].slot = i;
+			++unitp->num_ps_present;
+
+			if (pspr[i] == 0) {
+				cmn_err(CE_NOTE,
+					"Power Supply %d inserted\n", i);
+			}
+			pspr[i] = 1;
+
+			if (!(recv_data & power_ok_port)) {
+				cmn_err(CE_WARN,
+				    "Power Supply %d NOT okay\n", i);
+				unitp->ps_kstats[j].ps_ok = B_FALSE;
+				ps_error++;
+				psok[i] = 0;
+			} else {
+				unitp->ps_kstats[j].ps_ok = B_TRUE;
+				if (psok[i] == 0)
+					cmn_err(CE_NOTE,
+						"Power Supply %d okay\n", i);
+				psok[i] = 1;
+			}
+
+			if (!(recv_data & EHC_PCF8574_PORT2)) {
+				cmn_err(CE_WARN,
+				    "PS %d Shouln't interrupt\n", i);
+				ps_error++;
+			}
+
+			if (!(recv_data & EHC_PCF8574_PORT3)) {
+				cmn_err(CE_WARN,
+				    "PS %d Shouln't interrupt\n", i);
+				ps_error++;
+			}
+
+			if (!(recv_data & EHC_PCF8574_PORT6)) {
+				cmn_err(CE_WARN,
+				    "PS %d Shouln't interrupt\n", i);
+				ps_error++;
+			}
+
+			if (!(recv_data & EHC_PCF8574_PORT7)) {
+				cmn_err(CE_WARN,
+				    "PS %d Shouln't interrupt\n", i);
+				ps_error++;
+			}
+			j++;
+		} else {
+			if (pspr[i] == 1) {
+				cmn_err(CE_NOTE,
+					"Power Supply %d removed\n", i);
+			}
+			pspr[i] = 0;
+		}
+	}
+
+	status = envctrl_get_fpm_status(unitp, &fpmstat);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Read of Front Status Panel LEDs failed",
+			driver_name, unitp->instance);
+	}
+	if (ps_error) {
+		fpmstat |= (ENVCTRL_UE250_FSP_PS_ERR |
+				ENVCTRL_UE250_FSP_GEN_ERR);
+	} else {
+		if (envctrl_isother_fault_led(unitp, fpmstat,
+			ENVCTRL_UE250_FSP_PS_ERR)) {
+			fpmstat &= ~(ENVCTRL_UE250_FSP_PS_ERR);
+		} else {
+			fpmstat &= ~(ENVCTRL_UE250_FSP_PS_ERR |
+			    ENVCTRL_UE250_FSP_GEN_ERR);
+		}
+	}
+	status = envctrl_set_fsp(unitp, &fpmstat);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN,
+			"%s%d: Setting of Front Status Panel LEDs failed",
+			driver_name, unitp->instance);
+	}
+
+	if (ps_error) {
+		power_flt_led_lit = 1;
+	} else {
+		power_flt_led_lit = 0;
+	}
+}
+
+/*
+ * consider key switch position when handling an abort sequence
+ */
+static void
+envctrl_abort_seq_handler(char *msg)
+{
+	struct envctrlunit *unitp;
+	int i;
+	uint8_t secure = 0;
+
+	/*
+	 * Find the instance of the device available on this host.
+	 * Note that there may be only one, but the instance may
+	 * not be zero.
+	 */
+	for (i = 0; i < MAX_DEVS; i++) {
+		if (unitp = (struct envctrlunit *)
+				ddi_get_soft_state(envctrlsoft_statep, i))
+			break;
+	}
+
+	ASSERT(unitp);
+
+	secure = unitp->encl_kstats.value;
+
+	if ((secure & ENVCTRL_UE250_FSP_KEYMASK) ==
+		ENVCTRL_UE250_FSP_KEYLOCKED) {
+			cmn_err(CE_CONT,
+				"%s%d: ignoring debug enter sequence\n",
+				driver_name, unitp->instance);
+	} else {
+		if (envctrl_debug_flags) {
+			cmn_err(CE_CONT, "%s%d: allowing debug enter\n",
+				driver_name, unitp->instance);
+		}
+		debug_enter(msg);
+	}
+}
+
+/*
+ * get the front Panel module LED and keyswitch status.
+ * this part is addressed at 0x7C on the i2c bus.
+ * called with mutex held
+ */
+static int
+envctrl_get_fpm_status(struct envctrlunit *unitp, uint8_t *val)
+{
+	uint8_t recv_data;
+	int status;
+
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
+		0, &recv_data, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Read from PCF8574A (FSP) failed",
+			driver_name, unitp->instance);
+		return (status);
+	}
+
+	recv_data = ~recv_data;
+	if (val != (uint8_t *)NULL)
+		*val = recv_data;
+
+	/* Update kstats */
+	unitp->encl_kstats.value = recv_data;
+
+	return (status);
+}
+
+static int
+envctrl_set_fsp(struct envctrlunit *unitp, uint8_t *val)
+{
+	uint8_t value;
+	int status = DDI_SUCCESS;
+	uint8_t confirm_val = 0, confirm_val_hold;
+	int confirm_count = 0, confirm_max = 20;
+
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	value = ENVCTRL_UE250_FSP_OFF; /* init all values to off */
+
+	/*
+	 * strip off bits that are R/O
+	 */
+	value = (~(ENVCTRL_UE250_FSP_KEYMASK | ENVCTRL_UE250_FSP_POMASK) &
+			(*val));
+
+	confirm_val_hold = value;
+
+	value = ~value;
+
+	while (confirm_count < confirm_max) {
+		status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
+			0, &value, 1);
+		if (status == DDI_FAILURE) {
+			cmn_err(CE_WARN, "%s%d: Write to PCF8574A (FSP) failed",
+				driver_name, unitp->instance);
+			break;
+		} else {
+			/*
+			 * Sometimes the i2c hardware status is not
+			 * completely dependable as far as reporting
+			 * a condition where the set does not take
+			 * place. So we read back the set value to
+			 * confirm what we set.
+			 */
+			status = envctrl_get_fpm_status(unitp, &confirm_val);
+			confirm_val = ~(ENVCTRL_UE250_FSP_KEYMASK |
+				ENVCTRL_UE250_FSP_POMASK) & confirm_val;
+			if (status == DDI_FAILURE) {
+				cmn_err(CE_WARN,
+				"%s%d: Read of PCF8574A (FSP) failed",
+					driver_name, unitp->instance);
+				break;
+			} else if (confirm_val != confirm_val_hold) {
+				confirm_count++;
+				drv_usecwait(1000);
+				continue;
+			} else
+				/*
+				 * Set was confirmed.
+				 */
+				break;
+		}
+	}
+
+	if (confirm_count == confirm_max)
+		status = DDI_FAILURE;
+
+	return (status);
+
+}
+
+static int
+envctrl_get_dskled(struct envctrlunit *unitp, struct envctrl_chip *chip)
+{
+	int status;
+
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	if (chip->chip_num != EHC_DEV7 ||
+		chip->type != ENVCTRL_PCF8574A) {
+		return (DDI_FAILURE);
+	}
+
+	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV7,
+		0, &chip->val, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (DISKFL) failed",
+			driver_name, unitp->instance);
+	}
+	chip->val = ~chip->val;
+
+	return (status);
+}
+
+static int
+envctrl_set_dskled(struct envctrlunit *unitp, struct envctrl_chip *chip)
+{
+	uint8_t val;
+	int status;
+	struct envctrl_chip confirm_chip;
+	uint8_t confirm_val_hold;
+	int confirm_count = 0, confirm_max = 20;
+
+	/*
+	 * We need to check the type of disk led being set. If it
+	 * is a 4 slot backplane then the upper 4 bits (7, 6, 5, 4) are
+	 * invalid.
+	 */
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+
+	if (chip->chip_num != EHC_DEV7)
+		return (DDI_FAILURE);
+
+	if (chip->type != ENVCTRL_PCF8574A)
+		return (DDI_FAILURE);
+
+	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
+		0, &val, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (FSP) failed",
+			driver_name, unitp->instance);
+		return (status);
+	}
+
+	val = ~val;
+	if ((chip->val & 0x3F) == 0) {
+		if (!(envctrl_isother_fault_led(unitp, val,
+			ENVCTRL_UE250_FSP_DISK_ERR))) {
+			val &= ~(ENVCTRL_UE250_FSP_DISK_ERR);
+		} else {
+			val &= ~(ENVCTRL_UE250_FSP_DISK_ERR |
+			    ENVCTRL_UE250_FSP_GEN_ERR);
+		}
+		val = (val & ~(ENVCTRL_UE250_FSP_DISK_ERR |
+			ENVCTRL_UE250_FSP_GEN_ERR));
+	} else {
+		val = (val | (ENVCTRL_UE250_FSP_DISK_ERR |
+			ENVCTRL_UE250_FSP_GEN_ERR));
+	}
+
+	status = envctrl_set_fsp(unitp, &val);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (FSP) failed",
+			driver_name, unitp->instance);
+		return (status);
+	}
+
+
+	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV5,
+		0, &val, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (DISKFL) failed",
+			driver_name, unitp->instance);
+		return (status);
+	}
+
+	envctrl_update_disk_kstats(unitp, val, ~(chip->val));
+
+	/*
+	 * we take the ones compliment of the val passed in
+	 * because the hardware thinks that a "low" or "0"
+	 * is the way to indicate a fault. of course software
+	 * knows that a 1 is a TRUE state or fault. ;-)
+	 */
+
+	confirm_val_hold = chip->val;
+
+	chip->val = ~(chip->val);
+
+	while (confirm_count < confirm_max) {
+		status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV7,
+			0, &chip->val, 1);
+		if (status == DDI_FAILURE) {
+			cmn_err(CE_WARN, "%s%d: Write PCF8574A (DISKFL) failed",
+				driver_name, unitp->instance);
+			return (status);
+		} else {
+			/*
+			 * Sometimes the i2c hardware status is not
+			 * completely dependable as far as reporting
+			 * a condition where the set does not take
+			 * place. So we read back the set value to
+			 * confirm what we set.
+			 */
+			confirm_chip.type = chip->type;
+			confirm_chip.chip_num = chip->chip_num;
+			confirm_chip.index = chip->index;
+			status = envctrl_get_dskled(unitp, &confirm_chip);
+			if (status != DDI_SUCCESS) {
+				return (status);
+			} else if (confirm_chip.val != confirm_val_hold) {
+				confirm_count++;
+				drv_usecwait(1000);
+				continue;
+			} else
+				/*
+				 * Set was confirmed.
+				 */
+				break;
+		}
+	}
+
+	if (confirm_count == confirm_max)
+		return (DDI_FAILURE);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * After setting the fan speed, we read back the fan speed to confirm
+ * that the new value is within an acceptable range, else we retry.
+ * We do not confirm the fan speed if the set value is below the
+ * hardware determined speed (based on system temeratures).
+ */
+static int
+envctrl_set_fanspeed(struct envctrlunit *unitp, struct envctrl_chip *fanspeed)
+{
+	int readback_speed, max_speed;
+	int status;
+	int confirm_count = 0, confirm_max = 20;
+	uint8_t fanspeed_hold;
+
+	fanspeed_hold = fanspeed->val;
+	while (confirm_count < confirm_max) {
+		status = envctrl_write_chip(unitp, ENVCTRL_PCF8591,
+			EHC_DEV2, 0, &fanspeed->val, 1);
+		if (status == DDI_FAILURE) {
+			envctrl_fan_fail_service(unitp);
+			cmn_err(CE_WARN,
+			"%s%d: Set fanspeed failed", driver_name,
+				unitp->instance);
+			return (status);
+		} else {
+			drv_usecwait(100000);
+			envctrl_update_fanspeed(unitp);
+			readback_speed = unitp->fan_kstats.fanspeed;
+			if (fanspeed_hold > idle_fanspeed) {
+				max_speed =
+				(fanspeed->val + FAN_DRIFT > MAX_FAN_SPEED) ?
+				MAX_FAN_SPEED : (fanspeed->val + FAN_DRIFT);
+				if ((readback_speed < fanspeed->val -
+					FAN_DRIFT) ||
+					(readback_speed > max_speed)) {
+					confirm_count++;
+					drv_usecwait(1000);
+					continue;
+				}
+			}
+			break;
+		}
+	}
+
+	if (confirm_count == confirm_max)
+		return (DDI_FAILURE);
+
+	return (DDI_SUCCESS);
+}
+
+static void
+envctrl_add_kstats(struct envctrlunit *unitp)
+{
+
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	if ((unitp->enclksp = kstat_create(ENVCTRL_MODULE_NAME, unitp->instance,
+	    ENVCTRL_KSTAT_ENCL, "misc", KSTAT_TYPE_RAW,
+	    sizeof (unitp->encl_kstats),
+	    KSTAT_FLAG_PERSISTENT)) == NULL) {
+		cmn_err(CE_WARN, "%s%d: encl raw kstat_create failed",
+			driver_name, unitp->instance);
+		return;
+	}
+
+	unitp->enclksp->ks_update = envctrl_encl_kstat_update;
+	unitp->enclksp->ks_private = (void *)unitp;
+	kstat_install(unitp->enclksp);
+
+
+	if ((unitp->fanksp = kstat_create(ENVCTRL_MODULE_NAME, unitp->instance,
+	    ENVCTRL_KSTAT_FANSTAT, "misc", KSTAT_TYPE_RAW,
+	    sizeof (unitp->fan_kstats),
+	    KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_WRITABLE)) == NULL) {
+		cmn_err(CE_WARN, "%s%d: fans kstat_create failed",
+			driver_name, unitp->instance);
+		return;
+	}
+
+	unitp->fanksp->ks_update = envctrl_fanstat_kstat_update;
+	unitp->fanksp->ks_private = (void *)unitp;
+	kstat_install(unitp->fanksp);
+
+	if ((unitp->psksp = kstat_create(ENVCTRL_MODULE_NAME, unitp->instance,
+	    ENVCTRL_KSTAT_PSNAME2, "misc", KSTAT_TYPE_RAW,
+	    sizeof (unitp->ps_kstats),
+	    KSTAT_FLAG_PERSISTENT)) == NULL) {
+		cmn_err(CE_WARN, "%s%d: ps name kstat_create failed",
+			driver_name, unitp->instance);
+		return;
+	}
+
+	unitp->psksp->ks_update = envctrl_ps_kstat_update;
+	unitp->psksp->ks_private = (void *)unitp;
+	kstat_install(unitp->psksp);
+
+	if ((unitp->tempksp = kstat_create(ENVCTRL_MODULE_NAME,
+	    unitp->instance, ENVCTRL_KSTAT_TEMPERATURE, "misc", KSTAT_TYPE_RAW,
+	    sizeof (unitp->temp_kstats),
+	    KSTAT_FLAG_PERSISTENT)) == NULL) {
+		cmn_err(CE_WARN, "%s%d: temp name kstat_create failed",
+			driver_name, unitp->instance);
+		return;
+	}
+
+	unitp->tempksp->ks_update = envctrl_temp_kstat_update;
+	unitp->tempksp->ks_private = (void *)unitp;
+	kstat_install(unitp->tempksp);
+
+	if ((unitp->diskksp = kstat_create(ENVCTRL_MODULE_NAME,
+	    unitp->instance, ENVCTRL_KSTAT_DISK, "misc", KSTAT_TYPE_RAW,
+	    sizeof (unitp->disk_kstats),
+	    KSTAT_FLAG_PERSISTENT)) == NULL) {
+		cmn_err(CE_WARN, "%s%d: disk name kstat_create failed",
+			driver_name, unitp->instance);
+		return;
+	}
+
+	unitp->diskksp->ks_update = envctrl_disk_kstat_update;
+	unitp->diskksp->ks_private = (void *)unitp;
+	kstat_install(unitp->diskksp);
+
+}
+
+static int
+envctrl_ps_kstat_update(kstat_t *ksp, int rw)
+{
+	struct envctrlunit *unitp;
+	char *kstatp;
+
+
+
+	unitp = (struct envctrlunit *)ksp->ks_private;
+
+	mutex_enter(&unitp->umutex);
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	kstatp = (char *)ksp->ks_data;
+
+	if (rw == KSTAT_WRITE) {
+		mutex_exit(&unitp->umutex);
+		return (EACCES);
+	} else {
+
+		unitp->psksp->ks_ndata = unitp->num_ps_present;
+		bcopy((caddr_t)&unitp->ps_kstats, kstatp,
+		    sizeof (unitp->ps_kstats));
+	}
+	mutex_exit(&unitp->umutex);
+	return (DDI_SUCCESS);
+}
+
+static int
+envctrl_fanstat_kstat_update(kstat_t *ksp, int rw)
+{
+	struct envctrlunit *unitp;
+	char *kstatp;
+
+	kstatp = (char *)ksp->ks_data;
+	unitp = (struct envctrlunit *)ksp->ks_private;
+
+	mutex_enter(&unitp->umutex);
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	if (rw == KSTAT_WRITE) {
+		mutex_exit(&unitp->umutex);
+		return (EACCES);
+	} else {
+		unitp->fanksp->ks_ndata = unitp->num_fans_present;
+		bcopy((caddr_t)&unitp->fan_kstats, kstatp,
+		    sizeof (unitp->fan_kstats));
+	}
+	mutex_exit(&unitp->umutex);
+	return (DDI_SUCCESS);
+}
+
+static int
+envctrl_encl_kstat_update(kstat_t *ksp, int rw)
+{
+	struct envctrlunit *unitp;
+	char *kstatp;
+	int status;
+
+
+	kstatp = (char *)ksp->ks_data;
+	unitp = (struct envctrlunit *)ksp->ks_private;
+
+	mutex_enter(&unitp->umutex);
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	if (rw == KSTAT_WRITE) {
+		mutex_exit(&unitp->umutex);
+		return (EACCES);
+	} else {
+
+		unitp->enclksp->ks_ndata = unitp->num_encl_present;
+		status = envctrl_get_fpm_status(unitp, (uint8_t *)NULL);
+		if (status == DDI_SUCCESS)
+			bcopy((caddr_t)&unitp->encl_kstats, kstatp,
+				sizeof (unitp->encl_kstats));
+	}
+	mutex_exit(&unitp->umutex);
+	return (DDI_SUCCESS);
+}
+
+static int
+envctrl_temp_kstat_update(kstat_t *ksp, int rw)
+{
+	struct envctrlunit *unitp;
+	char *kstatp;
+
+	kstatp = (char *)ksp->ks_data;
+	unitp = (struct envctrlunit *)ksp->ks_private;
+
+	mutex_enter(&unitp->umutex);
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	if (rw == KSTAT_WRITE) {
+		mutex_exit(&unitp->umutex);
+		return (EACCES);
+	} else {
+		unitp->tempksp->ks_ndata = unitp->num_temps_present;
+		bcopy((caddr_t)unitp->temp_kstats, kstatp,
+		    sizeof (unitp->temp_kstats));
+	}
+	mutex_exit(&unitp->umutex);
+	return (DDI_SUCCESS);
+}
+
+static int
+envctrl_disk_kstat_update(kstat_t *ksp, int rw)
+{
+	struct envctrlunit *unitp;
+	char *kstatp;
+
+	kstatp = (char *)ksp->ks_data;
+	unitp = (struct envctrlunit *)ksp->ks_private;
+
+	mutex_enter(&unitp->umutex);
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	if (rw == KSTAT_WRITE) {
+		mutex_exit(&unitp->umutex);
+		return (EACCES);
+	} else {
+		unitp->diskksp->ks_ndata = unitp->num_disks_present;
+		bcopy((caddr_t)unitp->disk_kstats, kstatp,
+		    sizeof (unitp->disk_kstats));
+	}
+	mutex_exit(&unitp->umutex);
+	return (DDI_SUCCESS);
+}
+
+static void
+envctrl_init_encl_kstats(struct envctrlunit *unitp)
+{
+	uint8_t val;
+	int status;
+
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
+		0, &val, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (FSP) failed",
+			driver_name, unitp->instance);
+		return;
+	}
+
+	unitp->encl_kstats.value = val;
+}
+
+static void
+envctrl_check_disk_kstats(struct envctrlunit *unitp)
+{
+	uint8_t diskpr, diskfl;
+	int status;
+
+	ASSERT(MUTEX_HELD(&unitp->umutex));
+
+	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV5,
+		0, &diskpr, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (DISKPR) failed",
+			driver_name, unitp->instance);
+	}
+
+	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV7,
+		0, &diskfl, 1);
+	if (status == DDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (DISKFL) failed",
+			driver_name, unitp->instance);
+	}
+
+	envctrl_update_disk_kstats(unitp, diskpr, diskfl);
+
+}
+
+static void
+envctrl_update_disk_kstats(struct envctrlunit *unitp, uint8_t diskpr,
+	uint8_t diskfl)
+{
+	int i, j, count = 0;
+
+	DPRINTF1("diskpr = %X, diskfl = %X\n", diskpr, diskfl);
+	for (i = 0, j = 1; i < ENVCTRL_UE250_MAX_DISKS; i++, j = j << 1) {
+		if (!(diskpr & j)) {
+			if (!(diskfl & j))
+				unitp->disk_kstats[count].disk_ok = 0;
+			else
+				unitp->disk_kstats[count].disk_ok = 1;
+			unitp->disk_kstats[count].slot = i;
+			count++;
+		}
+	}
+
+	unitp->num_disks_present = count;
+}
+
+static void
+envctrl_probe_cpus(struct envctrlunit *unitp)
+{
+	int instance;
+
+	/*
+	 * The cpu search is as follows:
+	 * If there is only 1 CPU module it is named as
+	 * SUNW,UltraSPARC. If this is a match we still don't
+	 * know what slot the cpu module is in therefore
+	 * we need to check the "upa-portid" property.
+	 * If we have more than 1 cpu, then they are appended by
+	 * instance numbers and slot locations. e.g.
+	 * SUNW,UltraSPARC@1,0 (slot 1). it would have been
+	 * nice to have the naming consistent for one CPU e.g.
+	 * SUNW,UltraSPARC@0,0...sigh
+	 */
+
+	for (instance = 0; instance < ENVCTRL_MAX_CPUS; instance++) {
+		unitp->cpu_pr_location[instance] = B_FALSE;
+	}
+
+	ddi_walk_devs(ddi_root_node(), envctrl_match_cpu, unitp);
+}
+
+static int
+envctrl_match_cpu(dev_info_t *dip, void *arg)
+{
+
+	int cpu_slot;
+	char name[32];
+	char name1[32];
+	struct envctrlunit *unitp = (struct envctrlunit *)arg;
+
+	(void) sprintf(name, "%s", ENVCTRL_ULTRA1CPU_STRING);
+	(void) sprintf(name1, "%s", ENVCTRL_ULTRA2CPU_STRING);
+
+	if ((strcmp(ddi_node_name(dip), name) == 0) ||
+		(strcmp(ddi_node_name(dip), name1) == 0)) {
+		if ((cpu_slot = (int)ddi_getprop(DDI_DEV_T_ANY, dip,
+			    DDI_PROP_DONTPASS, "upa-portid",
+				    -1)) == -1) {
+			cmn_err(CE_WARN, "%s%d: no cpu upa-portid",
+				driver_name, unitp->instance);
+		} else {
+			unitp->cpu_pr_location[cpu_slot] = B_TRUE;
+			unitp->num_cpus_present++;
+		}
+	}
+
+	return (DDI_WALK_CONTINUE);
+}
+
+/*
+ * This routine returns TRUE if some other error condition
+ * has set the GEN_ERR FAULT LED. Tp further complicate this
+ * LED panel we have overloaded the GEN_ERR LED to indicate
+ * that a fan fault has occurred without having a fan fault
+ * LED as does all other error conditions. So we just take the
+ * software state and return true. The whole purpose of this functon
+ * is to tell us wehther or not we can shut off the GEN_FAULT LED.
+ * NOTE: this ledval is usually one of the following FSP vals
+ * EXCEPT in the case of the fan fail.. we pass in a "0".
+ */
+
+static int
+envctrl_isother_fault_led(struct envctrlunit *unitp, uint8_t fspval,
+    uint8_t thisled)
+{
+	int status = B_FALSE;
+
+	if (fspval != 0) {
+		fspval = (fspval & ~(thisled));
+	}
+	if ((unitp->fan_failed == B_TRUE) && thisled != 0) {
+		status = B_TRUE;
+	} else if (fspval & ENVCTRL_UE250_FSP_DISK_ERR) {
+		status = B_TRUE;
+	} else if (fspval & ENVCTRL_UE250_FSP_PS_ERR) {
+		status = B_TRUE;
+	} else if (fspval & ENVCTRL_UE250_FSP_TEMP_ERR) {
+		status = B_TRUE;
+	}
+	return (status);
+}
+
+static void
+envctrl_pshotplug_poll(void *arg)
+{
+	struct envctrlunit *unitp = (struct envctrlunit *)arg;
+
+	mutex_enter(&unitp->umutex);
+
+	envctrl_ps_probe(unitp);
+
+	mutex_exit(&unitp->umutex);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/javelin/sys/envctrltwo.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,83 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 1997 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_JAV_ENVCTRLTWO_H
+#define	_JAV_ENVCTRLTWO_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#if defined(_KERNEL)
+
+struct envctrlunit {
+	struct envctrl_pcd8584_regs *bus_ctl_regs;
+	ddi_acc_handle_t ctlr_handle;
+	kmutex_t umutex;			/* lock for this structure */
+	int instance;
+	dev_info_t *dip;			/* device information */
+	struct envctrl_ps2 ps_kstats[ENVCTRL_MAX_DEVS];	/* kstats for ps */
+	struct envctrl_fan fan_kstats; 		/* kstats for fans */
+	struct envctrl_encl encl_kstats;		/* kstats for FSP */
+	struct envctrl_temp temp_kstats[ENVCTRL_MAX_DEVS]; /* tempreratures */
+	struct envctrl_disk disk_kstats[ENVCTRL_MAX_DEVS]; /* disks */
+	int cpu_pr_location[ENVCTRL_MAX_CPUS]; /* slot true if cpu present */
+	uint_t num_fans_present;
+	uint_t num_ps_present;
+	uint_t num_encl_present;
+	uint_t num_cpus_present;
+	uint_t num_temps_present;
+	uint_t num_disks_present;
+	kstat_t *psksp;
+	kstat_t *fanksp;
+	kstat_t *enclksp;
+	kstat_t *tempksp;
+	kstat_t *diskksp;
+	ddi_iblock_cookie_t ic_trap_cookie;	/* interrupt cookie */
+	/*  CPR support */
+	boolean_t suspended;			/* TRUE if driver suspended */
+	boolean_t oflag;			/*  already open */
+	int current_mode;			/* NORMAL or DIAG_MODE */
+	timeout_id_t timeout_id;				/* timeout id */
+	timeout_id_t pshotplug_id;			/* ps poll id */
+	int activity_led_blink;
+	int present_led_state; 			/* is it on or off?? */
+	timeout_id_t blink_timeout_id;
+	int initting; /* 1 is TRUE , 0 is FALSE , used to mask intrs */
+	boolean_t shutdown; /* TRUE = power off in error event */
+	boolean_t fan_failed; /* TRUE = fan failure detected */
+	boolean_t tempr_warning; /* TRUE = thermal warning detected */
+};
+
+#endif	/* _KERNEL */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _JAV_ENVCTRLTWO_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/lw2plus/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -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 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 sun4u lw2plus platform
+#	module.
+#
+#	sun4u implementation architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	  = ../..
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sun4u/lw2plus/Makefile.lw2plus
+
+def		:=	TARGET= def
+all		:=	TARGET= all
+install		:=	TARGET= install
+install_h	:=	TARGET= install_h
+clean		:=	TARGET= clean
+clobber		:=	TARGET= clobber
+lint		:=	TARGET= lint
+lintlib		:=	TARGET= lintlib
+modlintlib	:=	TARGET= modlintlib
+modlist		:=	TARGET= modlist
+modlist		:=	NO_STATE= -K $$MODSTATE$$$$
+clean.lint	:=	TARGET= clean.lint
+check		:=	TARGET= check
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def all clean clean.lint clobber modlist: $(LW2PLUS_KMODS)
+
+lintlib:	unix
+
+modlintlib:	$(LW2PLUS_KMODS)
+
+IMPLEMENTED_PLATFORM	= SUNW,Netra-T4
+LINKS2DESTDIR	= ../../../../SUNW,Sun-Fire-280R/kernel/misc/sparcv9
+LW2PLUS_LINKS_2	= SUNW,Netra-T4/kernel/misc/sparcv9/platmod
+LW2PLUS_PLAT_LINKS_2  = $(LW2PLUS_LINKS_2:%=$(ROOT_PLAT_DIR)/%)
+
+# EXPORT DELETE START
+#
+# aes256 is delivered in the SUNWcryr package which is removed from
+# the EXPORT_SRC build.
+#
+LW2PLUS_CRYPTO_LINKS	+= aes256
+# EXPORT DELETE END
+  
+install:	$(ROOT_LW2PLUS_DIR) $(USR_LW2PLUS_DIR) \
+		$(ROOT_LW2PLUS_MISC_DIR_64) \
+		$(USR_LW2PLUS_INC_DIR) \
+		$(USR_LW2PLUS_SBIN_DIR) \
+		$(USR_LW2PLUS_LIB_DIR) \
+		.WAIT $(LW2PLUS_KMODS) \
+		$(LW2PLUS_PLAT_LINKS_2) \
+		$(LW2PLUS_CRYPTO_LINKS)
+
+install_h check:
+
+lint:		modlintlib
+
+LINT_LIBS	 = $(LINT_LIB) \
+		   -L$(LW2PLUS_LINT_LIB_DIR) \
+		   -L$(LINT_LIB_DIR) $(LINT_KMODS:%=-l%) \
+		   -L$(SPARC_LIB_DIR) $(SPARC_LINTS:%=-l%)
+
+$(LW2PLUS_KMODS): FRC
+	@cd $@; pwd; $(MAKE) $(NO_STATE) $(TARGET)
+
+$(LW2PLUS_PLAT_LINKS_2):
+	$(RM) $@; $(SYMLINK) $(LINKS2DESTDIR)/$(@F) $@ $(CHOWNLINK) $(CHGRPLINK)
+
+$(LW2PLUS_CRYPTO_LINKS): $(ROOT_LW2PLUS_CRYPTO_DIR_64)
+	-$(RM) $(ROOT_LW2PLUS_CRYPTO_DIR_64)/$@;
+	$(SYMLINK) $(ROOT_US3_CRYPTO_LINK)/$@ $(ROOT_LW2PLUS_CRYPTO_DIR_64)/$@
+
+# EXPORT DELETE START
+
+EXPORT_SRC:
+	$(RM) Makefile+
+	sed -e "/^# EXPORT DELETE START/,/^# EXPORT DELETE END/d" \
+	    < Makefile > Makefile+
+	$(MV) Makefile+ Makefile
+	$(CHMOD) 444 Makefile
+
+# EXPORT DELETE END
+
+#
+#
+#	Include common targets.
+#
+include $(UTSBASE)/sun4u/lw2plus/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/lw2plus/Makefile.files	Thu Jun 29 14:43:12 2006 -0700
@@ -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 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+#
+#	Global definitions for sun4u implementation specific modules.
+#
+
+#
+# Define objects.
+#
+LOMBUS_OBJS	= lombus.o
+
+#
+#	include lw2plus and serengeti header files
+#
+INC_PATH	+= -I$(UTSBASE)/sun4u/lw2plus
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/lw2plus/Makefile.lw2plus	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,119 @@
+#
+# 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.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+#
+#	Global definitions for sun4u implementation specific modules.
+#
+
+#
+#	Define the name of this implementation.
+#
+
+#
+#	Define directories.
+#
+ROOT_LW2PLUS_DIR	= $(ROOT_PLAT_DIR)/SUNW,Netra-T4
+ROOT_LW2PLUS_MOD_DIR	= $(ROOT_LW2PLUS_DIR)/kernel
+
+ROOT_LW2PLUS_DRV_DIR_32	= $(ROOT_LW2PLUS_MOD_DIR)/drv
+ROOT_LW2PLUS_DRV_DIR_64	= $(ROOT_LW2PLUS_MOD_DIR)/drv/$(SUBDIR64)
+ROOT_LW2PLUS_DRV_DIR	= $(ROOT_LW2PLUS_DRV_DIR_$(CLASS))
+
+ROOT_LW2PLUS_MISC_DIR_32	= $(ROOT_LW2PLUS_MOD_DIR)/misc
+ROOT_LW2PLUS_MISC_DIR_64	= $(ROOT_LW2PLUS_MOD_DIR)/misc/$(SUBDIR64)
+ROOT_LW2PLUS_MISC_DIR	= $(ROOT_LW2PLUS_MISC_DIR_$(CLASS))
+
+ROOT_LW2PLUS_CRYPTO_DIR_32	= $(ROOT_LW2PLUS_MOD_DIR)/crypto
+ROOT_LW2PLUS_CRYPTO_DIR_64	= $(ROOT_LW2PLUS_CRYPTO_DIR_32)/$(SUBDIR64)
+ROOT_LW2PLUS_CRYPTO_DIR		= $(ROOT_LW2PLUS_CRYPTO_DIR_$(CLASS))
+
+USR_LW2PLUS_DIR		= $(USR_PLAT_DIR)/SUNW,Netra-T4
+USR_LW2PLUS_INC_DIR	= $(USR_LW2PLUS_DIR)/include
+USR_LW2PLUS_ISYS_DIR	= $(USR_LW2PLUS_INC_DIR)/sys
+USR_LW2PLUS_SBIN_DIR	= $(USR_LW2PLUS_DIR)/sbin
+USR_LW2PLUS_LIB_DIR	= $(USR_LW2PLUS_DIR)/lib
+
+LW2PLUS_LINT_LIB_DIR	= $(UTSBASE)/$(PLATFORM)/lw2plus/lint-libs/$(OBJS_DIR)
+
+#
+#	Define modules.
+#
+LW2PLUS_KMODS	= lombus
+#
+#       Include the makefiles which define build rule templates, the
+#       collection of files per module, and a few specific flags. Note
+#       that order is significant, just as with an include path. The
+#       first build rule template which matches the files name will be
+#       used. By including these in order from most machine dependent
+#       to most machine independent, we allow a machine dependent file
+#       to be used in preference over a machine independent version
+#       (Such as a machine specific optimization, which preserves the
+#       interfaces.)
+#
+
+#
+#	Links to UltraSparc III crypto modules
+#
+LW2PLUS_CRYPTO_LINKS	= aes
+
+include $(UTSBASE)/sun4u/lw2plus/Makefile.files
+#
+#	Include common rules.
+#
+
+include $(UTSBASE)/sun4u/Makefile.sun4u
+#
+#       Everybody needs to know how to build modstubs.o and to locate unix.o
+#
+UNIX_DIR	= $(UTSBASE)/$(PLATFORM)/littleneck/unix
+MODSTUBS_DIR	= $(UNIX_DIR)
+DSF_DIR		= $(UTSBASE)/$(PLATFORM)/littleneck/genassym
+LINTS_DIR	= $(OBJS_DIR)
+LINT_LIB_DIR	= $(UTSBASE)/$(PLATFORM)/lw2plus/lint-libs/$(OBJS_DIR)
+
+#
+#       Define the actual specific platforms
+#
+MACHINE_DEFS	= -D$(PLATFORM) -D_MACHDEP -DSFMMU -DMP
+
+#
+#	Define platform specific values
+#
+#MACHINE_DEFS	+= -DNCPU=554
+#MACHINE_DEFS	+= -DMAX_UPA=1024
+#MACHINE_DEFS	+= -DIGN_SIZE=10
+# Max IOSRAM TOC major version number supported
+#MACHINE_DEFS	+= -DMAX_IOSRAM_TOC_VER=0x1
+
+#       Define for inline pre-processing since
+#       cpp not smart about v9 yet.
+#
+CPP_DEFS_32   =
+CPP_DEFS_64   = -D__sparcv9
+CPP_DEFS      = $(CPP_DEFS_$(CLASS))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/lw2plus/Makefile.rules	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,52 @@
+#
+# 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.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+#
+#	This Makefile defines the build rules for the directory
+#	uts/sun4u/lw2plus.
+#
+#	The following two-level ordering must be maintained in this file.
+#	  Lines are sorted first in order of decreasing specificity based on
+#	  the first directory component.  That is, sun4u rules come before
+#	  sparc rules come before common rules.
+#
+#	  Lines whose initial directory components are equal are sorted
+#	  alphabetically by the remaining components.
+
+#
+#	Section 1a: C object build rules.  For some reason $< doesn't
+#	work here, so we explicitly list the sourcefile.
+#
+$(OBJS_DIR)/lombus.o:		$(UTSBASE)/sun4u/lw2plus/io/lombus.c
+	$(COMPILE.c) -o $@ $(UTSBASE)/sun4u/lw2plus/io/lombus.c
+	$(CTFCONVERT_O)
+
+#
+#	Section 1b: Lint `object' build rules
+#
+$(LINTS_DIR)/lombus.ln:		$(UTSBASE)/sun4u/lw2plus/io/lombus.c
+	@($(LHEAD) $(LINT.c) $(UTSBASE)/sun4u/lw2plus/io/lombus.c $(LTAIL))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/lw2plus/Makefile.targ	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,83 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+#
+#	Common targets for sun4u LW2PLUS implementation specific modules.
+#
+
+.KEEP_STATE:
+
+#
+# Rules for implementation subdirectories.
+#
+$(ROOT_LW2PLUS_DIR): $(ROOT_PLAT_DIR)
+	-$(INS.dir.root.sys)
+
+$(ROOT_LW2PLUS_MOD_DIR): $(ROOT_LW2PLUS_DIR)
+	-$(INS.dir.root.sys)
+
+$(ROOT_LW2PLUS_DRV_DIR_32): $(ROOT_LW2PLUS_MOD_DIR)
+	-$(INS.dir.root.sys)
+
+$(ROOT_LW2PLUS_DRV_DIR_64): $(ROOT_LW2PLUS_DRV_DIR_32)
+	-$(INS.dir.root.sys)
+
+$(ROOT_LW2PLUS_MISC_DIR_32): $(ROOT_LW2PLUS_MOD_DIR)
+	-$(INS.dir.root.sys)
+
+$(ROOT_LW2PLUS_MISC_DIR_64): $(ROOT_LW2PLUS_MISC_DIR_32)
+	-$(INS.dir.root.sys)
+
+$(ROOT_LW2PLUS_CRYPTO_DIR_32): $(ROOT_LW2PLUS_MOD_DIR)
+	-$(INS.dir.root.sys)
+
+$(ROOT_LW2PLUS_CRYPTO_DIR_64): $(ROOT_LW2PLUS_CRYPTO_DIR_32)
+	-$(INS.dir.root.sys)
+
+$(USR_LW2PLUS_DIR): $(USR_PLAT_DIR)
+	-$(INS.dir.root.sys)
+
+$(USR_LW2PLUS_INC_DIR): $(USR_LW2PLUS_DIR)
+	$(INS.slink4)
+
+$(USR_LW2PLUS_ISYS_DIR): $(USR_LW2PLUS_INC_DIR)
+	$(INS.dir.root.bin)
+
+$(USR_LW2PLUS_SBIN_DIR): $(USR_LW2PLUS_DIR)
+	$(INS.slink5)
+
+$(USR_LW2PLUS_LIB_DIR): $(USR_LW2PLUS_DIR)
+	-$(INS.dir.root.bin)
+
+$(ROOT_LW2PLUS_DRV_DIR)/%: $(OBJS_DIR)/% $(ROOT_LW2PLUS_DRV_DIR) FRC
+	$(INS.file)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/sun4u/lw2plus/Makefile.rules
+include $(UTSBASE)/sun4u/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/lw2plus/io/lombus.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,2302 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * The "lombus" driver provides access to the LOMlite2 virtual registers,
+ * so that its clients (children) need not be concerned with the details
+ * of the access mechanism, which in this case is implemented via a
+ * packet-based protocol over a serial link connected to one of the serial
+ * ports of the SuperIO (SIO) chip.
+ *
+ * On the other hand, this driver doesn't generally know what the virtual
+ * registers signify - only the clients need this information.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ *  Header files
+ */
+
+#include <sys/types.h>
+#include <sys/conf.h>
+#include <sys/cyclic.h>
+#include <sys/debug.h>
+#include <sys/errno.h>
+#include <sys/file.h>
+#include <sys/intr.h>
+#include <sys/kmem.h>
+#include <sys/membar.h>
+#include <sys/modctl.h>
+#include <sys/note.h>
+#include <sys/open.h>
+#include <sys/poll.h>
+#include <sys/spl.h>
+#include <sys/stat.h>
+#include <sys/strlog.h>
+
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+
+#include <sys/lombus.h>
+
+
+#if	defined(NDI_ACC_HDL_V2)
+
+/*
+ * Compiling for Solaris 9+ with access handle enhancements
+ */
+#define	HANDLE_TYPE		ndi_acc_handle_t
+#define	HANDLE_ADDR(hdlp)	(hdlp->ah_addr)
+#define	HANDLE_FAULT(hdlp)	(hdlp->ah_fault)
+#define	HANDLE_MAPLEN(hdlp)	(hdlp->ah_len)
+#define	HANDLE_PRIVATE(hdlp)	(hdlp->ah_bus_private)
+
+#else
+
+/*
+ * Compatibility definitions for backport to Solaris 8
+ */
+#define	HANDLE_TYPE		ddi_acc_impl_t
+#define	HANDLE_ADDR(hdlp)	(hdlp->ahi_common.ah_addr)
+#define	HANDLE_FAULT(hdlp)	(hdlp->ahi_fault)
+#define	HANDLE_MAPLEN(hdlp)	(hdlp->ahi_common.ah_len)
+#define	HANDLE_PRIVATE(hdlp)	(hdlp->ahi_common.ah_bus_private)
+
+#define	ddi_driver_major(dip)	ddi_name_to_major(ddi_binding_name(dip))
+
+#endif	/* NDI_ACC_HDL_V2 */
+
+
+/*
+ * Local definitions
+ */
+#define	MYNAME			"lombus"
+#define	NOMAJOR			(~(major_t)0)
+#define	DUMMY_VALUE		(~(int8_t)0)
+
+#define	LOMBUS_INST_TO_MINOR(i)	(i)
+#define	LOMBUS_MINOR_TO_INST(m)	(m)
+
+#define	LOMBUS_DUMMY_ADDRESS	((caddr_t)0x0CADD1ED)
+#define	ADDR_TO_OFFSET(a, hdlp)	((caddr_t)(a) - HANDLE_ADDR(hdlp))
+#define	ADDR_TO_VREG(a)		((caddr_t)(a) - LOMBUS_DUMMY_ADDRESS)
+#define	VREG_TO_ADDR(v)		(LOMBUS_DUMMY_ADDRESS + (v))
+
+
+/*
+ * The following definitions are taken from the datasheet
+ * for the National Semiconductor PC87317 (SuperIO) chip.
+ *
+ * This chip implements UART functionality as logical device 6.
+ * It provides all sorts of wierd modes and extensions, but we
+ * have chosen to use only the 16550-compatible features
+ * ("non-extended mode").
+ *
+ * Hardware: serial chip register numbers
+ */
+#define	SIO_RXD			0	/* read		*/
+#define	SIO_TXD			0	/* write	*/
+#define	SIO_IER			1
+#define	SIO_EIR			2	/* read		*/
+#define	SIO_FCR			2	/* write	*/
+#define	SIO_LCR			3
+#define	SIO_BSR			3	/* wierd	*/
+#define	SIO_MCR			4
+#define	SIO_LSR			5
+#define	SIO_MSR			6
+#define	SIO_SCR			7
+
+#define	SIO_LBGDL		0	/* bank 1	*/
+#define	SIO_LBGDH		1	/* bank 1	*/
+
+/*
+ * Hardware: serial chip register bits
+ */
+#define	SIO_IER_RXHDL_IE	0x01
+#define	SIO_IER_STD		0x00
+
+#define	SIO_EIR_IPF		0x01
+#define	SIO_EIR_IPR0		0x02
+#define	SIO_EIR_IPR1		0x04
+#define	SIO_EIR_RXFT		0x08
+#define	SIO_EIR_FEN0		0x40
+#define	SIO_EIR_FEN1		0x80
+
+#define	SIO_FCR_FIFO_EN		0x01
+#define	SIO_FCR_RXSR		0x02
+#define	SIO_FCR_TXSR		0x04
+#define	SIO_FCR_RXFTH0		0x40
+#define	SIO_FCR_RXFTH1		0x80
+#define	SIO_FCR_STD		(SIO_FCR_RXFTH0|SIO_FCR_FIFO_EN)
+
+#define	SIO_LCR_WLS0		0x01
+#define	SIO_LCR_WLS1		0x02
+#define	SIO_LCR_STB		0x04
+#define	SIO_LCR_PEN		0x08
+#define	SIO_LCR_EPS		0x10
+#define	SIO_LCR_STKP		0x20
+#define	SIO_LCR_SBRK		0x40
+#define	SIO_LCR_BKSE		0x80
+#define	SIO_LCR_8BIT		(SIO_LCR_WLS0|SIO_LCR_WLS1)
+#define	SIO_LCR_EPAR		(SIO_LCR_PEN|SIO_LCR_EPS)
+#define	SIO_LCR_STD		(SIO_LCR_8BIT|SIO_LCR_EPAR)
+
+#define	SIO_BSR_BANK0		(SIO_LCR_STD)
+#define	SIO_BSR_BANK1		(SIO_LCR_BKSE|SIO_LCR_STD)
+
+#define	SIO_MCR_DTR		0x01
+#define	SIO_MCR_RTS		0x02
+#define	SIO_MCR_ISEN		0x08
+#define	SIO_MCR_STD		(SIO_MCR_ISEN)
+
+#define	SIO_LSR_RXDA		0x01
+#define	SIO_LSR_OE		0x02
+#define	SIO_LSR_PE		0x04
+#define	SIO_LSR_FE		0x08
+#define	SIO_LSR_BRKE		0x10
+#define	SIO_LSR_TXRDY		0x20
+#define	SIO_LSR_TXEMP		0x40
+#define	SIO_LSR_ER_INF		0x80
+
+#define	SIO_MSR_DCTS		0x01
+#define	SIO_MSR_DDSR		0x02
+#define	SIO_MSR_TERI		0x04
+#define	SIO_MSR_DDCD		0x08
+#define	SIO_MSR_CTS		0x10
+#define	SIO_MSR_DSR		0x20
+#define	SIO_MSR_RI		0x40
+#define	SIO_MSR_DCD		0x80
+
+/*
+ * Min/max/default baud rates, and a macro to convert from a baud
+ * rate to the number (divisor) to put in the baud rate registers
+ */
+#define	SIO_BAUD_MIN		50
+#define	SIO_BAUD_MAX		115200
+#define	SIO_BAUD_DEFAULT	38400
+#define	SIO_BAUD_TO_DIVISOR(b)	(115200 / (b))
+
+
+/*
+ * Packet format ...
+ */
+#define	LOMBUS_MASK		0xc0	/* Byte-type bits		*/
+#define	LOMBUS_PARAM		0x00	/* Parameter byte: 0b0xxxxxxx	*/
+#define	LOMBUS_LAST		0x80	/* Last byte of packet		*/
+#define	LOMBUS_CMD		0x80	/* Command byte:   0b10###XWV	*/
+#define	LOMBUS_STATUS		0xc0	/* Status  byte:   0b11###AEV	*/
+
+#define	LOMBUS_SEQ		0x38	/* Sequence number bits		*/
+#define	LOMBUS_SEQ_LSB		0x08	/* Sequence number LSB		*/
+#define	LOMBUS_CMD_XADDR	0x04	/* Extended (2-byte) addressing	*/
+#define	LOMBUS_CMD_WRITE	0x02	/* Write command		*/
+#define	LOMBUS_CMD_WMSB		0x01	/* Set MSB on Write		*/
+#define	LOMBUS_CMD_READ		0x01	/* Read command			*/
+#define	LOMBUS_CMD_NOP		0x00	/* NOP command			*/
+
+#define	LOMBUS_STATUS_ASYNC	0x04	/* Asynchronous event pending	*/
+#define	LOMBUS_STATUS_ERR	0x02	/* Error in command processing	*/
+#define	LOMBUS_STATUS_MSB	0x01	/* MSB of Value read		*/
+
+#define	LOMBUS_VREG_LO(x)	((x) & ((1 << 7) - 1))
+#define	LOMBUS_VREG_HI(x)	((x) >> 7)
+
+#define	LOMBUS_BUFSIZE		8
+
+
+/*
+ * Time periods, in nanoseconds
+ *
+ * Note that LOMBUS_ONE_SEC and some other time
+ * periods are defined in <sys/lombus.h>
+ */
+#define	LOMBUS_CMD_POLL		(LOMBUS_ONE_SEC/20)
+#define	LOMBUS_CTS_POLL		(LOMBUS_ONE_SEC/20)
+#define	LOMBUS_CTS_TIMEOUT	(LOMBUS_ONE_SEC*2)
+
+
+/*
+ * Local datatypes
+ */
+enum lombus_cmdstate {
+	LOMBUS_CMDSTATE_IDLE,
+	LOMBUS_CMDSTATE_BUSY,
+	LOMBUS_CMDSTATE_WAITING,
+	LOMBUS_CMDSTATE_READY,
+	LOMBUS_CMDSTATE_ERROR
+};
+
+
+/*
+ * This driver's soft-state structure
+ */
+
+struct lombus_state {
+	/*
+	 * Configuration data, set during attach
+	 */
+	dev_info_t *dip;
+	major_t majornum;
+	int instance;
+
+	ddi_acc_handle_t sio_handle;
+	uint8_t *sio_regs;
+	ddi_softintr_t softid;
+	cyclic_id_t cycid;
+
+	/*
+	 * Parameters derived from .conf properties
+	 */
+	boolean_t allow_echo;
+	int baud;
+	uint32_t debug;
+	boolean_t fake_cts;
+
+	/*
+	 * Hardware mutex (initialised using <hw_iblk>),
+	 * used to prevent retriggering the softint while
+	 * it's still fetching data out of the chip FIFO.
+	 */
+	kmutex_t hw_mutex[1];
+	ddi_iblock_cookie_t hw_iblk;
+
+	/*
+	 * Data protected by the hardware mutex: the watchdog-patting
+	 * protocol data (since the dog can be patted from a high-level
+	 * cyclic), and the interrupt-enabled flag.
+	 */
+	hrtime_t hw_last_pat;
+	boolean_t hw_int_enabled;
+
+	/*
+	 * Flag to indicate that we've incurred a hardware fault on
+	 * accesses to the SIO; once this is set, we fake all further
+	 * accesses in order not to provoke additional bus errors.
+	 */
+	boolean_t sio_fault;
+
+	/*
+	 * Serial protocol state data, protected by lo_mutex
+	 * (which is initialised using <lo_iblk>)
+	 */
+	kmutex_t lo_mutex[1];
+	ddi_iblock_cookie_t lo_iblk;
+	kcondvar_t lo_cv[1];
+
+	volatile enum lombus_cmdstate cmdstate;
+	clock_t deadline;
+	uint8_t cmdbuf[LOMBUS_BUFSIZE];
+	uint8_t reply[LOMBUS_BUFSIZE];
+	uint8_t async;
+	uint8_t index;
+	uint8_t result;
+	uint8_t sequence;
+	uint32_t error;
+};
+
+/*
+ * The auxiliary structure attached to each child
+ * (the child's parent-private-data points to this).
+ */
+struct lombus_child_info {
+	lombus_regspec_t *rsp;
+	int nregs;
+};
+
+
+/*
+ * Local data
+ */
+
+static void *lombus_statep;
+
+static major_t lombus_major = NOMAJOR;
+
+static ddi_device_acc_attr_t lombus_dev_acc_attr[1] =
+{
+	DDI_DEVICE_ATTR_V0,
+	DDI_STRUCTURE_LE_ACC,
+	DDI_STRICTORDER_ACC
+};
+
+
+/*
+ *  General utility routines ...
+ */
+
+static void
+lombus_trace(struct lombus_state *ssp, char code, const char *caller,
+	const char *fmt, ...)
+{
+	char buf[256];
+	char *p;
+	va_list va;
+
+	if (ssp->debug & (1 << (code-'@'))) {
+		p = buf;
+		snprintf(p, sizeof (buf) - (p - buf),
+			"%s/%s: ", MYNAME, caller);
+		p += strlen(p);
+
+		va_start(va, fmt);
+		vsnprintf(p, sizeof (buf) - (p - buf), fmt, va);
+		va_end(va);
+
+		buf[sizeof (buf) - 1] = '\0';
+		strlog(ssp->majornum, ssp->instance, code, SL_TRACE, buf);
+	}
+}
+
+static struct lombus_state *
+lombus_getstate(dev_info_t *dip, int instance, const char *caller)
+{
+	struct lombus_state *ssp = NULL;
+	dev_info_t *sdip = NULL;
+	major_t dmaj = NOMAJOR;
+
+	if (dip != NULL) {
+		/*
+		 * Use the instance number from the <dip>; also,
+		 * check that it really corresponds to this driver
+		 */
+		instance = ddi_get_instance(dip);
+		dmaj = ddi_driver_major(dip);
+		if (lombus_major == NOMAJOR && dmaj != NOMAJOR)
+			lombus_major = dmaj;
+		else if (dmaj != lombus_major) {
+			cmn_err(CE_WARN,
+			    "%s: major number mismatch (%d vs. %d) in %s(),"
+			    "probably due to child misconfiguration",
+			    MYNAME, lombus_major, dmaj, caller);
+			instance = -1;
+		}
+	}
+
+	if (instance >= 0)
+		ssp = ddi_get_soft_state(lombus_statep, instance);
+	if (ssp != NULL) {
+		sdip = ssp->dip;
+		if (dip == NULL && sdip == NULL)
+			ssp = NULL;
+		else if (dip != NULL && sdip != NULL && sdip != dip) {
+			cmn_err(CE_WARN,
+			    "%s: devinfo mismatch (%p vs. %p) in %s(), "
+			    "probably due to child misconfiguration",
+			    MYNAME, (void *)dip, (void *)sdip, caller);
+			ssp = NULL;
+		}
+	}
+
+	return (ssp);
+}
+
+/*
+ * Lowest-level serial I/O chip register read/write
+ */
+
+static void
+sio_put_reg(struct lombus_state *ssp, uint_t reg, uint8_t val)
+{
+	lombus_trace(ssp, 'P', "sio_put_reg", "REG[%d] <- $%02x", reg, val);
+
+	if (ssp->sio_handle != NULL && !ssp->sio_fault) {
+		/*
+		 * The chip is mapped as "I/O" (e.g. with the side-effect
+		 * bit on SPARC), therefore accesses are required to be
+		 * in-order, with no value cacheing.  However, there can
+		 * still be write-behind buffering, so it is not guaranteed
+		 * that a write actually reaches the chip in a given time.
+		 *
+		 * To force the access right through to the chip, we follow
+		 * the write with another write (to the SCRATCH register)
+		 * and a read (of the value just written to the SCRATCH
+		 * register).  The SCRATCH register is specifically provided
+		 * for temporary data and has no effect on the SIO's own
+		 * operation, making it ideal as a synchronising mechanism.
+		 *
+		 * If we didn't do this, it would be possible that the new
+		 * value wouldn't reach the chip (and have the *intended*
+		 * side-effects, such as disabling interrupts), for such a
+		 * long time that the processor could execute a *lot* of
+		 * instructions - including exiting the interrupt service
+		 * routine and re-enabling interrupts.  This effect was
+		 * observed to lead to spurious (unclaimed) interrupts in
+		 * some circumstances.
+		 *
+		 * This will no longer be needed once "synchronous" access
+		 * handles are available (see PSARC/2000/269 and 2000/531).
+		 */
+		ddi_put8(ssp->sio_handle, ssp->sio_regs + reg, val);
+		ddi_put8(ssp->sio_handle, ssp->sio_regs + SIO_SCR, val);
+		membar_sync();
+		(void) ddi_get8(ssp->sio_handle, ssp->sio_regs + SIO_SCR);
+	}
+}
+
+static uint8_t
+sio_get_reg(struct lombus_state *ssp, uint_t reg)
+{
+	uint8_t val;
+
+	if (ssp->sio_handle && !ssp->sio_fault)
+		val = ddi_get8(ssp->sio_handle, ssp->sio_regs + reg);
+	else
+		val = DUMMY_VALUE;
+
+	lombus_trace(ssp, 'G', "sio_get_reg", "$%02x <- REG[%d]", val, reg);
+
+	return (val);
+}
+
+static void
+sio_check_fault_status(struct lombus_state *ssp)
+{
+	ssp->sio_fault = ddi_check_acc_handle(ssp->sio_handle) != DDI_SUCCESS;
+}
+
+static boolean_t
+sio_faulty(struct lombus_state *ssp)
+{
+	if (!ssp->sio_fault)
+		sio_check_fault_status(ssp);
+	return (ssp->sio_fault);
+}
+
+
+/*
+ * Check for data ready.
+ */
+static boolean_t
+sio_data_ready(struct lombus_state *ssp)
+{
+	uint8_t status;
+
+	/*
+	 * Data is available if the RXDA bit in the LSR is nonzero
+	 * (if reading it didn't incur a fault).
+	 */
+	status = sio_get_reg(ssp, SIO_LSR);
+	return ((status & SIO_LSR_RXDA) != 0 && !sio_faulty(ssp));
+}
+
+/*
+ * Check for LOM ready
+ */
+static boolean_t
+sio_lom_ready(struct lombus_state *ssp)
+{
+	uint8_t status;
+	boolean_t rslt;
+
+	/*
+	 * The LOM is ready if the CTS bit in the MSR is 1, meaning
+	 * that the /CTS signal is being asserted (driven LOW) -
+	 * unless we incurred a fault in trying to read the MSR!
+	 *
+	 * For debugging, we force the result to TRUE if the FAKE flag is set
+	 */
+	status = sio_get_reg(ssp, SIO_MSR);
+	rslt = (status & SIO_MSR_CTS) != 0 && !sio_faulty(ssp);
+
+	lombus_trace(ssp, 'R', "sio_lom_ready", "S $%02x R %d F %d",
+		status, rslt, ssp->fake_cts);
+
+	return (rslt || ssp->fake_cts);
+}
+
+#if	0
+/*
+ * Check for interrupt pending
+ */
+static boolean_t
+sio_irq_pending(struct lombus_state *ssp)
+{
+	uint8_t status;
+	boolean_t rslt;
+
+	/*
+	 * An interrupt is pending if the IPF bit in the EIR is 0,
+	 * assuming we didn't incur a fault in trying to ready it.
+	 *
+	 * Note: we expect that every time we read this register
+	 * (which is only done from the interrupt service routine),
+	 * we will see $11001100 (RX FIFO timeout interrupt pending).
+	 */
+	status = sio_get_reg(ssp, SIO_EIR);
+
+	rslt = (status & SIO_EIR_IPF) == 0 && !sio_faulty(ssp);
+	lombus_trace(ssp, 'I', "sio_irq_pending", "S $%02x R %d",
+		status, rslt);
+
+	/*
+	 * To investigate whether we're getting any abnormal interrupts
+	 * this code checks that the status value is as expected, and that
+	 * chip-level interrupts are supposed to be enabled at this time.
+	 * This will cause a PANIC (on a driver compiled with DEBUG) if
+	 * all is not as expected ...
+	 */
+	ASSERT(status == 0xCC);
+	ASSERT(ssp->hw_int_enabled);
+
+	return (rslt);
+}
+#endif	/* 0 */
+
+/*
+ * Enable/disable interrupts
+ */
+static void
+lombus_set_irq(struct lombus_state *ssp, boolean_t newstate)
+{
+	uint8_t val;
+
+	val = newstate ? SIO_IER_RXHDL_IE : 0;
+	sio_put_reg(ssp, SIO_IER, SIO_IER_STD | val);
+	ssp->hw_int_enabled = newstate;
+}
+
+/*
+ * Assert/deassert RTS
+ */
+static void
+lombus_toggle_rts(struct lombus_state *ssp)
+{
+	uint8_t val;
+
+	val = sio_get_reg(ssp, SIO_MCR);
+	val &= SIO_MCR_RTS;
+	val ^= SIO_MCR_RTS;
+	val |= SIO_MCR_STD;
+	sio_put_reg(ssp, SIO_MCR, val);
+}
+
+
+/*
+ * High-level interrupt handler:
+ *	Checks whether initialisation is complete (to avoid a race
+ *	with mutex_init()), and whether chip interrupts are enabled.
+ *	If not, the interrupt's not for us, so just return UNCLAIMED.
+ *	Otherwise, disable the interrupt, trigger a softint, and return
+ *	CLAIMED.  The softint handler will then do all the real work.
+ *
+ *	NOTE: the chip interrupt capability is only re-enabled once the
+ *	receive code has run, but that can be called from a poll loop
+ *	or cyclic callback as well as from the softint.  So it's *not*
+ *	guaranteed that there really is a chip interrupt pending here,
+ *	'cos the work may already have been done and the reason for the
+ *	interrupt gone away before we get here.
+ *
+ *	OTOH, if we come through here twice without the receive code
+ *	having run in between, that's definitely wrong.  In such an
+ *	event, we would notice that chip interrupts haven't yet been
+ *	re-enabled and return UNCLAIMED, allowing the system's jabber
+ *	protect code (if any) to do its job.
+ */
+static uint_t
+lombus_hi_intr(caddr_t arg)
+{
+	struct lombus_state *ssp = (void *)arg;
+	uint_t claim;
+
+	claim = DDI_INTR_UNCLAIMED;
+	if (ssp->cycid != CYCLIC_NONE) {
+		mutex_enter(ssp->hw_mutex);
+		if (ssp->hw_int_enabled) {
+			lombus_set_irq(ssp, B_FALSE);
+			ddi_trigger_softintr(ssp->softid);
+			claim = DDI_INTR_CLAIMED;
+		}
+		mutex_exit(ssp->hw_mutex);
+	}
+
+	return (claim);
+}
+
+/*
+ * Packet receive handler
+ *
+ * This routine should be called from the low-level softint, or the
+ * cyclic callback, or lombus_cmd() (for polled operation), with the
+ * low-level mutex already held.
+ */
+static void
+lombus_receive(struct lombus_state *ssp)
+{
+	boolean_t ready = B_FALSE;
+	uint8_t data = 0;
+	uint8_t rcvd = 0;
+	uint8_t tmp;
+
+	lombus_trace(ssp, 'S', "lombus_receive",
+		"state %d; error $%x",
+		ssp->cmdstate, ssp->error);
+
+	/*
+	 * Check for access faults before starting the receive
+	 * loop (we don't want to cause bus errors or suchlike
+	 * unpleasantness in the event that the SIO has died).
+	 */
+	if (!sio_faulty(ssp)) {
+		/*
+		 * Read bytes from the FIFO until they're all gone,
+		 * or we find the 'END OF PACKET' set on one, or
+		 * our buffer overflows (which must be an error)
+		 */
+		mutex_enter(ssp->hw_mutex);
+		while (sio_data_ready(ssp)) {
+			data = sio_get_reg(ssp, SIO_RXD);
+			ssp->reply[rcvd = ssp->index] = data;
+			if (++rcvd >= LOMBUS_BUFSIZE)
+				break;
+			ssp->index = rcvd;
+			if (data & LOMBUS_LAST)
+				break;
+		}
+		lombus_set_irq(ssp, B_TRUE);
+		mutex_exit(ssp->hw_mutex);
+	}
+
+	lombus_trace(ssp, 'S', "lombus_receive",
+		"rcvd %d: $%02x $%02x $%02x $%02x $%02x $%02x $%02x $%02x",
+		rcvd,
+		ssp->reply[0], ssp->reply[1],
+		ssp->reply[2], ssp->reply[3],
+		ssp->reply[4], ssp->reply[5],
+		ssp->reply[6], ssp->reply[7]);
+
+	if (ssp->cmdstate != LOMBUS_CMDSTATE_WAITING) {
+		/*
+		 * We're not expecting any data in this state, so if
+		 * we DID receive any data, we just throw it away by
+		 * resetting the buffer index to 0.
+		 */
+		ssp->index = 0;
+	} else if (rcvd == 0) {
+		/*
+		 * No bytes received this time through (though there
+		 * might be a partial packet sitting in the buffer).
+		 * If it seems the LOM is taking too long to respond,
+		 * we'll assume it's died and return an error.
+		 */
+		if (ddi_get_lbolt() > ssp->deadline) {
+			ssp->cmdstate = LOMBUS_CMDSTATE_ERROR;
+			ssp->error = LOMBUS_ERR_TIMEOUT;
+			ready = B_TRUE;
+		}
+	} else if (rcvd >= LOMBUS_BUFSIZE) {
+		/*
+		 * Buffer overflow; discard the data & treat as an error
+		 * (even if the last byte read did claim to terminate a
+		 * packet, it can't be a valid one 'cos it's too long!)
+		 */
+		ssp->index = 0;
+		ssp->cmdstate = LOMBUS_CMDSTATE_ERROR;
+		ssp->error = LOMBUS_ERR_OFLOW;
+		ready = B_TRUE;
+	} else if ((data & LOMBUS_LAST) == 0) {
+		/*
+		 * Packet not yet complete; leave the partial packet in
+		 * the buffer for later ...
+		 */
+		_NOTE(EMPTY)
+		;
+	} else if ((data & LOMBUS_MASK) != LOMBUS_STATUS) {
+		/*
+		 * Invalid "status" byte - maybe an echo of the command?
+		 *
+		 * As a debugging feature, we allow for this, assuming
+		 * that if the LOM has echoed the command byte, it has
+		 * also echoed all the parameter bytes before starting
+		 * command processing.  So, we dump out the buffer and
+		 * then clear it, so we can go back to looking for the
+		 * real reply.
+		 *
+		 * Otherwise, we just drop the data & flag an error.
+		 */
+		if (ssp->allow_echo) {
+			lombus_trace(ssp, 'E', "lombus_receive",
+				"echo $%02x $%02x $%02x $%02x "
+				"$%02x $%02x $%02x $%02x",
+				ssp->reply[0], ssp->reply[1],
+				ssp->reply[2], ssp->reply[3],
+				ssp->reply[4], ssp->reply[5],
+				ssp->reply[6], ssp->reply[7]);
+			ssp->index = 0;
+		} else {
+			ssp->cmdstate = LOMBUS_CMDSTATE_ERROR;
+			ssp->error = LOMBUS_ERR_BADSTATUS;
+			ready = B_TRUE;
+		}
+	} else if ((data & LOMBUS_SEQ) != ssp->sequence) {
+		/*
+		 * Wrong sequence number!  Flag this as an error
+		 */
+		ssp->cmdstate = LOMBUS_CMDSTATE_ERROR;
+		ssp->error = LOMBUS_ERR_SEQUENCE;
+		ready = B_TRUE;
+	} else {
+		/*
+		 * Finally, we know that's it's a valid reply to our
+		 * last command.  Update the ASYNC status, derive the
+		 * reply parameter (if any), and check the ERROR bit
+		 * to find out what the parameter means.
+		 *
+		 * Note that not all the values read/assigned here
+		 * are meaningful, but it doesn't matter; the waiting
+		 * thread will know which one(s) it should check.
+		 */
+		ssp->async = (data & LOMBUS_STATUS_ASYNC) ? 1 : 0;
+		tmp = ((data & LOMBUS_STATUS_MSB) ? 0x80 : 0) | ssp->reply[0];
+		if (data & LOMBUS_STATUS_ERR) {
+			ssp->cmdstate = LOMBUS_CMDSTATE_ERROR;
+			ssp->error = tmp;
+		} else {
+			ssp->cmdstate = LOMBUS_CMDSTATE_READY;
+			ssp->result = tmp;
+		}
+		ready = B_TRUE;
+	}
+
+	lombus_trace(ssp, 'T', "lombus_receive",
+		"rcvd %d; last $%02x; state %d; error $%x; ready %d",
+			rcvd, data, ssp->cmdstate, ssp->error, ready);
+
+	if (ready)
+		cv_broadcast(ssp->lo_cv);
+}
+
+/*
+ * Low-level softint handler
+ *
+ * This routine should be triggered whenever there's a byte to be read
+ */
+static uint_t
+lombus_softint(caddr_t arg)
+{
+	struct lombus_state *ssp = (void *)arg;
+
+	mutex_enter(ssp->lo_mutex);
+	lombus_receive(ssp);
+	mutex_exit(ssp->lo_mutex);
+
+	return (DDI_INTR_CLAIMED);
+}
+
+/*
+ * Cyclic handler: just calls the receive routine, in case interrupts
+ * are not being delivered and in order to handle command timeout
+ */
+static void
+lombus_cyclic(void *arg)
+{
+	struct lombus_state *ssp = (void *)arg;
+
+	mutex_enter(ssp->lo_mutex);
+	lombus_receive(ssp);
+	mutex_exit(ssp->lo_mutex);
+}
+
+
+/*
+ * Serial protocol
+ *
+ * This routine builds a command and sets it in progress.
+ */
+static uint8_t
+lombus_cmd(HANDLE_TYPE *hdlp, ptrdiff_t vreg, uint_t val, uint_t cmd)
+{
+	struct lombus_state *ssp;
+	clock_t start;
+	clock_t tick;
+	uint8_t *p;
+
+	/*
+	 * First of all, wait for the interface to be available.
+	 *
+	 * NOTE: we blow through all the mutex/cv/state checking and
+	 * preempt any command in progress if the system is panicking!
+	 */
+	ssp = HANDLE_PRIVATE(hdlp);
+	mutex_enter(ssp->lo_mutex);
+	while (ssp->cmdstate != LOMBUS_CMDSTATE_IDLE && !panicstr)
+		cv_wait(ssp->lo_cv, ssp->lo_mutex);
+
+	ssp->cmdstate = LOMBUS_CMDSTATE_BUSY;
+	ssp->sequence = (ssp->sequence + LOMBUS_SEQ_LSB) & LOMBUS_SEQ;
+
+	/*
+	 * We have exclusive ownership, so assemble the command (backwards):
+	 *
+	 * [byte 0]	Command:	modified by XADDR and/or WMSB bits
+	 * [Optional] Parameter: 	Value to write (low 7 bits)
+	 * [Optional] Parameter: 	Register number (high 7 bits)
+	 * [Optional] Parameter: 	Register number (low 7 bits)
+	 */
+	p = &ssp->cmdbuf[0];
+	*p++ = LOMBUS_CMD | ssp->sequence | cmd;
+	switch (cmd) {
+	case LOMBUS_CMD_WRITE:
+		*p++ = val & 0x7f;
+		if (val >= 0x80)
+			ssp->cmdbuf[0] |= LOMBUS_CMD_WMSB;
+		/*FALLTHRU*/
+	case LOMBUS_CMD_READ:
+		if (LOMBUS_VREG_HI(vreg) != 0) {
+			*p++ = LOMBUS_VREG_HI(vreg);
+			ssp->cmdbuf[0] |= LOMBUS_CMD_XADDR;
+		}
+		*p++ = LOMBUS_VREG_LO(vreg);
+		/*FALLTHRU*/
+	case LOMBUS_CMD_NOP:
+		break;
+	}
+
+	/*
+	 * Check and update the SIO h/w fault status before accessing
+	 * the chip registers.  If there's a (new or previous) fault,
+	 * we'll run through the protocol but won't really touch the
+	 * hardware and all commands will timeout.  If a previously
+	 * discovered fault has now gone away (!), then we can (try to)
+	 * proceed with the new command (probably a probe).
+	 */
+	sio_check_fault_status(ssp);
+
+	/*
+	 * Wait up to LOMBUS_CTS_TIMEOUT (2 seconds) for the LOM to tell
+	 * us that it's ready for the next command.  If it doesn't, though,
+	 * we'll send it anyway, on the basis that the CTS signal might be
+	 * open- or short-circuited (or the LOM firmware forgot to set it,
+	 * or the LOM just got reset, or whatever ...)
+	 */
+	start = ddi_get_lbolt();
+	ssp->deadline = start + drv_usectohz(LOMBUS_CTS_TIMEOUT/1000);
+	while (!sio_lom_ready(ssp)) {
+		if ((tick = ddi_get_lbolt()) > ssp->deadline)
+			break;
+		tick += drv_usectohz(LOMBUS_CTS_POLL/1000);
+		cv_timedwait(ssp->lo_cv, ssp->lo_mutex, tick);
+	}
+
+	/*
+	 * Either the LOM is ready, or we timed out waiting for CTS.
+	 * In either case, we're going to send the command now by
+	 * stuffing the packet into the Tx FIFO, reversing it as we go.
+	 * We call lombus_receive() first to ensure there isn't any
+	 * garbage left in the Rx FIFO from an earlier command that
+	 * timed out (or was pre-empted by a PANIC!).  This also makes
+	 * sure that SIO interrupts are enabled so we'll see the reply
+	 * more quickly (the poll loop below will still work even if
+	 * interrupts aren't enabled, but it will take longer).
+	 */
+	lombus_receive(ssp);
+	mutex_enter(ssp->hw_mutex);
+	while (p > ssp->cmdbuf)
+		sio_put_reg(ssp, SIO_TXD, *--p);
+	mutex_exit(ssp->hw_mutex);
+
+	/*
+	 * Prepare for the reply (to be processed by the interrupt/cyclic
+	 * handler and/or polling loop below), then wait for a response
+	 * or timeout.
+	 */
+	start = ddi_get_lbolt();
+	ssp->deadline = start + drv_usectohz(LOMBUS_CMD_TIMEOUT/1000);
+	ssp->error = 0;
+	ssp->index = 0;
+	ssp->result = DUMMY_VALUE;
+	ssp->cmdstate = LOMBUS_CMDSTATE_WAITING;
+	while (ssp->cmdstate == LOMBUS_CMDSTATE_WAITING) {
+		tick = ddi_get_lbolt() + drv_usectohz(LOMBUS_CMD_POLL/1000);
+		if (cv_timedwait(ssp->lo_cv, ssp->lo_mutex, tick) == -1)
+			lombus_receive(ssp);
+	}
+
+	/*
+	 * The return value may not be meaningful but retrieve it anyway
+	 */
+	val = ssp->result;
+	if (sio_faulty(ssp)) {
+		val = DUMMY_VALUE;
+		HANDLE_FAULT(hdlp) = LOMBUS_ERR_SIOHW;
+	} else if (ssp->cmdstate != LOMBUS_CMDSTATE_READY) {
+		/*
+		 * Some problem here ... transfer the error code from
+		 * the per-instance state to the per-handle fault flag.
+		 * The error code shouldn't be zero!
+		 */
+		if (ssp->error != 0)
+			HANDLE_FAULT(hdlp) = ssp->error;
+		else
+			HANDLE_FAULT(hdlp) = LOMBUS_ERR_BADERRCODE;
+	}
+
+	/*
+	 * All done now!
+	 */
+	ssp->index = 0;
+	ssp->cmdstate = LOMBUS_CMDSTATE_IDLE;
+	cv_broadcast(ssp->lo_cv);
+	mutex_exit(ssp->lo_mutex);
+
+	return (val);
+}
+
+
+/*
+ * Space 0 - LOM virtual register access
+ * Only 8-bit accesses are supported.
+ */
+static uint8_t
+lombus_vreg_get8(HANDLE_TYPE *hdlp, uint8_t *addr)
+{
+	ptrdiff_t offset;
+
+	/*
+	 * Check the offset that the caller has added to the base address
+	 * against the length of the mapping originally requested.
+	 */
+	offset = ADDR_TO_OFFSET(addr, hdlp);
+	if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) {
+		/*
+		 * Invalid access - flag a fault and return a dummy value
+		 */
+		HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
+		return (DUMMY_VALUE);
+	}
+
+	/*
+	 * Derive the virtual register number and run the command
+	 */
+	return (lombus_cmd(hdlp, ADDR_TO_VREG(addr), 0, LOMBUS_CMD_READ));
+}
+
+static void
+lombus_vreg_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val)
+{
+	ptrdiff_t offset;
+
+	/*
+	 * Check the offset that the caller has added to the base address
+	 * against the length of the mapping originally requested.
+	 */
+	offset = ADDR_TO_OFFSET(addr, hdlp);
+	if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) {
+		/*
+		 * Invalid access - flag a fault and return
+		 */
+		HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
+		return;
+	}
+
+	/*
+	 * Derive the virtual register number and run the command
+	 */
+	(void) lombus_cmd(hdlp, ADDR_TO_VREG(addr), val, LOMBUS_CMD_WRITE);
+}
+
+static void
+lombus_vreg_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
+	uint8_t *dev_addr, size_t repcount, uint_t flags)
+{
+	size_t inc;
+
+	inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
+	for (; repcount--; dev_addr += inc)
+		*host_addr++ = lombus_vreg_get8(hdlp, dev_addr);
+}
+
+static void
+lombus_vreg_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
+	uint8_t *dev_addr, size_t repcount, uint_t flags)
+{
+	size_t inc;
+
+	inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
+	for (; repcount--; dev_addr += inc)
+		lombus_vreg_put8(hdlp, dev_addr, *host_addr++);
+}
+
+
+/*
+ * Space 1 - LOM watchdog pat register access
+ * Only 8-bit accesses are supported.
+ *
+ * Reads have no effect and return 0.
+ *
+ * Writes pat the dog by toggling the RTS line iff enough time has
+ * elapsed since last time we toggled it.
+ *
+ * Multi-byte reads (using ddi_rep_get8(9F)) are a fairly inefficient
+ * way of zeroing the destination area ;-) and still won't pat the dog.
+ *
+ * Multi-byte writes (using ddi_rep_put8(9F)) will almost certainly
+ * only count as a single pat, no matter how many bytes the caller
+ * says to write, as the inter-pat time is VERY long compared with
+ * the time it will take to read the memory source area.
+ */
+
+static uint8_t
+lombus_pat_get8(HANDLE_TYPE *hdlp, uint8_t *addr)
+{
+	ptrdiff_t offset;
+
+	/*
+	 * Check the offset that the caller has added to the base address
+	 * against the length of the mapping originally requested.
+	 */
+	offset = ADDR_TO_OFFSET(addr, hdlp);
+	if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) {
+		/*
+		 * Invalid access - flag a fault and return a dummy value
+		 */
+		HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
+		return (DUMMY_VALUE);
+	}
+
+	return (0);
+}
+
+static void
+lombus_pat_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val)
+{
+	struct lombus_state *ssp;
+	ptrdiff_t offset;
+	hrtime_t now;
+
+	_NOTE(ARGUNUSED(val))
+
+	/*
+	 * Check the offset that the caller has added to the base address
+	 * against the length of the mapping originally requested.
+	 */
+	offset = ADDR_TO_OFFSET(addr, hdlp);
+	if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) {
+		/*
+		 * Invalid access - flag a fault and return
+		 */
+		HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
+		return;
+	}
+
+	ssp = HANDLE_PRIVATE(hdlp);
+	mutex_enter(ssp->hw_mutex);
+	now = gethrtime();
+	if ((now - ssp->hw_last_pat) >= LOMBUS_MIN_PAT) {
+		lombus_toggle_rts(ssp);
+		ssp->hw_last_pat = now;
+	}
+	mutex_exit(ssp->hw_mutex);
+}
+
+static void
+lombus_pat_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
+	uint8_t *dev_addr, size_t repcount, uint_t flags)
+{
+	size_t inc;
+
+	inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
+	for (; repcount--; dev_addr += inc)
+		*host_addr++ = lombus_pat_get8(hdlp, dev_addr);
+}
+
+static void
+lombus_pat_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
+	uint8_t *dev_addr, size_t repcount, uint_t flags)
+{
+	size_t inc;
+
+	inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
+	for (; repcount--; dev_addr += inc)
+		lombus_pat_put8(hdlp, dev_addr, *host_addr++);
+}
+
+
+/*
+ * Space 2 - LOM async event flag register access
+ * Only 16-bit accesses are supported.
+ */
+static uint16_t
+lombus_event_get16(HANDLE_TYPE *hdlp, uint16_t *addr)
+{
+	struct lombus_state *ssp;
+	ptrdiff_t offset;
+
+	/*
+	 * Check the offset that the caller has added to the base address
+	 * against the length of the mapping orignally requested.
+	 */
+	offset = ADDR_TO_OFFSET(addr, hdlp);
+	if (offset < 0 || (offset%2) != 0 || offset >= HANDLE_MAPLEN(hdlp)) {
+		/*
+		 * Invalid access - flag a fault and return a dummy value
+		 */
+		HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
+		return (DUMMY_VALUE);
+	}
+
+	/*
+	 * Return the value of the asynchronous-event-pending flag
+	 * as passed back by the LOM at the end of the last command.
+	 */
+	ssp = HANDLE_PRIVATE(hdlp);
+	return (ssp->async);
+}
+
+static void
+lombus_event_put16(HANDLE_TYPE *hdlp, uint16_t *addr, uint16_t val)
+{
+	ptrdiff_t offset;
+
+	_NOTE(ARGUNUSED(val))
+
+	/*
+	 * Check the offset that the caller has added to the base address
+	 * against the length of the mapping originally requested.
+	 */
+	offset = ADDR_TO_OFFSET(addr, hdlp);
+	if (offset < 0 || (offset%2) != 0 || offset >= HANDLE_MAPLEN(hdlp)) {
+		/*
+		 * Invalid access - flag a fault and return
+		 */
+		HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
+		return;
+	}
+
+	/*
+	 * The user can't overwrite the asynchronous-event-pending flag!
+	 */
+	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_RO;
+}
+
+static void
+lombus_event_rep_get16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
+	uint16_t *dev_addr, size_t repcount, uint_t flags)
+{
+	size_t inc;
+
+	inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
+	for (; repcount--; dev_addr += inc)
+		*host_addr++ = lombus_event_get16(hdlp, dev_addr);
+}
+
+static void
+lombus_event_rep_put16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
+	uint16_t *dev_addr, size_t repcount, uint_t flags)
+{
+	size_t inc;
+
+	inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
+	for (; repcount--; dev_addr += inc)
+		lombus_event_put16(hdlp, dev_addr, *host_addr++);
+}
+
+
+/*
+ * All spaces - access handle fault information
+ * Only 32-bit accesses are supported.
+ */
+static uint32_t
+lombus_meta_get32(HANDLE_TYPE *hdlp, uint32_t *addr)
+{
+	struct lombus_state *ssp;
+	ptrdiff_t offset;
+
+	/*
+	 * Derive the offset that the caller has added to the base
+	 * address originally returned, and use it to determine
+	 * which meta-register is to be accessed ...
+	 */
+	offset = ADDR_TO_OFFSET(addr, hdlp);
+	switch (offset) {
+	case LOMBUS_FAULT_REG:
+		/*
+		 * This meta-register provides a code for the most
+		 * recent virtual register access fault, if any.
+		 */
+		return (HANDLE_FAULT(hdlp));
+
+	case LOMBUS_PROBE_REG:
+		/*
+		 * Reading this meta-register clears any existing fault
+		 * (at the virtual, not the hardware access layer), then
+		 * runs a NOP command and returns the fault code from that.
+		 */
+		HANDLE_FAULT(hdlp) = 0;
+		lombus_cmd(hdlp, 0, 0, LOMBUS_CMD_NOP);
+		return (HANDLE_FAULT(hdlp));
+
+	case LOMBUS_ASYNC_REG:
+		/*
+		 * Obsolescent - but still supported for backwards
+		 * compatibility.  This is an alias for the newer
+		 * LOMBUS_EVENT_REG, but doesn't require a separate
+		 * "reg" entry and ddi_regs_map_setup() call.
+		 *
+		 * It returns the value of the asynchronous-event-pending
+		 * flag as passed back by the LOM at the end of the last
+		 * completed command.
+		 */
+		ssp = HANDLE_PRIVATE(hdlp);
+		return (ssp->async);
+
+	default:
+		/*
+		 * Invalid access - flag a fault and return a dummy value
+		 */
+		HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
+		return (DUMMY_VALUE);
+	}
+}
+
+static void
+lombus_meta_put32(HANDLE_TYPE *hdlp, uint32_t *addr, uint32_t val)
+{
+	ptrdiff_t offset;
+
+	/*
+	 * Derive the offset that the caller has added to the base
+	 * address originally returned, and use it to determine
+	 * which meta-register is to be accessed ...
+	 */
+	offset = ADDR_TO_OFFSET(addr, hdlp);
+	switch (offset) {
+	case LOMBUS_FAULT_REG:
+		/*
+		 * This meta-register contains a code for the most
+		 * recent virtual register access fault, if any.
+		 * It can be cleared simply by writing 0 to it.
+		 */
+		HANDLE_FAULT(hdlp) = val;
+		return;
+
+	case LOMBUS_PROBE_REG:
+		/*
+		 * Writing this meta-register clears any existing fault
+		 * (at the virtual, not the hardware acess layer), then
+		 * runs a NOP command.  The caller can check the fault
+		 * code later if required.
+		 */
+		HANDLE_FAULT(hdlp) = 0;
+		lombus_cmd(hdlp, 0, 0, LOMBUS_CMD_NOP);
+		return;
+
+	default:
+		/*
+		 * Invalid access - flag a fault
+		 */
+		HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
+		return;
+	}
+}
+
+static void
+lombus_meta_rep_get32(HANDLE_TYPE *hdlp, uint32_t *host_addr,
+	uint32_t *dev_addr, size_t repcount, uint_t flags)
+{
+	size_t inc;
+
+	inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
+	for (; repcount--; dev_addr += inc)
+		*host_addr++ = lombus_meta_get32(hdlp, dev_addr);
+}
+
+static void
+lombus_meta_rep_put32(HANDLE_TYPE *hdlp, uint32_t *host_addr,
+	uint32_t *dev_addr, size_t repcount, uint_t flags)
+{
+	size_t inc;
+
+	inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
+	for (; repcount--; dev_addr += inc)
+		lombus_meta_put32(hdlp, dev_addr, *host_addr++);
+}
+
+
+/*
+ * Finally, some dummy functions for all unsupported access
+ * space/size/mode combinations ...
+ */
+static uint8_t
+lombus_no_get8(HANDLE_TYPE *hdlp, uint8_t *addr)
+{
+	_NOTE(ARGUNUSED(addr))
+
+	/*
+	 * Invalid access - flag a fault and return a dummy value
+	 */
+	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
+	return (DUMMY_VALUE);
+}
+
+static void
+lombus_no_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val)
+{
+	_NOTE(ARGUNUSED(addr, val))
+
+	/*
+	 * Invalid access - flag a fault
+	 */
+	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
+}
+
+static void
+lombus_no_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
+		uint8_t *dev_addr, size_t repcount, uint_t flags)
+{
+	_NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
+
+	/*
+	 * Invalid access - flag a fault
+	 */
+	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
+}
+
+static void
+lombus_no_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
+	uint8_t *dev_addr, size_t repcount, uint_t flags)
+{
+	_NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
+
+	/*
+	 * Invalid access - flag a fault
+	 */
+	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
+}
+
+static uint16_t
+lombus_no_get16(HANDLE_TYPE *hdlp, uint16_t *addr)
+{
+	_NOTE(ARGUNUSED(addr))
+
+	/*
+	 * Invalid access - flag a fault and return a dummy value
+	 */
+	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
+	return (DUMMY_VALUE);
+}
+
+static void
+lombus_no_put16(HANDLE_TYPE *hdlp, uint16_t *addr, uint16_t val)
+{
+	_NOTE(ARGUNUSED(addr, val))
+
+	/*
+	 * Invalid access - flag a fault
+	 */
+	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
+}
+
+static void
+lombus_no_rep_get16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
+		uint16_t *dev_addr, size_t repcount, uint_t flags)
+{
+	_NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
+
+	/*
+	 * Invalid access - flag a fault
+	 */
+	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
+}
+
+static void
+lombus_no_rep_put16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
+	uint16_t *dev_addr, size_t repcount, uint_t flags)
+{
+	_NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
+
+	/*
+	 * Invalid access - flag a fault
+	 */
+	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
+}
+
+static uint64_t
+lombus_no_get64(HANDLE_TYPE *hdlp, uint64_t *addr)
+{
+	_NOTE(ARGUNUSED(addr))
+
+	/*
+	 * Invalid access - flag a fault and return a dummy value
+	 */
+	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
+	return (DUMMY_VALUE);
+}
+
+static void
+lombus_no_put64(HANDLE_TYPE *hdlp, uint64_t *addr, uint64_t val)
+{
+	_NOTE(ARGUNUSED(addr, val))
+
+	/*
+	 * Invalid access - flag a fault
+	 */
+	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
+}
+
+static void
+lombus_no_rep_get64(HANDLE_TYPE *hdlp, uint64_t *host_addr,
+	uint64_t *dev_addr, size_t repcount, uint_t flags)
+{
+	_NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
+
+	/*
+	 * Invalid access - flag a fault
+	 */
+	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
+}
+
+static void
+lombus_no_rep_put64(HANDLE_TYPE *hdlp, uint64_t *host_addr,
+	uint64_t *dev_addr, size_t repcount, uint_t flags)
+{
+	_NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
+
+	/*
+	 * Invalid access - flag a fault
+	 */
+	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
+}
+
+static int
+lombus_acc_fault_check(HANDLE_TYPE *hdlp)
+{
+	return (HANDLE_FAULT(hdlp) != 0);
+}
+
+
+/*
+ * Hardware setup - put the SIO chip in the required operational
+ * state,  with all our favourite parameters programmed correctly.
+ * This routine leaves all SIO interrupts disabled.
+ */
+
+static void
+lombus_hw_reset(struct lombus_state *ssp)
+{
+	uint16_t divisor;
+
+	/*
+	 * Disable interrupts, soft reset Tx and Rx circuitry,
+	 * reselect standard modes (bits/char, parity, etc).
+	 */
+	lombus_set_irq(ssp, B_FALSE);
+	sio_put_reg(ssp, SIO_FCR, SIO_FCR_RXSR | SIO_FCR_TXSR);
+	sio_put_reg(ssp, SIO_LCR, SIO_LCR_STD);
+
+	/*
+	 * Select the proper baud rate; if the value is invalid
+	 * (presumably 0, i.e. not specified, but also if the
+	 * "baud" property is set to some silly value), we assume
+	 * the default.
+	 */
+	if (ssp->baud < SIO_BAUD_MIN || ssp->baud > SIO_BAUD_MAX)
+		divisor = SIO_BAUD_TO_DIVISOR(SIO_BAUD_DEFAULT);
+	else
+		divisor = SIO_BAUD_TO_DIVISOR(ssp->baud);
+
+	/*
+	 * According to the datasheet, it is forbidden for the divisor
+	 * register to be zero.  So when loading the register in two
+	 * steps, we have to make sure that the temporary value formed
+	 * between loads is nonzero.  However, we can't rely on either
+	 * half already having a nonzero value, as the datasheet also
+	 * says that these registers are indeterminate after a reset!
+	 * So, we explicitly set the low byte to a non-zero value first;
+	 * then we can safely load the high byte, and then the correct
+	 * value for the low byte, without the result ever being zero.
+	 */
+	sio_put_reg(ssp, SIO_BSR, SIO_BSR_BANK1);
+	sio_put_reg(ssp, SIO_LBGDL, 0xff);
+	sio_put_reg(ssp, SIO_LBGDH, divisor >> 8);
+	sio_put_reg(ssp, SIO_LBGDL, divisor & 0xff);
+	sio_put_reg(ssp, SIO_BSR, SIO_BSR_BANK0);
+
+	/*
+	 * Program the remaining device registers as required
+	 */
+	sio_put_reg(ssp, SIO_MCR, SIO_MCR_STD);
+	sio_put_reg(ssp, SIO_FCR, SIO_FCR_STD);
+}
+
+
+/*
+ * Higher-level setup & teardown
+ */
+
+static void
+lombus_offline(struct lombus_state *ssp)
+{
+	if (ssp->sio_handle != NULL)
+		ddi_regs_map_free(&ssp->sio_handle);
+	ssp->sio_handle = NULL;
+	ssp->sio_regs = NULL;
+}
+
+static int
+lombus_online(struct lombus_state *ssp)
+{
+	ddi_acc_handle_t h;
+	caddr_t p;
+	int nregs;
+	int err;
+
+	if (ddi_dev_nregs(ssp->dip, &nregs) != DDI_SUCCESS)
+		nregs = 0;
+
+	switch (nregs) {
+	default:
+	case 1:
+		/*
+		 *  regset 0 represents the SIO operating registers
+		 */
+		err = ddi_regs_map_setup(ssp->dip, 0, &p, 0, 0,
+		    lombus_dev_acc_attr, &h);
+		lombus_trace(ssp, 'O', "online",
+		    "regmap 0 status %d addr $%p", err, p);
+		if (err != DDI_SUCCESS)
+			return (EIO);
+
+		ssp->sio_handle = h;
+		ssp->sio_regs = (void *)p;
+		break;
+
+	case 0:
+		/*
+		 *  If no registers are defined, succeed vacuously;
+		 *  commands will be accepted, but we fake the accesses.
+		 */
+		break;
+	}
+
+	/*
+	 * Now that the registers are mapped, we can initialise the SIO h/w
+	 */
+	lombus_hw_reset(ssp);
+	return (0);
+}
+
+
+/*
+ *  Nexus routines
+ */
+
+#if	defined(NDI_ACC_HDL_V2)
+
+static const ndi_acc_fns_t lombus_vreg_acc_fns = {
+	NDI_ACC_FNS_CURRENT,
+	NDI_ACC_FNS_V1,
+
+	lombus_vreg_get8,
+	lombus_vreg_put8,
+	lombus_vreg_rep_get8,
+	lombus_vreg_rep_put8,
+
+	lombus_no_get16,
+	lombus_no_put16,
+	lombus_no_rep_get16,
+	lombus_no_rep_put16,
+
+	lombus_meta_get32,
+	lombus_meta_put32,
+	lombus_meta_rep_get32,
+	lombus_meta_rep_put32,
+
+	lombus_no_get64,
+	lombus_no_put64,
+	lombus_no_rep_get64,
+	lombus_no_rep_put64,
+
+	lombus_acc_fault_check
+};
+
+static const ndi_acc_fns_t lombus_pat_acc_fns = {
+	NDI_ACC_FNS_CURRENT,
+	NDI_ACC_FNS_V1,
+
+	lombus_pat_get8,
+	lombus_pat_put8,
+	lombus_pat_rep_get8,
+	lombus_pat_rep_put8,
+
+	lombus_no_get16,
+	lombus_no_put16,
+	lombus_no_rep_get16,
+	lombus_no_rep_put16,
+
+	lombus_meta_get32,
+	lombus_meta_put32,
+	lombus_meta_rep_get32,
+	lombus_meta_rep_put32,
+
+	lombus_no_get64,
+	lombus_no_put64,
+	lombus_no_rep_get64,
+	lombus_no_rep_put64,
+
+	lombus_acc_fault_check
+};
+
+static const ndi_acc_fns_t lombus_event_acc_fns = {
+	NDI_ACC_FNS_CURRENT,
+	NDI_ACC_FNS_V1,
+
+	lombus_no_get8,
+	lombus_no_put8,
+	lombus_no_rep_get8,
+	lombus_no_rep_put8,
+
+	lombus_event_get16,
+	lombus_event_put16,
+	lombus_event_rep_get16,
+	lombus_event_rep_put16,
+
+	lombus_meta_get32,
+	lombus_meta_put32,
+	lombus_meta_rep_get32,
+	lombus_meta_rep_put32,
+
+	lombus_no_get64,
+	lombus_no_put64,
+	lombus_no_rep_get64,
+	lombus_no_rep_put64,
+
+	lombus_acc_fault_check
+};
+
+static int
+lombus_map_handle(struct lombus_state *ssp, ddi_map_op_t op,
+	int space, caddr_t vaddr, off_t len,
+	ndi_acc_handle_t *hdlp, caddr_t *addrp)
+{
+	switch (op) {
+	default:
+		return (DDI_ME_UNIMPLEMENTED);
+
+	case DDI_MO_MAP_LOCKED:
+		switch (space) {
+		default:
+			return (DDI_ME_REGSPEC_RANGE);
+
+		case LOMBUS_VREG_SPACE:
+			ndi_set_acc_fns(hdlp, &lombus_vreg_acc_fns);
+			break;
+
+		case LOMBUS_PAT_SPACE:
+			ndi_set_acc_fns(hdlp, &lombus_pat_acc_fns);
+			break;
+
+		case LOMBUS_EVENT_SPACE:
+			ndi_set_acc_fns(hdlp, &lombus_event_acc_fns);
+			break;
+		}
+		hdlp->ah_addr = *addrp = vaddr;
+		hdlp->ah_len = len;
+		hdlp->ah_bus_private = ssp;
+		return (DDI_SUCCESS);
+
+	case DDI_MO_UNMAP:
+		*addrp = NULL;
+		hdlp->ah_bus_private = NULL;
+		return (DDI_SUCCESS);
+	}
+}
+
+#else
+
+static int
+lombus_map_handle(struct lombus_state *ssp, ddi_map_op_t op,
+	int space, caddr_t vaddr, off_t len,
+	ddi_acc_hdl_t *hdlp, caddr_t *addrp)
+{
+	ddi_acc_impl_t *aip = hdlp->ah_platform_private;
+
+	switch (op) {
+	default:
+		return (DDI_ME_UNIMPLEMENTED);
+
+	case DDI_MO_MAP_LOCKED:
+		switch (space) {
+		default:
+			return (DDI_ME_REGSPEC_RANGE);
+
+		case LOMBUS_VREG_SPACE:
+			aip->ahi_get8 = lombus_vreg_get8;
+			aip->ahi_put8 = lombus_vreg_put8;
+			aip->ahi_rep_get8 = lombus_vreg_rep_get8;
+			aip->ahi_rep_put8 = lombus_vreg_rep_put8;
+
+			aip->ahi_get16 = lombus_no_get16;
+			aip->ahi_put16 = lombus_no_put16;
+			aip->ahi_rep_get16 = lombus_no_rep_get16;
+			aip->ahi_rep_put16 = lombus_no_rep_put16;
+
+			aip->ahi_get32 = lombus_meta_get32;
+			aip->ahi_put32 = lombus_meta_put32;
+			aip->ahi_rep_get32 = lombus_meta_rep_get32;
+			aip->ahi_rep_put32 = lombus_meta_rep_put32;
+
+			aip->ahi_get64 = lombus_no_get64;
+			aip->ahi_put64 = lombus_no_put64;
+			aip->ahi_rep_get64 = lombus_no_rep_get64;
+			aip->ahi_rep_put64 = lombus_no_rep_put64;
+
+			aip->ahi_fault_check = lombus_acc_fault_check;
+			break;
+
+		case LOMBUS_PAT_SPACE:
+			aip->ahi_get8 = lombus_pat_get8;
+			aip->ahi_put8 = lombus_pat_put8;
+			aip->ahi_rep_get8 = lombus_pat_rep_get8;
+			aip->ahi_rep_put8 = lombus_pat_rep_put8;
+
+			aip->ahi_get16 = lombus_no_get16;
+			aip->ahi_put16 = lombus_no_put16;
+			aip->ahi_rep_get16 = lombus_no_rep_get16;
+			aip->ahi_rep_put16 = lombus_no_rep_put16;
+
+			aip->ahi_get32 = lombus_meta_get32;
+			aip->ahi_put32 = lombus_meta_put32;
+			aip->ahi_rep_get32 = lombus_meta_rep_get32;
+			aip->ahi_rep_put32 = lombus_meta_rep_put32;
+
+			aip->ahi_get64 = lombus_no_get64;
+			aip->ahi_put64 = lombus_no_put64;
+			aip->ahi_rep_get64 = lombus_no_rep_get64;
+			aip->ahi_rep_put64 = lombus_no_rep_put64;
+
+			aip->ahi_fault_check = lombus_acc_fault_check;
+			break;
+
+		case LOMBUS_EVENT_SPACE:
+			aip->ahi_get8 = lombus_no_get8;
+			aip->ahi_put8 = lombus_no_put8;
+			aip->ahi_rep_get8 = lombus_no_rep_get8;
+			aip->ahi_rep_put8 = lombus_no_rep_put8;
+
+			aip->ahi_get16 = lombus_event_get16;
+			aip->ahi_put16 = lombus_event_put16;
+			aip->ahi_rep_get16 = lombus_event_rep_get16;
+			aip->ahi_rep_put16 = lombus_event_rep_put16;
+
+			aip->ahi_get32 = lombus_meta_get32;
+			aip->ahi_put32 = lombus_meta_put32;
+			aip->ahi_rep_get32 = lombus_meta_rep_get32;
+			aip->ahi_rep_put32 = lombus_meta_rep_put32;
+
+			aip->ahi_get64 = lombus_no_get64;
+			aip->ahi_put64 = lombus_no_put64;
+			aip->ahi_rep_get64 = lombus_no_rep_get64;
+			aip->ahi_rep_put64 = lombus_no_rep_put64;
+
+			aip->ahi_fault_check = lombus_acc_fault_check;
+			break;
+		}
+		hdlp->ah_addr = *addrp = vaddr;
+		hdlp->ah_len = len;
+		hdlp->ah_bus_private = ssp;
+		return (DDI_SUCCESS);
+
+	case DDI_MO_UNMAP:
+		*addrp = NULL;
+		hdlp->ah_bus_private = NULL;
+		return (DDI_SUCCESS);
+	}
+}
+
+#endif	/* NDI_ACC_HDL_V2 */
+
+static int
+lombus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
+	off_t off, off_t len, caddr_t *addrp)
+{
+	struct lombus_child_info *lcip;
+	struct lombus_state *ssp;
+	lombus_regspec_t *rsp;
+
+	if ((ssp = lombus_getstate(dip, -1, "lombus_map")) == NULL)
+		return (DDI_FAILURE);	/* this "can't happen" */
+
+	/*
+	 * Validate mapping request ...
+	 */
+
+	if (mp->map_flags != DDI_MF_KERNEL_MAPPING)
+		return (DDI_ME_UNSUPPORTED);
+	if (mp->map_handlep == NULL)
+		return (DDI_ME_UNSUPPORTED);
+	if (mp->map_type != DDI_MT_RNUMBER)
+		return (DDI_ME_UNIMPLEMENTED);
+	if ((lcip = ddi_get_parent_data(rdip)) == NULL)
+		return (DDI_ME_INVAL);
+	if ((rsp = lcip->rsp) == NULL)
+		return (DDI_ME_INVAL);
+	if (mp->map_obj.rnumber >= lcip->nregs)
+		return (DDI_ME_RNUMBER_RANGE);
+	rsp += mp->map_obj.rnumber;
+	if (off < 0 || off >= rsp->lombus_size)
+		return (DDI_ME_INVAL);
+	if (len == 0)
+		len = rsp->lombus_size-off;
+	if (len < 0)
+		return (DDI_ME_INVAL);
+	if (off+len < 0 || off+len > rsp->lombus_size)
+		return (DDI_ME_INVAL);
+
+	return (lombus_map_handle(ssp, mp->map_op,
+		rsp->lombus_space, VREG_TO_ADDR(rsp->lombus_base+off), len,
+		mp->map_handlep, addrp));
+}
+
+static int
+lombus_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op,
+	void *arg, void *result)
+{
+	struct lombus_child_info *lcip;
+	struct lombus_state *ssp;
+	lombus_regspec_t *rsp;
+	dev_info_t *cdip;
+	char addr[32];
+	uint_t nregs;
+	uint_t rnum;
+	int *regs;
+	int limit;
+	int err;
+	int i;
+
+	if ((ssp = lombus_getstate(dip, -1, "lombus_ctlops")) == NULL)
+		return (DDI_FAILURE);	/* this "can't happen" */
+
+	switch (op) {
+	default:
+		break;
+
+	case DDI_CTLOPS_INITCHILD:
+		/*
+		 * First, look up and validate the "reg" property.
+		 *
+		 * It must be a non-empty integer array containing a set
+		 * of triples.  Once we've verified that, we can treat it
+		 * as an array of type lombus_regspec_t[], which defines
+		 * the meaning of the elements of each triple:
+		 * +  the first element of each triple must be a valid space
+		 * +  the second and third elements (base, size) of each
+		 *	triple must define a valid subrange of that space
+		 * If it passes all the tests, we save it away for future
+		 * reference in the child's parent-private-data field.
+		 */
+		cdip = arg;
+		err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
+			DDI_PROP_DONTPASS, "reg", &regs, &nregs);
+		lombus_trace(ssp, 'C', "initchild",
+		    "prop status %d size %d", err, nregs);
+		if (err != DDI_PROP_SUCCESS)
+			return (DDI_FAILURE);
+
+		err = (nregs <= 0 || (nregs % LOMBUS_REGSPEC_SIZE) != 0);
+		nregs /= LOMBUS_REGSPEC_SIZE;
+		rsp = (lombus_regspec_t *)regs;
+		for (i = 0; i < nregs && !err; ++i) {
+			switch (rsp[i].lombus_space) {
+			default:
+				limit = 0;
+				err = 1;
+				break;
+
+			case LOMBUS_VREG_SPACE:
+				limit = LOMBUS_MAX_REG+1;
+				break;
+
+			case LOMBUS_PAT_SPACE:
+				limit = LOMBUS_PAT_REG+1;
+				break;
+
+			case LOMBUS_EVENT_SPACE:
+				limit = LOMBUS_EVENT_REG+1;
+				break;
+			}
+
+			err |= (rsp[i].lombus_base < 0);
+			err |= (rsp[i].lombus_base >= limit);
+
+			if (rsp[i].lombus_size == 0)
+				rsp[i].lombus_size = limit-rsp[i].lombus_base;
+			err |= (rsp[i].lombus_size < 0);
+
+			err |= (rsp[i].lombus_base+rsp[i].lombus_size < 0);
+			err |= (rsp[i].lombus_base+rsp[i].lombus_size > limit);
+		}
+
+		if (err) {
+			ddi_prop_free(regs);
+			return (DDI_FAILURE);
+		}
+
+		lcip = kmem_zalloc(sizeof (*lcip), KM_SLEEP);
+		lcip->nregs = nregs;
+		lcip->rsp = rsp;
+		ddi_set_parent_data(cdip, lcip);
+
+		(void) snprintf(addr, sizeof (addr),
+			"%x,%x", rsp[0].lombus_space, rsp[0].lombus_base);
+		ddi_set_name_addr(cdip, addr);
+
+		return (DDI_SUCCESS);
+
+	case DDI_CTLOPS_UNINITCHILD:
+		cdip = arg;
+		ddi_set_name_addr(cdip, NULL);
+		lcip = ddi_get_parent_data(cdip);
+		ddi_set_parent_data(cdip, NULL);
+		ddi_prop_free(lcip->rsp);
+		kmem_free(lcip, sizeof (*lcip));
+		return (DDI_SUCCESS);
+
+	case DDI_CTLOPS_REPORTDEV:
+		if (rdip == NULL)
+			return (DDI_FAILURE);
+
+		cmn_err(CE_CONT, "?LOM device: %s@%s, %s#%d\n",
+			ddi_node_name(rdip), ddi_get_name_addr(rdip),
+			ddi_driver_name(dip), ddi_get_instance(dip));
+
+		return (DDI_SUCCESS);
+
+	case DDI_CTLOPS_REGSIZE:
+		if ((lcip = ddi_get_parent_data(rdip)) == NULL)
+			return (DDI_FAILURE);
+		if ((rnum = *(uint_t *)arg) >= lcip->nregs)
+			return (DDI_FAILURE);
+		*(off_t *)result = lcip->rsp[rnum].lombus_size;
+		return (DDI_SUCCESS);
+
+	case DDI_CTLOPS_NREGS:
+		if ((lcip = ddi_get_parent_data(rdip)) == NULL)
+			return (DDI_FAILURE);
+		*(int *)result = lcip->nregs;
+		return (DDI_SUCCESS);
+	}
+
+	return (ddi_ctlops(dip, rdip, op, arg, result));
+}
+
+
+/*
+ *  Clean up on detach or failure of attach
+ */
+static int
+lombus_unattach(struct lombus_state *ssp, int instance)
+{
+	if (ssp != NULL) {
+		lombus_hw_reset(ssp);
+		if (ssp->cycid != CYCLIC_NONE) {
+			mutex_enter(&cpu_lock);
+			cyclic_remove(ssp->cycid);
+			mutex_exit(&cpu_lock);
+			if (ssp->sio_handle != NULL)
+				ddi_remove_intr(ssp->dip, 0, ssp->hw_iblk);
+			ddi_remove_softintr(ssp->softid);
+			cv_destroy(ssp->lo_cv);
+			mutex_destroy(ssp->lo_mutex);
+			mutex_destroy(ssp->hw_mutex);
+		}
+		lombus_offline(ssp);
+		ddi_set_driver_private(ssp->dip, NULL);
+	}
+
+	ddi_soft_state_free(lombus_statep, instance);
+	return (DDI_FAILURE);
+}
+
+/*
+ *  Autoconfiguration routines
+ */
+
+static int
+lombus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	struct lombus_state *ssp = NULL;
+	cyc_handler_t cychand;
+	cyc_time_t cyctime;
+	int instance;
+	int err;
+
+	switch (cmd) {
+	default:
+		return (DDI_FAILURE);
+
+	case DDI_ATTACH:
+		break;
+	}
+
+	/*
+	 *  Allocate the soft-state structure
+	 */
+	instance = ddi_get_instance(dip);
+	if (ddi_soft_state_zalloc(lombus_statep, instance) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+	if ((ssp = lombus_getstate(dip, instance, "lombus_attach")) == NULL)
+		return (lombus_unattach(ssp, instance));
+	ddi_set_driver_private(dip, ssp);
+
+	/*
+	 *  Initialise devinfo-related fields
+	 */
+	ssp->dip = dip;
+	ssp->majornum = ddi_driver_major(dip);
+	ssp->instance = instance;
+
+	/*
+	 *  Set various options from .conf properties
+	 */
+	ssp->allow_echo = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+			DDI_PROP_DONTPASS, "allow-lom-echo", 0) != 0;
+	ssp->baud = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+			DDI_PROP_DONTPASS, "baud-rate", 0);
+	ssp->debug = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+			DDI_PROP_DONTPASS, "debug", 0);
+	ssp->fake_cts = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+			DDI_PROP_DONTPASS, "fake-cts", 0) != 0;
+
+	/*
+	 * Initialise current state & time
+	 */
+	ssp->cmdstate = LOMBUS_CMDSTATE_IDLE;
+	ssp->hw_last_pat = gethrtime();
+	ssp->cycid = CYCLIC_NONE;
+
+	/*
+	 *  Online the hardware ...
+	 */
+	err = lombus_online(ssp);
+	if (err != 0)
+		return (lombus_unattach(ssp, instance));
+
+	/*
+	 * Install soft and hard interrupt handler(s)
+	 * Initialise mutexes and cv
+	 * Start cyclic callbacks
+	 * Enable interrupts
+	 */
+	err = ddi_add_softintr(dip, DDI_SOFTINT_LOW, &ssp->softid,
+		&ssp->lo_iblk, NULL, lombus_softint, (caddr_t)ssp);
+	if (err != DDI_SUCCESS)
+		return (lombus_unattach(ssp, instance));
+
+	if (ssp->sio_handle != NULL)
+		err = ddi_add_intr(dip, 0, &ssp->hw_iblk, NULL,
+			lombus_hi_intr, (caddr_t)ssp);
+
+	mutex_init(ssp->hw_mutex, NULL, MUTEX_DRIVER, ssp->hw_iblk);
+	mutex_init(ssp->lo_mutex, NULL, MUTEX_DRIVER, ssp->lo_iblk);
+	cv_init(ssp->lo_cv, NULL, CV_DRIVER, NULL);
+
+	cychand.cyh_func = lombus_cyclic;
+	cychand.cyh_arg = ssp;
+	cychand.cyh_level = CY_LOW_LEVEL;
+	cyctime.cyt_when = 0;			/* from the next second	*/
+	cyctime.cyt_interval = LOMBUS_ONE_SEC;	/* call at 1s intervals	*/
+	mutex_enter(&cpu_lock);
+	ssp->cycid = cyclic_add(&cychand, &cyctime);
+	mutex_exit(&cpu_lock);
+
+	/*
+	 * Final check before enabling h/w interrupts - did
+	 * we successfully install the h/w interrupt handler?
+	 */
+	if (err != DDI_SUCCESS)
+		return (lombus_unattach(ssp, instance));
+
+	lombus_set_irq(ssp, B_TRUE);
+
+	/*
+	 *  All done, report success
+	 */
+	ddi_report_dev(dip);
+	return (DDI_SUCCESS);
+}
+
+
+static int
+lombus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+	struct lombus_state *ssp;
+	int instance;
+
+	switch (cmd) {
+	default:
+		return (DDI_FAILURE);
+
+	case DDI_DETACH:
+		break;
+	}
+
+	instance = ddi_get_instance(dip);
+	if ((ssp = lombus_getstate(dip, instance, "lombus_detach")) == NULL)
+		return (DDI_FAILURE);	/* this "can't happen" */
+
+	(void) lombus_unattach(ssp, instance);
+	return (DDI_SUCCESS);
+}
+
+static int
+lombus_reset(dev_info_t *dip, ddi_reset_cmd_t cmd)
+{
+	struct lombus_state *ssp;
+
+	_NOTE(ARGUNUSED(cmd))
+
+	if ((ssp = lombus_getstate(dip, -1, "lombus_reset")) == NULL)
+		return (DDI_FAILURE);
+
+	lombus_hw_reset(ssp);
+	return (DDI_SUCCESS);
+}
+
+
+/*
+ * System interface structures
+ */
+
+static struct cb_ops lombus_cb_ops =
+{
+	nodev,			/* b/c open	*/
+	nodev,			/* b/c close	*/
+	nodev,			/* b   strategy	*/
+	nodev,			/* b   print	*/
+	nodev,			/* b   dump 	*/
+	nodev,			/* c   read	*/
+	nodev,			/* c   write	*/
+	nodev,			/* c   ioctl	*/
+	nodev,			/* c   devmap	*/
+	nodev,			/* c   mmap	*/
+	nodev,			/* c   segmap	*/
+	nochpoll,		/* c   poll	*/
+	ddi_prop_op,		/* b/c prop_op	*/
+	NULL,			/* c   streamtab */
+	D_MP | D_NEW		/* b/c flags	*/
+};
+
+static struct bus_ops lombus_bus_ops =
+{
+	BUSO_REV,			/* revision		*/
+	lombus_map,			/* bus_map		*/
+	0,				/* get_intrspec		*/
+	0,				/* add_intrspec		*/
+	0,				/* remove_intrspec	*/
+	i_ddi_map_fault,		/* map_fault		*/
+	ddi_no_dma_map,			/* dma_map		*/
+	ddi_no_dma_allochdl,		/* allocate DMA handle	*/
+	ddi_no_dma_freehdl,		/* free DMA handle	*/
+	ddi_no_dma_bindhdl,		/* bind DMA handle	*/
+	ddi_no_dma_unbindhdl,		/* unbind DMA handle	*/
+	ddi_no_dma_flush,		/* flush DMA		*/
+	ddi_no_dma_win,			/* move DMA window	*/
+	ddi_no_dma_mctl,		/* generic DMA control	*/
+	lombus_ctlops,			/* generic control	*/
+	ddi_bus_prop_op,		/* prop_op		*/
+	ndi_busop_get_eventcookie,	/* get_eventcookie	*/
+	ndi_busop_add_eventcall,	/* add_eventcall	*/
+	ndi_busop_remove_eventcall,	/* remove_eventcall	*/
+	ndi_post_event,			/* post_event		*/
+	0,				/* interrupt control	*/
+	0,				/* bus_config		*/
+	0,				/* bus_unconfig		*/
+	0,				/* bus_fm_init		*/
+	0,				/* bus_fm_fini		*/
+	0,				/* bus_fm_access_enter	*/
+	0,				/* bus_fm_access_exit	*/
+	0,				/* bus_power		*/
+	i_ddi_intr_ops			/* bus_intr_op		*/
+};
+
+static struct dev_ops lombus_dev_ops =
+{
+	DEVO_REV,
+	0,				/* refcount		*/
+	ddi_no_info,			/* getinfo		*/
+	nulldev,			/* identify		*/
+	nulldev,			/* probe		*/
+	lombus_attach,			/* attach		*/
+	lombus_detach,			/* detach		*/
+	lombus_reset,			/* reset		*/
+	&lombus_cb_ops,			/* driver operations	*/
+	&lombus_bus_ops			/* bus operations	*/
+};
+
+static struct modldrv modldrv =
+{
+	&mod_driverops,
+	"lombus driver, v%I%",
+	&lombus_dev_ops
+};
+
+static struct modlinkage modlinkage =
+{
+	MODREV_1,
+	{
+		&modldrv,
+		NULL
+	}
+};
+
+
+/*
+ *  Dynamic loader interface code
+ */
+
+int
+_init(void)
+{
+	int err;
+
+	err = ddi_soft_state_init(&lombus_statep,
+		sizeof (struct lombus_state), 0);
+	if (err == DDI_SUCCESS)
+		if ((err = mod_install(&modlinkage)) != 0) {
+			ddi_soft_state_fini(&lombus_statep);
+		}
+
+	return (err);
+}
+
+int
+_info(struct modinfo *mip)
+{
+	return (mod_info(&modlinkage, mip));
+}
+
+int
+_fini(void)
+{
+	int err;
+
+	if ((err = mod_remove(&modlinkage)) == 0) {
+		ddi_soft_state_fini(&lombus_statep);
+		lombus_major = NOMAJOR;
+	}
+
+	return (err);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/lw2plus/io/lombus.conf	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,67 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2001 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Configuration file for "lombus" driver
+#
+
+#
+# The following are needed by our parent (ebus), but OBP should
+# have already created them.  So they should only be specified
+# here if you have an old version of OBP that didn't do this ...
+#
+#device_type = "serial";
+#interrupts = 1;
+
+#
+# Various debugging options interpreted by the lombus driver itself ...
+#
+# 'allow-lom-echo' (boolean) tells the driver to look for and filter
+# out echoes of its own messages to the LOM.  Only useful if the LOM
+# has been configured to echo messages!
+#
+#allow-lom-echo = 0;
+#
+# 'baud-rate' (int) specifies the speed of the serial link between
+# the host and the LOM.  Obviously, it must be the same as the value
+# selected by the LOM; getting it wrong will prevent any communication
+# with the LOM.  The default is 38400, which is the value used by the
+# standard version of the LOM firmware.
+#
+#baud-rate = 38400;
+#
+# 'debug' (int) is a bit-mask for turning on various traces from
+# different parts of the driver.  Only available if the driver
+# was compiled with DEBUG enabled.
+#
+#debug = 0;
+#
+# 'fake-cts' (boolean) tells the driver to ignore the CTS signal from
+# the LOM that's usually used for flow control and to show that the
+# LOM is ready for the next message.  Only useful for debugging.
+#
+#fake-cts = 0;
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/lw2plus/lombus/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,99 @@
+#
+# 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.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of the lombus driver kernel
+#	module in the sun4u LW2plus systems
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE   = ../../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= lombus
+OBJECTS		= $(LOMBUS_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(LOMBUS_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_LW2PLUS_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/sun4u/lw2plus/io
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sun4u/lw2plus/Makefile.lw2plus
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+#	Overrides
+#
+ALL_BUILDS	= $(ALL_BUILDSONLY64)
+DEF_BUILDS	= $(DEF_BUILDSONLY64)
+CLEANLINTFILES	+= $(LINT32_FILES)
+
+#
+# lint pass one enforcement
+#
+CFLAGS		+= $(CCVERBOSE)
+
+#
+# Turn on doubleword alignment for 64 bit registers
+#
+CFLAGS		+= -dalign
+
+#
+#	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)/sun4u/lw2plus/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/rmclomv/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,93 @@
+#
+# 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.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of the rmclomv driver kernel
+#	module in the sun4u systems
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	  = ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= rmclomv
+OBJECTS		= $(RMCLOMV_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(RMCLOMV_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_PSM_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/sun4u/io
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sun4u/Makefile.sun4u
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+# lint pass one enforcement
+#
+CFLAGS		+= $(CCVERBOSE)
+LDFLAGS += -dy -Ndrv/rmc_comm -Ndrv/pmugpio
+
+#
+# Turn on doubleword alignment for 64 bit registers
+#
+CFLAGS		+= -dalign
+
+#
+#	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)/sun4u/Makefile.targ
--- a/usr/src/uts/sun4u/sunfire/Makefile.files	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/uts/sun4u/sunfire/Makefile.files	Thu Jun 29 14:43:12 2006 -0700
@@ -40,6 +40,8 @@
 
 AC_OBJS         += ac.o ac_stat.o ac_add.o ac_del.o ac_test.o ac_asm.o
 
+CENTRAL_OBJS	+= central.o
+
 ENVIRON_OBJS	+= environ.o
 
 SYSCTRL_OBJS	+= sysctrl.o sysctrl_quiesce.o sysctrl_dr.o sysctrl_asm.o
--- a/usr/src/uts/sun4u/sunfire/Makefile.sunfire.shared	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/uts/sun4u/sunfire/Makefile.sunfire.shared	Thu Jun 29 14:43:12 2006 -0700
@@ -70,7 +70,6 @@
 #
 #	Define modules (must come after Makefile.sun4u for CLOSED_BUILD).
 #
-SUNFIRE_KMODS			= ac environ fhc simmstat sysctrl sram
+SUNFIRE_KMODS			= ac central environ fhc simmstat sysctrl sram
 $(CLOSED_BUILD)CLOSED_SUNFIRE_KMODS	= platmod
-$(CLOSED_BUILD)CLOSED_SUNFIRE_KMODS	+= central
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/sunfire/central/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,93 @@
+#
+# 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.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of the central driver kernel
+#	module.
+#
+#	sun4u 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		= central
+OBJECTS		= $(CENTRAL_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(CENTRAL_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_SUNFIRE_DRV_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sun4u/sunfire/Makefile.sunfire
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+# lint pass one enforcement
+#
+CFLAGS += $(CCVERBOSE)
+
+#
+# Turn on doubleword alignment for 64 bit registers
+#
+CFLAGS += -dalign
+
+#
+#	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)/sun4u/sunfire/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/sunfire/io/central.c	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,187 @@
+/*
+ * 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 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/conf.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/ddi_subrdefs.h>
+#include <sys/obpdefs.h>
+#include <sys/cmn_err.h>
+#include <sys/errno.h>
+#include <sys/kmem.h>
+#include <sys/debug.h>
+#include <sys/sysmacros.h>
+#include <sys/autoconf.h>
+#include <sys/modctl.h>
+
+/*
+ * module central.c
+ *
+ * This module is a nexus driver designed to support the fhc nexus driver
+ * and all children below it. This driver does not handle any of the
+ * DDI functions passed up to it by the fhc driver, but instead allows
+ * them to bubble up to the root node. A consequence of this is that
+ * the maintainer of this code must watch for changes in the sun4u
+ * rootnexus driver to make sure they do not break this driver or any
+ * of its children.
+ */
+
+/*
+ * Function Prototypes
+ */
+static int
+central_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
+
+static int
+central_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
+
+/*
+ * Configuration Data Structures
+ */
+static struct bus_ops central_bus_ops = {
+	BUSO_REV,
+	ddi_bus_map,		/* map */
+	0,			/* get_intrspec */
+	0,			/* add_intrspec */
+	0,			/* remove_intrspec */
+	i_ddi_map_fault,	/* map_fault */
+	ddi_no_dma_map,		/* dma_map */
+	ddi_no_dma_allochdl,
+	ddi_no_dma_freehdl,
+	ddi_no_dma_bindhdl,
+	ddi_no_dma_unbindhdl,
+	ddi_no_dma_flush,
+	ddi_no_dma_win,
+	ddi_dma_mctl,		/* dma_ctl */
+	ddi_ctlops,		/* ctl */
+	ddi_bus_prop_op,	/* 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)();		*/
+	0,			/* (*bus_fm_init)();		*/
+	0,			/* (*bus_fm_fini)();		*/
+	0,			/* (*bus_fm_access_enter)();	*/
+	0,			/* (*bus_fm_access_exit)();	*/
+	0,			/* (*bus_power)();		*/
+	i_ddi_intr_ops		/* (*bus_intr_op)();		*/
+};
+
+static struct dev_ops central_ops = {
+	DEVO_REV,		/* rev */
+	0,			/* refcnt */
+	ddi_no_info,		/* getinfo */
+	nulldev,		/* identify */
+	nulldev,		/* probe */
+	central_attach,		/* attach */
+	central_detach,		/* detach */
+	nulldev,		/* reset */
+	(struct cb_ops *)0,	/* cb_ops */
+	&central_bus_ops,	/* bus_ops */
+	nulldev			/* power */
+};
+
+extern struct mod_ops mod_driverops;
+
+static struct modldrv modldrv = {
+	&mod_driverops,		/* Type of module.  This one is a driver */
+	"Central Nexus %I%",	/* Name of module. */
+	&central_ops,		/* driver ops */
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1,		/* rev */
+	(void *)&modldrv,
+	NULL
+};
+
+/*
+ * These are the module initialization routines.
+ */
+
+int
+_init(void)
+{
+	return (mod_install(&modlinkage));
+}
+
+int
+_fini(void)
+{
+	int error;
+
+	if ((error = mod_remove(&modlinkage)) != 0)
+		return (error);
+
+	return (0);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+static int
+central_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
+{
+	switch (cmd) {
+	case DDI_ATTACH:
+		break;
+
+	case DDI_RESUME:
+		return (DDI_SUCCESS);
+
+	default:
+		return (DDI_FAILURE);
+	}
+
+	/* nothing to suspend/resume here */
+	(void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
+		"pm-hardware-state", "no-suspend-resume");
+
+	ddi_report_dev(devi);
+	return (DDI_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+central_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
+{
+	switch (cmd) {
+	case DDI_SUSPEND:
+	case DDI_DETACH:
+	default:
+		return (DDI_FAILURE);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/sys/rmclomv_impl.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,117 @@
+/*
+ * 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 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_RMCLOMV_IMPL_H
+#define	_SYS_RMCLOMV_IMPL_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/envmon.h>
+
+/*
+ * local driver defines and structures
+ */
+
+#define	RMCLOMV_DEFAULT_MAX_MBOX_WAIT_TIME	10000
+#define	RMCLOMV_MIN_LED_STATE			0
+#define	RMCLOMV_MAX_LED_STATE			2
+/*
+ * These are PSU flag bits that map to voltage-indicators:
+ * DP_PSU_OUTPUT_STATUS
+ * DP_PSU_INPUT_STATUS
+ * DP_PSU_SEC_INPUT_STATUS
+ * DP_PSU_OUTPUT_VLO_STATUS
+ * DP_PSU_OUTPUT_VHI_STATUS
+ */
+#define	RMCLOMV_MAX_VI_PER_PSU			5
+
+/*
+ * Current indicators:
+ * DP_PSU_OUTPUT_AHI_STATUS
+ * DP_PSU_NR_WARNING
+ */
+#define	RMCLOMV_MAX_CI_PER_PSU			2
+
+/*
+ * Fan indicators:
+ * DP_PSU_FAN_FAULT
+ * DP_PSU_PDCT_FAN
+ */
+#define	RMCLOMV_MAX_FI_PER_PSU			2
+
+/*
+ * Temperature indicators:
+ * DP_PSU_OVERTEMP_FAULT
+ */
+#define	RMCLOMV_MAX_TI_PER_PSU			1
+
+#define	RMCLOMV_NUM_SPECIAL_FRUS		1
+#define	RMCLOMV_MIN_ALARM_STATE			0
+#define	RMCLOMV_MAX_ALARM_STATE			1
+
+/*
+ * defines for various environmental detectors
+ */
+#define	RMCLOMV_ANY_ENV		0
+#define	RMCLOMV_TEMP_SENS	1
+#define	RMCLOMV_FAN_SENS	2
+#define	RMCLOMV_PSU_IND		3
+#define	RMCLOMV_LED_IND		4
+#define	RMCLOMV_VOLT_SENS	5
+#define	RMCLOMV_HPU_IND		6
+#define	RMCLOMV_AMP_IND		7
+#define	RMCLOMV_VOLT_IND	8
+#define	RMCLOMV_TEMP_IND	9
+#define	RMCLOMV_FAN_IND		10
+#define	RMCLOMV_ALARM_IND	11
+
+typedef struct {
+	dp_handle_t	handle;
+	uint16_t	ind_mask;
+	envmon_handle_t	handle_name;
+} rmclomv_cache_entry_t;
+
+/*
+ * section_len is used when freeing the structure.
+ * It includes unused entries whereas num_entries does not.
+ */
+typedef struct rmclomv_cache_section {
+	struct rmclomv_cache_section	*next_section;
+	size_t				section_len;
+	uint16_t			sensor_type;
+	uint16_t			num_entries;
+	rmclomv_cache_entry_t		entry[1];
+} rmclomv_cache_section_t;
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_RMCLOMV_IMPL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/sys/wrsmd.h	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,997 @@
+/*
+ * 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 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * DLPI driver for RSM over Wildcat
+ */
+
+#ifndef	_SYS_WRSMD_H_
+#define	_SYS_WRSMD_H_
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/ethernet.h>
+#include <sys/rsm/rsmpi.h>
+
+/*
+ * This driver is only supported on sparc systems, so there is no
+ * need to worry about byte ordering issues.
+ * However, need to update this version number whenever there is a
+ * change in the layout of wrsmd remote shared memory that could
+ * lead to incompatibilities between systems.
+ */
+
+#define	WRSMD_VERSION	(2)
+
+/*
+ * static limits
+ */
+
+#define	WRSMD_DUMP_IOCTL (5618)
+#define	WRSMD_DUMP_DEST  (5619)
+
+#define	RSM_MAX_DESTADDR 256	/* Wildcat maximum -- (must be power of 2) */
+
+#define	RSM_DLPI_QPRI	8	/* XXX what is the priority range?? */
+#define	RSM_DLPI_QDEPTH	100
+#define	RSM_DLPI_QFLAGS	(RSM_INTR_SEND_Q_NO_FENCE)
+
+#ifdef	_KERNEL
+
+#define	WRSMD_CACHELINE_SIZE	(0x40)
+#define	WRSMD_CACHELINE_SHIFT	6
+#define	WRSMD_CACHELINE_OFFSET	(WRSMD_CACHELINE_SIZE - 1)
+#define	WRSMD_CACHELINE_MASK	(~WRSMD_CACHELINE_OFFSET)
+#define	WRSMD_CACHELINE_ROUNDUP(b) \
+	(((uint64_t)(b) + WRSMD_CACHELINE_OFFSET) & WRSMD_CACHELINE_MASK)
+
+
+
+/*
+ * Use the same format address as ethernet when interacting with higher
+ * level modules.
+ */
+typedef struct dl_rsm_addr {
+	union {
+		rsm_addr_t rsm;		/* real RSM HW address */
+		struct {
+			unsigned char zeroes[7];
+			unsigned char addr;
+		} wrsm;
+		struct {		/* address in ethernet format */
+			ushort_t zero;
+			struct ether_addr addr;
+		} ether;
+	} m;
+} dl_rsm_addr_t;
+
+
+
+/*
+ * Declarations specific to the medium
+ */
+
+#define	MEDIUM_MTU	(64*1024-1)	/* max frame w/o header */
+#define	MEDIUM_MIN	(1)		/* min frame w/header w/o fcs */
+
+#define	MEDIUMSAP_MAX	(0xffff)	/* max valid medium sap */
+
+
+/*
+ * Definitions for module_info.
+ */
+
+#define	WRSMDIDNUM	(726)		/* module ID number */
+#define	WRSMDNAME	"wrsmd"		/* module name */
+#define	WRSMDMINPSZ	(0)		/* min packet size */
+#define	WRSMDMAXPSZ	(65536)		/* max packet size */
+#define	WRSMDHIWAT	(65536)		/* hi-water mark */
+#define	WRSMDLOWAT	(1)		/* lo-water mark */
+
+/*
+ * Driver parameters, from .conf file
+ */
+
+struct wrsmd_param {
+	/* Size of packet buffers (must be multiple of 64 bytes) */
+	uint_t wrsmd_buffer_size;
+
+	/* Mask of base ID bits in IP address */
+	uint_t wrsmd_netmask;
+
+	/* Number of packet buffers exported to each communicating peer */
+	ushort_t wrsmd_buffers;
+
+	/* Size of communications queues (must be at least wrsmd_buffers) */
+	ushort_t wrsmd_queue_size;
+
+	/* Number of buffers which won't be loaned upstream */
+	ushort_t wrsmd_buffers_retained;
+
+	/* Time to reclaim idle connection after (in seconds) UNIMPLEMENTED */
+	uint_t wrsmd_idle_reclaim_time;
+
+	/* Number of retries after a read or write error */
+	ushort_t wrsmd_err_retries;
+
+	/* Maximum # of queue packets per destination */
+	ushort_t wrsmd_max_queued_pkts;
+
+	/* Initial FQE timeout interval */
+	int wrsmd_nobuf_init_tmo;
+
+	/* Maximum FQE timeout interval */
+	int wrsmd_nobuf_max_tmo;
+
+	/* Time after which we drop packets instead of doing FQE timeout */
+	uint_t wrsmd_nobuf_drop_tmo;
+
+	/* Initial message timeout interval */
+	int wrsmd_msg_init_tmo;
+
+	/* Maximum message timeout interval */
+	int wrsmd_msg_max_tmo;
+
+	/* Time after which we drop connection instead of doing msg timeout */
+	uint_t wrsmd_msg_drop_tmo;
+
+	/* Acknowledgment timeout interval */
+	int wrsmd_ack_tmo;
+
+	/* Queue element sync timeout interval */
+	uint_t wrsmd_sync_tmo;
+
+	/*
+	 * timeout interval to wait before tearing down connection
+	 * after last attach to device is removed.
+	 */
+	uint_t wrsmd_teardown_tmo;
+
+	/* Number of packets to try and batch up in one transmission. */
+	ushort_t wrsmd_train_size;
+
+	/* Number of free buffers to try and batch up in one transmission. */
+	ushort_t wrsmd_fqe_sync_size;
+};
+
+/*
+ * Defaults and limits for parameters
+ * Timeout parameter values now given in milliseconds,
+ * rather than ticks.  Any values modified in wrsmd.conf
+ * must now be in milliseconds.  Values get rounded up to
+ * the next tick value, with granularity 10 ms for the default
+ * 100 hz.
+ */
+
+#define	WRSMD_BUFFERS_DFLT		32
+#define	WRSMD_BUFFER_SIZE_DFLT		16384
+#define	WRSMD_QUEUE_SIZE_DFLT		64
+#define	WRSMD_BUFFERS_RETAINED_DFLT	32
+#define	WRSMD_IDLE_RECLAIM_TIME_DFLT	36000
+#define	WRSMD_ERR_RETRIES_DFLT		1
+#define	WRSMD_MAX_QUEUED_PKTS_DFLT	100
+#define	WRSMD_NOBUF_INIT_TMO_DFLT	10
+#define	WRSMD_NOBUF_MAX_TMO_DFLT	2560
+#define	WRSMD_NOBUF_DROP_TMO_DFLT	5000
+#define	WRSMD_MSG_INIT_TMO_DFLT		10
+#define	WRSMD_MSG_MAX_TMO_DFLT		1280
+#define	WRSMD_MSG_DROP_TMO_DFLT		30000
+#define	WRSMD_ACK_TMO_DFLT		1000
+#define	WRSMD_SYNC_TMO_DFLT		10
+/*
+ * We set this to two clock ticks to allow free destination timeouts
+ * (<= 1 tick) to complete first, before next teardown timeout,
+ * allowing fewer iterations of the latter.
+ */
+#define	WRSMD_TEARDOWN_TMO_DFLT		20
+
+#define	WRSMD_TRAIN_SIZE_DFLT		8
+#define	WRSMD_FQE_SYNC_SIZE_DFLT	16
+
+/*
+ * Macro to convert millisecond timeout parameters to clock ticks.
+ */
+#define	WRSMD_TICKS(x)	(drv_usectohz(1000 * (x)))
+
+/* Definition of each possible event type */
+#define	WRSMD_EVT_FREEDEST	0
+#define	WRSMD_EVT_SYNC		1
+#define	WRSMD_EVT_SYNC_DQE	2
+
+/*
+ * Per-Stream instance state information.
+ *
+ * Each instance is dynamically allocated at open() and freed at
+ * close(). Each per-stream instance points to at most one per-device
+ * structure using the ss_wrsmdp field. All instances are threaded
+ * together into one list of active instances ordered on minor device
+ * number.
+ */
+
+typedef struct wrsmdstr {
+	struct wrsmdstr *ss_nextp;	/* next in list */
+	queue_t *ss_rq;			/* ptr to our read queue */
+	struct wrsmd *ss_wrsmdp;		/* attached device, if any */
+	ushort_t ss_state;		/* current state */
+	ushort_t ss_flags;		/* misc flags */
+	t_uscalar_t ss_sap;		/* bound sap (from dl_bind_req_t) */
+	minor_t ss_minor;		/* minor device number */
+	kmutex_t ss_lock;		/* protect this struct */
+} wrsmdstr_t;
+
+_NOTE(READ_ONLY_DATA(wrsmdstr::ss_rq))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmdstr::ss_lock, wrsmdstr::ss_wrsmdp))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmdstr::ss_lock, wrsmdstr::ss_state))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmdstr::ss_lock, wrsmdstr::ss_sap))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmdstr::ss_lock, wrsmdstr::ss_flags))
+_NOTE(READ_ONLY_DATA(wrsmdstr::ss_minor))
+
+/*
+ * For performance reasons, we read the following things in wrsmdsendup()
+ * without getting ss_lock.  As long as accesses to these variables are atomic,
+ * we believe nothing bad will happen.
+ */
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmdstr::ss_wrsmdp))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmdstr::ss_sap))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmdstr::ss_flags))
+
+/* Per-stream flags */
+
+#define	WRSMD_SLRAW	0x02	/* M_DATA plain raw mode */
+#define	WRSMD_SLALLPHYS	0x04	/* "promiscuous mode" */
+#define	WRSMD_SLALLSAP	0x08	/* enable all ether type values */
+#define	WRSMD_SLFAST	0x10	/* "fast mode" */
+
+typedef struct wrsmd_event {
+	struct wrsmd_event *next;
+	int type;
+	void *arg;
+} wrsmd_event_t;
+
+
+/*
+ * Per-Device instance state information.
+ *
+ * Each instance is dynamically allocated on first attach.
+ */
+typedef struct wrsmd {
+	struct wrsmd	*wrsmd_nextp; 	/* next in linked list */
+	queue_t		*wrsmd_wq;	/* ptr to one of our wq's, doesn't */
+					/*  matter which one, to run wsrv */
+	queue_t		*wrsmd_ipq;	/* IP queue, iff there's only one */
+	krwlock_t	wrsmd_ipq_rwlock; /* protects wrsmd_ipq */
+
+	dev_info_t	*wrsmd_dip;	/* dev info */
+	ushort_t	wrsmd_flags;	/* misc. flags */
+	ushort_t	wrsmd_promisc;	/* # of WRSMD_SLALLPHYS streams */
+	ushort_t	wrsmd_attached_streams;	/* streams attached to device */
+	kmutex_t	wrsmd_lock;	/* protect this struct */
+	kmutex_t	wrsmd_dest_lock; /* protect dest table (below) */
+
+	/* Counters to keep stats for netstat support */
+	uint64_t wrsmd_ipackets;	/* # packets received */
+	uint32_t wrsmd_ierrors;		/* # total input errors */
+	uint64_t wrsmd_opackets;	/* # packets sent */
+	uint32_t wrsmd_oerrors;		/* # total output errors */
+	uint32_t wrsmd_collisions;	/* # collisions (FQE waits) */
+
+	uint32_t wrsmd_in_bytes;	/* # bytes input (32 bit) */
+	uint32_t wrsmd_in_bytes64;	/* # bytes input (64 bit) */
+	uint64_t wrsmd_out_bytes;	/* # bytes output (32 bit) */
+	uint64_t wrsmd_out_bytes64;	/* # bytes output (64 bit) */
+
+	/* Other counters, for internal use */
+	uint32_t wrsmd_xfers;		/* # calls to wrsmd_xmit */
+	uint32_t wrsmd_xfer_pkts;	/* # pkts sent out by xmit */
+	uint32_t wrsmd_syncdqes;	/* # syncdqe-ints sent out by  xmit */
+	uint32_t wrsmd_lbufs;		/* # times we loaned bufs */
+	uint32_t wrsmd_nlbufs;		/* # times we had to alloc buf */
+	uint32_t wrsmd_pullup;		/* # times we had to coalesce pkts */
+	uint32_t wrsmd_pullup_fail;	/* # times we couldn't pullup */
+	uint32_t wrsmd_starts;		/* # calls to wrsmdstart */
+	uint32_t wrsmd_start_xfers;	/* # calls to wrsmdxfer from start */
+	uint32_t wrsmd_fqetmo_hint;	/* # times fqe tmo ended by hint */
+	uint32_t wrsmd_fqetmo_drops;	/* # pkts dropped by fqetmo */
+	uint32_t wrsmd_maxq_drops;	/* # pkts dropped 'cause q too long */
+	uint32_t wrsmd_errs;		/* # errors on transfers */
+
+	struct wrsmd_param 	wrsmd_param;	/* parameters */
+	struct kstat		*wrsmd_ksp;	/* our kstats */
+	dl_rsm_addr_t		wrsmd_rsm_addr; /* our RSM hardware address */
+	uint_t			wrsmd_ctlr_id; /* our RSM controller id  */
+	rsm_controller_object_t wrsmd_ctlr;
+	rsm_controller_attr_t	*wrsmd_ctlr_attr;
+	int	wrsmd_numdest;	/* Number of valid entries in desttbl */
+
+	struct wrsmd_dest		/* table for destination structures */
+		*wrsmd_desttbl[RSM_MAX_DESTADDR];
+
+	struct wrsmd_dest 	*wrsmd_runq;	/* service routine run queue */
+	kmutex_t wrsmd_runq_lock; /* protects wrsmd_runq, among others */
+
+	timeout_id_t		wrsmd_teardown_tmo_id;	/* teardown device */
+
+	/* Event thread for making RSM calles from non callback context */
+	kmutex_t		event_lock;
+	kthread_t 		*event_thread;
+	kcondvar_t		event_cv;
+	boolean_t		stop_events;
+	kcondvar_t		event_thread_exit_cv;
+	wrsmd_event_t		*events;
+
+} wrsmd_t;
+
+
+_NOTE(READ_ONLY_DATA(wrsmd::wrsmd_dip))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd::wrsmd_lock, wrsmd::wrsmd_flags))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd::wrsmd_lock, wrsmd::wrsmd_promisc))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmd::wrsmd_promisc))
+
+_NOTE(READ_ONLY_DATA(wrsmd::wrsmd_param))
+_NOTE(READ_ONLY_DATA(wrsmd_param))
+
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd::wrsmd_lock, wrsmd::wrsmd_ksp))
+_NOTE(READ_ONLY_DATA(wrsmd::wrsmd_ctlr_id))
+
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd::wrsmd_runq_lock, wrsmd::wrsmd_runq))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd::wrsmd_runq_lock, wrsmd::wrsmd_wq))
+
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmd::wrsmd_dip))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmd::wrsmd_ipackets))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmd::wrsmd_ierrors))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmd::wrsmd_opackets))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmd::wrsmd_oerrors))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmd::wrsmd_collisions))
+
+/* RSMPI progress flags */
+#define	WRSMDREGHANDLER	0x01
+#define	WRSMDGOTCTLR	0x02
+
+/* Attach progress bitmask */
+#define	WRSMD_ATT_MUTEX		0x01
+#define	WRSMD_ATT_LINKED		0x02
+#define	WRSMD_ATT_MINOR		0x04
+#define	WRSMD_ATT_KSTAT		0x08
+#define	WRSMD_ATT_EVT_THREAD	0x10
+
+#define	WRSMD_ATT_ALL	\
+	(WRSMD_ATT_MUTEX | WRSMD_ATT_LINKED | WRSMD_ATT_MINOR \
+	| WRSMD_ATT_KSTAT | WRSMD_ATT_EVT_THREAD)
+
+
+/*
+ * Number of bytes to add to buffer size to leave room for
+ * headers from other streams modules:
+ *
+ * TCP Header is 14 bytes
+ * IP Header is 20 bytes
+ */
+#define	WRSMDHEADROOM	34
+
+/*
+ * Full dlsap address format
+ */
+
+typedef struct wrsmddladdr {
+	struct ether_addr	dl_addr;	/* RSM hardware addr */
+	ushort_t		dl_sap;		/* SAP */
+} wrsmddladdr_t;
+
+
+/*
+ * Full DLSAP address length
+ */
+#define	WRSMD_DEVICE_ADDRL (sizeof (ushort_t) + sizeof (struct ether_addr))
+#define	WRSMD_IP_SAP	0x800	/* IP's sap */
+
+#define	WRSMD_BCAST_ADDRL (sizeof (struct ether_addr))
+
+#define	DLADDRL	(80)
+
+/*
+ * Export some of the error counters via the kstats mechanism.
+ */
+typedef struct wrsmd_stat {
+	struct kstat_named rsm_ipackets;
+	struct kstat_named rsm_ipackets64;
+	struct kstat_named rsm_ierrors;
+	struct kstat_named rsm_opackets;
+	struct kstat_named rsm_opackets64;
+	struct kstat_named rsm_oerrors;
+	struct kstat_named rsm_collisions;
+	struct kstat_named rsm_xfers;
+	struct kstat_named rsm_xfer_pkts;
+	struct kstat_named rsm_syncdqes;
+	struct kstat_named rsm_lbufs;
+	struct kstat_named rsm_nlbufs;
+	struct kstat_named rsm_pullup;
+	struct kstat_named rsm_pullup_fail;
+	struct kstat_named rsm_starts;
+	struct kstat_named rsm_start_xfers;
+	struct kstat_named rsm_fqetmo_hint;
+	struct kstat_named rsm_fqetmo_drops;
+	struct kstat_named rsm_maxq_drops;
+	struct kstat_named rsm_errs;
+	struct kstat_named rsm_in_bytes;
+	struct kstat_named rsm_in_bytes64;
+	struct kstat_named rsm_out_bytes;
+	struct kstat_named rsm_out_bytes64;
+} wrsmd_stat_t;
+
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_ipackets))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_ierrors))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_opackets))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_oerrors))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_collisions))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_xfers))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_xfer_pkts))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_lbufs))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_nlbufs))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_pullup))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_pullup_fail))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_starts))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_start_xfers))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_fqetmo_hint))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_fqetmo_drops))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_maxq_drops))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_errs))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_in_bytes))
+_NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", wrsmd_stat::rsm_out_bytes))
+
+/* Some streams defines */
+
+#define	DB_BASE(mp)		((mp)->b_datap->db_base)
+#define	DB_LIM(mp)		((mp)->b_datap->db_lim)
+#define	DB_REF(mp)		((mp)->b_datap->db_ref)
+#define	DB_TYPE(mp)		((mp)->b_datap->db_type)
+
+#define	MBLKL(mp)		((mp)->b_wptr - (mp)->b_rptr)
+#define	MBLKSIZE(mp)	((mp)->b_datap->db_lim - (mp)->b_datap->db_base)
+#define	MBLKHEAD(mp)	((mp)->b_rptr - (mp)->b_datap->db_base)
+#define	MBLKTAIL(mp)	((mp)->b_datap->db_lim - (mp)->b_wptr)
+
+/*
+ * On Wildcat, if there is a data delivery problem with one of the 32 byte
+ * halves of a 64 byte write to the remote node, the remote side writes all
+ * 0's to that 32 byte region of memory.  We guarantee that the 4 byte fqe
+ * entries and 8 byte byte dqe entries (described below) are aligned in a
+ * way that guarantees that each fits within a single 32 byte region, so
+ * checking for any non-zero value within the entry is sufficient to
+ * guarantee that the write was successful.
+ *
+ * We use the seqnum as the write validity check, which means it must never
+ * be 0.  A non-0 value ensures that the remote write was successful.
+ *
+ * Each fqe and dqe is 64 bytes in size.  This guarantees that
+ * we can write one entry at a time atomically, without disturbing any other
+ * entries.  This also quarantees alignment to wildcat hardware.  It does,
+ * however, waste some space.
+ *
+ */
+
+struct align_64byte {			/* Align to 64 bytes */
+	uint64_t pad[8];
+};
+
+/*
+ * Delivery Queue Entry, used to denote buffers containing new packets.
+ */
+#define	WRSMD_DQE_SEQ_MASK	0xFF	/* All 1's sequence */
+typedef union wrsmd_dqe {
+	struct align_64byte align;	/* Align to 64 bytes */
+	struct wrsmd_dqe_s {	/* actual structure */
+		ushort_t dq_length;	/* True length of packet */
+		ushort_t dq_sap;	/* Packet's SAP */
+		uchar_t	dq_seqnum;	/* Sequence number - validity check */
+		uchar_t	dq_offset;	/* Packet offset within buffer */
+		ushort_t dq_bufnum;	/* Buffer number */
+	} s;
+} wrsmd_dqe_t;
+
+/*
+ * Free Queue Entry, used to denote buffers which are available to be filled.
+ */
+#define	WRSMD_FQE_SEQ_MASK	0xFF	/* All 1's sequence */
+typedef union wrsmd_fqe {
+	struct align_64byte align;	/* Align to 64 bytes */
+	struct wrsmd_fqe_s {
+		uchar_t	fq_seqnum;	/* Sequence number - validity check */
+		uchar_t	fq_filler;	/* Unused */
+		ushort_t fq_bufnum;	/* Buffer number */
+	} s;
+} wrsmd_fqe_t;
+
+/*
+ * Segment data formats
+ */
+
+/*
+ * The major version should be bumped whenever the contents of the
+ * xfer segments are changed in a non-upward-compatible way, to prevent
+ * confused attempts at communication with machines running older protocol
+ * versions.
+ */
+#define	WRSMD_VERS_MAJOR		1
+#define	WRSMD_VERS_MINOR		0
+
+/*
+ * Header for the data transfer segment.
+ */
+typedef struct wrsmd_xfer_hdr {
+	size_t		rx_segsize;	/* size of segment */
+	uint32_t	rx_cookie;	/* magic cookie */
+	uint32_t	rx_bufsize;	/* size of buffers */
+	ushort_t	rx_numbufs;	/* number of buffers */
+	ushort_t	rx_numfqes;	/* number of elements in free queue */
+	ushort_t	rx_numdqes;	/* num of elements in delivery queue */
+	uint32_t	rx_buf_offset;	/* offset to start of buffers */
+	uint32_t	rx_fq_offset;	/* offset to start of free queue */
+	uint32_t	rx_dq_offset;	/* offset to start of delivery queue */
+} wrsmd_xfer_hdr_t;
+
+#define	WRSMD_XFER_COOKIE	0x58664572	/* 'XfEr' */
+
+/*
+ * Structure describing a loaned-up buffer
+ */
+
+typedef struct wrsmdbuf {
+	frtn_t	rb_frtn;		/* Pointer to our free routine */
+	int	rb_bufnum;		/* Number of loaned buffer */
+	struct wrsmd_dest *rb_rd;	/* Destination buffer belongs to */
+} wrsmdbuf_t;
+
+_NOTE(READ_ONLY_DATA(wrsmdbuf::rb_frtn))
+_NOTE(READ_ONLY_DATA(wrsmdbuf::rb_bufnum))
+_NOTE(READ_ONLY_DATA(wrsmdbuf::rb_rd))
+
+/*
+ * Structure describing a packet which is currently being sent
+ */
+
+typedef struct wrsmd_pkt {
+	mblk_t *rd_pkt_ptr;	/* packet pointer */
+	ushort_t rd_pkt_offset;	/* packet offset within buffer */
+	uint_t rd_pkt_len;	/* real length of packet */
+	ushort_t rd_pkt_sap;	/* packet SAP */
+} wrsmd_pkt_t;
+
+
+/*
+ * WRSMD message types
+ */
+
+#define	WRSMD_MSG_REQ_CONNECT		1
+#define	WRSMD_MSG_CON_ACCEPT		2
+#define	WRSMD_MSG_CON_ACK		3
+#define	WRSMD_MSG_SYNC_DQE		4
+
+#define	WRSMD_REXMIT			127
+
+
+
+/*
+ *
+ *          R S M D   C O N N E C T I O N   P R O T O C O L
+ *
+ *
+ * The connection protocol for the RSM DLPI driver is a follows:
+ *
+ * INITIATOR                              RESPONDER
+ *
+ * 1  Send RSDM_REQ_CONNECT
+ *         Includes xfer segment ID
+ *
+ * 2                                      Send WRSMD_CON_ACCEPT
+ *                                        Includes xfer segment ID
+ *
+ * 3  Send WRSMD_CON_ACK
+ *
+ * If an WRSMD_REQ_CONNECT message is received while an
+ * WRSMD_REQ_CONNECT is outstanding to the same node ID:  if the
+ * node receiving the duplicate WRSMD_REQ_CONNECT has a higher
+ * numbered ID, it will accept the connection.  The lower numbered
+ * node will reject the duplicate.
+ *
+ * The special message type WRSMD_REXMIT causes us to retransmit the
+ * last message we sent (unsuccessfully or successfully), without
+ * incrementing the sequence number on the message.  This is used when
+ * we get a timeout waiting for a response to an WRSMDM_REQ_CONNECT
+ * request and want to resend it.
+ *
+ */
+
+typedef struct wrsmd_msg_header {
+	uint8_t wrsmd_version;	/* Increment when incompatible change made */
+	uint8_t reqtype;	/* One of the above */
+	uint16_t seqno;		/* Sequence number */
+} wrsmd_msg_header_t;
+
+typedef struct wrsmd_con_request {
+	rsm_memseg_id_t send_segid; /* Segment you should use to talk to me */
+} wrsmd_con_request_t;
+
+typedef struct wrsmd_con_accept {
+	rsm_memseg_id_t send_segid; /* Segment you should use to talk to me */
+	rsm_memseg_id_t rcv_segid; /* Segment I use to talk to you */
+} wrsmd_con_accept_t;
+
+typedef struct wrsmd_con_ack {
+	rsm_memseg_id_t send_segid; /* Segment you should use to talk to me */
+	rsm_memseg_id_t rcv_segid; /* Segment I use to talk to you */
+} wrsmd_con_ack_t;
+
+typedef struct wrsmd_syncdqe {
+	rsm_memseg_id_t rcv_segid; /* Segment I use to talk to you */
+} wrsmd_syncdqe_t;
+
+
+
+typedef union wrsmd_msg {
+	uint64_t align;
+	struct {
+		wrsmd_msg_header_t hdr;
+		union {
+			wrsmd_con_request_t	con_request;
+			wrsmd_con_accept_t	con_accept;
+			wrsmd_con_ack_t		con_ack;
+			wrsmd_syncdqe_t		syncdqe;
+		} m;
+	} p;
+} wrsmd_msg_t;
+
+/*
+ * Structure describing someone else communicating with us (a destination)
+ */
+
+typedef struct wrsmd_dest {
+
+	/* Basics */
+	wrsmd_t		*rd_wrsmdp;	/* Pointer to our device structure */
+	rsm_addr_t 	rd_rsm_addr;	/* Address of destination */
+
+	/* Interrupt queue */
+	rsm_send_q_handle_t rsm_sendq;
+	wrsmd_msg_t 	rsm_previous_msg;
+	int 		rsm_previous_msg_valid;
+
+	/* Packet queue */
+	mblk_t	*rd_queue_h,	/* queue of packets waiting to go out */
+		*rd_queue_t;
+	ushort_t rd_queue_len;	/* number of packets on above queue */
+
+
+	/* Local transfer segment */
+	caddr_t 			rd_rawmem_base_addr;
+	size_t 				rd_rawmem_base_size;
+	rsm_memory_local_t 		rd_memory;
+	rsm_memseg_id_t 		rd_lxfersegid;
+	rsm_memseg_export_handle_t 	rd_lxferhand;
+
+
+	/* Remote transfer segment */
+	wrsmd_xfer_hdr_t			rd_rxferhdr;
+	int 				rd_rxferhdr_valid;
+	off_t 				rd_rbufoff;
+	boolean_t 			rd_segid_valid;
+	rsm_memseg_id_t 		rd_rxfersegid;
+	rsm_memseg_import_handle_t 	rd_rxferhand;
+	uint16_t 			rd_lastconnmsg_seq;
+
+
+	/*
+	 * Free queue we're writing to (describing buffers on our node
+	 * available to partner; lives on partner)
+	 */
+	off_t	rd_fqw_f_off;	/* First usable element in queue */
+	ushort_t rd_fqw_seq;	/* Sequence number we will write next */
+	ushort_t rd_num_fqws;	/* Number of usable elements in queue */
+
+
+	/*
+	 * Delivery queue that we're writing to (describing buffers on
+	 * partner that we've filled with data; lives on partner)
+	 */
+	off_t	rd_dqw_f_off;	/* First usable element in queue */
+	ushort_t rd_dqw_seq;	/* Sequence number we will write next */
+	ushort_t rd_num_dqws;	/* Number of usable elements in queue */
+
+
+	/* Buffers (on partner) that we're writing to */
+	uint_t	rd_rbuflen;	/* Length of remote buffers */
+	ushort_t rd_numrbuf;	/* Number of remote buffers */
+
+
+	/*
+	 * Free queue we're reading from (describing buffers on partner
+	 * available to us; lives on our node)
+	 */
+	volatile wrsmd_fqe_t	/* Pointers to ... */
+		*rd_fqr_f,	/* First usable element in queue */
+		*rd_fqr_l,	/* Last usable element in queue */
+		*rd_fqr_n;	/* Element we'll read next */
+	ushort_t rd_fqr_seq;	/* Sequence number we expect to read next */
+	ushort_t rd_num_fqrs;	/* Number of usable elements in queue */
+
+
+	/*
+	 * Delivery queue we're reading from (describing buffers on our
+	 * node that the partner has filled with data; lives on our node)
+	 */
+	volatile wrsmd_dqe_t	/* Pointers to ... */
+		*rd_dqr_f,	/* First usable element in queue */
+		*rd_dqr_l,	/* Last usable element in queue */
+		*rd_dqr_n;	/* Element we'll read next */
+	ushort_t rd_dqr_seq;	/* Sequence number we expect to read next */
+	ushort_t rd_num_dqrs;	/* Number of usable elements in queue */
+
+
+	/* (Local) buffers we're reading from */
+	volatile void *rd_lbuf;	/* Start of first local buffer */
+	uint_t	rd_lbuflen;	/* Length of each local buffer */
+	ushort_t rd_numlbufs;	/* Number of local buffers */
+	wrsmdbuf_t *rd_bufbase;	/* Local buffer description structures, */
+				/*  for use in loaning buffers upward */
+
+
+	/* Information on cached FQE's */
+	ushort_t rd_cached_fqr_cnt;	/* number of cached fqe's */
+	ushort_t *rd_cached_fqr;	/* buffer numbers from cached fqe's */
+
+
+	/*
+	 * Shadow free queue - local copy of free queue that lives on
+	 * partner
+	 */
+	wrsmd_fqe_t		/* Pointers to ... */
+		*rd_shdwfqw_f_addr,	/* Start of alloc'd memory for queue */
+		*rd_shdwfqw_f,	/* First usable element */
+		*rd_shdwfqw_l,	/* Last usable element */
+		*rd_shdwfqw_i,	/* Next element added to queue goes here */
+		*rd_shdwfqw_o;	/* Next element transmitted comes from here */
+
+	/*
+	 * Shadow delivery queue - local copy of delivery queue that lives
+	 * on partner
+	 */
+	wrsmd_dqe_t		/* Pointers to ... */
+		*rd_shdwdqw_f_addr,	/* Start of alloc'd memory for queue */
+		*rd_shdwdqw_f,	/* First usable element */
+		*rd_shdwdqw_l,	/* Last usable element */
+		*rd_shdwdqw_i,	/* Next element added to queue goes here */
+		*rd_shdwdqw_o;	/* Next element transmitted comes from here */
+
+	ushort_t rd_shdwfqw_errflag;	/* If nonzero, we had an error last */
+					/*  time we tried to write an FQE */
+	ushort_t rd_shdwdqw_errflag;	/* If nonzero, we had an error last */
+					/*  time we tried to write a DQE */
+	ushort_t rd_stopq;		/* If nonzero, we shouldn't try to */
+					/*  sync queues, the network is down */
+
+
+	/* State information */
+	ushort_t rd_state;	/* State (WRSMD_STATE_xxx, see below) */
+	ushort_t rd_estate;	/* Event State */
+	ushort_t rd_sstate;	/* Segment state (bitmask of WRSMD_RSMS_xxx) */
+	ushort_t rd_dstate;	/* Delete state (0-2), != 0 means deleting */
+	short	rd_refcnt;	/* Destination reference count */
+
+
+	/* Command/sequence information */
+	ushort_t rd_nseq;	/* Seq # we'll put on next message */
+	uchar_t	rd_recvdack;	/* Nonzero if we've gotten a valid ACK */
+	uchar_t	rd_sentconn;	/* Nonzero if we've sent a CONN */
+
+
+	/* Last message transmitted, for rexmits if needed */
+	wrsmd_msg_t rd_lastobmsg;	/* Last outbound message */
+
+
+
+	/* Timeout information */
+
+	timeout_id_t rd_fqe_tmo_id;	/* timeout ID for free queue retry. */
+	timeout_id_t rd_tmo_id;	/* timeout ID for empty queue retry, etc. */
+	int	rd_tmo_int;	/* backoff interval for timeout */
+	int	rd_tmo_tot;	/* ticks we've waited so far this timeout */
+
+	ushort_t rd_nlb;	/* number of outstanding loaned buffers */
+	ushort_t rd_nlb_del;	/* if nonzero, we're being deleted, and are */
+				/*  waiting for rd_nlb to go to 0 */
+
+
+	kmutex_t rd_nlb_lock;	/* mutex to protect rd_nlb/rd_nlb_del */
+	kmutex_t rd_lock;	/* mutex to protect this data structure */
+	kmutex_t rd_net_lock;	/* mutex to protect segment data/pointers */
+	kmutex_t rd_xmit_lock; 	/* mutex to protect xmit stuff */
+
+
+	struct wrsmd_dest *rd_next;	/* ptrs for svc routine run queue */
+} wrsmd_dest_t;
+
+_NOTE(READ_ONLY_DATA(wrsmd_dest::rd_wrsmdp))
+_NOTE(READ_ONLY_DATA(wrsmd_dest::rd_rsm_addr))
+
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_xmit_lock, wrsmd_dest::rd_queue_h))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_xmit_lock, wrsmd_dest::rd_queue_t))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_xmit_lock, wrsmd_dest::rd_queue_len))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_lock, wrsmd_dest::rd_lxferhand))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_lock, wrsmd_dest::rd_rbuflen))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmd_dest::rd_rbuflen))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_lock, wrsmd_dest::rd_numrbuf))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmd_dest::rd_numrbuf))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_lock, wrsmd_dest::rd_lbuf))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmd_dest::rd_lbuf))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_lock, wrsmd_dest::rd_lbuflen))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmd_dest::rd_lbuflen))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_lock, wrsmd_dest::rd_numlbufs))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmd_dest::rd_numlbufs))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_lock, wrsmd_dest::rd_bufbase))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmd_dest::rd_bufbase))
+
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_shdwfqw_f))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_shdwfqw_l))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_shdwfqw_i))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_shdwfqw_o))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_fqw_seq))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_shdwdqw_f))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_shdwdqw_l))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_shdwdqw_i))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_shdwdqw_o))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_dqw_seq))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_fqr_f))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_fqr_l))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_fqr_n))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_fqr_seq))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_dqr_f))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_dqr_l))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_dqr_n))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_dqr_seq))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock,
+    wrsmd_dest::rd_cached_fqr_cnt))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_cached_fqr))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock,
+    wrsmd_dest::rd_shdwfqw_errflag))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock,
+    wrsmd_dest::rd_shdwdqw_errflag))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_net_lock, wrsmd_dest::rd_stopq))
+
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_xmit_lock, wrsmd_dest::rd_tmo_id))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(wrsmd_dest::rd_tmo_id))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_xmit_lock, wrsmd_dest::rd_tmo_int))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_xmit_lock, wrsmd_dest::rd_tmo_tot))
+
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_nlb_lock, wrsmd_dest::rd_nlb))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd_dest::rd_nlb_lock, wrsmd_dest::rd_nlb_del))
+
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd::wrsmd_runq_lock, wrsmd_dest::rd_state))
+_NOTE(SCHEME_PROTECTS_DATA("see comment below", wrsmd_dest::rd_next))
+
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd::wrsmd_dest_lock, wrsmd_dest::rd_dstate))
+_NOTE(MUTEX_PROTECTS_DATA(wrsmd::wrsmd_dest_lock, wrsmd_dest::rd_refcnt))
+
+
+/*
+ * Run queue:
+ *
+ * Certain operations on destinations are performed by the driver's write
+ * service routine (wrsmd_wsrv).  In order to arrange for this, there is a
+ * queue of destinations waiting to be processed by the service routine.
+ * Each device's wrsmd_runq points to the head of this queue of destinations,
+ * which are linked together via rd_next.  Whenever the service routine
+ * runs, after it has served its usual purpose of processing messages from
+ * the stream's service queue, it traverses its list of destinations and
+ * performs appropriate operations on them, depending on their state.
+ *
+ * The rd_next pointer is protected by the runq_lock everywhere but in the
+ * middle of the service routine.  Essentially, the service routine takes a
+ * whole chain of destination entries off of the run queue at once (inside
+ * the runq_lock), and then traverses the list (outside the runq_lock).  Since
+ * a scheduled destination should never be given a new state except by the
+ * service routine, there should be no conflicting updates to rd_next.
+ *
+ * Destination states:
+ *
+ * A scheduled state means the destination is on the run queue; an unscheduled
+ * state means the destination is not.  State transitions are always from
+ * scheduled to unscheduled or vice versa.
+ *
+ * A state with a name of the form WRSMD_STATE_S_xxx is a scheduled state where
+ * the service routine is going to do xxx next.  These states have odd numbers.
+ *
+ * A state with a name of the form WRSMD_STATE_W_xxx is an unscheduled state
+ * where we are waiting for xxx to happen.  These states have even numbers.
+ */
+
+#define	WRSMD_STATE_NEW			0	/* Newly created */
+#define	WRSMD_STATE_INPROGRESS		1000	/* Being processed */
+#define	WRSMD_STATE_DELETING		2000	/* Being deleted */
+
+#define	WRSMD_STATE_W_SCONNTMO		2	/* Waiting for conn rxmit tmo */
+#define	WRSMD_STATE_W_ACCEPT		4	/* Waiting for accept msg */
+#define	WRSMD_STATE_W_ACK		6	/* Waiting for ack msg */
+#define	WRSMD_STATE_W_READY		8	/* Connected, wait for pkt */
+#define	WRSMD_STATE_W_FQE		10	/* Waiting for fqe to xmit */
+
+#define	WRSMD_STATE_S_REQ_CONNECT	1	/* Srv: send conn request */
+#define	WRSMD_STATE_S_NEWCONN		3	/* Srv: setup/accept new conn */
+#define	WRSMD_STATE_S_CONNXFER_ACCEPT	5	/* Srv: connxfer, then accept */
+#define	WRSMD_STATE_S_CONNXFER_ACK	7	/* Srv: connxfer, then ack */
+#define	WRSMD_STATE_S_XFER		9	/* Srv: xfer data */
+#define	WRSMD_STATE_S_DELETE		11	/* Srv: delete this dest */
+#define	WRSMD_STATE_S_SCONN		13	/* Srv: resend last conn */
+
+#define	WRSMD_SCHED_STATE(s)	((s) & 1)
+
+#define	WRSMD_STATE_STR(x) (						\
+	(x == WRSMD_STATE_NEW) ? "WRSMD_STATE_NEW" :			\
+	(x == WRSMD_STATE_INPROGRESS) ? "WRSMD_STATE_INPROGRESS" :	\
+	(x == WRSMD_STATE_DELETING) ? "WRSMD_STATE_DELETING" :		\
+	(x == WRSMD_STATE_W_SCONNTMO) ? "WRSMD_STATE_W_SCONNTMO" :	\
+	(x == WRSMD_STATE_W_ACCEPT) ? "WRSMD_STATE_W_ACCEPT" :		\
+	(x == WRSMD_STATE_W_ACK) ? "WRSMD_STATE_W_ACK" :		\
+	(x == WRSMD_STATE_W_READY) ? "WRSMD_STATE_W_READY" :		\
+	(x == WRSMD_STATE_W_FQE) ? "WRSMD_STATE_W_FQE" :		\
+	(x == WRSMD_STATE_S_REQ_CONNECT) ? "WRSMD_STATE_S_REQ_CONNECT" :\
+	(x == WRSMD_STATE_S_NEWCONN) ? "WRSMD_STATE_S_NEWCONN" :	\
+	(x == WRSMD_STATE_S_CONNXFER_ACCEPT) ? \
+	    "WRSMD_STATE_S_CONNXFER_ACCEPT" : \
+	(x == WRSMD_STATE_S_CONNXFER_ACK) ? "WRSMD_STATE_S_CONNXFER_ACK" : \
+	(x == WRSMD_STATE_S_XFER) ? "WRSMD_STATE_S_XFER" :		\
+	(x == WRSMD_STATE_S_DELETE) ? "WRSMD_STATE_S_DELETE" :		\
+	(x == WRSMD_STATE_S_SCONN) ? "WRSMD_STATE_S_SCONN" :		\
+	"unknown")
+
+
+/*
+ * RSM driver state - basically, what segments we've created/connected.  We
+ * keep a bitmask of the ones we've done, so that when we delete a
+ * destination we don't try and undo something we never did.  Also, we
+ * sometimes check to make sure rd_sstate is WRSMD_RSMS_ALL before trying to
+ * perform an operation on a destination, to ensure we don't get ahead of
+ * our initialization.
+ */
+
+#define	WRSMD_RSMS_LXFER_C	0x01	/* Create local xfer segment */
+#define	WRSMD_RSMS_LXFER_P	0x02	/* Publish local xfer segment */
+#define	WRSMD_RSMS_RXFER_S	0x04	/* Create send queue to remote node */
+#define	WRSMD_RSMS_RXFER_C	0x10	/* Connect to remote xfer */
+
+#define	WRSMD_RSMS_ALL	\
+	(WRSMD_RSMS_LXFER_C | WRSMD_RSMS_LXFER_P | WRSMD_RSMS_RXFER_S | \
+	WRSMD_RSMS_RXFER_C)
+
+#endif	/* _KERNEL */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif	/* _SYS_WRSMD_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/wrsmd/Makefile	Thu Jun 29 14:43:12 2006 -0700
@@ -0,0 +1,112 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# uts/sun4u/wrsmd/Makefile
+#
+#	This makefile drives the production of the sun4u "wrsmd" driver module.
+#
+#	sun4u 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		= wrsmd
+OBJECTS		= $(WRSMD_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(WRSMD_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_PSM_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/sun4u/io
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sun4u/Makefile.sun4u
+
+#
+# Include path for rsm header files
+#
+INC_PATH += -I$(UTSBASE)/common
+
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+#
+# Turn on doubleword alignment for 64 bit registers
+# lint pass one enforcement
+#
+CFLAGS += $(CCVERBOSE) -dalign
+
+#
+# module dependencies
+#
+LDFLAGS += -dy -Nmisc/rsmops
+
+#
+# to turn on TNF, add this line
+#
+LDFLAGS += -Ndrv/tnf
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+ll:		$(ALL_DEPS)
+	$(CC) $(CFLAGS) $(CPPFLAGS) $(CCVERBOSE) -Zll ../io/wrsmd.c
+
+
+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)/sun4u/Makefile.targ
--- a/usr/src/xmod/cry_files	Thu Jun 29 12:59:06 2006 -0700
+++ b/usr/src/xmod/cry_files	Thu Jun 29 14:43:12 2006 -0700
@@ -58,7 +58,7 @@
 usr/src/uts/sun4u/enchilada/Makefile
 usr/closed/uts/sun4u/ents/Makefile
 usr/src/uts/sun4u/littleneck/Makefile
-usr/closed/uts/sun4u/lw2plus/Makefile
+usr/src/uts/sun4u/lw2plus/Makefile
 usr/src/uts/sun4u/lw8/Makefile
 usr/src/uts/sun4u/mpxu/Makefile
 usr/src/uts/sun4u/serengeti/Makefile