xref: /illumos-gate/usr/src/uts/sun4v/io/vsw_txdring.c (revision 6e472272)
17bd3a2e2SSriharsha Basavapatna /*
27bd3a2e2SSriharsha Basavapatna  * CDDL HEADER START
37bd3a2e2SSriharsha Basavapatna  *
47bd3a2e2SSriharsha Basavapatna  * The contents of this file are subject to the terms of the
57bd3a2e2SSriharsha Basavapatna  * Common Development and Distribution License (the "License").
67bd3a2e2SSriharsha Basavapatna  * You may not use this file except in compliance with the License.
77bd3a2e2SSriharsha Basavapatna  *
87bd3a2e2SSriharsha Basavapatna  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97bd3a2e2SSriharsha Basavapatna  * or http://www.opensolaris.org/os/licensing.
107bd3a2e2SSriharsha Basavapatna  * See the License for the specific language governing permissions
117bd3a2e2SSriharsha Basavapatna  * and limitations under the License.
127bd3a2e2SSriharsha Basavapatna  *
137bd3a2e2SSriharsha Basavapatna  * When distributing Covered Code, include this CDDL HEADER in each
147bd3a2e2SSriharsha Basavapatna  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157bd3a2e2SSriharsha Basavapatna  * If applicable, add the following below this CDDL HEADER, with the
167bd3a2e2SSriharsha Basavapatna  * fields enclosed by brackets "[]" replaced with your own identifying
177bd3a2e2SSriharsha Basavapatna  * information: Portions Copyright [yyyy] [name of copyright owner]
187bd3a2e2SSriharsha Basavapatna  *
197bd3a2e2SSriharsha Basavapatna  * CDDL HEADER END
207bd3a2e2SSriharsha Basavapatna  */
217bd3a2e2SSriharsha Basavapatna 
227bd3a2e2SSriharsha Basavapatna /*
237bd3a2e2SSriharsha Basavapatna  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247bd3a2e2SSriharsha Basavapatna  * Use is subject to license terms.
257bd3a2e2SSriharsha Basavapatna  */
267bd3a2e2SSriharsha Basavapatna #include <sys/types.h>
277bd3a2e2SSriharsha Basavapatna #include <sys/errno.h>
287bd3a2e2SSriharsha Basavapatna #include <sys/sysmacros.h>
297bd3a2e2SSriharsha Basavapatna #include <sys/param.h>
307bd3a2e2SSriharsha Basavapatna #include <sys/machsystm.h>
317bd3a2e2SSriharsha Basavapatna #include <sys/stream.h>
327bd3a2e2SSriharsha Basavapatna #include <sys/strsubr.h>
337bd3a2e2SSriharsha Basavapatna #include <sys/kmem.h>
347bd3a2e2SSriharsha Basavapatna #include <sys/strsun.h>
357bd3a2e2SSriharsha Basavapatna #include <sys/callb.h>
367bd3a2e2SSriharsha Basavapatna #include <sys/sdt.h>
377bd3a2e2SSriharsha Basavapatna #include <sys/mach_descrip.h>
387bd3a2e2SSriharsha Basavapatna #include <sys/mdeg.h>
397bd3a2e2SSriharsha Basavapatna #include <net/if.h>
407bd3a2e2SSriharsha Basavapatna #include <sys/vsw.h>
417bd3a2e2SSriharsha Basavapatna #include <sys/vio_mailbox.h>
427bd3a2e2SSriharsha Basavapatna #include <sys/vio_common.h>
437bd3a2e2SSriharsha Basavapatna #include <sys/vnet_common.h>
447bd3a2e2SSriharsha Basavapatna #include <sys/vnet_mailbox.h>
457bd3a2e2SSriharsha Basavapatna #include <sys/vio_util.h>
467bd3a2e2SSriharsha Basavapatna 
477bd3a2e2SSriharsha Basavapatna /*
487bd3a2e2SSriharsha Basavapatna  * This file contains the implementation of TxDring data transfer mode of VIO
497bd3a2e2SSriharsha Basavapatna  * Protocol in vsw. The functions in this file are invoked from vsw_ldc.c
507bd3a2e2SSriharsha Basavapatna  * after TxDring mode is negotiated with the peer during attribute phase of
517bd3a2e2SSriharsha Basavapatna  * handshake. This file contains functions that setup the transmit and receive
527bd3a2e2SSriharsha Basavapatna  * descriptor rings, and associated resources in TxDring mode. It also contains
537bd3a2e2SSriharsha Basavapatna  * the transmit and receive data processing functions that are invoked in
547bd3a2e2SSriharsha Basavapatna  * TxDring mode.
557bd3a2e2SSriharsha Basavapatna  */
567bd3a2e2SSriharsha Basavapatna 
577bd3a2e2SSriharsha Basavapatna /* Functions exported to vsw_ldc.c */
587bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t *vsw_create_tx_dring_info(vsw_ldc_t *);
597bd3a2e2SSriharsha Basavapatna int vsw_setup_tx_dring(vsw_ldc_t *ldcp, dring_info_t *dp);
607bd3a2e2SSriharsha Basavapatna void vsw_destroy_tx_dring(vsw_ldc_t *ldcp);
617bd3a2e2SSriharsha Basavapatna dring_info_t *vsw_map_rx_dring(vsw_ldc_t *ldcp, void *pkt);
627bd3a2e2SSriharsha Basavapatna void vsw_unmap_rx_dring(vsw_ldc_t *ldcp);
637bd3a2e2SSriharsha Basavapatna int vsw_dringsend(vsw_ldc_t *, mblk_t *);
647bd3a2e2SSriharsha Basavapatna void vsw_ldc_msg_worker(void *arg);
657bd3a2e2SSriharsha Basavapatna void vsw_stop_msg_thread(vsw_ldc_t *ldcp);
667bd3a2e2SSriharsha Basavapatna void vsw_process_dringdata(void *, void *);
677bd3a2e2SSriharsha Basavapatna int vsw_send_msg(vsw_ldc_t *, void *, int, boolean_t);
687bd3a2e2SSriharsha Basavapatna int vsw_reclaim_dring(dring_info_t *dp, int start);
697bd3a2e2SSriharsha Basavapatna int vsw_dring_find_free_desc(dring_info_t *, vsw_private_desc_t **, int *);
707bd3a2e2SSriharsha Basavapatna 
717bd3a2e2SSriharsha Basavapatna /* Internal functions */
727bd3a2e2SSriharsha Basavapatna static int vsw_init_multipools(vsw_ldc_t *ldcp, vsw_t *vswp);
737bd3a2e2SSriharsha Basavapatna static dring_info_t *vsw_create_tx_dring(vsw_ldc_t *);
747bd3a2e2SSriharsha Basavapatna 
757bd3a2e2SSriharsha Basavapatna /* Functions imported from vsw_ldc.c */
767bd3a2e2SSriharsha Basavapatna extern void vsw_process_pkt(void *);
777bd3a2e2SSriharsha Basavapatna extern void vsw_destroy_rxpools(void *);
787bd3a2e2SSriharsha Basavapatna extern dring_info_t *vsw_map_dring_cmn(vsw_ldc_t *ldcp,
797bd3a2e2SSriharsha Basavapatna     vio_dring_reg_msg_t *dring_pkt);
807bd3a2e2SSriharsha Basavapatna extern void vsw_process_conn_evt(vsw_ldc_t *, uint16_t);
817bd3a2e2SSriharsha Basavapatna extern mblk_t *vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp);
827bd3a2e2SSriharsha Basavapatna 
837bd3a2e2SSriharsha Basavapatna /* Tunables */
847bd3a2e2SSriharsha Basavapatna extern int vsw_wretries;
857bd3a2e2SSriharsha Basavapatna extern int vsw_recv_delay;
867bd3a2e2SSriharsha Basavapatna extern int vsw_recv_retries;
877bd3a2e2SSriharsha Basavapatna extern boolean_t vsw_jumbo_rxpools;
887bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_chain_len;
897bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_num_descriptors;
907bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_mblk_size1;
917bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_mblk_size2;
927bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_mblk_size3;
937bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_mblk_size4;
947bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_num_mblks1;
957bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_num_mblks2;
967bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_num_mblks3;
977bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_num_mblks4;
987bd3a2e2SSriharsha Basavapatna 
997bd3a2e2SSriharsha Basavapatna #define	VSW_NUM_VMPOOLS		3	/* number of vio mblk pools */
1007bd3a2e2SSriharsha Basavapatna 
1017bd3a2e2SSriharsha Basavapatna #define	SND_DRING_NACK(ldcp, pkt) \
1027bd3a2e2SSriharsha Basavapatna 	pkt->tag.vio_subtype = VIO_SUBTYPE_NACK; \
1037bd3a2e2SSriharsha Basavapatna 	pkt->tag.vio_sid = ldcp->local_session; \
1047bd3a2e2SSriharsha Basavapatna 	(void) vsw_send_msg(ldcp, (void *)pkt, \
1057bd3a2e2SSriharsha Basavapatna 			sizeof (vio_dring_msg_t), B_TRUE);
1067bd3a2e2SSriharsha Basavapatna 
1077bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t *
vsw_create_tx_dring_info(vsw_ldc_t * ldcp)1087bd3a2e2SSriharsha Basavapatna vsw_create_tx_dring_info(vsw_ldc_t *ldcp)
1097bd3a2e2SSriharsha Basavapatna {
1107bd3a2e2SSriharsha Basavapatna 	vio_dring_reg_msg_t	*mp;
1117bd3a2e2SSriharsha Basavapatna 	dring_info_t		*dp;
1127bd3a2e2SSriharsha Basavapatna 	vsw_t			*vswp = ldcp->ldc_vswp;
1137bd3a2e2SSriharsha Basavapatna 
1147bd3a2e2SSriharsha Basavapatna 	D1(vswp, "%s enter\n", __func__);
1157bd3a2e2SSriharsha Basavapatna 
1167bd3a2e2SSriharsha Basavapatna 	/*
1177bd3a2e2SSriharsha Basavapatna 	 * If we can't create a dring, obviously no point sending
1187bd3a2e2SSriharsha Basavapatna 	 * a message.
1197bd3a2e2SSriharsha Basavapatna 	 */
1207bd3a2e2SSriharsha Basavapatna 	if ((dp = vsw_create_tx_dring(ldcp)) == NULL)
1217bd3a2e2SSriharsha Basavapatna 		return (NULL);
1227bd3a2e2SSriharsha Basavapatna 
1237bd3a2e2SSriharsha Basavapatna 	mp = kmem_zalloc(sizeof (vio_dring_reg_msg_t), KM_SLEEP);
1247bd3a2e2SSriharsha Basavapatna 
1257bd3a2e2SSriharsha Basavapatna 	mp->tag.vio_msgtype = VIO_TYPE_CTRL;
1267bd3a2e2SSriharsha Basavapatna 	mp->tag.vio_subtype = VIO_SUBTYPE_INFO;
1277bd3a2e2SSriharsha Basavapatna 	mp->tag.vio_subtype_env = VIO_DRING_REG;
1287bd3a2e2SSriharsha Basavapatna 	mp->tag.vio_sid = ldcp->local_session;
1297bd3a2e2SSriharsha Basavapatna 
1307bd3a2e2SSriharsha Basavapatna 	/* payload */
1317bd3a2e2SSriharsha Basavapatna 	mp->num_descriptors = dp->num_descriptors;
1327bd3a2e2SSriharsha Basavapatna 	mp->descriptor_size = dp->descriptor_size;
1337bd3a2e2SSriharsha Basavapatna 	mp->options = dp->options;
1347bd3a2e2SSriharsha Basavapatna 	mp->ncookies = dp->dring_ncookies;
1357bd3a2e2SSriharsha Basavapatna 	bcopy(&dp->dring_cookie[0], &mp->cookie[0], sizeof (ldc_mem_cookie_t));
1367bd3a2e2SSriharsha Basavapatna 
1377bd3a2e2SSriharsha Basavapatna 	mp->dring_ident = 0;
1387bd3a2e2SSriharsha Basavapatna 
1397bd3a2e2SSriharsha Basavapatna 	D1(vswp, "%s exit\n", __func__);
1407bd3a2e2SSriharsha Basavapatna 
1417bd3a2e2SSriharsha Basavapatna 	return (mp);
1427bd3a2e2SSriharsha Basavapatna }
1437bd3a2e2SSriharsha Basavapatna 
1447bd3a2e2SSriharsha Basavapatna /*
1457bd3a2e2SSriharsha Basavapatna  * Allocate transmit resources for the channel. The resources consist of a
1467bd3a2e2SSriharsha Basavapatna  * transmit descriptor ring and an associated transmit buffer area.
1477bd3a2e2SSriharsha Basavapatna  */
1487bd3a2e2SSriharsha Basavapatna static dring_info_t *
vsw_create_tx_dring(vsw_ldc_t * ldcp)1497bd3a2e2SSriharsha Basavapatna vsw_create_tx_dring(vsw_ldc_t *ldcp)
1507bd3a2e2SSriharsha Basavapatna {
1517bd3a2e2SSriharsha Basavapatna 	vsw_t			*vswp = ldcp->ldc_vswp;
1527bd3a2e2SSriharsha Basavapatna 	ldc_mem_info_t		minfo;
1537bd3a2e2SSriharsha Basavapatna 	dring_info_t		*dp;
1547bd3a2e2SSriharsha Basavapatna 
1557bd3a2e2SSriharsha Basavapatna 	dp = (dring_info_t *)kmem_zalloc(sizeof (dring_info_t), KM_SLEEP);
1567bd3a2e2SSriharsha Basavapatna 	mutex_init(&dp->dlock, NULL, MUTEX_DRIVER, NULL);
1577bd3a2e2SSriharsha Basavapatna 	mutex_init(&dp->restart_lock, NULL, MUTEX_DRIVER, NULL);
1587bd3a2e2SSriharsha Basavapatna 	ldcp->lane_out.dringp = dp;
1597bd3a2e2SSriharsha Basavapatna 
1607bd3a2e2SSriharsha Basavapatna 	/* create public section of ring */
1617bd3a2e2SSriharsha Basavapatna 	if ((ldc_mem_dring_create(vsw_num_descriptors,
1627bd3a2e2SSriharsha Basavapatna 	    sizeof (vnet_public_desc_t), &dp->dring_handle)) != 0) {
1637bd3a2e2SSriharsha Basavapatna 
1647bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "vsw_create_tx_dring(%lld): ldc dring create "
1657bd3a2e2SSriharsha Basavapatna 		    "failed", ldcp->ldc_id);
1667bd3a2e2SSriharsha Basavapatna 		goto fail;
1677bd3a2e2SSriharsha Basavapatna 	}
1687bd3a2e2SSriharsha Basavapatna 	ASSERT(dp->dring_handle != NULL);
1697bd3a2e2SSriharsha Basavapatna 
1707bd3a2e2SSriharsha Basavapatna 	/*
1717bd3a2e2SSriharsha Basavapatna 	 * Get the base address of the public section of the ring.
1727bd3a2e2SSriharsha Basavapatna 	 */
1737bd3a2e2SSriharsha Basavapatna 	if ((ldc_mem_dring_info(dp->dring_handle, &minfo)) != 0) {
1747bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "vsw_create_tx_dring(%lld): dring info failed\n",
1757bd3a2e2SSriharsha Basavapatna 		    ldcp->ldc_id);
1767bd3a2e2SSriharsha Basavapatna 		goto fail;
1777bd3a2e2SSriharsha Basavapatna 	} else {
1787bd3a2e2SSriharsha Basavapatna 		ASSERT(minfo.vaddr != 0);
1797bd3a2e2SSriharsha Basavapatna 		dp->pub_addr = minfo.vaddr;
1807bd3a2e2SSriharsha Basavapatna 	}
1817bd3a2e2SSriharsha Basavapatna 
1827bd3a2e2SSriharsha Basavapatna 	dp->num_descriptors = vsw_num_descriptors;
1837bd3a2e2SSriharsha Basavapatna 	dp->descriptor_size = sizeof (vnet_public_desc_t);
1847bd3a2e2SSriharsha Basavapatna 	dp->options = VIO_TX_DRING;
1857bd3a2e2SSriharsha Basavapatna 	dp->dring_ncookies = 1;	/* guaranteed by ldc */
1867bd3a2e2SSriharsha Basavapatna 
1877bd3a2e2SSriharsha Basavapatna 	/*
1887bd3a2e2SSriharsha Basavapatna 	 * create private portion of ring
1897bd3a2e2SSriharsha Basavapatna 	 */
1907bd3a2e2SSriharsha Basavapatna 	dp->priv_addr = (vsw_private_desc_t *)kmem_zalloc(
1917bd3a2e2SSriharsha Basavapatna 	    (sizeof (vsw_private_desc_t) * vsw_num_descriptors), KM_SLEEP);
1927bd3a2e2SSriharsha Basavapatna 
1937bd3a2e2SSriharsha Basavapatna 	if (vsw_setup_tx_dring(ldcp, dp)) {
1947bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "%s: unable to setup ring", __func__);
1957bd3a2e2SSriharsha Basavapatna 		goto fail;
1967bd3a2e2SSriharsha Basavapatna 	}
1977bd3a2e2SSriharsha Basavapatna 
1987bd3a2e2SSriharsha Basavapatna 	/* bind dring to the channel */
1997bd3a2e2SSriharsha Basavapatna 	if ((ldc_mem_dring_bind(ldcp->ldc_handle, dp->dring_handle,
2007bd3a2e2SSriharsha Basavapatna 	    LDC_DIRECT_MAP | LDC_SHADOW_MAP, LDC_MEM_RW,
2017bd3a2e2SSriharsha Basavapatna 	    &dp->dring_cookie[0], &dp->dring_ncookies)) != 0) {
2027bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "vsw_create_tx_dring: unable to bind to channel "
2037bd3a2e2SSriharsha Basavapatna 		    "%lld", ldcp->ldc_id);
2047bd3a2e2SSriharsha Basavapatna 		goto fail;
2057bd3a2e2SSriharsha Basavapatna 	}
2067bd3a2e2SSriharsha Basavapatna 
2077bd3a2e2SSriharsha Basavapatna 	/* haven't used any descriptors yet */
2087bd3a2e2SSriharsha Basavapatna 	dp->end_idx = 0;
2097bd3a2e2SSriharsha Basavapatna 	dp->last_ack_recv = -1;
2107bd3a2e2SSriharsha Basavapatna 	dp->restart_reqd = B_TRUE;
2117bd3a2e2SSriharsha Basavapatna 
2127bd3a2e2SSriharsha Basavapatna 	return (dp);
2137bd3a2e2SSriharsha Basavapatna 
2147bd3a2e2SSriharsha Basavapatna fail:
2157bd3a2e2SSriharsha Basavapatna 	vsw_destroy_tx_dring(ldcp);
2167bd3a2e2SSriharsha Basavapatna 	return (NULL);
2177bd3a2e2SSriharsha Basavapatna }
2187bd3a2e2SSriharsha Basavapatna 
2197bd3a2e2SSriharsha Basavapatna /*
2207bd3a2e2SSriharsha Basavapatna  * Setup the descriptors in the tx dring.
2217bd3a2e2SSriharsha Basavapatna  * Returns 0 on success, 1 on failure.
2227bd3a2e2SSriharsha Basavapatna  */
2237bd3a2e2SSriharsha Basavapatna int
vsw_setup_tx_dring(vsw_ldc_t * ldcp,dring_info_t * dp)2247bd3a2e2SSriharsha Basavapatna vsw_setup_tx_dring(vsw_ldc_t *ldcp, dring_info_t *dp)
2257bd3a2e2SSriharsha Basavapatna {
2267bd3a2e2SSriharsha Basavapatna 	vnet_public_desc_t	*pub_addr = NULL;
2277bd3a2e2SSriharsha Basavapatna 	vsw_private_desc_t	*priv_addr = NULL;
2287bd3a2e2SSriharsha Basavapatna 	vsw_t			*vswp = ldcp->ldc_vswp;
2297bd3a2e2SSriharsha Basavapatna 	uint64_t		*tmpp;
2307bd3a2e2SSriharsha Basavapatna 	uint64_t		offset = 0;
2317bd3a2e2SSriharsha Basavapatna 	uint32_t		ncookies = 0;
2327bd3a2e2SSriharsha Basavapatna 	static char		*name = "vsw_setup_ring";
2337bd3a2e2SSriharsha Basavapatna 	int			i, j, nc, rv;
2347bd3a2e2SSriharsha Basavapatna 	size_t			data_sz;
2357bd3a2e2SSriharsha Basavapatna 	void			*data_addr;
2367bd3a2e2SSriharsha Basavapatna 
2377bd3a2e2SSriharsha Basavapatna 	priv_addr = dp->priv_addr;
2387bd3a2e2SSriharsha Basavapatna 	pub_addr = dp->pub_addr;
2397bd3a2e2SSriharsha Basavapatna 
2407bd3a2e2SSriharsha Basavapatna 	/* public section may be null but private should never be */
2417bd3a2e2SSriharsha Basavapatna 	ASSERT(priv_addr != NULL);
2427bd3a2e2SSriharsha Basavapatna 
2437bd3a2e2SSriharsha Basavapatna 	/*
2447bd3a2e2SSriharsha Basavapatna 	 * Allocate the region of memory which will be used to hold
2457bd3a2e2SSriharsha Basavapatna 	 * the data the descriptors will refer to.
2467bd3a2e2SSriharsha Basavapatna 	 */
2477bd3a2e2SSriharsha Basavapatna 	data_sz = vswp->max_frame_size + VNET_IPALIGN + VNET_LDCALIGN;
2487bd3a2e2SSriharsha Basavapatna 
2497bd3a2e2SSriharsha Basavapatna 	/*
2507bd3a2e2SSriharsha Basavapatna 	 * In order to ensure that the number of ldc cookies per descriptor is
2517bd3a2e2SSriharsha Basavapatna 	 * limited to be within the default MAX_COOKIES (2), we take the steps
2527bd3a2e2SSriharsha Basavapatna 	 * outlined below:
2537bd3a2e2SSriharsha Basavapatna 	 *
2547bd3a2e2SSriharsha Basavapatna 	 * Align the entire data buffer area to 8K and carve out per descriptor
2557bd3a2e2SSriharsha Basavapatna 	 * data buffers starting from this 8K aligned base address.
2567bd3a2e2SSriharsha Basavapatna 	 *
2577bd3a2e2SSriharsha Basavapatna 	 * We round up the mtu specified to be a multiple of 2K or 4K.
2587bd3a2e2SSriharsha Basavapatna 	 * For sizes up to 12K we round up the size to the next 2K.
2597bd3a2e2SSriharsha Basavapatna 	 * For sizes > 12K we round up to the next 4K (otherwise sizes such as
2607bd3a2e2SSriharsha Basavapatna 	 * 14K could end up needing 3 cookies, with the buffer spread across
2617bd3a2e2SSriharsha Basavapatna 	 * 3 8K pages:  8K+6K, 2K+8K+2K, 6K+8K, ...).
2627bd3a2e2SSriharsha Basavapatna 	 */
2637bd3a2e2SSriharsha Basavapatna 	if (data_sz <= VNET_12K) {
2647bd3a2e2SSriharsha Basavapatna 		data_sz = VNET_ROUNDUP_2K(data_sz);
2657bd3a2e2SSriharsha Basavapatna 	} else {
2667bd3a2e2SSriharsha Basavapatna 		data_sz = VNET_ROUNDUP_4K(data_sz);
2677bd3a2e2SSriharsha Basavapatna 	}
2687bd3a2e2SSriharsha Basavapatna 
2697bd3a2e2SSriharsha Basavapatna 	dp->desc_data_sz = data_sz;
2707bd3a2e2SSriharsha Basavapatna 
2717bd3a2e2SSriharsha Basavapatna 	/* allocate extra 8K bytes for alignment */
2727bd3a2e2SSriharsha Basavapatna 	dp->data_sz = (vsw_num_descriptors * data_sz) + VNET_8K;
2737bd3a2e2SSriharsha Basavapatna 	data_addr = kmem_alloc(dp->data_sz, KM_SLEEP);
2747bd3a2e2SSriharsha Basavapatna 	dp->data_addr = data_addr;
2757bd3a2e2SSriharsha Basavapatna 
2767bd3a2e2SSriharsha Basavapatna 	D2(vswp, "%s: allocated %lld bytes at 0x%llx\n", name,
2777bd3a2e2SSriharsha Basavapatna 	    dp->data_sz, dp->data_addr);
2787bd3a2e2SSriharsha Basavapatna 
2797bd3a2e2SSriharsha Basavapatna 	/* align the starting address of the data area to 8K */
2807bd3a2e2SSriharsha Basavapatna 	data_addr = (void *)VNET_ROUNDUP_8K((uintptr_t)data_addr);
2817bd3a2e2SSriharsha Basavapatna 
2827bd3a2e2SSriharsha Basavapatna 	tmpp = (uint64_t *)data_addr;
2837bd3a2e2SSriharsha Basavapatna 	offset = dp->desc_data_sz/sizeof (tmpp);
2847bd3a2e2SSriharsha Basavapatna 
2857bd3a2e2SSriharsha Basavapatna 	/*
2867bd3a2e2SSriharsha Basavapatna 	 * Initialise some of the private and public (if they exist)
2877bd3a2e2SSriharsha Basavapatna 	 * descriptor fields.
2887bd3a2e2SSriharsha Basavapatna 	 */
2897bd3a2e2SSriharsha Basavapatna 	for (i = 0; i < vsw_num_descriptors; i++) {
2907bd3a2e2SSriharsha Basavapatna 		mutex_init(&priv_addr->dstate_lock, NULL, MUTEX_DRIVER, NULL);
2917bd3a2e2SSriharsha Basavapatna 
2927bd3a2e2SSriharsha Basavapatna 		if ((ldc_mem_alloc_handle(ldcp->ldc_handle,
2937bd3a2e2SSriharsha Basavapatna 		    &priv_addr->memhandle)) != 0) {
2947bd3a2e2SSriharsha Basavapatna 			DERR(vswp, "%s: alloc mem handle failed", name);
2957bd3a2e2SSriharsha Basavapatna 			goto fail;
2967bd3a2e2SSriharsha Basavapatna 		}
2977bd3a2e2SSriharsha Basavapatna 
2987bd3a2e2SSriharsha Basavapatna 		priv_addr->datap = (void *)tmpp;
2997bd3a2e2SSriharsha Basavapatna 
3007bd3a2e2SSriharsha Basavapatna 		rv = ldc_mem_bind_handle(priv_addr->memhandle,
3017bd3a2e2SSriharsha Basavapatna 		    (caddr_t)priv_addr->datap, dp->desc_data_sz,
3027bd3a2e2SSriharsha Basavapatna 		    LDC_SHADOW_MAP, LDC_MEM_R|LDC_MEM_W,
3037bd3a2e2SSriharsha Basavapatna 		    &(priv_addr->memcookie[0]), &ncookies);
3047bd3a2e2SSriharsha Basavapatna 		if (rv != 0) {
3057bd3a2e2SSriharsha Basavapatna 			DERR(vswp, "%s(%lld): ldc_mem_bind_handle failed "
3067bd3a2e2SSriharsha Basavapatna 			    "(rv %d)", name, ldcp->ldc_id, rv);
3077bd3a2e2SSriharsha Basavapatna 			goto fail;
3087bd3a2e2SSriharsha Basavapatna 		}
3097bd3a2e2SSriharsha Basavapatna 		priv_addr->bound = 1;
3107bd3a2e2SSriharsha Basavapatna 
3117bd3a2e2SSriharsha Basavapatna 		D2(vswp, "%s: %d: memcookie 0 : addr 0x%llx : size 0x%llx",
3127bd3a2e2SSriharsha Basavapatna 		    name, i, priv_addr->memcookie[0].addr,
3137bd3a2e2SSriharsha Basavapatna 		    priv_addr->memcookie[0].size);
3147bd3a2e2SSriharsha Basavapatna 
3157bd3a2e2SSriharsha Basavapatna 		if (ncookies >= (uint32_t)(VSW_MAX_COOKIES + 1)) {
3167bd3a2e2SSriharsha Basavapatna 			DERR(vswp, "%s(%lld) ldc_mem_bind_handle returned "
3177bd3a2e2SSriharsha Basavapatna 			    "invalid num of cookies (%d) for size 0x%llx",
3187bd3a2e2SSriharsha Basavapatna 			    name, ldcp->ldc_id, ncookies, VSW_RING_EL_DATA_SZ);
3197bd3a2e2SSriharsha Basavapatna 
3207bd3a2e2SSriharsha Basavapatna 			goto fail;
3217bd3a2e2SSriharsha Basavapatna 		} else {
3227bd3a2e2SSriharsha Basavapatna 			for (j = 1; j < ncookies; j++) {
3237bd3a2e2SSriharsha Basavapatna 				rv = ldc_mem_nextcookie(priv_addr->memhandle,
3247bd3a2e2SSriharsha Basavapatna 				    &(priv_addr->memcookie[j]));
3257bd3a2e2SSriharsha Basavapatna 				if (rv != 0) {
3267bd3a2e2SSriharsha Basavapatna 					DERR(vswp, "%s: ldc_mem_nextcookie "
3277bd3a2e2SSriharsha Basavapatna 					    "failed rv (%d)", name, rv);
3287bd3a2e2SSriharsha Basavapatna 					goto fail;
3297bd3a2e2SSriharsha Basavapatna 				}
3307bd3a2e2SSriharsha Basavapatna 				D3(vswp, "%s: memcookie %d : addr 0x%llx : "
3317bd3a2e2SSriharsha Basavapatna 				    "size 0x%llx", name, j,
3327bd3a2e2SSriharsha Basavapatna 				    priv_addr->memcookie[j].addr,
3337bd3a2e2SSriharsha Basavapatna 				    priv_addr->memcookie[j].size);
3347bd3a2e2SSriharsha Basavapatna 			}
3357bd3a2e2SSriharsha Basavapatna 
3367bd3a2e2SSriharsha Basavapatna 		}
3377bd3a2e2SSriharsha Basavapatna 		priv_addr->ncookies = ncookies;
3387bd3a2e2SSriharsha Basavapatna 		priv_addr->dstate = VIO_DESC_FREE;
3397bd3a2e2SSriharsha Basavapatna 
3407bd3a2e2SSriharsha Basavapatna 		if (pub_addr != NULL) {
3417bd3a2e2SSriharsha Basavapatna 
3427bd3a2e2SSriharsha Basavapatna 			/* link pub and private sides */
3437bd3a2e2SSriharsha Basavapatna 			priv_addr->descp = pub_addr;
3447bd3a2e2SSriharsha Basavapatna 
3457bd3a2e2SSriharsha Basavapatna 			pub_addr->ncookies = priv_addr->ncookies;
3467bd3a2e2SSriharsha Basavapatna 
3477bd3a2e2SSriharsha Basavapatna 			for (nc = 0; nc < pub_addr->ncookies; nc++) {
3487bd3a2e2SSriharsha Basavapatna 				bcopy(&priv_addr->memcookie[nc],
3497bd3a2e2SSriharsha Basavapatna 				    &pub_addr->memcookie[nc],
3507bd3a2e2SSriharsha Basavapatna 				    sizeof (ldc_mem_cookie_t));
3517bd3a2e2SSriharsha Basavapatna 			}
3527bd3a2e2SSriharsha Basavapatna 
3537bd3a2e2SSriharsha Basavapatna 			pub_addr->hdr.dstate = VIO_DESC_FREE;
3547bd3a2e2SSriharsha Basavapatna 			pub_addr++;
3557bd3a2e2SSriharsha Basavapatna 		}
3567bd3a2e2SSriharsha Basavapatna 
3577bd3a2e2SSriharsha Basavapatna 		/*
3587bd3a2e2SSriharsha Basavapatna 		 * move to next element in the dring and the next
3597bd3a2e2SSriharsha Basavapatna 		 * position in the data buffer.
3607bd3a2e2SSriharsha Basavapatna 		 */
3617bd3a2e2SSriharsha Basavapatna 		priv_addr++;
3627bd3a2e2SSriharsha Basavapatna 		tmpp += offset;
3637bd3a2e2SSriharsha Basavapatna 	}
3647bd3a2e2SSriharsha Basavapatna 
3657bd3a2e2SSriharsha Basavapatna 	return (0);
3667bd3a2e2SSriharsha Basavapatna 
3677bd3a2e2SSriharsha Basavapatna fail:
3687bd3a2e2SSriharsha Basavapatna 	/* return failure; caller will cleanup */
3697bd3a2e2SSriharsha Basavapatna 	return (1);
3707bd3a2e2SSriharsha Basavapatna }
3717bd3a2e2SSriharsha Basavapatna 
3727bd3a2e2SSriharsha Basavapatna /*
3737bd3a2e2SSriharsha Basavapatna  * Free transmit resources for the channel.
3747bd3a2e2SSriharsha Basavapatna  */
3757bd3a2e2SSriharsha Basavapatna void
vsw_destroy_tx_dring(vsw_ldc_t * ldcp)3767bd3a2e2SSriharsha Basavapatna vsw_destroy_tx_dring(vsw_ldc_t *ldcp)
3777bd3a2e2SSriharsha Basavapatna {
3787bd3a2e2SSriharsha Basavapatna 	vsw_private_desc_t	*paddr = NULL;
3797bd3a2e2SSriharsha Basavapatna 	int			i;
3807bd3a2e2SSriharsha Basavapatna 	lane_t			*lp = &ldcp->lane_out;
3817bd3a2e2SSriharsha Basavapatna 	dring_info_t		*dp;
3827bd3a2e2SSriharsha Basavapatna 
3837bd3a2e2SSriharsha Basavapatna 	dp = lp->dringp;
3847bd3a2e2SSriharsha Basavapatna 	if (dp == NULL) {
3857bd3a2e2SSriharsha Basavapatna 		return;
3867bd3a2e2SSriharsha Basavapatna 	}
3877bd3a2e2SSriharsha Basavapatna 
3887bd3a2e2SSriharsha Basavapatna 	mutex_enter(&dp->dlock);
3897bd3a2e2SSriharsha Basavapatna 
3907bd3a2e2SSriharsha Basavapatna 	if (dp->priv_addr != NULL) {
3917bd3a2e2SSriharsha Basavapatna 		/*
3927bd3a2e2SSriharsha Basavapatna 		 * First unbind and free the memory handles
3937bd3a2e2SSriharsha Basavapatna 		 * stored in each descriptor within the ring.
3947bd3a2e2SSriharsha Basavapatna 		 */
3957bd3a2e2SSriharsha Basavapatna 		for (i = 0; i < vsw_num_descriptors; i++) {
3967bd3a2e2SSriharsha Basavapatna 			paddr = (vsw_private_desc_t *)dp->priv_addr + i;
397*6e472272SToomas Soome 			if (paddr->memhandle != 0) {
3987bd3a2e2SSriharsha Basavapatna 				if (paddr->bound == 1) {
3997bd3a2e2SSriharsha Basavapatna 					if (ldc_mem_unbind_handle(
4007bd3a2e2SSriharsha Basavapatna 					    paddr->memhandle) != 0) {
4017bd3a2e2SSriharsha Basavapatna 						DERR(NULL, "error "
4027bd3a2e2SSriharsha Basavapatna 						"unbinding handle for "
4037bd3a2e2SSriharsha Basavapatna 						"ring 0x%llx at pos %d",
4047bd3a2e2SSriharsha Basavapatna 						    dp, i);
4057bd3a2e2SSriharsha Basavapatna 						continue;
4067bd3a2e2SSriharsha Basavapatna 					}
4077bd3a2e2SSriharsha Basavapatna 					paddr->bound = 0;
4087bd3a2e2SSriharsha Basavapatna 				}
4097bd3a2e2SSriharsha Basavapatna 
4107bd3a2e2SSriharsha Basavapatna 				if (ldc_mem_free_handle(
4117bd3a2e2SSriharsha Basavapatna 				    paddr->memhandle) != 0) {
4127bd3a2e2SSriharsha Basavapatna 					DERR(NULL, "error freeing "
4137bd3a2e2SSriharsha Basavapatna 					    "handle for ring 0x%llx "
4147bd3a2e2SSriharsha Basavapatna 					    "at pos %d", dp, i);
4157bd3a2e2SSriharsha Basavapatna 					continue;
4167bd3a2e2SSriharsha Basavapatna 				}
417*6e472272SToomas Soome 				paddr->memhandle = 0;
4187bd3a2e2SSriharsha Basavapatna 			}
4197bd3a2e2SSriharsha Basavapatna 			mutex_destroy(&paddr->dstate_lock);
4207bd3a2e2SSriharsha Basavapatna 		}
4217bd3a2e2SSriharsha Basavapatna 		kmem_free(dp->priv_addr,
4227bd3a2e2SSriharsha Basavapatna 		    (sizeof (vsw_private_desc_t) * vsw_num_descriptors));
4237bd3a2e2SSriharsha Basavapatna 	}
4247bd3a2e2SSriharsha Basavapatna 
4257bd3a2e2SSriharsha Basavapatna 	/*
4267bd3a2e2SSriharsha Basavapatna 	 * Now unbind and destroy the ring itself.
4277bd3a2e2SSriharsha Basavapatna 	 */
428*6e472272SToomas Soome 	if (dp->dring_handle != 0) {
4297bd3a2e2SSriharsha Basavapatna 		(void) ldc_mem_dring_unbind(dp->dring_handle);
4307bd3a2e2SSriharsha Basavapatna 		(void) ldc_mem_dring_destroy(dp->dring_handle);
4317bd3a2e2SSriharsha Basavapatna 	}
4327bd3a2e2SSriharsha Basavapatna 
4337bd3a2e2SSriharsha Basavapatna 	if (dp->data_addr != NULL) {
4347bd3a2e2SSriharsha Basavapatna 		kmem_free(dp->data_addr, dp->data_sz);
4357bd3a2e2SSriharsha Basavapatna 	}
4367bd3a2e2SSriharsha Basavapatna 
4377bd3a2e2SSriharsha Basavapatna 	mutex_exit(&dp->dlock);
4387bd3a2e2SSriharsha Basavapatna 	mutex_destroy(&dp->dlock);
4397bd3a2e2SSriharsha Basavapatna 	mutex_destroy(&dp->restart_lock);
4407bd3a2e2SSriharsha Basavapatna 	kmem_free(dp, sizeof (dring_info_t));
4417bd3a2e2SSriharsha Basavapatna 	lp->dringp = NULL;
4427bd3a2e2SSriharsha Basavapatna }
4437bd3a2e2SSriharsha Basavapatna 
4447bd3a2e2SSriharsha Basavapatna /*
4457bd3a2e2SSriharsha Basavapatna  * Map the transmit descriptor ring exported
4467bd3a2e2SSriharsha Basavapatna  * by the peer, as our receive descriptor ring.
4477bd3a2e2SSriharsha Basavapatna  */
4487bd3a2e2SSriharsha Basavapatna dring_info_t *
vsw_map_rx_dring(vsw_ldc_t * ldcp,void * pkt)4497bd3a2e2SSriharsha Basavapatna vsw_map_rx_dring(vsw_ldc_t *ldcp, void *pkt)
4507bd3a2e2SSriharsha Basavapatna {
4517bd3a2e2SSriharsha Basavapatna 	int			rv;
4527bd3a2e2SSriharsha Basavapatna 	dring_info_t		*dp;
4537bd3a2e2SSriharsha Basavapatna 	vio_dring_reg_msg_t	*dring_pkt = pkt;
4547bd3a2e2SSriharsha Basavapatna 	vsw_t			*vswp = ldcp->ldc_vswp;
4557bd3a2e2SSriharsha Basavapatna 
4567bd3a2e2SSriharsha Basavapatna 	dp = vsw_map_dring_cmn(ldcp, dring_pkt);
4577bd3a2e2SSriharsha Basavapatna 	if (dp == NULL) {
4587bd3a2e2SSriharsha Basavapatna 		return (NULL);
4597bd3a2e2SSriharsha Basavapatna 	}
4607bd3a2e2SSriharsha Basavapatna 
4617bd3a2e2SSriharsha Basavapatna 	/* TxDring mode specific initializations */
4627bd3a2e2SSriharsha Basavapatna 	dp->end_idx = 0;
4637bd3a2e2SSriharsha Basavapatna 	ldcp->lane_in.dringp = dp;
4647bd3a2e2SSriharsha Basavapatna 
4657bd3a2e2SSriharsha Basavapatna 	/* Allocate pools of receive mblks */
4667bd3a2e2SSriharsha Basavapatna 	rv = vsw_init_multipools(ldcp, vswp);
4677bd3a2e2SSriharsha Basavapatna 	if (rv != 0) {
4687bd3a2e2SSriharsha Basavapatna 		/*
4697bd3a2e2SSriharsha Basavapatna 		 * We do not return failure if receive mblk pools can't
4707bd3a2e2SSriharsha Basavapatna 		 * be allocated, instead allocb(9F) will be used to
4717bd3a2e2SSriharsha Basavapatna 		 * dynamically allocate buffers during receive.
4727bd3a2e2SSriharsha Basavapatna 		 */
4737bd3a2e2SSriharsha Basavapatna 		DWARN(vswp, "%s: unable to create free mblk pools for"
4747bd3a2e2SSriharsha Basavapatna 		    " channel %ld (rv %d)", __func__, ldcp->ldc_id, rv);
4757bd3a2e2SSriharsha Basavapatna 	}
4767bd3a2e2SSriharsha Basavapatna 
4777bd3a2e2SSriharsha Basavapatna 	return (dp);
4787bd3a2e2SSriharsha Basavapatna }
4797bd3a2e2SSriharsha Basavapatna 
4807bd3a2e2SSriharsha Basavapatna /*
4817bd3a2e2SSriharsha Basavapatna  * Unmap the receive descriptor ring.
4827bd3a2e2SSriharsha Basavapatna  */
4837bd3a2e2SSriharsha Basavapatna void
vsw_unmap_rx_dring(vsw_ldc_t * ldcp)4847bd3a2e2SSriharsha Basavapatna vsw_unmap_rx_dring(vsw_ldc_t *ldcp)
4857bd3a2e2SSriharsha Basavapatna {
4867bd3a2e2SSriharsha Basavapatna 	vio_mblk_pool_t *fvmp = NULL;
4877bd3a2e2SSriharsha Basavapatna 	vsw_t		*vswp = ldcp->ldc_vswp;
4887bd3a2e2SSriharsha Basavapatna 	lane_t		*lp = &ldcp->lane_in;
4897bd3a2e2SSriharsha Basavapatna 	dring_info_t	*dp;
4907bd3a2e2SSriharsha Basavapatna 
4917bd3a2e2SSriharsha Basavapatna 	if ((dp = lp->dringp) == NULL) {
4927bd3a2e2SSriharsha Basavapatna 		return;
4937bd3a2e2SSriharsha Basavapatna 	}
4947bd3a2e2SSriharsha Basavapatna 
4957bd3a2e2SSriharsha Basavapatna 	/*
4967bd3a2e2SSriharsha Basavapatna 	 * If we can't destroy all the rx pools for this channel,
4977bd3a2e2SSriharsha Basavapatna 	 * dispatch a task to retry and clean up those rx pools. Note
4987bd3a2e2SSriharsha Basavapatna 	 * that we don't need to wait for the task to complete. If the
4997bd3a2e2SSriharsha Basavapatna 	 * vsw device itself gets detached (vsw_detach()), it will wait
5007bd3a2e2SSriharsha Basavapatna 	 * for the task to complete implicitly in ddi_taskq_destroy().
5017bd3a2e2SSriharsha Basavapatna 	 */
5027bd3a2e2SSriharsha Basavapatna 	vio_destroy_multipools(&ldcp->vmp, &fvmp);
5037bd3a2e2SSriharsha Basavapatna 	if (fvmp != NULL) {
5047bd3a2e2SSriharsha Basavapatna 		(void) ddi_taskq_dispatch(vswp->rxp_taskq,
5057bd3a2e2SSriharsha Basavapatna 		    vsw_destroy_rxpools, fvmp, DDI_SLEEP);
5067bd3a2e2SSriharsha Basavapatna 	}
5077bd3a2e2SSriharsha Basavapatna 
508*6e472272SToomas Soome 	if (dp->dring_handle != 0) {
5097bd3a2e2SSriharsha Basavapatna 		(void) ldc_mem_dring_unmap(dp->dring_handle);
5107bd3a2e2SSriharsha Basavapatna 	}
5117bd3a2e2SSriharsha Basavapatna 	kmem_free(dp, sizeof (dring_info_t));
5127bd3a2e2SSriharsha Basavapatna 	lp->dringp = NULL;
5137bd3a2e2SSriharsha Basavapatna }
5147bd3a2e2SSriharsha Basavapatna 
5157bd3a2e2SSriharsha Basavapatna static int
vsw_init_multipools(vsw_ldc_t * ldcp,vsw_t * vswp)5167bd3a2e2SSriharsha Basavapatna vsw_init_multipools(vsw_ldc_t *ldcp, vsw_t *vswp)
5177bd3a2e2SSriharsha Basavapatna {
5187bd3a2e2SSriharsha Basavapatna 	size_t		data_sz;
5197bd3a2e2SSriharsha Basavapatna 	int		rv;
5207bd3a2e2SSriharsha Basavapatna 	uint32_t	sz1 = 0;
5217bd3a2e2SSriharsha Basavapatna 	uint32_t	sz2 = 0;
5227bd3a2e2SSriharsha Basavapatna 	uint32_t	sz3 = 0;
5237bd3a2e2SSriharsha Basavapatna 	uint32_t	sz4 = 0;
5247bd3a2e2SSriharsha Basavapatna 
5257bd3a2e2SSriharsha Basavapatna 	/*
5267bd3a2e2SSriharsha Basavapatna 	 * We round up the mtu specified to be a multiple of 2K to limit the
5277bd3a2e2SSriharsha Basavapatna 	 * number of rx buffer pools created for a given mtu.
5287bd3a2e2SSriharsha Basavapatna 	 */
5297bd3a2e2SSriharsha Basavapatna 	data_sz = vswp->max_frame_size + VNET_IPALIGN + VNET_LDCALIGN;
5307bd3a2e2SSriharsha Basavapatna 	data_sz = VNET_ROUNDUP_2K(data_sz);
5317bd3a2e2SSriharsha Basavapatna 
5327bd3a2e2SSriharsha Basavapatna 	/*
5337bd3a2e2SSriharsha Basavapatna 	 * If pool sizes are specified, use them. Note that the presence of
5347bd3a2e2SSriharsha Basavapatna 	 * the first tunable will be used as a hint.
5357bd3a2e2SSriharsha Basavapatna 	 */
5367bd3a2e2SSriharsha Basavapatna 	if (vsw_mblk_size1 != 0) {
5377bd3a2e2SSriharsha Basavapatna 		sz1 = vsw_mblk_size1;
5387bd3a2e2SSriharsha Basavapatna 		sz2 = vsw_mblk_size2;
5397bd3a2e2SSriharsha Basavapatna 		sz3 = vsw_mblk_size3;
5407bd3a2e2SSriharsha Basavapatna 		sz4 = vsw_mblk_size4;
5417bd3a2e2SSriharsha Basavapatna 
5427bd3a2e2SSriharsha Basavapatna 		if (sz4 == 0) { /* need 3 pools */
5437bd3a2e2SSriharsha Basavapatna 
5447bd3a2e2SSriharsha Basavapatna 			ldcp->max_rxpool_size = sz3;
5457bd3a2e2SSriharsha Basavapatna 			rv = vio_init_multipools(&ldcp->vmp,
5467bd3a2e2SSriharsha Basavapatna 			    VSW_NUM_VMPOOLS, sz1, sz2, sz3,
5477bd3a2e2SSriharsha Basavapatna 			    vsw_num_mblks1, vsw_num_mblks2, vsw_num_mblks3);
5487bd3a2e2SSriharsha Basavapatna 
5497bd3a2e2SSriharsha Basavapatna 		} else {
5507bd3a2e2SSriharsha Basavapatna 
5517bd3a2e2SSriharsha Basavapatna 			ldcp->max_rxpool_size = sz4;
5527bd3a2e2SSriharsha Basavapatna 			rv = vio_init_multipools(&ldcp->vmp,
5537bd3a2e2SSriharsha Basavapatna 			    VSW_NUM_VMPOOLS + 1, sz1, sz2, sz3, sz4,
5547bd3a2e2SSriharsha Basavapatna 			    vsw_num_mblks1, vsw_num_mblks2, vsw_num_mblks3,
5557bd3a2e2SSriharsha Basavapatna 			    vsw_num_mblks4);
5567bd3a2e2SSriharsha Basavapatna 
5577bd3a2e2SSriharsha Basavapatna 		}
5587bd3a2e2SSriharsha Basavapatna 
5597bd3a2e2SSriharsha Basavapatna 		return (rv);
5607bd3a2e2SSriharsha Basavapatna 	}
5617bd3a2e2SSriharsha Basavapatna 
5627bd3a2e2SSriharsha Basavapatna 	/*
5637bd3a2e2SSriharsha Basavapatna 	 * Pool sizes are not specified. We select the pool sizes based on the
5647bd3a2e2SSriharsha Basavapatna 	 * mtu if vnet_jumbo_rxpools is enabled.
5657bd3a2e2SSriharsha Basavapatna 	 */
5667bd3a2e2SSriharsha Basavapatna 	if (vsw_jumbo_rxpools == B_FALSE || data_sz == VNET_2K) {
5677bd3a2e2SSriharsha Basavapatna 		/*
5687bd3a2e2SSriharsha Basavapatna 		 * Receive buffer pool allocation based on mtu is disabled.
5697bd3a2e2SSriharsha Basavapatna 		 * Use the default mechanism of standard size pool allocation.
5707bd3a2e2SSriharsha Basavapatna 		 */
5717bd3a2e2SSriharsha Basavapatna 		sz1 = VSW_MBLK_SZ_128;
5727bd3a2e2SSriharsha Basavapatna 		sz2 = VSW_MBLK_SZ_256;
5737bd3a2e2SSriharsha Basavapatna 		sz3 = VSW_MBLK_SZ_2048;
5747bd3a2e2SSriharsha Basavapatna 		ldcp->max_rxpool_size = sz3;
5757bd3a2e2SSriharsha Basavapatna 
5767bd3a2e2SSriharsha Basavapatna 		rv = vio_init_multipools(&ldcp->vmp, VSW_NUM_VMPOOLS,
5777bd3a2e2SSriharsha Basavapatna 		    sz1, sz2, sz3,
5787bd3a2e2SSriharsha Basavapatna 		    vsw_num_mblks1, vsw_num_mblks2, vsw_num_mblks3);
5797bd3a2e2SSriharsha Basavapatna 
5807bd3a2e2SSriharsha Basavapatna 		return (rv);
5817bd3a2e2SSriharsha Basavapatna 	}
5827bd3a2e2SSriharsha Basavapatna 
5837bd3a2e2SSriharsha Basavapatna 	switch (data_sz) {
5847bd3a2e2SSriharsha Basavapatna 
5857bd3a2e2SSriharsha Basavapatna 	case VNET_4K:
5867bd3a2e2SSriharsha Basavapatna 
5877bd3a2e2SSriharsha Basavapatna 		sz1 = VSW_MBLK_SZ_128;
5887bd3a2e2SSriharsha Basavapatna 		sz2 = VSW_MBLK_SZ_256;
5897bd3a2e2SSriharsha Basavapatna 		sz3 = VSW_MBLK_SZ_2048;
5907bd3a2e2SSriharsha Basavapatna 		sz4 = sz3 << 1;			/* 4K */
5917bd3a2e2SSriharsha Basavapatna 		ldcp->max_rxpool_size = sz4;
5927bd3a2e2SSriharsha Basavapatna 
5937bd3a2e2SSriharsha Basavapatna 		rv = vio_init_multipools(&ldcp->vmp, VSW_NUM_VMPOOLS + 1,
5947bd3a2e2SSriharsha Basavapatna 		    sz1, sz2, sz3, sz4,
5957bd3a2e2SSriharsha Basavapatna 		    vsw_num_mblks1, vsw_num_mblks2, vsw_num_mblks3,
5967bd3a2e2SSriharsha Basavapatna 		    vsw_num_mblks4);
5977bd3a2e2SSriharsha Basavapatna 		break;
5987bd3a2e2SSriharsha Basavapatna 
5997bd3a2e2SSriharsha Basavapatna 	default:	/* data_sz:  4K+ to 16K */
6007bd3a2e2SSriharsha Basavapatna 
6017bd3a2e2SSriharsha Basavapatna 		sz1 = VSW_MBLK_SZ_256;
6027bd3a2e2SSriharsha Basavapatna 		sz2 = VSW_MBLK_SZ_2048;
6037bd3a2e2SSriharsha Basavapatna 		sz3 = data_sz >> 1;	/* Jumbo-size/2 */
6047bd3a2e2SSriharsha Basavapatna 		sz4 = data_sz;	/* Jumbo-size */
6057bd3a2e2SSriharsha Basavapatna 		ldcp->max_rxpool_size = sz4;
6067bd3a2e2SSriharsha Basavapatna 
6077bd3a2e2SSriharsha Basavapatna 		rv = vio_init_multipools(&ldcp->vmp, VSW_NUM_VMPOOLS + 1,
6087bd3a2e2SSriharsha Basavapatna 		    sz1, sz2, sz3, sz4,
6097bd3a2e2SSriharsha Basavapatna 		    vsw_num_mblks1, vsw_num_mblks2, vsw_num_mblks3,
6107bd3a2e2SSriharsha Basavapatna 		    vsw_num_mblks4);
6117bd3a2e2SSriharsha Basavapatna 		break;
6127bd3a2e2SSriharsha Basavapatna 	}
6137bd3a2e2SSriharsha Basavapatna 
6147bd3a2e2SSriharsha Basavapatna 	return (rv);
6157bd3a2e2SSriharsha Basavapatna 
6167bd3a2e2SSriharsha Basavapatna }
6177bd3a2e2SSriharsha Basavapatna 
6187bd3a2e2SSriharsha Basavapatna /*
6197bd3a2e2SSriharsha Basavapatna  * Generic routine to send message out over ldc channel.
6207bd3a2e2SSriharsha Basavapatna  *
6217bd3a2e2SSriharsha Basavapatna  * It is possible that when we attempt to write over the ldc channel
6227bd3a2e2SSriharsha Basavapatna  * that we get notified that it has been reset. Depending on the value
6237bd3a2e2SSriharsha Basavapatna  * of the handle_reset flag we either handle that event here or simply
6247bd3a2e2SSriharsha Basavapatna  * notify the caller that the channel was reset.
6257bd3a2e2SSriharsha Basavapatna  */
6267bd3a2e2SSriharsha Basavapatna int
vsw_send_msg(vsw_ldc_t * ldcp,void * msgp,int size,boolean_t handle_reset)6277bd3a2e2SSriharsha Basavapatna vsw_send_msg(vsw_ldc_t *ldcp, void *msgp, int size, boolean_t handle_reset)
6287bd3a2e2SSriharsha Basavapatna {
6297bd3a2e2SSriharsha Basavapatna 	int			rv;
6307bd3a2e2SSriharsha Basavapatna 	size_t			msglen = size;
6317bd3a2e2SSriharsha Basavapatna 	vio_msg_tag_t		*tag = (vio_msg_tag_t *)msgp;
6327bd3a2e2SSriharsha Basavapatna 	vsw_t			*vswp = ldcp->ldc_vswp;
6337bd3a2e2SSriharsha Basavapatna 	vio_dring_msg_t		*dmsg;
6347bd3a2e2SSriharsha Basavapatna 	vio_raw_data_msg_t	*rmsg;
6357bd3a2e2SSriharsha Basavapatna 	vnet_ibnd_desc_t	*imsg;
6367bd3a2e2SSriharsha Basavapatna 	boolean_t		data_msg = B_FALSE;
6377bd3a2e2SSriharsha Basavapatna 	int			retries = vsw_wretries;
6387bd3a2e2SSriharsha Basavapatna 
6397bd3a2e2SSriharsha Basavapatna 	D1(vswp, "vsw_send_msg (%lld) enter : sending %d bytes",
6407bd3a2e2SSriharsha Basavapatna 	    ldcp->ldc_id, size);
6417bd3a2e2SSriharsha Basavapatna 
6427bd3a2e2SSriharsha Basavapatna 	D2(vswp, "send_msg: type 0x%llx", tag->vio_msgtype);
6437bd3a2e2SSriharsha Basavapatna 	D2(vswp, "send_msg: stype 0x%llx", tag->vio_subtype);
6447bd3a2e2SSriharsha Basavapatna 	D2(vswp, "send_msg: senv 0x%llx", tag->vio_subtype_env);
6457bd3a2e2SSriharsha Basavapatna 
6467bd3a2e2SSriharsha Basavapatna 	mutex_enter(&ldcp->ldc_txlock);
6477bd3a2e2SSriharsha Basavapatna 
6487bd3a2e2SSriharsha Basavapatna 	if (tag->vio_subtype == VIO_SUBTYPE_INFO) {
6497bd3a2e2SSriharsha Basavapatna 		if (tag->vio_subtype_env == VIO_DRING_DATA) {
6507bd3a2e2SSriharsha Basavapatna 			dmsg = (vio_dring_msg_t *)tag;
6517bd3a2e2SSriharsha Basavapatna 			dmsg->seq_num = ldcp->lane_out.seq_num;
6527bd3a2e2SSriharsha Basavapatna 			data_msg = B_TRUE;
6537bd3a2e2SSriharsha Basavapatna 		} else if (tag->vio_subtype_env == VIO_PKT_DATA) {
6547bd3a2e2SSriharsha Basavapatna 			rmsg = (vio_raw_data_msg_t *)tag;
6557bd3a2e2SSriharsha Basavapatna 			rmsg->seq_num = ldcp->lane_out.seq_num;
6567bd3a2e2SSriharsha Basavapatna 			data_msg = B_TRUE;
6577bd3a2e2SSriharsha Basavapatna 		} else if (tag->vio_subtype_env == VIO_DESC_DATA) {
6587bd3a2e2SSriharsha Basavapatna 			imsg = (vnet_ibnd_desc_t *)tag;
6597bd3a2e2SSriharsha Basavapatna 			imsg->hdr.seq_num = ldcp->lane_out.seq_num;
6607bd3a2e2SSriharsha Basavapatna 			data_msg = B_TRUE;
6617bd3a2e2SSriharsha Basavapatna 		}
6627bd3a2e2SSriharsha Basavapatna 	}
6637bd3a2e2SSriharsha Basavapatna 
6647bd3a2e2SSriharsha Basavapatna 	do {
6657bd3a2e2SSriharsha Basavapatna 		msglen = size;
6667bd3a2e2SSriharsha Basavapatna 		rv = ldc_write(ldcp->ldc_handle, (caddr_t)msgp, &msglen);
6677bd3a2e2SSriharsha Basavapatna 	} while (rv == EWOULDBLOCK && --retries > 0);
6687bd3a2e2SSriharsha Basavapatna 
6697bd3a2e2SSriharsha Basavapatna 	if (rv == 0 && data_msg == B_TRUE) {
6707bd3a2e2SSriharsha Basavapatna 		ldcp->lane_out.seq_num++;
6717bd3a2e2SSriharsha Basavapatna 	}
6727bd3a2e2SSriharsha Basavapatna 
6737bd3a2e2SSriharsha Basavapatna 	if ((rv != 0) || (msglen != size)) {
6747bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "vsw_send_msg:ldc_write failed: chan(%lld) rv(%d) "
6757bd3a2e2SSriharsha Basavapatna 		    "size (%d) msglen(%d)\n", ldcp->ldc_id, rv, size, msglen);
6767bd3a2e2SSriharsha Basavapatna 		ldcp->ldc_stats.oerrors++;
6777bd3a2e2SSriharsha Basavapatna 	}
6787bd3a2e2SSriharsha Basavapatna 
6797bd3a2e2SSriharsha Basavapatna 	mutex_exit(&ldcp->ldc_txlock);
6807bd3a2e2SSriharsha Basavapatna 
6817bd3a2e2SSriharsha Basavapatna 	/*
6827bd3a2e2SSriharsha Basavapatna 	 * If channel has been reset we either handle it here or
6837bd3a2e2SSriharsha Basavapatna 	 * simply report back that it has been reset and let caller
6847bd3a2e2SSriharsha Basavapatna 	 * decide what to do.
6857bd3a2e2SSriharsha Basavapatna 	 */
6867bd3a2e2SSriharsha Basavapatna 	if (rv == ECONNRESET) {
6877bd3a2e2SSriharsha Basavapatna 		DWARN(vswp, "%s (%lld) channel reset", __func__, ldcp->ldc_id);
6887bd3a2e2SSriharsha Basavapatna 
6897bd3a2e2SSriharsha Basavapatna 		if (handle_reset) {
6907bd3a2e2SSriharsha Basavapatna 			vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
6917bd3a2e2SSriharsha Basavapatna 		}
6927bd3a2e2SSriharsha Basavapatna 	}
6937bd3a2e2SSriharsha Basavapatna 
6947bd3a2e2SSriharsha Basavapatna 	return (rv);
6957bd3a2e2SSriharsha Basavapatna }
6967bd3a2e2SSriharsha Basavapatna 
6977bd3a2e2SSriharsha Basavapatna /*
6987bd3a2e2SSriharsha Basavapatna  * A per LDC worker thread to process ldc messages. This thread is woken up by
6997bd3a2e2SSriharsha Basavapatna  * the LDC interrupt handler to process LDC packets and receive data.
7007bd3a2e2SSriharsha Basavapatna  */
7017bd3a2e2SSriharsha Basavapatna void
vsw_ldc_msg_worker(void * arg)7027bd3a2e2SSriharsha Basavapatna vsw_ldc_msg_worker(void *arg)
7037bd3a2e2SSriharsha Basavapatna {
7047bd3a2e2SSriharsha Basavapatna 	callb_cpr_t	cprinfo;
7057bd3a2e2SSriharsha Basavapatna 	vsw_ldc_t	*ldcp = (vsw_ldc_t *)arg;
7067bd3a2e2SSriharsha Basavapatna 	vsw_t		*vswp = ldcp->ldc_vswp;
7077bd3a2e2SSriharsha Basavapatna 
7087bd3a2e2SSriharsha Basavapatna 	D1(vswp, "%s(%lld):enter\n", __func__, ldcp->ldc_id);
7097bd3a2e2SSriharsha Basavapatna 	CALLB_CPR_INIT(&cprinfo, &ldcp->msg_thr_lock, callb_generic_cpr,
7107bd3a2e2SSriharsha Basavapatna 	    "vsw_msg_thread");
7117bd3a2e2SSriharsha Basavapatna 	mutex_enter(&ldcp->msg_thr_lock);
7127bd3a2e2SSriharsha Basavapatna 	while (!(ldcp->msg_thr_flags & VSW_WTHR_STOP)) {
7137bd3a2e2SSriharsha Basavapatna 
7147bd3a2e2SSriharsha Basavapatna 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
7157bd3a2e2SSriharsha Basavapatna 		/*
7167bd3a2e2SSriharsha Basavapatna 		 * Wait until the data is received or a stop
7177bd3a2e2SSriharsha Basavapatna 		 * request is received.
7187bd3a2e2SSriharsha Basavapatna 		 */
7197bd3a2e2SSriharsha Basavapatna 		while (!(ldcp->msg_thr_flags &
7207bd3a2e2SSriharsha Basavapatna 		    (VSW_WTHR_DATARCVD | VSW_WTHR_STOP))) {
7217bd3a2e2SSriharsha Basavapatna 			cv_wait(&ldcp->msg_thr_cv, &ldcp->msg_thr_lock);
7227bd3a2e2SSriharsha Basavapatna 		}
7237bd3a2e2SSriharsha Basavapatna 		CALLB_CPR_SAFE_END(&cprinfo, &ldcp->msg_thr_lock)
7247bd3a2e2SSriharsha Basavapatna 
7257bd3a2e2SSriharsha Basavapatna 		/*
7267bd3a2e2SSriharsha Basavapatna 		 * First process the stop request.
7277bd3a2e2SSriharsha Basavapatna 		 */
7287bd3a2e2SSriharsha Basavapatna 		if (ldcp->msg_thr_flags & VSW_WTHR_STOP) {
7297bd3a2e2SSriharsha Basavapatna 			D2(vswp, "%s(%lld):Rx thread stopped\n",
7307bd3a2e2SSriharsha Basavapatna 			    __func__, ldcp->ldc_id);
7317bd3a2e2SSriharsha Basavapatna 			break;
7327bd3a2e2SSriharsha Basavapatna 		}
7337bd3a2e2SSriharsha Basavapatna 		ldcp->msg_thr_flags &= ~VSW_WTHR_DATARCVD;
7347bd3a2e2SSriharsha Basavapatna 		mutex_exit(&ldcp->msg_thr_lock);
7357bd3a2e2SSriharsha Basavapatna 		D1(vswp, "%s(%lld):calling vsw_process_pkt\n",
7367bd3a2e2SSriharsha Basavapatna 		    __func__, ldcp->ldc_id);
7377bd3a2e2SSriharsha Basavapatna 		mutex_enter(&ldcp->ldc_cblock);
7387bd3a2e2SSriharsha Basavapatna 		vsw_process_pkt(ldcp);
7397bd3a2e2SSriharsha Basavapatna 		mutex_exit(&ldcp->ldc_cblock);
7407bd3a2e2SSriharsha Basavapatna 		mutex_enter(&ldcp->msg_thr_lock);
7417bd3a2e2SSriharsha Basavapatna 	}
7427bd3a2e2SSriharsha Basavapatna 
7437bd3a2e2SSriharsha Basavapatna 	/*
7447bd3a2e2SSriharsha Basavapatna 	 * Update the run status and wakeup the thread that
7457bd3a2e2SSriharsha Basavapatna 	 * has sent the stop request.
7467bd3a2e2SSriharsha Basavapatna 	 */
7477bd3a2e2SSriharsha Basavapatna 	ldcp->msg_thr_flags &= ~VSW_WTHR_STOP;
7487bd3a2e2SSriharsha Basavapatna 	ldcp->msg_thread = NULL;
7497bd3a2e2SSriharsha Basavapatna 	CALLB_CPR_EXIT(&cprinfo);
7507bd3a2e2SSriharsha Basavapatna 	D1(vswp, "%s(%lld):exit\n", __func__, ldcp->ldc_id);
7517bd3a2e2SSriharsha Basavapatna 	thread_exit();
7527bd3a2e2SSriharsha Basavapatna }
7537bd3a2e2SSriharsha Basavapatna 
7547bd3a2e2SSriharsha Basavapatna /* Co-ordinate with msg processing thread to stop it */
7557bd3a2e2SSriharsha Basavapatna void
vsw_stop_msg_thread(vsw_ldc_t * ldcp)7567bd3a2e2SSriharsha Basavapatna vsw_stop_msg_thread(vsw_ldc_t *ldcp)
7577bd3a2e2SSriharsha Basavapatna {
7587bd3a2e2SSriharsha Basavapatna 	kt_did_t	tid = 0;
7597bd3a2e2SSriharsha Basavapatna 	vsw_t		*vswp = ldcp->ldc_vswp;
7607bd3a2e2SSriharsha Basavapatna 
7617bd3a2e2SSriharsha Basavapatna 	D1(vswp, "%s(%lld):enter\n", __func__, ldcp->ldc_id);
7627bd3a2e2SSriharsha Basavapatna 	/*
7637bd3a2e2SSriharsha Basavapatna 	 * Send a stop request by setting the stop flag and
7647bd3a2e2SSriharsha Basavapatna 	 * wait until the msg process thread stops.
7657bd3a2e2SSriharsha Basavapatna 	 */
7667bd3a2e2SSriharsha Basavapatna 	mutex_enter(&ldcp->msg_thr_lock);
7677bd3a2e2SSriharsha Basavapatna 	if (ldcp->msg_thread != NULL) {
7687bd3a2e2SSriharsha Basavapatna 		tid = ldcp->msg_thread->t_did;
7697bd3a2e2SSriharsha Basavapatna 		ldcp->msg_thr_flags |= VSW_WTHR_STOP;
7707bd3a2e2SSriharsha Basavapatna 		cv_signal(&ldcp->msg_thr_cv);
7717bd3a2e2SSriharsha Basavapatna 	}
7727bd3a2e2SSriharsha Basavapatna 	mutex_exit(&ldcp->msg_thr_lock);
7737bd3a2e2SSriharsha Basavapatna 
7747bd3a2e2SSriharsha Basavapatna 	if (tid != 0) {
7757bd3a2e2SSriharsha Basavapatna 		thread_join(tid);
7767bd3a2e2SSriharsha Basavapatna 	}
7777bd3a2e2SSriharsha Basavapatna 	D1(vswp, "%s(%lld):exit\n", __func__, ldcp->ldc_id);
7787bd3a2e2SSriharsha Basavapatna }
7797bd3a2e2SSriharsha Basavapatna 
7807bd3a2e2SSriharsha Basavapatna /*
7817bd3a2e2SSriharsha Basavapatna  * Send packet out via descriptor ring to a logical device.
7827bd3a2e2SSriharsha Basavapatna  */
7837bd3a2e2SSriharsha Basavapatna int
vsw_dringsend(vsw_ldc_t * ldcp,mblk_t * mp)7847bd3a2e2SSriharsha Basavapatna vsw_dringsend(vsw_ldc_t *ldcp, mblk_t *mp)
7857bd3a2e2SSriharsha Basavapatna {
7867bd3a2e2SSriharsha Basavapatna 	vio_dring_msg_t		dring_pkt;
7877bd3a2e2SSriharsha Basavapatna 	dring_info_t		*dp = NULL;
7887bd3a2e2SSriharsha Basavapatna 	vsw_private_desc_t	*priv_desc = NULL;
7897bd3a2e2SSriharsha Basavapatna 	vnet_public_desc_t	*pub = NULL;
7907bd3a2e2SSriharsha Basavapatna 	vsw_t			*vswp = ldcp->ldc_vswp;
7917bd3a2e2SSriharsha Basavapatna 	mblk_t			*bp;
7927bd3a2e2SSriharsha Basavapatna 	size_t			n, size;
7937bd3a2e2SSriharsha Basavapatna 	caddr_t			bufp;
7947bd3a2e2SSriharsha Basavapatna 	int			idx;
7957bd3a2e2SSriharsha Basavapatna 	int			status = LDC_TX_SUCCESS;
7967bd3a2e2SSriharsha Basavapatna 	struct ether_header	*ehp = (struct ether_header *)mp->b_rptr;
7977bd3a2e2SSriharsha Basavapatna 	lane_t			*lp = &ldcp->lane_out;
7987bd3a2e2SSriharsha Basavapatna 
7997bd3a2e2SSriharsha Basavapatna 	D1(vswp, "%s(%lld): enter\n", __func__, ldcp->ldc_id);
8007bd3a2e2SSriharsha Basavapatna 
8017bd3a2e2SSriharsha Basavapatna 	/* TODO: make test a macro */
8027bd3a2e2SSriharsha Basavapatna 	if ((!(ldcp->lane_out.lstate & VSW_LANE_ACTIVE)) ||
803*6e472272SToomas Soome 	    (ldcp->ldc_status != LDC_UP) || (ldcp->ldc_handle == 0)) {
8047bd3a2e2SSriharsha Basavapatna 		DWARN(vswp, "%s(%lld) status(%d) lstate(0x%llx), dropping "
8057bd3a2e2SSriharsha Basavapatna 		    "packet\n", __func__, ldcp->ldc_id, ldcp->ldc_status,
8067bd3a2e2SSriharsha Basavapatna 		    ldcp->lane_out.lstate);
8077bd3a2e2SSriharsha Basavapatna 		ldcp->ldc_stats.oerrors++;
8087bd3a2e2SSriharsha Basavapatna 		return (LDC_TX_FAILURE);
8097bd3a2e2SSriharsha Basavapatna 	}
8107bd3a2e2SSriharsha Basavapatna 
8117bd3a2e2SSriharsha Basavapatna 	if ((dp = ldcp->lane_out.dringp) == NULL) {
8127bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "%s(%lld): no dring for outbound lane on"
8137bd3a2e2SSriharsha Basavapatna 		    " channel %d", __func__, ldcp->ldc_id, ldcp->ldc_id);
8147bd3a2e2SSriharsha Basavapatna 		ldcp->ldc_stats.oerrors++;
8157bd3a2e2SSriharsha Basavapatna 		return (LDC_TX_FAILURE);
8167bd3a2e2SSriharsha Basavapatna 	}
8177bd3a2e2SSriharsha Basavapatna 
8187bd3a2e2SSriharsha Basavapatna 	size = msgsize(mp);
8197bd3a2e2SSriharsha Basavapatna 	if (size > (size_t)lp->mtu) {
8207bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "%s(%lld) invalid size (%ld)\n", __func__,
8217bd3a2e2SSriharsha Basavapatna 		    ldcp->ldc_id, size);
8227bd3a2e2SSriharsha Basavapatna 		ldcp->ldc_stats.oerrors++;
8237bd3a2e2SSriharsha Basavapatna 		return (LDC_TX_FAILURE);
8247bd3a2e2SSriharsha Basavapatna 	}
8257bd3a2e2SSriharsha Basavapatna 
8267bd3a2e2SSriharsha Basavapatna 	/*
8277bd3a2e2SSriharsha Basavapatna 	 * Find a free descriptor
8287bd3a2e2SSriharsha Basavapatna 	 *
8297bd3a2e2SSriharsha Basavapatna 	 * Note: for the moment we are assuming that we will only
8307bd3a2e2SSriharsha Basavapatna 	 * have one dring going from the switch to each of its
8317bd3a2e2SSriharsha Basavapatna 	 * peers. This may change in the future.
8327bd3a2e2SSriharsha Basavapatna 	 */
8337bd3a2e2SSriharsha Basavapatna 	if (vsw_dring_find_free_desc(dp, &priv_desc, &idx) != 0) {
8347bd3a2e2SSriharsha Basavapatna 		D2(vswp, "%s(%lld): no descriptor available for ring "
8357bd3a2e2SSriharsha Basavapatna 		    "at 0x%llx", __func__, ldcp->ldc_id, dp);
8367bd3a2e2SSriharsha Basavapatna 
8377bd3a2e2SSriharsha Basavapatna 		/* nothing more we can do */
8387bd3a2e2SSriharsha Basavapatna 		status = LDC_TX_NORESOURCES;
8397bd3a2e2SSriharsha Basavapatna 		ldcp->ldc_stats.tx_no_desc++;
8407bd3a2e2SSriharsha Basavapatna 		goto vsw_dringsend_free_exit;
8417bd3a2e2SSriharsha Basavapatna 	} else {
8427bd3a2e2SSriharsha Basavapatna 		D2(vswp, "%s(%lld): free private descriptor found at pos %ld "
8437bd3a2e2SSriharsha Basavapatna 		    "addr 0x%llx\n", __func__, ldcp->ldc_id, idx, priv_desc);
8447bd3a2e2SSriharsha Basavapatna 	}
8457bd3a2e2SSriharsha Basavapatna 
8467bd3a2e2SSriharsha Basavapatna 	/* copy data into the descriptor */
8477bd3a2e2SSriharsha Basavapatna 	bufp = priv_desc->datap;
8487bd3a2e2SSriharsha Basavapatna 	bufp += VNET_IPALIGN;
8497bd3a2e2SSriharsha Basavapatna 	for (bp = mp, n = 0; bp != NULL; bp = bp->b_cont) {
8507bd3a2e2SSriharsha Basavapatna 		n = MBLKL(bp);
8517bd3a2e2SSriharsha Basavapatna 		bcopy(bp->b_rptr, bufp, n);
8527bd3a2e2SSriharsha Basavapatna 		bufp += n;
8537bd3a2e2SSriharsha Basavapatna 	}
8547bd3a2e2SSriharsha Basavapatna 
8557bd3a2e2SSriharsha Basavapatna 	priv_desc->datalen = (size < (size_t)ETHERMIN) ? ETHERMIN : size;
8567bd3a2e2SSriharsha Basavapatna 
8577bd3a2e2SSriharsha Basavapatna 	pub = priv_desc->descp;
8587bd3a2e2SSriharsha Basavapatna 	pub->nbytes = priv_desc->datalen;
8597bd3a2e2SSriharsha Basavapatna 
8607bd3a2e2SSriharsha Basavapatna 	/* update statistics */
8617bd3a2e2SSriharsha Basavapatna 	if (IS_BROADCAST(ehp))
8627bd3a2e2SSriharsha Basavapatna 		ldcp->ldc_stats.brdcstxmt++;
8637bd3a2e2SSriharsha Basavapatna 	else if (IS_MULTICAST(ehp))
8647bd3a2e2SSriharsha Basavapatna 		ldcp->ldc_stats.multixmt++;
8657bd3a2e2SSriharsha Basavapatna 	ldcp->ldc_stats.opackets++;
8667bd3a2e2SSriharsha Basavapatna 	ldcp->ldc_stats.obytes += priv_desc->datalen;
8677bd3a2e2SSriharsha Basavapatna 
8687bd3a2e2SSriharsha Basavapatna 	mutex_enter(&priv_desc->dstate_lock);
8697bd3a2e2SSriharsha Basavapatna 	pub->hdr.dstate = VIO_DESC_READY;
8707bd3a2e2SSriharsha Basavapatna 	mutex_exit(&priv_desc->dstate_lock);
8717bd3a2e2SSriharsha Basavapatna 
8727bd3a2e2SSriharsha Basavapatna 	/*
8737bd3a2e2SSriharsha Basavapatna 	 * Determine whether or not we need to send a message to our
8747bd3a2e2SSriharsha Basavapatna 	 * peer prompting them to read our newly updated descriptor(s).
8757bd3a2e2SSriharsha Basavapatna 	 */
8767bd3a2e2SSriharsha Basavapatna 	mutex_enter(&dp->restart_lock);
8777bd3a2e2SSriharsha Basavapatna 	if (dp->restart_reqd) {
8787bd3a2e2SSriharsha Basavapatna 		dp->restart_reqd = B_FALSE;
8797bd3a2e2SSriharsha Basavapatna 		ldcp->ldc_stats.dring_data_msgs_sent++;
8807bd3a2e2SSriharsha Basavapatna 		mutex_exit(&dp->restart_lock);
8817bd3a2e2SSriharsha Basavapatna 
8827bd3a2e2SSriharsha Basavapatna 		/*
8837bd3a2e2SSriharsha Basavapatna 		 * Send a vio_dring_msg to peer to prompt them to read
8847bd3a2e2SSriharsha Basavapatna 		 * the updated descriptor ring.
8857bd3a2e2SSriharsha Basavapatna 		 */
8867bd3a2e2SSriharsha Basavapatna 		dring_pkt.tag.vio_msgtype = VIO_TYPE_DATA;
8877bd3a2e2SSriharsha Basavapatna 		dring_pkt.tag.vio_subtype = VIO_SUBTYPE_INFO;
8887bd3a2e2SSriharsha Basavapatna 		dring_pkt.tag.vio_subtype_env = VIO_DRING_DATA;
8897bd3a2e2SSriharsha Basavapatna 		dring_pkt.tag.vio_sid = ldcp->local_session;
8907bd3a2e2SSriharsha Basavapatna 
8917bd3a2e2SSriharsha Basavapatna 		/* Note - for now using first ring */
8927bd3a2e2SSriharsha Basavapatna 		dring_pkt.dring_ident = dp->ident;
8937bd3a2e2SSriharsha Basavapatna 
8947bd3a2e2SSriharsha Basavapatna 		/*
8957bd3a2e2SSriharsha Basavapatna 		 * If last_ack_recv is -1 then we know we've not
8967bd3a2e2SSriharsha Basavapatna 		 * received any ack's yet, so this must be the first
8977bd3a2e2SSriharsha Basavapatna 		 * msg sent, so set the start to the begining of the ring.
8987bd3a2e2SSriharsha Basavapatna 		 */
8997bd3a2e2SSriharsha Basavapatna 		mutex_enter(&dp->dlock);
9007bd3a2e2SSriharsha Basavapatna 		if (dp->last_ack_recv == -1) {
9017bd3a2e2SSriharsha Basavapatna 			dring_pkt.start_idx = 0;
9027bd3a2e2SSriharsha Basavapatna 		} else {
9037bd3a2e2SSriharsha Basavapatna 			dring_pkt.start_idx =
9047bd3a2e2SSriharsha Basavapatna 			    (dp->last_ack_recv + 1) % dp->num_descriptors;
9057bd3a2e2SSriharsha Basavapatna 		}
9067bd3a2e2SSriharsha Basavapatna 		dring_pkt.end_idx = -1;
9077bd3a2e2SSriharsha Basavapatna 		mutex_exit(&dp->dlock);
9087bd3a2e2SSriharsha Basavapatna 
9097bd3a2e2SSriharsha Basavapatna 		D3(vswp, "%s(%lld): dring 0x%llx : ident 0x%llx\n", __func__,
9107bd3a2e2SSriharsha Basavapatna 		    ldcp->ldc_id, dp, dring_pkt.dring_ident);
9117bd3a2e2SSriharsha Basavapatna 		D3(vswp, "%s(%lld): start %lld : end %lld :\n",
9127bd3a2e2SSriharsha Basavapatna 		    __func__, ldcp->ldc_id, dring_pkt.start_idx,
9137bd3a2e2SSriharsha Basavapatna 		    dring_pkt.end_idx);
9147bd3a2e2SSriharsha Basavapatna 
9157bd3a2e2SSriharsha Basavapatna 		(void) vsw_send_msg(ldcp, (void *)&dring_pkt,
9167bd3a2e2SSriharsha Basavapatna 		    sizeof (vio_dring_msg_t), B_TRUE);
9177bd3a2e2SSriharsha Basavapatna 
9187bd3a2e2SSriharsha Basavapatna 		return (status);
9197bd3a2e2SSriharsha Basavapatna 
9207bd3a2e2SSriharsha Basavapatna 	} else {
9217bd3a2e2SSriharsha Basavapatna 		mutex_exit(&dp->restart_lock);
9227bd3a2e2SSriharsha Basavapatna 		D2(vswp, "%s(%lld): updating descp %d", __func__,
9237bd3a2e2SSriharsha Basavapatna 		    ldcp->ldc_id, idx);
9247bd3a2e2SSriharsha Basavapatna 	}
9257bd3a2e2SSriharsha Basavapatna 
9267bd3a2e2SSriharsha Basavapatna vsw_dringsend_free_exit:
9277bd3a2e2SSriharsha Basavapatna 
9287bd3a2e2SSriharsha Basavapatna 	D1(vswp, "%s(%lld): exit\n", __func__, ldcp->ldc_id);
9297bd3a2e2SSriharsha Basavapatna 	return (status);
9307bd3a2e2SSriharsha Basavapatna }
9317bd3a2e2SSriharsha Basavapatna 
9327bd3a2e2SSriharsha Basavapatna /*
9337bd3a2e2SSriharsha Basavapatna  * Searches the private section of a ring for a free descriptor,
9347bd3a2e2SSriharsha Basavapatna  * starting at the location of the last free descriptor found
9357bd3a2e2SSriharsha Basavapatna  * previously.
9367bd3a2e2SSriharsha Basavapatna  *
9377bd3a2e2SSriharsha Basavapatna  * Returns 0 if free descriptor is available, and updates state
9387bd3a2e2SSriharsha Basavapatna  * of private descriptor to VIO_DESC_READY,  otherwise returns 1.
9397bd3a2e2SSriharsha Basavapatna  *
9407bd3a2e2SSriharsha Basavapatna  * FUTURE: might need to return contiguous range of descriptors
9417bd3a2e2SSriharsha Basavapatna  * as dring info msg assumes all will be contiguous.
9427bd3a2e2SSriharsha Basavapatna  */
9437bd3a2e2SSriharsha Basavapatna int
vsw_dring_find_free_desc(dring_info_t * dringp,vsw_private_desc_t ** priv_p,int * idx)9447bd3a2e2SSriharsha Basavapatna vsw_dring_find_free_desc(dring_info_t *dringp,
945*6e472272SToomas Soome     vsw_private_desc_t **priv_p, int *idx)
9467bd3a2e2SSriharsha Basavapatna {
9477bd3a2e2SSriharsha Basavapatna 	vsw_private_desc_t	*addr = NULL;
9487bd3a2e2SSriharsha Basavapatna 	int			num = vsw_num_descriptors;
9497bd3a2e2SSriharsha Basavapatna 	int			ret = 1;
9507bd3a2e2SSriharsha Basavapatna 
9517bd3a2e2SSriharsha Basavapatna 	D1(NULL, "%s enter\n", __func__);
9527bd3a2e2SSriharsha Basavapatna 
9537bd3a2e2SSriharsha Basavapatna 	ASSERT(dringp->priv_addr != NULL);
9547bd3a2e2SSriharsha Basavapatna 
9557bd3a2e2SSriharsha Basavapatna 	D2(NULL, "%s: searching ring, dringp 0x%llx : start pos %lld",
9567bd3a2e2SSriharsha Basavapatna 	    __func__, dringp, dringp->end_idx);
9577bd3a2e2SSriharsha Basavapatna 
9587bd3a2e2SSriharsha Basavapatna 	addr = (vsw_private_desc_t *)dringp->priv_addr + dringp->end_idx;
9597bd3a2e2SSriharsha Basavapatna 
9607bd3a2e2SSriharsha Basavapatna 	mutex_enter(&addr->dstate_lock);
9617bd3a2e2SSriharsha Basavapatna 	if (addr->dstate == VIO_DESC_FREE) {
9627bd3a2e2SSriharsha Basavapatna 		addr->dstate = VIO_DESC_READY;
9637bd3a2e2SSriharsha Basavapatna 		*priv_p = addr;
9647bd3a2e2SSriharsha Basavapatna 		*idx = dringp->end_idx;
9657bd3a2e2SSriharsha Basavapatna 		dringp->end_idx = (dringp->end_idx + 1) % num;
9667bd3a2e2SSriharsha Basavapatna 		ret = 0;
9677bd3a2e2SSriharsha Basavapatna 
9687bd3a2e2SSriharsha Basavapatna 	}
9697bd3a2e2SSriharsha Basavapatna 	mutex_exit(&addr->dstate_lock);
9707bd3a2e2SSriharsha Basavapatna 
9717bd3a2e2SSriharsha Basavapatna 	/* ring full */
9727bd3a2e2SSriharsha Basavapatna 	if (ret == 1) {
9737bd3a2e2SSriharsha Basavapatna 		D2(NULL, "%s: no desp free: started at %d", __func__,
9747bd3a2e2SSriharsha Basavapatna 		    dringp->end_idx);
9757bd3a2e2SSriharsha Basavapatna 	}
9767bd3a2e2SSriharsha Basavapatna 
9777bd3a2e2SSriharsha Basavapatna 	D1(NULL, "%s: exit\n", __func__);
9787bd3a2e2SSriharsha Basavapatna 
9797bd3a2e2SSriharsha Basavapatna 	return (ret);
9807bd3a2e2SSriharsha Basavapatna }
9817bd3a2e2SSriharsha Basavapatna 
9827bd3a2e2SSriharsha Basavapatna /* vsw_reclaim_dring -- reclaim descriptors */
9837bd3a2e2SSriharsha Basavapatna int
vsw_reclaim_dring(dring_info_t * dp,int start)9847bd3a2e2SSriharsha Basavapatna vsw_reclaim_dring(dring_info_t *dp, int start)
9857bd3a2e2SSriharsha Basavapatna {
9867bd3a2e2SSriharsha Basavapatna 	int i, j, len;
9877bd3a2e2SSriharsha Basavapatna 	vsw_private_desc_t *priv_addr;
9887bd3a2e2SSriharsha Basavapatna 	vnet_public_desc_t *pub_addr;
9897bd3a2e2SSriharsha Basavapatna 
9907bd3a2e2SSriharsha Basavapatna 	pub_addr = (vnet_public_desc_t *)dp->pub_addr;
9917bd3a2e2SSriharsha Basavapatna 	priv_addr = (vsw_private_desc_t *)dp->priv_addr;
9927bd3a2e2SSriharsha Basavapatna 	len = dp->num_descriptors;
9937bd3a2e2SSriharsha Basavapatna 
9947bd3a2e2SSriharsha Basavapatna 	D2(NULL, "%s: start index %ld\n", __func__, start);
9957bd3a2e2SSriharsha Basavapatna 
9967bd3a2e2SSriharsha Basavapatna 	j = 0;
9977bd3a2e2SSriharsha Basavapatna 	for (i = start; j < len; i = (i + 1) % len, j++) {
9987bd3a2e2SSriharsha Basavapatna 		pub_addr = (vnet_public_desc_t *)dp->pub_addr + i;
9997bd3a2e2SSriharsha Basavapatna 		priv_addr = (vsw_private_desc_t *)dp->priv_addr + i;
10007bd3a2e2SSriharsha Basavapatna 
10017bd3a2e2SSriharsha Basavapatna 		mutex_enter(&priv_addr->dstate_lock);
10027bd3a2e2SSriharsha Basavapatna 		if (pub_addr->hdr.dstate != VIO_DESC_DONE) {
10037bd3a2e2SSriharsha Basavapatna 			mutex_exit(&priv_addr->dstate_lock);
10047bd3a2e2SSriharsha Basavapatna 			break;
10057bd3a2e2SSriharsha Basavapatna 		}
10067bd3a2e2SSriharsha Basavapatna 		pub_addr->hdr.dstate = VIO_DESC_FREE;
10077bd3a2e2SSriharsha Basavapatna 		priv_addr->dstate = VIO_DESC_FREE;
10087bd3a2e2SSriharsha Basavapatna 		/* clear all the fields */
10097bd3a2e2SSriharsha Basavapatna 		priv_addr->datalen = 0;
10107bd3a2e2SSriharsha Basavapatna 		pub_addr->hdr.ack = 0;
10117bd3a2e2SSriharsha Basavapatna 		mutex_exit(&priv_addr->dstate_lock);
10127bd3a2e2SSriharsha Basavapatna 
10137bd3a2e2SSriharsha Basavapatna 		D3(NULL, "claiming descp:%d pub state:0x%llx priv state 0x%llx",
10147bd3a2e2SSriharsha Basavapatna 		    i, pub_addr->hdr.dstate, priv_addr->dstate);
10157bd3a2e2SSriharsha Basavapatna 	}
10167bd3a2e2SSriharsha Basavapatna 	return (j);
10177bd3a2e2SSriharsha Basavapatna }
10187bd3a2e2SSriharsha Basavapatna 
10197bd3a2e2SSriharsha Basavapatna void
vsw_process_dringdata(void * arg,void * dpkt)10207bd3a2e2SSriharsha Basavapatna vsw_process_dringdata(void *arg, void *dpkt)
10217bd3a2e2SSriharsha Basavapatna {
10227bd3a2e2SSriharsha Basavapatna 	vsw_ldc_t		*ldcp = arg;
10237bd3a2e2SSriharsha Basavapatna 	vio_dring_msg_t		*dring_pkt;
10247bd3a2e2SSriharsha Basavapatna 	vnet_public_desc_t	desc, *pub_addr = NULL;
10257bd3a2e2SSriharsha Basavapatna 	vsw_private_desc_t	*priv_addr = NULL;
10267bd3a2e2SSriharsha Basavapatna 	dring_info_t		*dp = NULL;
10277bd3a2e2SSriharsha Basavapatna 	vsw_t			*vswp = ldcp->ldc_vswp;
10287bd3a2e2SSriharsha Basavapatna 	mblk_t			*mp = NULL;
10297bd3a2e2SSriharsha Basavapatna 	vio_mblk_t		*vmp = NULL;
10307bd3a2e2SSriharsha Basavapatna 	mblk_t			*bp = NULL;
10317bd3a2e2SSriharsha Basavapatna 	mblk_t			*bpt = NULL;
10327bd3a2e2SSriharsha Basavapatna 	size_t			nbytes = 0;
10337bd3a2e2SSriharsha Basavapatna 	uint64_t		chain = 0;
10347bd3a2e2SSriharsha Basavapatna 	uint64_t		len;
10357bd3a2e2SSriharsha Basavapatna 	uint32_t		pos, start;
10367bd3a2e2SSriharsha Basavapatna 	uint32_t		range_start, range_end;
10377bd3a2e2SSriharsha Basavapatna 	int32_t			end, num, cnt = 0;
10387bd3a2e2SSriharsha Basavapatna 	int			i, rv, rng_rv = 0, msg_rv = 0;
10397bd3a2e2SSriharsha Basavapatna 	boolean_t		prev_desc_ack = B_FALSE;
10407bd3a2e2SSriharsha Basavapatna 	int			read_attempts = 0;
10417bd3a2e2SSriharsha Basavapatna 	struct ether_header	*ehp;
10427bd3a2e2SSriharsha Basavapatna 	lane_t			*lp = &ldcp->lane_out;
10437bd3a2e2SSriharsha Basavapatna 
10447bd3a2e2SSriharsha Basavapatna 	D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
10457bd3a2e2SSriharsha Basavapatna 
10467bd3a2e2SSriharsha Basavapatna 	/*
10477bd3a2e2SSriharsha Basavapatna 	 * We know this is a data/dring packet so
10487bd3a2e2SSriharsha Basavapatna 	 * cast it into the correct structure.
10497bd3a2e2SSriharsha Basavapatna 	 */
10507bd3a2e2SSriharsha Basavapatna 	dring_pkt = (vio_dring_msg_t *)dpkt;
10517bd3a2e2SSriharsha Basavapatna 
10527bd3a2e2SSriharsha Basavapatna 	/*
10537bd3a2e2SSriharsha Basavapatna 	 * Switch on the vio_subtype. If its INFO then we need to
10547bd3a2e2SSriharsha Basavapatna 	 * process the data. If its an ACK we need to make sure
10557bd3a2e2SSriharsha Basavapatna 	 * it makes sense (i.e did we send an earlier data/info),
10567bd3a2e2SSriharsha Basavapatna 	 * and if its a NACK then we maybe attempt a retry.
10577bd3a2e2SSriharsha Basavapatna 	 */
10587bd3a2e2SSriharsha Basavapatna 	switch (dring_pkt->tag.vio_subtype) {
10597bd3a2e2SSriharsha Basavapatna 	case VIO_SUBTYPE_INFO:
10607bd3a2e2SSriharsha Basavapatna 		D2(vswp, "%s(%lld): VIO_SUBTYPE_INFO", __func__, ldcp->ldc_id);
10617bd3a2e2SSriharsha Basavapatna 
10627bd3a2e2SSriharsha Basavapatna 		dp = ldcp->lane_in.dringp;
10637bd3a2e2SSriharsha Basavapatna 		if (dp->ident != dring_pkt->dring_ident) {
10647bd3a2e2SSriharsha Basavapatna 			DERR(vswp, "%s(%lld): unable to find dring from "
10657bd3a2e2SSriharsha Basavapatna 			    "ident 0x%llx", __func__, ldcp->ldc_id,
10667bd3a2e2SSriharsha Basavapatna 			    dring_pkt->dring_ident);
10677bd3a2e2SSriharsha Basavapatna 
10687bd3a2e2SSriharsha Basavapatna 			SND_DRING_NACK(ldcp, dring_pkt);
10697bd3a2e2SSriharsha Basavapatna 			return;
10707bd3a2e2SSriharsha Basavapatna 		}
10717bd3a2e2SSriharsha Basavapatna 
10727bd3a2e2SSriharsha Basavapatna 		ldcp->ldc_stats.dring_data_msgs_rcvd++;
10737bd3a2e2SSriharsha Basavapatna 
10747bd3a2e2SSriharsha Basavapatna 		start = pos = dring_pkt->start_idx;
10757bd3a2e2SSriharsha Basavapatna 		end = dring_pkt->end_idx;
10767bd3a2e2SSriharsha Basavapatna 		len = dp->num_descriptors;
10777bd3a2e2SSriharsha Basavapatna 
10787bd3a2e2SSriharsha Basavapatna 		range_start = range_end = pos;
10797bd3a2e2SSriharsha Basavapatna 
10807bd3a2e2SSriharsha Basavapatna 		D2(vswp, "%s(%lld): start index %ld : end %ld\n",
10817bd3a2e2SSriharsha Basavapatna 		    __func__, ldcp->ldc_id, start, end);
10827bd3a2e2SSriharsha Basavapatna 
10837bd3a2e2SSriharsha Basavapatna 		if (end == -1) {
10847bd3a2e2SSriharsha Basavapatna 			num = -1;
10857bd3a2e2SSriharsha Basavapatna 		} else if (end >= 0) {
10867bd3a2e2SSriharsha Basavapatna 			num = end >= pos ? end - pos + 1: (len - pos + 1) + end;
10877bd3a2e2SSriharsha Basavapatna 
10887bd3a2e2SSriharsha Basavapatna 			/* basic sanity check */
10897bd3a2e2SSriharsha Basavapatna 			if (end > len) {
10907bd3a2e2SSriharsha Basavapatna 				DERR(vswp, "%s(%lld): endpoint %lld outside "
10917bd3a2e2SSriharsha Basavapatna 				    "ring length %lld", __func__,
10927bd3a2e2SSriharsha Basavapatna 				    ldcp->ldc_id, end, len);
10937bd3a2e2SSriharsha Basavapatna 
10947bd3a2e2SSriharsha Basavapatna 				SND_DRING_NACK(ldcp, dring_pkt);
10957bd3a2e2SSriharsha Basavapatna 				return;
10967bd3a2e2SSriharsha Basavapatna 			}
10977bd3a2e2SSriharsha Basavapatna 		} else {
10987bd3a2e2SSriharsha Basavapatna 			DERR(vswp, "%s(%lld): invalid endpoint %lld",
10997bd3a2e2SSriharsha Basavapatna 			    __func__, ldcp->ldc_id, end);
11007bd3a2e2SSriharsha Basavapatna 			SND_DRING_NACK(ldcp, dring_pkt);
11017bd3a2e2SSriharsha Basavapatna 			return;
11027bd3a2e2SSriharsha Basavapatna 		}
11037bd3a2e2SSriharsha Basavapatna 
11047bd3a2e2SSriharsha Basavapatna 		while (cnt != num) {
11057bd3a2e2SSriharsha Basavapatna vsw_recheck_desc:
11067bd3a2e2SSriharsha Basavapatna 			pub_addr = (vnet_public_desc_t *)dp->pub_addr + pos;
11077bd3a2e2SSriharsha Basavapatna 
11087bd3a2e2SSriharsha Basavapatna 			if ((rng_rv = vnet_dring_entry_copy(pub_addr,
11097bd3a2e2SSriharsha Basavapatna 			    &desc, dp->dring_mtype, dp->dring_handle,
11107bd3a2e2SSriharsha Basavapatna 			    pos, pos)) != 0) {
11117bd3a2e2SSriharsha Basavapatna 				DERR(vswp, "%s(%lld): unable to copy "
11127bd3a2e2SSriharsha Basavapatna 				    "descriptor at pos %d: err %d",
11137bd3a2e2SSriharsha Basavapatna 				    __func__, pos, ldcp->ldc_id, rng_rv);
11147bd3a2e2SSriharsha Basavapatna 				ldcp->ldc_stats.ierrors++;
11157bd3a2e2SSriharsha Basavapatna 				break;
11167bd3a2e2SSriharsha Basavapatna 			}
11177bd3a2e2SSriharsha Basavapatna 
11187bd3a2e2SSriharsha Basavapatna 			/*
11197bd3a2e2SSriharsha Basavapatna 			 * When given a bounded range of descriptors
11207bd3a2e2SSriharsha Basavapatna 			 * to process, its an error to hit a descriptor
11217bd3a2e2SSriharsha Basavapatna 			 * which is not ready. In the non-bounded case
11227bd3a2e2SSriharsha Basavapatna 			 * (end_idx == -1) this simply indicates we have
11237bd3a2e2SSriharsha Basavapatna 			 * reached the end of the current active range.
11247bd3a2e2SSriharsha Basavapatna 			 */
11257bd3a2e2SSriharsha Basavapatna 			if (desc.hdr.dstate != VIO_DESC_READY) {
11267bd3a2e2SSriharsha Basavapatna 				/* unbound - no error */
11277bd3a2e2SSriharsha Basavapatna 				if (end == -1) {
11287bd3a2e2SSriharsha Basavapatna 					if (read_attempts == vsw_recv_retries)
11297bd3a2e2SSriharsha Basavapatna 						break;
11307bd3a2e2SSriharsha Basavapatna 
11317bd3a2e2SSriharsha Basavapatna 					delay(drv_usectohz(vsw_recv_delay));
11327bd3a2e2SSriharsha Basavapatna 					read_attempts++;
11337bd3a2e2SSriharsha Basavapatna 					goto vsw_recheck_desc;
11347bd3a2e2SSriharsha Basavapatna 				}
11357bd3a2e2SSriharsha Basavapatna 
11367bd3a2e2SSriharsha Basavapatna 				/* bounded - error - so NACK back */
11377bd3a2e2SSriharsha Basavapatna 				DERR(vswp, "%s(%lld): descriptor not READY "
11387bd3a2e2SSriharsha Basavapatna 				    "(%d)", __func__, ldcp->ldc_id,
11397bd3a2e2SSriharsha Basavapatna 				    desc.hdr.dstate);
11407bd3a2e2SSriharsha Basavapatna 				SND_DRING_NACK(ldcp, dring_pkt);
11417bd3a2e2SSriharsha Basavapatna 				return;
11427bd3a2e2SSriharsha Basavapatna 			}
11437bd3a2e2SSriharsha Basavapatna 
11447bd3a2e2SSriharsha Basavapatna 			DTRACE_PROBE1(read_attempts, int, read_attempts);
11457bd3a2e2SSriharsha Basavapatna 
11467bd3a2e2SSriharsha Basavapatna 			range_end = pos;
11477bd3a2e2SSriharsha Basavapatna 
11487bd3a2e2SSriharsha Basavapatna 			/*
11497bd3a2e2SSriharsha Basavapatna 			 * If we ACK'd the previous descriptor then now
11507bd3a2e2SSriharsha Basavapatna 			 * record the new range start position for later
11517bd3a2e2SSriharsha Basavapatna 			 * ACK's.
11527bd3a2e2SSriharsha Basavapatna 			 */
11537bd3a2e2SSriharsha Basavapatna 			if (prev_desc_ack) {
11547bd3a2e2SSriharsha Basavapatna 				range_start = pos;
11557bd3a2e2SSriharsha Basavapatna 
11567bd3a2e2SSriharsha Basavapatna 				D2(vswp, "%s(%lld): updating range start to be "
11577bd3a2e2SSriharsha Basavapatna 				    "%d", __func__, ldcp->ldc_id, range_start);
11587bd3a2e2SSriharsha Basavapatna 
11597bd3a2e2SSriharsha Basavapatna 				prev_desc_ack = B_FALSE;
11607bd3a2e2SSriharsha Basavapatna 			}
11617bd3a2e2SSriharsha Basavapatna 
11627bd3a2e2SSriharsha Basavapatna 			D2(vswp, "%s(%lld): processing desc %lld at pos"
11637bd3a2e2SSriharsha Basavapatna 			    " 0x%llx : dstate 0x%lx : datalen 0x%lx",
11647bd3a2e2SSriharsha Basavapatna 			    __func__, ldcp->ldc_id, pos, &desc,
11657bd3a2e2SSriharsha Basavapatna 			    desc.hdr.dstate, desc.nbytes);
11667bd3a2e2SSriharsha Basavapatna 
11677bd3a2e2SSriharsha Basavapatna 			if ((desc.nbytes < ETHERMIN) ||
11687bd3a2e2SSriharsha Basavapatna 			    (desc.nbytes > lp->mtu)) {
11697bd3a2e2SSriharsha Basavapatna 				/* invalid size; drop the packet */
11707bd3a2e2SSriharsha Basavapatna 				ldcp->ldc_stats.ierrors++;
11717bd3a2e2SSriharsha Basavapatna 				goto vsw_process_desc_done;
11727bd3a2e2SSriharsha Basavapatna 			}
11737bd3a2e2SSriharsha Basavapatna 
11747bd3a2e2SSriharsha Basavapatna 			/*
11757bd3a2e2SSriharsha Basavapatna 			 * Ensure that we ask ldc for an aligned
11767bd3a2e2SSriharsha Basavapatna 			 * number of bytes. Data is padded to align on 8
11777bd3a2e2SSriharsha Basavapatna 			 * byte boundary, desc.nbytes is actual data length,
11787bd3a2e2SSriharsha Basavapatna 			 * i.e. minus that padding.
11797bd3a2e2SSriharsha Basavapatna 			 */
11807bd3a2e2SSriharsha Basavapatna 			nbytes = (desc.nbytes + VNET_IPALIGN + 7) & ~7;
11817bd3a2e2SSriharsha Basavapatna 			if (nbytes > ldcp->max_rxpool_size) {
11827bd3a2e2SSriharsha Basavapatna 				mp = allocb(desc.nbytes + VNET_IPALIGN + 8,
11837bd3a2e2SSriharsha Basavapatna 				    BPRI_MED);
11847bd3a2e2SSriharsha Basavapatna 				vmp = NULL;
11857bd3a2e2SSriharsha Basavapatna 			} else {
11867bd3a2e2SSriharsha Basavapatna 				vmp = vio_multipool_allocb(&ldcp->vmp, nbytes);
11877bd3a2e2SSriharsha Basavapatna 				if (vmp == NULL) {
11887bd3a2e2SSriharsha Basavapatna 					ldcp->ldc_stats.rx_vio_allocb_fail++;
11897bd3a2e2SSriharsha Basavapatna 					/*
11907bd3a2e2SSriharsha Basavapatna 					 * No free receive buffers available,
11917bd3a2e2SSriharsha Basavapatna 					 * so fallback onto allocb(9F). Make
11927bd3a2e2SSriharsha Basavapatna 					 * sure that we get a data buffer which
11937bd3a2e2SSriharsha Basavapatna 					 * is a multiple of 8 as this is
11947bd3a2e2SSriharsha Basavapatna 					 * required by ldc_mem_copy.
11957bd3a2e2SSriharsha Basavapatna 					 */
11967bd3a2e2SSriharsha Basavapatna 					DTRACE_PROBE(allocb);
11977bd3a2e2SSriharsha Basavapatna 					mp = allocb(desc.nbytes +
11987bd3a2e2SSriharsha Basavapatna 					    VNET_IPALIGN + 8, BPRI_MED);
11997bd3a2e2SSriharsha Basavapatna 				} else {
12007bd3a2e2SSriharsha Basavapatna 					mp = vmp->mp;
12017bd3a2e2SSriharsha Basavapatna 				}
12027bd3a2e2SSriharsha Basavapatna 			}
12037bd3a2e2SSriharsha Basavapatna 			if (mp == NULL) {
12047bd3a2e2SSriharsha Basavapatna 				DERR(vswp, "%s(%ld): allocb failed",
12057bd3a2e2SSriharsha Basavapatna 				    __func__, ldcp->ldc_id);
12067bd3a2e2SSriharsha Basavapatna 				rng_rv = vnet_dring_entry_set_dstate(pub_addr,
12077bd3a2e2SSriharsha Basavapatna 				    dp->dring_mtype, dp->dring_handle, pos, pos,
12087bd3a2e2SSriharsha Basavapatna 				    VIO_DESC_DONE);
12097bd3a2e2SSriharsha Basavapatna 				ldcp->ldc_stats.ierrors++;
12107bd3a2e2SSriharsha Basavapatna 				ldcp->ldc_stats.rx_allocb_fail++;
12117bd3a2e2SSriharsha Basavapatna 				break;
12127bd3a2e2SSriharsha Basavapatna 			}
12137bd3a2e2SSriharsha Basavapatna 
12147bd3a2e2SSriharsha Basavapatna 			rv = ldc_mem_copy(ldcp->ldc_handle,
12157bd3a2e2SSriharsha Basavapatna 			    (caddr_t)mp->b_rptr, 0, &nbytes,
12167bd3a2e2SSriharsha Basavapatna 			    desc.memcookie, desc.ncookies, LDC_COPY_IN);
12177bd3a2e2SSriharsha Basavapatna 			if (rv != 0) {
12187bd3a2e2SSriharsha Basavapatna 				DERR(vswp, "%s(%d): unable to copy in data "
12197bd3a2e2SSriharsha Basavapatna 				    "from %d cookies in desc %d (rv %d)",
12207bd3a2e2SSriharsha Basavapatna 				    __func__, ldcp->ldc_id, desc.ncookies,
12217bd3a2e2SSriharsha Basavapatna 				    pos, rv);
12227bd3a2e2SSriharsha Basavapatna 				freemsg(mp);
12237bd3a2e2SSriharsha Basavapatna 
12247bd3a2e2SSriharsha Basavapatna 				rng_rv = vnet_dring_entry_set_dstate(pub_addr,
12257bd3a2e2SSriharsha Basavapatna 				    dp->dring_mtype, dp->dring_handle, pos, pos,
12267bd3a2e2SSriharsha Basavapatna 				    VIO_DESC_DONE);
12277bd3a2e2SSriharsha Basavapatna 				ldcp->ldc_stats.ierrors++;
12287bd3a2e2SSriharsha Basavapatna 				break;
12297bd3a2e2SSriharsha Basavapatna 			} else {
12307bd3a2e2SSriharsha Basavapatna 				D2(vswp, "%s(%d): copied in %ld bytes"
12317bd3a2e2SSriharsha Basavapatna 				    " using %d cookies", __func__,
12327bd3a2e2SSriharsha Basavapatna 				    ldcp->ldc_id, nbytes, desc.ncookies);
12337bd3a2e2SSriharsha Basavapatna 			}
12347bd3a2e2SSriharsha Basavapatna 
12357bd3a2e2SSriharsha Basavapatna 			/* adjust the read pointer to skip over the padding */
12367bd3a2e2SSriharsha Basavapatna 			mp->b_rptr += VNET_IPALIGN;
12377bd3a2e2SSriharsha Basavapatna 
12387bd3a2e2SSriharsha Basavapatna 			/* point to the actual end of data */
12397bd3a2e2SSriharsha Basavapatna 			mp->b_wptr = mp->b_rptr + desc.nbytes;
12407bd3a2e2SSriharsha Basavapatna 
12417bd3a2e2SSriharsha Basavapatna 			if (vmp != NULL) {
12427bd3a2e2SSriharsha Basavapatna 				vmp->state = VIO_MBLK_HAS_DATA;
12437bd3a2e2SSriharsha Basavapatna 			}
12447bd3a2e2SSriharsha Basavapatna 
12457bd3a2e2SSriharsha Basavapatna 			/* update statistics */
12467bd3a2e2SSriharsha Basavapatna 			ehp = (struct ether_header *)mp->b_rptr;
12477bd3a2e2SSriharsha Basavapatna 			if (IS_BROADCAST(ehp))
12487bd3a2e2SSriharsha Basavapatna 				ldcp->ldc_stats.brdcstrcv++;
12497bd3a2e2SSriharsha Basavapatna 			else if (IS_MULTICAST(ehp))
12507bd3a2e2SSriharsha Basavapatna 				ldcp->ldc_stats.multircv++;
12517bd3a2e2SSriharsha Basavapatna 
12527bd3a2e2SSriharsha Basavapatna 			ldcp->ldc_stats.ipackets++;
12537bd3a2e2SSriharsha Basavapatna 			ldcp->ldc_stats.rbytes += desc.nbytes;
12547bd3a2e2SSriharsha Basavapatna 
12557bd3a2e2SSriharsha Basavapatna 			/*
12567bd3a2e2SSriharsha Basavapatna 			 * IPALIGN space can be used for VLAN_TAG
12577bd3a2e2SSriharsha Basavapatna 			 */
12587bd3a2e2SSriharsha Basavapatna 			(void) vsw_vlan_frame_pretag(ldcp->ldc_port,
12597bd3a2e2SSriharsha Basavapatna 			    VSW_VNETPORT, mp);
12607bd3a2e2SSriharsha Basavapatna 
12617bd3a2e2SSriharsha Basavapatna 			/* build a chain of received packets */
12627bd3a2e2SSriharsha Basavapatna 			if (bp == NULL) {
12637bd3a2e2SSriharsha Basavapatna 				/* first pkt */
12647bd3a2e2SSriharsha Basavapatna 				bp = mp;
12657bd3a2e2SSriharsha Basavapatna 				bp->b_next = bp->b_prev = NULL;
12667bd3a2e2SSriharsha Basavapatna 				bpt = bp;
12677bd3a2e2SSriharsha Basavapatna 				chain = 1;
12687bd3a2e2SSriharsha Basavapatna 			} else {
12697bd3a2e2SSriharsha Basavapatna 				mp->b_next = mp->b_prev = NULL;
12707bd3a2e2SSriharsha Basavapatna 				bpt->b_next = mp;
12717bd3a2e2SSriharsha Basavapatna 				bpt = mp;
12727bd3a2e2SSriharsha Basavapatna 				chain++;
12737bd3a2e2SSriharsha Basavapatna 			}
12747bd3a2e2SSriharsha Basavapatna 
12757bd3a2e2SSriharsha Basavapatna vsw_process_desc_done:
12767bd3a2e2SSriharsha Basavapatna 			/* mark we are finished with this descriptor */
12777bd3a2e2SSriharsha Basavapatna 			if ((rng_rv = vnet_dring_entry_set_dstate(pub_addr,
12787bd3a2e2SSriharsha Basavapatna 			    dp->dring_mtype, dp->dring_handle, pos, pos,
12797bd3a2e2SSriharsha Basavapatna 			    VIO_DESC_DONE)) != 0) {
12807bd3a2e2SSriharsha Basavapatna 				DERR(vswp, "%s(%lld): unable to update "
12817bd3a2e2SSriharsha Basavapatna 				    "dstate at pos %d: err %d",
12827bd3a2e2SSriharsha Basavapatna 				    __func__, pos, ldcp->ldc_id, rng_rv);
12837bd3a2e2SSriharsha Basavapatna 				ldcp->ldc_stats.ierrors++;
12847bd3a2e2SSriharsha Basavapatna 				break;
12857bd3a2e2SSriharsha Basavapatna 			}
12867bd3a2e2SSriharsha Basavapatna 
12877bd3a2e2SSriharsha Basavapatna 			/*
12887bd3a2e2SSriharsha Basavapatna 			 * Send an ACK back to peer if requested.
12897bd3a2e2SSriharsha Basavapatna 			 */
12907bd3a2e2SSriharsha Basavapatna 			if (desc.hdr.ack) {
12917bd3a2e2SSriharsha Basavapatna 				dring_pkt->start_idx = range_start;
12927bd3a2e2SSriharsha Basavapatna 				dring_pkt->end_idx = range_end;
12937bd3a2e2SSriharsha Basavapatna 
12947bd3a2e2SSriharsha Basavapatna 				DERR(vswp, "%s(%lld): processed %d %d, ACK"
12957bd3a2e2SSriharsha Basavapatna 				    " requested", __func__, ldcp->ldc_id,
12967bd3a2e2SSriharsha Basavapatna 				    dring_pkt->start_idx, dring_pkt->end_idx);
12977bd3a2e2SSriharsha Basavapatna 
12987bd3a2e2SSriharsha Basavapatna 				dring_pkt->dring_process_state = VIO_DP_ACTIVE;
12997bd3a2e2SSriharsha Basavapatna 				dring_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
13007bd3a2e2SSriharsha Basavapatna 				dring_pkt->tag.vio_sid = ldcp->local_session;
13017bd3a2e2SSriharsha Basavapatna 
13027bd3a2e2SSriharsha Basavapatna 				msg_rv = vsw_send_msg(ldcp, (void *)dring_pkt,
13037bd3a2e2SSriharsha Basavapatna 				    sizeof (vio_dring_msg_t), B_FALSE);
13047bd3a2e2SSriharsha Basavapatna 
13057bd3a2e2SSriharsha Basavapatna 				/*
13067bd3a2e2SSriharsha Basavapatna 				 * Check if ACK was successfully sent. If not
13077bd3a2e2SSriharsha Basavapatna 				 * we break and deal with that below.
13087bd3a2e2SSriharsha Basavapatna 				 */
13097bd3a2e2SSriharsha Basavapatna 				if (msg_rv != 0)
13107bd3a2e2SSriharsha Basavapatna 					break;
13117bd3a2e2SSriharsha Basavapatna 
13127bd3a2e2SSriharsha Basavapatna 				prev_desc_ack = B_TRUE;
13137bd3a2e2SSriharsha Basavapatna 				range_start = pos;
13147bd3a2e2SSriharsha Basavapatna 			}
13157bd3a2e2SSriharsha Basavapatna 
13167bd3a2e2SSriharsha Basavapatna 			/* next descriptor */
13177bd3a2e2SSriharsha Basavapatna 			pos = (pos + 1) % len;
13187bd3a2e2SSriharsha Basavapatna 			cnt++;
13197bd3a2e2SSriharsha Basavapatna 
13207bd3a2e2SSriharsha Basavapatna 			/*
13217bd3a2e2SSriharsha Basavapatna 			 * Break out of loop here and stop processing to
13227bd3a2e2SSriharsha Basavapatna 			 * allow some other network device (or disk) to
13237bd3a2e2SSriharsha Basavapatna 			 * get access to the cpu.
13247bd3a2e2SSriharsha Basavapatna 			 */
13257bd3a2e2SSriharsha Basavapatna 			if (chain > vsw_chain_len) {
13267bd3a2e2SSriharsha Basavapatna 				D3(vswp, "%s(%lld): switching chain of %d "
13277bd3a2e2SSriharsha Basavapatna 				    "msgs", __func__, ldcp->ldc_id, chain);
13287bd3a2e2SSriharsha Basavapatna 				break;
13297bd3a2e2SSriharsha Basavapatna 			}
13307bd3a2e2SSriharsha Basavapatna 		}
13317bd3a2e2SSriharsha Basavapatna 
13327bd3a2e2SSriharsha Basavapatna 		/* send the chain of packets to be switched */
13337bd3a2e2SSriharsha Basavapatna 		if (bp != NULL) {
13347bd3a2e2SSriharsha Basavapatna 			DTRACE_PROBE1(vsw_rcv_msgs, int, chain);
13357bd3a2e2SSriharsha Basavapatna 			D3(vswp, "%s(%lld): switching chain of %d msgs",
13367bd3a2e2SSriharsha Basavapatna 			    __func__, ldcp->ldc_id, chain);
13377bd3a2e2SSriharsha Basavapatna 			vswp->vsw_switch_frame(vswp, bp, VSW_VNETPORT,
13387bd3a2e2SSriharsha Basavapatna 			    ldcp->ldc_port, NULL);
13397bd3a2e2SSriharsha Basavapatna 		}
13407bd3a2e2SSriharsha Basavapatna 
13417bd3a2e2SSriharsha Basavapatna 		/*
13427bd3a2e2SSriharsha Basavapatna 		 * If when we encountered an error when attempting to
13437bd3a2e2SSriharsha Basavapatna 		 * access an imported dring, initiate a connection reset.
13447bd3a2e2SSriharsha Basavapatna 		 */
13457bd3a2e2SSriharsha Basavapatna 		if (rng_rv != 0) {
13467bd3a2e2SSriharsha Basavapatna 			vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
13477bd3a2e2SSriharsha Basavapatna 			break;
13487bd3a2e2SSriharsha Basavapatna 		}
13497bd3a2e2SSriharsha Basavapatna 
13507bd3a2e2SSriharsha Basavapatna 		/*
13517bd3a2e2SSriharsha Basavapatna 		 * If when we attempted to send the ACK we found that the
13527bd3a2e2SSriharsha Basavapatna 		 * channel had been reset then now handle this.
13537bd3a2e2SSriharsha Basavapatna 		 */
13547bd3a2e2SSriharsha Basavapatna 		if (msg_rv == ECONNRESET) {
13557bd3a2e2SSriharsha Basavapatna 			vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
13567bd3a2e2SSriharsha Basavapatna 			break;
13577bd3a2e2SSriharsha Basavapatna 		}
13587bd3a2e2SSriharsha Basavapatna 
13597bd3a2e2SSriharsha Basavapatna 		DTRACE_PROBE1(msg_cnt, int, cnt);
13607bd3a2e2SSriharsha Basavapatna 
13617bd3a2e2SSriharsha Basavapatna 		/*
13627bd3a2e2SSriharsha Basavapatna 		 * We are now finished so ACK back with the state
13637bd3a2e2SSriharsha Basavapatna 		 * set to STOPPING so our peer knows we are finished
13647bd3a2e2SSriharsha Basavapatna 		 */
13657bd3a2e2SSriharsha Basavapatna 		dring_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
13667bd3a2e2SSriharsha Basavapatna 		dring_pkt->tag.vio_sid = ldcp->local_session;
13677bd3a2e2SSriharsha Basavapatna 
13687bd3a2e2SSriharsha Basavapatna 		dring_pkt->dring_process_state = VIO_DP_STOPPED;
13697bd3a2e2SSriharsha Basavapatna 
13707bd3a2e2SSriharsha Basavapatna 		DTRACE_PROBE(stop_process_sent);
13717bd3a2e2SSriharsha Basavapatna 
13727bd3a2e2SSriharsha Basavapatna 		/*
13737bd3a2e2SSriharsha Basavapatna 		 * We have not processed any more descriptors beyond
13747bd3a2e2SSriharsha Basavapatna 		 * the last one we ACK'd.
13757bd3a2e2SSriharsha Basavapatna 		 */
13767bd3a2e2SSriharsha Basavapatna 		if (prev_desc_ack)
13777bd3a2e2SSriharsha Basavapatna 			range_start = range_end;
13787bd3a2e2SSriharsha Basavapatna 
13797bd3a2e2SSriharsha Basavapatna 		dring_pkt->start_idx = range_start;
13807bd3a2e2SSriharsha Basavapatna 		dring_pkt->end_idx = range_end;
13817bd3a2e2SSriharsha Basavapatna 
13827bd3a2e2SSriharsha Basavapatna 		D2(vswp, "%s(%lld) processed : %d : %d, now stopping",
13837bd3a2e2SSriharsha Basavapatna 		    __func__, ldcp->ldc_id, dring_pkt->start_idx,
13847bd3a2e2SSriharsha Basavapatna 		    dring_pkt->end_idx);
13857bd3a2e2SSriharsha Basavapatna 
13867bd3a2e2SSriharsha Basavapatna 		(void) vsw_send_msg(ldcp, (void *)dring_pkt,
13877bd3a2e2SSriharsha Basavapatna 		    sizeof (vio_dring_msg_t), B_TRUE);
13887bd3a2e2SSriharsha Basavapatna 		ldcp->ldc_stats.dring_data_acks_sent++;
13897bd3a2e2SSriharsha Basavapatna 		ldcp->ldc_stats.dring_stopped_acks_sent++;
13907bd3a2e2SSriharsha Basavapatna 		break;
13917bd3a2e2SSriharsha Basavapatna 
13927bd3a2e2SSriharsha Basavapatna 	case VIO_SUBTYPE_ACK:
13937bd3a2e2SSriharsha Basavapatna 		D2(vswp, "%s(%lld): VIO_SUBTYPE_ACK", __func__, ldcp->ldc_id);
13947bd3a2e2SSriharsha Basavapatna 		/*
13957bd3a2e2SSriharsha Basavapatna 		 * Verify that the relevant descriptors are all
13967bd3a2e2SSriharsha Basavapatna 		 * marked as DONE
13977bd3a2e2SSriharsha Basavapatna 		 */
13987bd3a2e2SSriharsha Basavapatna 		dp = ldcp->lane_out.dringp;
13997bd3a2e2SSriharsha Basavapatna 		if (dp->ident != dring_pkt->dring_ident) {
14007bd3a2e2SSriharsha Basavapatna 			DERR(vswp, "%s: unknown ident in ACK", __func__);
14017bd3a2e2SSriharsha Basavapatna 			return;
14027bd3a2e2SSriharsha Basavapatna 		}
14037bd3a2e2SSriharsha Basavapatna 
14047bd3a2e2SSriharsha Basavapatna 		start = end = 0;
14057bd3a2e2SSriharsha Basavapatna 		start = dring_pkt->start_idx;
14067bd3a2e2SSriharsha Basavapatna 		end = dring_pkt->end_idx;
14077bd3a2e2SSriharsha Basavapatna 		len = dp->num_descriptors;
14087bd3a2e2SSriharsha Basavapatna 
14097bd3a2e2SSriharsha Basavapatna 
14107bd3a2e2SSriharsha Basavapatna 		mutex_enter(&dp->dlock);
14117bd3a2e2SSriharsha Basavapatna 		dp->last_ack_recv = end;
14127bd3a2e2SSriharsha Basavapatna 		ldcp->ldc_stats.dring_data_acks_rcvd++;
14137bd3a2e2SSriharsha Basavapatna 		mutex_exit(&dp->dlock);
14147bd3a2e2SSriharsha Basavapatna 
14157bd3a2e2SSriharsha Basavapatna 		(void) vsw_reclaim_dring(dp, start);
14167bd3a2e2SSriharsha Basavapatna 
14177bd3a2e2SSriharsha Basavapatna 		/*
14187bd3a2e2SSriharsha Basavapatna 		 * If our peer is stopping processing descriptors then
14197bd3a2e2SSriharsha Basavapatna 		 * we check to make sure it has processed all the descriptors
14207bd3a2e2SSriharsha Basavapatna 		 * we have updated. If not then we send it a new message
14217bd3a2e2SSriharsha Basavapatna 		 * to prompt it to restart.
14227bd3a2e2SSriharsha Basavapatna 		 */
14237bd3a2e2SSriharsha Basavapatna 		if (dring_pkt->dring_process_state == VIO_DP_STOPPED) {
14247bd3a2e2SSriharsha Basavapatna 			DTRACE_PROBE(stop_process_recv);
14257bd3a2e2SSriharsha Basavapatna 			D2(vswp, "%s(%lld): got stopping msg : %d : %d",
14267bd3a2e2SSriharsha Basavapatna 			    __func__, ldcp->ldc_id, dring_pkt->start_idx,
14277bd3a2e2SSriharsha Basavapatna 			    dring_pkt->end_idx);
14287bd3a2e2SSriharsha Basavapatna 
14297bd3a2e2SSriharsha Basavapatna 			/*
14307bd3a2e2SSriharsha Basavapatna 			 * Check next descriptor in public section of ring.
14317bd3a2e2SSriharsha Basavapatna 			 * If its marked as READY then we need to prompt our
14327bd3a2e2SSriharsha Basavapatna 			 * peer to start processing the ring again.
14337bd3a2e2SSriharsha Basavapatna 			 */
14347bd3a2e2SSriharsha Basavapatna 			i = (end + 1) % len;
14357bd3a2e2SSriharsha Basavapatna 			pub_addr = (vnet_public_desc_t *)dp->pub_addr + i;
14367bd3a2e2SSriharsha Basavapatna 			priv_addr = (vsw_private_desc_t *)dp->priv_addr + i;
14377bd3a2e2SSriharsha Basavapatna 
14387bd3a2e2SSriharsha Basavapatna 			/*
14397bd3a2e2SSriharsha Basavapatna 			 * Hold the restart lock across all of this to
14407bd3a2e2SSriharsha Basavapatna 			 * make sure that its not possible for us to
14417bd3a2e2SSriharsha Basavapatna 			 * decide that a msg needs to be sent in the future
14427bd3a2e2SSriharsha Basavapatna 			 * but the sending code having already checked is
14437bd3a2e2SSriharsha Basavapatna 			 * about to exit.
14447bd3a2e2SSriharsha Basavapatna 			 */
14457bd3a2e2SSriharsha Basavapatna 			mutex_enter(&dp->restart_lock);
14467bd3a2e2SSriharsha Basavapatna 			ldcp->ldc_stats.dring_stopped_acks_rcvd++;
14477bd3a2e2SSriharsha Basavapatna 			mutex_enter(&priv_addr->dstate_lock);
14487bd3a2e2SSriharsha Basavapatna 			if (pub_addr->hdr.dstate == VIO_DESC_READY) {
14497bd3a2e2SSriharsha Basavapatna 
14507bd3a2e2SSriharsha Basavapatna 				mutex_exit(&priv_addr->dstate_lock);
14517bd3a2e2SSriharsha Basavapatna 
14527bd3a2e2SSriharsha Basavapatna 				dring_pkt->tag.vio_subtype = VIO_SUBTYPE_INFO;
14537bd3a2e2SSriharsha Basavapatna 				dring_pkt->tag.vio_sid = ldcp->local_session;
14547bd3a2e2SSriharsha Basavapatna 
14557bd3a2e2SSriharsha Basavapatna 				dring_pkt->start_idx = (end + 1) % len;
14567bd3a2e2SSriharsha Basavapatna 				dring_pkt->end_idx = -1;
14577bd3a2e2SSriharsha Basavapatna 
14587bd3a2e2SSriharsha Basavapatna 				D2(vswp, "%s(%lld) : sending restart msg:"
14597bd3a2e2SSriharsha Basavapatna 				    " %d : %d", __func__, ldcp->ldc_id,
14607bd3a2e2SSriharsha Basavapatna 				    dring_pkt->start_idx, dring_pkt->end_idx);
14617bd3a2e2SSriharsha Basavapatna 
14627bd3a2e2SSriharsha Basavapatna 				msg_rv = vsw_send_msg(ldcp, (void *)dring_pkt,
14637bd3a2e2SSriharsha Basavapatna 				    sizeof (vio_dring_msg_t), B_FALSE);
14647bd3a2e2SSriharsha Basavapatna 				ldcp->ldc_stats.dring_data_msgs_sent++;
14657bd3a2e2SSriharsha Basavapatna 
14667bd3a2e2SSriharsha Basavapatna 			} else {
14677bd3a2e2SSriharsha Basavapatna 				mutex_exit(&priv_addr->dstate_lock);
14687bd3a2e2SSriharsha Basavapatna 				dp->restart_reqd = B_TRUE;
14697bd3a2e2SSriharsha Basavapatna 			}
14707bd3a2e2SSriharsha Basavapatna 			mutex_exit(&dp->restart_lock);
14717bd3a2e2SSriharsha Basavapatna 		}
14727bd3a2e2SSriharsha Basavapatna 
14737bd3a2e2SSriharsha Basavapatna 		if (msg_rv == ECONNRESET)
14747bd3a2e2SSriharsha Basavapatna 			vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
14757bd3a2e2SSriharsha Basavapatna 
14767bd3a2e2SSriharsha Basavapatna 		break;
14777bd3a2e2SSriharsha Basavapatna 
14787bd3a2e2SSriharsha Basavapatna 	case VIO_SUBTYPE_NACK:
14797bd3a2e2SSriharsha Basavapatna 		DWARN(vswp, "%s(%lld): VIO_SUBTYPE_NACK",
14807bd3a2e2SSriharsha Basavapatna 		    __func__, ldcp->ldc_id);
14817bd3a2e2SSriharsha Basavapatna 		/*
14827bd3a2e2SSriharsha Basavapatna 		 * Something is badly wrong if we are getting NACK's
14837bd3a2e2SSriharsha Basavapatna 		 * for our data pkts. So reset the channel.
14847bd3a2e2SSriharsha Basavapatna 		 */
14857bd3a2e2SSriharsha Basavapatna 		vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
14867bd3a2e2SSriharsha Basavapatna 
14877bd3a2e2SSriharsha Basavapatna 		break;
14887bd3a2e2SSriharsha Basavapatna 
14897bd3a2e2SSriharsha Basavapatna 	default:
14907bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "%s(%lld): Unknown vio_subtype %x\n", __func__,
14917bd3a2e2SSriharsha Basavapatna 		    ldcp->ldc_id, dring_pkt->tag.vio_subtype);
14927bd3a2e2SSriharsha Basavapatna 	}
14937bd3a2e2SSriharsha Basavapatna 
14947bd3a2e2SSriharsha Basavapatna 	D1(vswp, "%s(%lld) exit", __func__, ldcp->ldc_id);
14957bd3a2e2SSriharsha Basavapatna }
1496