xref: /onnv-gate/usr/src/uts/sun4v/io/vnet_rxdring.c (revision 13098:496fd9979cfc)
112011SSriharsha.Basavapatna@Sun.COM /*
212011SSriharsha.Basavapatna@Sun.COM  * CDDL HEADER START
312011SSriharsha.Basavapatna@Sun.COM  *
412011SSriharsha.Basavapatna@Sun.COM  * The contents of this file are subject to the terms of the
512011SSriharsha.Basavapatna@Sun.COM  * Common Development and Distribution License (the "License").
612011SSriharsha.Basavapatna@Sun.COM  * You may not use this file except in compliance with the License.
712011SSriharsha.Basavapatna@Sun.COM  *
812011SSriharsha.Basavapatna@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
912011SSriharsha.Basavapatna@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1012011SSriharsha.Basavapatna@Sun.COM  * See the License for the specific language governing permissions
1112011SSriharsha.Basavapatna@Sun.COM  * and limitations under the License.
1212011SSriharsha.Basavapatna@Sun.COM  *
1312011SSriharsha.Basavapatna@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1412011SSriharsha.Basavapatna@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1512011SSriharsha.Basavapatna@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1612011SSriharsha.Basavapatna@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1712011SSriharsha.Basavapatna@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1812011SSriharsha.Basavapatna@Sun.COM  *
1912011SSriharsha.Basavapatna@Sun.COM  * CDDL HEADER END
2012011SSriharsha.Basavapatna@Sun.COM  */
2112011SSriharsha.Basavapatna@Sun.COM 
2212011SSriharsha.Basavapatna@Sun.COM /*
2312642SWentao.Yang@Sun.COM  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
2412011SSriharsha.Basavapatna@Sun.COM  */
2512642SWentao.Yang@Sun.COM 
2612011SSriharsha.Basavapatna@Sun.COM #include <sys/types.h>
2712011SSriharsha.Basavapatna@Sun.COM #include <sys/errno.h>
2812011SSriharsha.Basavapatna@Sun.COM #include <sys/sysmacros.h>
2912011SSriharsha.Basavapatna@Sun.COM #include <sys/param.h>
3012011SSriharsha.Basavapatna@Sun.COM #include <sys/machsystm.h>
3112011SSriharsha.Basavapatna@Sun.COM #include <sys/stream.h>
3212011SSriharsha.Basavapatna@Sun.COM #include <sys/strsubr.h>
3312011SSriharsha.Basavapatna@Sun.COM #include <sys/kmem.h>
3412011SSriharsha.Basavapatna@Sun.COM #include <sys/strsun.h>
3512011SSriharsha.Basavapatna@Sun.COM #include <sys/callb.h>
3612011SSriharsha.Basavapatna@Sun.COM #include <sys/sdt.h>
3712011SSriharsha.Basavapatna@Sun.COM #include <sys/ethernet.h>
3812011SSriharsha.Basavapatna@Sun.COM #include <sys/mach_descrip.h>
3912011SSriharsha.Basavapatna@Sun.COM #include <sys/mdeg.h>
4012011SSriharsha.Basavapatna@Sun.COM #include <sys/vnet.h>
4112011SSriharsha.Basavapatna@Sun.COM #include <sys/vio_mailbox.h>
4212011SSriharsha.Basavapatna@Sun.COM #include <sys/vio_common.h>
4312011SSriharsha.Basavapatna@Sun.COM #include <sys/vnet_common.h>
4412011SSriharsha.Basavapatna@Sun.COM #include <sys/vnet_mailbox.h>
4512011SSriharsha.Basavapatna@Sun.COM #include <sys/vio_util.h>
4612011SSriharsha.Basavapatna@Sun.COM #include <sys/vnet_gen.h>
4712011SSriharsha.Basavapatna@Sun.COM 
4812011SSriharsha.Basavapatna@Sun.COM /*
4912011SSriharsha.Basavapatna@Sun.COM  * This file contains the implementation of RxDringData transfer mode of VIO
5012011SSriharsha.Basavapatna@Sun.COM  * Protocol in vnet. The functions in this file are invoked from vnet_gen.c
5112011SSriharsha.Basavapatna@Sun.COM  * after RxDringData mode is negotiated with the peer during attribute phase of
5212011SSriharsha.Basavapatna@Sun.COM  * handshake. This file contains functions that setup the transmit and receive
5312011SSriharsha.Basavapatna@Sun.COM  * descriptor rings, and associated resources in RxDringData mode. It also
5412011SSriharsha.Basavapatna@Sun.COM  * contains the transmit and receive data processing functions that are invoked
5512011SSriharsha.Basavapatna@Sun.COM  * in RxDringData mode. The data processing routines in this file have the
5612011SSriharsha.Basavapatna@Sun.COM  * suffix '_shm' to indicate the shared memory mechanism used in RxDringData
5712011SSriharsha.Basavapatna@Sun.COM  * mode.
5812011SSriharsha.Basavapatna@Sun.COM  */
5912011SSriharsha.Basavapatna@Sun.COM 
6012011SSriharsha.Basavapatna@Sun.COM /* Functions exported to vnet_gen.c */
6112011SSriharsha.Basavapatna@Sun.COM int vgen_create_rx_dring(vgen_ldc_t *ldcp);
6212011SSriharsha.Basavapatna@Sun.COM void vgen_destroy_rx_dring(vgen_ldc_t *ldcp);
6312011SSriharsha.Basavapatna@Sun.COM int vgen_map_tx_dring(vgen_ldc_t *ldcp, void *pkt);
6412011SSriharsha.Basavapatna@Sun.COM void vgen_unmap_tx_dring(vgen_ldc_t *ldcp);
6512011SSriharsha.Basavapatna@Sun.COM int vgen_map_data(vgen_ldc_t *ldcp, void *pkt);
6612011SSriharsha.Basavapatna@Sun.COM int vgen_dringsend_shm(void *arg, mblk_t *mp);
6712011SSriharsha.Basavapatna@Sun.COM int vgen_handle_dringdata_shm(void *arg1, void *arg2);
6812011SSriharsha.Basavapatna@Sun.COM mblk_t *vgen_poll_rcv_shm(vgen_ldc_t *ldcp, int bytes_to_pickup);
6912011SSriharsha.Basavapatna@Sun.COM int vgen_send_dringack_shm(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
7012011SSriharsha.Basavapatna@Sun.COM     uint32_t start, int32_t end, uint8_t pstate);
7112011SSriharsha.Basavapatna@Sun.COM 
7212011SSriharsha.Basavapatna@Sun.COM /* Internal functions */
7312011SSriharsha.Basavapatna@Sun.COM static int vgen_handle_dringdata_info_shm(vgen_ldc_t *ldcp, vio_msg_tag_t *tp);
7412011SSriharsha.Basavapatna@Sun.COM static int vgen_handle_dringdata_ack_shm(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
7512011SSriharsha.Basavapatna@Sun.COM static int vgen_handle_dringdata_nack_shm(vgen_ldc_t *ldcp, vio_msg_tag_t *tp);
7612011SSriharsha.Basavapatna@Sun.COM static int vgen_intr_rcv_shm(vgen_ldc_t *ldcp);
7712011SSriharsha.Basavapatna@Sun.COM static int vgen_receive_packet(vgen_ldc_t *ldcp, mblk_t **bp, uint_t *size);
7812011SSriharsha.Basavapatna@Sun.COM static int vgen_send_dringdata_shm(vgen_ldc_t *ldcp, uint32_t start,
7912011SSriharsha.Basavapatna@Sun.COM     int32_t end);
8012011SSriharsha.Basavapatna@Sun.COM static int vgen_sendmsg_shm(vgen_ldc_t *ldcp, caddr_t msg,  size_t msglen);
8112011SSriharsha.Basavapatna@Sun.COM 
8212011SSriharsha.Basavapatna@Sun.COM /* Functions imported from vnet_gen.c */
8312011SSriharsha.Basavapatna@Sun.COM extern int vgen_handle_evt_read(vgen_ldc_t *ldcp, vgen_caller_t caller);
8412011SSriharsha.Basavapatna@Sun.COM extern int vgen_handle_evt_reset(vgen_ldc_t *ldcp, vgen_caller_t caller);
8512011SSriharsha.Basavapatna@Sun.COM extern void vgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen);
8612011SSriharsha.Basavapatna@Sun.COM extern void vgen_destroy_rxpools(void *arg);
8712011SSriharsha.Basavapatna@Sun.COM 
8812011SSriharsha.Basavapatna@Sun.COM /* Tunables */
8912011SSriharsha.Basavapatna@Sun.COM extern uint32_t vnet_num_descriptors;
9012011SSriharsha.Basavapatna@Sun.COM extern uint32_t vgen_chain_len;
9112011SSriharsha.Basavapatna@Sun.COM extern uint32_t vgen_ldcwr_retries;
9212011SSriharsha.Basavapatna@Sun.COM extern uint32_t vgen_recv_delay;
9312011SSriharsha.Basavapatna@Sun.COM extern uint32_t vgen_recv_retries;
9412011SSriharsha.Basavapatna@Sun.COM extern uint32_t vgen_nrbufs_factor;
9512011SSriharsha.Basavapatna@Sun.COM 
9612011SSriharsha.Basavapatna@Sun.COM #ifdef DEBUG
9712011SSriharsha.Basavapatna@Sun.COM 
9812011SSriharsha.Basavapatna@Sun.COM #define	DEBUG_PRINTF	vgen_debug_printf
9912011SSriharsha.Basavapatna@Sun.COM 
10012011SSriharsha.Basavapatna@Sun.COM extern int vnet_dbglevel;
10112011SSriharsha.Basavapatna@Sun.COM extern int vgen_inject_err_flag;
10212011SSriharsha.Basavapatna@Sun.COM 
10312011SSriharsha.Basavapatna@Sun.COM extern void vgen_debug_printf(const char *fname, vgen_t *vgenp,
10412011SSriharsha.Basavapatna@Sun.COM 	vgen_ldc_t *ldcp, const char *fmt, ...);
10512011SSriharsha.Basavapatna@Sun.COM extern boolean_t vgen_inject_error(vgen_ldc_t *ldcp, int error);
10612011SSriharsha.Basavapatna@Sun.COM 
10712011SSriharsha.Basavapatna@Sun.COM #endif
10812011SSriharsha.Basavapatna@Sun.COM 
10912011SSriharsha.Basavapatna@Sun.COM /*
11012011SSriharsha.Basavapatna@Sun.COM  * Allocate receive resources for the channel. The resources consist of a
11112011SSriharsha.Basavapatna@Sun.COM  * receive descriptor ring and an associated receive buffer area.
11212011SSriharsha.Basavapatna@Sun.COM  */
11312011SSriharsha.Basavapatna@Sun.COM int
vgen_create_rx_dring(vgen_ldc_t * ldcp)11412011SSriharsha.Basavapatna@Sun.COM vgen_create_rx_dring(vgen_ldc_t *ldcp)
11512011SSriharsha.Basavapatna@Sun.COM {
11612642SWentao.Yang@Sun.COM 	int 				i, j;
11712011SSriharsha.Basavapatna@Sun.COM 	int 				rv;
11812011SSriharsha.Basavapatna@Sun.COM 	uint32_t			ncookies;
11912011SSriharsha.Basavapatna@Sun.COM 	ldc_mem_info_t			minfo;
12012011SSriharsha.Basavapatna@Sun.COM 	vnet_rx_dringdata_desc_t	*rxdp;
12112011SSriharsha.Basavapatna@Sun.COM 	size_t				data_sz;
12212011SSriharsha.Basavapatna@Sun.COM 	vio_mblk_t			*vmp;
12312011SSriharsha.Basavapatna@Sun.COM 	vio_mblk_t			**rxdp_to_vmp;
12412011SSriharsha.Basavapatna@Sun.COM 	uint32_t			rxdsize;
12512011SSriharsha.Basavapatna@Sun.COM 	caddr_t				datap = NULL;
12612011SSriharsha.Basavapatna@Sun.COM 	vgen_t				*vgenp = LDC_TO_VGEN(ldcp);
12712011SSriharsha.Basavapatna@Sun.COM 
12812011SSriharsha.Basavapatna@Sun.COM 	rxdsize = sizeof (vnet_rx_dringdata_desc_t);
12912011SSriharsha.Basavapatna@Sun.COM 	ldcp->num_rxds = vnet_num_descriptors;
130*13098SWentao.Yang@Sun.COM 	ldcp->num_rbufs = VGEN_RXDRING_NRBUFS;
13112011SSriharsha.Basavapatna@Sun.COM 
13212011SSriharsha.Basavapatna@Sun.COM 	/* Create the receive descriptor ring */
13312011SSriharsha.Basavapatna@Sun.COM 	rv = ldc_mem_dring_create(ldcp->num_rxds, rxdsize,
13412011SSriharsha.Basavapatna@Sun.COM 	    &ldcp->rx_dring_handle);
13512011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
13612011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "ldc_mem_dring_create() failed\n");
13712011SSriharsha.Basavapatna@Sun.COM 		goto fail;
13812011SSriharsha.Basavapatna@Sun.COM 	}
13912011SSriharsha.Basavapatna@Sun.COM 
14012011SSriharsha.Basavapatna@Sun.COM 	/* Get the addr of descriptor ring */
14112011SSriharsha.Basavapatna@Sun.COM 	rv = ldc_mem_dring_info(ldcp->rx_dring_handle, &minfo);
14212011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
14312011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "ldc_mem_dring_info() failed\n");
14412011SSriharsha.Basavapatna@Sun.COM 		goto fail;
14512011SSriharsha.Basavapatna@Sun.COM 	}
14612011SSriharsha.Basavapatna@Sun.COM 	ldcp->rxdp = (vnet_rx_dringdata_desc_t *)(minfo.vaddr);
14712011SSriharsha.Basavapatna@Sun.COM 	bzero(ldcp->rxdp, sizeof (*rxdp) * (ldcp->num_rxds));
14812011SSriharsha.Basavapatna@Sun.COM 
14912011SSriharsha.Basavapatna@Sun.COM 	/*
15012011SSriharsha.Basavapatna@Sun.COM 	 * Allocate a table that maps descriptor to its associated buffer;
15112011SSriharsha.Basavapatna@Sun.COM 	 * used while receiving to validate that the peer has not changed the
15212011SSriharsha.Basavapatna@Sun.COM 	 * buffer offset provided in the descriptor.
15312011SSriharsha.Basavapatna@Sun.COM 	 */
15412011SSriharsha.Basavapatna@Sun.COM 	rxdp_to_vmp = kmem_zalloc(ldcp->num_rxds * sizeof (uintptr_t),
15512011SSriharsha.Basavapatna@Sun.COM 	    KM_SLEEP);
15612011SSriharsha.Basavapatna@Sun.COM 	ldcp->rxdp_to_vmp = rxdp_to_vmp;
15712011SSriharsha.Basavapatna@Sun.COM 
15812011SSriharsha.Basavapatna@Sun.COM 	/*
15912011SSriharsha.Basavapatna@Sun.COM 	 * Allocate a single large buffer that serves as the rx buffer area.
16012011SSriharsha.Basavapatna@Sun.COM 	 * We allocate a ldc memory handle and export the buffer area as shared
16112011SSriharsha.Basavapatna@Sun.COM 	 * memory. We send the ldc memcookie for this buffer space to the peer,
16212011SSriharsha.Basavapatna@Sun.COM 	 * as part of dring registration phase during handshake. We manage this
16312011SSriharsha.Basavapatna@Sun.COM 	 * buffer area as individual buffers of max_frame_size and provide
16412011SSriharsha.Basavapatna@Sun.COM 	 * specific buffer offsets in each descriptor to the peer. Note that
16512011SSriharsha.Basavapatna@Sun.COM 	 * the factor used to compute the # of buffers (above) must be > 1 to
16612011SSriharsha.Basavapatna@Sun.COM 	 * ensure that there are more buffers than the # of descriptors. This
16712011SSriharsha.Basavapatna@Sun.COM 	 * is needed because, while the shared memory buffers are sent up our
16812011SSriharsha.Basavapatna@Sun.COM 	 * stack during receive, the sender needs additional buffers that can
16912011SSriharsha.Basavapatna@Sun.COM 	 * be used for further transmits. This also means there is no one to
17012011SSriharsha.Basavapatna@Sun.COM 	 * one correspondence between the descriptor index and buffer offset.
17112011SSriharsha.Basavapatna@Sun.COM 	 * The sender has to read the buffer offset in the descriptor and use
17212011SSriharsha.Basavapatna@Sun.COM 	 * the specified offset to copy the tx data into the shared buffer. We
17312011SSriharsha.Basavapatna@Sun.COM 	 * (receiver) manage the individual buffers and their state (see
17412011SSriharsha.Basavapatna@Sun.COM 	 * VIO_MBLK_STATEs in vio_util.h).
17512011SSriharsha.Basavapatna@Sun.COM 	 */
176*13098SWentao.Yang@Sun.COM 	data_sz = RXDRING_DBLK_SZ(vgenp->max_frame_size);
17712011SSriharsha.Basavapatna@Sun.COM 
17812011SSriharsha.Basavapatna@Sun.COM 	ldcp->rx_data_sz = data_sz * ldcp->num_rbufs;
17912011SSriharsha.Basavapatna@Sun.COM 	ldcp->rx_dblk_sz = data_sz;
18012011SSriharsha.Basavapatna@Sun.COM 	datap = kmem_zalloc(ldcp->rx_data_sz, KM_SLEEP);
18112011SSriharsha.Basavapatna@Sun.COM 	ldcp->rx_datap = datap;
18212011SSriharsha.Basavapatna@Sun.COM 
18312011SSriharsha.Basavapatna@Sun.COM 	/* Allocate a ldc memhandle for the entire rx data area */
18412011SSriharsha.Basavapatna@Sun.COM 	rv = ldc_mem_alloc_handle(ldcp->ldc_handle, &ldcp->rx_data_handle);
18512011SSriharsha.Basavapatna@Sun.COM 	if (rv) {
18612011SSriharsha.Basavapatna@Sun.COM 		ldcp->rx_data_handle = 0;
18712011SSriharsha.Basavapatna@Sun.COM 		goto fail;
18812011SSriharsha.Basavapatna@Sun.COM 	}
18912011SSriharsha.Basavapatna@Sun.COM 
19012011SSriharsha.Basavapatna@Sun.COM 	/* Allocate memory for the data cookies */
19112011SSriharsha.Basavapatna@Sun.COM 	ldcp->rx_data_cookie = kmem_zalloc(VNET_DATA_AREA_COOKIES *
19212011SSriharsha.Basavapatna@Sun.COM 	    sizeof (ldc_mem_cookie_t), KM_SLEEP);
19312011SSriharsha.Basavapatna@Sun.COM 
19412011SSriharsha.Basavapatna@Sun.COM 	/*
19512011SSriharsha.Basavapatna@Sun.COM 	 * Bind ldc memhandle to the corresponding rx data area.
19612011SSriharsha.Basavapatna@Sun.COM 	 */
19712011SSriharsha.Basavapatna@Sun.COM 	ncookies = 0;
19812011SSriharsha.Basavapatna@Sun.COM 	rv = ldc_mem_bind_handle(ldcp->rx_data_handle, (caddr_t)datap,
19912011SSriharsha.Basavapatna@Sun.COM 	    ldcp->rx_data_sz, LDC_DIRECT_MAP, LDC_MEM_W,
20012011SSriharsha.Basavapatna@Sun.COM 	    ldcp->rx_data_cookie, &ncookies);
20112011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
20212011SSriharsha.Basavapatna@Sun.COM 		goto fail;
20312011SSriharsha.Basavapatna@Sun.COM 	}
20412011SSriharsha.Basavapatna@Sun.COM 	if ((ncookies == 0) || (ncookies > VNET_DATA_AREA_COOKIES)) {
20512011SSriharsha.Basavapatna@Sun.COM 		goto fail;
20612011SSriharsha.Basavapatna@Sun.COM 	}
20712011SSriharsha.Basavapatna@Sun.COM 	ldcp->rx_data_ncookies = ncookies;
20812011SSriharsha.Basavapatna@Sun.COM 
20912642SWentao.Yang@Sun.COM 	for (j = 1; j < ncookies; j++) {
21012642SWentao.Yang@Sun.COM 		rv = ldc_mem_nextcookie(ldcp->rx_data_handle,
21112642SWentao.Yang@Sun.COM 		    &(ldcp->rx_data_cookie[j]));
21212642SWentao.Yang@Sun.COM 		if (rv != 0) {
21312642SWentao.Yang@Sun.COM 			DERR(vgenp, ldcp, "ldc_mem_nextcookie "
21412642SWentao.Yang@Sun.COM 			    "failed rv (%d)", rv);
21512642SWentao.Yang@Sun.COM 			goto fail;
21612642SWentao.Yang@Sun.COM 		}
21712642SWentao.Yang@Sun.COM 	}
21812642SWentao.Yang@Sun.COM 
21912011SSriharsha.Basavapatna@Sun.COM 	/*
22012011SSriharsha.Basavapatna@Sun.COM 	 * Successful in binding the handle to rx data area. Now setup mblks
22112011SSriharsha.Basavapatna@Sun.COM 	 * around each data buffer and setup the descriptors to point to these
22212011SSriharsha.Basavapatna@Sun.COM 	 * rx data buffers. We associate each descriptor with a buffer
22312011SSriharsha.Basavapatna@Sun.COM 	 * by specifying the buffer offset in the descriptor. When the peer
22412011SSriharsha.Basavapatna@Sun.COM 	 * needs to transmit data, this offset is read by the peer to determine
22512011SSriharsha.Basavapatna@Sun.COM 	 * the buffer in the mapped buffer area where the data to be
22612011SSriharsha.Basavapatna@Sun.COM 	 * transmitted should be copied, for a specific descriptor.
22712011SSriharsha.Basavapatna@Sun.COM 	 */
22812011SSriharsha.Basavapatna@Sun.COM 	rv = vio_create_mblks(ldcp->num_rbufs, data_sz, (uint8_t *)datap,
22912011SSriharsha.Basavapatna@Sun.COM 	    &ldcp->rx_vmp);
23012011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
23112011SSriharsha.Basavapatna@Sun.COM 		goto fail;
23212011SSriharsha.Basavapatna@Sun.COM 	}
23312011SSriharsha.Basavapatna@Sun.COM 
23412011SSriharsha.Basavapatna@Sun.COM 	for (i = 0; i < ldcp->num_rxds; i++) {
23512011SSriharsha.Basavapatna@Sun.COM 		rxdp = &(ldcp->rxdp[i]);
23612011SSriharsha.Basavapatna@Sun.COM 		/* allocate an mblk around this data buffer */
23712011SSriharsha.Basavapatna@Sun.COM 		vmp = vio_allocb(ldcp->rx_vmp);
23812011SSriharsha.Basavapatna@Sun.COM 		ASSERT(vmp != NULL);
23912011SSriharsha.Basavapatna@Sun.COM 		rxdp->data_buf_offset = VIO_MBLK_DATA_OFF(vmp) + VNET_IPALIGN;
24012011SSriharsha.Basavapatna@Sun.COM 		rxdp->dstate = VIO_DESC_FREE;
24112011SSriharsha.Basavapatna@Sun.COM 		rxdp_to_vmp[i] = vmp;
24212011SSriharsha.Basavapatna@Sun.COM 	}
24312011SSriharsha.Basavapatna@Sun.COM 
24412011SSriharsha.Basavapatna@Sun.COM 	/*
24512011SSriharsha.Basavapatna@Sun.COM 	 * The descriptors and the associated buffers are all ready;
24612011SSriharsha.Basavapatna@Sun.COM 	 * now bind descriptor ring to the channel.
24712011SSriharsha.Basavapatna@Sun.COM 	 */
24812011SSriharsha.Basavapatna@Sun.COM 	rv = ldc_mem_dring_bind(ldcp->ldc_handle, ldcp->rx_dring_handle,
24912011SSriharsha.Basavapatna@Sun.COM 	    LDC_DIRECT_MAP | LDC_SHADOW_MAP, LDC_MEM_RW,
25012011SSriharsha.Basavapatna@Sun.COM 	    &ldcp->rx_dring_cookie, &ncookies);
25112011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
25212011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "ldc_mem_dring_bind failed "
25312011SSriharsha.Basavapatna@Sun.COM 		    "rv(%x)\n", rv);
25412011SSriharsha.Basavapatna@Sun.COM 		goto fail;
25512011SSriharsha.Basavapatna@Sun.COM 	}
25612011SSriharsha.Basavapatna@Sun.COM 	ASSERT(ncookies == 1);
25712011SSriharsha.Basavapatna@Sun.COM 	ldcp->rx_dring_ncookies = ncookies;
25812011SSriharsha.Basavapatna@Sun.COM 
25912011SSriharsha.Basavapatna@Sun.COM 	/* initialize rx seqnum and index */
26012011SSriharsha.Basavapatna@Sun.COM 	ldcp->next_rxseq = VNET_ISS;
26112011SSriharsha.Basavapatna@Sun.COM 	ldcp->next_rxi = 0;
26212011SSriharsha.Basavapatna@Sun.COM 
26312011SSriharsha.Basavapatna@Sun.COM 	return (VGEN_SUCCESS);
26412011SSriharsha.Basavapatna@Sun.COM 
26512011SSriharsha.Basavapatna@Sun.COM fail:
26612011SSriharsha.Basavapatna@Sun.COM 	vgen_destroy_rx_dring(ldcp);
26712011SSriharsha.Basavapatna@Sun.COM 	return (VGEN_FAILURE);
26812011SSriharsha.Basavapatna@Sun.COM }
26912011SSriharsha.Basavapatna@Sun.COM 
27012011SSriharsha.Basavapatna@Sun.COM /*
27112011SSriharsha.Basavapatna@Sun.COM  * Free receive resources for the channel.
27212011SSriharsha.Basavapatna@Sun.COM  */
27312011SSriharsha.Basavapatna@Sun.COM void
vgen_destroy_rx_dring(vgen_ldc_t * ldcp)27412011SSriharsha.Basavapatna@Sun.COM vgen_destroy_rx_dring(vgen_ldc_t *ldcp)
27512011SSriharsha.Basavapatna@Sun.COM {
27612011SSriharsha.Basavapatna@Sun.COM 	vgen_t	*vgenp = LDC_TO_VGEN(ldcp);
27712011SSriharsha.Basavapatna@Sun.COM 
27812011SSriharsha.Basavapatna@Sun.COM 	/* We first unbind the descriptor ring */
27912011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->rx_dring_ncookies != 0) {
28012011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_dring_unbind(ldcp->rx_dring_handle);
28112011SSriharsha.Basavapatna@Sun.COM 		ldcp->rx_dring_ncookies = 0;
28212011SSriharsha.Basavapatna@Sun.COM 	}
28312011SSriharsha.Basavapatna@Sun.COM 
28412011SSriharsha.Basavapatna@Sun.COM 	/* Destroy the mblks that are wrapped around the rx data buffers */
28512011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->rx_vmp != NULL) {
28612011SSriharsha.Basavapatna@Sun.COM 		vio_clobber_pool(ldcp->rx_vmp);
28712011SSriharsha.Basavapatna@Sun.COM 		if (vio_destroy_mblks(ldcp->rx_vmp) != 0) {
28812011SSriharsha.Basavapatna@Sun.COM 			/*
28912011SSriharsha.Basavapatna@Sun.COM 			 * If we can't destroy the rx pool for this channel,
29012011SSriharsha.Basavapatna@Sun.COM 			 * dispatch a task to retry and clean up. Note that we
29112011SSriharsha.Basavapatna@Sun.COM 			 * don't need to wait for the task to complete. If the
29212011SSriharsha.Basavapatna@Sun.COM 			 * vnet device itself gets detached, it will wait for
29312011SSriharsha.Basavapatna@Sun.COM 			 * the task to complete implicitly in
29412011SSriharsha.Basavapatna@Sun.COM 			 * ddi_taskq_destroy().
29512011SSriharsha.Basavapatna@Sun.COM 			 */
29612011SSriharsha.Basavapatna@Sun.COM 			(void) ddi_taskq_dispatch(vgenp->rxp_taskq,
29712011SSriharsha.Basavapatna@Sun.COM 			    vgen_destroy_rxpools, ldcp->rx_vmp, DDI_SLEEP);
29812011SSriharsha.Basavapatna@Sun.COM 		}
29912011SSriharsha.Basavapatna@Sun.COM 		ldcp->rx_vmp = NULL;
30012011SSriharsha.Basavapatna@Sun.COM 	}
30112011SSriharsha.Basavapatna@Sun.COM 
30212011SSriharsha.Basavapatna@Sun.COM 	/* Free rx data area cookies */
30312011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->rx_data_cookie != NULL) {
30412011SSriharsha.Basavapatna@Sun.COM 		kmem_free(ldcp->rx_data_cookie, VNET_DATA_AREA_COOKIES *
30512011SSriharsha.Basavapatna@Sun.COM 		    sizeof (ldc_mem_cookie_t));
30612011SSriharsha.Basavapatna@Sun.COM 		ldcp->rx_data_cookie = NULL;
30712011SSriharsha.Basavapatna@Sun.COM 	}
30812011SSriharsha.Basavapatna@Sun.COM 
30912011SSriharsha.Basavapatna@Sun.COM 	/* Unbind rx data area memhandle */
31012011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->rx_data_ncookies != 0) {
31112011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_unbind_handle(ldcp->rx_data_handle);
31212011SSriharsha.Basavapatna@Sun.COM 		ldcp->rx_data_ncookies = 0;
31312011SSriharsha.Basavapatna@Sun.COM 	}
31412011SSriharsha.Basavapatna@Sun.COM 
31512011SSriharsha.Basavapatna@Sun.COM 	/* Free rx data area memhandle */
31612011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->rx_data_handle != 0) {
31712011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_free_handle(ldcp->rx_data_handle);
31812011SSriharsha.Basavapatna@Sun.COM 		ldcp->rx_data_handle = 0;
31912011SSriharsha.Basavapatna@Sun.COM 	}
32012011SSriharsha.Basavapatna@Sun.COM 
32112011SSriharsha.Basavapatna@Sun.COM 	/* Now free the rx data area itself */
32212011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->rx_datap != NULL) {
32312011SSriharsha.Basavapatna@Sun.COM 		/* prealloc'd rx data buffer */
32412011SSriharsha.Basavapatna@Sun.COM 		kmem_free(ldcp->rx_datap, ldcp->rx_data_sz);
32512011SSriharsha.Basavapatna@Sun.COM 		ldcp->rx_datap = NULL;
32612011SSriharsha.Basavapatna@Sun.COM 		ldcp->rx_data_sz = 0;
32712011SSriharsha.Basavapatna@Sun.COM 	}
32812011SSriharsha.Basavapatna@Sun.COM 
32912011SSriharsha.Basavapatna@Sun.COM 	/* Finally, free the receive descriptor ring */
33012011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->rx_dring_handle != 0) {
33112011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_dring_destroy(ldcp->rx_dring_handle);
33212011SSriharsha.Basavapatna@Sun.COM 		ldcp->rx_dring_handle = 0;
33312011SSriharsha.Basavapatna@Sun.COM 		ldcp->rxdp = NULL;
33412011SSriharsha.Basavapatna@Sun.COM 	}
33512011SSriharsha.Basavapatna@Sun.COM 
33612011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->rxdp_to_vmp != NULL) {
33712011SSriharsha.Basavapatna@Sun.COM 		kmem_free(ldcp->rxdp_to_vmp,
33812011SSriharsha.Basavapatna@Sun.COM 		    ldcp->num_rxds * sizeof (uintptr_t));
33912011SSriharsha.Basavapatna@Sun.COM 		ldcp->rxdp_to_vmp = NULL;
34012011SSriharsha.Basavapatna@Sun.COM 	}
34112011SSriharsha.Basavapatna@Sun.COM 
34212011SSriharsha.Basavapatna@Sun.COM 	/* Reset rx index and seqnum */
34312011SSriharsha.Basavapatna@Sun.COM 	ldcp->next_rxi = 0;
34412011SSriharsha.Basavapatna@Sun.COM 	ldcp->next_rxseq = VNET_ISS;
34512011SSriharsha.Basavapatna@Sun.COM }
34612011SSriharsha.Basavapatna@Sun.COM 
34712011SSriharsha.Basavapatna@Sun.COM /*
34812011SSriharsha.Basavapatna@Sun.COM  * Map the receive descriptor ring exported
34912011SSriharsha.Basavapatna@Sun.COM  * by the peer, as our transmit descriptor ring.
35012011SSriharsha.Basavapatna@Sun.COM  */
35112011SSriharsha.Basavapatna@Sun.COM int
vgen_map_tx_dring(vgen_ldc_t * ldcp,void * pkt)35212011SSriharsha.Basavapatna@Sun.COM vgen_map_tx_dring(vgen_ldc_t *ldcp, void *pkt)
35312011SSriharsha.Basavapatna@Sun.COM {
35412011SSriharsha.Basavapatna@Sun.COM 	int				i;
35512011SSriharsha.Basavapatna@Sun.COM 	int				rv;
35612011SSriharsha.Basavapatna@Sun.COM 	ldc_mem_info_t			minfo;
35712011SSriharsha.Basavapatna@Sun.COM 	ldc_mem_cookie_t		dcookie;
35812011SSriharsha.Basavapatna@Sun.COM 	uint32_t			ncookies;
35912011SSriharsha.Basavapatna@Sun.COM 	uint32_t 			num_desc;
36012011SSriharsha.Basavapatna@Sun.COM 	uint32_t			desc_size;
36112011SSriharsha.Basavapatna@Sun.COM 	vnet_rx_dringdata_desc_t	*txdp;
36212011SSriharsha.Basavapatna@Sun.COM 	on_trap_data_t			otd;
36312011SSriharsha.Basavapatna@Sun.COM 	vio_dring_reg_msg_t 		*msg = pkt;
36412011SSriharsha.Basavapatna@Sun.COM 
36512011SSriharsha.Basavapatna@Sun.COM 	ncookies = msg->ncookies;
36612011SSriharsha.Basavapatna@Sun.COM 	num_desc = msg->num_descriptors;
36712011SSriharsha.Basavapatna@Sun.COM 	desc_size = msg->descriptor_size;
36812011SSriharsha.Basavapatna@Sun.COM 
36912011SSriharsha.Basavapatna@Sun.COM 	/*
37012011SSriharsha.Basavapatna@Sun.COM 	 * Sanity check.
37112011SSriharsha.Basavapatna@Sun.COM 	 */
37212011SSriharsha.Basavapatna@Sun.COM 	if (num_desc < VGEN_NUM_DESCRIPTORS_MIN ||
37312011SSriharsha.Basavapatna@Sun.COM 	    desc_size < sizeof (vnet_rx_dringdata_desc_t) ||
37412011SSriharsha.Basavapatna@Sun.COM 	    ncookies > 1) {
37512011SSriharsha.Basavapatna@Sun.COM 		goto fail;
37612011SSriharsha.Basavapatna@Sun.COM 	}
37712011SSriharsha.Basavapatna@Sun.COM 
37812011SSriharsha.Basavapatna@Sun.COM 	bcopy(&msg->cookie[0], &dcookie, sizeof (ldc_mem_cookie_t));
37912011SSriharsha.Basavapatna@Sun.COM 
38012011SSriharsha.Basavapatna@Sun.COM 	/* Map the remote dring */
38112011SSriharsha.Basavapatna@Sun.COM 	rv = ldc_mem_dring_map(ldcp->ldc_handle, &dcookie, ncookies, num_desc,
38212011SSriharsha.Basavapatna@Sun.COM 	    desc_size, LDC_DIRECT_MAP, &(ldcp->tx_dring_handle));
38312011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
38412011SSriharsha.Basavapatna@Sun.COM 		goto fail;
38512011SSriharsha.Basavapatna@Sun.COM 	}
38612011SSriharsha.Basavapatna@Sun.COM 
38712011SSriharsha.Basavapatna@Sun.COM 	/*
38812011SSriharsha.Basavapatna@Sun.COM 	 * Sucessfully mapped; now try to get info about the mapped dring
38912011SSriharsha.Basavapatna@Sun.COM 	 */
39012011SSriharsha.Basavapatna@Sun.COM 	rv = ldc_mem_dring_info(ldcp->tx_dring_handle, &minfo);
39112011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
39212011SSriharsha.Basavapatna@Sun.COM 		goto fail;
39312011SSriharsha.Basavapatna@Sun.COM 	}
39412011SSriharsha.Basavapatna@Sun.COM 
39512011SSriharsha.Basavapatna@Sun.COM 	/*
39612011SSriharsha.Basavapatna@Sun.COM 	 * Save ring address, number of descriptors.
39712011SSriharsha.Basavapatna@Sun.COM 	 */
39812011SSriharsha.Basavapatna@Sun.COM 	ldcp->mtxdp = (vnet_rx_dringdata_desc_t *)(minfo.vaddr);
39912011SSriharsha.Basavapatna@Sun.COM 	bcopy(&dcookie, &(ldcp->tx_dring_cookie), sizeof (dcookie));
40012011SSriharsha.Basavapatna@Sun.COM 	ldcp->tx_dring_ncookies = ncookies;
40112011SSriharsha.Basavapatna@Sun.COM 	ldcp->num_txds = num_desc;
40212011SSriharsha.Basavapatna@Sun.COM 
40312011SSriharsha.Basavapatna@Sun.COM 	/* Initialize tx dring indexes and seqnum */
40412950SWentao.Yang@Sun.COM 	ldcp->next_txi = ldcp->cur_txi = ldcp->resched_peer_txi = 0;
40512011SSriharsha.Basavapatna@Sun.COM 	ldcp->next_txseq = VNET_ISS - 1;
40612011SSriharsha.Basavapatna@Sun.COM 	ldcp->resched_peer = B_TRUE;
40712011SSriharsha.Basavapatna@Sun.COM 	ldcp->dring_mtype = minfo.mtype;
40812011SSriharsha.Basavapatna@Sun.COM 	ldcp->dringdata_msgid = 0;
40912011SSriharsha.Basavapatna@Sun.COM 
41012011SSriharsha.Basavapatna@Sun.COM 	/* Save peer's dring_info values */
41112011SSriharsha.Basavapatna@Sun.COM 	bcopy(&dcookie, &(ldcp->peer_hparams.dring_cookie),
41212011SSriharsha.Basavapatna@Sun.COM 	    sizeof (ldc_mem_cookie_t));
41312011SSriharsha.Basavapatna@Sun.COM 	ldcp->peer_hparams.num_desc = num_desc;
41412011SSriharsha.Basavapatna@Sun.COM 	ldcp->peer_hparams.desc_size = desc_size;
41512011SSriharsha.Basavapatna@Sun.COM 	ldcp->peer_hparams.dring_ncookies = ncookies;
41612011SSriharsha.Basavapatna@Sun.COM 
41712011SSriharsha.Basavapatna@Sun.COM 	/* Set dring_ident for the peer */
41812011SSriharsha.Basavapatna@Sun.COM 	ldcp->peer_hparams.dring_ident = (uint64_t)ldcp->mtxdp;
41912011SSriharsha.Basavapatna@Sun.COM 
42012011SSriharsha.Basavapatna@Sun.COM 	/* Return the dring_ident in ack msg */
42112011SSriharsha.Basavapatna@Sun.COM 	msg->dring_ident = (uint64_t)ldcp->mtxdp;
42212011SSriharsha.Basavapatna@Sun.COM 
42312011SSriharsha.Basavapatna@Sun.COM 	/*
42412011SSriharsha.Basavapatna@Sun.COM 	 * Mark the descriptor state as 'done'. This is implementation specific
42512011SSriharsha.Basavapatna@Sun.COM 	 * and not required by the protocol. In our implementation, we only
42612011SSriharsha.Basavapatna@Sun.COM 	 * need the descripor to be in 'done' state to be used by the transmit
42712011SSriharsha.Basavapatna@Sun.COM 	 * function and the peer is not aware of it. As the protocol requires
42812011SSriharsha.Basavapatna@Sun.COM 	 * that during initial registration the exporting end point mark the
42912011SSriharsha.Basavapatna@Sun.COM 	 * dstate as 'free', we change it 'done' here. After this, the dstate
43012011SSriharsha.Basavapatna@Sun.COM 	 * in our implementation will keep moving between 'ready', set by our
43112011SSriharsha.Basavapatna@Sun.COM 	 * transmit function; and and 'done', set by the peer (per protocol)
43212011SSriharsha.Basavapatna@Sun.COM 	 * after receiving data.
43312011SSriharsha.Basavapatna@Sun.COM 	 * Setup on_trap() protection before accessing dring shared memory area.
43412011SSriharsha.Basavapatna@Sun.COM 	 */
43512011SSriharsha.Basavapatna@Sun.COM 	rv = LDC_ON_TRAP(&otd);
43612011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
43712011SSriharsha.Basavapatna@Sun.COM 		/*
43812011SSriharsha.Basavapatna@Sun.COM 		 * Data access fault occured down the code path below while
43912011SSriharsha.Basavapatna@Sun.COM 		 * accessing the descriptors. Return failure.
44012011SSriharsha.Basavapatna@Sun.COM 		 */
44112011SSriharsha.Basavapatna@Sun.COM 		goto fail;
44212011SSriharsha.Basavapatna@Sun.COM 	}
44312011SSriharsha.Basavapatna@Sun.COM 
44412011SSriharsha.Basavapatna@Sun.COM 	for (i = 0; i < num_desc; i++) {
44512011SSriharsha.Basavapatna@Sun.COM 		txdp = &ldcp->mtxdp[i];
44612011SSriharsha.Basavapatna@Sun.COM 		txdp->dstate = VIO_DESC_DONE;
44712011SSriharsha.Basavapatna@Sun.COM 	}
44812011SSriharsha.Basavapatna@Sun.COM 
44912011SSriharsha.Basavapatna@Sun.COM 	(void) LDC_NO_TRAP();
45012011SSriharsha.Basavapatna@Sun.COM 	return (VGEN_SUCCESS);
45112011SSriharsha.Basavapatna@Sun.COM 
45212011SSriharsha.Basavapatna@Sun.COM fail:
45312011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->tx_dring_handle != 0) {
45412011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_dring_unmap(ldcp->tx_dring_handle);
45512011SSriharsha.Basavapatna@Sun.COM 		ldcp->tx_dring_handle = 0;
45612011SSriharsha.Basavapatna@Sun.COM 	}
45712011SSriharsha.Basavapatna@Sun.COM 	return (VGEN_FAILURE);
45812011SSriharsha.Basavapatna@Sun.COM }
45912011SSriharsha.Basavapatna@Sun.COM 
46012011SSriharsha.Basavapatna@Sun.COM /*
46112011SSriharsha.Basavapatna@Sun.COM  * Unmap the transmit descriptor ring.
46212011SSriharsha.Basavapatna@Sun.COM  */
46312011SSriharsha.Basavapatna@Sun.COM void
vgen_unmap_tx_dring(vgen_ldc_t * ldcp)46412011SSriharsha.Basavapatna@Sun.COM vgen_unmap_tx_dring(vgen_ldc_t *ldcp)
46512011SSriharsha.Basavapatna@Sun.COM {
46612011SSriharsha.Basavapatna@Sun.COM 	/* Unmap mapped tx data area */
46712011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->tx_datap != NULL) {
46812011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_unmap(ldcp->tx_data_handle);
46912011SSriharsha.Basavapatna@Sun.COM 		ldcp->tx_datap = NULL;
47012011SSriharsha.Basavapatna@Sun.COM 	}
47112011SSriharsha.Basavapatna@Sun.COM 
47212011SSriharsha.Basavapatna@Sun.COM 	/* Free tx data area handle */
47312011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->tx_data_handle != 0) {
47412011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_free_handle(ldcp->tx_data_handle);
47512011SSriharsha.Basavapatna@Sun.COM 		ldcp->tx_data_handle = 0;
47612011SSriharsha.Basavapatna@Sun.COM 	}
47712011SSriharsha.Basavapatna@Sun.COM 
47812011SSriharsha.Basavapatna@Sun.COM 	/* Free tx data area cookies */
47912011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->tx_data_cookie != NULL) {
48012011SSriharsha.Basavapatna@Sun.COM 		kmem_free(ldcp->tx_data_cookie, ldcp->tx_data_ncookies *
48112011SSriharsha.Basavapatna@Sun.COM 		    sizeof (ldc_mem_cookie_t));
48212011SSriharsha.Basavapatna@Sun.COM 		ldcp->tx_data_cookie = NULL;
48312011SSriharsha.Basavapatna@Sun.COM 		ldcp->tx_data_ncookies = 0;
48412011SSriharsha.Basavapatna@Sun.COM 	}
48512011SSriharsha.Basavapatna@Sun.COM 
48612011SSriharsha.Basavapatna@Sun.COM 	/* Unmap peer's dring */
48712011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->tx_dring_handle != 0) {
48812011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_dring_unmap(ldcp->tx_dring_handle);
48912011SSriharsha.Basavapatna@Sun.COM 		ldcp->tx_dring_handle = 0;
49012011SSriharsha.Basavapatna@Sun.COM 	}
49112011SSriharsha.Basavapatna@Sun.COM 
49212011SSriharsha.Basavapatna@Sun.COM 	/* clobber tx ring members */
49312011SSriharsha.Basavapatna@Sun.COM 	bzero(&ldcp->tx_dring_cookie, sizeof (ldcp->tx_dring_cookie));
49412011SSriharsha.Basavapatna@Sun.COM 	ldcp->mtxdp = NULL;
49512950SWentao.Yang@Sun.COM 	ldcp->next_txi = ldcp->cur_txi = ldcp->resched_peer_txi = 0;
49612011SSriharsha.Basavapatna@Sun.COM 	ldcp->num_txds = 0;
49712011SSriharsha.Basavapatna@Sun.COM 	ldcp->next_txseq = VNET_ISS - 1;
49812011SSriharsha.Basavapatna@Sun.COM 	ldcp->resched_peer = B_TRUE;
49912011SSriharsha.Basavapatna@Sun.COM }
50012011SSriharsha.Basavapatna@Sun.COM 
50112011SSriharsha.Basavapatna@Sun.COM /*
50212011SSriharsha.Basavapatna@Sun.COM  * Map the shared memory data buffer area exported by the peer.
50312011SSriharsha.Basavapatna@Sun.COM  */
50412011SSriharsha.Basavapatna@Sun.COM int
vgen_map_data(vgen_ldc_t * ldcp,void * pkt)50512011SSriharsha.Basavapatna@Sun.COM vgen_map_data(vgen_ldc_t *ldcp, void *pkt)
50612011SSriharsha.Basavapatna@Sun.COM {
50712011SSriharsha.Basavapatna@Sun.COM 	int			rv;
50812011SSriharsha.Basavapatna@Sun.COM 	vio_dring_reg_ext_msg_t	*emsg;
50912011SSriharsha.Basavapatna@Sun.COM 	vio_dring_reg_msg_t	*msg = (vio_dring_reg_msg_t *)pkt;
51012011SSriharsha.Basavapatna@Sun.COM 	uint8_t			*buf = (uint8_t *)msg->cookie;
51112011SSriharsha.Basavapatna@Sun.COM 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
512*13098SWentao.Yang@Sun.COM 	ldc_mem_info_t		minfo;
51312011SSriharsha.Basavapatna@Sun.COM 
51412011SSriharsha.Basavapatna@Sun.COM 	/* skip over dring cookies */
51512011SSriharsha.Basavapatna@Sun.COM 	ASSERT(msg->ncookies == 1);
51612011SSriharsha.Basavapatna@Sun.COM 	buf += (msg->ncookies * sizeof (ldc_mem_cookie_t));
51712011SSriharsha.Basavapatna@Sun.COM 
51812011SSriharsha.Basavapatna@Sun.COM 	emsg = (vio_dring_reg_ext_msg_t *)buf;
51912011SSriharsha.Basavapatna@Sun.COM 	if (emsg->data_ncookies > VNET_DATA_AREA_COOKIES) {
52012011SSriharsha.Basavapatna@Sun.COM 		return (VGEN_FAILURE);
52112011SSriharsha.Basavapatna@Sun.COM 	}
52212011SSriharsha.Basavapatna@Sun.COM 
52312011SSriharsha.Basavapatna@Sun.COM 	/* save # of data area cookies */
52412011SSriharsha.Basavapatna@Sun.COM 	ldcp->tx_data_ncookies = emsg->data_ncookies;
52512011SSriharsha.Basavapatna@Sun.COM 
52612011SSriharsha.Basavapatna@Sun.COM 	/* save data area size */
52712011SSriharsha.Basavapatna@Sun.COM 	ldcp->tx_data_sz = emsg->data_area_size;
52812011SSriharsha.Basavapatna@Sun.COM 
52912011SSriharsha.Basavapatna@Sun.COM 	/* allocate ldc mem handle for data area */
53012011SSriharsha.Basavapatna@Sun.COM 	rv = ldc_mem_alloc_handle(ldcp->ldc_handle, &ldcp->tx_data_handle);
53112011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
53212011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "ldc_mem_alloc_handle() failed: %d\n", rv);
53312011SSriharsha.Basavapatna@Sun.COM 		return (VGEN_FAILURE);
53412011SSriharsha.Basavapatna@Sun.COM 	}
53512011SSriharsha.Basavapatna@Sun.COM 
53612011SSriharsha.Basavapatna@Sun.COM 	/* map the data area */
53712011SSriharsha.Basavapatna@Sun.COM 	rv = ldc_mem_map(ldcp->tx_data_handle, emsg->data_cookie,
53812011SSriharsha.Basavapatna@Sun.COM 	    emsg->data_ncookies, LDC_DIRECT_MAP, LDC_MEM_W,
53912011SSriharsha.Basavapatna@Sun.COM 	    (caddr_t *)&ldcp->tx_datap, NULL);
54012011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
54112011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "ldc_mem_map() failed: %d\n", rv);
542*13098SWentao.Yang@Sun.COM 		return (VGEN_FAILURE);
543*13098SWentao.Yang@Sun.COM 	}
544*13098SWentao.Yang@Sun.COM 
545*13098SWentao.Yang@Sun.COM 	/* get the map info */
546*13098SWentao.Yang@Sun.COM 	rv = ldc_mem_info(ldcp->tx_data_handle, &minfo);
547*13098SWentao.Yang@Sun.COM 	if (rv != 0) {
548*13098SWentao.Yang@Sun.COM 		DWARN(vgenp, ldcp, "ldc_mem_info() failed: %d\n", rv);
549*13098SWentao.Yang@Sun.COM 		return (VGEN_FAILURE);
550*13098SWentao.Yang@Sun.COM 	}
551*13098SWentao.Yang@Sun.COM 
552*13098SWentao.Yang@Sun.COM 	if (minfo.mtype != LDC_DIRECT_MAP) {
553*13098SWentao.Yang@Sun.COM 		DWARN(vgenp, ldcp, "mtype(%d) is not direct map\n",
554*13098SWentao.Yang@Sun.COM 		    minfo.mtype);
55512011SSriharsha.Basavapatna@Sun.COM 		return (VGEN_FAILURE);
55612011SSriharsha.Basavapatna@Sun.COM 	}
55712011SSriharsha.Basavapatna@Sun.COM 
55812011SSriharsha.Basavapatna@Sun.COM 	/* allocate memory for data area cookies */
55912011SSriharsha.Basavapatna@Sun.COM 	ldcp->tx_data_cookie = kmem_zalloc(emsg->data_ncookies *
56012011SSriharsha.Basavapatna@Sun.COM 	    sizeof (ldc_mem_cookie_t), KM_SLEEP);
56112011SSriharsha.Basavapatna@Sun.COM 
56212011SSriharsha.Basavapatna@Sun.COM 	/* save data area cookies */
56312011SSriharsha.Basavapatna@Sun.COM 	bcopy(emsg->data_cookie, ldcp->tx_data_cookie,
56412011SSriharsha.Basavapatna@Sun.COM 	    emsg->data_ncookies * sizeof (ldc_mem_cookie_t));
56512011SSriharsha.Basavapatna@Sun.COM 
56612011SSriharsha.Basavapatna@Sun.COM 	return (VGEN_SUCCESS);
56712011SSriharsha.Basavapatna@Sun.COM }
56812011SSriharsha.Basavapatna@Sun.COM 
56912011SSriharsha.Basavapatna@Sun.COM /*
57012011SSriharsha.Basavapatna@Sun.COM  * This function transmits normal data frames (non-priority) over the channel.
57112011SSriharsha.Basavapatna@Sun.COM  * It queues the frame into the transmit descriptor ring and sends a
57212011SSriharsha.Basavapatna@Sun.COM  * VIO_DRING_DATA message if needed, to wake up the peer to (re)start
57312011SSriharsha.Basavapatna@Sun.COM  * processing.
57412011SSriharsha.Basavapatna@Sun.COM  */
57512011SSriharsha.Basavapatna@Sun.COM int
vgen_dringsend_shm(void * arg,mblk_t * mp)57612011SSriharsha.Basavapatna@Sun.COM vgen_dringsend_shm(void *arg, mblk_t *mp)
57712011SSriharsha.Basavapatna@Sun.COM {
57812011SSriharsha.Basavapatna@Sun.COM 	uint32_t			next_txi;
57912011SSriharsha.Basavapatna@Sun.COM 	uint32_t			txi;
58012011SSriharsha.Basavapatna@Sun.COM 	vnet_rx_dringdata_desc_t	*txdp;
58112011SSriharsha.Basavapatna@Sun.COM 	struct ether_header		*ehp;
58212011SSriharsha.Basavapatna@Sun.COM 	size_t				mblksz;
58312011SSriharsha.Basavapatna@Sun.COM 	caddr_t				dst;
58412011SSriharsha.Basavapatna@Sun.COM 	mblk_t				*bp;
58512011SSriharsha.Basavapatna@Sun.COM 	size_t				size;
58612011SSriharsha.Basavapatna@Sun.COM 	uint32_t			buf_offset;
58712011SSriharsha.Basavapatna@Sun.COM 	on_trap_data_t			otd;
58812011SSriharsha.Basavapatna@Sun.COM 	int				rv = 0;
58912011SSriharsha.Basavapatna@Sun.COM 	boolean_t			is_bcast = B_FALSE;
59012011SSriharsha.Basavapatna@Sun.COM 	boolean_t			is_mcast = B_FALSE;
59112011SSriharsha.Basavapatna@Sun.COM 	vgen_ldc_t			*ldcp = (vgen_ldc_t *)arg;
59212011SSriharsha.Basavapatna@Sun.COM 	vgen_t				*vgenp = LDC_TO_VGEN(ldcp);
59312011SSriharsha.Basavapatna@Sun.COM 	vgen_stats_t			*statsp = &ldcp->stats;
59412011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t			*lp = &ldcp->local_hparams;
59512011SSriharsha.Basavapatna@Sun.COM 	boolean_t			resched_peer = B_FALSE;
59612011SSriharsha.Basavapatna@Sun.COM 	boolean_t			tx_update = B_FALSE;
59712011SSriharsha.Basavapatna@Sun.COM 
59812011SSriharsha.Basavapatna@Sun.COM 	/* Drop the packet if ldc is not up or handshake is not done */
59912011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->ldc_status != LDC_UP) {
60012011SSriharsha.Basavapatna@Sun.COM 		DBG2(vgenp, ldcp, "status(%d), dropping packet\n",
60112011SSriharsha.Basavapatna@Sun.COM 		    ldcp->ldc_status);
60212011SSriharsha.Basavapatna@Sun.COM 		goto dringsend_shm_exit;
60312011SSriharsha.Basavapatna@Sun.COM 	}
60412011SSriharsha.Basavapatna@Sun.COM 
60512011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->hphase != VH_DONE) {
60612011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "hphase(%x), dropping packet\n",
60712011SSriharsha.Basavapatna@Sun.COM 		    ldcp->hphase);
60812011SSriharsha.Basavapatna@Sun.COM 		goto dringsend_shm_exit;
60912011SSriharsha.Basavapatna@Sun.COM 	}
61012011SSriharsha.Basavapatna@Sun.COM 
61112011SSriharsha.Basavapatna@Sun.COM 	size = msgsize(mp);
61212011SSriharsha.Basavapatna@Sun.COM 	if (size > (size_t)lp->mtu) {
61312011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "invalid size(%d)\n", size);
61412011SSriharsha.Basavapatna@Sun.COM 		goto dringsend_shm_exit;
61512011SSriharsha.Basavapatna@Sun.COM 	}
61612011SSriharsha.Basavapatna@Sun.COM 	if (size < ETHERMIN)
61712011SSriharsha.Basavapatna@Sun.COM 		size = ETHERMIN;
61812011SSriharsha.Basavapatna@Sun.COM 
61912011SSriharsha.Basavapatna@Sun.COM 	ehp = (struct ether_header *)mp->b_rptr;
62012011SSriharsha.Basavapatna@Sun.COM 	is_bcast = IS_BROADCAST(ehp);
62112011SSriharsha.Basavapatna@Sun.COM 	is_mcast = IS_MULTICAST(ehp);
62212011SSriharsha.Basavapatna@Sun.COM 
62312011SSriharsha.Basavapatna@Sun.COM 	/*
62412011SSriharsha.Basavapatna@Sun.COM 	 * Setup on_trap() protection before accessing shared memory areas
62512011SSriharsha.Basavapatna@Sun.COM 	 * (descriptor and data buffer). Note that we enable this protection a
62612011SSriharsha.Basavapatna@Sun.COM 	 * little early and turn it off slightly later, than keeping it enabled
62712011SSriharsha.Basavapatna@Sun.COM 	 * strictly at the points in code below where the descriptor and data
62812011SSriharsha.Basavapatna@Sun.COM 	 * buffer are accessed. This is done for performance reasons:
62912011SSriharsha.Basavapatna@Sun.COM 	 * (a) to avoid calling the trap protection code while holding mutex.
63012011SSriharsha.Basavapatna@Sun.COM 	 * (b) to avoid multiple on/off steps for descriptor and data accesses.
63112011SSriharsha.Basavapatna@Sun.COM 	 */
63212011SSriharsha.Basavapatna@Sun.COM 	rv = LDC_ON_TRAP(&otd);
63312011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
63412011SSriharsha.Basavapatna@Sun.COM 		/*
63512011SSriharsha.Basavapatna@Sun.COM 		 * Data access fault occured down the code path below while
63612011SSriharsha.Basavapatna@Sun.COM 		 * accessing either the descriptor or the data buffer. Release
63712011SSriharsha.Basavapatna@Sun.COM 		 * any locks that we might have acquired in the code below and
63812011SSriharsha.Basavapatna@Sun.COM 		 * return failure.
63912011SSriharsha.Basavapatna@Sun.COM 		 */
64012011SSriharsha.Basavapatna@Sun.COM 		DERR(vgenp, ldcp, "data access fault occured\n");
64112011SSriharsha.Basavapatna@Sun.COM 		statsp->oerrors++;
64212011SSriharsha.Basavapatna@Sun.COM 		if (mutex_owned(&ldcp->txlock)) {
64312011SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&ldcp->txlock);
64412011SSriharsha.Basavapatna@Sun.COM 		}
64512011SSriharsha.Basavapatna@Sun.COM 		if (mutex_owned(&ldcp->wrlock)) {
64612011SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&ldcp->wrlock);
64712011SSriharsha.Basavapatna@Sun.COM 		}
64812011SSriharsha.Basavapatna@Sun.COM 		goto dringsend_shm_exit;
64912011SSriharsha.Basavapatna@Sun.COM 	}
65012011SSriharsha.Basavapatna@Sun.COM 
65112011SSriharsha.Basavapatna@Sun.COM 	/*
65212011SSriharsha.Basavapatna@Sun.COM 	 * Allocate a descriptor
65312011SSriharsha.Basavapatna@Sun.COM 	 */
65412011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->txlock);
65512011SSriharsha.Basavapatna@Sun.COM 	txi = next_txi = ldcp->next_txi;
65612011SSriharsha.Basavapatna@Sun.COM 	INCR_TXI(next_txi, ldcp);
65712950SWentao.Yang@Sun.COM 	txdp = &(ldcp->mtxdp[txi]);
65812950SWentao.Yang@Sun.COM 	if (txdp->dstate != VIO_DESC_DONE) { /* out of descriptors */
65912011SSriharsha.Basavapatna@Sun.COM 		if (ldcp->tx_blocked == B_FALSE) {
66012011SSriharsha.Basavapatna@Sun.COM 			ldcp->tx_blocked_lbolt = ddi_get_lbolt();
66112011SSriharsha.Basavapatna@Sun.COM 			ldcp->tx_blocked = B_TRUE;
66212011SSriharsha.Basavapatna@Sun.COM 		}
66312011SSriharsha.Basavapatna@Sun.COM 		statsp->tx_no_desc++;
66412011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->txlock);
66512011SSriharsha.Basavapatna@Sun.COM 		(void) LDC_NO_TRAP();
66612011SSriharsha.Basavapatna@Sun.COM 		return (VGEN_TX_NORESOURCES);
66712950SWentao.Yang@Sun.COM 	} else {
66812950SWentao.Yang@Sun.COM 		txdp->dstate = VIO_DESC_INITIALIZING;
66912011SSriharsha.Basavapatna@Sun.COM 	}
67012011SSriharsha.Basavapatna@Sun.COM 
67112011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->tx_blocked == B_TRUE) {
67212011SSriharsha.Basavapatna@Sun.COM 		ldcp->tx_blocked = B_FALSE;
67312011SSriharsha.Basavapatna@Sun.COM 		tx_update = B_TRUE;
67412011SSriharsha.Basavapatna@Sun.COM 	}
67512011SSriharsha.Basavapatna@Sun.COM 
67612011SSriharsha.Basavapatna@Sun.COM 	/* Update descriptor ring index */
67712011SSriharsha.Basavapatna@Sun.COM 	ldcp->next_txi = next_txi;
67812011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&ldcp->txlock);
67912011SSriharsha.Basavapatna@Sun.COM 
68012011SSriharsha.Basavapatna@Sun.COM 	if (tx_update == B_TRUE) {
68112011SSriharsha.Basavapatna@Sun.COM 		vio_net_tx_update_t vtx_update =
68212011SSriharsha.Basavapatna@Sun.COM 		    ldcp->portp->vcb.vio_net_tx_update;
68312011SSriharsha.Basavapatna@Sun.COM 
68412011SSriharsha.Basavapatna@Sun.COM 		vtx_update(ldcp->portp->vhp);
68512011SSriharsha.Basavapatna@Sun.COM 	}
68612011SSriharsha.Basavapatna@Sun.COM 
68712011SSriharsha.Basavapatna@Sun.COM 	/* Ensure load ordering of dstate (above) and data_buf_offset. */
68812011SSriharsha.Basavapatna@Sun.COM 	MEMBAR_CONSUMER();
68912011SSriharsha.Basavapatna@Sun.COM 
69012011SSriharsha.Basavapatna@Sun.COM 	/* Get the offset of the buffer to be used */
69112011SSriharsha.Basavapatna@Sun.COM 	buf_offset = txdp->data_buf_offset;
69212011SSriharsha.Basavapatna@Sun.COM 
69312011SSriharsha.Basavapatna@Sun.COM 	/* Access the buffer using the offset */
69412011SSriharsha.Basavapatna@Sun.COM 	dst = (caddr_t)ldcp->tx_datap + buf_offset;
69512011SSriharsha.Basavapatna@Sun.COM 
69612011SSriharsha.Basavapatna@Sun.COM 	/* Copy data into mapped transmit buffer */
69712011SSriharsha.Basavapatna@Sun.COM 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
69812011SSriharsha.Basavapatna@Sun.COM 		mblksz = MBLKL(bp);
69912011SSriharsha.Basavapatna@Sun.COM 		bcopy(bp->b_rptr, dst, mblksz);
70012011SSriharsha.Basavapatna@Sun.COM 		dst += mblksz;
70112011SSriharsha.Basavapatna@Sun.COM 	}
70212011SSriharsha.Basavapatna@Sun.COM 
70312011SSriharsha.Basavapatna@Sun.COM 	/* Set the size of data in the descriptor */
70412011SSriharsha.Basavapatna@Sun.COM 	txdp->nbytes = size;
70512011SSriharsha.Basavapatna@Sun.COM 
70612011SSriharsha.Basavapatna@Sun.COM 	/*
70712011SSriharsha.Basavapatna@Sun.COM 	 * Ensure store ordering of nbytes and dstate (below); so that the peer
70812011SSriharsha.Basavapatna@Sun.COM 	 * sees the right nbytes value after it checks that the dstate is READY.
70912011SSriharsha.Basavapatna@Sun.COM 	 */
71012011SSriharsha.Basavapatna@Sun.COM 	MEMBAR_PRODUCER();
71112011SSriharsha.Basavapatna@Sun.COM 
71212011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->wrlock);
71312011SSriharsha.Basavapatna@Sun.COM 
71412950SWentao.Yang@Sun.COM 	ASSERT(txdp->dstate == VIO_DESC_INITIALIZING);
71512950SWentao.Yang@Sun.COM 
71612011SSriharsha.Basavapatna@Sun.COM 	/* Mark the descriptor ready */
71712011SSriharsha.Basavapatna@Sun.COM 	txdp->dstate = VIO_DESC_READY;
71812011SSriharsha.Basavapatna@Sun.COM 
71912011SSriharsha.Basavapatna@Sun.COM 	/* Check if peer needs wake up (handled below) */
72012950SWentao.Yang@Sun.COM 	if (ldcp->resched_peer == B_TRUE && ldcp->resched_peer_txi == txi) {
72112950SWentao.Yang@Sun.COM 		resched_peer = B_TRUE;
72212011SSriharsha.Basavapatna@Sun.COM 		ldcp->resched_peer = B_FALSE;
72312011SSriharsha.Basavapatna@Sun.COM 	}
72412011SSriharsha.Basavapatna@Sun.COM 
72512011SSriharsha.Basavapatna@Sun.COM 	/* Update tx stats */
72612011SSriharsha.Basavapatna@Sun.COM 	statsp->opackets++;
72712011SSriharsha.Basavapatna@Sun.COM 	statsp->obytes += size;
72812011SSriharsha.Basavapatna@Sun.COM 	if (is_bcast)
72912011SSriharsha.Basavapatna@Sun.COM 		statsp->brdcstxmt++;
73012011SSriharsha.Basavapatna@Sun.COM 	else if (is_mcast)
73112011SSriharsha.Basavapatna@Sun.COM 		statsp->multixmt++;
73212011SSriharsha.Basavapatna@Sun.COM 
73312011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&ldcp->wrlock);
73412011SSriharsha.Basavapatna@Sun.COM 
73512011SSriharsha.Basavapatna@Sun.COM 	/*
73612011SSriharsha.Basavapatna@Sun.COM 	 * We are done accessing shared memory; clear trap protection.
73712011SSriharsha.Basavapatna@Sun.COM 	 */
73812011SSriharsha.Basavapatna@Sun.COM 	(void) LDC_NO_TRAP();
73912011SSriharsha.Basavapatna@Sun.COM 
74012011SSriharsha.Basavapatna@Sun.COM 	/*
74112011SSriharsha.Basavapatna@Sun.COM 	 * Need to wake up the peer ?
74212011SSriharsha.Basavapatna@Sun.COM 	 */
74312011SSriharsha.Basavapatna@Sun.COM 	if (resched_peer == B_TRUE) {
74412011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_send_dringdata_shm(ldcp, (uint32_t)txi, -1);
74512011SSriharsha.Basavapatna@Sun.COM 		if (rv != 0) {
74612011SSriharsha.Basavapatna@Sun.COM 			/* error: drop the packet */
74712011SSriharsha.Basavapatna@Sun.COM 			DWARN(vgenp, ldcp, "failed sending dringdata msg "
74812011SSriharsha.Basavapatna@Sun.COM 			    "rv(%d) len(%d)\n", rv, size);
74912011SSriharsha.Basavapatna@Sun.COM 			mutex_enter(&ldcp->wrlock);
75012011SSriharsha.Basavapatna@Sun.COM 			statsp->oerrors++;
75112011SSriharsha.Basavapatna@Sun.COM 			ldcp->resched_peer = B_TRUE;
75212011SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&ldcp->wrlock);
75312011SSriharsha.Basavapatna@Sun.COM 		}
75412011SSriharsha.Basavapatna@Sun.COM 	}
75512011SSriharsha.Basavapatna@Sun.COM 
75612011SSriharsha.Basavapatna@Sun.COM dringsend_shm_exit:
75712011SSriharsha.Basavapatna@Sun.COM 	if (rv == ECONNRESET || rv == EACCES) {
75812011SSriharsha.Basavapatna@Sun.COM 		(void) vgen_handle_evt_reset(ldcp, VGEN_OTHER);
75912011SSriharsha.Basavapatna@Sun.COM 	}
76012011SSriharsha.Basavapatna@Sun.COM 	freemsg(mp);
76112011SSriharsha.Basavapatna@Sun.COM 	return (VGEN_TX_SUCCESS);
76212011SSriharsha.Basavapatna@Sun.COM }
76312011SSriharsha.Basavapatna@Sun.COM 
76412011SSriharsha.Basavapatna@Sun.COM /*
76512011SSriharsha.Basavapatna@Sun.COM  * Process dring data messages (info/ack/nack)
76612011SSriharsha.Basavapatna@Sun.COM  */
76712011SSriharsha.Basavapatna@Sun.COM int
vgen_handle_dringdata_shm(void * arg1,void * arg2)76812011SSriharsha.Basavapatna@Sun.COM vgen_handle_dringdata_shm(void *arg1, void *arg2)
76912011SSriharsha.Basavapatna@Sun.COM {
77012011SSriharsha.Basavapatna@Sun.COM 	vgen_ldc_t	*ldcp = (vgen_ldc_t *)arg1;
77112011SSriharsha.Basavapatna@Sun.COM 	vio_msg_tag_t	*tagp = (vio_msg_tag_t *)arg2;
77212011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
77312011SSriharsha.Basavapatna@Sun.COM 	int		rv = 0;
77412011SSriharsha.Basavapatna@Sun.COM 
77512011SSriharsha.Basavapatna@Sun.COM 	switch (tagp->vio_subtype) {
77612011SSriharsha.Basavapatna@Sun.COM 
77712011SSriharsha.Basavapatna@Sun.COM 	case VIO_SUBTYPE_INFO:
77812011SSriharsha.Basavapatna@Sun.COM 		/*
77912011SSriharsha.Basavapatna@Sun.COM 		 * To reduce the locking contention, release the
78012011SSriharsha.Basavapatna@Sun.COM 		 * cblock here and re-acquire it once we are done
78112011SSriharsha.Basavapatna@Sun.COM 		 * receiving packets.
78212011SSriharsha.Basavapatna@Sun.COM 		 */
78312011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->cblock);
78412011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->rxlock);
78512011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_handle_dringdata_info_shm(ldcp, tagp);
78612011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->rxlock);
78712011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->cblock);
78812011SSriharsha.Basavapatna@Sun.COM 		if (rv != 0) {
78912011SSriharsha.Basavapatna@Sun.COM 			DWARN(vgenp, ldcp, "handle_data_info failed(%d)\n", rv);
79012011SSriharsha.Basavapatna@Sun.COM 		}
79112011SSriharsha.Basavapatna@Sun.COM 		break;
79212011SSriharsha.Basavapatna@Sun.COM 
79312011SSriharsha.Basavapatna@Sun.COM 	case VIO_SUBTYPE_ACK:
79412011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_handle_dringdata_ack_shm(ldcp, tagp);
79512011SSriharsha.Basavapatna@Sun.COM 		if (rv != 0) {
79612011SSriharsha.Basavapatna@Sun.COM 			DWARN(vgenp, ldcp, "handle_data_ack failed(%d)\n", rv);
79712011SSriharsha.Basavapatna@Sun.COM 		}
79812011SSriharsha.Basavapatna@Sun.COM 		break;
79912011SSriharsha.Basavapatna@Sun.COM 
80012011SSriharsha.Basavapatna@Sun.COM 	case VIO_SUBTYPE_NACK:
80112011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_handle_dringdata_nack_shm(ldcp, tagp);
80212011SSriharsha.Basavapatna@Sun.COM 		if (rv != 0) {
80312011SSriharsha.Basavapatna@Sun.COM 			DWARN(vgenp, ldcp, "handle_data_nack failed(%d)\n", rv);
80412011SSriharsha.Basavapatna@Sun.COM 		}
80512011SSriharsha.Basavapatna@Sun.COM 		break;
80612011SSriharsha.Basavapatna@Sun.COM 	}
80712011SSriharsha.Basavapatna@Sun.COM 
80812011SSriharsha.Basavapatna@Sun.COM 	return (rv);
80912011SSriharsha.Basavapatna@Sun.COM }
81012011SSriharsha.Basavapatna@Sun.COM 
81112011SSriharsha.Basavapatna@Sun.COM static int
vgen_handle_dringdata_info_shm(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)81212011SSriharsha.Basavapatna@Sun.COM vgen_handle_dringdata_info_shm(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
81312011SSriharsha.Basavapatna@Sun.COM {
81412011SSriharsha.Basavapatna@Sun.COM 	uint32_t	start;
81512011SSriharsha.Basavapatna@Sun.COM 	int32_t		end;
81612011SSriharsha.Basavapatna@Sun.COM 	int		rv = 0;
81712011SSriharsha.Basavapatna@Sun.COM 	vio_dring_msg_t	*dringmsg = (vio_dring_msg_t *)tagp;
81812011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
81912011SSriharsha.Basavapatna@Sun.COM 	vgen_stats_t	*statsp = &ldcp->stats;
82012011SSriharsha.Basavapatna@Sun.COM 
82112011SSriharsha.Basavapatna@Sun.COM 	start = dringmsg->start_idx;
82212011SSriharsha.Basavapatna@Sun.COM 	end = dringmsg->end_idx;
82312011SSriharsha.Basavapatna@Sun.COM 
82412011SSriharsha.Basavapatna@Sun.COM 	DBG1(vgenp, ldcp, "INFO: start(%d), end(%d)\n",
82512011SSriharsha.Basavapatna@Sun.COM 	    start, end);
82612011SSriharsha.Basavapatna@Sun.COM 
82712011SSriharsha.Basavapatna@Sun.COM 	if (!(CHECK_RXI(start, ldcp)) ||
82812011SSriharsha.Basavapatna@Sun.COM 	    ((end != -1) && !(CHECK_RXI(end, ldcp)))) {
82912011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "Invalid Rx start(%d) or end(%d)\n",
83012011SSriharsha.Basavapatna@Sun.COM 		    start, end);
83112011SSriharsha.Basavapatna@Sun.COM 		/* drop the message if invalid index */
83212011SSriharsha.Basavapatna@Sun.COM 		return (0);
83312011SSriharsha.Basavapatna@Sun.COM 	}
83412011SSriharsha.Basavapatna@Sun.COM 
83512011SSriharsha.Basavapatna@Sun.COM 	/* validate dring_ident */
83612011SSriharsha.Basavapatna@Sun.COM 	if (dringmsg->dring_ident != ldcp->peer_hparams.dring_ident) {
83712011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n",
83812011SSriharsha.Basavapatna@Sun.COM 		    dringmsg->dring_ident);
83912011SSriharsha.Basavapatna@Sun.COM 		/* invalid dring_ident, drop the msg */
84012011SSriharsha.Basavapatna@Sun.COM 		return (0);
84112011SSriharsha.Basavapatna@Sun.COM 	}
84212011SSriharsha.Basavapatna@Sun.COM 
84312011SSriharsha.Basavapatna@Sun.COM 	statsp->dring_data_msgs_rcvd++;
84412011SSriharsha.Basavapatna@Sun.COM 
84512011SSriharsha.Basavapatna@Sun.COM 	/*
84612011SSriharsha.Basavapatna@Sun.COM 	 * If we are in polling mode, return from here without processing the
84712011SSriharsha.Basavapatna@Sun.COM 	 * dring. We will process the dring in the context of polling thread.
84812011SSriharsha.Basavapatna@Sun.COM 	 */
84912011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->polling_on == B_TRUE) {
85012011SSriharsha.Basavapatna@Sun.COM 		return (0);
85112011SSriharsha.Basavapatna@Sun.COM 	}
85212011SSriharsha.Basavapatna@Sun.COM 
85312011SSriharsha.Basavapatna@Sun.COM 	/*
85412011SSriharsha.Basavapatna@Sun.COM 	 * Process the dring and receive packets in intr context.
85512011SSriharsha.Basavapatna@Sun.COM 	 */
85612011SSriharsha.Basavapatna@Sun.COM 	rv = vgen_intr_rcv_shm(ldcp);
85712011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
85812011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "vgen_intr_rcv_shm() failed\n");
85912011SSriharsha.Basavapatna@Sun.COM 	}
86012011SSriharsha.Basavapatna@Sun.COM 	return (rv);
86112011SSriharsha.Basavapatna@Sun.COM }
86212011SSriharsha.Basavapatna@Sun.COM 
86312011SSriharsha.Basavapatna@Sun.COM /*
86412011SSriharsha.Basavapatna@Sun.COM  * Process the rx descriptor ring in the context of interrupt thread
86512011SSriharsha.Basavapatna@Sun.COM  * (vgen_ldc_cb() callback) and send the received packets up the stack.
86612011SSriharsha.Basavapatna@Sun.COM  */
86712011SSriharsha.Basavapatna@Sun.COM static int
vgen_intr_rcv_shm(vgen_ldc_t * ldcp)86812011SSriharsha.Basavapatna@Sun.COM vgen_intr_rcv_shm(vgen_ldc_t *ldcp)
86912011SSriharsha.Basavapatna@Sun.COM {
87012011SSriharsha.Basavapatna@Sun.COM 	int		rv;
87112011SSriharsha.Basavapatna@Sun.COM 	uint32_t	end_ix;
87212011SSriharsha.Basavapatna@Sun.COM 	vio_dring_msg_t msg;
87312011SSriharsha.Basavapatna@Sun.COM 	uint_t		mblk_sz;
87412011SSriharsha.Basavapatna@Sun.COM 	int		count = 0;
87512011SSriharsha.Basavapatna@Sun.COM 	int		total_count = 0;
87612011SSriharsha.Basavapatna@Sun.COM 	mblk_t		*bp = NULL;
87712011SSriharsha.Basavapatna@Sun.COM 	mblk_t		*bpt = NULL;
87812011SSriharsha.Basavapatna@Sun.COM 	mblk_t		*mp = NULL;
87912011SSriharsha.Basavapatna@Sun.COM 	vio_net_rx_cb_t vrx_cb = ldcp->portp->vcb.vio_net_rx_cb;
88012011SSriharsha.Basavapatna@Sun.COM 
88112011SSriharsha.Basavapatna@Sun.COM 	ASSERT(MUTEX_HELD(&ldcp->rxlock));
88212011SSriharsha.Basavapatna@Sun.COM 
88312011SSriharsha.Basavapatna@Sun.COM 	do {
88412011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_receive_packet(ldcp, &mp, &mblk_sz);
88512011SSriharsha.Basavapatna@Sun.COM 		if (rv != 0) {
88612011SSriharsha.Basavapatna@Sun.COM 			if (rv == EINVAL) {
88712011SSriharsha.Basavapatna@Sun.COM 				/* Invalid descriptor error; get next */
88812011SSriharsha.Basavapatna@Sun.COM 				continue;
88912011SSriharsha.Basavapatna@Sun.COM 			}
89012011SSriharsha.Basavapatna@Sun.COM 			DTRACE_PROBE1(vgen_intr_nopkts, vgen_ldc_t *, ldcp);
89112011SSriharsha.Basavapatna@Sun.COM 			break;
89212011SSriharsha.Basavapatna@Sun.COM 		}
89312011SSriharsha.Basavapatna@Sun.COM 
89412011SSriharsha.Basavapatna@Sun.COM 		/* Build a chain of received packets */
89512011SSriharsha.Basavapatna@Sun.COM 		if (bp == NULL) {
89612011SSriharsha.Basavapatna@Sun.COM 			/* first pkt */
89712011SSriharsha.Basavapatna@Sun.COM 			bp = mp;
89812011SSriharsha.Basavapatna@Sun.COM 			bpt = bp;
89912011SSriharsha.Basavapatna@Sun.COM 			bpt->b_next = NULL;
90012011SSriharsha.Basavapatna@Sun.COM 		} else {
90112011SSriharsha.Basavapatna@Sun.COM 			mp->b_next = NULL;
90212011SSriharsha.Basavapatna@Sun.COM 			bpt->b_next = mp;
90312011SSriharsha.Basavapatna@Sun.COM 			bpt = mp;
90412011SSriharsha.Basavapatna@Sun.COM 		}
90512011SSriharsha.Basavapatna@Sun.COM 
90612011SSriharsha.Basavapatna@Sun.COM 		total_count++;
90712011SSriharsha.Basavapatna@Sun.COM 		count++;
90812011SSriharsha.Basavapatna@Sun.COM 
90912011SSriharsha.Basavapatna@Sun.COM 		/*
91012011SSriharsha.Basavapatna@Sun.COM 		 * We are receiving the packets in interrupt context. If we
91112011SSriharsha.Basavapatna@Sun.COM 		 * have gathered vgen_chain_len (tunable) # of packets in the
91212011SSriharsha.Basavapatna@Sun.COM 		 * chain, send them up. (See vgen_poll_rcv_shm() for receiving
91312011SSriharsha.Basavapatna@Sun.COM 		 * in polling thread context).
91412011SSriharsha.Basavapatna@Sun.COM 		 */
91512011SSriharsha.Basavapatna@Sun.COM 		if (count == vgen_chain_len) {
91612011SSriharsha.Basavapatna@Sun.COM 			DTRACE_PROBE2(vgen_intr_pkts, vgen_ldc_t *, ldcp,
91712011SSriharsha.Basavapatna@Sun.COM 			    int, count);
91812011SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&ldcp->rxlock);
91912011SSriharsha.Basavapatna@Sun.COM 			vrx_cb(ldcp->portp->vhp, bp);
92012011SSriharsha.Basavapatna@Sun.COM 			mutex_enter(&ldcp->rxlock);
92112011SSriharsha.Basavapatna@Sun.COM 			bp = bpt = NULL;
92212011SSriharsha.Basavapatna@Sun.COM 			count = 0;
92312011SSriharsha.Basavapatna@Sun.COM 		}
92412011SSriharsha.Basavapatna@Sun.COM 
92512011SSriharsha.Basavapatna@Sun.COM 		/*
92612011SSriharsha.Basavapatna@Sun.COM 		 * Stop further processing if we processed the entire dring
92712011SSriharsha.Basavapatna@Sun.COM 		 * once; otherwise continue.
92812011SSriharsha.Basavapatna@Sun.COM 		 */
92912011SSriharsha.Basavapatna@Sun.COM 	} while (total_count < ldcp->num_rxds);
93012011SSriharsha.Basavapatna@Sun.COM 
93112011SSriharsha.Basavapatna@Sun.COM 	if (bp != NULL) {
93212011SSriharsha.Basavapatna@Sun.COM 		DTRACE_PROBE2(vgen_intr_pkts, vgen_ldc_t *, ldcp, int, count);
93312011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->rxlock);
93412011SSriharsha.Basavapatna@Sun.COM 		vrx_cb(ldcp->portp->vhp, bp);
93512011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->rxlock);
93612011SSriharsha.Basavapatna@Sun.COM 	}
93712011SSriharsha.Basavapatna@Sun.COM 
93812011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->polling_on == B_FALSE) {
93912011SSriharsha.Basavapatna@Sun.COM 		/*
94012011SSriharsha.Basavapatna@Sun.COM 		 * We send a stopped message to peer (sender) while we are in
94112011SSriharsha.Basavapatna@Sun.COM 		 * intr mode only; allowing the peer to send further data intrs
94212011SSriharsha.Basavapatna@Sun.COM 		 * (dring data msgs) to us.
94312011SSriharsha.Basavapatna@Sun.COM 		 */
94412011SSriharsha.Basavapatna@Sun.COM 		end_ix = ldcp->next_rxi;
94512011SSriharsha.Basavapatna@Sun.COM 		DECR_RXI(end_ix, ldcp);
94612011SSriharsha.Basavapatna@Sun.COM 		msg.dring_ident = ldcp->peer_hparams.dring_ident;
94712011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_send_dringack_shm(ldcp, (vio_msg_tag_t *)&msg,
94812011SSriharsha.Basavapatna@Sun.COM 		    VNET_START_IDX_UNSPEC, end_ix, VIO_DP_STOPPED);
94912011SSriharsha.Basavapatna@Sun.COM 		return (rv);
95012011SSriharsha.Basavapatna@Sun.COM 	}
95112011SSriharsha.Basavapatna@Sun.COM 
95212011SSriharsha.Basavapatna@Sun.COM 	return (0);
95312011SSriharsha.Basavapatna@Sun.COM }
95412011SSriharsha.Basavapatna@Sun.COM 
95512011SSriharsha.Basavapatna@Sun.COM /*
95612011SSriharsha.Basavapatna@Sun.COM  * Process the rx descriptor ring in the context of mac polling thread. Receive
95712011SSriharsha.Basavapatna@Sun.COM  * packets upto the limit specified by bytes_to_pickup or until there are no
95812011SSriharsha.Basavapatna@Sun.COM  * more packets, whichever occurs first. Return the chain of received packets.
95912011SSriharsha.Basavapatna@Sun.COM  */
96012011SSriharsha.Basavapatna@Sun.COM mblk_t *
vgen_poll_rcv_shm(vgen_ldc_t * ldcp,int bytes_to_pickup)96112011SSriharsha.Basavapatna@Sun.COM vgen_poll_rcv_shm(vgen_ldc_t *ldcp, int bytes_to_pickup)
96212011SSriharsha.Basavapatna@Sun.COM {
96312011SSriharsha.Basavapatna@Sun.COM 	uint_t		mblk_sz = 0;
96412011SSriharsha.Basavapatna@Sun.COM 	uint_t		sz = 0;
96512011SSriharsha.Basavapatna@Sun.COM 	mblk_t		*bp = NULL;
96612011SSriharsha.Basavapatna@Sun.COM 	mblk_t		*bpt = NULL;
96712011SSriharsha.Basavapatna@Sun.COM 	mblk_t		*mp = NULL;
96812011SSriharsha.Basavapatna@Sun.COM 	int		count = 0;
96912011SSriharsha.Basavapatna@Sun.COM 	int		rv;
97012011SSriharsha.Basavapatna@Sun.COM 
97112011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->rxlock);
97212011SSriharsha.Basavapatna@Sun.COM 
97312011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->hphase != VH_DONE) {
97412011SSriharsha.Basavapatna@Sun.COM 		/* Channel is being reset and handshake not complete */
97512011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->rxlock);
97612011SSriharsha.Basavapatna@Sun.COM 		return (NULL);
97712011SSriharsha.Basavapatna@Sun.COM 	}
97812011SSriharsha.Basavapatna@Sun.COM 
97912011SSriharsha.Basavapatna@Sun.COM 	do {
98012011SSriharsha.Basavapatna@Sun.COM 		rv = vgen_receive_packet(ldcp, &mp, &mblk_sz);
98112011SSriharsha.Basavapatna@Sun.COM 		if (rv != 0) {
98212011SSriharsha.Basavapatna@Sun.COM 			if (rv == EINVAL) {
98312011SSriharsha.Basavapatna@Sun.COM 				/* Invalid descriptor error; get next */
98412011SSriharsha.Basavapatna@Sun.COM 				continue;
98512011SSriharsha.Basavapatna@Sun.COM 			}
98612011SSriharsha.Basavapatna@Sun.COM 			DTRACE_PROBE1(vgen_poll_nopkts, vgen_ldc_t *, ldcp);
98712011SSriharsha.Basavapatna@Sun.COM 			break;
98812011SSriharsha.Basavapatna@Sun.COM 		}
98912011SSriharsha.Basavapatna@Sun.COM 
99012011SSriharsha.Basavapatna@Sun.COM 		/* Build a chain of received packets */
99112011SSriharsha.Basavapatna@Sun.COM 		if (bp == NULL) {
99212011SSriharsha.Basavapatna@Sun.COM 			/* first pkt */
99312011SSriharsha.Basavapatna@Sun.COM 			bp = mp;
99412011SSriharsha.Basavapatna@Sun.COM 			bpt = bp;
99512011SSriharsha.Basavapatna@Sun.COM 			bpt->b_next = NULL;
99612011SSriharsha.Basavapatna@Sun.COM 		} else {
99712011SSriharsha.Basavapatna@Sun.COM 			mp->b_next = NULL;
99812011SSriharsha.Basavapatna@Sun.COM 			bpt->b_next = mp;
99912011SSriharsha.Basavapatna@Sun.COM 			bpt = mp;
100012011SSriharsha.Basavapatna@Sun.COM 		}
100112011SSriharsha.Basavapatna@Sun.COM 
100212011SSriharsha.Basavapatna@Sun.COM 		/* Compute total size accumulated */
100312011SSriharsha.Basavapatna@Sun.COM 		sz += mblk_sz;
100412011SSriharsha.Basavapatna@Sun.COM 		count++;
100512011SSriharsha.Basavapatna@Sun.COM 
100612011SSriharsha.Basavapatna@Sun.COM 		/* Reached the bytes limit; we are done. */
100712011SSriharsha.Basavapatna@Sun.COM 		if (sz >= bytes_to_pickup) {
100812011SSriharsha.Basavapatna@Sun.COM 			break;
100912011SSriharsha.Basavapatna@Sun.COM 		}
101012011SSriharsha.Basavapatna@Sun.COM 
101112011SSriharsha.Basavapatna@Sun.COM 	_NOTE(CONSTCOND)
101212011SSriharsha.Basavapatna@Sun.COM 	} while (1);
101312011SSriharsha.Basavapatna@Sun.COM 
101412011SSriharsha.Basavapatna@Sun.COM 	/*
101512011SSriharsha.Basavapatna@Sun.COM 	 * We prepend any high priority packets to the chain of packets; note
101612011SSriharsha.Basavapatna@Sun.COM 	 * that if we are already at the bytes_to_pickup limit, we might
101712011SSriharsha.Basavapatna@Sun.COM 	 * slightly exceed that in such cases. That should be ok, as these pkts
101812011SSriharsha.Basavapatna@Sun.COM 	 * are expected to be small in size and arrive at an interval in the
101912011SSriharsha.Basavapatna@Sun.COM 	 * the order of a few seconds.
102012011SSriharsha.Basavapatna@Sun.COM 	 */
102112011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->rx_pktdata == vgen_handle_pkt_data &&
102212011SSriharsha.Basavapatna@Sun.COM 	    ldcp->rx_pri_head != NULL) {
102312011SSriharsha.Basavapatna@Sun.COM 		ldcp->rx_pri_tail->b_next = bp;
102412011SSriharsha.Basavapatna@Sun.COM 		bp = ldcp->rx_pri_head;
102512011SSriharsha.Basavapatna@Sun.COM 		ldcp->rx_pri_head = ldcp->rx_pri_tail = NULL;
102612011SSriharsha.Basavapatna@Sun.COM 	}
102712011SSriharsha.Basavapatna@Sun.COM 
102812011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&ldcp->rxlock);
102912011SSriharsha.Basavapatna@Sun.COM 
103012011SSriharsha.Basavapatna@Sun.COM 	DTRACE_PROBE2(vgen_poll_pkts, vgen_ldc_t *, ldcp, int, count);
103112011SSriharsha.Basavapatna@Sun.COM 	DTRACE_PROBE2(vgen_poll_bytes, vgen_ldc_t *, ldcp, uint_t, sz);
103212011SSriharsha.Basavapatna@Sun.COM 	return (bp);
103312011SSriharsha.Basavapatna@Sun.COM }
103412011SSriharsha.Basavapatna@Sun.COM 
103512011SSriharsha.Basavapatna@Sun.COM /*
103612011SSriharsha.Basavapatna@Sun.COM  * Process the next index in the rx dring and receive the associated packet.
103712011SSriharsha.Basavapatna@Sun.COM  *
103812011SSriharsha.Basavapatna@Sun.COM  * Returns:
103912011SSriharsha.Basavapatna@Sun.COM  *	bp:	Success: The received packet.
104012011SSriharsha.Basavapatna@Sun.COM  *		Failure: NULL
104112011SSriharsha.Basavapatna@Sun.COM  *      size:	Success: Size of received packet.
104212011SSriharsha.Basavapatna@Sun.COM  *		Failure: 0
104312011SSriharsha.Basavapatna@Sun.COM  *      retval:
104412011SSriharsha.Basavapatna@Sun.COM  *		Success: 0
104512011SSriharsha.Basavapatna@Sun.COM  *		Failure: EAGAIN: Descriptor not ready
104612011SSriharsha.Basavapatna@Sun.COM  *			 EIO:    Descriptor contents invalid.
104712011SSriharsha.Basavapatna@Sun.COM  */
104812011SSriharsha.Basavapatna@Sun.COM static int
vgen_receive_packet(vgen_ldc_t * ldcp,mblk_t ** bp,uint_t * size)104912011SSriharsha.Basavapatna@Sun.COM vgen_receive_packet(vgen_ldc_t *ldcp, mblk_t **bp, uint_t *size)
105012011SSriharsha.Basavapatna@Sun.COM {
105112011SSriharsha.Basavapatna@Sun.COM 	uint32_t			rxi;
105212011SSriharsha.Basavapatna@Sun.COM 	vio_mblk_t			*vmp;
105312011SSriharsha.Basavapatna@Sun.COM 	vio_mblk_t			*new_vmp;
105412011SSriharsha.Basavapatna@Sun.COM 	struct ether_header		*ehp;
105512011SSriharsha.Basavapatna@Sun.COM 	vnet_rx_dringdata_desc_t	*rxdp;
105612011SSriharsha.Basavapatna@Sun.COM 	int				err = 0;
105712011SSriharsha.Basavapatna@Sun.COM 	uint32_t			nbytes = 0;
105812011SSriharsha.Basavapatna@Sun.COM 	mblk_t				*mp = NULL;
105912011SSriharsha.Basavapatna@Sun.COM 	mblk_t				*dmp = NULL;
106012011SSriharsha.Basavapatna@Sun.COM 	vgen_stats_t			*statsp = &ldcp->stats;
106112011SSriharsha.Basavapatna@Sun.COM 	vgen_hparams_t			*lp = &ldcp->local_hparams;
106212011SSriharsha.Basavapatna@Sun.COM 
106312011SSriharsha.Basavapatna@Sun.COM 	rxi = ldcp->next_rxi;
106412011SSriharsha.Basavapatna@Sun.COM 	rxdp = &(ldcp->rxdp[rxi]);
106512011SSriharsha.Basavapatna@Sun.COM 	vmp = ldcp->rxdp_to_vmp[rxi];
106612011SSriharsha.Basavapatna@Sun.COM 
106712011SSriharsha.Basavapatna@Sun.COM 	if (rxdp->dstate != VIO_DESC_READY) {
106812011SSriharsha.Basavapatna@Sun.COM 		/*
106912011SSriharsha.Basavapatna@Sun.COM 		 * Descriptor is not ready.
107012011SSriharsha.Basavapatna@Sun.COM 		 */
107112011SSriharsha.Basavapatna@Sun.COM 		DTRACE_PROBE1(vgen_noready_rxds, vgen_ldc_t *, ldcp);
107212011SSriharsha.Basavapatna@Sun.COM 		return (EAGAIN);
107312011SSriharsha.Basavapatna@Sun.COM 	}
107412011SSriharsha.Basavapatna@Sun.COM 
107512011SSriharsha.Basavapatna@Sun.COM 	/*
107612011SSriharsha.Basavapatna@Sun.COM 	 * Ensure load ordering of dstate and nbytes.
107712011SSriharsha.Basavapatna@Sun.COM 	 */
107812011SSriharsha.Basavapatna@Sun.COM 	MEMBAR_CONSUMER();
107912011SSriharsha.Basavapatna@Sun.COM 
108012011SSriharsha.Basavapatna@Sun.COM 	nbytes = rxdp->nbytes;
108112011SSriharsha.Basavapatna@Sun.COM 
108212011SSriharsha.Basavapatna@Sun.COM 	if ((nbytes < ETHERMIN) ||
108312011SSriharsha.Basavapatna@Sun.COM 	    (nbytes > lp->mtu) ||
108412011SSriharsha.Basavapatna@Sun.COM 	    (rxdp->data_buf_offset !=
108512011SSriharsha.Basavapatna@Sun.COM 	    (VIO_MBLK_DATA_OFF(vmp) + VNET_IPALIGN))) {
108612011SSriharsha.Basavapatna@Sun.COM 		/*
108712011SSriharsha.Basavapatna@Sun.COM 		 * Descriptor contents invalid.
108812011SSriharsha.Basavapatna@Sun.COM 		 */
108912011SSriharsha.Basavapatna@Sun.COM 		statsp->ierrors++;
109012011SSriharsha.Basavapatna@Sun.COM 		rxdp->dstate = VIO_DESC_DONE;
109112011SSriharsha.Basavapatna@Sun.COM 		err = EIO;
109212011SSriharsha.Basavapatna@Sun.COM 		goto done;
109312011SSriharsha.Basavapatna@Sun.COM 	}
109412011SSriharsha.Basavapatna@Sun.COM 
109512011SSriharsha.Basavapatna@Sun.COM 	/*
109612011SSriharsha.Basavapatna@Sun.COM 	 * Now allocate a new buffer for this descriptor before sending up the
109712011SSriharsha.Basavapatna@Sun.COM 	 * buffer being processed. If that fails, stop processing; as we are
109812011SSriharsha.Basavapatna@Sun.COM 	 * out of receive buffers.
109912011SSriharsha.Basavapatna@Sun.COM 	 */
110012011SSriharsha.Basavapatna@Sun.COM 	new_vmp = vio_allocb(ldcp->rx_vmp);
110112011SSriharsha.Basavapatna@Sun.COM 
110212011SSriharsha.Basavapatna@Sun.COM 	/*
110312011SSriharsha.Basavapatna@Sun.COM 	 * Process the current buffer being received.
110412011SSriharsha.Basavapatna@Sun.COM 	 */
110512011SSriharsha.Basavapatna@Sun.COM 	mp = vmp->mp;
110612011SSriharsha.Basavapatna@Sun.COM 
110712011SSriharsha.Basavapatna@Sun.COM 	if (new_vmp == NULL) {
110812011SSriharsha.Basavapatna@Sun.COM 		/*
110912011SSriharsha.Basavapatna@Sun.COM 		 * We failed to get a new mapped buffer that is needed to
111012011SSriharsha.Basavapatna@Sun.COM 		 * refill the descriptor. In that case, leave the current
111112011SSriharsha.Basavapatna@Sun.COM 		 * buffer bound to the descriptor; allocate an mblk dynamically
111212011SSriharsha.Basavapatna@Sun.COM 		 * and copy the contents of the buffer to the mblk. Then send
111312011SSriharsha.Basavapatna@Sun.COM 		 * up this mblk. This way the sender has the same buffer as
111412011SSriharsha.Basavapatna@Sun.COM 		 * before that can be used to send new data.
111512011SSriharsha.Basavapatna@Sun.COM 		 */
111612011SSriharsha.Basavapatna@Sun.COM 		statsp->norcvbuf++;
111712011SSriharsha.Basavapatna@Sun.COM 		dmp = allocb(nbytes + VNET_IPALIGN, BPRI_MED);
111812011SSriharsha.Basavapatna@Sun.COM 		if (dmp == NULL) {
111912011SSriharsha.Basavapatna@Sun.COM 			statsp->ierrors++;
112012011SSriharsha.Basavapatna@Sun.COM 			return (ENOMEM);
112112011SSriharsha.Basavapatna@Sun.COM 		}
112212011SSriharsha.Basavapatna@Sun.COM 		bcopy(mp->b_rptr + VNET_IPALIGN,
112312011SSriharsha.Basavapatna@Sun.COM 		    dmp->b_rptr + VNET_IPALIGN, nbytes);
112412011SSriharsha.Basavapatna@Sun.COM 		mp = dmp;
112512011SSriharsha.Basavapatna@Sun.COM 	} else {
112612011SSriharsha.Basavapatna@Sun.COM 		/* Mark the status of the current rbuf */
112712011SSriharsha.Basavapatna@Sun.COM 		vmp->state = VIO_MBLK_HAS_DATA;
112812011SSriharsha.Basavapatna@Sun.COM 
112912011SSriharsha.Basavapatna@Sun.COM 		/* Set the offset of the new buffer in the descriptor */
113012011SSriharsha.Basavapatna@Sun.COM 		rxdp->data_buf_offset =
113112011SSriharsha.Basavapatna@Sun.COM 		    VIO_MBLK_DATA_OFF(new_vmp) + VNET_IPALIGN;
113212011SSriharsha.Basavapatna@Sun.COM 		ldcp->rxdp_to_vmp[rxi] = new_vmp;
113312011SSriharsha.Basavapatna@Sun.COM 	}
113412011SSriharsha.Basavapatna@Sun.COM 	mp->b_rptr += VNET_IPALIGN;
113512011SSriharsha.Basavapatna@Sun.COM 	mp->b_wptr = mp->b_rptr + nbytes;
113612011SSriharsha.Basavapatna@Sun.COM 
113712011SSriharsha.Basavapatna@Sun.COM 	/*
113812011SSriharsha.Basavapatna@Sun.COM 	 * Ensure store ordering of data_buf_offset and dstate; so that the
113912011SSriharsha.Basavapatna@Sun.COM 	 * peer sees the right data_buf_offset after it checks that the dstate
114012011SSriharsha.Basavapatna@Sun.COM 	 * is DONE.
114112011SSriharsha.Basavapatna@Sun.COM 	 */
114212011SSriharsha.Basavapatna@Sun.COM 	MEMBAR_PRODUCER();
114312011SSriharsha.Basavapatna@Sun.COM 
114412011SSriharsha.Basavapatna@Sun.COM 	/* Now mark the descriptor 'done' */
114512011SSriharsha.Basavapatna@Sun.COM 	rxdp->dstate = VIO_DESC_DONE;
114612011SSriharsha.Basavapatna@Sun.COM 
114712011SSriharsha.Basavapatna@Sun.COM 	/* Update stats */
114812011SSriharsha.Basavapatna@Sun.COM 	statsp->ipackets++;
114912011SSriharsha.Basavapatna@Sun.COM 	statsp->rbytes += rxdp->nbytes;
115012011SSriharsha.Basavapatna@Sun.COM 	ehp = (struct ether_header *)mp->b_rptr;
115112011SSriharsha.Basavapatna@Sun.COM 	if (IS_BROADCAST(ehp))
115212011SSriharsha.Basavapatna@Sun.COM 		statsp->brdcstrcv++;
115312011SSriharsha.Basavapatna@Sun.COM 	else if (IS_MULTICAST(ehp))
115412011SSriharsha.Basavapatna@Sun.COM 		statsp->multircv++;
115512011SSriharsha.Basavapatna@Sun.COM done:
115612011SSriharsha.Basavapatna@Sun.COM 	/* Update the next index to be processed */
115712011SSriharsha.Basavapatna@Sun.COM 	INCR_RXI(rxi, ldcp);
115812011SSriharsha.Basavapatna@Sun.COM 
115912011SSriharsha.Basavapatna@Sun.COM 	/* Save the new recv index */
116012011SSriharsha.Basavapatna@Sun.COM 	ldcp->next_rxi = rxi;
116112011SSriharsha.Basavapatna@Sun.COM 
116212011SSriharsha.Basavapatna@Sun.COM 	/* Return the packet received */
116312011SSriharsha.Basavapatna@Sun.COM 	*size = nbytes;
116412011SSriharsha.Basavapatna@Sun.COM 	*bp = mp;
116512011SSriharsha.Basavapatna@Sun.COM 	return (err);
116612011SSriharsha.Basavapatna@Sun.COM }
116712011SSriharsha.Basavapatna@Sun.COM 
116812011SSriharsha.Basavapatna@Sun.COM static int
vgen_handle_dringdata_ack_shm(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)116912011SSriharsha.Basavapatna@Sun.COM vgen_handle_dringdata_ack_shm(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
117012011SSriharsha.Basavapatna@Sun.COM {
117112011SSriharsha.Basavapatna@Sun.COM 	uint32_t			start;
117212011SSriharsha.Basavapatna@Sun.COM 	int32_t				end;
117312011SSriharsha.Basavapatna@Sun.COM 	uint32_t			txi;
117412011SSriharsha.Basavapatna@Sun.COM 	vgen_stats_t			*statsp;
117512011SSriharsha.Basavapatna@Sun.COM 	vnet_rx_dringdata_desc_t	*txdp;
117612011SSriharsha.Basavapatna@Sun.COM 	on_trap_data_t			otd;
117712011SSriharsha.Basavapatna@Sun.COM 	int				rv = 0;
117812011SSriharsha.Basavapatna@Sun.COM 	boolean_t			ready_txd = B_FALSE;
117912011SSriharsha.Basavapatna@Sun.COM 	vgen_t				*vgenp = LDC_TO_VGEN(ldcp);
118012011SSriharsha.Basavapatna@Sun.COM 	vio_dring_msg_t			*dringmsg = (vio_dring_msg_t *)tagp;
118112011SSriharsha.Basavapatna@Sun.COM 
118212011SSriharsha.Basavapatna@Sun.COM 	start = dringmsg->start_idx;
118312011SSriharsha.Basavapatna@Sun.COM 	end = dringmsg->end_idx;
118412011SSriharsha.Basavapatna@Sun.COM 	statsp = &ldcp->stats;
118512011SSriharsha.Basavapatna@Sun.COM 
118612011SSriharsha.Basavapatna@Sun.COM 	/*
118712011SSriharsha.Basavapatna@Sun.COM 	 * Received an ack for our transmits upto a certain dring index. This
118812011SSriharsha.Basavapatna@Sun.COM 	 * enables us to reclaim descriptors. We also send a new dring data msg
118912011SSriharsha.Basavapatna@Sun.COM 	 * to the peer to restart processing if there are pending transmit pkts.
119012011SSriharsha.Basavapatna@Sun.COM 	 */
119112011SSriharsha.Basavapatna@Sun.COM 	DBG2(vgenp, ldcp, "ACK:  start(%d), end(%d)\n", start, end);
119212011SSriharsha.Basavapatna@Sun.COM 
119312011SSriharsha.Basavapatna@Sun.COM 	/*
119412011SSriharsha.Basavapatna@Sun.COM 	 * In RxDringData mode (v1.6), start index of -1 can be used by the
119512011SSriharsha.Basavapatna@Sun.COM 	 * peer to indicate that it is unspecified. However, the end index
119612011SSriharsha.Basavapatna@Sun.COM 	 * must be set correctly indicating the last descriptor index processed.
119712011SSriharsha.Basavapatna@Sun.COM 	 */
119812011SSriharsha.Basavapatna@Sun.COM 	if (((start != VNET_START_IDX_UNSPEC) && !(CHECK_TXI(start, ldcp))) ||
119912011SSriharsha.Basavapatna@Sun.COM 	    !(CHECK_TXI(end, ldcp))) {
120012011SSriharsha.Basavapatna@Sun.COM 		/* drop the message if invalid index */
120112011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "Invalid Tx ack start(%d) or end(%d)\n",
120212011SSriharsha.Basavapatna@Sun.COM 		    start, end);
120312011SSriharsha.Basavapatna@Sun.COM 		return (rv);
120412011SSriharsha.Basavapatna@Sun.COM 	}
120512011SSriharsha.Basavapatna@Sun.COM 
120612011SSriharsha.Basavapatna@Sun.COM 	/* Validate dring_ident */
120712011SSriharsha.Basavapatna@Sun.COM 	if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
120812011SSriharsha.Basavapatna@Sun.COM 		/* invalid dring_ident, drop the msg */
120912011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n",
121012011SSriharsha.Basavapatna@Sun.COM 		    dringmsg->dring_ident);
121112011SSriharsha.Basavapatna@Sun.COM 		return (rv);
121212011SSriharsha.Basavapatna@Sun.COM 	}
121312011SSriharsha.Basavapatna@Sun.COM 	statsp->dring_data_acks_rcvd++;
121412011SSriharsha.Basavapatna@Sun.COM 
121512011SSriharsha.Basavapatna@Sun.COM 	/*
121612011SSriharsha.Basavapatna@Sun.COM 	 * Clear transmit flow control condition
121712011SSriharsha.Basavapatna@Sun.COM 	 * as some descriptors should be free now.
121812011SSriharsha.Basavapatna@Sun.COM 	 */
121912011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->txlock);
122012011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->tx_blocked == B_TRUE) {
122112011SSriharsha.Basavapatna@Sun.COM 		vio_net_tx_update_t vtx_update =
122212011SSriharsha.Basavapatna@Sun.COM 		    ldcp->portp->vcb.vio_net_tx_update;
122312011SSriharsha.Basavapatna@Sun.COM 
122412011SSriharsha.Basavapatna@Sun.COM 		ldcp->tx_blocked = B_FALSE;
122512011SSriharsha.Basavapatna@Sun.COM 		vtx_update(ldcp->portp->vhp);
122612011SSriharsha.Basavapatna@Sun.COM 	}
122712011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&ldcp->txlock);
122812011SSriharsha.Basavapatna@Sun.COM 
122912011SSriharsha.Basavapatna@Sun.COM 	if (dringmsg->dring_process_state != VIO_DP_STOPPED) {
123012011SSriharsha.Basavapatna@Sun.COM 		/*
123112011SSriharsha.Basavapatna@Sun.COM 		 * Receiver continued processing
123212011SSriharsha.Basavapatna@Sun.COM 		 * dring after sending us the ack.
123312011SSriharsha.Basavapatna@Sun.COM 		 */
123412011SSriharsha.Basavapatna@Sun.COM 		return (rv);
123512011SSriharsha.Basavapatna@Sun.COM 	}
123612011SSriharsha.Basavapatna@Sun.COM 
123712011SSriharsha.Basavapatna@Sun.COM 	/*
123812011SSriharsha.Basavapatna@Sun.COM 	 * Receiver stopped processing descriptors.
123912011SSriharsha.Basavapatna@Sun.COM 	 */
124012011SSriharsha.Basavapatna@Sun.COM 	statsp->dring_stopped_acks_rcvd++;
124112011SSriharsha.Basavapatna@Sun.COM 
124212011SSriharsha.Basavapatna@Sun.COM 	/*
124312011SSriharsha.Basavapatna@Sun.COM 	 * Setup on_trap() protection before accessing dring shared memory area.
124412011SSriharsha.Basavapatna@Sun.COM 	 */
124512011SSriharsha.Basavapatna@Sun.COM 	rv = LDC_ON_TRAP(&otd);
124612011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
124712011SSriharsha.Basavapatna@Sun.COM 		/*
124812011SSriharsha.Basavapatna@Sun.COM 		 * Data access fault occured down the code path below while
124912011SSriharsha.Basavapatna@Sun.COM 		 * accessing the descriptors. Release any locks that we might
125012011SSriharsha.Basavapatna@Sun.COM 		 * have acquired in the code below and return failure.
125112011SSriharsha.Basavapatna@Sun.COM 		 */
125212011SSriharsha.Basavapatna@Sun.COM 		if (mutex_owned(&ldcp->wrlock)) {
125312011SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&ldcp->wrlock);
125412011SSriharsha.Basavapatna@Sun.COM 		}
125512011SSriharsha.Basavapatna@Sun.COM 		return (ECONNRESET);
125612011SSriharsha.Basavapatna@Sun.COM 	}
125712011SSriharsha.Basavapatna@Sun.COM 
125812011SSriharsha.Basavapatna@Sun.COM 	/*
125912011SSriharsha.Basavapatna@Sun.COM 	 * Determine if there are any pending tx descriptors ready to be
126012011SSriharsha.Basavapatna@Sun.COM 	 * processed by the receiver(peer) and if so, send a message to the
126112011SSriharsha.Basavapatna@Sun.COM 	 * peer to restart receiving.
126212011SSriharsha.Basavapatna@Sun.COM 	 */
126312011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->wrlock);
126412011SSriharsha.Basavapatna@Sun.COM 
126512011SSriharsha.Basavapatna@Sun.COM 	ready_txd = B_FALSE;
126612011SSriharsha.Basavapatna@Sun.COM 	txi = end;
126712011SSriharsha.Basavapatna@Sun.COM 	INCR_TXI(txi, ldcp);
126812011SSriharsha.Basavapatna@Sun.COM 	txdp = &ldcp->mtxdp[txi];
126912011SSriharsha.Basavapatna@Sun.COM 	if (txdp->dstate == VIO_DESC_READY) {
127012011SSriharsha.Basavapatna@Sun.COM 		ready_txd = B_TRUE;
127112011SSriharsha.Basavapatna@Sun.COM 	}
127212011SSriharsha.Basavapatna@Sun.COM 
127312011SSriharsha.Basavapatna@Sun.COM 	/*
127412011SSriharsha.Basavapatna@Sun.COM 	 * We are done accessing shared memory; clear trap protection.
127512011SSriharsha.Basavapatna@Sun.COM 	 */
127612011SSriharsha.Basavapatna@Sun.COM 	(void) LDC_NO_TRAP();
127712011SSriharsha.Basavapatna@Sun.COM 
127812011SSriharsha.Basavapatna@Sun.COM 	if (ready_txd == B_FALSE) {
127912011SSriharsha.Basavapatna@Sun.COM 		/*
128012011SSriharsha.Basavapatna@Sun.COM 		 * No ready tx descriptors. Set the flag to send a message to
128112011SSriharsha.Basavapatna@Sun.COM 		 * the peer when tx descriptors are ready in transmit routine.
128212011SSriharsha.Basavapatna@Sun.COM 		 */
128312011SSriharsha.Basavapatna@Sun.COM 		ldcp->resched_peer = B_TRUE;
128412950SWentao.Yang@Sun.COM 		ldcp->resched_peer_txi = txi;
128512011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->wrlock);
128612011SSriharsha.Basavapatna@Sun.COM 		return (rv);
128712011SSriharsha.Basavapatna@Sun.COM 	}
128812011SSriharsha.Basavapatna@Sun.COM 
128912011SSriharsha.Basavapatna@Sun.COM 	/*
129012011SSriharsha.Basavapatna@Sun.COM 	 * We have some tx descriptors ready to be processed by the receiver.
129112011SSriharsha.Basavapatna@Sun.COM 	 * Send a dring data message to the peer to restart processing.
129212011SSriharsha.Basavapatna@Sun.COM 	 */
129312011SSriharsha.Basavapatna@Sun.COM 	ldcp->resched_peer = B_FALSE;
129412011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&ldcp->wrlock);
129512011SSriharsha.Basavapatna@Sun.COM 	rv = vgen_send_dringdata_shm(ldcp, txi, -1);
129612011SSriharsha.Basavapatna@Sun.COM 	if (rv != VGEN_SUCCESS) {
129712011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->wrlock);
129812011SSriharsha.Basavapatna@Sun.COM 		ldcp->resched_peer = B_TRUE;
129912011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->wrlock);
130012011SSriharsha.Basavapatna@Sun.COM 	}
130112011SSriharsha.Basavapatna@Sun.COM 
130212011SSriharsha.Basavapatna@Sun.COM 	return (rv);
130312011SSriharsha.Basavapatna@Sun.COM }
130412011SSriharsha.Basavapatna@Sun.COM 
130512011SSriharsha.Basavapatna@Sun.COM static int
vgen_handle_dringdata_nack_shm(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)130612011SSriharsha.Basavapatna@Sun.COM vgen_handle_dringdata_nack_shm(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
130712011SSriharsha.Basavapatna@Sun.COM {
130812011SSriharsha.Basavapatna@Sun.COM 	uint32_t			start;
130912011SSriharsha.Basavapatna@Sun.COM 	int32_t				end;
131012011SSriharsha.Basavapatna@Sun.COM 	uint32_t			txi;
131112011SSriharsha.Basavapatna@Sun.COM 	vnet_rx_dringdata_desc_t	*txdp;
131212011SSriharsha.Basavapatna@Sun.COM 	on_trap_data_t			otd;
131312011SSriharsha.Basavapatna@Sun.COM 	int				rv = 0;
131412011SSriharsha.Basavapatna@Sun.COM 	vgen_t				*vgenp = LDC_TO_VGEN(ldcp);
131512011SSriharsha.Basavapatna@Sun.COM 	vio_dring_msg_t			*dringmsg = (vio_dring_msg_t *)tagp;
131612011SSriharsha.Basavapatna@Sun.COM 
131712011SSriharsha.Basavapatna@Sun.COM 	DBG1(vgenp, ldcp, "enter\n");
131812011SSriharsha.Basavapatna@Sun.COM 	start = dringmsg->start_idx;
131912011SSriharsha.Basavapatna@Sun.COM 	end = dringmsg->end_idx;
132012011SSriharsha.Basavapatna@Sun.COM 
132112011SSriharsha.Basavapatna@Sun.COM 	/*
132212011SSriharsha.Basavapatna@Sun.COM 	 * Peer sent a NACK msg (to indicate bad descriptors ?). The start and
132312011SSriharsha.Basavapatna@Sun.COM 	 * end correspond to the range of descriptors which are being nack'd.
132412011SSriharsha.Basavapatna@Sun.COM 	 */
132512011SSriharsha.Basavapatna@Sun.COM 	DWARN(vgenp, ldcp, "NACK: start(%d), end(%d)\n", start, end);
132612011SSriharsha.Basavapatna@Sun.COM 
132712011SSriharsha.Basavapatna@Sun.COM 	/*
132812011SSriharsha.Basavapatna@Sun.COM 	 * In RxDringData mode (v1.6), start index of -1 can be used by
132912011SSriharsha.Basavapatna@Sun.COM 	 * the peer to indicate that it is unspecified. However, the end index
133012011SSriharsha.Basavapatna@Sun.COM 	 * must be set correctly indicating the last descriptor index processed.
133112011SSriharsha.Basavapatna@Sun.COM 	 */
133212011SSriharsha.Basavapatna@Sun.COM 	if (((start != VNET_START_IDX_UNSPEC) && !(CHECK_TXI(start, ldcp))) ||
133312011SSriharsha.Basavapatna@Sun.COM 	    !(CHECK_TXI(end, ldcp))) {
133412011SSriharsha.Basavapatna@Sun.COM 		/* drop the message if invalid index */
133512011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "Invalid Tx nack start(%d) or end(%d)\n",
133612011SSriharsha.Basavapatna@Sun.COM 		    start, end);
133712011SSriharsha.Basavapatna@Sun.COM 		return (rv);
133812011SSriharsha.Basavapatna@Sun.COM 	}
133912011SSriharsha.Basavapatna@Sun.COM 
134012011SSriharsha.Basavapatna@Sun.COM 	/* Validate dring_ident */
134112011SSriharsha.Basavapatna@Sun.COM 	if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) {
134212011SSriharsha.Basavapatna@Sun.COM 		/* invalid dring_ident, drop the msg */
134312011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n",
134412011SSriharsha.Basavapatna@Sun.COM 		    dringmsg->dring_ident);
134512011SSriharsha.Basavapatna@Sun.COM 		return (rv);
134612011SSriharsha.Basavapatna@Sun.COM 	}
134712011SSriharsha.Basavapatna@Sun.COM 
134812011SSriharsha.Basavapatna@Sun.COM 	/*
134912011SSriharsha.Basavapatna@Sun.COM 	 * Setup on_trap() protection before accessing dring shared memory area.
135012011SSriharsha.Basavapatna@Sun.COM 	 */
135112011SSriharsha.Basavapatna@Sun.COM 	rv = LDC_ON_TRAP(&otd);
135212011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
135312011SSriharsha.Basavapatna@Sun.COM 		/*
135412011SSriharsha.Basavapatna@Sun.COM 		 * Data access fault occured down the code path below while
135512011SSriharsha.Basavapatna@Sun.COM 		 * accessing the descriptors. Release any locks that we might
135612011SSriharsha.Basavapatna@Sun.COM 		 * have acquired in the code below and return failure.
135712011SSriharsha.Basavapatna@Sun.COM 		 */
135812011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->txlock);
135912011SSriharsha.Basavapatna@Sun.COM 		return (ECONNRESET);
136012011SSriharsha.Basavapatna@Sun.COM 	}
136112011SSriharsha.Basavapatna@Sun.COM 
136212011SSriharsha.Basavapatna@Sun.COM 	/* We just mark the descrs as free so they can be reused */
136312011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->txlock);
136412011SSriharsha.Basavapatna@Sun.COM 	for (txi = start; txi <= end; ) {
136512011SSriharsha.Basavapatna@Sun.COM 		txdp = &(ldcp->mtxdp[txi]);
136612011SSriharsha.Basavapatna@Sun.COM 		if (txdp->dstate == VIO_DESC_READY)
136712011SSriharsha.Basavapatna@Sun.COM 			txdp->dstate = VIO_DESC_DONE;
136812011SSriharsha.Basavapatna@Sun.COM 		INCR_TXI(txi, ldcp);
136912011SSriharsha.Basavapatna@Sun.COM 	}
137012011SSriharsha.Basavapatna@Sun.COM 
137112011SSriharsha.Basavapatna@Sun.COM 	/*
137212011SSriharsha.Basavapatna@Sun.COM 	 * We are done accessing shared memory; clear trap protection.
137312011SSriharsha.Basavapatna@Sun.COM 	 */
137412011SSriharsha.Basavapatna@Sun.COM 	(void) LDC_NO_TRAP();
137512011SSriharsha.Basavapatna@Sun.COM 
137612011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&ldcp->txlock);
137712011SSriharsha.Basavapatna@Sun.COM 
137812011SSriharsha.Basavapatna@Sun.COM 	return (rv);
137912011SSriharsha.Basavapatna@Sun.COM }
138012011SSriharsha.Basavapatna@Sun.COM 
138112011SSriharsha.Basavapatna@Sun.COM /*
138212011SSriharsha.Basavapatna@Sun.COM  * Send descriptor ring data message to the peer over LDC.
138312011SSriharsha.Basavapatna@Sun.COM  */
138412011SSriharsha.Basavapatna@Sun.COM static int
vgen_send_dringdata_shm(vgen_ldc_t * ldcp,uint32_t start,int32_t end)138512011SSriharsha.Basavapatna@Sun.COM vgen_send_dringdata_shm(vgen_ldc_t *ldcp, uint32_t start, int32_t end)
138612011SSriharsha.Basavapatna@Sun.COM {
138712011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
138812011SSriharsha.Basavapatna@Sun.COM 	vio_dring_msg_t	dringmsg, *msgp = &dringmsg;
138912011SSriharsha.Basavapatna@Sun.COM 	vio_msg_tag_t	*tagp = &msgp->tag;
139012011SSriharsha.Basavapatna@Sun.COM 	vgen_stats_t	*statsp = &ldcp->stats;
139112011SSriharsha.Basavapatna@Sun.COM 	int		rv;
139212011SSriharsha.Basavapatna@Sun.COM 
139312011SSriharsha.Basavapatna@Sun.COM #ifdef DEBUG
139412011SSriharsha.Basavapatna@Sun.COM 	if (vgen_inject_error(ldcp, VGEN_ERR_TXTIMEOUT)) {
139512011SSriharsha.Basavapatna@Sun.COM 		return (VGEN_SUCCESS);
139612011SSriharsha.Basavapatna@Sun.COM 	}
139712011SSriharsha.Basavapatna@Sun.COM #endif
139812011SSriharsha.Basavapatna@Sun.COM 	bzero(msgp, sizeof (*msgp));
139912011SSriharsha.Basavapatna@Sun.COM 
140012011SSriharsha.Basavapatna@Sun.COM 	tagp->vio_msgtype = VIO_TYPE_DATA;
140112011SSriharsha.Basavapatna@Sun.COM 	tagp->vio_subtype = VIO_SUBTYPE_INFO;
140212011SSriharsha.Basavapatna@Sun.COM 	tagp->vio_subtype_env = VIO_DRING_DATA;
140312011SSriharsha.Basavapatna@Sun.COM 	tagp->vio_sid = ldcp->local_sid;
140412011SSriharsha.Basavapatna@Sun.COM 
140512011SSriharsha.Basavapatna@Sun.COM 	msgp->dring_ident = ldcp->local_hparams.dring_ident;
140612011SSriharsha.Basavapatna@Sun.COM 	msgp->start_idx = start;
140712011SSriharsha.Basavapatna@Sun.COM 	msgp->end_idx = end;
140812011SSriharsha.Basavapatna@Sun.COM 	msgp->seq_num = atomic_inc_32_nv(&ldcp->dringdata_msgid);
140912011SSriharsha.Basavapatna@Sun.COM 
141012011SSriharsha.Basavapatna@Sun.COM 	rv = vgen_sendmsg_shm(ldcp, (caddr_t)tagp, sizeof (dringmsg));
141112011SSriharsha.Basavapatna@Sun.COM 	if (rv != VGEN_SUCCESS) {
141212011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "vgen_sendmsg_shm() failed\n");
141312011SSriharsha.Basavapatna@Sun.COM 		return (rv);
141412011SSriharsha.Basavapatna@Sun.COM 	}
141512011SSriharsha.Basavapatna@Sun.COM 
141612011SSriharsha.Basavapatna@Sun.COM 	statsp->dring_data_msgs_sent++;
141712011SSriharsha.Basavapatna@Sun.COM 
141812011SSriharsha.Basavapatna@Sun.COM 	DBG2(vgenp, ldcp, "DRING_DATA_SENT \n");
141912011SSriharsha.Basavapatna@Sun.COM 
142012011SSriharsha.Basavapatna@Sun.COM 	return (VGEN_SUCCESS);
142112011SSriharsha.Basavapatna@Sun.COM }
142212011SSriharsha.Basavapatna@Sun.COM 
142312011SSriharsha.Basavapatna@Sun.COM /*
142412011SSriharsha.Basavapatna@Sun.COM  * Send dring data ack message.
142512011SSriharsha.Basavapatna@Sun.COM  */
142612011SSriharsha.Basavapatna@Sun.COM int
vgen_send_dringack_shm(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp,uint32_t start,int32_t end,uint8_t pstate)142712011SSriharsha.Basavapatna@Sun.COM vgen_send_dringack_shm(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t start,
142812011SSriharsha.Basavapatna@Sun.COM     int32_t end, uint8_t pstate)
142912011SSriharsha.Basavapatna@Sun.COM {
143012011SSriharsha.Basavapatna@Sun.COM 	int		rv = 0;
143112011SSriharsha.Basavapatna@Sun.COM 	vgen_t		*vgenp = LDC_TO_VGEN(ldcp);
143212011SSriharsha.Basavapatna@Sun.COM 	vio_dring_msg_t	*msgp = (vio_dring_msg_t *)tagp;
143312011SSriharsha.Basavapatna@Sun.COM 	vgen_stats_t	*statsp = &ldcp->stats;
143412011SSriharsha.Basavapatna@Sun.COM 
143512011SSriharsha.Basavapatna@Sun.COM 	tagp->vio_msgtype = VIO_TYPE_DATA;
143612011SSriharsha.Basavapatna@Sun.COM 	tagp->vio_subtype = VIO_SUBTYPE_ACK;
143712011SSriharsha.Basavapatna@Sun.COM 	tagp->vio_subtype_env = VIO_DRING_DATA;
143812011SSriharsha.Basavapatna@Sun.COM 	tagp->vio_sid = ldcp->local_sid;
143912011SSriharsha.Basavapatna@Sun.COM 	msgp->start_idx = start;
144012011SSriharsha.Basavapatna@Sun.COM 	msgp->end_idx = end;
144112011SSriharsha.Basavapatna@Sun.COM 	msgp->dring_process_state = pstate;
144212011SSriharsha.Basavapatna@Sun.COM 	msgp->seq_num = atomic_inc_32_nv(&ldcp->dringdata_msgid);
144312011SSriharsha.Basavapatna@Sun.COM 
144412011SSriharsha.Basavapatna@Sun.COM 	rv = vgen_sendmsg_shm(ldcp, (caddr_t)tagp, sizeof (*msgp));
144512011SSriharsha.Basavapatna@Sun.COM 	if (rv != VGEN_SUCCESS) {
144612011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "vgen_sendmsg_shm() failed\n");
144712011SSriharsha.Basavapatna@Sun.COM 	}
144812011SSriharsha.Basavapatna@Sun.COM 
144912011SSriharsha.Basavapatna@Sun.COM 	statsp->dring_data_acks_sent++;
145012011SSriharsha.Basavapatna@Sun.COM 	if (pstate == VIO_DP_STOPPED) {
145112011SSriharsha.Basavapatna@Sun.COM 		statsp->dring_stopped_acks_sent++;
145212011SSriharsha.Basavapatna@Sun.COM 	}
145312011SSriharsha.Basavapatna@Sun.COM 
145412011SSriharsha.Basavapatna@Sun.COM 	return (rv);
145512011SSriharsha.Basavapatna@Sun.COM }
145612011SSriharsha.Basavapatna@Sun.COM 
145712011SSriharsha.Basavapatna@Sun.COM /*
145812011SSriharsha.Basavapatna@Sun.COM  * Send dring data msgs (info/ack/nack) over LDC.
145912011SSriharsha.Basavapatna@Sun.COM  */
146012011SSriharsha.Basavapatna@Sun.COM static int
vgen_sendmsg_shm(vgen_ldc_t * ldcp,caddr_t msg,size_t msglen)146112011SSriharsha.Basavapatna@Sun.COM vgen_sendmsg_shm(vgen_ldc_t *ldcp, caddr_t msg,  size_t msglen)
146212011SSriharsha.Basavapatna@Sun.COM {
146312011SSriharsha.Basavapatna@Sun.COM 	int			rv;
146412011SSriharsha.Basavapatna@Sun.COM 	size_t			len;
146512011SSriharsha.Basavapatna@Sun.COM 	uint32_t		retries = 0;
146612011SSriharsha.Basavapatna@Sun.COM 	vgen_t			*vgenp = LDC_TO_VGEN(ldcp);
146712011SSriharsha.Basavapatna@Sun.COM 
146812011SSriharsha.Basavapatna@Sun.COM 	len = msglen;
146912011SSriharsha.Basavapatna@Sun.COM 	if ((len == 0) || (msg == NULL))
147012011SSriharsha.Basavapatna@Sun.COM 		return (VGEN_FAILURE);
147112011SSriharsha.Basavapatna@Sun.COM 
147212011SSriharsha.Basavapatna@Sun.COM 	do {
147312011SSriharsha.Basavapatna@Sun.COM 		len = msglen;
147412011SSriharsha.Basavapatna@Sun.COM 		rv = ldc_write(ldcp->ldc_handle, (caddr_t)msg, &len);
147512011SSriharsha.Basavapatna@Sun.COM 		if (retries++ >= vgen_ldcwr_retries)
147612011SSriharsha.Basavapatna@Sun.COM 			break;
147712011SSriharsha.Basavapatna@Sun.COM 	} while (rv == EWOULDBLOCK);
147812011SSriharsha.Basavapatna@Sun.COM 
147912011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
148012011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "ldc_write failed: rv(%d) msglen(%d)\n",
148112011SSriharsha.Basavapatna@Sun.COM 		    rv, msglen);
148212011SSriharsha.Basavapatna@Sun.COM 		return (rv);
148312011SSriharsha.Basavapatna@Sun.COM 	}
148412011SSriharsha.Basavapatna@Sun.COM 
148512011SSriharsha.Basavapatna@Sun.COM 	if (len != msglen) {
148612011SSriharsha.Basavapatna@Sun.COM 		DWARN(vgenp, ldcp, "ldc_write failed: rv(%d) msglen (%d)\n",
148712011SSriharsha.Basavapatna@Sun.COM 		    rv, msglen);
148812011SSriharsha.Basavapatna@Sun.COM 		return (VGEN_FAILURE);
148912011SSriharsha.Basavapatna@Sun.COM 	}
149012011SSriharsha.Basavapatna@Sun.COM 
149112011SSriharsha.Basavapatna@Sun.COM 	return (VGEN_SUCCESS);
149212011SSriharsha.Basavapatna@Sun.COM }
1493