435 Need an open iprb(7d)
authorGarrett D'Amore <garrett@nexenta.com>
Fri, 03 Dec 2010 07:32:02 -0800
changeset 13248 ed4997a098c7
parent 13247 93e476e940b6
child 13249 abc9578d5a0e
435 Need an open iprb(7d) Reviewed by: [email protected] Reviewed by: [email protected] Reviewed by: [email protected] Reviewed by: [email protected] Reviewed by: [email protected] Approved by: [email protected]
exception_lists/closed-bins
usr/src/pkg/manifests/driver-network-iprb.mf
usr/src/pkg/manifests/driver-network-platform.mf
usr/src/uts/common/Makefile.files
usr/src/uts/common/Makefile.rules
usr/src/uts/common/io/iprb/THIRDPARTYLICENSE
usr/src/uts/common/io/iprb/THIRDPARTYLICENSE.descrip
usr/src/uts/common/io/iprb/iprb.c
usr/src/uts/common/io/iprb/iprb.h
usr/src/uts/common/io/iprb/rcvbundl.h
usr/src/uts/intel/Makefile.intel.shared
usr/src/uts/intel/iprb/Makefile
--- a/exception_lists/closed-bins	Thu Dec 02 20:23:12 2010 +0530
+++ b/exception_lists/closed-bins	Fri Dec 03 07:32:02 2010 -0800
@@ -13,6 +13,8 @@
 ./etc/snmp/conf
 ./etc/snmp/conf/mibiisa.reg
 ./etc/snmp/conf/snmp.conf
+./kernel/drv/iprb
+./kernel/drv/amd64/iprb
 ./lib/crypto
 ./lib/crypto/kcfd
 ./lib/libc_i18n.a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkg/manifests/driver-network-iprb.mf	Fri Dec 03 07:32:02 2010 -0800
@@ -0,0 +1,64 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
+#
+
+#
+# The default for payload-bearing actions in this package is to appear in the
+# global zone only.  See the include file for greater detail, as well as
+# information about overriding the defaults.
+#
+<include global_zone_only_component>
+set name=pkg.fmri value=pkg:/driver/network/iprb@$(PKGVERS)
+set name=pkg.description value="Intel 8255x Fast Ethernet Driver"
+set name=pkg.summary value="Intel 8255x Fast Ethernet Driver"
+set name=info.classification \
+    value=org.opensolaris.category.2008:Drivers/Networking
+set name=variant.arch value=i386
+dir path=etc group=sys
+dir path=kernel group=sys
+dir path=kernel/drv group=sys
+dir path=kernel/drv/$(ARCH64) group=sys
+driver name=iprb clone_perms="iprb 0666 root sys" perms="* 0666 root sys" \
+    alias=pci8086,1029 \
+    alias=pci8086,1030 \
+    alias=pci8086,1031 \
+    alias=pci8086,1032 \
+    alias=pci8086,1038 \
+    alias=pci8086,1039 \
+    alias=pci8086,103d \
+    alias=pci8086,1050 \
+    alias=pci8086,1059 \
+    alias=pci8086,1068 \
+    alias=pci8086,1069 \
+    alias=pci8086,1092 \
+    alias=pci8086,1209 \
+    alias=pci8086,1229 \
+    alias=pci8086,2449 \
+    alias=pci8086,27dc
+file path=kernel/drv/$(ARCH64)/iprb group=sys
+file path=kernel/drv/iprb group=sys
+license lic_CDDL license=lic_CDDL
+license usr/src/uts/common/io/iprb/THIRDPARTYLICENSE \
+    license=usr/src/uts/common/io/iprb/THIRDPARTYLICENSE
--- a/usr/src/pkg/manifests/driver-network-platform.mf	Thu Dec 02 20:23:12 2010 +0530
+++ b/usr/src/pkg/manifests/driver-network-platform.mf	Fri Dec 03 07:32:02 2010 -0800
@@ -48,135 +48,14 @@
     alias=pci1109,1400 \
     alias=pci1109,2400 \
     alias=pci2646,1
-driver name=iprb clone_perms="iprb 0666 root sys" perms="* 0666 root sys" \
-    alias=pci8086,1029 \
-    alias=pci8086,1030 \
-    alias=pci8086,1031 \
-    alias=pci8086,1032 \
-    alias=pci8086,1038 \
-    alias=pci8086,1039 \
-    alias=pci8086,103d \
-    alias=pci8086,103d.8086.103d \
-    alias=pci8086,1050 \
-    alias=pci8086,1050.8086.3020 \
-    alias=pci8086,1050.8086.302f \
-    alias=pci8086,1050.8086.3427 \
-    alias=pci8086,1059 \
-    alias=pci8086,1068 \
-    alias=pci8086,1069 \
-    alias=pci8086,1092 \
-    alias=pci8086,1209 \
-    alias=pci8086,1229 \
-    alias=pci8086,1229.8086.1 \
-    alias=pci8086,1229.8086.10 \
-    alias=pci8086,1229.8086.1009 \
-    alias=pci8086,1229.8086.100c \
-    alias=pci8086,1229.8086.1012 \
-    alias=pci8086,1229.8086.1013 \
-    alias=pci8086,1229.8086.1015 \
-    alias=pci8086,1229.8086.1016 \
-    alias=pci8086,1229.8086.1017 \
-    alias=pci8086,1229.8086.1030 \
-    alias=pci8086,1229.8086.1040 \
-    alias=pci8086,1229.8086.1041 \
-    alias=pci8086,1229.8086.1042 \
-    alias=pci8086,1229.8086.1050 \
-    alias=pci8086,1229.8086.1051 \
-    alias=pci8086,1229.8086.1052 \
-    alias=pci8086,1229.8086.10f0 \
-    alias=pci8086,1229.8086.11 \
-    alias=pci8086,1229.8086.12 \
-    alias=pci8086,1229.8086.1229 \
-    alias=pci8086,1229.8086.13 \
-    alias=pci8086,1229.8086.2 \
-    alias=pci8086,1229.8086.2009 \
-    alias=pci8086,1229.8086.200d \
-    alias=pci8086,1229.8086.200e \
-    alias=pci8086,1229.8086.200f \
-    alias=pci8086,1229.8086.2010 \
-    alias=pci8086,1229.8086.2013 \
-    alias=pci8086,1229.8086.2016 \
-    alias=pci8086,1229.8086.2017 \
-    alias=pci8086,1229.8086.2018 \
-    alias=pci8086,1229.8086.2019 \
-    alias=pci8086,1229.8086.2101 \
-    alias=pci8086,1229.8086.2102 \
-    alias=pci8086,1229.8086.2103 \
-    alias=pci8086,1229.8086.2104 \
-    alias=pci8086,1229.8086.2105 \
-    alias=pci8086,1229.8086.2106 \
-    alias=pci8086,1229.8086.2107 \
-    alias=pci8086,1229.8086.2108 \
-    alias=pci8086,1229.8086.2200 \
-    alias=pci8086,1229.8086.2201 \
-    alias=pci8086,1229.8086.2202 \
-    alias=pci8086,1229.8086.2203 \
-    alias=pci8086,1229.8086.2204 \
-    alias=pci8086,1229.8086.2205 \
-    alias=pci8086,1229.8086.2206 \
-    alias=pci8086,1229.8086.2207 \
-    alias=pci8086,1229.8086.2208 \
-    alias=pci8086,1229.8086.2402 \
-    alias=pci8086,1229.8086.2407 \
-    alias=pci8086,1229.8086.2408 \
-    alias=pci8086,1229.8086.2409 \
-    alias=pci8086,1229.8086.240f \
-    alias=pci8086,1229.8086.2410 \
-    alias=pci8086,1229.8086.2411 \
-    alias=pci8086,1229.8086.2412 \
-    alias=pci8086,1229.8086.2413 \
-    alias=pci8086,1229.8086.3 \
-    alias=pci8086,1229.8086.30 \
-    alias=pci8086,1229.8086.3000 \
-    alias=pci8086,1229.8086.3001 \
-    alias=pci8086,1229.8086.3002 \
-    alias=pci8086,1229.8086.3006 \
-    alias=pci8086,1229.8086.3007 \
-    alias=pci8086,1229.8086.3008 \
-    alias=pci8086,1229.8086.3010 \
-    alias=pci8086,1229.8086.3011 \
-    alias=pci8086,1229.8086.3012 \
-    alias=pci8086,1229.8086.301a \
-    alias=pci8086,1229.8086.31 \
-    alias=pci8086,1229.8086.3411 \
-    alias=pci8086,1229.8086.4 \
-    alias=pci8086,1229.8086.40 \
-    alias=pci8086,1229.8086.41 \
-    alias=pci8086,1229.8086.42 \
-    alias=pci8086,1229.8086.5 \
-    alias=pci8086,1229.8086.50 \
-    alias=pci8086,1229.8086.6 \
-    alias=pci8086,1229.8086.7 \
-    alias=pci8086,1229.8086.8 \
-    alias=pci8086,1229.8086.9 \
-    alias=pci8086,1229.8086.a \
-    alias=pci8086,1229.8086.b \
-    alias=pci8086,1229.8086.c \
-    alias=pci8086,1229.8086.d \
-    alias=pci8086,1229.8086.e \
-    alias=pci8086,1229.8086.f \
-    alias=pci8086,2449 \
-    alias=pci8086,2449.8086.3010 \
-    alias=pci8086,2449.8086.3011 \
-    alias=pci8086,2449.8086.3012 \
-    alias=pci8086,2449.8086.3013 \
-    alias=pci8086,2449.8086.3014 \
-    alias=pci8086,2449.8086.3015 \
-    alias=pci8086,2449.8086.3016 \
-    alias=pci8086,2449.8086.3017 \
-    alias=pci8086,2449.8086.3018 \
-    alias=pci8086,27dc \
-    alias=pci8086,27dc.8086.308d
 driver name=pcn clone_perms="pcn 0666 root sys" perms="* 0666 root sys" \
     alias=pci1022,2000 \
     alias=pci103c,104c
 file path=etc/bootrc group=sys mode=0755
 file path=etc/mach group=sys original_name=SUNWos86r:etc/mach preserve=true
 file path=kernel/drv/$(ARCH64)/dnet group=sys
-file path=kernel/drv/$(ARCH64)/iprb group=sys
 file path=kernel/drv/$(ARCH64)/pcn group=sys
 file path=kernel/drv/dnet group=sys
-file path=kernel/drv/iprb group=sys
 file path=kernel/drv/pcn group=sys
 file path=kernel/drv/sd group=sys
 file path=kernel/drv/sd.conf group=sys \
@@ -185,9 +64,10 @@
     name="Platform Support, OS Functionality (Root)"
 license cr_Sun license=cr_Sun
 license lic_CDDL license=lic_CDDL
+# when pcn is removed, we can remove the OSBL as well
 license lic_OSBL license=lic_OSBL
 license lic_OSBL_preamble license=lic_OSBL_preamble
-license usr/closed/uts/intel/io/iprb/THIRDPARTYLICENSE \
-    license=usr/closed/uts/intel/io/iprb/THIRDPARTYLICENSE
 # elxl moved out of this package, so create a dependency for upgraded systems
 depend fmri=driver/network/elxl type=require
+# iprb moved out of this package, so create a dependency for upgraded systems
+depend fmri=driver/network/iprb type=require
--- a/usr/src/uts/common/Makefile.files	Thu Dec 02 20:23:12 2010 +0530
+++ b/usr/src/uts/common/Makefile.files	Fri Dec 03 07:32:02 2010 -0800
@@ -1900,6 +1900,11 @@
 		igb_rx.o igb_stat.o igb_tx.o
 
 #
+#	Intel Pro/100 NIC driver module
+#
+IPRB_OBJS =	iprb.o
+
+#
 #       Intel 10GbE PCIE NIC driver module
 #
 IXGBE_OBJS =    ixgbe_82598.o ixgbe_82599.o ixgbe_api.o		\
--- a/usr/src/uts/common/Makefile.rules	Thu Dec 02 20:23:12 2010 +0530
+++ b/usr/src/uts/common/Makefile.rules	Fri Dec 03 07:32:02 2010 -0800
@@ -1303,6 +1303,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/iprb/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/ixgbe/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -2485,6 +2489,9 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/igb/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/iprb/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/ixgbe/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/iprb/THIRDPARTYLICENSE	Fri Dec 03 07:32:02 2010 -0800
@@ -0,0 +1,28 @@
+Copyright (c) 1999-2001, Intel Corporation 
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without 
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice, 
+    this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation 
+    and/or other materials provided with the distribution.
+
+ 3. Neither the name of Intel Corporation nor the names of its contributors 
+    may be used to endorse or promote products derived from this software 
+    without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/iprb/THIRDPARTYLICENSE.descrip	Fri Dec 03 07:32:02 2010 -0800
@@ -0,0 +1,1 @@
+INTEL 8255x CPUSAVER MICROCODE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/iprb/iprb.c	Fri Dec 03 07:32:02 2010 -0800
@@ -0,0 +1,1796 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
+ */
+
+/*
+ * Intel Pro/100B Ethernet Driver
+ */
+
+#include <sys/types.h>
+#include <sys/modctl.h>
+#include <sys/conf.h>
+#include <sys/kmem.h>
+#include <sys/ksynch.h>
+#include <sys/cmn_err.h>
+#include <sys/note.h>
+#include <sys/pci.h>
+#include <sys/pci_cap.h>
+#include <sys/ethernet.h>
+#include <sys/mii.h>
+#include <sys/miiregs.h>
+#include <sys/mac.h>
+#include <sys/mac_ether.h>
+#include <sys/ethernet.h>
+#include <sys/vlan.h>
+#include <sys/list.h>
+#include <sys/sysmacros.h>
+#include <sys/varargs.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+
+#include "iprb.h"
+#include "rcvbundl.h"
+
+/*
+ * Intel has openly documented the programming interface for these
+ * parts in the "Intel 8255x 10/100 Mbps Ethernet Controller Family
+ * Open Source Software Developer Manual".
+ *
+ * While some open source systems have utilized many of the features
+ * of some models in this family (especially scatter gather and IP
+ * checksum support), we have elected to offer only the basic
+ * functionality.  These are only 10/100 parts, and the additional
+ * complexity is not justified by the minimal performance benefit.
+ * KISS.  So, we are only supporting the simple 82557 features.
+ */
+
+static uint16_t	iprb_mii_read(void *, uint8_t, uint8_t);
+static void	iprb_mii_write(void *, uint8_t, uint8_t, uint16_t);
+static void	iprb_mii_notify(void *, link_state_t);
+static int	iprb_attach(dev_info_t *);
+static int	iprb_detach(dev_info_t *);
+static int	iprb_quiesce(dev_info_t *);
+static int	iprb_suspend(dev_info_t *);
+static int	iprb_resume(dev_info_t *);
+static int	iprb_m_stat(void *, uint_t, uint64_t *);
+static int	iprb_m_start(void *);
+static void	iprb_m_stop(void *);
+static int	iprb_m_promisc(void *, boolean_t);
+static int	iprb_m_multicst(void *, boolean_t, const uint8_t *);
+static int	iprb_m_unicst(void *, const uint8_t *);
+static mblk_t	*iprb_m_tx(void *, mblk_t *);
+static void	iprb_m_ioctl(void *, queue_t *, mblk_t *);
+static int	iprb_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
+    const void *);
+static int	iprb_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
+    void *);
+static void	iprb_m_propinfo(void *, const char *, mac_prop_id_t,
+    mac_prop_info_handle_t);
+static void	iprb_destroy(iprb_t *);
+static int	iprb_configure(iprb_t *);
+static void	iprb_eeprom_sendbits(iprb_t *, uint32_t, uint8_t);
+static uint16_t	iprb_eeprom_read(iprb_t *, uint16_t);
+static void	iprb_identify(iprb_t *);
+static int	iprb_cmd_submit(iprb_t *, uint16_t);
+static void	iprb_cmd_reclaim(iprb_t *);
+static int	iprb_cmd_ready(iprb_t *);
+static int	iprb_cmd_drain(iprb_t *);
+static void	iprb_rx_add(iprb_t *);
+static void	iprb_rx_init(iprb_t *);
+static mblk_t	*iprb_rx(iprb_t *);
+static mblk_t	*iprb_send(iprb_t *, mblk_t *);
+static uint_t	iprb_intr(caddr_t, caddr_t);
+static void	iprb_periodic(void *);
+static int	iprb_add_intr(iprb_t *);
+static int	iprb_dma_alloc(iprb_t *, iprb_dma_t *, size_t);
+static void	iprb_dma_free(iprb_dma_t *);
+static iprb_dma_t *iprb_cmd_next(iprb_t *);
+static int	iprb_set_config(iprb_t *);
+static int	iprb_set_unicast(iprb_t *);
+static int	iprb_set_multicast(iprb_t *);
+static int	iprb_set_ucode(iprb_t *);
+static void	iprb_update_stats(iprb_t *);
+static int	iprb_start(iprb_t *);
+static void	iprb_stop(iprb_t *);
+static int	iprb_ddi_attach(dev_info_t *, ddi_attach_cmd_t);
+static int	iprb_ddi_detach(dev_info_t *, ddi_detach_cmd_t);
+static void	iprb_error(iprb_t *, const char *, ...);
+
+static mii_ops_t iprb_mii_ops = {
+	MII_OPS_VERSION,
+	iprb_mii_read,
+	iprb_mii_write,
+	iprb_mii_notify,
+	NULL,		/* reset */
+};
+
+static mac_callbacks_t iprb_m_callbacks = {
+	MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
+	iprb_m_stat,
+	iprb_m_start,
+	iprb_m_stop,
+	iprb_m_promisc,
+	iprb_m_multicst,
+	iprb_m_unicst,
+	iprb_m_tx,
+	NULL,
+	iprb_m_ioctl,	/* mc_ioctl */
+	NULL,		/* mc_getcapab */
+	NULL,		/* mc_open */
+	NULL,		/* mc_close */
+	iprb_m_setprop,
+	iprb_m_getprop,
+	iprb_m_propinfo
+};
+
+
+/*
+ * Stream information
+ */
+DDI_DEFINE_STREAM_OPS(iprb_devops, nulldev, nulldev,
+    iprb_ddi_attach, iprb_ddi_detach, nodev, NULL, D_MP, NULL, iprb_quiesce);
+
+static struct modldrv iprb_modldrv = {
+	&mod_driverops,			/* drv_modops */
+	"Intel 8255x Ethernet",		/* drv_linkinfo */
+	&iprb_devops			/* drv_dev_ops */
+};
+
+static struct modlinkage iprb_modlinkage = {
+	MODREV_1,		/* ml_rev */
+	{ &iprb_modldrv, NULL }	/* ml_linkage */
+};
+
+
+static ddi_device_acc_attr_t acc_attr = {
+	DDI_DEVICE_ATTR_V0,
+	DDI_STRUCTURE_LE_ACC,
+	DDI_STRICTORDER_ACC
+};
+
+static ddi_device_acc_attr_t buf_attr = {
+	DDI_DEVICE_ATTR_V0,
+	DDI_NEVERSWAP_ACC,
+	DDI_STORECACHING_OK_ACC
+};
+
+/*
+ * The 8225x is a 32-bit addressing engine, but it can only address up
+ * to 31 bits on a single transaction.  (Far less in reality it turns
+ * out.)  Statistics buffers have to be 16-byte aligned, and as we
+ * allocate individual data pieces for other things, there is no
+ * compelling reason to use another attribute with support for less
+ * strict alignment.
+ */
+static ddi_dma_attr_t dma_attr = {
+	DMA_ATTR_V0,		/* dma_attr_version */
+	0,			/* dma_attr_addr_lo */
+	0xFFFFFFFFU,		/* dma_attr_addr_hi */
+	0x7FFFFFFFU,		/* dma_attr_count_max */
+	16,			/* dma_attr_align */
+	0x100,			/* dma_attr_burstsizes */
+	1,			/* dma_attr_minxfer */
+	0xFFFFFFFFU,		/* dma_attr_maxxfer */
+	0xFFFFFFFFU,		/* dma_attr_seg */
+	1,			/* dma_attr_sgllen */
+	1,			/* dma_attr_granular */
+	0			/* dma_attr_flags */
+};
+
+#define	DECL_UCODE(x)						\
+	static const uint32_t x ## _WORDS[] = x ## _RCVBUNDLE_UCODE
+DECL_UCODE(D101_A);
+DECL_UCODE(D101_B0);
+DECL_UCODE(D101M_B);
+DECL_UCODE(D101S);
+DECL_UCODE(D102_B);
+DECL_UCODE(D102_C);
+DECL_UCODE(D102_E);
+
+static uint8_t iprb_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+/*
+ * We don't bother allowing for tuning of the CPU saver algorithm.
+ * The ucode has reasonable defaults built-in.  However, some variants
+ * apparently have bug fixes delivered via this ucode, so we still
+ * need to support the ucode upload.
+ */
+typedef struct {
+	uint8_t		rev;
+	uint8_t		length;
+	const uint32_t	*ucode;
+} iprb_ucode_t;
+
+#define	UCODE(x)						\
+	sizeof (x ## _WORDS) / sizeof (uint32_t), x ## _WORDS
+
+static const iprb_ucode_t iprb_ucode[] = {
+	{ REV_82558_A4,	UCODE(D101_A) },
+	{ REV_82558_B0,	UCODE(D101_B0) },
+	{ REV_82559_A0,	UCODE(D101M_B) },
+	{ REV_82559S_A,	UCODE(D101S) },
+	{ REV_82550,	UCODE(D102_B) },
+	{ REV_82550_C,	UCODE(D102_C) },
+	{ REV_82551_F,	UCODE(D102_E) },
+	{ 0 },
+};
+
+int
+_init(void)
+{
+	int	rv;
+	mac_init_ops(&iprb_devops, "iprb");
+	if ((rv = mod_install(&iprb_modlinkage)) != DDI_SUCCESS) {
+		mac_fini_ops(&iprb_devops);
+	}
+	return (rv);
+}
+
+int
+_fini(void)
+{
+	int	rv;
+	if ((rv = mod_remove(&iprb_modlinkage)) == DDI_SUCCESS) {
+		mac_fini_ops(&iprb_devops);
+	}
+	return (rv);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&iprb_modlinkage, modinfop));
+}
+
+int
+iprb_attach(dev_info_t *dip)
+{
+	iprb_t		*ip;
+	uint16_t	w;
+	int		i;
+	mac_register_t	*macp;
+
+	ip = kmem_zalloc(sizeof (*ip), KM_SLEEP);
+	ddi_set_driver_private(dip, ip);
+	ip->dip = dip;
+
+	list_create(&ip->mcast, sizeof (struct iprb_mcast),
+	    offsetof(struct iprb_mcast, node));
+
+	/* we don't support high level interrupts, so we don't need cookies */
+	mutex_init(&ip->culock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&ip->rulock, NULL, MUTEX_DRIVER, NULL);
+
+	if (pci_config_setup(dip, &ip->pcih) != DDI_SUCCESS) {
+		iprb_error(ip, "unable to map configuration space");
+		iprb_destroy(ip);
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_regs_map_setup(dip, 1, &ip->regs, 0, 0, &acc_attr,
+	    &ip->regsh) != DDI_SUCCESS) {
+		iprb_error(ip, "unable to map device registers");
+		iprb_destroy(ip);
+		return (DDI_FAILURE);
+	}
+
+	/* Reset, but first go into idle state */
+	PUT32(ip, CSR_PORT, PORT_SEL_RESET);
+	drv_usecwait(10);
+	PUT32(ip, CSR_PORT, PORT_SW_RESET);
+	drv_usecwait(10);
+	PUT8(ip, CSR_INTCTL, INTCTL_MASK);
+	(void) GET8(ip, CSR_INTCTL);
+
+	/*
+	 * Precalculate watchdog times.
+	 */
+	ip->tx_timeout = drv_usectohz(TX_WATCHDOG * 1000000);
+	ip->rx_timeout = drv_usectohz(RX_WATCHDOG * 1000000);
+
+	iprb_identify(ip);
+
+	/* Obtain our factory MAC address */
+	w = iprb_eeprom_read(ip, 0);
+	ip->factaddr[0] = w & 0xff;
+	ip->factaddr[1] = w >> 8;
+	w = iprb_eeprom_read(ip, 1);
+	ip->factaddr[2] = w & 0xff;
+	ip->factaddr[3] = w >> 8;
+	w = iprb_eeprom_read(ip, 2);
+	ip->factaddr[4] = w & 0xff;
+	ip->factaddr[5] = w >> 8;
+	bcopy(ip->factaddr, ip->curraddr, 6);
+
+	if (ip->resumebug) {
+		/*
+		 * Generally, most devices we will ever see will
+		 * already have fixed firmware.  Since I can't verify
+		 * the validity of the fix (no suitably downrev
+		 * hardware), we'll just do our best to avoid it for
+		 * devices that exhibit this behavior.
+		 */
+		if ((iprb_eeprom_read(ip, 10) & 0x02) == 0) {
+			/* EEPROM fix was already applied, assume safe. */
+			ip->resumebug = B_FALSE;
+		}
+	}
+
+	if ((iprb_eeprom_read(ip, 3) & 0x3) != 0x3) {
+		cmn_err(CE_CONT, "?Enabling RX errata workaround.\n");
+		ip->rxhangbug = B_TRUE;
+	}
+
+	/* Determine whether we have an MII or a legacy 80c24 */
+	w = iprb_eeprom_read(ip, 6);
+	if ((w & 0x3f00) != 0x0600) {
+		if ((ip->miih = mii_alloc(ip, dip, &iprb_mii_ops)) == NULL) {
+			iprb_error(ip, "unable to allocate MII ops vector");
+			iprb_destroy(ip);
+			return (DDI_FAILURE);
+		}
+		if (ip->canpause) {
+			mii_set_pauseable(ip->miih, B_TRUE, B_FALSE);
+		}
+	}
+
+	/* Allocate cmds and tx region */
+	for (i = 0; i < NUM_TX; i++) {
+		/* Command blocks */
+		if (iprb_dma_alloc(ip, &ip->cmds[i], CB_SIZE) != DDI_SUCCESS) {
+			iprb_destroy(ip);
+			return (DDI_FAILURE);
+		}
+	}
+
+	for (i = 0; i < NUM_TX; i++) {
+		iprb_dma_t *cb = &ip->cmds[i];
+		/* Link the command blocks into a ring */
+		PUTCB32(cb, CB_LNK_OFFSET, (ip->cmds[(i + 1) % NUM_TX].paddr));
+	}
+
+	for (i = 0; i < NUM_RX; i++) {
+		/* Rx packet buffers */
+		if (iprb_dma_alloc(ip, &ip->rxb[i], RFD_SIZE) != DDI_SUCCESS) {
+			iprb_destroy(ip);
+			return (DDI_FAILURE);
+		}
+	}
+	if (iprb_dma_alloc(ip, &ip->stats, STATS_SIZE) != DDI_SUCCESS) {
+		iprb_destroy(ip);
+		return (DDI_FAILURE);
+	}
+
+	if (iprb_add_intr(ip) != DDI_SUCCESS) {
+		iprb_destroy(ip);
+		return (DDI_FAILURE);
+	}
+
+	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
+		iprb_error(ip, "unable to allocate mac structure");
+		iprb_destroy(ip);
+		return (DDI_FAILURE);
+	}
+
+	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
+	macp->m_driver = ip;
+	macp->m_dip = dip;
+	macp->m_src_addr = ip->curraddr;
+	macp->m_callbacks = &iprb_m_callbacks;
+	macp->m_min_sdu = 0;
+	macp->m_max_sdu = ETHERMTU;
+	macp->m_margin = VLAN_TAGSZ;
+	if (mac_register(macp, &ip->mach) != 0) {
+		iprb_error(ip, "unable to register mac with framework");
+		mac_free(macp);
+		iprb_destroy(ip);
+		return (DDI_FAILURE);
+	}
+
+	mac_free(macp);
+	return (DDI_SUCCESS);
+}
+
+int
+iprb_detach(dev_info_t *dip)
+{
+	iprb_t *ip;
+
+	ip = ddi_get_driver_private(dip);
+	ASSERT(ip != NULL);
+
+	if (mac_disable(ip->mach) != 0)
+		return (DDI_FAILURE);
+
+	(void) mac_unregister(ip->mach);
+	iprb_destroy(ip);
+	return (DDI_SUCCESS);
+}
+
+int
+iprb_add_intr(iprb_t *ip)
+{
+	int	actual;
+
+	if (ddi_intr_alloc(ip->dip, &ip->intrh, DDI_INTR_TYPE_FIXED, 0, 1,
+	    &actual, DDI_INTR_ALLOC_STRICT) != DDI_SUCCESS) {
+		iprb_error(ip, "failed allocating interrupt handle");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_intr_add_handler(ip->intrh, iprb_intr, ip, NULL) !=
+	    DDI_SUCCESS) {
+		(void) ddi_intr_free(ip->intrh);
+		ip->intrh = NULL;
+		iprb_error(ip, "failed adding interrupt handler");
+		return (DDI_FAILURE);
+	}
+	if (ddi_intr_enable(ip->intrh) != DDI_SUCCESS) {
+		(void) ddi_intr_remove_handler(ip->intrh);
+		(void) ddi_intr_free(ip->intrh);
+		ip->intrh = NULL;
+		iprb_error(ip, "failed enabling interrupt");
+		return (DDI_FAILURE);
+	}
+	return (DDI_SUCCESS);
+}
+
+int
+iprb_dma_alloc(iprb_t *ip, iprb_dma_t *h, size_t size)
+{
+	size_t			rlen;
+	ddi_dma_cookie_t	dmac;
+	uint_t			ndmac;
+
+	if (ddi_dma_alloc_handle(ip->dip, &dma_attr, DDI_DMA_SLEEP, NULL,
+	    &h->dmah) != DDI_SUCCESS) {
+		iprb_error(ip, "unable to allocate dma handle");
+		return (DDI_FAILURE);
+	}
+	if (ddi_dma_mem_alloc(h->dmah, size, &buf_attr, DDI_DMA_CONSISTENT,
+	    DDI_DMA_SLEEP, NULL, &h->vaddr, &rlen, &h->acch) != DDI_SUCCESS) {
+		iprb_error(ip, "unable to allocate dma memory");
+		return (DDI_FAILURE);
+	}
+	bzero(h->vaddr, size);
+	if (ddi_dma_addr_bind_handle(h->dmah, NULL, h->vaddr, size,
+	    DDI_DMA_CONSISTENT | DDI_DMA_RDWR, DDI_DMA_SLEEP, NULL,
+	    &dmac, &ndmac) != DDI_DMA_MAPPED) {
+		iprb_error(ip, "unable to map command memory");
+		return (DDI_FAILURE);
+	}
+	h->paddr = dmac.dmac_address;
+	return (DDI_SUCCESS);
+}
+
+void
+iprb_dma_free(iprb_dma_t *h)
+{
+	if (h->paddr != 0)
+		(void) ddi_dma_unbind_handle(h->dmah);
+	h->paddr = 0;
+	if (h->acch != NULL)
+		ddi_dma_mem_free(&h->acch);
+	h->acch = NULL;
+	if (h->dmah != NULL)
+		ddi_dma_free_handle(&h->dmah);
+	h->dmah = NULL;
+}
+
+void
+iprb_destroy(iprb_t *ip)
+{
+	int i;
+	iprb_mcast_t *mc;
+
+	/* shut down interrupts */
+	if (ip->intrh != NULL) {
+		(void) ddi_intr_disable(ip->intrh);
+		(void) ddi_intr_remove_handler(ip->intrh);
+		(void) ddi_intr_free(ip->intrh);
+	}
+	/* release DMA resources */
+	for (i = 0; i < NUM_TX; i++) {
+		iprb_dma_free(&ip->cmds[i]);
+	}
+	for (i = 0; i < NUM_RX; i++) {
+		iprb_dma_free(&ip->rxb[i]);
+	}
+	iprb_dma_free(&ip->stats);
+
+	if (ip->miih)
+		mii_free(ip->miih);
+
+	/* clean up the multicast list */
+	while ((mc = list_head(&ip->mcast)) != NULL) {
+		list_remove(&ip->mcast, mc);
+		kmem_free(mc, sizeof (*mc));
+	}
+
+	/* tear down register mappings */
+	if (ip->pcih)
+		pci_config_teardown(&ip->pcih);
+	if (ip->regsh)
+		ddi_regs_map_free(&ip->regsh);
+
+	/* clean the dip */
+	ddi_set_driver_private(ip->dip, NULL);
+
+	list_destroy(&ip->mcast);
+	mutex_destroy(&ip->culock);
+	mutex_destroy(&ip->rulock);
+
+	/* and finally toss the structure itself */
+	kmem_free(ip, sizeof (*ip));
+}
+
+void
+iprb_identify(iprb_t *ip)
+{
+	ip->devid = pci_config_get16(ip->pcih, PCI_CONF_DEVID);
+	ip->revid = pci_config_get8(ip->pcih, PCI_CONF_REVID);
+
+	switch (ip->devid) {
+	case 0x1229:	/* 8255x family */
+	case 0x1030:	/* Intel InBusiness */
+
+		if (ip->revid >= REV_82558_A4) {
+			ip->canpause = B_TRUE;
+			ip->canmwi = B_TRUE;
+		} else {
+			ip->is557 = B_TRUE;
+		}
+		if (ip->revid >= REV_82559_A0)
+			ip->resumebug = B_TRUE;
+		break;
+
+	case 0x1209:	/* Embedded 82559ER */
+		ip->canpause = B_TRUE;
+		ip->resumebug = B_TRUE;
+		ip->canmwi = B_TRUE;
+		break;
+
+	case 0x2449:	/* ICH2 */
+	case 0x1031:	/* Pro/100 VE (ICH3) */
+	case 0x1032:	/* Pro/100 VE (ICH3) */
+	case 0x1033:	/* Pro/100 VM (ICH3) */
+	case 0x1034:	/* Pro/100 VM (ICH3) */
+	case 0x1038:	/* Pro/100 VM (ICH3) */
+		ip->resumebug = B_TRUE;
+		if (ip->revid >= REV_82558_A4)
+			ip->canpause = B_TRUE;
+		break;
+
+	default:
+		if (ip->revid >= REV_82558_A4)
+			ip->canpause = B_TRUE;
+		break;
+	}
+
+	/* Allow property override MWI support - not normally needed. */
+	if (ddi_prop_get_int(DDI_DEV_T_ANY, ip->dip, 0, "MWIEnable", 1) == 0) {
+		ip->canmwi = B_FALSE;
+	}
+}
+
+void
+iprb_eeprom_sendbits(iprb_t *ip, uint32_t val, uint8_t nbits)
+{
+	uint32_t	mask;
+	uint16_t	x;
+
+	mask = 1U << (nbits - 1);
+	while (mask) {
+		x = (mask & val) ? EEPROM_EEDI : 0;
+		PUT16(ip, CSR_EECTL, x | EEPROM_EECS);
+		drv_usecwait(100);
+		PUT16(ip, CSR_EECTL, x | EEPROM_EESK | EEPROM_EECS);
+		drv_usecwait(100);
+		PUT16(ip, CSR_EECTL, x | EEPROM_EECS);
+		drv_usecwait(100);
+		mask >>= 1;
+	}
+}
+
+uint16_t
+iprb_eeprom_read(iprb_t *ip, uint16_t address)
+{
+	uint16_t	val;
+	int		mask;
+	uint16_t	n;
+	uint16_t	bits;
+
+	/* if we don't know the address size yet call again to determine it */
+	if ((address != 0) && (ip->eeprom_bits == 0))
+		(void) iprb_eeprom_read(ip, 0);
+
+	if ((bits = ip->eeprom_bits) == 0) {
+		bits = 8;
+		ASSERT(address == 0);
+	}
+	/* enable the EEPROM chip select */
+	PUT16(ip, CSR_EECTL, EEPROM_EECS);
+	drv_usecwait(100);
+
+	/* send a read command */
+	iprb_eeprom_sendbits(ip, 6, 3);
+	n = 0;
+	for (mask = (1U << (bits - 1)); mask != 0; mask >>= 1) {
+		uint16_t x = (mask & address) ? EEPROM_EEDI : 0;
+		PUT16(ip, CSR_EECTL, x | EEPROM_EECS);
+		drv_usecwait(100);
+		PUT16(ip, CSR_EECTL, x | EEPROM_EESK | EEPROM_EECS);
+		drv_usecwait(100);
+		PUT16(ip, CSR_EECTL, x | EEPROM_EECS);
+		drv_usecwait(100);
+
+		n++;
+		/* check the dummy 0 bit */
+		if ((GET16(ip, CSR_EECTL) & EEPROM_EEDO) == 0) {
+			if (ip->eeprom_bits == 0) {
+				ip->eeprom_bits = n;
+				cmn_err(CE_CONT, "?EEPROM size %d words.\n",
+				    1U << ip->eeprom_bits);
+			}
+			break;
+		}
+	}
+	if (n != ip->eeprom_bits) {
+		iprb_error(ip, "cannot determine EEPROM size (%d, %d)",
+		    ip->eeprom_bits, n);
+	}
+
+	/* shift out a 16-bit word */
+	val = 0;
+	for (mask = 0x8000; mask; mask >>= 1) {
+		PUT16(ip, CSR_EECTL, EEPROM_EECS | EEPROM_EESK);
+		drv_usecwait(100);
+		if (GET16(ip, CSR_EECTL) & EEPROM_EEDO)
+			val |= mask;
+		drv_usecwait(100);
+		PUT16(ip, CSR_EECTL, EEPROM_EECS);
+		drv_usecwait(100);
+	}
+
+	/* and disable the eeprom */
+	PUT16(ip, CSR_EECTL, 0);
+	drv_usecwait(100);
+
+	return (val);
+}
+
+int
+iprb_cmd_ready(iprb_t *ip)
+{
+	/* wait for pending SCB commands to be accepted */
+	for (int cnt = 1000000; cnt != 0; cnt -= 10) {
+		if (GET8(ip, CSR_CMD) == 0) {
+			return (DDI_SUCCESS);
+		}
+		drv_usecwait(10);
+	}
+	iprb_error(ip, "timeout waiting for chip to become ready");
+	return (DDI_FAILURE);
+}
+
+void
+iprb_cmd_reclaim(iprb_t *ip)
+{
+	while (ip->cmd_count) {
+		iprb_dma_t *cb = &ip->cmds[ip->cmd_tail];
+
+		SYNCCB(cb, CB_STS_OFFSET, 2, DDI_DMA_SYNC_FORKERNEL);
+		if ((GETCB16(cb, CB_STS_OFFSET) & CB_STS_C) == 0) {
+			break;
+		}
+
+		ip->cmd_tail++;
+		ip->cmd_tail %= NUM_TX;
+		ip->cmd_count--;
+		if (ip->cmd_count == 0) {
+			ip->tx_wdog = 0;
+		} else {
+			ip->tx_wdog = ddi_get_time();
+		}
+	}
+}
+
+int
+iprb_cmd_drain(iprb_t *ip)
+{
+	for (int i = 1000000; i; i -= 10) {
+		iprb_cmd_reclaim(ip);
+		if (ip->cmd_count == 0)
+			return (DDI_SUCCESS);
+		drv_usecwait(10);
+	}
+	iprb_error(ip, "time out waiting for commands to drain");
+	return (DDI_FAILURE);
+}
+
+int
+iprb_cmd_submit(iprb_t *ip, uint16_t cmd)
+{
+	iprb_dma_t	*ncb = &ip->cmds[ip->cmd_head];
+	iprb_dma_t	*lcb = &ip->cmds[ip->cmd_last];
+
+	/* If this command will consume the last CB, interrupt when done */
+	ASSERT((ip->cmd_count) < NUM_TX);
+	if (ip->cmd_count == (NUM_TX - 1)) {
+		cmd |= CB_CMD_I;
+	}
+
+	/* clear the status entry */
+	PUTCB16(ncb, CB_STS_OFFSET, 0);
+
+	/* suspend upon completion of this new command */
+	cmd |= CB_CMD_S;
+	PUTCB16(ncb, CB_CMD_OFFSET, cmd);
+	SYNCCB(ncb, 0, 0, DDI_DMA_SYNC_FORDEV);
+
+	/* clear the suspend flag from the last submitted command */
+	SYNCCB(lcb, CB_CMD_OFFSET, 2, DDI_DMA_SYNC_FORKERNEL);
+	PUTCB16(lcb, CB_CMD_OFFSET, GETCB16(lcb, CB_CMD_OFFSET) & ~CB_CMD_S);
+	SYNCCB(lcb, CB_CMD_OFFSET, 2, DDI_DMA_SYNC_FORDEV);
+
+
+	/*
+	 * If the chip has a resume bug, then we need to try this as a work
+	 * around.  Some anecdotal evidence is that this will help solve
+	 * the resume bug.  Its a performance hit, but only if the EEPROM
+	 * is not updated.  (In theory we could do this only for 10Mbps HDX,
+	 * but since it should just about never get used, we keep it simple.)
+	 */
+	if (ip->resumebug) {
+		if (iprb_cmd_ready(ip) != DDI_SUCCESS)
+			return (DDI_FAILURE);
+		PUT8(ip, CSR_CMD, CUC_NOP);
+		(void) GET8(ip, CSR_CMD);
+		drv_usecwait(1);
+	}
+
+	/* wait for the SCB to be ready to accept a new command */
+	if (iprb_cmd_ready(ip) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+
+	/*
+	 * Finally we can resume the CU.  Note that if this the first
+	 * command in the sequence (i.e. if the CU is IDLE), or if the
+	 * CU is already busy working, then this CU resume command
+	 * will not have any effect.
+	 */
+	PUT8(ip, CSR_CMD, CUC_RESUME);
+	(void) GET8(ip, CSR_CMD);	/* flush CSR */
+
+	ip->tx_wdog = ddi_get_time();
+	ip->cmd_last = ip->cmd_head;
+	ip->cmd_head++;
+	ip->cmd_head %= NUM_TX;
+	ip->cmd_count++;
+
+	return (DDI_SUCCESS);
+}
+
+iprb_dma_t *
+iprb_cmd_next(iprb_t *ip)
+{
+	if (ip->cmd_count == NUM_TX) {
+		return (NULL);
+	}
+	ASSERT(ip->cmd_count < NUM_TX);
+	return (&ip->cmds[ip->cmd_head]);
+}
+
+int
+iprb_set_unicast(iprb_t *ip)
+{
+	iprb_dma_t	*cb;
+
+	ASSERT(mutex_owned(&ip->culock));
+
+	if ((cb = iprb_cmd_next(ip)) == NULL)
+		return (DDI_FAILURE);
+
+	PUTCBEA(cb, CB_IAS_ADR_OFFSET, ip->curraddr);
+	return (iprb_cmd_submit(ip, CB_CMD_IAS));
+}
+
+int
+iprb_set_multicast(iprb_t *ip)
+{
+	iprb_dma_t	*cb;
+	iprb_mcast_t	*mc;
+	int		i;
+	list_t		*l;
+
+	ASSERT(mutex_owned(&ip->culock));
+
+	if ((ip->nmcast <= 0) || (ip->nmcast > CB_MCS_CNT_MAX)) {
+		/*
+		 * Only send the list if the total number of multicast
+		 * address is nonzero and small enough to fit.  We
+		 * don't error out if it is too big, because in that
+		 * case we will use the "allmulticast" support
+		 * via iprb_set_config instead.
+		 */
+		return (DDI_SUCCESS);
+	}
+
+	if ((cb = iprb_cmd_next(ip)) == NULL) {
+		return (DDI_FAILURE);
+	}
+
+	l = &ip->mcast;
+	for (mc = list_head(l), i = 0; mc; mc = list_next(l, mc), i++) {
+		PUTCBEA(cb, CB_MCS_ADR_OFFSET + (i * 6), mc->addr);
+	}
+	ASSERT(i == ip->nmcast);
+	PUTCB16(cb, CB_MCS_CNT_OFFSET, i);
+	return (iprb_cmd_submit(ip, CB_CMD_MCS));
+}
+
+int
+iprb_set_config(iprb_t *ip)
+{
+	iprb_dma_t *cb;
+
+	ASSERT(mutex_owned(&ip->culock));
+	if ((cb = iprb_cmd_next(ip)) == NULL) {
+		return (DDI_FAILURE);
+	}
+	PUTCB8(cb, CB_CONFIG_OFFSET + 0, 0x16);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 1, 0x8);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 2, 0);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 3, (ip->canmwi ? 1 : 0));
+	PUTCB8(cb, CB_CONFIG_OFFSET + 4, 0);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 5, 0);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 6, (ip->promisc ? 0x80 : 0) | 0x3a);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 7, (ip->promisc ? 0 : 0x1) | 2);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 8, (ip->miih ? 0x1 : 0));
+	PUTCB8(cb, CB_CONFIG_OFFSET + 9, 0);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 10, 0x2e);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 11, 0);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 12, (ip->is557 ? 0 : 1) | 0x60);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 13, 0);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 14, 0xf2);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 15,
+	    (ip->miih ? 0x80 : 0) | (ip->promisc ? 0x1 : 0) | 0x48);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 16, 0);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 17, (ip->canpause ? 0x40 : 0));
+	PUTCB8(cb, CB_CONFIG_OFFSET + 18, (ip->is557 ? 0 : 0x8) | 0xf2);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 19,
+	    ((ip->revid < REV_82558_B0) ? 0 : 0x80) |
+	    (ip->canpause ? 0x18 : 0));
+	PUTCB8(cb, CB_CONFIG_OFFSET + 20, 0x3f);
+	PUTCB8(cb, CB_CONFIG_OFFSET + 21,
+	    ((ip->nmcast >= CB_MCS_CNT_MAX) ? 0x8 : 0) | 0x5);
+
+	return (iprb_cmd_submit(ip, CB_CMD_CONFIG));
+}
+
+int
+iprb_set_ucode(iprb_t *ip)
+{
+	iprb_dma_t *cb;
+	const iprb_ucode_t *uc = NULL;
+	int i;
+
+	for (i = 0; iprb_ucode[i].length; i++) {
+		if (iprb_ucode[i].rev == ip->revid) {
+			uc = &iprb_ucode[i];
+			break;
+		}
+	}
+	if (uc == NULL) {
+		/* no matching firmware found, assume success */
+		return (DDI_SUCCESS);
+	}
+
+	ASSERT(mutex_owned(&ip->culock));
+	if ((cb = iprb_cmd_next(ip)) == NULL) {
+		return (DDI_FAILURE);
+	}
+	for (i = 0; i < uc->length; i++) {
+		PUTCB32(cb, (CB_UCODE_OFFSET + i * 4), uc->ucode[i]);
+	}
+	return (iprb_cmd_submit(ip, CB_CMD_UCODE));
+}
+
+int
+iprb_configure(iprb_t *ip)
+{
+	ASSERT(mutex_owned(&ip->culock));
+
+	if (iprb_cmd_drain(ip) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+
+	if (iprb_set_config(ip) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+	if (iprb_set_unicast(ip) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+	if (iprb_set_multicast(ip) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+
+	return (DDI_SUCCESS);
+}
+
+void
+iprb_stop(iprb_t *ip)
+{
+	/* go idle */
+	PUT32(ip, CSR_PORT, PORT_SEL_RESET);
+	(void) GET32(ip, CSR_PORT);
+	drv_usecwait(50);
+
+	/* shut off device interrupts */
+	PUT8(ip, CSR_INTCTL, INTCTL_MASK);
+}
+
+int
+iprb_start(iprb_t *ip)
+{
+	iprb_dma_t *cb;
+
+	ASSERT(mutex_owned(&ip->rulock));
+	ASSERT(mutex_owned(&ip->culock));
+
+	/* Reset, but first go into idle state */
+	PUT32(ip, CSR_PORT, PORT_SEL_RESET);
+	(void) GET32(ip, CSR_PORT);
+	drv_usecwait(50);
+
+	PUT32(ip, CSR_PORT, PORT_SW_RESET);
+	(void) GET32(ip, CSR_PORT);
+	drv_usecwait(10);
+	PUT8(ip, CSR_INTCTL, INTCTL_MASK);
+
+	/* Reset pointers */
+	ip->cmd_head = ip->cmd_tail = 0;
+	ip->cmd_last = NUM_TX - 1;
+
+	if (iprb_cmd_ready(ip) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+	PUT32(ip, CSR_GEN_PTR, 0);
+	PUT8(ip, CSR_CMD, CUC_CUBASE);
+	(void) GET8(ip, CSR_CMD);
+
+	if (iprb_cmd_ready(ip) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+	PUT32(ip, CSR_GEN_PTR, 0);
+	PUT8(ip, CSR_CMD, RUC_RUBASE);
+	(void) GET8(ip, CSR_CMD);
+
+	/* Send a NOP.  This will be the first command seen by the device. */
+	cb = iprb_cmd_next(ip);
+	ASSERT(cb);
+	if (iprb_cmd_submit(ip, CB_CMD_NOP) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+
+	/* as that was the first command, go ahead and submit a CU start */
+	if (iprb_cmd_ready(ip) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+	PUT32(ip, CSR_GEN_PTR, cb->paddr);
+	PUT8(ip, CSR_CMD, CUC_START);
+	(void) GET8(ip, CSR_CMD);
+
+	/* Upload firmware. */
+	if (iprb_set_ucode(ip) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+
+	/* Set up RFDs */
+	iprb_rx_init(ip);
+
+	PUT32(ip, CSR_GEN_PTR, ip->rxb[0].paddr);
+	/* wait for the SCB */
+	(void) iprb_cmd_ready(ip);
+	PUT8(ip, CSR_CMD, RUC_START);
+	(void) GET8(ip, CSR_CMD);	/* flush CSR */
+
+	/* Enable device interrupts */
+	PUT8(ip, CSR_INTCTL, 0);
+	(void) GET8(ip, CSR_INTCTL);
+
+	return (DDI_SUCCESS);
+}
+
+void
+iprb_update_stats(iprb_t *ip)
+{
+	iprb_dma_t	*sp = &ip->stats;
+	time_t		tstamp;
+	int		i;
+
+	ASSERT(mutex_owned(&ip->culock));
+
+	/* Collect the hardware stats, but don't keep redoing it */
+	if ((tstamp = ddi_get_time()) == ip->stats_time) {
+		return;
+	}
+
+	PUTSTAT(sp, STATS_DONE_OFFSET, 0);
+	SYNCSTATS(sp, 0, 0, DDI_DMA_SYNC_FORDEV);
+
+	if (iprb_cmd_ready(ip) != DDI_SUCCESS)
+		return;
+	PUT32(ip, CSR_GEN_PTR, sp->paddr);
+	PUT8(ip, CSR_CMD, CUC_STATSBASE);
+	(void) GET8(ip, CSR_CMD);
+
+	if (iprb_cmd_ready(ip) != DDI_SUCCESS)
+		return;
+	PUT8(ip, CSR_CMD, CUC_STATS_RST);
+	(void) GET8(ip, CSR_CMD);	/* flush wb */
+
+	for (i = 10000; i; i -= 10) {
+		SYNCSTATS(sp, 0, 0, DDI_DMA_SYNC_FORKERNEL);
+		if (GETSTAT(sp, STATS_DONE_OFFSET) == STATS_RST_DONE) {
+			/* yay stats are updated */
+			break;
+		}
+		drv_usecwait(10);
+	}
+	if (i == 0) {
+		iprb_error(ip, "time out acquiring hardware statistics");
+		return;
+	}
+
+	ip->ex_coll += GETSTAT(sp, STATS_TX_MAXCOL_OFFSET);
+	ip->late_coll += GETSTAT(sp, STATS_TX_LATECOL_OFFSET);
+	ip->uflo += GETSTAT(sp, STATS_TX_UFLO_OFFSET);
+	ip->defer_xmt += GETSTAT(sp, STATS_TX_DEFER_OFFSET);
+	ip->one_coll += GETSTAT(sp, STATS_TX_ONECOL_OFFSET);
+	ip->multi_coll += GETSTAT(sp, STATS_TX_MULTCOL_OFFSET);
+	ip->collisions += GETSTAT(sp, STATS_TX_TOTCOL_OFFSET);
+	ip->fcs_errs += GETSTAT(sp, STATS_RX_FCS_OFFSET);
+	ip->align_errs += GETSTAT(sp, STATS_RX_ALIGN_OFFSET);
+	ip->norcvbuf += GETSTAT(sp, STATS_RX_NOBUF_OFFSET);
+	ip->oflo += GETSTAT(sp, STATS_RX_OFLO_OFFSET);
+	ip->runt += GETSTAT(sp, STATS_RX_SHORT_OFFSET);
+
+	ip->stats_time = tstamp;
+}
+
+mblk_t *
+iprb_send(iprb_t *ip, mblk_t *mp)
+{
+	iprb_dma_t	*cb;
+	size_t		sz;
+
+	ASSERT(mutex_owned(&ip->culock));
+
+	/* possibly reclaim some CBs */
+	iprb_cmd_reclaim(ip);
+
+	cb = iprb_cmd_next(ip);
+
+	if (cb == NULL) {
+		/* flow control */
+		ip->wantw = B_TRUE;
+		return (mp);
+	}
+
+	if ((sz = msgsize(mp)) > (ETHERMAX + VLAN_TAGSZ)) {
+		/* Generally this should never occur */
+		ip->macxmt_errs++;
+		freemsg(mp);
+		return (NULL);
+	}
+
+	ip->opackets++;
+	ip->obytes += sz;
+
+	PUTCB32(cb, CB_TX_TBD_OFFSET, 0xffffffffU);
+	PUTCB16(cb, CB_TX_COUNT_OFFSET, (sz & 0x3fff) | CB_TX_EOF);
+	PUTCB8(cb, CB_TX_THRESH_OFFSET, (sz / 8) & 0xff);
+	PUTCB8(cb, CB_TX_NUMBER_OFFSET, 0);
+	mcopymsg(mp, cb->vaddr + CB_TX_DATA_OFFSET);
+	if (cb->vaddr[CB_TX_DATA_OFFSET] & 0x1) {
+		if (bcmp(cb->vaddr + CB_TX_DATA_OFFSET, &iprb_bcast, 6) != 0) {
+			ip->multixmt++;
+		} else {
+			ip->brdcstxmt++;
+		}
+	}
+	SYNCCB(cb, 0, CB_TX_DATA_OFFSET + sz, DDI_DMA_SYNC_FORDEV);
+
+	if (iprb_cmd_submit(ip, CB_CMD_TX) != DDI_SUCCESS) {
+		ip->macxmt_errs++;
+	}
+
+	return (NULL);
+}
+
+void
+iprb_rx_add(iprb_t *ip)
+{
+	uint16_t	last, curr, next;
+	iprb_dma_t	*rfd, *nfd, *lfd;
+
+	ASSERT(mutex_owned(&ip->rulock));
+
+	curr = ip->rx_index;
+	last = ip->rx_last;
+	next = (curr + 1) % NUM_RX;
+
+	ip->rx_last = curr;
+	ip->rx_index = next;
+
+	lfd = &ip->rxb[last];
+	rfd = &ip->rxb[curr];
+	nfd = &ip->rxb[next];
+
+	PUTRFD32(rfd, RFD_LNK_OFFSET, nfd->paddr);
+	PUTRFD16(rfd, RFD_CTL_OFFSET, RFD_CTL_EL);
+	PUTRFD16(rfd, RFD_SIZ_OFFSET, RFD_SIZE - RFD_PKT_OFFSET);
+	PUTRFD16(rfd, RFD_CNT_OFFSET, 0);
+	SYNCRFD(rfd, 0, RFD_PKT_OFFSET, DDI_DMA_SYNC_FORDEV);
+	/* clear the suspend & EL bits from the previous RFD */
+	PUTRFD16(lfd, RFD_CTL_OFFSET, 0);
+	SYNCRFD(rfd, RFD_CTL_OFFSET, 2, DDI_DMA_SYNC_FORDEV);
+}
+
+void
+iprb_rx_init(iprb_t *ip)
+{
+	ip->rx_index = 0;
+	ip->rx_last = NUM_RX - 1;
+	for (int i = 0; i < NUM_RX; i++)
+		iprb_rx_add(ip);
+	ip->rx_index = 0;
+	ip->rx_last = NUM_RX - 1;
+}
+
+mblk_t *
+iprb_rx(iprb_t *ip)
+{
+	iprb_dma_t	*rfd;
+	uint16_t	cnt;
+	uint16_t	sts;
+	int		i;
+	mblk_t		*mplist;
+	mblk_t		**mpp;
+	mblk_t		*mp;
+
+	mplist = NULL;
+	mpp = &mplist;
+
+	for (i = 0; i < NUM_RX; i++) {
+		rfd = &ip->rxb[ip->rx_index];
+		SYNCRFD(rfd, RFD_STS_OFFSET, 2, DDI_DMA_SYNC_FORKERNEL);
+		if ((GETRFD16(rfd, RFD_STS_OFFSET) & RFD_STS_C) == 0) {
+			break;
+		}
+
+		ip->rx_wdog = ddi_get_time();
+
+		SYNCRFD(rfd, 0, 0, DDI_DMA_SYNC_FORKERNEL);
+		cnt = GETRFD16(rfd, RFD_CNT_OFFSET);
+		cnt &= ~(RFD_CNT_EOF | RFD_CNT_F);
+		sts = GETRFD16(rfd, RFD_STS_OFFSET);
+
+		if (cnt > (ETHERMAX + VLAN_TAGSZ)) {
+			ip->toolong++;
+			iprb_rx_add(ip);
+			continue;
+		}
+		if (((sts & RFD_STS_OK) == 0) && (sts & RFD_STS_ERRS)) {
+			iprb_rx_add(ip);
+			continue;
+		}
+		if ((mp = allocb(cnt, BPRI_MED)) == NULL) {
+			ip->norcvbuf++;
+			iprb_rx_add(ip);
+			continue;
+		}
+		bcopy(rfd->vaddr + RFD_PKT_OFFSET, mp->b_wptr, cnt);
+
+		/* return it to the RFD list */
+		iprb_rx_add(ip);
+
+		mp->b_wptr += cnt;
+		ip->ipackets++;
+		ip->rbytes += cnt;
+		if (mp->b_rptr[0] & 0x1) {
+			if (bcmp(mp->b_rptr, &iprb_bcast, 6) != 0) {
+				ip->multircv++;
+			} else {
+				ip->brdcstrcv++;
+			}
+		}
+		*mpp = mp;
+		mpp = &mp->b_next;
+	}
+	return (mplist);
+}
+
+int
+iprb_m_promisc(void *arg, boolean_t on)
+{
+	iprb_t *ip = arg;
+
+	mutex_enter(&ip->culock);
+	ip->promisc = on;
+	if (ip->running && !ip->suspended)
+		(void) iprb_configure(ip);
+	mutex_exit(&ip->culock);
+	return (0);
+}
+
+int
+iprb_m_unicst(void *arg, const uint8_t *macaddr)
+{
+	iprb_t *ip = arg;
+
+	mutex_enter(&ip->culock);
+	bcopy(macaddr, ip->curraddr, 6);
+	if (ip->running && !ip->suspended)
+		(void) iprb_configure(ip);
+	mutex_exit(&ip->culock);
+	return (0);
+}
+
+int
+iprb_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
+{
+	iprb_t		*ip = arg;
+	list_t		*l = &ip->mcast;
+	iprb_mcast_t	*mc;
+
+	if (add) {
+		mc = kmem_alloc(sizeof (*mc), KM_NOSLEEP);
+		if (mc == NULL) {
+			return (ENOMEM);
+		}
+		bcopy(macaddr, mc->addr, 6);
+		mutex_enter(&ip->culock);
+		list_insert_head(l, mc);
+		ip->nmcast++;
+		if (ip->running && !ip->suspended)
+			(void) iprb_configure(ip);
+		mutex_exit(&ip->culock);
+	} else {
+		mutex_enter(&ip->culock);
+		for (mc = list_head(l); mc != NULL; mc = list_next(l, mc)) {
+			if (bcmp(macaddr, mc->addr, 6) == 0) {
+				list_remove(&ip->mcast, mc);
+				ip->nmcast--;
+				if (ip->running && !ip->suspended)
+					(void) iprb_configure(ip);
+				break;
+			}
+		}
+		mutex_exit(&ip->culock);
+		if (mc)
+			kmem_free(mc, sizeof (*mc));
+	}
+	return (0);
+}
+
+int
+iprb_m_start(void *arg)
+{
+	int rv;
+	iprb_t *ip = arg;
+
+	mutex_enter(&ip->rulock);
+	mutex_enter(&ip->culock);
+	rv = ip->suspended ? 0 : iprb_start(ip);
+	if (rv == 0)
+		ip->running = B_TRUE;
+	ip->perh = ddi_periodic_add(iprb_periodic, ip, 5000000000, 0);
+	mutex_exit(&ip->culock);
+	mutex_exit(&ip->rulock);
+	if (rv == 0) {
+		if (ip->miih)
+			mii_start(ip->miih);
+		else
+			/* might be a lie. */
+			mac_link_update(ip->mach, LINK_STATE_UP);
+	}
+	return (rv ? EIO : 0);
+}
+
+void
+iprb_m_stop(void *arg)
+{
+	iprb_t *ip = arg;
+
+	if (ip->miih) {
+		mii_stop(ip->miih);
+	} else {
+		mac_link_update(ip->mach, LINK_STATE_DOWN);
+	}
+	mutex_enter(&ip->rulock);
+	mutex_enter(&ip->culock);
+	ddi_periodic_delete(ip->perh);
+
+	if (!ip->suspended) {
+		iprb_update_stats(ip);
+		iprb_stop(ip);
+	}
+	ip->running = B_FALSE;
+	mutex_exit(&ip->culock);
+	mutex_exit(&ip->rulock);
+}
+
+int
+iprb_m_stat(void *arg, uint_t stat, uint64_t *val)
+{
+	iprb_t		*ip = arg;
+
+	if (ip->miih && (mii_m_getstat(ip->miih, stat, val) == 0)) {
+		return (0);
+	}
+
+	mutex_enter(&ip->culock);
+	if ((!ip->suspended) && (ip->running)) {
+		iprb_update_stats(ip);
+	}
+	mutex_exit(&ip->culock);
+
+	switch (stat) {
+	case MAC_STAT_IFSPEED:
+		if (ip->miih == NULL) {
+			*val = 10000000;	/* 10 Mbps */
+		}
+		break;
+	case ETHER_STAT_LINK_DUPLEX:
+		if (ip->miih == NULL) {
+			*val = LINK_DUPLEX_UNKNOWN;
+		}
+		break;
+	case MAC_STAT_MULTIRCV:
+		*val = ip->multircv;
+		break;
+	case MAC_STAT_BRDCSTRCV:
+		*val = ip->brdcstrcv;
+		break;
+	case MAC_STAT_MULTIXMT:
+		*val = ip->multixmt;
+		break;
+	case MAC_STAT_BRDCSTXMT:
+		*val = ip->brdcstxmt;
+		break;
+	case MAC_STAT_IPACKETS:
+		* val = ip->ipackets;
+		break;
+	case MAC_STAT_RBYTES:
+		*val = ip->rbytes;
+		break;
+	case MAC_STAT_OPACKETS:
+		*val = ip->opackets;
+		break;
+	case MAC_STAT_OBYTES:
+		*val = ip->obytes;
+		break;
+	case MAC_STAT_NORCVBUF:
+		*val = ip->norcvbuf;
+		break;
+	case MAC_STAT_COLLISIONS:
+		*val = ip->collisions;
+		break;
+	case MAC_STAT_IERRORS:
+		*val = ip->align_errs +
+		    ip->fcs_errs +
+		    ip->norcvbuf +
+		    ip->runt +
+		    ip->toolong +
+		    ip->macrcv_errs;
+		break;
+	case MAC_STAT_OERRORS:
+		*val = ip->ex_coll +
+		    ip->late_coll +
+		    ip->uflo +
+		    ip->macxmt_errs +
+		    ip->nocarrier;
+		break;
+	case ETHER_STAT_ALIGN_ERRORS:
+		*val = ip->align_errs;
+		break;
+	case ETHER_STAT_FCS_ERRORS:
+		*val = ip->fcs_errs;
+		break;
+	case ETHER_STAT_DEFER_XMTS:
+		*val = ip->defer_xmt;
+		break;
+	case ETHER_STAT_FIRST_COLLISIONS:
+		*val = ip->one_coll + ip->multi_coll + ip->ex_coll;
+		break;
+	case ETHER_STAT_MULTI_COLLISIONS:
+		*val = ip->multi_coll;
+		break;
+	case ETHER_STAT_TX_LATE_COLLISIONS:
+		*val = ip->late_coll;
+		break;
+	case ETHER_STAT_EX_COLLISIONS:
+		*val = ip->ex_coll;
+		break;
+	case MAC_STAT_OVERFLOWS:
+		*val = ip->oflo;
+		break;
+	case MAC_STAT_UNDERFLOWS:
+		*val = ip->uflo;
+		break;
+	case ETHER_STAT_TOOSHORT_ERRORS:
+		*val = ip->runt;
+		break;
+	case ETHER_STAT_TOOLONG_ERRORS:
+		*val = ip->toolong;
+		break;
+	case ETHER_STAT_CARRIER_ERRORS:
+		*val = ip->nocarrier;	/* reported only for "suspend" */
+		break;
+	case ETHER_STAT_MACXMT_ERRORS:
+		*val = ip->macxmt_errs;
+		break;
+	case ETHER_STAT_MACRCV_ERRORS:
+		*val = ip->macrcv_errs;
+		break;
+	default:
+		return (ENOTSUP);
+	}
+	return (0);
+}
+
+void
+iprb_m_propinfo(void *arg, const char *name, mac_prop_id_t id,
+    mac_prop_info_handle_t pih)
+{
+	iprb_t *ip = arg;
+
+	if (ip->miih != NULL) {
+		mii_m_propinfo(ip->miih, name, id, pih);
+		return;
+	}
+	switch (id) {
+	case MAC_PROP_DUPLEX:
+	case MAC_PROP_SPEED:
+		mac_prop_info_set_perm(pih, MAC_PROP_PERM_READ);
+		break;
+	}
+}
+
+int
+iprb_m_getprop(void *arg, const char *name, mac_prop_id_t id, uint_t sz,
+    void *val)
+{
+	iprb_t *ip = arg;
+	uint64_t x;
+
+	if (ip->miih != NULL) {
+		return (mii_m_getprop(ip->miih, name, id, sz, val));
+	}
+	switch (id) {
+	case MAC_PROP_SPEED:
+		x = 10000000;
+		bcopy(&x, val, sizeof (x));
+		return (0);
+
+	case MAC_PROP_DUPLEX:
+		x = LINK_DUPLEX_UNKNOWN;
+		bcopy(&x, val, sizeof (x));
+		return (0);
+	}
+
+	return (ENOTSUP);
+}
+
+int
+iprb_m_setprop(void *arg, const char *name, mac_prop_id_t id, uint_t sz,
+    const void *val)
+{
+	iprb_t *ip = arg;
+
+	if (ip->miih != NULL) {
+		return (mii_m_setprop(ip->miih, name, id, sz, val));
+	}
+	return (ENOTSUP);
+}
+
+mblk_t *
+iprb_m_tx(void *arg, mblk_t *mp)
+{
+	iprb_t *ip = arg;
+	mblk_t *nmp;
+
+	mutex_enter(&ip->culock);
+
+	while (mp != NULL) {
+		nmp = mp->b_next;
+		mp->b_next = NULL;
+		if (ip->suspended) {
+			freemsg(mp);
+			ip->nocarrier++;
+			mp = nmp;
+			continue;
+		}
+		if ((mp = iprb_send(ip, mp)) != NULL) {
+			mp->b_next = nmp;
+			break;
+		}
+		mp = nmp;
+	}
+	mutex_exit(&ip->culock);
+	return (mp);
+}
+
+void
+iprb_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
+{
+	iprb_t	*ip = arg;
+
+	if ((ip->miih != NULL) && (mii_m_loop_ioctl(ip->miih, wq, mp)))
+		return;
+
+	miocnak(wq, mp, 0, EINVAL);
+}
+
+uint16_t
+iprb_mii_read(void *arg, uint8_t phy, uint8_t reg)
+{
+	iprb_t	*ip = arg;
+	uint32_t mdi;
+
+	/*
+	 * NB: we are guaranteed by the MII layer not to be suspended.
+	 * Furthermore, we have an independent MII register.
+	 */
+
+	mdi = MDI_OP_RD |
+	    ((uint32_t)phy << MDI_PHYAD_SHIFT) |
+	    ((uint32_t)reg << MDI_REGAD_SHIFT);
+
+	PUT32(ip, CSR_MDICTL, mdi);
+	for (int i = 0; i < 100; i++) {
+		mdi = GET32(ip, CSR_MDICTL);
+		if (mdi & MDI_R) {
+			return (mdi & 0xffff);
+		}
+		drv_usecwait(1);
+	}
+	return (0xffff);
+}
+
+void
+iprb_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t data)
+{
+	iprb_t	*ip = arg;
+	uint32_t mdi;
+
+	mdi = MDI_OP_WR |
+	    ((uint32_t)phy << MDI_PHYAD_SHIFT) |
+	    ((uint32_t)reg << MDI_REGAD_SHIFT) |
+	    (data);
+
+	PUT32(ip, CSR_MDICTL, mdi);
+	for (int i = 0; i < 100; i++) {
+		if (GET32(ip, CSR_MDICTL) & MDI_R)
+			break;
+	}
+}
+
+void
+iprb_mii_notify(void *arg, link_state_t link)
+{
+	iprb_t *ip = arg;
+
+	mac_link_update(ip->mach, link);
+}
+
+uint_t
+iprb_intr(caddr_t arg1, caddr_t arg2)
+{
+	iprb_t *ip = (void *)arg1;
+	uint8_t	sts;
+	mblk_t	*mp = NULL;
+
+	_NOTE(ARGUNUSED(arg2));
+
+	mutex_enter(&ip->rulock);
+	if (ip->suspended) {
+		mutex_exit(&ip->rulock);
+		return (DDI_INTR_UNCLAIMED);
+	}
+	sts = GET8(ip, CSR_STS);
+	if (sts == 0) {
+		/* No interrupt status! */
+		mutex_exit(&ip->rulock);
+		return (DDI_INTR_UNCLAIMED);
+	}
+	/* acknowledge the interrupts */
+	PUT8(ip, CSR_STS, sts);
+
+	if (sts & (STS_RNR | STS_FR)) {
+		mp = iprb_rx(ip);
+
+		if ((sts & STS_RNR) &&
+		    ((GET8(ip, CSR_STATE) & STATE_RUS) == STATE_RUS_NORES)) {
+			iprb_rx_init(ip);
+
+			mutex_enter(&ip->culock);
+			PUT32(ip, CSR_GEN_PTR, ip->rxb[0].paddr);
+			/* wait for the SCB */
+			(void) iprb_cmd_ready(ip);
+			PUT8(ip, CSR_CMD, RUC_START);
+			(void) GET8(ip, CSR_CMD);	/* flush CSR */
+			mutex_exit(&ip->culock);
+		}
+	}
+	mutex_exit(&ip->rulock);
+
+	if (mp) {
+		mac_rx(ip->mach, NULL, mp);
+	}
+	if ((sts & (STS_CNA | STS_CX)) && ip->wantw)  {
+		ip->wantw = B_FALSE;
+		mac_tx_update(ip->mach);
+	}
+	return (DDI_INTR_CLAIMED);
+}
+
+void
+iprb_periodic(void *arg)
+{
+	iprb_t *ip = arg;
+	boolean_t reset = B_FALSE;
+
+	mutex_enter(&ip->rulock);
+	if (ip->suspended || !ip->running) {
+		mutex_exit(&ip->rulock);
+		return;
+	}
+
+	/*
+	 * If we haven't received a packet in a while, and if the link
+	 * is up, then it might be a hung chip.  This problem
+	 * reportedly only occurs at 10 Mbps.
+	 */
+	if (ip->rxhangbug &&
+	    ((ip->miih == NULL) || (mii_get_speed(ip->miih) == 10000000)) &&
+	    ((ddi_get_time() - ip->rx_wdog) > ip->rx_timeout)) {
+		cmn_err(CE_CONT, "?Possible RU hang, resetting.\n");
+		reset = B_TRUE;
+	}
+
+	/* update the statistics */
+	mutex_enter(&ip->culock);
+
+	if (ip->tx_wdog && ((ddi_get_time() - ip->tx_wdog) > ip->tx_timeout)) {
+		/* transmit/CU hang? */
+		cmn_err(CE_CONT, "?CU stalled, resetting.\n");
+		reset = B_TRUE;
+	}
+
+	if (reset) {
+		/* We want to reconfigure */
+		iprb_stop(ip);
+		if (iprb_start(ip) != DDI_SUCCESS) {
+			iprb_error(ip, "unable to restart chip");
+		}
+	}
+
+	iprb_update_stats(ip);
+
+	mutex_exit(&ip->culock);
+	mutex_exit(&ip->rulock);
+}
+
+int
+iprb_quiesce(dev_info_t *dip)
+{
+	iprb_t *ip = ddi_get_driver_private(dip);
+
+	/* Reset, but first go into idle state */
+	PUT32(ip, CSR_PORT, PORT_SEL_RESET);
+	drv_usecwait(50);
+	PUT32(ip, CSR_PORT, PORT_SW_RESET);
+	drv_usecwait(10);
+	PUT8(ip, CSR_INTCTL, INTCTL_MASK);
+
+	return (DDI_SUCCESS);
+}
+
+int
+iprb_suspend(dev_info_t *dip)
+{
+	iprb_t *ip = ddi_get_driver_private(dip);
+
+	if (ip->miih)
+		mii_suspend(ip->miih);
+
+	mutex_enter(&ip->rulock);
+	mutex_enter(&ip->culock);
+	if (!ip->suspended) {
+		ip->suspended = B_TRUE;
+		if (ip->running) {
+			iprb_update_stats(ip);
+			iprb_stop(ip);
+		}
+	}
+	mutex_exit(&ip->culock);
+	mutex_exit(&ip->rulock);
+	return (DDI_SUCCESS);
+}
+
+int
+iprb_resume(dev_info_t *dip)
+{
+	iprb_t *ip = ddi_get_driver_private(dip);
+
+	mutex_enter(&ip->rulock);
+	mutex_enter(&ip->culock);
+
+	ip->suspended = B_FALSE;
+	if (ip->running) {
+		if (iprb_start(ip) != DDI_SUCCESS) {
+			iprb_error(ip, "unable to restart chip!");
+			ip->suspended = B_TRUE;
+			mutex_exit(&ip->culock);
+			mutex_exit(&ip->rulock);
+			return (DDI_FAILURE);
+		}
+	}
+
+	mutex_exit(&ip->culock);
+	mutex_exit(&ip->rulock);
+	if (ip->miih)
+		mii_resume(ip->miih);
+	return (DDI_SUCCESS);
+}
+
+int
+iprb_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	switch (cmd) {
+	case DDI_ATTACH:
+		return (iprb_attach(dip));
+
+	case DDI_RESUME:
+		return (iprb_resume(dip));
+
+	default:
+		return (DDI_FAILURE);
+	}
+}
+
+int
+iprb_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+	switch (cmd) {
+	case DDI_DETACH:
+		return (iprb_detach(dip));
+
+	case DDI_SUSPEND:
+		return (iprb_suspend(dip));
+
+	default:
+		return (DDI_FAILURE);
+	}
+}
+
+void
+iprb_error(iprb_t *ip, const char *fmt, ...)
+{
+	va_list ap;
+	char buf[256];
+
+	va_start(ap, fmt);
+	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
+	va_end(ap);
+
+	cmn_err(CE_WARN, "%s%d: %s",
+	    ddi_driver_name(ip->dip), ddi_get_instance(ip->dip), buf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/iprb/iprb.h	Fri Dec 03 07:32:02 2010 -0800
@@ -0,0 +1,373 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
+ */
+
+#ifndef _IPRB_H
+#define	_IPRB_H
+
+/*
+ * iprb - Intel Pro/100B Ethernet Driver
+ */
+
+/*
+ * Tunables.
+ */
+#define	NUM_TX		128	/* outstanding tx queue */
+#define	NUM_RX		128	/* outstanding rx queue */
+
+#define	RX_WATCHDOG	15	/* timeout for rx watchdog (sec) */
+#define	TX_WATCHDOG	15	/* timeout for tx watchdog (sec) */
+
+/*
+ * Driver structures.
+ */
+typedef struct {
+	ddi_acc_handle_t	acch;
+	ddi_dma_handle_t	dmah;
+	caddr_t			vaddr;
+	uint32_t		paddr;
+} iprb_dma_t;
+
+typedef struct iprb_mcast {
+	list_node_t		node;
+	uint8_t			addr[6];
+} iprb_mcast_t;
+
+typedef struct iprb {
+	dev_info_t		*dip;
+	ddi_acc_handle_t	pcih;
+	ddi_acc_handle_t	regsh;
+	caddr_t			regs;
+
+	uint16_t		devid;
+	uint8_t			revid;
+
+	mac_handle_t		mach;
+	mii_handle_t		miih;
+
+	ddi_intr_handle_t	intrh;
+
+	ddi_periodic_t		perh;
+
+	kmutex_t		culock;
+	kmutex_t		rulock;
+
+	uint8_t			factaddr[6];
+	uint8_t			curraddr[6];
+
+	int			nmcast;
+	list_t			mcast;
+	boolean_t		promisc;
+	iprb_dma_t		cmds[NUM_TX];
+	iprb_dma_t		rxb[NUM_RX];
+	iprb_dma_t		stats;
+	time_t			stats_time;
+
+	uint16_t		cmd_head;
+	uint16_t		cmd_last;
+	uint16_t		cmd_tail;
+	uint16_t		cmd_count;
+
+	uint16_t		rx_index;
+	uint16_t		rx_last;
+	time_t			rx_wdog;
+	time_t			rx_timeout;
+	time_t			tx_wdog;
+	time_t			tx_timeout;
+
+	uint16_t		eeprom_bits;
+
+	boolean_t		running;
+	boolean_t		suspended;
+	boolean_t		wantw;
+	boolean_t		rxhangbug;
+	boolean_t		resumebug;
+	boolean_t		is557;
+	boolean_t		canpause;
+	boolean_t		canmwi;
+
+	/*
+	 * Statistics
+	 */
+	uint64_t		ipackets;
+	uint64_t		rbytes;
+	uint64_t		multircv;
+	uint64_t		brdcstrcv;
+	uint64_t		opackets;
+	uint64_t		obytes;
+	uint64_t		multixmt;
+	uint64_t		brdcstxmt;
+	uint64_t		ex_coll;
+	uint64_t		late_coll;
+	uint64_t		uflo;
+	uint64_t		defer_xmt;
+	uint64_t		one_coll;
+	uint64_t		multi_coll;
+	uint64_t		collisions;
+	uint64_t		fcs_errs;
+	uint64_t		align_errs;
+	uint64_t		norcvbuf;
+	uint64_t		oflo;
+	uint64_t		runt;
+	uint64_t		nocarrier;
+	uint64_t		toolong;
+	uint64_t		macxmt_errs;
+	uint64_t		macrcv_errs;
+} iprb_t;
+
+/*
+ * Idenfication values.
+ */
+#define	REV_82557	1
+#define	REV_82558_A4	4
+#define	REV_82558_B0	5
+#define	REV_82559_A0	8
+#define	REV_82559S_A	9
+#define	REV_82550	12
+#define	REV_82550_C	13
+#define	REV_82551_E	14
+#define	REV_82551_F	15
+#define	REV_82551_10	16
+
+/*
+ * Device registers.
+ */
+#define	CSR_STATE	0x00
+#define	CSR_STS		0x01
+#define	CSR_CMD		0x02
+#define	CSR_INTCTL	0x03
+#define	CSR_GEN_PTR	0x04
+#define	CSR_PORT	0x08
+#define	CSR_EECTL	0x0e
+#define	CSR_MDICTL	0x10
+
+#define	STATE_CUS	0xc0	/* CU state (mask) */
+#define	STATE_CUS_IDLE	0x00	/* CU idle */
+#define	STATE_CUS_SUSP	0x40	/* CU suspended */
+#define	STATE_CUS_LPQA	0x80	/* LPQ active */
+#define	STATE_CUS_HQPA	0xc0	/* HQP active */
+#define	STATE_RUS	0x3c	/* RU state (mask) */
+#define	STATE_RUS_IDLE	0x00	/* RU idle */
+#define	STATE_RUS_SUSP	0x04	/* RU suspended */
+#define	STATE_RUS_NORES	0x08	/* RU no resources */
+#define	STATE_RUS_READY	0x10	/* RU ready */
+
+#define	STS_FCP		0x01	/* flow control pause */
+#define	STS_RSVD	0x02	/* reserved bit */
+#define	STS_SWI		0x04	/* software interrupt */
+#define	STS_MDI		0x08	/* MDI read/write done */
+#define	STS_RNR		0x10	/* RU not ready */
+#define	STS_CNA		0x20	/* CU state change */
+#define	STS_FR		0x40	/* frame receive */
+#define	STS_CX		0x80	/* cmd exec done */
+
+#define	CMD_CUC		0xf0	/* CU command (mask) */
+#define	CUC_NOP		0x00	/* no operation */
+#define	CUC_START	0x10	/* start CU */
+#define	CUC_RESUME	0x20	/* resume CU */
+#define	CUC_STATSBASE	0x40	/* load statistics address */
+#define	CUC_STATS	0x50	/* dump statistics */
+#define	CUC_CUBASE	0x60	/* load CU base address */
+#define	CUC_STATS_RST	0x70	/* dump statistics and reset */
+#define	CUC_SRES	0xa0	/* static resume CU */
+#define	CMD_RUC		0x07	/* RU command (mask) */
+#define	RUC_NOP		0x00	/* no operation */
+#define	RUC_START	0x01	/* start RU */
+#define	RUC_RESUME	0x02	/* resume RU */
+#define	RUC_DMAREDIR	0x03	/* receive DMA redirect */
+#define	RUC_ABORT	0x40	/* abort RU */
+#define	RUC_HDRSZ	0x50	/* load header data size */
+#define	RUC_RUBASE	0x60	/* load RU base address */
+
+#define	INTCTL_MASK	0x01	/* disable all interrupts */
+#define	INTCTL_SI	0x02	/* generate software interrupt */
+#define	INTCTL_FCP	0x04	/* flow control pause */
+#define	INTCTL_ER	0x08	/* early receive */
+#define	INTCTL_RNR	0x10	/* RU not ready */
+#define	INTCTL_CNA	0x20	/* CU state change */
+#define	INTCTL_FR	0x40	/* frame receive */
+#define	INTCTL_CX	0x80	/* cmd exec done */
+
+#define	PORT_SW_RESET	0x00
+#define	PORT_SELF_TEST	0x01
+#define	PORT_SEL_RESET	0x02
+
+#define	EEPROM_EEDO	0x0008	/* data out */
+#define	EEPROM_EEDI	0x0004	/* data in */
+#define	EEPROM_EECS	0x0002	/* chip select */
+#define	EEPROM_EESK	0x0001	/* clock */
+
+#define	EEPROM_OP_RD	0x06
+#define	EEPROM_OP_WR	0x05
+#define	EEPROM_OP_WE	0x13	/* write enable */
+#define	EEPROM_OP_WD	0x13	/* write disable */
+
+#define	MDI_IE		0x20000000	/* interrupt enable */
+#define	MDI_R		0x10000000	/* ready */
+#define	MDI_OP_RD	0x08000000	/* read */
+#define	MDI_OP_WR	0x04000000	/* write */
+#define	MDI_PHYAD_SHIFT	21
+#define	MDI_REGAD_SHIFT	16
+
+#define	GET8(ip, offset)					\
+	ddi_get8(ip->regsh, (void *)(ip->regs + (offset)))
+#define	GET16(ip, offset)					\
+	ddi_get16(ip->regsh, (void *)(ip->regs + (offset)))
+#define	GET32(ip, offset)					\
+	ddi_get32(ip->regsh, (void *)(ip->regs + (offset)))
+#define	PUT8(ip, offset, val)						\
+	ddi_put8(ip->regsh, (void *)(ip->regs + (offset)), (val))
+#define	PUT16(ip, offset, val)						\
+	ddi_put16(ip->regsh, (void *)(ip->regs + (offset)), (val))
+#define	PUT32(ip, offset, val)						\
+	ddi_put32(ip->regsh, (void *)(ip->regs + (offset)), (val))
+
+
+#define	PUTDMA8(d, off, val)					\
+	ddi_put8(d->acch, (void *)(d->vaddr + (off)), LE_8(val))
+#define	PUTDMA16(d, off, val)						\
+	ddi_put16(d->acch, (void *)(d->vaddr + (off)), LE_16(val))
+#define	PUTDMA32(d, off, val)						\
+	ddi_put32(d->acch, (void *)(d->vaddr + (off)), LE_32(val))
+#define	GETDMA8(d, off)						\
+	LE_8(ddi_get8(d->acch, (void *)(d->vaddr + (off))))
+#define	GETDMA16(d, off)					\
+	LE_16(ddi_get16(d->acch, (void *)(d->vaddr + (off))))
+#define	GETDMA32(d, off)					\
+	LE_32(ddi_get32(d->acch, (void *)(d->vaddr + (off))))
+#define	SYNCDMA(d, off, size, dir)			\
+	(void) ddi_dma_sync(d->dmah, off, size, dir)
+
+/*
+ * Command block offsets.
+ */
+#define	CB_STS_OFFSET		0
+#define	CB_CMD_OFFSET		2
+#define	CB_LNK_OFFSET		4
+#define	CB_SIZE			2048	/* size of cmd blk */
+
+#define	CB_IAS_ADR_OFFSET	8
+
+#define	CB_MCS_CNT_OFFSET	8
+#define	CB_MCS_ADR_OFFSET	10
+#define	CB_MCS_CNT_MAX		((CB_SIZE - CB_MCS_ADR_OFFSET) / 6)
+
+#define	CB_UCODE_OFFSET		8
+
+#define	CB_CONFIG_OFFSET	8
+
+#define	CB_TX_TBD_OFFSET	8
+#define	CB_TX_COUNT_OFFSET	12
+#define	CB_TX_EOF		0x8000
+#define	CB_TX_THRESH_OFFSET	14
+#define	CB_TX_NUMBER_OFFSET	15
+#define	CB_TX_DATA_OFFSET	16
+
+#define	PUTCB8(cb, o, v)	PUTDMA8(cb, o, v)
+#define	PUTCB16(cb, o, v)	PUTDMA16(cb, o, v)
+#define	PUTCB32(cb, o, v)	PUTDMA32(cb, o, v)
+#define	PUTCBEA(cb, o, enet)						\
+	ddi_rep_put8(cb->acch, enet, (void *)(cb->vaddr + (o)), 6,	\
+	DDI_DEV_AUTOINCR);
+#define	GETCB8(cb, o)		GETDMA8(cb, o)
+#define	GETCB16(cb, o)		GETDMA16(cb, o)
+#define	GETCB32(cb, o)		GETDMA32(cb, o)
+#define	SYNCCB(cb, o, s, dir)	SYNCDMA(cb, o, s, dir)
+/*
+ * CB status bits.
+ */
+#define	CB_STS_OK		0x2000
+#define	CB_STS_C		0x8000
+
+/*
+ * Commands.
+ */
+#define	CB_CMD_NOP		0x0
+#define	CB_CMD_IAS		0x1
+#define	CB_CMD_CONFIG		0x2
+#define	CB_CMD_MCS		0x3
+#define	CB_CMD_TX		0x4
+#define	CB_CMD_UCODE		0x5
+/* and flags to go with */
+#define	CB_CMD_SF		0x0008	/* simple/flex */
+#define	CB_CMD_I		0x2000	/* generate an interrupt */
+#define	CB_CMD_S		0x4000	/* suspend on completion */
+#define	CB_CMD_EL		0x8000	/* end of list */
+
+/*
+ * RFD offsets.
+ */
+#define	GETRFD16(r, o)		GETDMA16(r, o)
+#define	PUTRFD16(r, o, v)	PUTDMA16(r, o, v)
+#define	PUTRFD32(r, o, v)	PUTDMA32(r, o, v)
+#define	SYNCRFD(r, o, s, dir)	SYNCDMA(r, o, s, dir)
+
+#define	RFD_STS_OFFSET		0x00
+#define	RFD_CTL_OFFSET		0x02
+#define	RFD_LNK_OFFSET		0x04
+#define	RFD_CNT_OFFSET		0x0c	/* bytes received */
+#define	RFD_SIZ_OFFSET		0x0e	/* size of packet area */
+#define	RFD_PKT_OFFSET		0x10
+#define	RFD_SIZE		2048
+
+#define	RFD_CTL_EL		0x8000
+#define	RFD_CTL_S		0x4000
+#define	RFD_CTL_H		0x0010
+#define	RFD_CTL_SF		0x0008
+
+#define	RFD_STS_C		0x8000
+#define	RFD_STS_OK		0x2000
+#define	RFD_STS_FCS		0x0800
+#define	RFD_STS_ALIGN		0x0400
+#define	RFD_STS_TOOBIG		0x0200
+#define	RFD_STS_DMAOFLO		0x0100
+#define	RFD_STS_TOOSHORT	0x0080
+#define	RFD_STS_802		0x0020
+#define	RFD_STS_RXERR		0x0010
+#define	RFD_STS_NOMATCH		0x0004
+#define	RFD_STS_IAMATCH		0x0002
+#define	RFD_STS_COLL_TCO	0x0001
+#define	RFD_STS_ERRS		0x0d90
+
+#define	RFD_CNT_EOF		0x8000
+#define	RFD_CNT_F		0x4000
+
+/*
+ * Stats offsets.
+ */
+#define	STATS_TX_GOOD_OFFSET	0
+#define	STATS_TX_MAXCOL_OFFSET	4
+#define	STATS_TX_LATECOL_OFFSET	8
+#define	STATS_TX_UFLO_OFFSET	16
+#define	STATS_TX_DEFER_OFFSET	20
+#define	STATS_TX_ONECOL_OFFSET	24
+#define	STATS_TX_MULTCOL_OFFSET	28
+#define	STATS_TX_TOTCOL_OFFSET	32
+#define	STATS_RX_GOOD_OFFSET	36
+#define	STATS_RX_FCS_OFFSET	40
+#define	STATS_RX_ALIGN_OFFSET	44
+#define	STATS_RX_NOBUF_OFFSET	48
+#define	STATS_RX_OFLO_OFFSET	52
+#define	STATS_RX_COL_OFFSET	56
+#define	STATS_RX_SHORT_OFFSET	60
+#define	STATS_DONE_OFFSET	64
+#define	STATS_SIZE		68
+#define	STATS_DONE		0xa005
+#define	STATS_RST_DONE		0xa007
+
+#define	SYNCSTATS(sp, o, s, dir)	SYNCDMA(sp, o, s, dir)
+#define	PUTSTAT(sp, o, v)		PUTDMA32(sp, o, v)
+#define	GETSTAT(sp, o)			GETDMA32(sp, o)
+
+#endif /* _IPRB_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/iprb/rcvbundl.h	Fri Dec 03 07:32:02 2010 -0800
@@ -0,0 +1,1090 @@
+/*
+Copyright (c) 1999-2001, Intel Corporation 
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without 
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice, 
+    this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation 
+    and/or other materials provided with the distribution.
+
+ 3. Neither the name of Intel Corporation nor the names of its contributors 
+    may be used to endorse or promote products derived from this software 
+    without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+*/
+
+/*
+ * rcvbundl.h
+ *
+ * Author:  Patrick J Luhmann (PJL)
+ * Date:    05/30/2000
+ * Version: 3.28
+ *
+ * This file contains the loadable micro code arrays to implement
+ * receive bundling on the D101 A-step, D101 B-step, D101M (B-step
+ * only), D101S, D102 B-step, D102 C-step and D102 E-step.
+ *
+ * Each controller has its own specific micro code array.  The array
+ * for one controller is totally incompatible with any other
+ * controller, and if used will most likely cause the controller to
+ * lock up and stop responding to the driver.  Each micro code array
+ * has its own parameter offsets (described below), and they each have
+ * their own version number (which should not be confused with the
+ * version of the rcvbundl.h file given above).
+ */
+
+/* Note: Minor formatting changes made for illumos. */
+
+/*
+ * CPUSaver parameters
+ *
+ * All CPUSaver parameters are 16-bit literals that are part of a
+ * "move immediate value" instruction.  By changing the value of the
+ * literal in the instruction before the code is loaded, the driver
+ * can change algorithm.
+ *
+ * CPUSAVER_DWORD - This is the location of the instruction that loads
+ *    the dead-man timer with its inital value.  By writing a 16-bit
+ *    value to the low word of this instruction, the driver can change
+ *    the timer value.  The current default is either x600 or x800;
+ *    experiments show that the value probably should stay within the
+ *    range of x200 - x1000.
+ *
+ * CPUSAVER_BUNDLE_MAX_DWORD - This is the location of the instruction
+ *    that sets the maximum number of frames that will be bundled.  In
+ *    some situations, such as the TCP windowing algorithm, it may be
+ *    better to limit the growth of the bundle size than let it go as
+ *    high as it can, because that could cause too much added latency.
+ *    The default is six, because this is the number of packets in the
+ *    default TCP window size.  A value of 1 would make CPUSaver
+ *    indicate an interrupt for every frame received.  If you do not
+ *    want to put a limit on the bundle size, set this value to xFFFF.
+ *
+ * CPUSAVER_MIN_SIZE_DWORD - This is the location of the instruction
+ *    that contains a bit-mask describing the minimum size frame that
+ *    will be bundled.  The default masks the lower 7 bits, which
+ *    means that any frame less than 128 bytes in length will not be
+ *    bundled, but will instead immediately generate an interrupt.
+ *    This does not affect the current bundle in any way.  Any frame
+ *    that is 128 bytes or large will be bundled normally.  This
+ *    feature is meant to provide immediate indication of ACK frames
+ *    in a TCP environment.  Customers were seeing poor performance
+ *    when a machine with CPUSaver enabled was sending but not
+ *    receiving.  The delay introduced when the ACKs were received was
+ *    enough to reduce total throughput, because the sender would sit
+ *    idle until the ACK was finally seen.
+ *
+ *    The current default is 0xFF80, which masks out the lower 7 bits.
+ *    This means that any frame which is x7F (127) bytes or smaller
+ *    will cause an immediate interrupt.  Because this value must be a
+ *    bit mask, there are only a few valid values that can be used.
+ *    To turn this feature off, the driver can write the value xFFFF
+ *    to the lower word of this instruction (in the same way that the
+ *    other parameters are used).  Likewise, a value of 0xF800 (2047)
+ *    would cause an interrupt to be generated for every frame,
+ *    because all standard Ethernet frames are <= 2047 bytes in
+ *    length.
+ */
+
+
+
+/*
+ * CPUSaver micro code for the D101A
+ */
+
+/* Version 2.0 */
+
+/* This value is the same for both A and B step of 558. */
+#define	D101_CPUSAVER_DWORD		72
+
+#define	D101_A_RCVBUNDLE_UCODE			\
+{\
+0x03B301BB, \
+0x0046FFFF, \
+0xFFFFFFFF, \
+0x051DFFFF, \
+0xFFFFFFFF, \
+0xFFFFFFFF, \
+0x000C0001, \
+0x00101212, \
+0x000C0008, \
+0x003801BC, \
+0x00000000, \
+0x00124818, \
+0x000C1000, \
+0x00220809, \
+0x00010200, \
+0x00124818, \
+0x000CFFFC, \
+0x003803B5, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x0010009C, \
+0x0024B81D, \
+0x00130836, \
+0x000C0001, \
+0x0026081C, \
+0x0020C81B, \
+0x00130824, \
+0x00222819, \
+0x00101213, \
+0x00041000, \
+0x003A03B3, \
+0x00010200, \
+0x00101B13, \
+0x00238081, \
+0x00213049, \
+0x0038003B, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x0010009C, \
+0x0024B83E, \
+0x00130826, \
+0x000C0001, \
+0x0026083B, \
+0x00010200, \
+0x00134824, \
+0x000C0001, \
+0x00101213, \
+0x00041000, \
+0x0038051E, \
+0x00101313, \
+0x00010400, \
+0x00380521, \
+0x00050600, \
+0x00100824, \
+0x00101310, \
+0x00041000, \
+0x00080600, \
+0x00101B10, \
+0x0038051E, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+}
+
+
+/*
+ * CPUSaver micro code for the D101B
+ */
+
+/* Version 2.0 */
+#define	D101_B0_CPUSAVER_DWORD		72
+
+#define	D101_B0_RCVBUNDLE_UCODE			\
+{\
+0x03B401BC, \
+0x0047FFFF, \
+0xFFFFFFFF, \
+0x051EFFFF, \
+0xFFFFFFFF, \
+0xFFFFFFFF, \
+0x000C0001, \
+0x00101B92, \
+0x000C0008, \
+0x003801BD, \
+0x00000000, \
+0x00124818, \
+0x000C1000, \
+0x00220809, \
+0x00010200, \
+0x00124818, \
+0x000CFFFC, \
+0x003803B6, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x0010009C, \
+0x0024B81D, \
+0x0013082F, \
+0x000C0001, \
+0x0026081C, \
+0x0020C81B, \
+0x00130837, \
+0x00222819, \
+0x00101B93, \
+0x00041000, \
+0x003A03B4, \
+0x00010200, \
+0x00101793, \
+0x00238082, \
+0x0021304A, \
+0x0038003C, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x0010009C, \
+0x0024B83E, \
+0x00130826, \
+0x000C0001, \
+0x0026083B, \
+0x00010200, \
+0x00134837, \
+0x000C0001, \
+0x00101B93, \
+0x00041000, \
+0x0038051F, \
+0x00101313, \
+0x00010400, \
+0x00380522, \
+0x00050600, \
+0x00100837, \
+0x00101310, \
+0x00041000, \
+0x00080600, \
+0x00101790, \
+0x0038051F, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+}
+
+
+/*
+ * CPUSaver micro code for the D101M (B-step only)
+ */
+
+/* Version 2.10 */
+
+/* Parameter values for the D101M B-step */
+#define	D101M_CPUSAVER_DWORD			78
+#define	D101M_CPUSAVER_BUNDLE_MAX_DWORD		65
+#define	D101M_CPUSAVER_MIN_SIZE_DWORD		126
+
+#define D101M_B_RCVBUNDLE_UCODE			\
+{\
+0x00550215, \
+0xFFFF0437, \
+0xFFFFFFFF, \
+0x06A70789, \
+0xFFFFFFFF, \
+0x0558FFFF, \
+0x000C0001, \
+0x00101312, \
+0x000C0008, \
+0x00380216, \
+0x0010009C, \
+0x00204056, \
+0x002380CC, \
+0x00380056, \
+0x0010009C, \
+0x00244C0B, \
+0x00000800, \
+0x00124818, \
+0x00380438, \
+0x00000000, \
+0x00140000, \
+0x00380555, \
+0x00308000, \
+0x00100662, \
+0x00100561, \
+0x000E0408, \
+0x00134861, \
+0x000C0002, \
+0x00103093, \
+0x00308000, \
+0x00100624, \
+0x00100561, \
+0x000E0408, \
+0x00100861, \
+0x000C007E, \
+0x00222C21, \
+0x000C0002, \
+0x00103093, \
+0x00380C7A, \
+0x00080000, \
+0x00103090, \
+0x00380C7A, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x0010009C, \
+0x00244C2D, \
+0x00010004, \
+0x00041000, \
+0x003A0437, \
+0x00044010, \
+0x0038078A, \
+0x00000000, \
+0x00100099, \
+0x00206C7A, \
+0x0010009C, \
+0x00244C48, \
+0x00130824, \
+0x000C0001, \
+0x00101213, \
+0x00260C75, \
+0x00041000, \
+0x00010004, \
+0x00130826, \
+0x000C0006, \
+0x002206A8, \
+0x0013C926, \
+0x00101313, \
+0x003806A8, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00080600, \
+0x00101B10, \
+0x00050004, \
+0x00100826, \
+0x00101210, \
+0x00380C34, \
+0x00000000, \
+0x00000000, \
+0x0021155B, \
+0x00100099, \
+0x00206559, \
+0x0010009C, \
+0x00244559, \
+0x00130836, \
+0x000C0000, \
+0x00220C62, \
+0x000C0001, \
+0x00101B13, \
+0x00229C0E, \
+0x00210C0E, \
+0x00226C0E, \
+0x00216C0E, \
+0x0022FC0E, \
+0x00215C0E, \
+0x00214C0E, \
+0x00380555, \
+0x00010004, \
+0x00041000, \
+0x00278C67, \
+0x00040800, \
+0x00018100, \
+0x003A0437, \
+0x00130826, \
+0x000C0001, \
+0x00220559, \
+0x00101313, \
+0x00380559, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00130831, \
+0x0010090B, \
+0x00124813, \
+0x000CFF80, \
+0x002606AB, \
+0x00041000, \
+0x003806A8, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+}
+
+
+/*
+ * CPUSaver micro code for the D101S
+ */
+
+/* Version 1.20 */
+
+/* Parameter values for the D101S */
+#define	D101S_CPUSAVER_DWORD			78
+#define	D101S_CPUSAVER_BUNDLE_MAX_DWORD		67
+#define	D101S_CPUSAVER_MIN_SIZE_DWORD		129
+
+
+#define	D101S_RCVBUNDLE_UCODE			\
+{\
+0x00550242, \
+0xFFFF047E, \
+0xFFFFFFFF, \
+0x06FF0818, \
+0xFFFFFFFF, \
+0x05A6FFFF, \
+0x000C0001, \
+0x00101312, \
+0x000C0008, \
+0x00380243, \
+0x0010009C, \
+0x00204056, \
+0x002380D0, \
+0x00380056, \
+0x0010009C, \
+0x00244F8B, \
+0x00000800, \
+0x00124818, \
+0x0038047F, \
+0x00000000, \
+0x00140000, \
+0x003805A3, \
+0x00308000, \
+0x00100610, \
+0x00100561, \
+0x000E0408, \
+0x00134861, \
+0x000C0002, \
+0x00103093, \
+0x00308000, \
+0x00100624, \
+0x00100561, \
+0x000E0408, \
+0x00100861, \
+0x000C007E, \
+0x00222FA1, \
+0x000C0002, \
+0x00103093, \
+0x00380F90, \
+0x00080000, \
+0x00103090, \
+0x00380F90, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x0010009C, \
+0x00244FAD, \
+0x00010004, \
+0x00041000, \
+0x003A047E, \
+0x00044010, \
+0x00380819, \
+0x00000000, \
+0x00100099, \
+0x00206FFD, \
+0x0010009A, \
+0x0020AFFD, \
+0x0010009C, \
+0x00244FC8, \
+0x00130824, \
+0x000C0001, \
+0x00101213, \
+0x00260FF8, \
+0x00041000, \
+0x00010004, \
+0x00130826, \
+0x000C0006, \
+0x00220700, \
+0x0013C926, \
+0x00101313, \
+0x00380700, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00080600, \
+0x00101B10, \
+0x00050004, \
+0x00100826, \
+0x00101210, \
+0x00380FB6, \
+0x00000000, \
+0x00000000, \
+0x002115A9, \
+0x00100099, \
+0x002065A7, \
+0x0010009A, \
+0x0020A5A7, \
+0x0010009C, \
+0x002445A7, \
+0x00130836, \
+0x000C0000, \
+0x00220FE4, \
+0x000C0001, \
+0x00101B13, \
+0x00229F8E, \
+0x00210F8E, \
+0x00226F8E, \
+0x00216F8E, \
+0x0022FF8E, \
+0x00215F8E, \
+0x00214F8E, \
+0x003805A3, \
+0x00010004, \
+0x00041000, \
+0x00278FE9, \
+0x00040800, \
+0x00018100, \
+0x003A047E, \
+0x00130826, \
+0x000C0001, \
+0x002205A7, \
+0x00101313, \
+0x003805A7, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00130831, \
+0x0010090B, \
+0x00124813, \
+0x000CFF80, \
+0x00260703, \
+0x00041000, \
+0x00380700, \
+0x00000000, \
+}
+
+
+/*
+ * CPUSaver micro code for the D102 B-step
+ */
+
+/* Version 2.0 */
+
+/*
+ * This version of CPUSaver is different from all others in a
+ * different way.  It combines the CPUSaver algorithm with fixes for
+ * bugs in the B-step hardware (specifically, bugs with Inline
+ * Receive).  Thus, when CPUSaver is disabled, this micro code image
+ * will still need to be loaded.  Before this happens, the hit
+ * addresses for the CPUSaver algorithm must be set to 0x1FFFF.  The
+ * hit addresses for CPUSaver are (starting with 0, and remember that.
+ */
+
+/* Parameter values for the D102 B-step */
+#define	D102_B_CPUSAVER_DWORD			91
+#define	D102_B_CPUSAVER_BUNDLE_MAX_DWORD	115
+#define	D102_B_CPUSAVER_MIN_SIZE_DWORD		70
+
+#define	D102_B_RCVBUNDLE_UCODE \
+{\
+0x006F0276, \
+0x02BF0E93, \
+0x1FFF0ED9, \
+0x0D2508FA, \
+0x04D21FFF, \
+0x0EA10892, \
+0x00300001, \
+0x0140D871, \
+0x00300008, \
+0x00E00277, \
+0x01406C57, \
+0x00816073, \
+0x008700FA, \
+0x00E00070, \
+0x00E00E94, \
+0x00200004, \
+0x01410000, \
+0x014B6F6F, \
+0x0030FFFF, \
+0x01486F72, \
+0x00E81F9B, \
+0x00E00EA3, \
+0x003C0040, \
+0x00380920, \
+0x00C02000, \
+0x0150ED38, \
+0x0150EE39, \
+0x0150EF3A, \
+0x003C0040, \
+0x01506F0D, \
+0x01600E72, \
+0x00380AE0, \
+0x00E002C0, \
+0x00300001, \
+0x014C0000, \
+0x008404DC, \
+0x014C6F72, \
+0x00E01F9D, \
+0x01406C51, \
+0x0080DFC2, \
+0x01406C52, \
+0x00815FC2, \
+0x01406C57, \
+0x00917FD5, \
+0x00E01FE6, \
+0x00000000, \
+0x01406C57, \
+0x00919FAD, \
+0x00038800, \
+0x00300000, \
+0x00E81FF2, \
+0x014D6FC4, \
+0x00E008FB, \
+0x00000000, \
+0x00822D30, \
+0x01406C51, \
+0x0080CD26, \
+0x01406C52, \
+0x00814D26, \
+0x01406C57, \
+0x00916D26, \
+0x014C6FD7, \
+0x00300000, \
+0x00841FDB, \
+0x00300001, \
+0x0140D772, \
+0x00E012B3, \
+0x014C6F91, \
+0x0150710B, \
+0x01496F72, \
+0x0030FF80, \
+0x00940EDD, \
+0x00102000, \
+0x00E00EDA, \
+0x01406C57, \
+0x00917FFD, \
+0x00001000, \
+0x00E01FFD, \
+0x00138800, \
+0x00300001, \
+0x00E81FF2, \
+0x00202500, \
+0x00E81F9B, \
+0x01600EC5, \
+0x00E00893, \
+0x00000000, \
+0x01406CD5, \
+0x0091EEA3, \
+0x00904EA3, \
+0x00901F89, \
+0x00E00EA3, \
+0x00200600, \
+0x0140D76F, \
+0x00138400, \
+0x01406FD8, \
+0x0140D96F, \
+0x00E01FE6, \
+0x00038400, \
+0x00102000, \
+0x00971FE0, \
+0x00101000, \
+0x00050200, \
+0x00E804D2, \
+0x014C6FD8, \
+0x00300001, \
+0x00840D26, \
+0x0140D872, \
+0x00E00D26, \
+0x014C6FD9, \
+0x00300001, \
+0x0140D972, \
+0x00941FBD, \
+0x00102000, \
+0x00038400, \
+0x014C6FD8, \
+0x00300006, \
+0x00840EDA, \
+0x014F71D8, \
+0x0140D872, \
+0x00E00EDA, \
+0x00340020, \
+0x014C6FED, \
+0x01603472, \
+0x016035EE, \
+0x016036EF, \
+0x00300004, \
+0x01611C71, \
+0x00300014, \
+0x00200A00, \
+0x00E810B9, \
+0x00600000, \
+0x01496F50, \
+0x00E004D3, \
+0x00000000, \
+}
+
+
+/*
+ * Micro code for the D102 C-step
+ */
+
+/* Parameter values for the D102 C-step */
+#define	D102_C_CPUSAVER_DWORD			46
+#define	D102_C_CPUSAVER_BUNDLE_MAX_DWORD	54
+#define	D102_C_CPUSAVER_MIN_SIZE_DWORD		133 /* not implemented */
+
+#define D102_C_RCVBUNDLE_UCODE			\
+{ \
+0x00700279, \
+0x0E6104E2, \
+0x02BF0CAE, \
+0x1519150C, \
+0x1FFF0E5B, \
+0x1FFF1FFF, \
+0x00E014D8, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00E014DC, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00E014F4, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00E014E0, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00E014E7, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00141000, \
+0x015D6F0D, \
+0x00E002C0, \
+0x00000000, \
+0x00200600, \
+0x00E0150D, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00300006, \
+0x00E0151A, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00906E65, \
+0x00800E60, \
+0x00E00E5D, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+}
+
+/*
+ * Micro code for the D102 E-step
+ */
+
+/* Parameter values for the D102 E-step */
+#define	D102_E_CPUSAVER_DWORD			42
+#define	D102_E_CPUSAVER_BUNDLE_MAX_DWORD	54
+#define	D102_E_CPUSAVER_MIN_SIZE_DWORD		46
+
+#define	D102_E_RCVBUNDLE_UCODE			\
+{\
+0x007D028F, \
+0x0E4204F9, \
+0x14ED0C85, \
+0x14FA14E9, \
+0x0EF70E36, \
+0x1FFF1FFF, \
+0x00E014B9, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00E014BD, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00E014D5, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00E014C1, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00E014C8, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00200600, \
+0x00E014EE, \
+0x00000000, \
+0x00000000, \
+0x0030FF80, \
+0x00940E46, \
+0x00038200, \
+0x00102000, \
+0x00E00E43, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00300006, \
+0x00E014FB, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00906E41, \
+0x00800E3C, \
+0x00E00E39, \
+0x00000000, \
+0x00906EFD, \
+0x00900EFD, \
+0x00E00EF8, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+0x00000000, \
+}
--- a/usr/src/uts/intel/Makefile.intel.shared	Thu Dec 02 20:23:12 2010 +0530
+++ b/usr/src/uts/intel/Makefile.intel.shared	Fri Dec 03 07:32:02 2010 -0800
@@ -369,7 +369,6 @@
 $(CLOSED_BUILD)CLOSED_DRV_KMODS		+= bmc
 $(CLOSED_BUILD)CLOSED_DRV_KMODS		+= glm
 $(CLOSED_BUILD)CLOSED_DRV_KMODS		+= intel_nhmex
-$(CLOSED_BUILD)CLOSED_DRV_KMODS		+= iprb
 $(CLOSED_BUILD)CLOSED_DRV_KMODS		+= cpqary3
 $(CLOSED_BUILD)CLOSED_DRV_KMODS		+= marvell88sx
 $(CLOSED_BUILD)CLOSED_DRV_KMODS		+= bcm_sata
@@ -398,6 +397,7 @@
 DRV_KMODS	+= sfe
 DRV_KMODS	+= amd8111s
 DRV_KMODS	+= igb
+DRV_KMODS	+= iprb
 DRV_KMODS	+= ixgbe
 DRV_KMODS	+= vr
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= ixgb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/iprb/Makefile	Fri Dec 03 07:32:02 2010 -0800
@@ -0,0 +1,86 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE		= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= iprb
+OBJECTS		= $(IPRB_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(IPRB_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+#	Overrides
+#
+
+#
+# Driver depends on GLD
+#
+LDFLAGS		+= -dy -N misc/mac -Nmisc/mii
+
+#
+#	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