changeset 13032:1b6086d6d5a1

6941306 oce driver performance is <3G on certain sparc platforms
author Sukumar Swaminathan <Sukumar.Swaminathan@Sun.COM>
date Thu, 05 Aug 2010 11:14:15 -0600
parents b11dd158cab1
children 0cbad7fa62eb
files usr/src/uts/common/io/fibre-channel/fca/oce/oce_buf.c usr/src/uts/common/io/fibre-channel/fca/oce/oce_gld.c usr/src/uts/common/io/fibre-channel/fca/oce/oce_hw.c usr/src/uts/common/io/fibre-channel/fca/oce/oce_intr.c usr/src/uts/common/io/fibre-channel/fca/oce/oce_main.c usr/src/uts/common/io/fibre-channel/fca/oce/oce_mbx.c usr/src/uts/common/io/fibre-channel/fca/oce/oce_mq.c usr/src/uts/common/io/fibre-channel/fca/oce/oce_queue.c usr/src/uts/common/io/fibre-channel/fca/oce/oce_rx.c usr/src/uts/common/io/fibre-channel/fca/oce/oce_stat.c usr/src/uts/common/io/fibre-channel/fca/oce/oce_tx.c usr/src/uts/common/io/fibre-channel/fca/oce/oce_utils.c usr/src/uts/common/sys/fibre-channel/fca/oce/oce_buf.h usr/src/uts/common/sys/fibre-channel/fca/oce/oce_hw.h usr/src/uts/common/sys/fibre-channel/fca/oce/oce_hw_eth.h usr/src/uts/common/sys/fibre-channel/fca/oce/oce_impl.h usr/src/uts/common/sys/fibre-channel/fca/oce/oce_io.h usr/src/uts/common/sys/fibre-channel/fca/oce/oce_utils.h usr/src/uts/common/sys/fibre-channel/fca/oce/oce_version.h
diffstat 19 files changed, 1298 insertions(+), 1050 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_buf.c	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_buf.c	Thu Aug 05 11:14:15 2010 -0600
@@ -64,7 +64,7 @@
  */
 oce_dma_buf_t *
 oce_alloc_dma_buffer(struct oce_dev *dev,
-    uint32_t size, uint32_t flags)
+    uint32_t size, ddi_dma_attr_t *dma_attr, uint32_t flags)
 {
 	oce_dma_buf_t  *dbuf;
 	ddi_dma_cookie_t cookie;
@@ -73,6 +73,10 @@
 	int ret = 0;
 
 	ASSERT(size > 0);
+	/* if NULL use default */
+	if (dma_attr == NULL) {
+		dma_attr = &oce_dma_buf_attr;
+	}
 
 	dbuf = kmem_zalloc(sizeof (oce_dma_buf_t), KM_NOSLEEP);
 	if (dbuf == NULL) {
@@ -80,12 +84,12 @@
 	}
 
 	/* allocate dma handle */
-	ret = ddi_dma_alloc_handle(dev->dip, &oce_dma_buf_attr,
+	ret = ddi_dma_alloc_handle(dev->dip, dma_attr,
 	    DDI_DMA_DONTWAIT, NULL, &dbuf->dma_handle);
 	if (ret != DDI_SUCCESS) {
 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
 		    "Failed to allocate DMA handle");
-		goto alloc_fail;
+		goto handle_fail;
 	}
 	/* allocate the DMA-able memory */
 	ret = ddi_dma_mem_alloc(dbuf->dma_handle, size, &oce_dma_buf_accattr,
@@ -105,7 +109,7 @@
 	if (ret != DDI_DMA_MAPPED) {
 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
 		    "Failed to bind dma handle");
-		goto alloc_fail;
+		goto bind_fail;
 	}
 	bzero(dbuf->base, actual_len);
 	dbuf->addr = cookie.dmac_laddress;
@@ -114,8 +118,13 @@
 	dbuf->len  = size;
 	dbuf->num_pages = OCE_NUM_PAGES(size);
 	return (dbuf);
+
+bind_fail:
+	ddi_dma_mem_free(&dbuf->acc_handle);
 alloc_fail:
-	oce_free_dma_buffer(dev, dbuf);
+	ddi_dma_free_handle(&dbuf->dma_handle);
+handle_fail:
+	kmem_free(dbuf, sizeof (oce_dma_buf_t));
 	return (NULL);
 } /* oce_dma_alloc_buffer */
 
@@ -172,7 +181,7 @@
 
 	/* get the dbuf defining the ring */
 	size = num_items * item_size;
-	ring->dbuf = oce_alloc_dma_buffer(dev, size, flags);
+	ring->dbuf = oce_alloc_dma_buffer(dev, size, NULL, flags);
 	if (ring->dbuf  == NULL) {
 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
 		    "Ring buffer allocation failed");
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_gld.c	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_gld.c	Thu Aug 05 11:14:15 2010 -0600
@@ -41,8 +41,9 @@
 	NULL
 };
 
+extern int pow10[];
+
 /* ---[ static function declarations ]----------------------------------- */
-static int oce_power10(int power);
 static int oce_set_priv_prop(struct oce_dev *dev, const char *name,
     uint_t size, const void *val);
 
@@ -103,35 +104,25 @@
 oce_start(struct oce_dev *dev)
 {
 	int qidx = 0;
-	int ret;
+	struct link_status link = {0};
 
-	ret = oce_alloc_intr(dev);
-	if (ret != DDI_SUCCESS)
-		goto  start_fail;
-	ret = oce_setup_handlers(dev);
-	if (ret != DDI_SUCCESS) {
-		oce_log(dev, CE_WARN, MOD_CONFIG,
-		    "Interrupt handler setup failed with %d", ret);
-		(void) oce_teardown_intr(dev);
-		goto  start_fail;
-	}
 	/* get link status */
-	(void) oce_get_link_status(dev, &dev->link);
+	(void) oce_get_link_status(dev, &link);
+
+	dev->link_status  = (link.logical_link_status == NTWK_LOGICAL_LINK_UP) ?
+	    LINK_STATE_UP : LINK_STATE_DOWN;
 
-	if (dev->link.mac_speed == PHY_LINK_SPEED_ZERO) {
-		oce_log(dev, CE_NOTE, MOD_CONFIG,
-		    "LINK_DOWN: 0x%x", dev->link.mac_speed);
-		mac_link_update(dev->mac_handle, LINK_STATE_DOWN);
-	} else {
-		oce_log(dev, CE_NOTE, MOD_CONFIG,
-		    "(f,s,d,pp)=(0x%x, 0x%x, 0x%x, 0x%x)",
-		    dev->link.mac_fault, dev->link.mac_speed,
-		    dev->link.mac_duplex, dev->link.physical_port);
-		mac_link_update(dev->mac_handle, LINK_STATE_UP);
+	dev->link_speed = link.qos_link_speed ? link.qos_link_speed * 10 :
+	    pow10[link.mac_speed];
+
+	mac_link_update(dev->mac_handle, dev->link_status);
+
+	for (qidx = 0; qidx < dev->nwqs; qidx++) {
+		(void) oce_start_wq(dev->wq[qidx]);
 	}
-
-	(void) oce_start_wq(dev->wq[0]);
-	(void) oce_start_rq(dev->rq[0]);
+	for (qidx = 0; qidx < dev->nrqs; qidx++) {
+		(void) oce_start_rq(dev->rq[qidx]);
+	}
 	(void) oce_start_mq(dev->mq);
 	/* enable interrupts */
 	oce_ei(dev);
@@ -139,11 +130,8 @@
 	for (qidx = 0; qidx < dev->neqs; qidx++) {
 		oce_arm_eq(dev, dev->eq[qidx]->eq_id, 0, B_TRUE, B_FALSE);
 	}
-
-	/* update state */
+	/* TODO update state */
 	return (DDI_SUCCESS);
-start_fail:
-	return (DDI_FAILURE);
 } /* oce_start */
 
 
@@ -168,19 +156,24 @@
 void
 oce_stop(struct oce_dev *dev)
 {
+	int qidx;
 	/* disable interrupts */
 	oce_di(dev);
-	oce_remove_handler(dev);
-	(void) oce_teardown_intr(dev);
-	mutex_enter(&dev->wq[0]->tx_lock);
-	mutex_enter(&dev->rq[0]->rx_lock);
+	for (qidx = 0; qidx < dev->nwqs; qidx++) {
+		mutex_enter(&dev->wq[qidx]->tx_lock);
+	}
 	mutex_enter(&dev->mq->lock);
 	/* complete the pending Tx */
-	oce_clean_wq(dev->wq[0]);
+	for (qidx = 0; qidx < dev->nwqs; qidx++)
+		oce_clean_wq(dev->wq[qidx]);
 	/* Release all the locks */
 	mutex_exit(&dev->mq->lock);
-	mutex_exit(&dev->rq[0]->rx_lock);
-	mutex_exit(&dev->wq[0]->tx_lock);
+	for (qidx = 0; qidx < dev->nwqs; qidx++)
+		mutex_exit(&dev->wq[qidx]->tx_lock);
+	if (dev->link_status == LINK_STATE_UP) {
+		dev->link_status = LINK_STATE_UNKNOWN;
+		mac_link_update(dev->mac_handle, dev->link_status);
+	}
 
 } /* oce_stop */
 
@@ -191,7 +184,7 @@
 	struct oce_dev *dev = (struct oce_dev *)arg;
 	struct ether_addr  *mca_drv_list;
 	struct ether_addr  mca_hw_list[OCE_MAX_MCA];
-	uint16_t new_mcnt = 0;
+	uint16_t new_mcnt = dev->num_mca;
 	int ret;
 	int i;
 
@@ -206,7 +199,7 @@
 	DEV_LOCK(dev);
 	if (add) {
 		/* check if we exceeded hw max  supported */
-		if (dev->num_mca <= OCE_MAX_MCA) {
+		if (new_mcnt < OCE_MAX_MCA) {
 			/* copy entire dev mca to the mbx */
 			bcopy((void*)mca_drv_list,
 			    (void*)mca_hw_list,
@@ -215,7 +208,7 @@
 			bcopy(mca, &mca_hw_list[dev->num_mca],
 			    sizeof (struct ether_addr));
 		}
-		new_mcnt = dev->num_mca + 1;
+		new_mcnt++;
 	} else {
 		struct ether_addr *hwlistp = &mca_hw_list[0];
 		for (i = 0; i < dev->num_mca; i++) {
@@ -224,16 +217,18 @@
 				bcopy(mca_drv_list + i, hwlistp,
 				    ETHERADDRL);
 				hwlistp++;
+			} else {
+				new_mcnt--;
 			}
 		}
-		new_mcnt = dev->num_mca - 1;
 	}
 
 	if (dev->suspended) {
 		goto finish;
 	}
-	if (new_mcnt == 0 || new_mcnt > OCE_MAX_MCA) {
-		ret = oce_set_multicast_table(dev, dev->if_id, NULL, 0, B_TRUE);
+	if (new_mcnt > OCE_MAX_MCA) {
+		ret = oce_set_multicast_table(dev, dev->if_id, &mca_hw_list[0],
+		    OCE_MAX_MCA, B_TRUE);
 	} else {
 		ret = oce_set_multicast_table(dev, dev->if_id,
 		    &mca_hw_list[0], new_mcnt, B_FALSE);
@@ -249,8 +244,9 @@
 	if (new_mcnt && new_mcnt <= OCE_MAX_MCA) {
 		bcopy(mca_hw_list, mca_drv_list,
 		    new_mcnt * sizeof (struct ether_addr));
+
+		dev->num_mca = (uint16_t)new_mcnt;
 	}
-	dev->num_mca = (uint16_t)new_mcnt;
 	DEV_UNLOCK(dev);
 	return (0);
 } /* oce_m_multicast */
@@ -274,6 +270,7 @@
 		DEV_UNLOCK(dev);
 		return (EIO);
 	}
+	bzero(dev->unicast_addr, ETHERADDRL);
 
 	/* Set the New MAC addr earlier is no longer valid */
 	ret = oce_add_mac(dev, dev->if_id, uca, &dev->pmac_id);
@@ -281,10 +278,15 @@
 		DEV_UNLOCK(dev);
 		return (EIO);
 	}
+	bcopy(uca, dev->unicast_addr, ETHERADDRL);
 	DEV_UNLOCK(dev);
 	return (ret);
 } /* oce_m_unicast */
 
+/*
+ * Hashing policy for load balancing over the set of TX rings
+ * available to the driver.
+ */
 mblk_t *
 oce_m_send(void *arg, mblk_t *mp)
 {
@@ -300,7 +302,10 @@
 		return (NULL);
 	}
 	DEV_UNLOCK(dev);
-	wq = dev->wq[0];
+	/*
+	 * Hash to pick a wq
+	 */
+	wq = oce_get_wq(dev, mp);
 
 	while (mp != NULL) {
 		/* Save the Pointer since mp will be freed in case of copy */
@@ -469,12 +474,20 @@
 
 	case MAC_PROP_SPEED: {
 		uint64_t *speed = (uint64_t *)val;
+		struct link_status link = {0};
 
 		ASSERT(size >= sizeof (uint64_t));
 		*speed = 0;
-		if ((dev->state & STATE_MAC_STARTED) &&
-		    (dev->link.mac_speed != 0)) {
-			*speed = 1000000ull * oce_power10(dev->link.mac_speed);
+
+		if (dev->state & STATE_MAC_STARTED) {
+			if (dev->link_speed < 0) {
+				(void) oce_get_link_status(dev, &link);
+				dev->link_speed = link.qos_link_speed ?
+				    link.qos_link_speed * 10 :
+				    pow10[link.mac_speed];
+			}
+
+			*speed = dev->link_speed * 1000000ull;
 		}
 		break;
 	}
@@ -631,18 +644,6 @@
 	return (ret);
 } /* oce_m_promiscuous */
 
-static int
-oce_power10(int power)
-{
-	int ret = 1;
-
-	while (power) {
-		ret *= 10;
-		power--;
-	}
-	return (ret);
-}
-
 /*
  * function to set a private property.
  * Called from the set_prop GLD entry point
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_hw.c	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_hw.c	Thu Aug 05 11:14:15 2010 -0600
@@ -158,6 +158,7 @@
 	ret = oce_map_regs(dev);
 
 	if (ret != DDI_SUCCESS) {
+		pci_config_teardown(&dev->pci_cfg_handle);
 		return (DDI_FAILURE);
 	}
 	dev->fn =  OCE_PCI_FUNC(dev);
@@ -335,9 +336,16 @@
 oce_create_nw_interface(struct oce_dev *dev)
 {
 	int ret;
+	uint32_t capab_flags = OCE_CAPAB_FLAGS;
+	uint32_t capab_en_flags = OCE_CAPAB_ENABLE;
+
+	if (dev->rss_enable) {
+		capab_flags |= MBX_RX_IFACE_FLAGS_RSS;
+		capab_en_flags |= MBX_RX_IFACE_FLAGS_RSS;
+	}
 
 	/* create an interface for the device with out mac */
-	ret = oce_if_create(dev, OCE_DEFAULT_IF_CAP, OCE_DEFAULT_IF_CAP_EN,
+	ret = oce_if_create(dev, capab_flags, capab_en_flags,
 	    0, &dev->mac_addr[0], (uint32_t *)&dev->if_id);
 	if (ret != 0) {
 		oce_log(dev, CE_WARN, MOD_CONFIG,
@@ -346,7 +354,7 @@
 	}
 	atomic_inc_32(&dev->nifs);
 
-	dev->if_cap_flags = OCE_DEFAULT_IF_CAP_EN;
+	dev->if_cap_flags = capab_en_flags;
 
 	/* Enable VLAN Promisc on HW */
 	ret = oce_config_vlan(dev, (uint8_t)dev->if_id, NULL, 0,
@@ -371,17 +379,6 @@
 		oce_log(dev, CE_NOTE, MOD_CONFIG,
 		    "Set Promisc failed: %d", ret);
 	}
-#if 0
-	/* this could happen if the  driver is resuming after suspend */
-	if (dev->num_mca > 0) {
-		ret = oce_set_multicast_table(dev, dev->multi_cast,
-		    dev->num_mca);
-		if (ret != 0) {
-			oce_log(dev, CE_NOTE, MOD_CONFIG,
-			    "Set Multicast failed: %d", ret);
-		}
-	}
-#endif
 
 	return (0);
 }
@@ -396,11 +393,28 @@
 	}
 }
 
+static void
+oce_create_itbl(struct oce_dev *dev, char *itbl)
+{
+	int i;
+	struct oce_rq **rss_queuep = &dev->rq[1];
+	int nrss  = dev->nrqs - 1;
+	/* fill the indirection table rq 0 is default queue */
+	for (i = 0; i < OCE_ITBL_SIZE; i++) {
+		itbl[i] = rss_queuep[i % nrss]->rss_cpuid;
+	}
+}
 
 int
 oce_setup_adapter(struct oce_dev *dev)
 {
 	int ret;
+	char itbl[OCE_ITBL_SIZE];
+	char hkey[OCE_HKEY_SIZE];
+
+	/* disable the interrupts here and enable in start */
+	oce_chip_di(dev);
+
 	ret = oce_create_nw_interface(dev);
 	if (ret != DDI_SUCCESS) {
 		return (DDI_FAILURE);
@@ -410,12 +424,47 @@
 		oce_delete_nw_interface(dev);
 		return (DDI_FAILURE);
 	}
+	if (dev->rss_enable) {
+		(void) oce_create_itbl(dev, itbl);
+		(void) oce_gen_hkey(hkey, OCE_HKEY_SIZE);
+		ret = oce_config_rss(dev, dev->if_id, hkey, itbl, OCE_ITBL_SIZE,
+		    OCE_DEFAULT_RSS_TYPE, B_TRUE);
+		if (ret != DDI_SUCCESS) {
+			oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
+			    "Failed to Configure RSS");
+			oce_delete_queues(dev);
+			oce_delete_nw_interface(dev);
+			return (ret);
+		}
+	}
+	ret = oce_setup_handlers(dev);
+	if (ret != DDI_SUCCESS) {
+		oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
+		    "Failed to Setup handlers");
+		oce_delete_queues(dev);
+		oce_delete_nw_interface(dev);
+		return (ret);
+	}
 	return (DDI_SUCCESS);
 }
 
 void
 oce_unsetup_adapter(struct oce_dev *dev)
 {
+	oce_remove_handler(dev);
+	if (dev->rss_enable) {
+		char itbl[OCE_ITBL_SIZE] = {0};
+		char hkey[OCE_HKEY_SIZE] = {0};
+		int ret = 0;
+
+		ret = oce_config_rss(dev, dev->if_id, hkey, itbl, OCE_ITBL_SIZE,
+		    RSS_ENABLE_NONE, B_TRUE);
+
+		if (ret != DDI_SUCCESS) {
+			oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
+			    "Failed to Disable RSS");
+		}
+	}
 	oce_delete_queues(dev);
 	oce_delete_nw_interface(dev);
 }
@@ -435,7 +484,7 @@
 	}
 	/* create bootstrap mailbox */
 	dev->bmbx = oce_alloc_dma_buffer(dev,
-	    sizeof (struct oce_bmbx), DDI_DMA_CONSISTENT);
+	    sizeof (struct oce_bmbx), NULL, DDI_DMA_CONSISTENT);
 	if (dev->bmbx == NULL) {
 		oce_log(dev, CE_WARN, MOD_CONFIG,
 		    "Failed to allocate bmbx: size = %u",
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_intr.c	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_intr.c	Thu Aug 05 11:14:15 2010 -0600
@@ -31,17 +31,8 @@
 
 #include <oce_impl.h>
 
-static int oce_setup_msix(struct oce_dev *dev);
-static int oce_teardown_msix(struct oce_dev *dev);
-static int oce_add_msix_handlers(struct oce_dev *dev);
-static void oce_del_msix_handlers(struct oce_dev *dev);
 static uint_t oce_isr(caddr_t arg1, caddr_t arg2);
 
-static int oce_setup_intx(struct oce_dev *dev);
-static int oce_teardown_intx(struct oce_dev *dev);
-static int oce_add_intx_handlers(struct oce_dev *dev);
-static void oce_del_intx_handlers(struct oce_dev *dev);
-
 /*
  * top level function to setup interrupts
  *
@@ -54,6 +45,11 @@
 {
 	int ret;
 	int intr_types = 0;
+	int navail = 0;
+	int nsupported = 0;
+	int min = 0;
+	int nreqd = 0;
+	int nallocd = 0;
 
 	/* get supported intr types */
 	ret = ddi_intr_get_supported_types(dev->dip, &intr_types);
@@ -63,30 +59,94 @@
 		return (DDI_FAILURE);
 	}
 
+retry_intr:
 	if (intr_types & DDI_INTR_TYPE_MSIX) {
-		dev->intr_types = DDI_INTR_TYPE_MSIX;
-		dev->num_vectors = 2;
-		return (DDI_SUCCESS);
+		dev->intr_type = DDI_INTR_TYPE_MSIX;
+		/* one vector is shared by MCC and Tx */
+		nreqd = dev->rx_rings + 1;
+		min = OCE_MIN_VECTORS;
+	} else if (intr_types & DDI_INTR_TYPE_FIXED) {
+		dev->intr_type = DDI_INTR_TYPE_FIXED;
+		nreqd = OCE_MIN_VECTORS;
+		min = OCE_MIN_VECTORS;
+	}
+
+	ret = ddi_intr_get_nintrs(dev->dip, dev->intr_type, &nsupported);
+	if (ret != DDI_SUCCESS) {
+		oce_log(dev, CE_WARN, MOD_CONFIG,
+		    "Could not get nintrs:0x%d", ret);
+		return (DDI_FAILURE);
+	}
+
+	/* get the number of vectors available */
+	ret = ddi_intr_get_navail(dev->dip, dev->intr_type, &navail);
+	if (ret != DDI_SUCCESS || navail < min) {
+		oce_log(dev, CE_WARN, MOD_CONFIG,
+		    "Could not get msix vectors:0x%x",
+		    navail);
+		return (DDI_FAILURE);
+	}
+
+	if (navail < min) {
+		return (DDI_FAILURE);
+	}
+
+	/* if the requested number is more than available reset reqd */
+	if (navail < nreqd) {
+		nreqd = navail;
 	}
 
-	if (intr_types & DDI_INTR_TYPE_FIXED) {
-		dev->intr_types = DDI_INTR_TYPE_FIXED;
-		dev->num_vectors = 1;
-		return (DDI_SUCCESS);
-	}
-	return (DDI_FAILURE);
-}
+	/* allocate htable */
+	dev->hsize  = nreqd *  sizeof (ddi_intr_handle_t);
+	dev->htable = kmem_zalloc(dev->hsize,  KM_NOSLEEP);
+
+	if (dev->htable == NULL)
+		return (DDI_FAILURE);
 
-int
-oce_alloc_intr(struct oce_dev *dev)
-{
-	if (dev->intr_types == DDI_INTR_TYPE_MSIX) {
-		return (oce_setup_msix(dev));
+	nallocd = 0;
+	/* allocate interrupt handlers */
+	ret = ddi_intr_alloc(dev->dip, dev->htable, dev->intr_type,
+	    0, nreqd, &nallocd, DDI_INTR_ALLOC_NORMAL);
+
+	if (ret != DDI_SUCCESS) {
+		goto fail_intr;
 	}
-	if (dev->intr_types == DDI_INTR_TYPE_FIXED) {
-		return (oce_setup_intx(dev));
+
+	dev->num_vectors = nallocd;
+	if (nallocd < min) {
+		goto fail_intr;
 	}
 
+	/*
+	 * get the interrupt priority. Assumption is that all handlers have
+	 * equal priority
+	 */
+
+	ret = ddi_intr_get_pri(dev->htable[0], &dev->intr_pri);
+
+	if (ret != DDI_SUCCESS) {
+		goto fail_intr;
+	}
+
+	(void) ddi_intr_get_cap(dev->htable[0], &dev->intr_cap);
+
+	if ((intr_types & DDI_INTR_TYPE_MSIX) && (nallocd > 1)) {
+		dev->rx_rings = nallocd - 1;
+	} else {
+		dev->rx_rings = 1;
+	}
+
+	return (DDI_SUCCESS);
+
+fail_intr:
+	(void) oce_teardown_intr(dev);
+	if ((dev->intr_type == DDI_INTR_TYPE_MSIX) &&
+	    (intr_types & DDI_INTR_TYPE_FIXED)) {
+		intr_types &= ~DDI_INTR_TYPE_MSIX;
+		oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
+		    "Could not get MSIX vectors, trying for FIXED vectors");
+		goto retry_intr;
+	}
 	return (DDI_FAILURE);
 }
 
@@ -100,15 +160,18 @@
 int
 oce_teardown_intr(struct oce_dev *dev)
 {
-	if (dev->intr_types ==  DDI_INTR_TYPE_MSIX) {
-		return (oce_teardown_msix(dev));
+	int i;
+
+	/* release handlers */
+	for (i = 0; i < dev->num_vectors; i++) {
+		(void) ddi_intr_free(dev->htable[i]);
 	}
 
-	if (dev->intr_types == DDI_INTR_TYPE_FIXED) {
-		return (oce_teardown_intx(dev));
-	}
+	/* release htable */
+	kmem_free(dev->htable, dev->hsize);
+	dev->htable = NULL;
 
-	return (DDI_FAILURE);
+	return (DDI_SUCCESS);
 }
 
 /*
@@ -121,15 +184,21 @@
 int
 oce_setup_handlers(struct oce_dev *dev)
 {
-	if (dev->intr_types == DDI_INTR_TYPE_MSIX) {
-		return (oce_add_msix_handlers(dev));
+	int i = 0;
+	int ret;
+	for (i = 0; i < dev->num_vectors; i++) {
+		ret = ddi_intr_add_handler(dev->htable[i], oce_isr,
+		    (caddr_t)dev->eq[i], NULL);
+		if (ret != DDI_SUCCESS) {
+			oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
+			    "Failed to add interrupt handlers");
+			for (i--; i >= 0; i--) {
+				(void) ddi_intr_remove_handler(dev->htable[i]);
+			}
+			return (DDI_FAILURE);
+		}
 	}
-
-	if (dev->intr_types == DDI_INTR_TYPE_FIXED) {
-		return (oce_add_intx_handlers(dev));
-	}
-
-	return (DDI_FAILURE);
+	return (DDI_SUCCESS);
 }
 
 /*
@@ -142,12 +211,9 @@
 void
 oce_remove_handler(struct oce_dev *dev)
 {
-	if (dev->intr_types == DDI_INTR_TYPE_MSIX) {
-		oce_del_msix_handlers(dev);
-	}
-
-	if (dev->intr_types == DDI_INTR_TYPE_FIXED) {
-		oce_del_intx_handlers(dev);
+	int nvec;
+	for (nvec = 0; nvec < dev->num_vectors; nvec++) {
+		(void) ddi_intr_remove_handler(dev->htable[nvec]);
 	}
 }
 
@@ -225,6 +291,7 @@
 	int i;
 	int ret;
 
+	oce_chip_di(dev);
 	if (dev->intr_cap & DDI_INTR_FLAG_BLOCK) {
 		(void) ddi_intr_block_disable(dev->htable, dev->num_vectors);
 	} else {
@@ -236,160 +303,9 @@
 			}
 		}
 	}
-	oce_chip_di(dev);
 } /* oce_di */
 
 /*
- * function to setup the MSIX vectors
- *
- * dev - software handle to the device
- *
- * return 0=>success, failure otherwise
- */
-static int
-oce_setup_msix(struct oce_dev *dev)
-{
-	int navail = 0;
-	int ret = 0;
-
-	ret = ddi_intr_get_nintrs(dev->dip, DDI_INTR_TYPE_MSIX, &navail);
-	if (ret != DDI_SUCCESS) {
-		oce_log(dev, CE_WARN, MOD_CONFIG,
-		    "Could not get nintrs:0x%x %d",
-		    navail, ret);
-		return (DDI_FAILURE);
-	}
-
-	/* get the number of vectors available */
-	ret = ddi_intr_get_navail(dev->dip, DDI_INTR_TYPE_MSIX, &navail);
-	if (ret != DDI_SUCCESS) {
-		oce_log(dev, CE_WARN, MOD_CONFIG,
-		    "Could not get msix vectors:0x%x",
-		    navail);
-		return (DDI_FAILURE);
-	}
-
-	if (navail < dev->num_vectors)
-		return (DDI_FAILURE);
-
-	/* allocate htable */
-	dev->htable = kmem_zalloc(dev->num_vectors *
-	    sizeof (ddi_intr_handle_t), KM_NOSLEEP);
-
-	if (dev->htable == NULL)
-		return (DDI_FAILURE);
-
-	/* allocate interrupt handlers */
-	ret = ddi_intr_alloc(dev->dip, dev->htable, DDI_INTR_TYPE_MSIX,
-	    0, dev->num_vectors, &navail, DDI_INTR_ALLOC_NORMAL);
-
-	if (ret != DDI_SUCCESS || navail < dev->num_vectors) {
-		oce_log(dev, CE_WARN, MOD_CONFIG,
-		    "Alloc intr failed: %d %d",
-		    navail, ret);
-		kmem_free(dev->htable,
-		    dev->num_vectors * sizeof (ddi_intr_handle_t));
-		return (DDI_FAILURE);
-	}
-
-	/* update the actual number of interrupts allocated */
-	dev->num_vectors = navail;
-
-	/*
-	 * get the interrupt priority. Assumption is that all handlers have
-	 * equal priority
-	 */
-
-	ret = ddi_intr_get_pri(dev->htable[0], &dev->intr_pri);
-
-	if (ret != DDI_SUCCESS) {
-		int i;
-		oce_log(dev, CE_WARN, MOD_CONFIG,
-		    "Unable to get intr priority: 0x%x",
-		    dev->intr_pri);
-		for (i = 0; i < dev->num_vectors; i++) {
-			(void) ddi_intr_free(dev->htable[i]);
-		}
-		kmem_free(dev->htable,
-		    dev->num_vectors * sizeof (ddi_intr_handle_t));
-		return (DDI_FAILURE);
-	}
-
-	(void) ddi_intr_get_cap(dev->htable[0], &dev->intr_cap);
-	return (DDI_SUCCESS);
-} /* oce_setup_msix */
-
-/*
- * helper function to teardown MSIX interrupts
- *
- * dev - software handle to the device
- *
- * return 0 => success, failure otherwise
- */
-static int
-oce_teardown_msix(struct oce_dev *dev)
-{
-	int i;
-
-	/* release handlers */
-	for (i = 0; i < dev->num_vectors; i++) {
-		(void) ddi_intr_free(dev->htable[i]);
-	}
-
-	/* release htable */
-	kmem_free(dev->htable,
-	    dev->num_vectors * sizeof (ddi_intr_handle_t));
-
-	return (DDI_SUCCESS);
-} /* oce_teardown_msix */
-
-/*
- * function to add MSIX handlers to vectors
- *
- * dev - software handle to the device
- *
- * return DDI_SUCCESS => success, failure otherwise
- */
-static int
-oce_add_msix_handlers(struct oce_dev *dev)
-{
-	int ret;
-	int i;
-
-	for (i = 0; i < dev->neqs; i++) {
-		ret = ddi_intr_add_handler(dev->htable[i], oce_isr,
-		    (caddr_t)dev->eq[i], NULL);
-		if (ret != DDI_SUCCESS) {
-			oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
-			    "Failed to add interrupt handlers");
-			for (i--; i >= 0; i--) {
-				(void) ddi_intr_remove_handler(dev->htable[i]);
-			}
-			return (DDI_FAILURE);
-		}
-	}
-
-	return (DDI_SUCCESS);
-} /* oce_add_msix_handlers */
-
-/*
- * function to disassociate msix handlers added in oce_add_msix_handlers
- *
- * dev - software handle to the device
- *
- * return DDI_SUCCESS => success, failure otherwise
- */
-static void
-oce_del_msix_handlers(struct oce_dev *dev)
-{
-	int nvec;
-
-	for (nvec = 0; nvec < dev->num_vectors; nvec++) {
-		(void) ddi_intr_remove_handler(dev->htable[nvec]);
-	}
-} /* oce_del_msix_handlers */
-
-/*
  * command interrupt handler routine added to all vectors
  *
  * arg1 = callback data
@@ -411,22 +327,8 @@
 
 	eq = (struct oce_eq *)(void *)(arg1);
 
-	if (eq == NULL) {
-		return (DDI_INTR_UNCLAIMED);
-	}
 	dev = eq->parent;
 
-	/* If device is getting suspended or closing, then return */
-	if ((dev == NULL) ||
-	    (dev->state & STATE_MAC_STOPPING) ||
-	    !(dev->state & STATE_MAC_STARTED) ||
-	    dev->suspended) {
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	(void) ddi_dma_sync(eq->ring->dbuf->dma_handle, 0, 0,
-	    DDI_DMA_SYNC_FORKERNEL);
-
 	eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
 
 	while (eqe->u0.dw0) {
@@ -441,7 +343,7 @@
 		}
 
 		/* get the cq from the eqe */
-		cq_id = eqe->u0.s.resource_id;
+		cq_id = eqe->u0.s.resource_id % OCE_MAX_CQ;
 		cq = dev->cq[cq_id];
 
 		/* Call the completion handler */
@@ -455,119 +357,10 @@
 	} /* for all EQEs */
 
 	/* ring the eq doorbell, signify that it's done processing  */
+	oce_arm_eq(dev, eq->eq_id, num_eqe, B_TRUE, B_TRUE);
 	if (num_eqe > 0) {
-		oce_arm_eq(dev, eq->eq_id, num_eqe, B_TRUE, B_TRUE);
 		return (DDI_INTR_CLAIMED);
 	} else {
 		return (DDI_INTR_UNCLAIMED);
 	}
 } /* oce_msix_handler */
-
-static int
-oce_setup_intx(struct oce_dev *dev)
-{
-	int navail = 0;
-	int nintr = 0;
-	int ret = 0;
-
-	ret = ddi_intr_get_nintrs(dev->dip, DDI_INTR_TYPE_FIXED, &nintr);
-	if (ret != DDI_SUCCESS) {
-		oce_log(dev, CE_WARN, MOD_CONFIG,
-		    "could not get nintrs:0x%x %d",
-		    navail, ret);
-		return (DDI_FAILURE);
-	}
-
-	/* get the number of vectors available */
-	ret = ddi_intr_get_navail(dev->dip, DDI_INTR_TYPE_FIXED, &navail);
-	if (ret != DDI_SUCCESS) {
-		oce_log(dev, CE_WARN, MOD_CONFIG,
-		    "could not get intx vectors:0x%x",
-		    navail);
-		return (DDI_FAILURE);
-	}
-
-	/* always 1 */
-	if (navail != nintr)
-		return (DDI_FAILURE);
-
-	dev->num_vectors = navail;
-
-	/* allocate htable */
-	dev->htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_NOSLEEP);
-	if (dev->htable == NULL) {
-		return (DDI_FAILURE);
-	}
-
-	/* allocate interrupt handlers */
-	ret = ddi_intr_alloc(dev->dip, dev->htable, DDI_INTR_TYPE_FIXED,
-	    0, dev->num_vectors, &navail, DDI_INTR_ALLOC_NORMAL);
-
-	if (ret != DDI_SUCCESS || navail != 1) {
-		oce_log(dev, CE_WARN, MOD_CONFIG,
-		    "alloc intr failed: %d %d",
-		    navail, ret);
-		kmem_free(dev->htable, sizeof (ddi_intr_handle_t));
-		return (DDI_FAILURE);
-	}
-
-	/* update the actual number of interrupts allocated */
-	dev->num_vectors = navail;
-
-	/*
-	 * get the interrupt priority. Assumption is that all handlers have
-	 * equal priority
-	 */
-
-	ret = ddi_intr_get_pri(dev->htable[0], &dev->intr_pri);
-
-	if (ret != DDI_SUCCESS) {
-		int i;
-		oce_log(dev, CE_WARN, MOD_CONFIG,
-		    "Unable to get intr priority: 0x%x",
-		    dev->intr_pri);
-		for (i = 0; i < dev->num_vectors; i++) {
-			(void) ddi_intr_free(dev->htable[i]);
-		}
-		kmem_free(dev->htable, sizeof (ddi_intr_handle_t));
-		return (DDI_FAILURE);
-	}
-
-	(void) ddi_intr_get_cap(dev->htable[0], &dev->intr_cap);
-	return (DDI_SUCCESS);
-} /* oce_setup_intx */
-
-static int
-oce_teardown_intx(struct oce_dev *dev)
-{
-	/* release handlers */
-	(void) ddi_intr_free(dev->htable[0]);
-
-	/* release htable */
-	kmem_free(dev->htable, sizeof (ddi_intr_handle_t));
-
-	return (DDI_FAILURE);
-} /* oce_teardown_intx */
-
-static int
-oce_add_intx_handlers(struct oce_dev *dev)
-{
-	int ret;
-
-	ret = ddi_intr_add_handler(dev->htable[0], oce_isr,
-	    (caddr_t)dev->eq[0], NULL);
-	if (ret != DDI_SUCCESS) {
-		oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
-		    "failed to add intr handlers");
-		(void) ddi_intr_remove_handler(dev->htable[0]);
-		return (DDI_FAILURE);
-	}
-
-	return (DDI_SUCCESS);
-} /* oce_add_intx_handlers */
-
-static void
-oce_del_intx_handlers(struct oce_dev *dev)
-{
-	(void) ddi_intr_remove_handler(dev->htable[0]);
-} /* oce_del_intx_handlers */
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_main.c	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_main.c	Thu Aug 05 11:14:15 2010 -0600
@@ -40,6 +40,7 @@
 #define	ATTACH_HW_INIT		0x10
 #define	ATTACH_SETUP_TXRX 	0x20
 #define	ATTACH_SETUP_ADAP	0x40
+#define	ATTACH_SETUP_INTR	0x80
 #define	ATTACH_STAT_INIT	0x100
 #define	ATTACH_MAC_REG		0x200
 
@@ -47,16 +48,21 @@
 const char oce_ident_string[] = OCE_IDENT_STRING;
 const char oce_mod_name[] = OCE_MOD_NAME;
 
-char oce_version[] = OCE_REVISION;
-
 /* driver properties */
-static const char mtu_prop_name[] = "oce_default_mtu";
-static const char tx_ring_size_name[] = "oce_tx_ring_size";
-static const char tx_bcopy_limit_name[] = "oce_tx_bcopy_limit";
-static const char rx_bcopy_limit_name[] = "oce_rx_bcopy_limit";
-static const char fm_cap_name[] = "oce_fm_capability";
-static const char log_level_name[] = "oce_log_level";
-static const char lso_capable_name[] = "oce_lso_capable";
+static const char flow_control[]	 = "flow_control";
+static const char mtu_prop_name[]	 = "oce_default_mtu";
+static const char tx_ring_size_name[]	 = "tx_ring_size";
+static const char tx_bcopy_limit_name[]	 = "tx_bcopy_limit";
+static const char rx_bcopy_limit_name[]	 = "rx_bcopy_limit";
+static const char rx_frag_size_name[]	 = "rx_frag_size";
+static const char rx_max_bufs_name[]	 = "rx_max_bufs";
+static const char fm_cap_name[]		 = "oce_fm_capability";
+static const char log_level_name[]	 = "oce_log_level";
+static const char lso_capable_name[]	 = "lso_capable";
+static const char rx_pkt_per_intr_name[] = "rx_pkts_per_intr";
+static const char tx_reclaim_threshold_name[] = "tx_reclaim_threshold";
+static const char rx_rings_name[]	 = "max_rx_rings";
+static const char tx_rings_name[]	 = "max_tx_rings";
 
 /* --[ static function prototypes here ]------------------------------- */
 static int oce_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd);
@@ -68,6 +74,8 @@
 static void oce_init_locks(struct oce_dev *dev);
 static void oce_destroy_locks(struct oce_dev *dev);
 static void oce_get_params(struct oce_dev *dev);
+static int oce_get_prop(struct oce_dev *dev, char *propname, int minval,
+    int maxval, int defval, uint32_t *values);
 
 static struct cb_ops oce_cb_ops = {
 	nulldev,		/* cb_open */
@@ -196,10 +204,7 @@
 	}
 
 	/* allocate dev */
-	dev = kmem_zalloc(sizeof (struct oce_dev), KM_NOSLEEP);
-	if (dev == NULL) {
-		return (DDI_FAILURE);
-	}
+	dev = kmem_zalloc(sizeof (struct oce_dev), KM_SLEEP);
 
 	/* populate the dev structure */
 	dev->dip = dip;
@@ -219,17 +224,6 @@
 
 	oce_fm_init(dev);
 	dev->attach_state |= ATTACH_FM_INIT;
-	ret = oce_setup_intr(dev);
-	if (ret != DDI_SUCCESS) {
-		oce_log(dev, CE_WARN, MOD_CONFIG,
-		    "Interrupt setup failed with %d", ret);
-		goto attach_fail;
-
-	}
-
-	/* initialize locks */
-	oce_init_locks(dev);
-	dev->attach_state |= ATTACH_LOCK_INIT;
 
 	/* setup PCI bars */
 	ret = oce_pci_init(dev);
@@ -240,6 +234,20 @@
 	}
 	dev->attach_state |= ATTACH_PCI_INIT;
 
+	ret = oce_setup_intr(dev);
+	if (ret != DDI_SUCCESS) {
+		oce_log(dev, CE_WARN, MOD_CONFIG,
+		    "Interrupt setup failed with %d", ret);
+		goto attach_fail;
+
+	}
+	dev->attach_state |= ATTACH_SETUP_INTR;
+
+	/* initialize locks */
+	oce_init_locks(dev);
+	dev->attach_state |= ATTACH_LOCK_INIT;
+
+
 	/* HW init */
 	ret = oce_hw_init(dev);
 	if (ret != DDI_SUCCESS) {
@@ -312,7 +320,8 @@
 	}
 
 	/* correct link status only after start */
-	mac_link_update(dev->mac_handle, LINK_STATE_UNKNOWN);
+	dev->link_status = LINK_STATE_UNKNOWN;
+	mac_link_update(dev->mac_handle, dev->link_status);
 
 	dev->attach_state |= ATTACH_MAC_REG;
 	dev->state |= STATE_INIT;
@@ -332,6 +341,7 @@
 {
 	struct oce_dev *dev;
 	int pcnt = 0;
+	int qid;
 
 	dev = ddi_get_driver_private(dip);
 	if (dev == NULL) {
@@ -353,7 +363,6 @@
 	if (mac_unregister(dev->mac_handle) != 0) {
 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
 		    "Failed to unregister MAC ");
-		return (DDI_FAILURE);
 	}
 	dev->attach_state &= ~ATTACH_MAC_REG;
 
@@ -369,10 +378,13 @@
 	/*
 	 * Wait for Packets sent up to be freed
 	 */
-	if ((pcnt = oce_rx_pending(dev)) != 0) {
-		oce_log(dev, CE_WARN, MOD_CONFIG,
-		    "%d Pending Buffers Detach failed", pcnt);
-		return (DDI_FAILURE);
+	for (qid = 0; qid < dev->rx_rings; qid++) {
+		pcnt = oce_rx_pending(dev, dev->rq[qid], DEFAULT_DRAIN_TIME);
+		if (pcnt != 0) {
+			oce_log(dev, CE_WARN, MOD_CONFIG,
+			    "%d Pending Buffers Detach failed", pcnt);
+			return (DDI_FAILURE);
+		}
 	}
 	oce_unconfigure(dev);
 
@@ -430,7 +442,7 @@
 		mutex_exit(&dev->dev_lock);
 		return (DDI_SUCCESS);
 	}
-	if (dev->state & STATE_MAC_STARTED) {
+	if (!(dev->state & STATE_MAC_STARTED)) {
 		ret = oce_setup_adapter(dev);
 		if (ret != DDI_SUCCESS) {
 			mutex_exit(&dev->dev_lock);
@@ -487,12 +499,16 @@
 	if (state & ATTACH_HW_INIT) {
 		oce_hw_fini(dev);
 	}
+	if (state & ATTACH_LOCK_INIT) {
+		oce_destroy_locks(dev);
+	}
+
+	if (state & ATTACH_SETUP_INTR) {
+		(void) oce_teardown_intr(dev);
+	}
 	if (state & ATTACH_PCI_INIT) {
 		oce_pci_fini(dev);
 	}
-	if (state & ATTACH_LOCK_INIT) {
-		oce_destroy_locks(dev);
-	}
 	if (state & ATTACH_FM_INIT) {
 		oce_fm_fini(dev);
 	}
@@ -508,39 +524,77 @@
 	uint32_t log_level;
 	uint16_t mod_mask;
 	uint16_t severity;
+	/*
+	 * Allowed values for the driver parameters. If all values in a range
+	 * is allowed, the the array has only one value.
+	 */
+	uint32_t fc_values[] = {OCE_FC_NONE, OCE_FC_TX, OCE_FC_RX,
+	    OCE_DEFAULT_FLOW_CONTROL, END};
+	uint32_t mtu_values[] = {OCE_MIN_MTU, OCE_MAX_MTU, END};
+	uint32_t tx_rs_values[] = {SIZE_256, SIZE_512, SIZE_1K, SIZE_2K, END};
+	uint32_t tx_bcl_values[] = {SIZE_128, SIZE_256, SIZE_512, SIZE_1K,
+	    SIZE_2K, END};
+	uint32_t rx_bcl_values[] = {SIZE_128, SIZE_256, SIZE_512, SIZE_1K,
+	    SIZE_2K, END};
+	uint32_t rq_fs_values[] = {SIZE_2K, SIZE_4K, SIZE_8K, END};
+	uint32_t rq_mb_values[] = {SIZE_2K, SIZE_4K, SIZE_8K, END};
+	uint32_t lso_capable_values[] = {0, 1, END};
+	uint32_t fm_caps_values[] = {DDI_FM_NOT_CAPABLE, OCE_FM_CAPABILITY,
+	    END};
+	uint32_t tx_rt_values[] = {END};
+	uint32_t rx_ppi_values[] = {END};
+	uint32_t rx_rings_values[] = {END};
+	uint32_t tx_rings_values[] = {END};
+	uint32_t log_level_values[] = {END};
 
 	/* non tunables  */
 	dev->rx_ring_size = OCE_DEFAULT_RX_RING_SIZE;
-	dev->flow_control = OCE_DEFAULT_FLOW_CONTROL;
 
 	/* configurable parameters */
+	dev->flow_control = oce_get_prop(dev, (char *)flow_control, OCE_FC_NONE,
+	    OCE_DEFAULT_FLOW_CONTROL, OCE_DEFAULT_FLOW_CONTROL, fc_values);
 
-	/* restrict MTU to 1500 and 9000 only */
-	dev->mtu = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
-	    DDI_PROP_DONTPASS, (char *)mtu_prop_name, OCE_MIN_MTU);
-	if (dev->mtu != OCE_MIN_MTU && dev->mtu != OCE_MAX_MTU)
-		dev->mtu = OCE_MIN_MTU;
+	dev->mtu = oce_get_prop(dev, (char *)mtu_prop_name, OCE_MIN_MTU,
+	    OCE_MAX_MTU, OCE_MIN_MTU, mtu_values);
+
+	dev->tx_ring_size = oce_get_prop(dev, (char *)tx_ring_size_name,
+	    SIZE_256, SIZE_2K, OCE_DEFAULT_TX_RING_SIZE, tx_rs_values);
+
+	dev->tx_bcopy_limit = oce_get_prop(dev, (char *)tx_bcopy_limit_name,
+	    SIZE_128, SIZE_2K, OCE_DEFAULT_TX_BCOPY_LIMIT, tx_bcl_values);
 
-	dev->tx_ring_size = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
-	    DDI_PROP_DONTPASS, (char *)tx_ring_size_name,
-	    OCE_DEFAULT_TX_RING_SIZE);
+	dev->rx_bcopy_limit = oce_get_prop(dev, (char *)rx_bcopy_limit_name,
+	    SIZE_128, SIZE_2K, OCE_DEFAULT_RX_BCOPY_LIMIT, rx_bcl_values);
+
+	dev->rq_frag_size = oce_get_prop(dev, (char *)rx_frag_size_name,
+	    SIZE_2K, SIZE_8K, OCE_RQ_BUF_SIZE, rq_fs_values);
+
+	dev->rq_max_bufs = oce_get_prop(dev, (char *)rx_max_bufs_name, SIZE_2K,
+	    SIZE_8K, OCE_RQ_NUM_BUFFERS, rq_mb_values);
 
-	dev->tx_bcopy_limit = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
-	    DDI_PROP_DONTPASS, (char *)tx_bcopy_limit_name,
-	    OCE_DEFAULT_TX_BCOPY_LIMIT);
-	dev->rx_bcopy_limit = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
-	    DDI_PROP_DONTPASS, (char *)rx_bcopy_limit_name,
-	    OCE_DEFAULT_RX_BCOPY_LIMIT);
+	dev->lso_capable = oce_get_prop(dev, (char *)lso_capable_name, 0,
+	    1, 1, lso_capable_values);
+
+	dev->fm_caps = oce_get_prop(dev, (char *)fm_cap_name,
+	    DDI_FM_NOT_CAPABLE, OCE_FM_CAPABILITY, OCE_FM_CAPABILITY,
+	    fm_caps_values);
+
+	dev->tx_reclaim_threshold = oce_get_prop(dev,
+	    (char *)tx_reclaim_threshold_name, 0, dev->tx_ring_size/2,
+	    OCE_DEFAULT_TX_RECLAIM_THRESHOLD, tx_rt_values);
 
-	dev->lso_capable = (boolean_t)ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
-	    DDI_PROP_DONTPASS, (char *)lso_capable_name, 1);
+	dev->rx_pkt_per_intr = oce_get_prop(dev, (char *)rx_pkt_per_intr_name,
+	    0, dev->rx_ring_size/2, OCE_DEFAULT_RX_PKT_PER_INTR, rx_ppi_values);
+
+	dev->rx_rings = oce_get_prop(dev, (char *)rx_rings_name,
+	    OCE_DEFAULT_RQS, OCE_MAX_RQS, OCE_DEFAULT_RQS, rx_rings_values);
 
-	dev->fm_caps = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
-	    DDI_PROP_DONTPASS, (char *)fm_cap_name, OCE_FM_CAPABILITY);
+	dev->tx_rings = oce_get_prop(dev, (char *)tx_rings_name,
+	    OCE_DEFAULT_WQS, OCE_DEFAULT_WQS, OCE_DEFAULT_WQS, tx_rings_values);
 
-	log_level = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
-	    DDI_PROP_DONTPASS, (char *)log_level_name,
-	    OCE_DEFAULT_LOG_SETTINGS);
+	log_level = oce_get_prop(dev, (char *)log_level_name, 0,
+	    OCE_MAX_LOG_SETTINGS, OCE_DEFAULT_LOG_SETTINGS, log_level_values);
+
 	severity = (uint16_t)(log_level & 0xffff);
 	mod_mask = (uint16_t)(log_level >> 16);
 	if (mod_mask > MOD_ISR) {
@@ -553,3 +607,33 @@
 	dev->mod_mask = mod_mask;
 	dev->severity = severity;
 } /* oce_get_params */
+
+static int
+oce_get_prop(struct oce_dev *dev, char *propname, int minval, int maxval,
+    int defval, uint32_t *values)
+{
+	int value = 0;
+	int i = 0;
+
+	value = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
+	    DDI_PROP_DONTPASS, propname, defval);
+
+	if (value > maxval)
+		value = maxval;
+
+	if (value < minval)
+		value = minval;
+
+	while (values[i] != 0xdeadface) {
+		if (values[i] == value) {
+			break;
+		}
+		i++;
+	}
+
+	if ((i != 0) && (values[i] == 0xdeadface)) {
+		value = defval;
+	}
+
+	return (value);
+}
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_mbx.c	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_mbx.c	Thu Aug 05 11:14:15 2010 -0600
@@ -79,6 +79,7 @@
 
 	hdr->u0.req.timeout = timeout;
 	hdr->u0.req.request_length = pyld_len - sizeof (struct mbx_hdr);
+	hdr->u0.req.rsvd0 = 0;
 } /* mbx_common_req_hdr_init */
 
 /*
@@ -615,7 +616,10 @@
 	}
 
 	/* interpret response */
-	bcopy(&fwcmd->params.rsp, link, 8);
+	bcopy(&fwcmd->params.rsp, link, sizeof (struct link_status));
+	link->logical_link_status = LE_32(link->logical_link_status);
+	link->qos_link_speed = LE_16(link->qos_link_speed);
+
 	return (0);
 } /* oce_get_link_status */
 
@@ -750,6 +754,15 @@
 	dev->port_id = fwcmd->params.rsp.port_id;
 	dev->function_mode = fwcmd->params.rsp.function_mode;
 
+	/* get the max rings alloted for this function */
+	if (fwcmd->params.rsp.ulp[0].mode & ULP_NIC_MODE) {
+		dev->max_tx_rings = fwcmd->params.rsp.ulp[0].wq_count;
+		dev->max_rx_rings = fwcmd->params.rsp.ulp[0].rq_count;
+	} else {
+		dev->max_tx_rings = fwcmd->params.rsp.ulp[1].wq_count;
+		dev->max_rx_rings = fwcmd->params.rsp.ulp[1].rq_count;
+	}
+	dev->function_caps = fwcmd->params.rsp.function_caps;
 	return (0);
 } /* oce_get_fw_config */
 
@@ -1162,6 +1175,50 @@
 	return (ret);
 } /* oce_config_link */
 
+int
+oce_config_rss(struct oce_dev *dev, uint16_t if_id, char *hkey, char *itbl,
+    int  tbl_sz, uint16_t rss_type, uint8_t flush)
+{
+	struct oce_mbx mbx;
+	struct mbx_config_nic_rss *fwcmd;
+	int i;
+	int ret = 0;
+
+	bzero(&mbx, sizeof (struct oce_mbx));
+	fwcmd = (struct mbx_config_nic_rss *)&mbx.payload;
+
+	/* initialize the ioctl header */
+	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
+	    MBX_SUBSYSTEM_NIC,
+	    OPCODE_CONFIG_NIC_RSS,
+	    MBX_TIMEOUT_SEC,
+	    sizeof (struct mbx_config_nic_rss));
+	fwcmd->params.req.enable_rss = LE_16(rss_type);
+	fwcmd->params.req.flush = flush;
+	fwcmd->params.req.if_id = LE_32(if_id);
+
+	if (hkey != NULL) {
+		bcopy(hkey, fwcmd->params.req.hash, OCE_HKEY_SIZE);
+	}
+
+
+	/* Fill the indirection table */
+	for (i = 0; i < tbl_sz; i++) {
+		fwcmd->params.req.cputable[i] = itbl[i];
+	}
+
+	fwcmd->params.req.cpu_tbl_sz_log2 = LE_16(OCE_LOG2(tbl_sz));
+
+	/* fill rest of mbx */
+	mbx.u0.s.embedded = B_TRUE;
+	mbx.payload_length = sizeof (struct mbx_config_nic_rss);
+	DW_SWAP(u32ptr(&mbx), (OCE_BMBX_RHDR_SZ + OCE_MBX_RRHDR_SZ));
+
+	/* post the command */
+	ret = oce_mbox_post(dev, &mbx, NULL);
+
+	return (ret);
+}
 
 /*
  * function called from the gld ioctl entry point to send a mbx to fw
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_mq.c	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_mq.c	Thu Aug 05 11:14:15 2010 -0600
@@ -62,9 +62,18 @@
 			acqe = (struct oce_async_cqe_link_state *)cqe;
 			if (acqe->u0.s.event_code ==
 			    ASYNC_EVENT_CODE_LINK_STATE) {
-				link_status = (acqe->u0.s.link_status)?
-				    LINK_STATE_UP : LINK_STATE_DOWN;
+				/*
+				 * don't care logical or not,
+				 * just check up down
+				 */
+
+				link_status = ((acqe->u0.s.link_status &
+				    ~ASYNC_EVENT_LOGICAL) ==
+				    ASYNC_EVENT_LINK_UP) ?
+				    LINK_STATE_UP: LINK_STATE_DOWN;
 				mac_link_update(dev->mac_handle, link_status);
+				dev->link_status = link_status;
+				dev->link_speed = -1;
 			}
 		}
 		cqe->u0.dw[3] = 0;
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_queue.c	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_queue.c	Thu Aug 05 11:14:15 2010 -0600
@@ -278,7 +278,7 @@
 	cq->cq_cfg.nodelay = (uint8_t)nodelay;
 	/* interpret the response */
 	cq->cq_id = LE_16(fwcmd->params.rsp.cq_id);
-	dev->cq[cq->cq_id] = cq;
+	dev->cq[cq->cq_id % OCE_MAX_CQ] = cq;
 	atomic_inc_32(&eq->ref_count);
 	return (cq);
 } /* oce_cq_create */
@@ -311,7 +311,7 @@
 
 	/* Reset the handler */
 	cq->cq_handler = NULL;
-	dev->cq[cq->cq_id] = NULL;
+	dev->cq[cq->cq_id % OCE_MAX_CQ] = NULL;
 	atomic_dec_32(&cq->eq->ref_count);
 	mutex_destroy(&cq->lock);
 
@@ -359,7 +359,7 @@
 
 	/* create the ring buffer for this queue */
 	mq->ring = create_ring_buffer(dev, q_len,
-	    sizeof (struct oce_mbx), DDI_DMA_CONSISTENT);
+	    sizeof (struct oce_mbx), DDI_DMA_CONSISTENT | DDI_DMA_RDWR);
 	if (mq->ring == NULL) {
 		oce_log(dev, CE_WARN, MOD_CONFIG,
 		    "MQ ring alloc failed:0x%p",
@@ -462,6 +462,7 @@
 	struct oce_wq *wq;
 	char str[MAX_POOL_NAME];
 	int ret;
+	static int wq_id = 0;
 
 	ASSERT(dev != NULL);
 	/* q_len must be min 256 and max 2k */
@@ -486,12 +487,13 @@
 	wq->cfg.eqd = OCE_DEFAULT_WQ_EQD;
 	wq->cfg.nbufs = 2 * wq->cfg.q_len;
 	wq->cfg.nhdl = 2 * wq->cfg.q_len;
+	wq->cfg.buf_size = dev->tx_bcopy_limit;
 
 	/* assign parent */
 	wq->parent = (void *)dev;
 
 	/* Create the WQ Buffer pool */
-	ret  = oce_wqb_cache_create(wq, dev->tx_bcopy_limit);
+	ret  = oce_wqb_cache_create(wq, wq->cfg.buf_size);
 	if (ret != DDI_SUCCESS) {
 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
 		    "WQ Buffer Pool create failed ");
@@ -506,10 +508,10 @@
 		goto wqm_fail;
 	}
 
-	(void) snprintf(str, MAX_POOL_NAME, "%s%d", "oce_wqed_", dev->dev_id);
+	(void) snprintf(str, MAX_POOL_NAME, "%s%d%s%d", "oce_wqed_",
+	    dev->dev_id, "_", wq_id++);
 	wq->wqed_cache = kmem_cache_create(str, sizeof (oce_wqe_desc_t),
-	    0, oce_wqe_desc_ctor,
-	    oce_wqe_desc_dtor, NULL, NULL, NULL, 0);
+	    0, NULL, NULL, NULL, NULL, NULL, 0);
 	if (wq->wqed_cache == NULL) {
 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
 		    "WQ Packet Desc Pool create failed ");
@@ -518,7 +520,7 @@
 
 	/* create the ring buffer */
 	wq->ring = create_ring_buffer(dev, q_len,
-	    NIC_WQE_SIZE, DDI_DMA_CONSISTENT);
+	    NIC_WQE_SIZE, DDI_DMA_CONSISTENT | DDI_DMA_RDWR);
 	if (wq->ring == NULL) {
 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
 		    "Failed to create WQ ring ");
@@ -690,7 +692,6 @@
  *
  * return pointer to the RQ created. NULL on failure
  */
-/* ARGSUSED */
 static struct oce_rq *
 oce_rq_init(struct oce_dev *dev, uint32_t q_len,
     uint32_t frag_size, uint32_t mtu,
@@ -718,13 +719,37 @@
 	rq->cfg.frag_size = frag_size;
 	rq->cfg.mtu = mtu;
 	rq->cfg.eqd = 0;
-	rq->cfg.nbufs = 8 * 1024;
+	rq->cfg.nbufs = dev->rq_max_bufs;
+	rq->cfg.is_rss_queue = rss;
 
 	/* assign parent */
 	rq->parent = (void *)dev;
 
-	/* create the cache */
-	ret  =  oce_rqb_cache_create(rq, OCE_RQ_BUF_SIZE +
+	rq->rq_bdesc_array =
+	    kmem_zalloc((sizeof (oce_rq_bdesc_t) * rq->cfg.nbufs), KM_NOSLEEP);
+	if (rq->rq_bdesc_array == NULL) {
+		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
+		    "RQ bdesc alloc failed");
+		goto rqbd_alloc_fail;
+	}
+	/* create the rq buffer descriptor ring */
+	rq->shadow_ring =
+	    kmem_zalloc((rq->cfg.q_len * sizeof (oce_rq_bdesc_t *)),
+	    KM_NOSLEEP);
+	if (rq->shadow_ring == NULL) {
+		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
+		    "RQ shadow ring alloc failed ");
+		goto rq_shdw_fail;
+	}
+
+	/* allocate the free list array */
+	rq->rqb_freelist =
+	    kmem_zalloc(rq->cfg.nbufs * sizeof (oce_rq_bdesc_t *), KM_NOSLEEP);
+	if (rq->rqb_freelist == NULL) {
+		goto rqb_free_list_fail;
+	}
+	/* create the buffer pool */
+	ret  =  oce_rqb_cache_create(rq, dev->rq_frag_size +
 	    OCE_RQE_BUF_HEADROOM);
 	if (ret != DDI_SUCCESS) {
 		goto rqb_fail;
@@ -732,17 +757,13 @@
 
 	/* create the ring buffer */
 	rq->ring = create_ring_buffer(dev, q_len,
-	    sizeof (struct oce_nic_rqe), DDI_DMA_CONSISTENT);
+	    sizeof (struct oce_nic_rqe), DDI_DMA_CONSISTENT | DDI_DMA_RDWR);
 	if (rq->ring == NULL) {
 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
 		    "RQ ring create failed ");
 		goto rq_ringfail;
 	}
 
-	/* allocate mbx */
-	rq->shadow_ring = kmem_zalloc(sizeof (struct rq_shadow_entry) *
-	    q_len, KM_SLEEP);
-
 	/* Initialize the RQ lock */
 	mutex_init(&rq->rx_lock, NULL, MUTEX_DRIVER,
 	    DDI_INTR_PRI(dev->intr_pri));
@@ -752,13 +773,18 @@
 	atomic_inc_32(&dev->nrqs);
 	return (rq);
 
-rqcq_fail:
-	kmem_free(rq->shadow_ring,
-	    sizeof (struct rq_shadow_entry) * q_len);
-	destroy_ring_buffer(dev, rq->ring);
 rq_ringfail:
 	oce_rqb_cache_destroy(rq);
 rqb_fail:
+	kmem_free(rq->shadow_ring,
+	    (rq->cfg.q_len * sizeof (oce_rq_bdesc_t *)));
+rqb_free_list_fail:
+	kmem_free(rq->rqb_freelist,
+	    (rq->cfg.nbufs * sizeof (oce_rq_bdesc_t *)));
+rq_shdw_fail:
+	kmem_free(rq->rq_bdesc_array,
+	    (sizeof (oce_rq_bdesc_t) * rq->cfg.q_len));
+rqbd_alloc_fail:
 	kmem_free(rq, sizeof (struct oce_rq));
 	return (NULL);
 } /* oce_rq_create */
@@ -779,8 +805,14 @@
 	destroy_ring_buffer(dev, rq->ring);
 	rq->ring = NULL;
 	kmem_free(rq->shadow_ring,
-	    sizeof (struct rq_shadow_entry) * rq->cfg.q_len);
+	    sizeof (oce_rq_bdesc_t *) * rq->cfg.q_len);
 	rq->shadow_ring = NULL;
+	kmem_free(rq->rq_bdesc_array,
+	    (sizeof (oce_rq_bdesc_t) * rq->cfg.nbufs));
+	rq->rq_bdesc_array = NULL;
+	kmem_free(rq->rqb_freelist,
+	    (rq->cfg.nbufs * sizeof (oce_rq_bdesc_t *)));
+	rq->rqb_freelist = NULL;
 	mutex_destroy(&rq->rx_lock);
 	mutex_destroy(&rq->rc_lock);
 	kmem_free(rq, sizeof (struct oce_rq));
@@ -838,7 +870,7 @@
 
 	/* interpret the response */
 	rq->rq_id = LE_16(fwcmd->params.rsp.u0.s.rq_id);
-	/* rq->rss_cpuid = fwcmd->params.rsp.u0.bits.rss_cpuid; */
+	rq->rss_cpuid = fwcmd->params.rsp.u0.s.rss_cpuid;
 	rq->cfg.if_id = if_id;
 	rq->qstate = QCREATED;
 	rq->cq = cq;
@@ -885,7 +917,7 @@
 		oce_cq_del(dev, rq->cq);
 		rq->cq = NULL;
 		/* free up the posted buffers */
-		oce_rq_discharge(dev->rq[0]);
+		oce_rq_discharge(rq);
 	}
 } /* oce_rq_del */
 
@@ -913,9 +945,6 @@
 	eq_db.bits.clrint = clearint;
 	eq_db.bits.qid = qid;
 	OCE_DB_WRITE32(dev, PD_EQ_DB, eq_db.dw0);
-	if (oce_fm_check_acc_handle(dev, dev->db_handle) != DDI_FM_OK) {
-		ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
-	}
 }
 
 /*
@@ -938,9 +967,6 @@
 	cq_db.bits.event = 0;
 	cq_db.bits.qid = qid;
 	OCE_DB_WRITE32(dev, PD_CQ_DB, cq_db.dw0);
-	if (oce_fm_check_acc_handle(dev, dev->db_handle) != DDI_FM_OK) {
-		ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
-	}
 }
 
 
@@ -1106,17 +1132,36 @@
 int
 oce_init_txrx(struct oce_dev  *dev)
 {
-	dev->wq[0] = oce_wq_init(dev, dev->tx_ring_size, NIC_WQ_TYPE_STANDARD);
+	int qid = 0;
+
+	/* enable RSS if rx queues > 1 */
+	dev->rss_enable = (dev->rx_rings > 1) ? B_TRUE : B_FALSE;
 
-	if (dev->wq[0] == NULL) {
+	for (qid = 0; qid < dev->tx_rings; qid++) {
+		dev->wq[qid] = oce_wq_init(dev, dev->tx_ring_size,
+		    NIC_WQ_TYPE_STANDARD);
+		if (dev->wq[qid] == NULL) {
+			goto queue_fail;
+		}
+	}
+
+	/* Now create the Rx Queues */
+	/* qid 0 is always default non rss queue for rss */
+	dev->rq[0] = oce_rq_init(dev, dev->rx_ring_size, dev->rq_frag_size,
+	    OCE_MAX_JUMBO_FRAME_SIZE, B_FALSE);
+	if (dev->rq[0] == NULL) {
 		goto queue_fail;
 	}
 
-	dev->rq[0] = oce_rq_init(dev, dev->rx_ring_size, OCE_RQ_BUF_SIZE,
-	    OCE_RQ_MAX_FRAME_SZ, B_FALSE);
-	if (dev->rq[0] == NULL) {
-		goto queue_fail;
+	for (qid = 1; qid < dev->rx_rings; qid++) {
+		dev->rq[qid] = oce_rq_init(dev, dev->rx_ring_size,
+		    dev->rq_frag_size, OCE_MAX_JUMBO_FRAME_SIZE,
+		    dev->rss_enable);
+		if (dev->rq[qid] == NULL) {
+			goto queue_fail;
+		}
 	}
+
 	return (DDI_SUCCESS);
 queue_fail:
 	oce_fini_txrx(dev);
@@ -1125,16 +1170,26 @@
 void
 oce_fini_txrx(struct oce_dev *dev)
 {
-	if (dev->wq[0] != NULL) {
-		oce_wq_fini(dev, dev->wq[0]);
-		dev->wq[0] = NULL;
+	int qid;
+	int nqs;
+
+	/* free all the tx rings */
+	/* nwqs is decremented in fini so copy count first */
+	nqs = dev->nwqs;
+	for (qid = 0; qid < nqs; qid++) {
+		if (dev->wq[qid] != NULL) {
+			oce_wq_fini(dev, dev->wq[qid]);
+			dev->wq[qid] = NULL;
+		}
 	}
-	if (dev->rq[0] != NULL) {
-		oce_rq_fini(dev, dev->rq[0]);
-		dev->rq[0] = NULL;
+	/* free all the rx rings */
+	nqs = dev->nrqs;
+	for (qid = 0; qid < nqs; qid++) {
+		if (dev->rq[qid] != NULL) {
+			oce_rq_fini(dev, dev->rq[qid]);
+			dev->rq[qid] = NULL;
+		}
 	}
-	return;
-
 }
 
 int
@@ -1152,11 +1207,16 @@
 		}
 		dev->eq[i] = eq;
 	}
-	if (oce_wq_create(dev->wq[0], dev->eq[0]) != 0)
-		goto rings_fail;
-	if (oce_rq_create(dev->rq[0], dev->if_id,
-	    dev->neqs > 1 ? dev->eq[1] : dev->eq[0]) != 0)
-		goto rings_fail;
+	for (i = 0; i < dev->nwqs; i++) {
+		if (oce_wq_create(dev->wq[i], dev->eq[0]) != 0)
+			goto rings_fail;
+	}
+
+	for (i = 0; i < dev->nrqs; i++) {
+		if (oce_rq_create(dev->rq[i], dev->if_id,
+		    dev->neqs > 1 ? dev->eq[1 + i] : dev->eq[0]) != 0)
+			goto rings_fail;
+	}
 	mq = oce_mq_create(dev, dev->eq[0], 64);
 	if (mq == NULL)
 		goto rings_fail;
@@ -1172,6 +1232,7 @@
 oce_delete_queues(struct oce_dev *dev)
 {
 	int i;
+	int neqs = dev->neqs;
 	if (dev->mq != NULL) {
 		oce_mq_del(dev, dev->mq);
 		dev->mq = NULL;
@@ -1183,8 +1244,8 @@
 	for (i = 0; i < dev->nwqs; i++) {
 		oce_wq_del(dev, dev->wq[i]);
 	}
-	/* create as many eqs as the number of vectors */
-	for (i = 0; i < dev->num_vectors; i++) {
+	/* delete as many eqs as the number of vectors */
+	for (i = 0; i < neqs; i++) {
 		oce_eq_del(dev, dev->eq[i]);
 		dev->eq[i] = NULL;
 	}
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_rx.c	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_rx.c	Thu Aug 05 11:14:15 2010 -0600
@@ -31,23 +31,48 @@
 #include <oce_impl.h>
 
 
-static void rx_pool_free(char *arg);
+void oce_rx_pool_free(char *arg);
+static void oce_rqb_dtor(oce_rq_bdesc_t *rqbd);
+static int oce_rqb_ctor(oce_rq_bdesc_t *rqbd, struct oce_rq *rq,
+    size_t size, int flags);
+
 static inline mblk_t *oce_rx(struct oce_dev *dev, struct oce_rq *rq,
     struct oce_nic_rx_cqe *cqe);
 static inline mblk_t *oce_rx_bcopy(struct oce_dev *dev,
 	struct oce_rq *rq, struct oce_nic_rx_cqe *cqe);
-static int oce_rq_charge(struct oce_dev *dev, struct oce_rq *rq,
-    uint32_t nbufs);
-static oce_rq_bdesc_t *oce_rqb_alloc(struct oce_rq *rq);
-static void oce_rqb_free(struct oce_rq *rq, oce_rq_bdesc_t *rqbd);
-static void oce_rqb_dtor(oce_rq_bdesc_t *rqbd);
-static int oce_rqb_ctor(oce_rq_bdesc_t *rqbd, struct oce_rq *rq,
-    size_t size, int flags);
+static int oce_rq_charge(struct oce_rq *rq, uint32_t nbufs, boolean_t repost);
 static void oce_rx_insert_tag(mblk_t *mp, uint16_t vtag);
 static void oce_set_rx_oflags(mblk_t *mp, struct oce_nic_rx_cqe *cqe);
 static inline void oce_rx_drop_pkt(struct oce_rq *rq,
     struct oce_nic_rx_cqe *cqe);
+static oce_rq_bdesc_t *oce_rqb_alloc(struct oce_rq *rq);
+static void oce_rqb_free(struct oce_rq *rq, oce_rq_bdesc_t *rqbd);
+static void oce_rq_post_buffer(struct oce_rq *rq, int nbufs);
 
+#pragma	inline(oce_rx)
+#pragma	inline(oce_rx_bcopy)
+#pragma	inline(oce_rq_charge)
+#pragma	inline(oce_rx_insert_tag)
+#pragma	inline(oce_set_rx_oflags)
+#pragma	inline(oce_rx_drop_pkt)
+#pragma	inline(oce_rqb_alloc)
+#pragma	inline(oce_rqb_free)
+#pragma inline(oce_rq_post_buffer)
+
+static ddi_dma_attr_t oce_rx_buf_attr = {
+	DMA_ATTR_V0,		/* version number */
+	0x0000000000000000ull,	/* low address */
+	0xFFFFFFFFFFFFFFFFull,	/* high address */
+	0x00000000FFFFFFFFull,	/* dma counter max */
+	OCE_DMA_ALIGNMENT,	/* alignment */
+	0x000007FF,		/* burst sizes */
+	0x00000001,		/* minimum transfer size */
+	0x00000000FFFFFFFFull,	/* maximum transfer size */
+	0xFFFFFFFFFFFFFFFFull,	/* maximum segment size */
+	1,			/* scatter/gather list length */
+	0x00000001,		/* granularity */
+	DDI_DMA_FLAGERR|DDI_DMA_RELAXED_ORDERING		/* DMA flags */
+};
 
 /*
  * function to create a DMA buffer pool for RQ
@@ -61,31 +86,25 @@
 int
 oce_rqb_cache_create(struct oce_rq *rq, size_t buf_size)
 {
-	struct oce_dev *dev = rq->parent;
 	int size;
 	int cnt;
 	int ret;
-	int nitems;
+	oce_rq_bdesc_t *rqbd;
 
-	nitems = rq->cfg.nbufs;
-	size = nitems * sizeof (oce_rq_bdesc_t);
-	rq->rq_bdesc_array = kmem_zalloc(size, KM_NOSLEEP);
-	if (rq->rq_bdesc_array == NULL) {
-		return (DDI_FAILURE);
-	}
-
-	/* Create the free buffer list */
-	OCE_LIST_CREATE(&rq->rq_buf_list, DDI_INTR_PRI(dev->intr_pri));
-
-	for (cnt = 0; cnt < nitems; cnt++) {
-		ret = oce_rqb_ctor(&rq->rq_bdesc_array[cnt],
-		    rq, buf_size, DDI_DMA_STREAMING);
+	_NOTE(ARGUNUSED(buf_size));
+	rqbd = rq->rq_bdesc_array;
+	size = rq->cfg.frag_size + OCE_RQE_BUF_HEADROOM;
+	for (cnt = 0; cnt < rq->cfg.nbufs; cnt++, rqbd++) {
+		rq->rqb_freelist[cnt] = rqbd;
+		ret = oce_rqb_ctor(rqbd, rq,
+		    size, (DDI_DMA_RDWR|DDI_DMA_STREAMING));
 		if (ret != DDI_SUCCESS) {
 			goto rqb_fail;
 		}
-		OCE_LIST_INSERT_TAIL(&rq->rq_buf_list,
-		    &(rq->rq_bdesc_array[cnt].link));
 	}
+	rq->rqb_free = rq->cfg.nbufs;
+	rq->rqb_rc_head = 0;
+	rq->rqb_next_free = 0;
 	return (DDI_SUCCESS);
 
 rqb_fail:
@@ -104,14 +123,12 @@
 oce_rqb_cache_destroy(struct oce_rq *rq)
 {
 	oce_rq_bdesc_t *rqbd = NULL;
+	int cnt;
 
-	while ((rqbd = (oce_rq_bdesc_t *)OCE_LIST_REM_HEAD(&rq->rq_buf_list))
-	    != NULL) {
+	rqbd = rq->rq_bdesc_array;
+	for (cnt = 0; cnt < rq->cfg.nbufs; cnt++, rqbd++) {
 		oce_rqb_dtor(rqbd);
 	}
-	kmem_free(rq->rq_bdesc_array,
-	    rq->cfg.nbufs * sizeof (oce_rq_bdesc_t));
-	OCE_LIST_DESTROY(&rq->rq_buf_list);
 } /* oce_rqb_cache_destroy */
 
 /*
@@ -127,12 +144,12 @@
 	if ((rqbd == NULL) || (rqbd->rq == NULL)) {
 		return;
 	}
+	if (rqbd->mp != NULL) {
+		rqbd->fr_rtn.free_arg = NULL;
+		freemsg(rqbd->mp);
+		rqbd->mp = NULL;
+	}
 	oce_free_dma_buffer(rqbd->rq->parent, rqbd->rqb);
-	if (rqbd->mp != NULL) {
-		/* Buffer is already free  */
-		rqbd->fr_rtn.free_arg = NULL;
-		freeb(rqbd->mp);
-	}
 } /* oce_rqb_dtor */
 
 /*
@@ -153,20 +170,24 @@
 
 	dev = rq->parent;
 
-	dbuf  = oce_alloc_dma_buffer(dev, size, flags);
+	dbuf  = oce_alloc_dma_buffer(dev, size, &oce_rx_buf_attr, flags);
 	if (dbuf == NULL) {
 		return (DDI_FAILURE);
 	}
 
-	/* override usable length */
+	/* Set the call back function parameters */
+	rqbd->fr_rtn.free_func = (void (*)())oce_rx_pool_free;
+	rqbd->fr_rtn.free_arg = (caddr_t)(void *)rqbd;
+	rqbd->mp = desballoc((uchar_t *)(dbuf->base),
+	    dbuf->size, 0, &rqbd->fr_rtn);
+	if (rqbd->mp == NULL) {
+		oce_free_dma_buffer(dev, dbuf);
+		return (DDI_FAILURE);
+	}
 	rqbd->rqb = dbuf;
 	rqbd->rq = rq;
 	rqbd->frag_addr.dw.addr_lo = ADDR_LO(dbuf->addr + OCE_RQE_BUF_HEADROOM);
 	rqbd->frag_addr.dw.addr_hi = ADDR_HI(dbuf->addr + OCE_RQE_BUF_HEADROOM);
-	rqbd->fr_rtn.free_func = (void (*)())rx_pool_free;
-	rqbd->fr_rtn.free_arg = (caddr_t)(void *)rqbd;
-	rqbd->mp = desballoc((uchar_t *)(rqbd->rqb->base),
-	    rqbd->rqb->size, 0, &rqbd->fr_rtn);
 	rqbd->mp->b_rptr = (uchar_t *)rqbd->rqb->base + OCE_RQE_BUF_HEADROOM;
 
 	return (DDI_SUCCESS);
@@ -183,7 +204,11 @@
 oce_rqb_alloc(struct oce_rq *rq)
 {
 	oce_rq_bdesc_t *rqbd;
-	rqbd = OCE_LIST_REM_HEAD(&rq->rq_buf_list);
+	uint32_t free_index;
+	free_index = rq->rqb_next_free;
+	rqbd = rq->rqb_freelist[free_index];
+	rq->rqb_freelist[free_index] = NULL;
+	rq->rqb_next_free = GET_Q_NEXT(free_index, 1, rq->cfg.nbufs);
 	return (rqbd);
 } /* oce_rqb_alloc */
 
@@ -198,10 +223,40 @@
 static inline void
 oce_rqb_free(struct oce_rq *rq, oce_rq_bdesc_t *rqbd)
 {
-	OCE_LIST_INSERT_TAIL(&rq->rq_buf_list, rqbd);
+	uint32_t free_index;
+	mutex_enter(&rq->rc_lock);
+	free_index = rq->rqb_rc_head;
+	rq->rqb_freelist[free_index] = rqbd;
+	rq->rqb_rc_head = GET_Q_NEXT(free_index, 1, rq->cfg.nbufs);
+	mutex_exit(&rq->rc_lock);
+	atomic_add_32(&rq->rqb_free, 1);
 } /* oce_rqb_free */
 
 
+
+
+static void oce_rq_post_buffer(struct oce_rq *rq, int nbufs)
+{
+	pd_rxulp_db_t rxdb_reg;
+	int count;
+	struct oce_dev *dev =  rq->parent;
+
+
+	rxdb_reg.dw0 = 0;
+	rxdb_reg.bits.qid = rq->rq_id & DB_RQ_ID_MASK;
+
+	for (count = nbufs/OCE_MAX_RQ_POSTS; count > 0; count--) {
+		rxdb_reg.bits.num_posted = OCE_MAX_RQ_POSTS;
+		OCE_DB_WRITE32(dev, PD_RXULP_DB, rxdb_reg.dw0);
+		rq->buf_avail += OCE_MAX_RQ_POSTS;
+		nbufs -= OCE_MAX_RQ_POSTS;
+	}
+	if (nbufs > 0) {
+		rxdb_reg.bits.num_posted = nbufs;
+		OCE_DB_WRITE32(dev, PD_RXULP_DB, rxdb_reg.dw0);
+		rq->buf_avail += nbufs;
+	}
+}
 /*
  * function to charge a given rq with buffers from a pool's free list
  *
@@ -212,89 +267,38 @@
  * return number of rqe's charges.
  */
 static inline int
-oce_rq_charge(struct oce_dev *dev,
-    struct oce_rq *rq, uint32_t nbufs)
+oce_rq_charge(struct oce_rq *rq, uint32_t nbufs, boolean_t repost)
 {
 	struct oce_nic_rqe *rqe;
 	oce_rq_bdesc_t *rqbd;
-	struct rq_shadow_entry	*shadow_rq;
-	int32_t num_bufs = 0;
-	int32_t total_bufs = 0;
-	pd_rxulp_db_t rxdb_reg;
-	uint32_t cnt;
+	oce_rq_bdesc_t **shadow_rq;
+	int cnt;
+	int cur_index;
+	oce_ring_buffer_t *ring;
 
 	shadow_rq = rq->shadow_ring;
-	/* check number of slots free and recharge */
-	nbufs = ((rq->buf_avail + nbufs) > rq->cfg.q_len) ?
-	    (rq->cfg.q_len - rq->buf_avail) : nbufs;
+	ring = rq->ring;
+	cur_index = ring->cidx;
+
 	for (cnt = 0; cnt < nbufs; cnt++) {
-		rqbd = oce_rqb_alloc(rq);
-		if (rqbd == NULL) {
-			oce_log(dev, CE_NOTE, MOD_RX, "%s %x",
-			    "rqb pool empty @ ticks",
-			    (uint32_t)ddi_get_lbolt());
-			break;
+		if (!repost) {
+			rqbd = oce_rqb_alloc(rq);
+		} else {
+			/* just repost the buffers from shadow ring */
+			rqbd = shadow_rq[cur_index];
+			cur_index = GET_Q_NEXT(cur_index, 1, ring->num_items);
 		}
-		if (rqbd->mp == NULL) {
-			rqbd->mp = desballoc((uchar_t *)(rqbd->rqb->base),
-			    rqbd->rqb->size, 0, &rqbd->fr_rtn);
-			if (rqbd->mp != NULL) {
-				rqbd->mp->b_rptr =
-				    (uchar_t *)rqbd->rqb->base +
-				    OCE_RQE_BUF_HEADROOM;
-			}
-
-			/*
-			 * Failed again put back the buffer and continue
-			 * loops for nbufs so its a finite loop
-			 */
-
-			if (rqbd->mp == NULL) {
-				oce_rqb_free(rq, rqbd);
-				continue;
-			}
-		}
-
 		/* fill the rqes */
 		rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring,
 		    struct oce_nic_rqe);
 		rqe->u0.s.frag_pa_lo = rqbd->frag_addr.dw.addr_lo;
 		rqe->u0.s.frag_pa_hi = rqbd->frag_addr.dw.addr_hi;
-		shadow_rq[rq->ring->pidx].rqbd = rqbd;
+		shadow_rq[rq->ring->pidx] = rqbd;
 		DW_SWAP(u32ptr(rqe), sizeof (struct oce_nic_rqe));
 		RING_PUT(rq->ring, 1);
-
-		/* if we have reached the max allowed posts, post */
-		if (cnt && !(cnt % OCE_MAX_RQ_POSTS)) {
-			rxdb_reg.dw0 = 0;
-			rxdb_reg.bits.num_posted = num_bufs;
-			rxdb_reg.bits.qid = rq->rq_id & DB_RQ_ID_MASK;
-			OCE_DB_WRITE32(dev, PD_RXULP_DB, rxdb_reg.dw0);
-			if (oce_fm_check_acc_handle(dev, dev->db_handle) !=
-			    DDI_FM_OK) {
-				ddi_fm_service_impact(dev->dip,
-				    DDI_SERVICE_DEGRADED);
-			}
-			num_bufs = 0;
-		}
-		num_bufs++;
-		total_bufs++;
 	}
 
-	/* post pending bufs */
-	if (num_bufs) {
-		rxdb_reg.dw0 = 0;
-		rxdb_reg.bits.num_posted = num_bufs;
-		rxdb_reg.bits.qid = rq->rq_id & DB_RQ_ID_MASK;
-		OCE_DB_WRITE32(dev, PD_RXULP_DB, rxdb_reg.dw0);
-		if (oce_fm_check_acc_handle(dev, dev->db_handle) !=
-		    DDI_FM_OK) {
-			ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
-		}
-	}
-	atomic_add_32(&rq->buf_avail, total_bufs);
-
-	return (total_bufs);
+	return (cnt);
 } /* oce_rq_charge */
 
 /*
@@ -308,12 +312,12 @@
 oce_rq_discharge(struct oce_rq *rq)
 {
 	oce_rq_bdesc_t *rqbd;
-	struct rq_shadow_entry *shadow_rq;
+	oce_rq_bdesc_t **shadow_rq;
 
 	shadow_rq = rq->shadow_ring;
 	/* Free the posted buffer since RQ is destroyed already */
 	while ((int32_t)rq->buf_avail > 0) {
-		rqbd = shadow_rq[rq->ring->cidx].rqbd;
+		rqbd = shadow_rq[rq->ring->cidx];
 		oce_rqb_free(rq, rqbd);
 		RING_GET(rq->ring, 1);
 		rq->buf_avail--;
@@ -334,48 +338,60 @@
 	mblk_t *mp;
 	int pkt_len;
 	int32_t frag_cnt = 0;
-	mblk_t *mblk_prev = NULL;
-	mblk_t	*mblk_head = NULL;
+	mblk_t **mblk_tail;
+	mblk_t	*mblk_head;
 	int frag_size;
-	struct rq_shadow_entry *shadow_rq;
-	struct rq_shadow_entry *shadow_rqe;
 	oce_rq_bdesc_t *rqbd;
+	uint16_t cur_index;
+	oce_ring_buffer_t *ring;
+	int i;
+
+	frag_cnt  = cqe->u0.s.num_fragments & 0x7;
+	mblk_head = NULL;
+	mblk_tail = &mblk_head;
+
+	ring = rq->ring;
+	cur_index = ring->cidx;
 
 	/* Get the relevant Queue pointers */
-	shadow_rq = rq->shadow_ring;
 	pkt_len = cqe->u0.s.pkt_size;
-	for (; frag_cnt < cqe->u0.s.num_fragments; frag_cnt++) {
-		shadow_rqe = &shadow_rq[rq->ring->cidx];
-		rqbd = shadow_rqe->rqbd;
+	for (i = 0; i < frag_cnt; i++) {
+		rqbd = rq->shadow_ring[cur_index];
+		if (rqbd->mp == NULL) {
+			rqbd->mp = desballoc((uchar_t *)rqbd->rqb->base,
+			    rqbd->rqb->size, 0, &rqbd->fr_rtn);
+			if (rqbd->mp == NULL) {
+				return (NULL);
+			}
+
+			rqbd->mp->b_rptr =
+			    (uchar_t *)rqbd->rqb->base + OCE_RQE_BUF_HEADROOM;
+		}
+
 		mp = rqbd->mp;
-		if (mp == NULL)
-			return (NULL);
 		frag_size  = (pkt_len > rq->cfg.frag_size) ?
 		    rq->cfg.frag_size : pkt_len;
 		mp->b_wptr = mp->b_rptr + frag_size;
 		pkt_len   -= frag_size;
+		mp->b_next = mp->b_cont = NULL;
 		/* Chain the message mblks */
-		if (mblk_head == NULL) {
-			mblk_head = mblk_prev = mp;
-		} else {
-			mblk_prev->b_cont = mp;
-			mblk_prev = mp;
-		}
-		(void) ddi_dma_sync(rqbd->rqb->dma_handle, 0, frag_size,
-		    DDI_DMA_SYNC_FORKERNEL);
-		RING_GET(rq->ring, 1);
+		*mblk_tail = mp;
+		mblk_tail = &mp->b_cont;
+		(void) DBUF_SYNC(rqbd->rqb, DDI_DMA_SYNC_FORCPU);
+		cur_index = GET_Q_NEXT(cur_index, 1, ring->num_items);
 	}
 
 	if (mblk_head == NULL) {
 		oce_log(dev, CE_WARN, MOD_RX, "%s", "oce_rx:no frags?");
 		return (NULL);
 	}
-	atomic_add_32(&rq->pending, (cqe->u0.s.num_fragments & 0x7));
-	mblk_head->b_next = NULL;
+
+	/* replace the buffer with new ones */
+	(void) oce_rq_charge(rq, frag_cnt, B_FALSE);
+	atomic_add_32(&rq->pending, frag_cnt);
 	return (mblk_head);
 } /* oce_rx */
 
-/* ARGSUSED */
 static inline mblk_t *
 oce_rx_bcopy(struct oce_dev *dev, struct oce_rq *rq, struct oce_nic_rx_cqe *cqe)
 {
@@ -384,45 +400,42 @@
 	int alloc_len;
 	int32_t frag_cnt = 0;
 	int frag_size;
-	struct rq_shadow_entry *shadow_rq;
-	struct rq_shadow_entry *shadow_rqe;
 	oce_rq_bdesc_t *rqbd;
-	boolean_t tag_present =  B_FALSE;
 	unsigned char  *rptr;
+	uint32_t cur_index;
+	oce_ring_buffer_t *ring;
+	oce_rq_bdesc_t **shadow_rq;
+	int cnt = 0;
+
+	_NOTE(ARGUNUSED(dev));
 
 	shadow_rq = rq->shadow_ring;
 	pkt_len = cqe->u0.s.pkt_size;
-	alloc_len = pkt_len;
+	alloc_len = pkt_len + OCE_RQE_BUF_HEADROOM;
+	frag_cnt = cqe->u0.s.num_fragments & 0x7;
 
-	/* Hardware always Strips Vlan tag so insert it back */
-	if (cqe->u0.s.vlan_tag_present) {
-		alloc_len += VLAN_TAGSZ;
-		tag_present = B_TRUE;
-	}
 	mp = allocb(alloc_len, BPRI_HI);
-	if (mp == NULL)
+	if (mp == NULL) {
 		return (NULL);
-	if (tag_present) {
-		/* offset the read pointer by 4 bytes to insert tag */
-		mp->b_rptr += VLAN_TAGSZ;
 	}
+
+	mp->b_rptr += OCE_RQE_BUF_HEADROOM;
 	rptr = mp->b_rptr;
-	mp->b_wptr = mp->b_wptr + alloc_len;
+	mp->b_wptr = mp->b_rptr + pkt_len;
+	ring = rq->ring;
 
-	for (frag_cnt = 0; frag_cnt < cqe->u0.s.num_fragments; frag_cnt++) {
-		shadow_rqe = &shadow_rq[rq->ring->cidx];
-		rqbd = shadow_rqe->rqbd;
+	cur_index = ring->cidx;
+	for (cnt = 0; cnt < frag_cnt; cnt++) {
+		rqbd = shadow_rq[cur_index];
 		frag_size  = (pkt_len > rq->cfg.frag_size) ?
 		    rq->cfg.frag_size : pkt_len;
-		(void) ddi_dma_sync(rqbd->rqb->dma_handle, 0, frag_size,
-		    DDI_DMA_SYNC_FORKERNEL);
-		bcopy(rqbd->rqb->base + OCE_RQE_BUF_HEADROOM,
-		    rptr, frag_size);
+		(void) DBUF_SYNC(rqbd->rqb, DDI_DMA_SYNC_FORCPU);
+		bcopy(rqbd->rqb->base + OCE_RQE_BUF_HEADROOM, rptr, frag_size);
 		rptr += frag_size;
 		pkt_len   -= frag_size;
-		oce_rqb_free(rq, rqbd);
-		RING_GET(rq->ring, 1);
+		cur_index = GET_Q_NEXT(cur_index, 1, ring->num_items);
 	}
+	(void) oce_rq_charge(rq, frag_cnt, B_TRUE);
 	return (mp);
 }
 
@@ -458,6 +471,19 @@
 	ehp->ether_tci = LE_16(vtag);
 }
 
+static inline void
+oce_rx_drop_pkt(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe)
+{
+	int frag_cnt;
+	oce_rq_bdesc_t *rqbd;
+	oce_rq_bdesc_t  **shadow_rq;
+	shadow_rq = rq->shadow_ring;
+	for (frag_cnt = 0; frag_cnt < cqe->u0.s.num_fragments; frag_cnt++) {
+		rqbd = shadow_rq[rq->ring->cidx];
+		oce_rqb_free(rq, rqbd);
+		RING_GET(rq->ring, 1);
+	}
+}
 
 
 /*
@@ -473,56 +499,65 @@
 	struct oce_nic_rx_cqe *cqe;
 	struct oce_rq *rq;
 	mblk_t *mp = NULL;
-	mblk_t *mblk_head  = NULL;
-	mblk_t *mblk_prev  = NULL;
+	mblk_t *mblk_head;
+	mblk_t **mblk_tail;
 	uint16_t num_cqe = 0;
 	struct oce_cq  *cq;
 	struct oce_dev *dev;
-
-	if (arg == NULL)
-		return (0);
+	int32_t frag_cnt;
+	uint32_t nbufs = 0;
 
 	rq = (struct oce_rq *)arg;
 	dev = rq->parent;
 	cq = rq->cq;
-	mutex_enter(&rq->rx_lock);
+	mblk_head = NULL;
+	mblk_tail = &mblk_head;
+
 	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
 
+	(void) DBUF_SYNC(cq->ring->dbuf, DDI_DMA_SYNC_FORKERNEL);
 	/* dequeue till you reach an invalid cqe */
-	while (RQ_CQE_VALID(cqe) && (num_cqe < rq->cfg.q_len)) {
+	while (RQ_CQE_VALID(cqe)) {
 		DW_SWAP(u32ptr(cqe), sizeof (struct oce_nic_rx_cqe));
+		frag_cnt = cqe->u0.s.num_fragments & 0x7;
 		/* if insufficient buffers to charge then do copy */
-		if (cqe->u0.s.pkt_size < dev->rx_bcopy_limit ||
-		    OCE_LIST_SIZE(&rq->rq_buf_list) < cqe->u0.s.num_fragments) {
+		if ((cqe->u0.s.pkt_size < dev->rx_bcopy_limit) ||
+		    (oce_atomic_reserve(&rq->rqb_free, frag_cnt) < 0)) {
 			mp = oce_rx_bcopy(dev, rq, cqe);
 		} else {
 			mp = oce_rx(dev, rq, cqe);
+			if (mp == NULL) {
+				atomic_add_32(&rq->rqb_free, frag_cnt);
+				mp = oce_rx_bcopy(dev, rq, cqe);
+			}
 		}
 		if (mp != NULL) {
 			if (cqe->u0.s.vlan_tag_present) {
 				oce_rx_insert_tag(mp, cqe->u0.s.vlan_tag);
 			}
 			oce_set_rx_oflags(mp, cqe);
-			if (mblk_head == NULL) {
-				mblk_head = mblk_prev  = mp;
-			} else {
-				mblk_prev->b_next = mp;
-				mblk_prev = mp;
-			}
 
+			*mblk_tail = mp;
+			mblk_tail = &mp->b_next;
 		} else {
-			oce_rx_drop_pkt(rq, cqe);
+			(void) oce_rq_charge(rq, frag_cnt, B_TRUE);
 		}
-		atomic_add_32(&rq->buf_avail, -(cqe->u0.s.num_fragments & 0x7));
-		(void) oce_rq_charge(dev, rq,
-		    (cqe->u0.s.num_fragments & 0x7));
+		RING_GET(rq->ring, frag_cnt);
+		rq->buf_avail -= frag_cnt;
+		nbufs += frag_cnt;
+
+		oce_rq_post_buffer(rq, frag_cnt);
 		RQ_CQE_INVALIDATE(cqe);
 		RING_GET(cq->ring, 1);
 		cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring,
 		    struct oce_nic_rx_cqe);
 		num_cqe++;
+		/* process max ring size */
+		if (num_cqe > dev->rx_pkt_per_intr) {
+			break;
+		}
 	} /* for all valid CQEs */
-	mutex_exit(&rq->rx_lock);
+
 	if (mblk_head) {
 		mac_rx(dev->mac_handle, NULL, mblk_head);
 	}
@@ -537,8 +572,8 @@
  *
  * return none
  */
-static void
-rx_pool_free(char *arg)
+void
+oce_rx_pool_free(char *arg)
 {
 	oce_rq_bdesc_t *rqbd;
 	struct oce_rq  *rq;
@@ -551,13 +586,14 @@
 	/* retrieve the pointers from arg */
 	rqbd = (oce_rq_bdesc_t *)(void *)arg;
 	rq = rqbd->rq;
-
-	rqbd->mp = desballoc((uchar_t *)(rqbd->rqb->base),
+	rqbd->mp = desballoc((uchar_t *)rqbd->rqb->base,
 	    rqbd->rqb->size, 0, &rqbd->fr_rtn);
-	if (rqbd->mp != NULL) {
-		rqbd->mp->b_rptr = (uchar_t *)rqbd->rqb->base +
-		    OCE_RQE_BUF_HEADROOM;
+
+	if (rqbd->mp) {
+		rqbd->mp->b_rptr =
+		    (uchar_t *)rqbd->rqb->base + OCE_RQE_BUF_HEADROOM;
 	}
+
 	oce_rqb_free(rq, rqbd);
 	(void) atomic_add_32(&rq->pending, -1);
 } /* rx_pool_free */
@@ -598,14 +634,6 @@
 		}
 		OCE_MSDELAY(1);
 	}
-#if 0
-	if (num_cqe) {
-		oce_arm_cq(dev, cq->cq_id, num_cqe, B_FALSE);
-	}
-	/* Drain the Event queue now */
-	oce_drain_eq(rq->cq->eq);
-	return (num_cqe);
-#endif
 } /* oce_clean_rq */
 
 /*
@@ -619,41 +647,33 @@
 oce_start_rq(struct oce_rq *rq)
 {
 	int ret = 0;
+	int to_charge = 0;
 	struct oce_dev *dev = rq->parent;
-
-	(void) oce_rq_charge(dev, rq, rq->cfg.q_len);
+	to_charge = rq->cfg.q_len - rq->buf_avail;
+	to_charge = min(to_charge, rq->rqb_free);
+	atomic_add_32(&rq->rqb_free, -to_charge);
+	(void) oce_rq_charge(rq, to_charge, B_FALSE);
+	/* ok to do it here since Rx has not even started */
+	oce_rq_post_buffer(rq, to_charge);
 	oce_arm_cq(dev, rq->cq->cq_id, 0, B_TRUE);
 	return (ret);
 } /* oce_start_rq */
 
 /* Checks for pending rx buffers with Stack */
 int
-oce_rx_pending(struct oce_dev *dev)
+oce_rx_pending(struct oce_dev *dev, struct oce_rq *rq, int32_t timeout)
 {
 	int ti;
+	_NOTE(ARGUNUSED(dev));
 
-	for (ti = 0; ti < 200; ti++) {
-		if (dev->rq[0]->pending > 0) {
-			OCE_MSDELAY(1);
+	for (ti = 0; ti < timeout; ti++) {
+		if (rq->pending > 0) {
+			OCE_MSDELAY(10);
 			continue;
 		} else {
-			dev->rq[0]->pending = 0;
+			rq->pending = 0;
 			break;
 		}
 	}
-	return (dev->rq[0]->pending);
+	return (rq->pending);
 }
-
-static inline void
-oce_rx_drop_pkt(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe)
-{
-	int frag_cnt;
-	oce_rq_bdesc_t *rqbd;
-	struct rq_shadow_entry *shadow_rq;
-	shadow_rq = rq->shadow_ring;
-	for (frag_cnt = 0; frag_cnt < cqe->u0.s.num_fragments; frag_cnt++) {
-		rqbd = shadow_rq[rq->ring->cidx].rqbd;
-		oce_rqb_free(rq, rqbd);
-		RING_GET(rq->ring, 1);
-	}
-}
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_stat.c	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_stat.c	Thu Aug 05 11:14:15 2010 -0600
@@ -33,6 +33,14 @@
 #include <oce_stat.h>
 #include <oce_buf.h>
 
+int pow10[5] = {
+	0,
+	10,
+	100,
+	1000,
+	10000
+};
+
 /*
  * function called by kstat to update the stats counters
  *
@@ -176,7 +184,7 @@
 	/* allocate the device copy of the stats */
 	dev->stats_dbuf = oce_alloc_dma_buffer(dev,
 	    sizeof (struct mbx_get_nic_stats),
-	    DDI_DMA_CONSISTENT);
+	    NULL, DDI_DMA_CONSISTENT);
 	if (dev->stats_dbuf == NULL) {
 		oce_log(dev, CE_NOTE, MOD_CONFIG,
 		    "Could not allocate stats_dbuf: %p",
@@ -294,11 +302,16 @@
 	}
 
 	switch (stat) {
-	case MAC_STAT_IFSPEED:
-		if (dev->state & STATE_MAC_STARTED)
-			*val = 10000000000ull;
-		else
-			*val = 0;
+	case MAC_STAT_IFSPEED: {
+		struct link_status link = {0};
+		if (dev->link_speed < 0) {
+			(void) oce_get_link_status(dev, &link);
+			dev->link_speed = link.qos_link_speed ?
+			    link.qos_link_speed * 10 :
+			    pow10[link.mac_speed];
+		}
+		*val = dev->link_speed * 1000000ull;
+	}
 	break;
 
 	case MAC_STAT_RBYTES:
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_tx.c	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_tx.c	Thu Aug 05 11:14:15 2010 -0600
@@ -33,18 +33,18 @@
 
 static void oce_free_wqed(struct oce_wq *wq,  oce_wqe_desc_t *wqed);
 static int oce_map_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed,
-    mblk_t *mp);
+    mblk_t *mp, uint32_t pkt_len);
 static int oce_bcopy_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed, mblk_t *mp,
     uint32_t pkt_len);
 static void oce_wqb_dtor(struct oce_wq *wq, oce_wq_bdesc_t *wqbd);
 static int oce_wqb_ctor(oce_wq_bdesc_t *wqbd, struct oce_wq *wq,
     size_t size, int flags);
-static oce_wq_bdesc_t *oce_wqb_alloc(struct oce_wq *wq);
+static inline oce_wq_bdesc_t *oce_wqb_alloc(struct oce_wq *wq);
 static void oce_wqb_free(struct oce_wq *wq, oce_wq_bdesc_t *wqbd);
 
-static void oce_wqmd_free(struct oce_wq *wq, oce_wqe_desc_t *wqed);
+static void oce_wqmd_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd);
 static void oce_wqm_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd);
-static inline oce_wq_mdesc_t *oce_wqm_alloc(struct oce_wq *wq);
+static oce_wq_mdesc_t *oce_wqm_alloc(struct oce_wq *wq);
 static int oce_wqm_ctor(oce_wq_mdesc_t *wqmd, struct oce_wq *wq);
 static void oce_wqm_dtor(struct oce_wq *wq, oce_wq_mdesc_t *wqmd);
 static void oce_fill_ring_descs(struct oce_wq *wq, oce_wqe_desc_t *wqed);
@@ -54,7 +54,7 @@
 
 
 static ddi_dma_attr_t tx_map_dma_attr = {
-	DMA_ATTR_V0,			/* version number */
+	DMA_ATTR_V0,		/* version number */
 	0x0000000000000000ull,	/* low address */
 	0xFFFFFFFFFFFFFFFFull,	/* high address */
 	0x0000000000010000ull,	/* dma counter max */
@@ -65,7 +65,23 @@
 	0xFFFFFFFFFFFFFFFFull,	/* maximum segment size */
 	OCE_MAX_TXDMA_COOKIES,	/* scatter/gather list length */
 	0x00000001,		/* granularity */
-	0			/* DMA flags */
+	DDI_DMA_FLAGERR		/* dma_attr_flags */
+};
+
+
+ddi_dma_attr_t oce_tx_dma_buf_attr = {
+	DMA_ATTR_V0,		/* version number */
+	0x0000000000000000ull,	/* low address */
+	0xFFFFFFFFFFFFFFFFull,	/* high address */
+	0x00000000FFFFFFFFull,	/* dma counter max */
+	OCE_DMA_ALIGNMENT,	/* alignment */
+	0x000007FF,		/* burst sizes */
+	0x00000001,		/* minimum transfer size */
+	0x00000000FFFFFFFFull,	/* maximum transfer size */
+	0xFFFFFFFFFFFFFFFFull,	/* maximum segment size */
+	1,			/* scatter/gather list length */
+	0x00000001,		/* granularity */
+	DDI_DMA_FLAGERR		/* dma_attr_flags */
 };
 
 /*
@@ -245,7 +261,9 @@
 {
 	struct oce_dev *dev;
 	dev = wq->parent;
-	wqbd->wqb = oce_alloc_dma_buffer(dev, size, flags);
+
+	wqbd->wqb = oce_alloc_dma_buffer(dev, size, &oce_tx_dma_buf_attr,
+	    flags);
 	if (wqbd->wqb == NULL) {
 		return (DDI_FAILURE);
 	}
@@ -278,9 +296,7 @@
 static inline oce_wq_bdesc_t *
 oce_wqb_alloc(struct oce_wq *wq)
 {
-	oce_wq_bdesc_t *wqbd;
-	wqbd = OCE_LIST_REM_HEAD(&wq->wq_buf_list);
-	return (wqbd);
+	return (OCE_LIST_REM_HEAD(&wq->wq_buf_list));
 }
 
 /*
@@ -307,10 +323,7 @@
 static inline oce_wq_mdesc_t *
 oce_wqm_alloc(struct oce_wq *wq)
 {
-	oce_wq_mdesc_t *wqmd;
-	wqmd = OCE_LIST_REM_HEAD(&wq->wq_mdesc_list);
-	return (wqmd);
-
+	return (OCE_LIST_REM_HEAD(&wq->wq_mdesc_list));
 } /* oce_wqm_alloc */
 
 /*
@@ -336,19 +349,13 @@
  * return none
  */
 static void
-oce_wqmd_free(struct oce_wq *wq, oce_wqe_desc_t *wqed)
+oce_wqmd_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd)
 {
-	int ndesc;
-	oce_wq_mdesc_t *wqmd;
-
-	if (wqed == NULL) {
+	if (wqmd == NULL) {
 		return;
 	}
-	for (ndesc = 0; ndesc < wqed->nhdl; ndesc++) {
-		wqmd = wqed->hdesc[ndesc].hdl;
-		(void) ddi_dma_unbind_handle(wqmd->dma_handle);
-		oce_wqm_free(wq, wqmd);
-	}
+	(void) ddi_dma_unbind_handle(wqmd->dma_handle);
+	oce_wqm_free(wq, wqmd);
 }
 
 /*
@@ -361,12 +368,10 @@
 int
 oce_wqe_desc_ctor(void *buf, void *arg, int kmflags)
 {
-	oce_wqe_desc_t *wqed = (oce_wqe_desc_t *)buf;
-
+	_NOTE(ARGUNUSED(buf));
 	_NOTE(ARGUNUSED(arg));
 	_NOTE(ARGUNUSED(kmflags));
 
-	bzero(wqed, sizeof (oce_wqe_desc_t));
 	return (DDI_SUCCESS);
 }
 
@@ -388,16 +393,26 @@
  * function to choose a WQ given a mblk depending on priority, flowID etc.
  *
  * dev - software handle to device
- * pkt - the mblk to send
+ * mp - the mblk to send
  *
  * return pointer to the WQ selected
  */
+static uint8_t oce_tx_hash_policy = 0x4;
 struct oce_wq *
-oce_get_wq(struct oce_dev *dev, mblk_t *pkt)
+oce_get_wq(struct oce_dev *dev, mblk_t *mp)
 {
-	_NOTE(ARGUNUSED(pkt));
+	struct oce_wq *wq;
+	int qidx = 0;
+	if (dev->nwqs > 1) {
+		qidx = mac_pkt_hash(DL_ETHER, mp, oce_tx_hash_policy, B_TRUE);
+		qidx = qidx % dev->nwqs;
+
+	} else {
+		qidx = 0;
+	}
+	wq = dev->wq[qidx];
 	/* for the time being hardcode */
-	return (dev->wq[0]);
+	return (wq);
 } /* oce_get_wq */
 
 /*
@@ -442,6 +457,7 @@
 	oce_wq_bdesc_t *wqbd;
 	caddr_t buf_va;
 	struct oce_dev *dev = wq->parent;
+	int len = 0;
 
 	wqbd = oce_wqb_alloc(wq);
 	if (wqbd == NULL) {
@@ -452,19 +468,17 @@
 	}
 
 	/* create a fragment wqe for the packet */
-	wqed->frag[1].u0.s.frag_pa_hi = wqbd->frag_addr.dw.addr_hi;
-	wqed->frag[1].u0.s.frag_pa_lo = wqbd->frag_addr.dw.addr_lo;
+	wqed->frag[wqed->frag_idx].u0.s.frag_pa_hi = wqbd->frag_addr.dw.addr_hi;
+	wqed->frag[wqed->frag_idx].u0.s.frag_pa_lo = wqbd->frag_addr.dw.addr_lo;
 	buf_va = DBUF_VA(wqbd->wqb);
 
 	/* copy pkt into buffer */
-	for (; mp != NULL; mp = mp->b_cont) {
+	for (len = 0; mp != NULL && len < pkt_len; mp = mp->b_cont) {
 		bcopy(mp->b_rptr, buf_va, MBLKL(mp));
 		buf_va += MBLKL(mp);
+		len += MBLKL(mp);
 	}
 
-	wqed->frag[1].u0.s.frag_len   =  pkt_len;
-	wqed->hdesc[0].hdl = (void *)(wqbd);
-
 	(void) ddi_dma_sync(DBUF_DHDL(wqbd->wqb), 0, pkt_len,
 	    DDI_DMA_SYNC_FORDEV);
 
@@ -474,9 +488,12 @@
 		oce_wqb_free(wq, wqbd);
 		return (EIO);
 	}
-	wqed->frag_cnt = 2;
-	wqed->nhdl = 1;
-	wqed->type = COPY_WQE;
+	wqed->frag[wqed->frag_idx].u0.s.frag_len   =  pkt_len;
+	wqed->hdesc[wqed->nhdl].hdl = (void *)(wqbd);
+	wqed->hdesc[wqed->nhdl].type = COPY_WQE;
+	wqed->frag_cnt++;
+	wqed->frag_idx++;
+	wqed->nhdl++;
 	return (0);
 } /* oce_bcopy_wqe */
 
@@ -490,75 +507,52 @@
  * return DDI_SUCCESS=>success, DDI_FAILURE=>error
  */
 static  int
-oce_map_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed, mblk_t *mp)
+oce_map_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed, mblk_t *mp,
+    uint32_t pkt_len)
 {
 	ddi_dma_cookie_t cookie;
 	oce_wq_mdesc_t *wqmd;
-	int32_t nfrag = 1;
 	uint32_t ncookies;
 	int ret;
-	uint32_t len;
 	struct oce_dev *dev = wq->parent;
 
-	wqed->nhdl = 0;
-	wqed->mp = mp;
-
-	for (; mp != NULL; mp = mp->b_cont) {
-		len = MBLKL(mp);
-		if (len == 0) {
-			oce_log(dev, CE_NOTE, MOD_TX, "%s",
-			    "Zero len MBLK ");
-			continue;
-		}
-
-		wqmd = oce_wqm_alloc(wq);
-		if (wqmd == NULL) {
-			oce_log(dev, CE_WARN, MOD_TX, "%s",
-			    "wqm pool empty");
-			ret = ENOMEM;
-			goto map_fail;
-		}
+	wqmd = oce_wqm_alloc(wq);
+	if (wqmd == NULL) {
+		oce_log(dev, CE_WARN, MOD_TX, "%s",
+		    "wqm pool empty");
+		return (ENOMEM);
+	}
 
-		ret = ddi_dma_addr_bind_handle(wqmd->dma_handle,
-		    (struct as *)0, (caddr_t)mp->b_rptr,
-		    len, DDI_DMA_WRITE | DDI_DMA_STREAMING,
-		    DDI_DMA_DONTWAIT, NULL, &cookie, &ncookies);
-		if (ret != DDI_DMA_MAPPED) {
-			oce_log(dev, CE_WARN, MOD_TX, "%s",
-			    "Failed to Map SGL");
-			/* free the last one */
-			oce_wqm_free(wq, wqmd);
-			goto map_fail;
-		}
+	ret = ddi_dma_addr_bind_handle(wqmd->dma_handle,
+	    (struct as *)0, (caddr_t)mp->b_rptr,
+	    pkt_len, DDI_DMA_WRITE | DDI_DMA_STREAMING,
+	    DDI_DMA_DONTWAIT, NULL, &cookie, &ncookies);
+	if (ret != DDI_DMA_MAPPED) {
+		oce_log(dev, CE_WARN, MOD_TX, "MAP FAILED %d",
+		    ret);
+		/* free the last one */
+		oce_wqm_free(wq, wqmd);
+		return (ENOMEM);
+	}
+	do {
+		wqed->frag[wqed->frag_idx].u0.s.frag_pa_hi =
+		    ADDR_HI(cookie.dmac_laddress);
+		wqed->frag[wqed->frag_idx].u0.s.frag_pa_lo =
+		    ADDR_LO(cookie.dmac_laddress);
+		wqed->frag[wqed->frag_idx].u0.s.frag_len =
+		    (uint32_t)cookie.dmac_size;
+		wqed->frag_cnt++;
+		wqed->frag_idx++;
+		if (--ncookies > 0)
+			ddi_dma_nextcookie(wqmd->dma_handle,
+			    &cookie);
+			else break;
+	} while (ncookies > 0);
 
-		do {
-			wqed->frag[nfrag].u0.s.frag_pa_hi =
-			    ADDR_HI(cookie.dmac_laddress);
-			wqed->frag[nfrag].u0.s.frag_pa_lo =
-			    ADDR_LO(cookie.dmac_laddress);
-			wqed->frag[nfrag].u0.s.frag_len =
-			    (uint32_t)cookie.dmac_size;
-			nfrag++;
-			if (--ncookies > 0)
-				ddi_dma_nextcookie(wqmd->dma_handle,
-				    &cookie);
-			else break;
-		} while (ncookies > 0);
-
-		wqed->hdesc[wqed->nhdl].hdl = (void *)wqmd;
-		wqed->nhdl++;
-
-		(void) ddi_dma_sync(wqmd->dma_handle,
-		    0, 0, DDI_DMA_SYNC_FORDEV);
-	}
-	wqed->frag_cnt = nfrag;
-	wqed->type = MAPPED_WQE;
+	wqed->hdesc[wqed->nhdl].hdl = (void *)wqmd;
+	wqed->hdesc[wqed->nhdl].type = MAPPED_WQE;
+	wqed->nhdl++;
 	return (0);
-
-map_fail:
-	wqed->mp = NULL;
-	oce_wqmd_free(wq, wqed);
-	return (ret);
 } /* oce_map_wqe */
 
 static inline int
@@ -703,14 +697,15 @@
 	uint32_t pkt_len = 0;
 	int num_mblks = 0;
 	int ret = 0;
+	uint32_t mss = 0;
 	uint32_t flags = 0;
-	uint32_t mss = 0;
+	int len = 0;
 
 	/* retrieve the adap priv struct ptr */
 	dev = wq->parent;
 
 	/* check if we have enough free slots */
-	if (wq->wq_free < wq->cfg.q_len/2) {
+	if (wq->wq_free < dev->tx_reclaim_threshold) {
 		(void) oce_process_tx_compl(wq, B_FALSE);
 	}
 	if (wq->wq_free < OCE_MAX_TX_HDL) {
@@ -723,28 +718,28 @@
 		num_mblks++;
 	}
 
-	/* Retrieve LSO info */
+	if (pkt_len == 0 || num_mblks == 0) {
+		freemsg(mp);
+		return (NULL);
+	}
+
+	/* retrieve LSO information */
 	mac_lso_get(mp, &mss, &flags);
 
 	/* get the offload flags */
 	mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &csum_flags);
 
-	/* Limit should be always less than Tx Buffer Size */
-	if (pkt_len < dev->tx_bcopy_limit) {
-		use_copy = B_TRUE;
-	} else {
-		/* restrict the mapped segment to wat we support */
-		if (num_mblks  > OCE_MAX_TX_HDL) {
-			nmp = msgpullup(mp, -1);
-			if (nmp == NULL) {
-				atomic_inc_32(&wq->pkt_drops);
-				freemsg(mp);
-				return (NULL);
-			}
-			/* Reset it to new collapsed mp */
+	/* restrict the mapped segment to wat we support */
+	if (num_mblks  > OCE_MAX_TX_HDL) {
+		nmp = msgpullup(mp, -1);
+		if (nmp == NULL) {
+			atomic_inc_32(&wq->pkt_drops);
 			freemsg(mp);
-			mp = nmp;
+			return (NULL);
 		}
+		/* Reset it to new collapsed mp */
+		freemsg(mp);
+		mp = nmp;
 	}
 
 	/* Get the packet descriptor for Tx */
@@ -767,14 +762,34 @@
 		etype = ntohs(eh->ether_type);
 		ip_offset = sizeof (struct ether_header);
 	}
-	bzero(wqed, sizeof (oce_wqe_desc_t));
 
 	/* Save the WQ pointer */
 	wqed->wq = wq;
-	if (use_copy == B_TRUE) {
+	wqed->frag_idx = 1; /* index zero is always header */
+	wqed->frag_cnt = 0;
+	wqed->nhdl = 0;
+	wqed->mp = NULL;
+	OCE_LIST_LINK_INIT(&wqed->link);
+
+	/* If entire packet is less than the copy limit  just do copy */
+	if (pkt_len < dev->tx_bcopy_limit) {
+		use_copy = B_TRUE;
 		ret = oce_bcopy_wqe(wq, wqed, mp, pkt_len);
 	} else {
-		ret = oce_map_wqe(wq, wqed, mp);
+		/* copy or dma map the individual fragments */
+		for (nmp = mp; nmp != NULL; nmp = nmp->b_cont) {
+			len = MBLKL(nmp);
+			if (len == 0) {
+				continue;
+			}
+			if (len < dev->tx_bcopy_limit) {
+				ret = oce_bcopy_wqe(wq, wqed, nmp, len);
+			} else {
+				ret = oce_map_wqe(wq, wqed, nmp, len);
+			}
+			if (ret != 0)
+				break;
+		}
 	}
 
 	/*
@@ -782,15 +797,14 @@
 	 * drop the packet
 	 */
 	if (ret != 0) {
-		kmem_cache_free(wq->wqed_cache, wqed);
-		/* drop the packet */
+		oce_free_wqed(wq, wqed);
 		atomic_inc_32(&wq->pkt_drops);
 		freemsg(mp);
 		return (NULL);
 	}
 
-	/* increment pending wqed to be scheduled */
 	wqeh = (struct oce_nic_hdr_wqe *)&wqed->frag[0];
+	bzero(wqeh, sizeof (struct oce_nic_hdr_wqe));
 
 	/* fill rest of wqe header fields based on packet */
 	if (flags & HW_LSO) {
@@ -823,12 +837,13 @@
 	wqeh->u0.s.crc = B_TRUE;
 	wqeh->u0.s.total_length = pkt_len;
 
-	/* frag count +  header wqe */
-	num_wqes = wqed->frag_cnt;
+	num_wqes = wqed->frag_cnt + 1;
 
 	/* h/w expects even no. of WQEs */
-	if (num_wqes & 0x1)
+	if (num_wqes & 0x1) {
+		bzero(&wqed->frag[num_wqes], sizeof (struct oce_nic_frag_wqe));
 		num_wqes++;
+	}
 	wqed->wqe_cnt = (uint16_t)num_wqes;
 	wqeh->u0.s.num_wqe = num_wqes;
 	DW_SWAP(u32ptr(&wqed->frag[0]), (wqed->wqe_cnt * NIC_WQE_SIZE));
@@ -840,7 +855,6 @@
 		goto wqe_fail;
 	}
 	atomic_add_32(&wq->wq_free, -num_wqes);
-	wqed->wq_start_idx = wq->ring->pidx;
 
 	/* fill the wq for adapter */
 	oce_fill_ring_descs(wq, wqed);
@@ -854,15 +868,16 @@
 	reg_value = (num_wqes << 16) | wq->wq_id;
 	/* Ring the door bell  */
 	OCE_DB_WRITE32(dev, PD_TXULP_DB, reg_value);
+	mutex_exit(&wq->tx_lock);
 	if (oce_fm_check_acc_handle(dev, dev->db_handle) != DDI_FM_OK) {
 		ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
 	}
-	mutex_exit(&wq->tx_lock);
 
 	/* free mp if copied or packet chain collapsed */
 	if (use_copy == B_TRUE) {
 		freemsg(mp);
-	}
+	} else
+		wqed->mp = mp;
 	return (NULL);
 
 wqe_fail:
@@ -870,9 +885,6 @@
 	if (tagged) {
 		oce_insert_vtag(mp, vlan_tag);
 	}
-
-	/* set it to null in case map_wqe has set it */
-	wqed->mp = NULL;
 	oce_free_wqed(wq, wqed);
 	return (mp);
 } /* oce_send_packet */
@@ -889,16 +901,18 @@
 static void
 oce_free_wqed(struct oce_wq *wq, oce_wqe_desc_t *wqed)
 {
+	int i = 0;
 	if (wqed == NULL) {
 		return;
 	}
 
-	if (wqed->type == COPY_WQE) {
-		oce_wqb_free(wq, wqed->hdesc[0].hdl);
-	} else if (wqed->type == MAPPED_WQE) {
-		oce_wqmd_free(wq, wqed);
-	} else ASSERT(0);
-
+	for (i = 0; i < wqed->nhdl; i++) {
+		if (wqed->hdesc[i].type == COPY_WQE) {
+		oce_wqb_free(wq, wqed->hdesc[i].hdl);
+		} else 	if (wqed->hdesc[i].type == MAPPED_WQE) {
+			oce_wqmd_free(wq, wqed->hdesc[i].hdl);
+		}
+	}
 	if (wqed->mp)
 		freemsg(wqed->mp);
 	kmem_cache_free(wq->wqed_cache, wqed);
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_utils.c	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_utils.c	Thu Aug 05 11:14:15 2010 -0600
@@ -62,6 +62,13 @@
 	}
 } /* oce_page_list */
 
+void
+oce_list_link_init(OCE_LIST_NODE_T  *list_node)
+{
+	list_node->next = NULL;
+	list_node->prev = NULL;
+}
+
 static inline void
 oce_list_insert_node(OCE_LIST_NODE_T  *list_node, OCE_LIST_NODE_T *prev_node,
     OCE_LIST_NODE_T *next_node)
@@ -206,3 +213,35 @@
 	oce_list_remove(list_node);
 	mutex_exit(&list_hdr->list_lock);
 }
+
+void
+oce_gen_hkey(char *hkey, int key_size)
+{
+	int i;
+	int nkeys = key_size/sizeof (uint32_t);
+	for (i = 0; i < nkeys; i++) {
+		(void) random_get_pseudo_bytes(
+		    (uint8_t *)&hkey[i * sizeof (uint32_t)],
+		    sizeof (uint32_t));
+	}
+}
+
+int
+oce_atomic_reserve(uint32_t *count_p, uint32_t n)
+{
+	uint32_t oldval;
+	uint32_t newval;
+
+	/*
+	 * ATOMICALLY
+	 */
+	do {
+		oldval = *count_p;
+		if (oldval < n)
+			return (-1);
+		newval = oldval - n;
+
+	} while (atomic_cas_32(count_p, oldval, newval) != oldval);
+
+	return (newval);
+}
--- a/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_buf.h	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_buf.h	Thu Aug 05 11:14:15 2010 -0600
@@ -44,10 +44,9 @@
 	: (((_START) + (_STEP)) - (_END)))
 
 #define	OCE_MAX_TX_HDL		8
-#define	OCE_MAX_TXDMA_COOKIES	16
+#define	OCE_MAX_TXDMA_COOKIES	18
 #define	OCE_TXMAP_ALIGN		1
 #define	OCE_TX_MAX_FRAGS	(OCE_MAX_TX_HDL * OCE_MAX_TXDMA_COOKIES)
-#define	OCE_TX_LO_WM		OCE_TX_MAX_FRAGS
 
 /* helper structure to access OS addresses */
 typedef union  oce_addr_s {
@@ -79,8 +78,8 @@
 #define	DBUF_VA(obj) (((oce_dma_buf_t *)(obj))->base)
 #define	DBUF_DHDL(obj) (((oce_dma_buf_t *)(obj))->dma_handle)
 #define	DBUF_AHDL(obj) (((oce_dma_buf_t *)obj))->acc_handle)
-#define	DBUF_SYNC(obj, flags)	ddi_dma_sync(DBUF_DHDL(obj), 0,\
-			((oce_dma_buf_t *)obj)->len, (flags))
+#define	DBUF_SYNC(obj, flags)	(void) ddi_dma_sync(DBUF_DHDL(obj), 0,\
+			0, (flags))
 
 typedef struct oce_ring_buffer_s {
 	uint16_t    cidx; 	/* Get ptr */
@@ -92,12 +91,12 @@
 }oce_ring_buffer_t;
 
 typedef struct oce_rq_bdesc_s {
-	OCE_LIST_NODE_T  link;
 	oce_dma_buf_t	*rqb;
 	struct oce_rq	*rq;
 	oce_addr64_t 	frag_addr;
 	mblk_t		*mp;
 	frtn_t		fr_rtn;
+    uint32_t    ref_cnt;
 }oce_rq_bdesc_t;
 
 typedef struct oce_wq_bdesc_s {
@@ -119,6 +118,7 @@
 };
 
 typedef struct _oce_handle_s {
+    enum entry_type	type;
 	void		*hdl; /* opaque handle */
 }oce_handle_t;
 
@@ -128,13 +128,10 @@
 	struct oce_nic_frag_wqe frag[OCE_TX_MAX_FRAGS];
 	struct oce_wq  *wq;
 	mblk_t		*mp;
-	enum entry_type	type;
-	uint16_t	wq_start_idx;
-	uint16_t	wq_end_idx;
 	uint16_t	wqe_cnt;
-	uint16_t	pkt_len; /* 64K MAX */
-	uint32_t	frag_cnt;
-	uint32_t	nhdl;
+	uint16_t	frag_idx;
+	uint16_t	frag_cnt;
+	uint16_t	nhdl;
 }oce_wqe_desc_t;
 
 #pragma pack(1)
--- a/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_hw.h	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_hw.h	Thu Aug 05 11:14:15 2010 -0600
@@ -136,6 +136,13 @@
 #define	ASYNC_EVENT_LINK_UP			0x1
 #define	ASYNC_EVENT_LINK_DOWN		0x0
 
+/* port link_status */
+#define	ASYNC_EVENT_LOGICAL		0x02
+
+/* Logical Link Status */
+#define	NTWK_LOGICAL_LINK_DOWN		0
+#define	NTWK_LOGICAL_LINK_UP		1
+
 /* Rx filter bits */
 #define	NTWK_RX_FILTER_IP_CKSUM 	0x1
 #define	NTWK_RX_FILTER_TCP_CKSUM	0x2
@@ -812,17 +819,10 @@
 	struct mbx_hdr hdr;
 	union {
 		struct {
-#ifdef _BIG_ENDIAN
-			/* dw 0 */
-			uint8_t if_id;
-			uint8_t promiscuous;
-			uint16_t num_mac;
-#else
 			/* dw 0 */
 			uint16_t num_mac;
 			uint8_t promiscuous;
 			uint8_t if_id;
-#endif
 			/* dw 1-48 */
 			struct {
 				uint8_t byte[6];
@@ -1254,6 +1254,36 @@
 	uint8_t		data_buffer[4];  /* + IMAGE_TRANSFER_SIZE */
 };
 
+/* ULP MODE SUPPORTED */
+enum {
+	ULP_TOE_MODE = 0x1,
+	ULP_NIC_MODE = 0x2,
+	ULP_RDMA_MODE = 0x4,
+	ULP_ISCSI_INI_MODE = 0x10,
+	ULP_ISCSI_TGT_MODE = 0x20,
+	ULP_FCOE_INI_MODE = 0x40,
+	ULP_FCOE_TGT_MODE = 0x80,
+	ULP_DAL_MODE = 0x100,
+	ULP_LRO_MODE = 0x200
+};
+
+/* Function Mode Supported */
+enum {
+	TOE_MODE = 0x1, /* TCP offload  */
+	NIC_MODE = 0x2, /* Raw Ethernet  */
+	RDMA_MODE = 0x4, /*  RDMA  */
+	VM_MODE = 0x8,   /* VM  */
+	ISCSI_INI_MODE = 0x10, /*  iSCSI initiator */
+	ISCSI_TGT_MODE = 0x20, /* iSCSI target plus initiator */
+	FCOE_INI_MODE = 0x40, /* FCoE Initiator */
+	FCOE_TGT_MODE = 0x80, /* FCoE target */
+	DAL_MODE = 0x100, /* DAL */
+	LRO_MODE = 0x200, /* LRO */
+	FLEX10_MODE = 0x400, /*  FLEX-10  or VNIC */
+	NCSI_MODE = 0x800, /* NCSI */
+	INVALID_MODE = 0x8000 /* Invalid */
+};
+
 struct mbx_common_query_fw_config {
 	struct mbx_hdr hdr;
 	union {
@@ -1266,32 +1296,23 @@
 			uint32_t    asic_revision;
 			uint32_t    port_id; /* used for stats retrieval */
 			uint32_t    function_mode;
-			uint32_t    ulp0_mode;
-			uint32_t    ulp0_nic_wqid_base;
-			uint32_t    ulp0_nic_wq_tot;
-			uint32_t    ulp0_toe_wqid_base;
-			uint32_t    ulp0_toe_wq_tot;
-			uint32_t    ulp0_toe_rqid_base;
-			uint32_t    ulp0_toe_rqid_tot;
-			uint32_t    ulp0_toe_defrqid_base;
-			uint32_t    ulp0_toe_defrq_tot;
-			uint32_t    ulp0_lro_rqid_base;
-			uint32_t    ulp0_lro_rqid_tot;
-			uint32_t    ulp0_iscsi_icd_base;
-			uint32_t    ulp0_iscsi_icd_tot;
-			uint32_t    ulp1_mode;
-			uint32_t    ulp1_nic_wqid_base;
-			uint32_t    ulp1_wq_tot;
-			uint32_t    ulp1_toe_wqid_base;
-			uint32_t    ulp1_toe_wq_tot;
-			uint32_t    ulp1_toe_rqid_base;
-			uint32_t    ulp1_toe_rqid_tot;
-			uint32_t    ulp1_toe_defrqid_base;
-			uint32_t    ulp1_toe_defrq_tot;
-			uint32_t    ulp1_lro_rqid_base;
-			uint32_t    ulp1_lro_rqid_tot;
-			uint32_t    ulp1_iscsi_icd_base;
-			uint32_t    ulp1_iscsi_icd_tot;
+			struct {
+
+				uint32_t    mode;
+				uint32_t    wq_base;
+				uint32_t    wq_count;
+				uint32_t    sq_base;
+				uint32_t    sq_count;
+				uint32_t    rq_base;
+				uint32_t    rq_count;
+				uint32_t    dq_base;
+				uint32_t    dq_count;
+				uint32_t    lro_base;
+				uint32_t    lro_count;
+				uint32_t    icd_base;
+				uint32_t    icd_count;
+			} ulp[2];
+			uint32_t function_caps;
 		}rsp;
 	}params;
 };
--- a/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_hw_eth.h	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_hw_eth.h	Thu Aug 05 11:14:15 2010 -0600
@@ -72,6 +72,14 @@
 	OPCODE_CONFIG_NIC_RSS_ADVANCED = 16
 };
 
+enum {
+	RSS_ENABLE_NONE		= 0x0, /* (No RSS) */
+	RSS_ENABLE_IPV4		= 0x1, /* (IPV4 HASH enabled ) */
+	RSS_ENABLE_TCP_IPV4	= 0x2, /* (TCP IPV4 Hash enabled) */
+	RSS_ENABLE_IPV6		= 0x4, /* (IPV6 HASH enabled) */
+	RSS_ENABLE_TCP_IPV6	= 0x8  /* (TCP IPV6 HASH */
+
+};
 /* NIC header WQE */
 struct oce_nic_hdr_wqe {
 	union {
@@ -240,12 +248,12 @@
 			uint32_t rsvd0:1;
 			uint32_t vlan_tag_present:1;
 			uint32_t mac_dst:6;
-			uint32_t ip6_frame:1;
+			uint32_t ip_ver:1;
 			uint32_t l4_cksum_pass:1;
 			uint32_t ip_cksum_pass:1;
 			uint32_t udpframe:1;
 			uint32_t tcpframe:1;
-			uint32_t ip4_frame:1;
+			uint32_t ipframe:1;
 			uint32_t rss_hp:1;
 			uint32_t error:1;
 
@@ -272,12 +280,12 @@
 			/* dw 1 */
 			uint32_t error:1;
 			uint32_t rss_hp:1;
-			uint32_t ip4_frame:1;
+			uint32_t ipframe:1;
 			uint32_t tcpframe:1;
 			uint32_t udpframe:1;
 			uint32_t ip_cksum_pass:1;
 			uint32_t l4_cksum_pass:1;
-			uint32_t ip6_frame:1;
+			uint32_t ip_ver:1;
 			uint32_t mac_dst:6;
 			uint32_t vlan_tag_present:1;
 			uint32_t rsvd0:1;
@@ -637,6 +645,36 @@
 	}params;
 };
 
+/* [01] OPCODE_CONFIG_NIC_RSS */
+struct mbx_config_nic_rss {
+	struct mbx_hdr hdr;
+	union {
+		struct {
+#ifdef _BIG_ENDIAN
+			uint32_t if_id;
+			uint16_t cpu_tbl_sz_log2;
+			uint16_t enable_rss;
+			uint32_t hash[10];
+			uint8_t cputable[128];
+			uint8_t rsvd[3];
+			uint8_t flush;
+#else
+			uint32_t if_id;
+			uint16_t enable_rss;
+			uint16_t cpu_tbl_sz_log2;
+			uint32_t hash[10];
+			uint8_t cputable[128];
+			uint8_t flush;
+			uint8_t rsvd[3];
+#endif
+		}req;
+		struct {
+			uint8_t rsvd[3];
+			uint8_t rss_bank;
+		}rsp;
+	}params;
+};
+
 #pragma pack()
 
 #ifdef __cplusplus
--- a/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_impl.h	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_impl.h	Thu Aug 05 11:14:15 2010 -0600
@@ -63,6 +63,8 @@
 #include <sys/fm/util.h>
 #include <sys/fm/io/ddi.h>
 #include <sys/note.h>
+#include <sys/pci.h>
+#include <sys/random.h>
 #include <oce_hw.h>
 #include <oce_hw_eth.h>
 #include <oce_io.h>
@@ -70,6 +72,21 @@
 #include <oce_utils.h>
 #include <oce_version.h>
 
+#define	SIZE_128	128
+#define	SIZE_256	256
+#define	SIZE_512	512
+#define	SIZE_1K		1024
+#define	SIZE_2K		(2 * 1024)
+#define	SIZE_4K		(4 * 1024)
+#define	SIZE_8K		(8 * 1024)
+
+#define	END		0xdeadface
+
+#define	OCE_MAX_ETH_FRAME_SIZE	1500
+#define	OCE_MAX_JUMBO_FRAME_SIZE 9018
+#define	OCE_MIN_ETH_FRAME_SIZE	64
+#define	OCE_LLC_SNAP_HDR_LEN	8
+
 #define	OCE_MIN_MTU	1500
 #define	OCE_MAX_MTU	9000
 #define	OCE_MAX_MCA	32
@@ -78,47 +95,51 @@
 #define	OCE_MAX_EQ	8
 #define	OCE_MAX_CQ	1024
 #define	OCE_MAX_WQ	8
-#define	OCE_WQ_NUM_BUFFERS	2048
-#define	OCE_WQ_BUF_SIZE	2048
-#define	OCE_LSO_MAX_SIZE (32 * 1024)
-#define	OCE_DEFAULT_TX_BCOPY_LIMIT	1024
+#define	OCE_MAX_RQ	5
+
+#define	OCE_WQ_NUM_BUFFERS		2048
+#define	OCE_WQ_BUF_SIZE			2048
+#define	OCE_LSO_MAX_SIZE		(64 * 1024)
+#define	OCE_DEFAULT_TX_BCOPY_LIMIT	512
 #define	OCE_DEFAULT_RX_BCOPY_LIMIT	128
-#define	OCE_DEFAULT_WQ_EQD	16
+#define	OCE_DEFAULT_WQ_EQD		16
+
+#define	OCE_DEFAULT_TX_RING_SIZE	2048
+#define	OCE_DEFAULT_RX_RING_SIZE	1024
+#define	OCE_DEFAULT_WQS			1
+#define	OCE_DEFAULT_RQS			1
+#define	OCE_MAX_RQS			5
 
-#define	OCE_MAX_RQ		8
-#define	OCE_MAX_RQ_POSTS	255
-#define	OCE_RQ_NUM_BUFFERS	2048
-#define	OCE_RQ_BUF_SIZE		2048
+#define	OCE_DEFAULT_RX_PKT_PER_INTR (OCE_DEFAULT_RX_RING_SIZE / 2)
+#define	OCE_DEFAULT_TX_RECLAIM_THRESHOLD 1024
+#define	OCE_MAX_RQ_POSTS		255
+#define	OCE_RQ_NUM_BUFFERS		2048
+#define	OCE_RQ_BUF_SIZE			8192
 #define	OCE_DEFAULT_RECHARGE_THRESHOLD	OCE_MAX_RQ_POSTS
-#define	OCE_NUM_USED_VECTORS    2
-#define	OCE_DMA_ALIGNMENT   0x1000ull
+#define	OCE_NUM_USED_VECTORS		2
+#define	OCE_ITBL_SIZE			64
+#define	OCE_HKEY_SIZE			40
+#define	OCE_DMA_ALIGNMENT		0x1000ull
 
-#define	OCE_DEFAULT_TX_RING_SIZE    2048
-#define	OCE_DEFAULT_RX_RING_SIZE    1024
+#define	OCE_MIN_VECTORS			1
 
-#define	OCE_INVAL_IF_ID			-1
-
-#define	OCE_DEFAULT_IF_CAP	(MBX_RX_IFACE_FLAGS_PROMISCUOUS	| \
-			MBX_RX_IFACE_FLAGS_BROADCAST		| \
+#define	OCE_CAPAB_FLAGS	(MBX_RX_IFACE_FLAGS_BROADCAST		| \
+			MBX_RX_IFACE_FLAGS_PROMISCUOUS		| \
 			MBX_RX_IFACE_FLAGS_UNTAGGED		| \
 			MBX_RX_IFACE_FLAGS_MCAST_PROMISCUOUS	| \
 			MBX_RX_IFACE_FLAGS_PASS_L3L4)
 
-#define	OCE_DEFAULT_IF_CAP_EN	(MBX_RX_IFACE_FLAGS_BROADCAST	| \
+#define	OCE_CAPAB_ENABLE	(MBX_RX_IFACE_FLAGS_BROADCAST	| \
 				MBX_RX_IFACE_FLAGS_UNTAGGED	| \
-				MBX_RX_IFACE_FLAGS_MCAST_PROMISCUOUS	| \
 				MBX_RX_IFACE_FLAGS_PASS_L3L4)
 
-#define	OCE_RX_FILTER_GLOBAL_FLAGS	(NTWK_RX_FILTER_IP_CKSUM | \
-					NTWK_RX_FILTER_TCP_CKSUM | \
-					NTWK_RX_FILTER_UDP_CKSUM | \
-					NTWK_RX_FILTER_STRIP_CRC)
-
-
 #define	OCE_FM_CAPABILITY		(DDI_FM_EREPORT_CAPABLE	|	\
 					DDI_FM_ACCCHK_CAPABLE	|	\
 					DDI_FM_DMACHK_CAPABLE)
 
+
+#define	OCE_DEFAULT_RSS_TYPE	(RSS_ENABLE_IPV4|RSS_ENABLE_TCP_IPV4)
+
 /* flow control definitions */
 #define	OCE_FC_NONE	0x00000000
 #define	OCE_FC_TX	0x00000001
@@ -181,42 +202,41 @@
 };
 
 struct oce_dev {
-	uint32_t dev_id;		/* device ID or instance number */
-	int32_t if_id; 			/* IF ID */
-	uint8_t fn; 			/* function number */
-	uint8_t fw_version[32]; 	/* fw version string */
-	enum oce_driver_state state; 	/* state */
-	struct oce_mq *mq;		/* MQ ring */
-	oce_dma_buf_t *bmbx;		/* Bootstrap MailBox	*/
-	kmutex_t bmbx_lock;		/* Bootstrap Lock	*/
-	uint16_t mod_mask;		/* Log Mask 	*/
-	int16_t severity;		/* Log level	*/
+	kmutex_t bmbx_lock;		/* Bootstrap Lock */
+	kmutex_t dev_lock;		/* lock for device */
+
+	/* Queues relarted */
 	struct oce_wq *wq[OCE_MAX_WQ];	/* TXQ Array */
 	struct oce_rq *rq[OCE_MAX_RQ];	/* RXQ Array */
 	struct oce_cq *cq[OCE_MAX_CQ];	/* Completion Queues */
 	struct oce_eq *eq[OCE_MAX_EQ];	/* Event Queues	*/
+	struct oce_mq *mq;		/* MQ ring */
+
+	/* driver state  machine */
+	enum oce_driver_state state;	/* state */
+	boolean_t suspended;		/* CPR */
+	uint32_t attach_state;		/* attach progress */
+
+	oce_dma_buf_t *bmbx;		/* Bootstrap MailBox */
+
 	uint32_t tx_bcopy_limit;	/* TX BCOPY Limit */
 	uint32_t rx_bcopy_limit;	/* RX BCOPY Limit */
-
-	uint32_t cookie;
+	uint32_t tx_reclaim_threshold;	/* Tx reclaim */
+	uint32_t rx_pkt_per_intr;	/* Rx pkts processed per intr */
 
-	clock_t stat_ticks;
-	uint32_t in_stats;
-
-	/* Add implementation specific stuff here */
+	/* BARS */
+	int num_bars;
 	ddi_acc_handle_t pci_cfg_handle; /* Config space handle */
-	int num_bars;
 	ddi_acc_handle_t cfg_handle;	/* MMIO PCI Config Space Regs */
-	caddr_t csr_addr;
 	ddi_acc_handle_t csr_handle;	/* MMIO Control Status Regs */
+	caddr_t csr_addr;
 	caddr_t db_addr;
+	caddr_t dev_cfg_addr;
 	ddi_acc_handle_t db_handle;	/* MMIO DoorBell Area */
-	caddr_t dev_cfg_addr;
-	ddi_acc_handle_t dev_cfg_handle;	/* MMIO CONFIG SPACE */
+	ddi_acc_handle_t dev_cfg_handle; /* MMIO CONFIG SPACE */
 	mac_handle_t mac_handle;	/* MAC HANDLE	*/
 
-	/* device info structure for device tree node */
-	dev_info_t *dip;
+	/* device stats */
 	kstat_t *oce_kstats;		/* NIC STATS */
 	oce_dma_buf_t *stats_dbuf;	/* STATS BUFFER */
 	struct mbx_get_nic_stats *hw_stats;
@@ -225,53 +245,61 @@
 	uint32_t tx_noxmtbuf;
 
 	/* link status */
-	struct link_status link;
-
-	/* flow control settings */
-	uint32_t flow_control;
+	link_state_t link_status;
+	int32_t link_speed;		/* Link speed in Mbps */
 
-	/* the type of interrupts supported */
-	int intr_types;
-	/* number of vectors used */
-	int num_vectors;
-	/* interrupt priority */
-	uint_t intr_pri;
+	/* OS */
+	uint32_t dev_id;	/* device ID or instance number */
+	dev_info_t *dip;	/* device info structure for device tree node */
+
+	/* Interrupt related */
+	int intr_type;		/* INTR TYPE USED */
+	int num_vectors;	/* number of vectors used */
+	uint_t intr_pri;	/* interrupt priority */
 	int intr_cap;
-	/* intr handler table */
-	ddi_intr_handle_t *htable;
-
-	/* lock for device */
-	kmutex_t dev_lock;
-
-	/* hardware mac address */
-	uint8_t mac_addr[ETHERADDRL];
-
-	/* Current Multicast address table that we have set to h/w */
-	uint16_t num_mca;
-	struct ether_addr multi_cast[OCE_MAX_MCA];
+	ddi_intr_handle_t *htable;	/* intr handler table */
+	int32_t hsize;
 
 	/* device configuration */
-	uint32_t pmac_id; /* used to add or remove mac */
-	uint8_t unicast_addr[ETHERADDRL];
-	uint32_t mtu;
+	uint32_t rq_max_bufs;		/* maximum prealloced buffers */
+	uint32_t rq_frag_size;		/* Rxq fragment size */
 	enum oce_ring_size tx_ring_size;
 	enum oce_ring_size rx_ring_size;
-	boolean_t lso_capable;
-	boolean_t promisc;
-	uint32_t if_cap_flags;
-	int32_t  fm_caps;
-	uint32_t  attach_state;
-	boolean_t suspended;
-	uint32_t  neqs;	/* No of event queues */
-	uint32_t  nwqs;	/* No of Work Queues */
-	uint32_t  nrqs;	/* No of Receive Queues */
-	uint32_t  nifs; /* No of interfaces created */
+	uint32_t neqs;			/* No of event queues */
+	uint32_t nwqs;			/* No of Work Queues */
+	uint32_t nrqs;			/* No of Receive Queues */
+	uint32_t nifs;			/* No of interfaces created */
+	uint32_t tx_rings;
+	uint32_t rx_rings;
+	uint32_t pmac_id;		/* used to add or remove mac */
+	uint8_t unicast_addr[ETHERADDRL];
+	uint32_t mtu;
+	int32_t fm_caps;
+	boolean_t rss_enable;		/* RSS support */
+	boolean_t lso_capable;		/* LSO */
+	boolean_t promisc;		/* PROMISC MODE */
+	uint32_t if_cap_flags;		/* IF CAPAB */
+	uint32_t flow_control;		/* flow control settings */
+	uint8_t mac_addr[ETHERADDRL];	/* hardware mac address */
+	uint16_t num_mca;		/* MCA supported */
+	struct ether_addr multi_cast[OCE_MAX_MCA];	/* MC TABLE */
+	uint32_t cookie;		/* used during fw download */
 
 	/* fw config: only relevant fields */
-	uint32_t    config_number;
-	uint32_t    asic_revision;
-	uint32_t    port_id;
-	uint32_t    function_mode;
+	uint32_t config_number;
+	uint32_t asic_revision;
+	uint32_t port_id;
+	uint32_t function_mode;
+	uint32_t function_caps;
+	uint32_t max_tx_rings;		/* Max Rx rings available */
+	uint32_t max_rx_rings;		/* Max rx rings available */
+	int32_t if_id;			/* IF ID */
+	uint8_t fn;			/* function number */
+	uint8_t fw_version[32];		/* fw version string */
+
+	/* Logging related */
+	uint16_t mod_mask;		/* Log Mask */
+	int16_t severity;		/* Log level */
 };
 
 /* GLD handler functions */
@@ -310,7 +338,6 @@
 
 /* Interrupt handling */
 int oce_setup_intr(struct oce_dev *dev);
-int oce_alloc_intr(struct oce_dev *dev);
 int oce_teardown_intr(struct oce_dev *dev);
 int oce_setup_handlers(struct oce_dev *dev);
 void oce_remove_handler(struct oce_dev *dev);
--- a/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_io.h	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_io.h	Thu Aug 05 11:14:15 2010 -0600
@@ -96,22 +96,22 @@
 };
 
 struct oce_eq {
-	/* configuration of this eq */
-	struct eq_config eq_cfg;
+	/* Lock for this queue */
+	kmutex_t lock;
 	/* id assigned by the hw to this eq */
 	uint32_t eq_id;
 	/* handle to the creating parent dev */
 	void *parent;
 	/* callback context */
 	void *cb_context;
-	/* reference count of this structure */
-	uint32_t ref_count;
 	/* ring buffer for this eq */
 	oce_ring_buffer_t *ring;
+	/* reference count of this structure */
+	uint32_t ref_count;
 	/* Queue state */
 	qstate_t qstate;
-	/* Lock for this queue */
-	kmutex_t lock;
+	/* configuration of this eq */
+	struct eq_config eq_cfg;
 };
 
 enum cq_len {
@@ -138,10 +138,8 @@
 typedef uint16_t (*cq_handler_t)(void *arg1);
 
 struct oce_cq {
-	/* configuration of this cq */
-	struct cq_config cq_cfg;
-	/* reference count of this structure */
-	uint32_t ref_count;
+	/* lock */
+	kmutex_t lock;
 	/* id given by the hardware */
 	uint32_t    cq_id;
 	/* parent device to which this cq belongs */
@@ -155,8 +153,10 @@
 	oce_ring_buffer_t *ring;
 	/* Queue state */
 	qstate_t qstate;
-	/* lock */
-	kmutex_t lock;
+	/* configuration of this cq */
+	struct cq_config cq_cfg;
+	/* reference count of this structure */
+	uint32_t ref_count;
 };
 
 struct mq_config {
@@ -167,8 +167,8 @@
 };
 
 struct oce_mq {
-	/* configuration of this mq */
-	struct mq_config cfg;
+	/* lock for the mq */
+	kmutex_t lock;
 	/* handle to the parent device */
 	void *parent;
 	/* send queue */
@@ -181,8 +181,9 @@
 	uint32_t mq_free;
 	/* Queue state */
 	qstate_t qstate;
-	/* lock for the mq */
-	kmutex_t lock;
+
+	/* configuration of this mq */
+	struct mq_config cfg;
 };
 
 
@@ -201,7 +202,8 @@
 struct wq_config {
 	/* qtype */
 	uint8_t wq_type;
-	uint8_t pad[3];
+	uint16_t buf_size;
+	uint8_t pad[1];
 	uint32_t q_len; /* number of wqes */
 	uint16_t pd_id; /* protection domain id */
 	uint16_t pci_fn_num; /* pci function number */
@@ -211,15 +213,15 @@
 };
 
 struct oce_wq {
-	struct wq_config cfg; /* q config */
+	kmutex_t tx_lock; /* lock for the WQ */
+	kmutex_t txc_lock; /* tx compl lock */
 	void *parent; /* parent of this wq */
-	uint16_t wq_id; /* wq ID */
 	oce_ring_buffer_t *ring; /* ring buffer managing the wqes */
 	struct oce_cq	*cq; 	/* cq associated with this wq */
 	kmem_cache_t	*wqed_cache; /* packet desc cache */
-	OCE_LIST_T	wqe_desc_list; /* packet descriptor list */
-	oce_wq_bdesc_t  *wq_bdesc_array; /* buffer desc array */
-	OCE_LIST_T	wq_buf_list; /* buffer list */
+	oce_wq_bdesc_t *wq_bdesc_array; /* buffer desc array */
+	OCE_LIST_T wq_buf_list; /* buffer list */
+	OCE_LIST_T wqe_desc_list; /* packet descriptor list */
 	OCE_LIST_T 	wq_mdesc_list; /* free list of memory handles */
 	oce_wq_mdesc_t  *wq_mdesc_array; /* preallocated memory handles */
 	uint32_t	wqm_used; /* memory handles uses */
@@ -227,11 +229,11 @@
 	uint32_t	wq_free; /* Wqe free */
 	uint32_t	tx_deferd; /* Wqe free */
 	uint32_t	pkt_drops; /* drops */
+
 	/* Queue state */
 	qstate_t qstate;
-	kmutex_t tx_lock; /* lock for the WQ */
-	kmutex_t txc_lock; /* tx compl lock */
-	kmutex_t resched_lock; /* tx compl lock */
+	uint16_t wq_id; /* wq ID */
+    struct wq_config cfg; /* q config */
 };
 
 struct rq_config {
@@ -259,14 +261,15 @@
 	uint32_t rss_cpuid;
 	/* ring buffer managing the RQEs */
 	oce_ring_buffer_t *ring;
-	/* RQ Buffer cache  */
-	/* kmem_cache_t *rqb_cache; */
-	/* shadow list of mblk for rq ring */
-	struct rq_shadow_entry *shadow_ring;
 	/* cq associated with this queue */
 	struct oce_cq *cq;
 	oce_rq_bdesc_t  *rq_bdesc_array;
-	OCE_LIST_T rq_buf_list; /* Free list */
+	/* shadow list of mblk for rq ring */
+	oce_rq_bdesc_t **shadow_ring;
+	oce_rq_bdesc_t  **rqb_freelist;
+	uint32_t rqb_free;
+	uint32_t rqb_next_free; /* next free slot */
+	uint32_t rqb_rc_head; /* recycling  head */
 	uint32_t buf_avail; /* buffer avaialable with hw */
 	uint32_t pending; /* Buffers sent up */
 	/* Queue state */
@@ -285,11 +288,13 @@
 	/* dw 1 */
 	uint8_t mgmt_mac_duplex;
 	uint8_t mgmt_mac_speed;
-	uint16_t rsvd0;
+	uint16_t qos_link_speed;
+	/* dw2 */
+	uint32_t logical_link_status;
 };
 
 oce_dma_buf_t *oce_alloc_dma_buffer(struct oce_dev *dev,
-    uint32_t size, uint32_t flags);
+    uint32_t size, ddi_dma_attr_t *dma_attr, uint32_t flags);
 void oce_free_dma_buffer(struct oce_dev *dev, oce_dma_buf_t *dbuf);
 
 oce_ring_buffer_t *create_ring_buffer(struct oce_dev *dev,
@@ -342,7 +347,7 @@
 int oce_start_rq(struct oce_rq *rq);
 void oce_clean_rq(struct oce_rq *rq);
 void oce_rq_discharge(struct oce_rq *rq);
-int oce_rx_pending(struct oce_dev *dev);
+int oce_rx_pending(struct oce_dev *dev, struct oce_rq *rq, int32_t timeout);
 
 /* event handling */
 uint16_t oce_drain_mq_cq(void *arg);
@@ -385,7 +390,8 @@
     uint8_t vtag_cnt,  boolean_t untagged,
     boolean_t enable_promisc);
 int oce_config_link(struct oce_dev *dev, boolean_t enable);
-
+int oce_config_rss(struct oce_dev *dev, uint16_t if_id, char *hkey, char *itbl,
+    int  tbl_sz, uint16_t rss_type, uint8_t flush);
 int oce_issue_mbox(struct oce_dev *dev, queue_t *wq, mblk_t *mp,
     uint32_t *payload_length);
 
--- a/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_utils.h	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_utils.h	Thu Aug 05 11:14:15 2010 -0600
@@ -47,16 +47,19 @@
 #define	OCE_DEFAULT_LOG_SETTINGS	(CE_WARN	|	\
 					((MOD_CONFIG | MOD_TX | MOD_RX) << 16))
 
+#define	OCE_MAX_LOG_SETTINGS		(CE_IGNORE | ((MOD_CONFIG | MOD_TX | \
+					MOD_RX | MOD_ISR) << 16))
+
 #define	oce_log(dev_p, level, module, fmt, arg...) {	\
 	if (dev_p) {					\
 		if ((dev_p->mod_mask & module) && 	\
 		    (dev_p->severity < CE_IGNORE) && 	\
 		    ((uint32_t)level >= dev_p->severity)) 	\
-			cmn_err(level, "%s[%d]: %s[%d]: " fmt, OCE_MOD_NAME, \
-			    dev_p->dev_id, __FILE__, __LINE__, ## arg);	     \
+			cmn_err(level, "%s[%d]: " fmt, OCE_MOD_NAME,	\
+			    dev_p->dev_id, ## arg);			\
 	} else {							\
-		cmn_err(level, "%s[%d]: %s[%d]: " fmt, OCE_MOD_NAME,	\
-		    0, __FILE__, __LINE__, ## arg);			\
+		cmn_err(level, "%s[%d]: " fmt, OCE_MOD_NAME,		\
+		    0, ## arg);						\
 	}								\
 }
 
@@ -90,11 +93,13 @@
 /* Utility Functions */
 
 #define	OCE_DW_SWAP(datap, length)	{			\
-	int len;						\
-	for (len = ((length)/4 - 1); len >= 0; len--) {		\
-		*((uint32_t *)(datap) + len) =			\
-		    LE_32(*((uint32_t *)(datap) + len));	\
-	}							\
+	int len;	                                \
+	uint32_t *wptr = (uint32_t *)(datap);                 \
+	len = (length) + (((length)  %4) ? (4  - (4 %(length))) : 0); \
+	for (len = len/4; len > 0; len--) {		\
+		*wptr = LE_32(*wptr);			\
+		wptr++;	                    \
+	}							        \
 }
 
 
@@ -110,14 +115,15 @@
 }OCE_LIST_NODE_T;
 
 typedef struct {
+	kmutex_t list_lock;
 	OCE_LIST_NODE_T head;
 	int32_t nitems;
-	kmutex_t list_lock;
-
 }OCE_LIST_T;
 
 /* externs for  list manipulation functions */
 
+
+void oce_list_link_init(OCE_LIST_NODE_T  *list_node);
 void oce_list_create(OCE_LIST_T  *list_hdr, void *arg);
 void oce_list_destroy(OCE_LIST_T *list_hdr);
 void oce_list_insert_tail(OCE_LIST_T *list_hdr, OCE_LIST_NODE_T *list_node);
@@ -125,6 +131,7 @@
 void oce_list_remove_node(OCE_LIST_T  *list_hdr, OCE_LIST_NODE_T *list_node);
 boolean_t oce_list_is_empty(OCE_LIST_T *list_hdr);
 int32_t oce_list_items_avail(OCE_LIST_T *list_hdr);
+int oce_atomic_reserve(uint32_t *count_p, uint32_t n);
 
 #define	OCE_LIST_CREATE(_LH, _LCK_PRI)	oce_list_create((_LH), (_LCK_PRI))
 #define	OCE_LIST_DESTROY(_LH)		oce_list_destroy((_LH))
@@ -135,6 +142,9 @@
 #define	OCE_LIST_REMOVE(_LH, _N)				\
 			oce_list_remove_node((_LH), (void *)(_N))
 #define	OCE_LIST_SIZE(_LH)		oce_list_items_avail((_LH))
+#define	OCE_LIST_LINK_INIT(_N)		oce_list_link_init(_N)
+
+void oce_gen_hkey(char *hkey, int key_size);
 
 #ifdef __cplusplus
 }
--- a/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_version.h	Thu Aug 05 09:40:41 2010 -0700
+++ b/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_version.h	Thu Aug 05 11:14:15 2010 -0600
@@ -38,7 +38,7 @@
 #define	OCE_MAJOR_VERSION	"1"
 #define	OCE_MINOR_VERSION	"1"
 #define	OCE_RELEASE_NUM		"0"
-#define	OCE_PROTO_LEVEL		"f2"
+#define	OCE_PROTO_LEVEL		"s"
 
 #define	OCE_VERSION		OCE_MAJOR_VERSION "." \
 				OCE_MINOR_VERSION \