xref: /illumos-gate/usr/src/uts/sun4v/io/ldc.c (revision bbfa0259e68b6b625e9e085053d41d620f185eee)
11ae08745Sheppo /*
21ae08745Sheppo  * CDDL HEADER START
31ae08745Sheppo  *
41ae08745Sheppo  * The contents of this file are subject to the terms of the
51ae08745Sheppo  * Common Development and Distribution License (the "License").
61ae08745Sheppo  * You may not use this file except in compliance with the License.
71ae08745Sheppo  *
81ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
101ae08745Sheppo  * See the License for the specific language governing permissions
111ae08745Sheppo  * and limitations under the License.
121ae08745Sheppo  *
131ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181ae08745Sheppo  *
191ae08745Sheppo  * CDDL HEADER END
201ae08745Sheppo  */
211ae08745Sheppo 
221ae08745Sheppo /*
2358283286Sha137994  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241ae08745Sheppo  * Use is subject to license terms.
251ae08745Sheppo  */
261ae08745Sheppo 
271ae08745Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
281ae08745Sheppo 
291ae08745Sheppo /*
30e1ebb9ecSlm66018  * sun4v LDC Link Layer
311ae08745Sheppo  */
321ae08745Sheppo #include <sys/types.h>
331ae08745Sheppo #include <sys/file.h>
341ae08745Sheppo #include <sys/errno.h>
351ae08745Sheppo #include <sys/open.h>
361ae08745Sheppo #include <sys/cred.h>
371ae08745Sheppo #include <sys/kmem.h>
381ae08745Sheppo #include <sys/conf.h>
391ae08745Sheppo #include <sys/cmn_err.h>
401ae08745Sheppo #include <sys/ksynch.h>
411ae08745Sheppo #include <sys/modctl.h>
421ae08745Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */
431ae08745Sheppo #include <sys/debug.h>
441ae08745Sheppo #include <sys/cred.h>
451ae08745Sheppo #include <sys/promif.h>
461ae08745Sheppo #include <sys/ddi.h>
471ae08745Sheppo #include <sys/sunddi.h>
481ae08745Sheppo #include <sys/cyclic.h>
491ae08745Sheppo #include <sys/machsystm.h>
501ae08745Sheppo #include <sys/vm.h>
511ae08745Sheppo #include <sys/cpu.h>
521ae08745Sheppo #include <sys/intreg.h>
531ae08745Sheppo #include <sys/machcpuvar.h>
544bac2208Snarayan #include <sys/mmu.h>
554bac2208Snarayan #include <sys/pte.h>
564bac2208Snarayan #include <vm/hat.h>
574bac2208Snarayan #include <vm/as.h>
584bac2208Snarayan #include <vm/hat_sfmmu.h>
594bac2208Snarayan #include <sys/vm_machparam.h>
604bac2208Snarayan #include <vm/seg_kmem.h>
614bac2208Snarayan #include <vm/seg_kpm.h>
621ae08745Sheppo #include <sys/note.h>
631ae08745Sheppo #include <sys/ivintr.h>
641ae08745Sheppo #include <sys/hypervisor_api.h>
651ae08745Sheppo #include <sys/ldc.h>
661ae08745Sheppo #include <sys/ldc_impl.h>
671ae08745Sheppo #include <sys/cnex.h>
681ae08745Sheppo #include <sys/hsvc.h>
6958283286Sha137994 #include <sys/sdt.h>
701ae08745Sheppo 
711ae08745Sheppo /* Core internal functions */
7220ae46ebSha137994 int i_ldc_h2v_error(int h_error);
7320ae46ebSha137994 void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset);
7420ae46ebSha137994 
751ae08745Sheppo static int i_ldc_txq_reconf(ldc_chan_t *ldcp);
763af08d82Slm66018 static int i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset);
77a8ea4edeSnarayan static int i_ldc_rxq_drain(ldc_chan_t *ldcp);
781ae08745Sheppo static void i_ldc_reset_state(ldc_chan_t *ldcp);
791ae08745Sheppo 
801ae08745Sheppo static int i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail);
8122f747efSnarayan static void i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head);
821ae08745Sheppo static int i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail);
831ae08745Sheppo static int i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head);
841ae08745Sheppo static int i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
851ae08745Sheppo     uint8_t ctrlmsg);
861ae08745Sheppo 
8758283286Sha137994 static int  i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head);
8858283286Sha137994 static void i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head);
8958283286Sha137994 static uint64_t i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head,
9058283286Sha137994     uint64_t *tail, uint64_t *link_state);
9158283286Sha137994 static uint64_t i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head,
9258283286Sha137994     uint64_t *tail, uint64_t *link_state);
9358283286Sha137994 static int i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head,
9458283286Sha137994     uint64_t rx_tail);
9558283286Sha137994 static uint_t i_ldc_chkq(ldc_chan_t *ldcp);
9658283286Sha137994 
971ae08745Sheppo /* Interrupt handling functions */
981ae08745Sheppo static uint_t i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2);
991ae08745Sheppo static uint_t i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2);
10058283286Sha137994 static uint_t i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client,
10158283286Sha137994     uint64_t *notify_event);
1021ae08745Sheppo static void i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype);
1031ae08745Sheppo 
1041ae08745Sheppo /* Read method functions */
1051ae08745Sheppo static int i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep);
1061ae08745Sheppo static int i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp,
1071ae08745Sheppo 	size_t *sizep);
1081ae08745Sheppo static int i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp,
1091ae08745Sheppo 	size_t *sizep);
1101ae08745Sheppo 
1111ae08745Sheppo /* Write method functions */
1121ae08745Sheppo static int i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t target_bufp,
1131ae08745Sheppo 	size_t *sizep);
1141ae08745Sheppo static int i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t target_bufp,
1151ae08745Sheppo 	size_t *sizep);
1161ae08745Sheppo static int i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t target_bufp,
1171ae08745Sheppo 	size_t *sizep);
1181ae08745Sheppo 
1191ae08745Sheppo /* Pkt processing internal functions */
1201ae08745Sheppo static int i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg);
1211ae08745Sheppo static int i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg);
1221ae08745Sheppo static int i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg);
1231ae08745Sheppo static int i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg);
1241ae08745Sheppo static int i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg);
1251ae08745Sheppo static int i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg);
1261ae08745Sheppo static int i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg);
1271ae08745Sheppo 
1281ae08745Sheppo /* LDC Version */
1291ae08745Sheppo static ldc_ver_t ldc_versions[] = { {1, 0} };
1301ae08745Sheppo 
1311ae08745Sheppo /* number of supported versions */
1321ae08745Sheppo #define	LDC_NUM_VERS	(sizeof (ldc_versions) / sizeof (ldc_versions[0]))
1331ae08745Sheppo 
13458283286Sha137994 /* Invalid value for the ldc_chan_t rx_ack_head field */
13558283286Sha137994 #define	ACKPEEK_HEAD_INVALID	((uint64_t)-1)
13658283286Sha137994 
13758283286Sha137994 
1381ae08745Sheppo /* Module State Pointer */
13920ae46ebSha137994 ldc_soft_state_t *ldcssp;
1401ae08745Sheppo 
1411ae08745Sheppo static struct modldrv md = {
1421ae08745Sheppo 	&mod_miscops,			/* This is a misc module */
1431ae08745Sheppo 	"sun4v LDC module v%I%",	/* Name of the module */
1441ae08745Sheppo };
1451ae08745Sheppo 
1461ae08745Sheppo static struct modlinkage ml = {
1471ae08745Sheppo 	MODREV_1,
1481ae08745Sheppo 	&md,
1491ae08745Sheppo 	NULL
1501ae08745Sheppo };
1511ae08745Sheppo 
1521ae08745Sheppo static uint64_t ldc_sup_minor;		/* Supported minor number */
1531ae08745Sheppo static hsvc_info_t ldc_hsvc = {
154*bbfa0259Sha137994 	HSVC_REV_1, NULL, HSVC_GROUP_LDC, 1, 1, "ldc"
1551ae08745Sheppo };
1561ae08745Sheppo 
1574bac2208Snarayan /*
158e1ebb9ecSlm66018  * The no. of MTU size messages that can be stored in
159e1ebb9ecSlm66018  * the LDC Tx queue. The number of Tx queue entries is
160e1ebb9ecSlm66018  * then computed as (mtu * mtu_msgs)/sizeof(queue_entry)
161e1ebb9ecSlm66018  */
162e1ebb9ecSlm66018 uint64_t ldc_mtu_msgs = LDC_MTU_MSGS;
163e1ebb9ecSlm66018 
164e1ebb9ecSlm66018 /*
165e1ebb9ecSlm66018  * The minimum queue length. This is the size of the smallest
166e1ebb9ecSlm66018  * LDC queue. If the computed value is less than this default,
167e1ebb9ecSlm66018  * the queue length is rounded up to 'ldc_queue_entries'.
168e1ebb9ecSlm66018  */
169e1ebb9ecSlm66018 uint64_t ldc_queue_entries = LDC_QUEUE_ENTRIES;
170e1ebb9ecSlm66018 
171e1ebb9ecSlm66018 /*
17258283286Sha137994  * The length of the reliable-mode data queue in terms of the LDC
17358283286Sha137994  * receive queue length. i.e., the number of times larger than the
17458283286Sha137994  * LDC receive queue that the data queue should be. The HV receive
17558283286Sha137994  * queue is required to be a power of 2 and this implementation
17658283286Sha137994  * assumes the data queue will also be a power of 2. By making the
17758283286Sha137994  * multiplier a power of 2, we ensure the data queue will be a
17858283286Sha137994  * power of 2. We use a multiplier because the receive queue is
17958283286Sha137994  * sized to be sane relative to the MTU and the same is needed for
18058283286Sha137994  * the data queue.
18158283286Sha137994  */
18258283286Sha137994 uint64_t ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER;
18358283286Sha137994 
18458283286Sha137994 /*
185e1ebb9ecSlm66018  * LDC retry count and delay - when the HV returns EWOULDBLOCK
186e1ebb9ecSlm66018  * the operation is retried 'ldc_max_retries' times with a
187e1ebb9ecSlm66018  * wait of 'ldc_delay' usecs between each retry.
1880a55fbb7Slm66018  */
1890a55fbb7Slm66018 int ldc_max_retries = LDC_MAX_RETRIES;
1900a55fbb7Slm66018 clock_t ldc_delay = LDC_DELAY;
1910a55fbb7Slm66018 
1924d39be2bSsg70180 /*
1934d39be2bSsg70180  * delay between each retry of channel unregistration in
1944d39be2bSsg70180  * ldc_close(), to wait for pending interrupts to complete.
1954d39be2bSsg70180  */
1964d39be2bSsg70180 clock_t ldc_close_delay = LDC_CLOSE_DELAY;
1974d39be2bSsg70180 
1981ae08745Sheppo #ifdef DEBUG
1991ae08745Sheppo 
2001ae08745Sheppo /*
2011ae08745Sheppo  * Print debug messages
2021ae08745Sheppo  *
2031ae08745Sheppo  * set ldcdbg to 0x7 for enabling all msgs
2041ae08745Sheppo  * 0x4 - Warnings
2051ae08745Sheppo  * 0x2 - All debug messages
2061ae08745Sheppo  * 0x1 - Minimal debug messages
2071ae08745Sheppo  *
2081ae08745Sheppo  * set ldcdbgchan to the channel number you want to debug
2091ae08745Sheppo  * setting it to -1 prints debug messages for all channels
2101ae08745Sheppo  * NOTE: ldcdbgchan has no effect on error messages
2111ae08745Sheppo  */
2121ae08745Sheppo 
2131ae08745Sheppo int ldcdbg = 0x0;
2141ae08745Sheppo int64_t ldcdbgchan = DBG_ALL_LDCS;
21583d3bc6fSnarayan uint64_t ldc_inject_err_flag = 0;
2161ae08745Sheppo 
21720ae46ebSha137994 void
2181ae08745Sheppo ldcdebug(int64_t id, const char *fmt, ...)
2191ae08745Sheppo {
2201ae08745Sheppo 	char buf[512];
2211ae08745Sheppo 	va_list ap;
2221ae08745Sheppo 
2231ae08745Sheppo 	/*
2241ae08745Sheppo 	 * Do not return if,
2251ae08745Sheppo 	 * caller wants to print it anyway - (id == DBG_ALL_LDCS)
2261ae08745Sheppo 	 * debug channel is set to all LDCs - (ldcdbgchan == DBG_ALL_LDCS)
2271ae08745Sheppo 	 * debug channel = caller specified channel
2281ae08745Sheppo 	 */
2291ae08745Sheppo 	if ((id != DBG_ALL_LDCS) &&
2301ae08745Sheppo 	    (ldcdbgchan != DBG_ALL_LDCS) &&
2311ae08745Sheppo 	    (ldcdbgchan != id)) {
2321ae08745Sheppo 		return;
2331ae08745Sheppo 	}
2341ae08745Sheppo 
2351ae08745Sheppo 	va_start(ap, fmt);
2361ae08745Sheppo 	(void) vsprintf(buf, fmt, ap);
2371ae08745Sheppo 	va_end(ap);
2381ae08745Sheppo 
2393af08d82Slm66018 	cmn_err(CE_CONT, "?%s", buf);
2403af08d82Slm66018 }
2413af08d82Slm66018 
24283d3bc6fSnarayan #define	LDC_ERR_RESET		0x1
24383d3bc6fSnarayan #define	LDC_ERR_PKTLOSS		0x2
24458283286Sha137994 #define	LDC_ERR_DQFULL		0x4
245*bbfa0259Sha137994 #define	LDC_ERR_DRNGCLEAR	0x8
24683d3bc6fSnarayan 
2473af08d82Slm66018 static boolean_t
24883d3bc6fSnarayan ldc_inject_error(ldc_chan_t *ldcp, uint64_t error)
2493af08d82Slm66018 {
2503af08d82Slm66018 	if ((ldcdbgchan != DBG_ALL_LDCS) && (ldcdbgchan != ldcp->id))
2513af08d82Slm66018 		return (B_FALSE);
2523af08d82Slm66018 
25383d3bc6fSnarayan 	if ((ldc_inject_err_flag & error) == 0)
2543af08d82Slm66018 		return (B_FALSE);
2553af08d82Slm66018 
2563af08d82Slm66018 	/* clear the injection state */
25783d3bc6fSnarayan 	ldc_inject_err_flag &= ~error;
2583af08d82Slm66018 
2593af08d82Slm66018 	return (B_TRUE);
2601ae08745Sheppo }
2611ae08745Sheppo 
2621ae08745Sheppo #define	D1		\
2631ae08745Sheppo if (ldcdbg & 0x01)	\
2641ae08745Sheppo 	ldcdebug
2651ae08745Sheppo 
2661ae08745Sheppo #define	D2		\
2671ae08745Sheppo if (ldcdbg & 0x02)	\
2681ae08745Sheppo 	ldcdebug
2691ae08745Sheppo 
2701ae08745Sheppo #define	DWARN		\
2711ae08745Sheppo if (ldcdbg & 0x04)	\
2721ae08745Sheppo 	ldcdebug
2731ae08745Sheppo 
2741ae08745Sheppo #define	DUMP_PAYLOAD(id, addr)						\
2751ae08745Sheppo {									\
2761ae08745Sheppo 	char buf[65*3];							\
2771ae08745Sheppo 	int i;								\
2781ae08745Sheppo 	uint8_t *src = (uint8_t *)addr;					\
2791ae08745Sheppo 	for (i = 0; i < 64; i++, src++)					\
2801ae08745Sheppo 		(void) sprintf(&buf[i * 3], "|%02x", *src);		\
2811ae08745Sheppo 	(void) sprintf(&buf[i * 3], "|\n");				\
2821ae08745Sheppo 	D2((id), "payload: %s", buf);					\
2831ae08745Sheppo }
2841ae08745Sheppo 
2851ae08745Sheppo #define	DUMP_LDC_PKT(c, s, addr)					\
2861ae08745Sheppo {									\
2871ae08745Sheppo 	ldc_msg_t *msg = (ldc_msg_t *)(addr);				\
2881ae08745Sheppo 	uint32_t mid = ((c)->mode != LDC_MODE_RAW) ? msg->seqid : 0;	\
2891ae08745Sheppo 	if (msg->type == LDC_DATA) {                                    \
2901ae08745Sheppo 	    D2((c)->id, "%s: msg%d (/%x/%x/%x/,env[%c%c,sz=%d])",	\
2911ae08745Sheppo 	    (s), mid, msg->type, msg->stype, msg->ctrl,			\
2921ae08745Sheppo 	    (msg->env & LDC_FRAG_START) ? 'B' : ' ',                    \
2931ae08745Sheppo 	    (msg->env & LDC_FRAG_STOP) ? 'E' : ' ',                     \
2941ae08745Sheppo 	    (msg->env & LDC_LEN_MASK));					\
2951ae08745Sheppo 	} else { 							\
2961ae08745Sheppo 	    D2((c)->id, "%s: msg%d (/%x/%x/%x/,env=%x)", (s),		\
2971ae08745Sheppo 	    mid, msg->type, msg->stype, msg->ctrl, msg->env);		\
2981ae08745Sheppo 	} 								\
2991ae08745Sheppo }
3001ae08745Sheppo 
30183d3bc6fSnarayan #define	LDC_INJECT_RESET(_ldcp)	ldc_inject_error(_ldcp, LDC_ERR_RESET)
30283d3bc6fSnarayan #define	LDC_INJECT_PKTLOSS(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_PKTLOSS)
30358283286Sha137994 #define	LDC_INJECT_DQFULL(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DQFULL)
304*bbfa0259Sha137994 #define	LDC_INJECT_DRNGCLEAR(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DRNGCLEAR)
305*bbfa0259Sha137994 extern void i_ldc_mem_inject_dring_clear(ldc_chan_t *ldcp);
3063af08d82Slm66018 
3071ae08745Sheppo #else
3081ae08745Sheppo 
3091ae08745Sheppo #define	DBG_ALL_LDCS -1
3101ae08745Sheppo 
3111ae08745Sheppo #define	D1
3121ae08745Sheppo #define	D2
3131ae08745Sheppo #define	DWARN
3141ae08745Sheppo 
3151ae08745Sheppo #define	DUMP_PAYLOAD(id, addr)
3161ae08745Sheppo #define	DUMP_LDC_PKT(c, s, addr)
3171ae08745Sheppo 
3183af08d82Slm66018 #define	LDC_INJECT_RESET(_ldcp)	(B_FALSE)
31983d3bc6fSnarayan #define	LDC_INJECT_PKTLOSS(_ldcp) (B_FALSE)
32058283286Sha137994 #define	LDC_INJECT_DQFULL(_ldcp) (B_FALSE)
321*bbfa0259Sha137994 #define	LDC_INJECT_DRNGCLEAR(_ldcp) (B_FALSE)
3223af08d82Slm66018 
3231ae08745Sheppo #endif
3241ae08745Sheppo 
32558283286Sha137994 /*
32658283286Sha137994  * dtrace SDT probes to ease tracing of the rx data queue and HV queue
32758283286Sha137994  * lengths. Just pass the head, tail, and entries values so that the
32858283286Sha137994  * length can be calculated in a dtrace script when the probe is enabled.
32958283286Sha137994  */
33058283286Sha137994 #define	TRACE_RXDQ_LENGTH(ldcp)						\
33158283286Sha137994 	DTRACE_PROBE4(rxdq__size,					\
33258283286Sha137994 	uint64_t, ldcp->id,						\
33358283286Sha137994 	uint64_t, ldcp->rx_dq_head,					\
33458283286Sha137994 	uint64_t, ldcp->rx_dq_tail,					\
33558283286Sha137994 	uint64_t, ldcp->rx_dq_entries)
33658283286Sha137994 
33758283286Sha137994 #define	TRACE_RXHVQ_LENGTH(ldcp, head, tail)				\
33858283286Sha137994 	DTRACE_PROBE4(rxhvq__size,					\
33958283286Sha137994 	uint64_t, ldcp->id,						\
34058283286Sha137994 	uint64_t, head,							\
34158283286Sha137994 	uint64_t, tail,							\
34258283286Sha137994 	uint64_t, ldcp->rx_q_entries)
34358283286Sha137994 
34458283286Sha137994 /* A dtrace SDT probe to ease tracing of data queue copy operations */
34558283286Sha137994 #define	TRACE_RXDQ_COPY(ldcp, bytes)					\
34658283286Sha137994 	DTRACE_PROBE2(rxdq__copy, uint64_t, ldcp->id, uint64_t, bytes)	\
34758283286Sha137994 
34858283286Sha137994 /* The amount of contiguous space at the tail of the queue */
34958283286Sha137994 #define	Q_CONTIG_SPACE(head, tail, size)				\
35058283286Sha137994 	((head) <= (tail) ? ((size) - (tail)) :				\
35158283286Sha137994 	((head) - (tail) - LDC_PACKET_SIZE))
35258283286Sha137994 
3531ae08745Sheppo #define	ZERO_PKT(p)			\
3541ae08745Sheppo 	bzero((p), sizeof (ldc_msg_t));
3551ae08745Sheppo 
3561ae08745Sheppo #define	IDX2COOKIE(idx, pg_szc, pg_shift)				\
3571ae08745Sheppo 	(((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift)))
3581ae08745Sheppo 
3591ae08745Sheppo int
3601ae08745Sheppo _init(void)
3611ae08745Sheppo {
3621ae08745Sheppo 	int status;
363*bbfa0259Sha137994 	extern void i_ldc_mem_set_hsvc_vers(uint64_t major, uint64_t minor);
3641ae08745Sheppo 
3651ae08745Sheppo 	status = hsvc_register(&ldc_hsvc, &ldc_sup_minor);
3661ae08745Sheppo 	if (status != 0) {
367d66f8315Sjb145095 		cmn_err(CE_NOTE, "!%s: cannot negotiate hypervisor LDC services"
3681ae08745Sheppo 		    " group: 0x%lx major: %ld minor: %ld errno: %d",
3691ae08745Sheppo 		    ldc_hsvc.hsvc_modname, ldc_hsvc.hsvc_group,
3701ae08745Sheppo 		    ldc_hsvc.hsvc_major, ldc_hsvc.hsvc_minor, status);
3711ae08745Sheppo 		return (-1);
3721ae08745Sheppo 	}
3731ae08745Sheppo 
374*bbfa0259Sha137994 	/* Initialize shared memory HV API version checking */
375*bbfa0259Sha137994 	i_ldc_mem_set_hsvc_vers(ldc_hsvc.hsvc_major, ldc_sup_minor);
376*bbfa0259Sha137994 
3771ae08745Sheppo 	/* allocate soft state structure */
3781ae08745Sheppo 	ldcssp = kmem_zalloc(sizeof (ldc_soft_state_t), KM_SLEEP);
3791ae08745Sheppo 
3801ae08745Sheppo 	/* Link the module into the system */
3811ae08745Sheppo 	status = mod_install(&ml);
3821ae08745Sheppo 	if (status != 0) {
3831ae08745Sheppo 		kmem_free(ldcssp, sizeof (ldc_soft_state_t));
3841ae08745Sheppo 		return (status);
3851ae08745Sheppo 	}
3861ae08745Sheppo 
3871ae08745Sheppo 	/* Initialize the LDC state structure */
3881ae08745Sheppo 	mutex_init(&ldcssp->lock, NULL, MUTEX_DRIVER, NULL);
3891ae08745Sheppo 
3901ae08745Sheppo 	mutex_enter(&ldcssp->lock);
3911ae08745Sheppo 
3924bac2208Snarayan 	/* Create a cache for memory handles */
3934bac2208Snarayan 	ldcssp->memhdl_cache = kmem_cache_create("ldc_memhdl_cache",
3944bac2208Snarayan 	    sizeof (ldc_mhdl_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
3954bac2208Snarayan 	if (ldcssp->memhdl_cache == NULL) {
3964bac2208Snarayan 		DWARN(DBG_ALL_LDCS, "_init: ldc_memhdl cache create failed\n");
3974bac2208Snarayan 		mutex_exit(&ldcssp->lock);
3984bac2208Snarayan 		return (-1);
3994bac2208Snarayan 	}
4004bac2208Snarayan 
4014bac2208Snarayan 	/* Create cache for memory segment structures */
4024bac2208Snarayan 	ldcssp->memseg_cache = kmem_cache_create("ldc_memseg_cache",
4034bac2208Snarayan 	    sizeof (ldc_memseg_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
4044bac2208Snarayan 	if (ldcssp->memseg_cache == NULL) {
4054bac2208Snarayan 		DWARN(DBG_ALL_LDCS, "_init: ldc_memseg cache create failed\n");
4064bac2208Snarayan 		mutex_exit(&ldcssp->lock);
4074bac2208Snarayan 		return (-1);
4084bac2208Snarayan 	}
4094bac2208Snarayan 
4104bac2208Snarayan 
4111ae08745Sheppo 	ldcssp->channel_count = 0;
4121ae08745Sheppo 	ldcssp->channels_open = 0;
4131ae08745Sheppo 	ldcssp->chan_list = NULL;
4141ae08745Sheppo 	ldcssp->dring_list = NULL;
4151ae08745Sheppo 
4161ae08745Sheppo 	mutex_exit(&ldcssp->lock);
4171ae08745Sheppo 
4181ae08745Sheppo 	return (0);
4191ae08745Sheppo }
4201ae08745Sheppo 
4211ae08745Sheppo int
4221ae08745Sheppo _info(struct modinfo *modinfop)
4231ae08745Sheppo {
4241ae08745Sheppo 	/* Report status of the dynamically loadable driver module */
4251ae08745Sheppo 	return (mod_info(&ml, modinfop));
4261ae08745Sheppo }
4271ae08745Sheppo 
4281ae08745Sheppo int
4291ae08745Sheppo _fini(void)
4301ae08745Sheppo {
4311ae08745Sheppo 	int 		rv, status;
43222f747efSnarayan 	ldc_chan_t 	*tmp_ldcp, *ldcp;
43322f747efSnarayan 	ldc_dring_t 	*tmp_dringp, *dringp;
4341ae08745Sheppo 	ldc_mem_info_t 	minfo;
4351ae08745Sheppo 
4361ae08745Sheppo 	/* Unlink the driver module from the system */
4371ae08745Sheppo 	status = mod_remove(&ml);
4381ae08745Sheppo 	if (status) {
4391ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "_fini: mod_remove failed\n");
4401ae08745Sheppo 		return (EIO);
4411ae08745Sheppo 	}
4421ae08745Sheppo 
4431ae08745Sheppo 	/* Free descriptor rings */
4441ae08745Sheppo 	dringp = ldcssp->dring_list;
4451ae08745Sheppo 	while (dringp != NULL) {
44622f747efSnarayan 		tmp_dringp = dringp->next;
4471ae08745Sheppo 
4481ae08745Sheppo 		rv = ldc_mem_dring_info((ldc_dring_handle_t)dringp, &minfo);
4491ae08745Sheppo 		if (rv == 0 && minfo.status != LDC_UNBOUND) {
4501ae08745Sheppo 			if (minfo.status == LDC_BOUND) {
4511ae08745Sheppo 				(void) ldc_mem_dring_unbind(
4521ae08745Sheppo 				    (ldc_dring_handle_t)dringp);
4531ae08745Sheppo 			}
4541ae08745Sheppo 			if (minfo.status == LDC_MAPPED) {
4551ae08745Sheppo 				(void) ldc_mem_dring_unmap(
4561ae08745Sheppo 				    (ldc_dring_handle_t)dringp);
4571ae08745Sheppo 			}
4581ae08745Sheppo 		}
4591ae08745Sheppo 
4601ae08745Sheppo 		(void) ldc_mem_dring_destroy((ldc_dring_handle_t)dringp);
46122f747efSnarayan 		dringp = tmp_dringp;
4621ae08745Sheppo 	}
4631ae08745Sheppo 	ldcssp->dring_list = NULL;
4641ae08745Sheppo 
46522f747efSnarayan 	/* close and finalize channels */
46622f747efSnarayan 	ldcp = ldcssp->chan_list;
46722f747efSnarayan 	while (ldcp != NULL) {
46822f747efSnarayan 		tmp_ldcp = ldcp->next;
46922f747efSnarayan 
47022f747efSnarayan 		(void) ldc_close((ldc_handle_t)ldcp);
47122f747efSnarayan 		(void) ldc_fini((ldc_handle_t)ldcp);
47222f747efSnarayan 
47322f747efSnarayan 		ldcp = tmp_ldcp;
47422f747efSnarayan 	}
47522f747efSnarayan 	ldcssp->chan_list = NULL;
47622f747efSnarayan 
4774bac2208Snarayan 	/* Destroy kmem caches */
4784bac2208Snarayan 	kmem_cache_destroy(ldcssp->memhdl_cache);
4794bac2208Snarayan 	kmem_cache_destroy(ldcssp->memseg_cache);
4804bac2208Snarayan 
4811ae08745Sheppo 	/*
4821ae08745Sheppo 	 * We have successfully "removed" the driver.
4831ae08745Sheppo 	 * Destroying soft states
4841ae08745Sheppo 	 */
4851ae08745Sheppo 	mutex_destroy(&ldcssp->lock);
4861ae08745Sheppo 	kmem_free(ldcssp, sizeof (ldc_soft_state_t));
4871ae08745Sheppo 
4881ae08745Sheppo 	(void) hsvc_unregister(&ldc_hsvc);
4891ae08745Sheppo 
4901ae08745Sheppo 	return (status);
4911ae08745Sheppo }
4921ae08745Sheppo 
4931ae08745Sheppo /* -------------------------------------------------------------------------- */
4941ae08745Sheppo 
4951ae08745Sheppo /*
496e1ebb9ecSlm66018  * LDC Link Layer Internal Functions
4971ae08745Sheppo  */
4981ae08745Sheppo 
4991ae08745Sheppo /*
5001ae08745Sheppo  * Translate HV Errors to sun4v error codes
5011ae08745Sheppo  */
50220ae46ebSha137994 int
5031ae08745Sheppo i_ldc_h2v_error(int h_error)
5041ae08745Sheppo {
5051ae08745Sheppo 	switch (h_error) {
5061ae08745Sheppo 
5071ae08745Sheppo 	case	H_EOK:
5081ae08745Sheppo 		return (0);
5091ae08745Sheppo 
5101ae08745Sheppo 	case	H_ENORADDR:
5111ae08745Sheppo 		return (EFAULT);
5121ae08745Sheppo 
5131ae08745Sheppo 	case	H_EBADPGSZ:
5141ae08745Sheppo 	case	H_EINVAL:
5151ae08745Sheppo 		return (EINVAL);
5161ae08745Sheppo 
5171ae08745Sheppo 	case	H_EWOULDBLOCK:
5181ae08745Sheppo 		return (EWOULDBLOCK);
5191ae08745Sheppo 
5201ae08745Sheppo 	case	H_ENOACCESS:
5211ae08745Sheppo 	case	H_ENOMAP:
5221ae08745Sheppo 		return (EACCES);
5231ae08745Sheppo 
5241ae08745Sheppo 	case	H_EIO:
5251ae08745Sheppo 	case	H_ECPUERROR:
5261ae08745Sheppo 		return (EIO);
5271ae08745Sheppo 
5281ae08745Sheppo 	case	H_ENOTSUPPORTED:
5291ae08745Sheppo 		return (ENOTSUP);
5301ae08745Sheppo 
5311ae08745Sheppo 	case 	H_ETOOMANY:
5321ae08745Sheppo 		return (ENOSPC);
5331ae08745Sheppo 
5341ae08745Sheppo 	case	H_ECHANNEL:
5351ae08745Sheppo 		return (ECHRNG);
5361ae08745Sheppo 	default:
5371ae08745Sheppo 		break;
5381ae08745Sheppo 	}
5391ae08745Sheppo 
5401ae08745Sheppo 	return (EIO);
5411ae08745Sheppo }
5421ae08745Sheppo 
5431ae08745Sheppo /*
5441ae08745Sheppo  * Reconfigure the transmit queue
5451ae08745Sheppo  */
5461ae08745Sheppo static int
5471ae08745Sheppo i_ldc_txq_reconf(ldc_chan_t *ldcp)
5481ae08745Sheppo {
5491ae08745Sheppo 	int rv;
5501ae08745Sheppo 
5511ae08745Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
552d10e4ef2Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
553d10e4ef2Snarayan 
5541ae08745Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
5551ae08745Sheppo 	if (rv) {
5561ae08745Sheppo 		cmn_err(CE_WARN,
5573af08d82Slm66018 		    "i_ldc_txq_reconf: (0x%lx) cannot set qconf", ldcp->id);
5581ae08745Sheppo 		return (EIO);
5591ae08745Sheppo 	}
5601ae08745Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id, &(ldcp->tx_head),
5611ae08745Sheppo 	    &(ldcp->tx_tail), &(ldcp->link_state));
5621ae08745Sheppo 	if (rv) {
5631ae08745Sheppo 		cmn_err(CE_WARN,
5643af08d82Slm66018 		    "i_ldc_txq_reconf: (0x%lx) cannot get qptrs", ldcp->id);
5651ae08745Sheppo 		return (EIO);
5661ae08745Sheppo 	}
5673af08d82Slm66018 	D1(ldcp->id, "i_ldc_txq_reconf: (0x%llx) h=0x%llx,t=0x%llx,"
5681ae08745Sheppo 	    "s=0x%llx\n", ldcp->id, ldcp->tx_head, ldcp->tx_tail,
5691ae08745Sheppo 	    ldcp->link_state);
5701ae08745Sheppo 
5711ae08745Sheppo 	return (0);
5721ae08745Sheppo }
5731ae08745Sheppo 
5741ae08745Sheppo /*
5751ae08745Sheppo  * Reconfigure the receive queue
5761ae08745Sheppo  */
5771ae08745Sheppo static int
5783af08d82Slm66018 i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset)
5791ae08745Sheppo {
5801ae08745Sheppo 	int rv;
5811ae08745Sheppo 	uint64_t rx_head, rx_tail;
5821ae08745Sheppo 
5831ae08745Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
5841ae08745Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
5851ae08745Sheppo 	    &(ldcp->link_state));
5861ae08745Sheppo 	if (rv) {
5871ae08745Sheppo 		cmn_err(CE_WARN,
5883af08d82Slm66018 		    "i_ldc_rxq_reconf: (0x%lx) cannot get state",
5891ae08745Sheppo 		    ldcp->id);
5901ae08745Sheppo 		return (EIO);
5911ae08745Sheppo 	}
5921ae08745Sheppo 
5933af08d82Slm66018 	if (force_reset || (ldcp->tstate & ~TS_IN_RESET) == TS_UP) {
5941ae08745Sheppo 		rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra,
5951ae08745Sheppo 		    ldcp->rx_q_entries);
5961ae08745Sheppo 		if (rv) {
5971ae08745Sheppo 			cmn_err(CE_WARN,
5983af08d82Slm66018 			    "i_ldc_rxq_reconf: (0x%lx) cannot set qconf",
5991ae08745Sheppo 			    ldcp->id);
6001ae08745Sheppo 			return (EIO);
6011ae08745Sheppo 		}
6023af08d82Slm66018 		D1(ldcp->id, "i_ldc_rxq_reconf: (0x%llx) completed q reconf",
6031ae08745Sheppo 		    ldcp->id);
6041ae08745Sheppo 	}
6051ae08745Sheppo 
6061ae08745Sheppo 	return (0);
6071ae08745Sheppo }
6081ae08745Sheppo 
609a8ea4edeSnarayan 
610a8ea4edeSnarayan /*
611a8ea4edeSnarayan  * Drain the contents of the receive queue
612a8ea4edeSnarayan  */
613a8ea4edeSnarayan static int
614a8ea4edeSnarayan i_ldc_rxq_drain(ldc_chan_t *ldcp)
615a8ea4edeSnarayan {
616a8ea4edeSnarayan 	int rv;
617a8ea4edeSnarayan 	uint64_t rx_head, rx_tail;
618a8ea4edeSnarayan 
619a8ea4edeSnarayan 	ASSERT(MUTEX_HELD(&ldcp->lock));
620a8ea4edeSnarayan 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
621a8ea4edeSnarayan 	    &(ldcp->link_state));
622a8ea4edeSnarayan 	if (rv) {
623a8ea4edeSnarayan 		cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot get state",
624a8ea4edeSnarayan 		    ldcp->id);
625a8ea4edeSnarayan 		return (EIO);
626a8ea4edeSnarayan 	}
627a8ea4edeSnarayan 
628a8ea4edeSnarayan 	/* flush contents by setting the head = tail */
629a8ea4edeSnarayan 	return (i_ldc_set_rx_head(ldcp, rx_tail));
630a8ea4edeSnarayan }
631a8ea4edeSnarayan 
632a8ea4edeSnarayan 
6331ae08745Sheppo /*
6341ae08745Sheppo  * Reset LDC state structure and its contents
6351ae08745Sheppo  */
6361ae08745Sheppo static void
6371ae08745Sheppo i_ldc_reset_state(ldc_chan_t *ldcp)
6381ae08745Sheppo {
6391ae08745Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
6401ae08745Sheppo 	ldcp->last_msg_snt = LDC_INIT_SEQID;
6411ae08745Sheppo 	ldcp->last_ack_rcd = 0;
6421ae08745Sheppo 	ldcp->last_msg_rcd = 0;
6431ae08745Sheppo 	ldcp->tx_ackd_head = ldcp->tx_head;
64458283286Sha137994 	ldcp->stream_remains = 0;
6451ae08745Sheppo 	ldcp->next_vidx = 0;
6461ae08745Sheppo 	ldcp->hstate = 0;
6471ae08745Sheppo 	ldcp->tstate = TS_OPEN;
6481ae08745Sheppo 	ldcp->status = LDC_OPEN;
64958283286Sha137994 	ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
65058283286Sha137994 	ldcp->rx_dq_head = 0;
65158283286Sha137994 	ldcp->rx_dq_tail = 0;
6521ae08745Sheppo 
6531ae08745Sheppo 	if (ldcp->link_state == LDC_CHANNEL_UP ||
6541ae08745Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
6551ae08745Sheppo 
6561ae08745Sheppo 		if (ldcp->mode == LDC_MODE_RAW) {
6571ae08745Sheppo 			ldcp->status = LDC_UP;
6581ae08745Sheppo 			ldcp->tstate = TS_UP;
6591ae08745Sheppo 		} else {
6601ae08745Sheppo 			ldcp->status = LDC_READY;
6611ae08745Sheppo 			ldcp->tstate |= TS_LINK_READY;
6621ae08745Sheppo 		}
6631ae08745Sheppo 	}
6641ae08745Sheppo }
6651ae08745Sheppo 
6661ae08745Sheppo /*
6671ae08745Sheppo  * Reset a LDC channel
6681ae08745Sheppo  */
66920ae46ebSha137994 void
6703af08d82Slm66018 i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset)
6711ae08745Sheppo {
67283d3bc6fSnarayan 	DWARN(ldcp->id, "i_ldc_reset: (0x%llx) channel reset\n", ldcp->id);
6731ae08745Sheppo 
674d10e4ef2Snarayan 	ASSERT(MUTEX_HELD(&ldcp->lock));
675d10e4ef2Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
676d10e4ef2Snarayan 
6773af08d82Slm66018 	/* reconfig Tx and Rx queues */
6781ae08745Sheppo 	(void) i_ldc_txq_reconf(ldcp);
6793af08d82Slm66018 	(void) i_ldc_rxq_reconf(ldcp, force_reset);
6803af08d82Slm66018 
6813af08d82Slm66018 	/* Clear Tx and Rx interrupts */
6823af08d82Slm66018 	(void) i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
6833af08d82Slm66018 	(void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
6843af08d82Slm66018 
6853af08d82Slm66018 	/* Reset channel state */
6861ae08745Sheppo 	i_ldc_reset_state(ldcp);
6873af08d82Slm66018 
6883af08d82Slm66018 	/* Mark channel in reset */
6893af08d82Slm66018 	ldcp->tstate |= TS_IN_RESET;
6901ae08745Sheppo }
6911ae08745Sheppo 
6924bac2208Snarayan 
6931ae08745Sheppo /*
6941ae08745Sheppo  * Clear pending interrupts
6951ae08745Sheppo  */
6961ae08745Sheppo static void
6971ae08745Sheppo i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype)
6981ae08745Sheppo {
6991ae08745Sheppo 	ldc_cnex_t *cinfo = &ldcssp->cinfo;
7001ae08745Sheppo 
7011ae08745Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
7023af08d82Slm66018 	ASSERT(cinfo->dip != NULL);
7034bac2208Snarayan 
7043af08d82Slm66018 	switch (itype) {
7053af08d82Slm66018 	case CNEX_TX_INTR:
7064bac2208Snarayan 		/* check Tx interrupt */
7073af08d82Slm66018 		if (ldcp->tx_intr_state)
7083af08d82Slm66018 			ldcp->tx_intr_state = LDC_INTR_NONE;
7094bac2208Snarayan 		else
7104bac2208Snarayan 			return;
7113af08d82Slm66018 		break;
7123af08d82Slm66018 
7133af08d82Slm66018 	case CNEX_RX_INTR:
7144bac2208Snarayan 		/* check Rx interrupt */
7153af08d82Slm66018 		if (ldcp->rx_intr_state)
7163af08d82Slm66018 			ldcp->rx_intr_state = LDC_INTR_NONE;
7174bac2208Snarayan 		else
7184bac2208Snarayan 			return;
7193af08d82Slm66018 		break;
7204bac2208Snarayan 	}
7214bac2208Snarayan 
7221ae08745Sheppo 	(void) cinfo->clr_intr(cinfo->dip, ldcp->id, itype);
7234bac2208Snarayan 	D2(ldcp->id,
7244bac2208Snarayan 	    "i_ldc_clear_intr: (0x%llx) cleared 0x%x intr\n",
7254bac2208Snarayan 	    ldcp->id, itype);
7261ae08745Sheppo }
7271ae08745Sheppo 
7281ae08745Sheppo /*
7291ae08745Sheppo  * Set the receive queue head
7300a55fbb7Slm66018  * Resets connection and returns an error if it fails.
7311ae08745Sheppo  */
7321ae08745Sheppo static int
7331ae08745Sheppo i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head)
7341ae08745Sheppo {
7351ae08745Sheppo 	int 	rv;
7360a55fbb7Slm66018 	int 	retries;
7371ae08745Sheppo 
7381ae08745Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
7390a55fbb7Slm66018 	for (retries = 0; retries < ldc_max_retries; retries++) {
7400a55fbb7Slm66018 
7410a55fbb7Slm66018 		if ((rv = hv_ldc_rx_set_qhead(ldcp->id, head)) == 0)
7420a55fbb7Slm66018 			return (0);
7430a55fbb7Slm66018 
7440a55fbb7Slm66018 		if (rv != H_EWOULDBLOCK)
7450a55fbb7Slm66018 			break;
7460a55fbb7Slm66018 
7470a55fbb7Slm66018 		/* wait for ldc_delay usecs */
7480a55fbb7Slm66018 		drv_usecwait(ldc_delay);
7491ae08745Sheppo 	}
7501ae08745Sheppo 
7510a55fbb7Slm66018 	cmn_err(CE_WARN, "ldc_rx_set_qhead: (0x%lx) cannot set qhead 0x%lx",
7520a55fbb7Slm66018 	    ldcp->id, head);
753d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
7543af08d82Slm66018 	i_ldc_reset(ldcp, B_TRUE);
755d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
7560a55fbb7Slm66018 
7570a55fbb7Slm66018 	return (ECONNRESET);
7581ae08745Sheppo }
7591ae08745Sheppo 
76022f747efSnarayan /*
76122f747efSnarayan  * Returns the tx_head to be used for transfer
76222f747efSnarayan  */
76322f747efSnarayan static void
76422f747efSnarayan i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head)
76522f747efSnarayan {
76622f747efSnarayan 	ldc_msg_t 	*pkt;
76722f747efSnarayan 
76822f747efSnarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
76922f747efSnarayan 
77022f747efSnarayan 	/* get current Tx head */
77122f747efSnarayan 	*head = ldcp->tx_head;
77222f747efSnarayan 
77322f747efSnarayan 	/*
77422f747efSnarayan 	 * Reliable mode will use the ACKd head instead of the regular tx_head.
77522f747efSnarayan 	 * Also in Reliable mode, advance ackd_head for all non DATA/INFO pkts,
77622f747efSnarayan 	 * up to the current location of tx_head. This needs to be done
77722f747efSnarayan 	 * as the peer will only ACK DATA/INFO pkts.
77822f747efSnarayan 	 */
77920ae46ebSha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
78022f747efSnarayan 		while (ldcp->tx_ackd_head != ldcp->tx_head) {
78122f747efSnarayan 			pkt = (ldc_msg_t *)(ldcp->tx_q_va + ldcp->tx_ackd_head);
78222f747efSnarayan 			if ((pkt->type & LDC_DATA) && (pkt->stype & LDC_INFO)) {
78322f747efSnarayan 				break;
78422f747efSnarayan 			}
78522f747efSnarayan 			/* advance ACKd head */
78622f747efSnarayan 			ldcp->tx_ackd_head =
78722f747efSnarayan 			    (ldcp->tx_ackd_head + LDC_PACKET_SIZE) %
78822f747efSnarayan 			    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
78922f747efSnarayan 		}
79022f747efSnarayan 		*head = ldcp->tx_ackd_head;
79122f747efSnarayan 	}
79222f747efSnarayan }
7931ae08745Sheppo 
7941ae08745Sheppo /*
7951ae08745Sheppo  * Returns the tx_tail to be used for transfer
7961ae08745Sheppo  * Re-reads the TX queue ptrs if and only if the
7971ae08745Sheppo  * the cached head and tail are equal (queue is full)
7981ae08745Sheppo  */
7991ae08745Sheppo static int
8001ae08745Sheppo i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail)
8011ae08745Sheppo {
8021ae08745Sheppo 	int 		rv;
8031ae08745Sheppo 	uint64_t 	current_head, new_tail;
8041ae08745Sheppo 
805d10e4ef2Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
8061ae08745Sheppo 	/* Read the head and tail ptrs from HV */
8071ae08745Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
8081ae08745Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
8091ae08745Sheppo 	if (rv) {
8101ae08745Sheppo 		cmn_err(CE_WARN,
8111ae08745Sheppo 		    "i_ldc_get_tx_tail: (0x%lx) cannot read qptrs\n",
8121ae08745Sheppo 		    ldcp->id);
8131ae08745Sheppo 		return (EIO);
8141ae08745Sheppo 	}
8151ae08745Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN) {
816cb112a14Slm66018 		D1(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) channel not ready\n",
8171ae08745Sheppo 		    ldcp->id);
8181ae08745Sheppo 		return (ECONNRESET);
8191ae08745Sheppo 	}
8201ae08745Sheppo 
82122f747efSnarayan 	i_ldc_get_tx_head(ldcp, &current_head);
8221ae08745Sheppo 
8231ae08745Sheppo 	/* increment the tail */
8241ae08745Sheppo 	new_tail = (ldcp->tx_tail + LDC_PACKET_SIZE) %
8251ae08745Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
8261ae08745Sheppo 
8271ae08745Sheppo 	if (new_tail == current_head) {
8281ae08745Sheppo 		DWARN(ldcp->id,
8291ae08745Sheppo 		    "i_ldc_get_tx_tail: (0x%llx) TX queue is full\n",
8301ae08745Sheppo 		    ldcp->id);
8311ae08745Sheppo 		return (EWOULDBLOCK);
8321ae08745Sheppo 	}
8331ae08745Sheppo 
8341ae08745Sheppo 	D2(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) head=0x%llx, tail=0x%llx\n",
8351ae08745Sheppo 	    ldcp->id, ldcp->tx_head, ldcp->tx_tail);
8361ae08745Sheppo 
8371ae08745Sheppo 	*tail = ldcp->tx_tail;
8381ae08745Sheppo 	return (0);
8391ae08745Sheppo }
8401ae08745Sheppo 
8411ae08745Sheppo /*
8421ae08745Sheppo  * Set the tail pointer. If HV returns EWOULDBLOCK, it will back off
8430a55fbb7Slm66018  * and retry ldc_max_retries times before returning an error.
8441ae08745Sheppo  * Returns 0, EWOULDBLOCK or EIO
8451ae08745Sheppo  */
8461ae08745Sheppo static int
8471ae08745Sheppo i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail)
8481ae08745Sheppo {
8491ae08745Sheppo 	int		rv, retval = EWOULDBLOCK;
8500a55fbb7Slm66018 	int 		retries;
8511ae08745Sheppo 
852d10e4ef2Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
8530a55fbb7Slm66018 	for (retries = 0; retries < ldc_max_retries; retries++) {
8541ae08745Sheppo 
8551ae08745Sheppo 		if ((rv = hv_ldc_tx_set_qtail(ldcp->id, tail)) == 0) {
8561ae08745Sheppo 			retval = 0;
8571ae08745Sheppo 			break;
8581ae08745Sheppo 		}
8591ae08745Sheppo 		if (rv != H_EWOULDBLOCK) {
8601ae08745Sheppo 			DWARN(ldcp->id, "i_ldc_set_tx_tail: (0x%llx) set "
8611ae08745Sheppo 			    "qtail=0x%llx failed, rv=%d\n", ldcp->id, tail, rv);
8621ae08745Sheppo 			retval = EIO;
8631ae08745Sheppo 			break;
8641ae08745Sheppo 		}
8651ae08745Sheppo 
8660a55fbb7Slm66018 		/* wait for ldc_delay usecs */
8670a55fbb7Slm66018 		drv_usecwait(ldc_delay);
8681ae08745Sheppo 	}
8691ae08745Sheppo 	return (retval);
8701ae08745Sheppo }
8711ae08745Sheppo 
8721ae08745Sheppo /*
87358283286Sha137994  * Copy a data packet from the HV receive queue to the data queue.
87458283286Sha137994  * Caller must ensure that the data queue is not already full.
87558283286Sha137994  *
87658283286Sha137994  * The *head argument represents the current head pointer for the HV
87758283286Sha137994  * receive queue. After copying a packet from the HV receive queue,
87858283286Sha137994  * the *head pointer will be updated. This allows the caller to update
87958283286Sha137994  * the head pointer in HV using the returned *head value.
88058283286Sha137994  */
88158283286Sha137994 void
88258283286Sha137994 i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head)
88358283286Sha137994 {
88458283286Sha137994 	uint64_t	q_size, dq_size;
88558283286Sha137994 
88658283286Sha137994 	ASSERT(MUTEX_HELD(&ldcp->lock));
88758283286Sha137994 
88858283286Sha137994 	q_size  = ldcp->rx_q_entries << LDC_PACKET_SHIFT;
88958283286Sha137994 	dq_size = ldcp->rx_dq_entries << LDC_PACKET_SHIFT;
89058283286Sha137994 
89158283286Sha137994 	ASSERT(Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail,
89258283286Sha137994 	    dq_size) >= LDC_PACKET_SIZE);
89358283286Sha137994 
89458283286Sha137994 	bcopy((void *)(ldcp->rx_q_va + *head),
89558283286Sha137994 	    (void *)(ldcp->rx_dq_va + ldcp->rx_dq_tail), LDC_PACKET_SIZE);
89658283286Sha137994 	TRACE_RXDQ_COPY(ldcp, LDC_PACKET_SIZE);
89758283286Sha137994 
89858283286Sha137994 	/* Update rx head */
89958283286Sha137994 	*head = (*head + LDC_PACKET_SIZE) % q_size;
90058283286Sha137994 
90158283286Sha137994 	/* Update dq tail */
90258283286Sha137994 	ldcp->rx_dq_tail = (ldcp->rx_dq_tail + LDC_PACKET_SIZE) % dq_size;
90358283286Sha137994 }
90458283286Sha137994 
90558283286Sha137994 /*
90658283286Sha137994  * Update the Rx data queue head pointer
90758283286Sha137994  */
90858283286Sha137994 static int
90958283286Sha137994 i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head)
91058283286Sha137994 {
91158283286Sha137994 	ldcp->rx_dq_head = head;
91258283286Sha137994 	return (0);
91358283286Sha137994 }
91458283286Sha137994 
91558283286Sha137994 /*
91658283286Sha137994  * Get the Rx data queue head and tail pointers
91758283286Sha137994  */
91858283286Sha137994 static uint64_t
91958283286Sha137994 i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail,
92058283286Sha137994     uint64_t *link_state)
92158283286Sha137994 {
92258283286Sha137994 	_NOTE(ARGUNUSED(link_state))
92358283286Sha137994 	*head = ldcp->rx_dq_head;
92458283286Sha137994 	*tail = ldcp->rx_dq_tail;
92558283286Sha137994 	return (0);
92658283286Sha137994 }
92758283286Sha137994 
92858283286Sha137994 /*
92958283286Sha137994  * Wrapper for the Rx HV queue set head function. Giving the
93058283286Sha137994  * data queue and HV queue set head functions the same type.
93158283286Sha137994  */
93258283286Sha137994 static uint64_t
93358283286Sha137994 i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail,
93458283286Sha137994     uint64_t *link_state)
93558283286Sha137994 {
93658283286Sha137994 	return (i_ldc_h2v_error(hv_ldc_rx_get_state(ldcp->id, head, tail,
93758283286Sha137994 	    link_state)));
93858283286Sha137994 }
93958283286Sha137994 
94058283286Sha137994 /*
94158283286Sha137994  * LDC receive interrupt handler
94258283286Sha137994  *    triggered for channel with data pending to read
94358283286Sha137994  *    i.e. Rx queue content changes
94458283286Sha137994  */
94558283286Sha137994 static uint_t
94658283286Sha137994 i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2)
94758283286Sha137994 {
94858283286Sha137994 	_NOTE(ARGUNUSED(arg2))
94958283286Sha137994 
95058283286Sha137994 	ldc_chan_t	*ldcp;
95158283286Sha137994 	boolean_t	notify;
95258283286Sha137994 	uint64_t	event;
95358283286Sha137994 	int		rv;
95458283286Sha137994 
95558283286Sha137994 	/* Get the channel for which interrupt was received */
95658283286Sha137994 	if (arg1 == NULL) {
95758283286Sha137994 		cmn_err(CE_WARN, "i_ldc_rx_hdlr: invalid arg\n");
95858283286Sha137994 		return (DDI_INTR_UNCLAIMED);
95958283286Sha137994 	}
96058283286Sha137994 
96158283286Sha137994 	ldcp = (ldc_chan_t *)arg1;
96258283286Sha137994 
96358283286Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
96458283286Sha137994 	    ldcp->id, ldcp);
96558283286Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (%llx) USR%lx/TS%lx/HS%lx, LSTATE=%lx\n",
96658283286Sha137994 	    ldcp->id, ldcp->status, ldcp->tstate, ldcp->hstate,
96758283286Sha137994 	    ldcp->link_state);
96858283286Sha137994 
96958283286Sha137994 	/* Lock channel */
97058283286Sha137994 	mutex_enter(&ldcp->lock);
97158283286Sha137994 
97258283286Sha137994 	/* Mark the interrupt as being actively handled */
97358283286Sha137994 	ldcp->rx_intr_state = LDC_INTR_ACTIVE;
97458283286Sha137994 
97558283286Sha137994 	(void) i_ldc_rx_process_hvq(ldcp, &notify, &event);
97658283286Sha137994 
97720ae46ebSha137994 	if (ldcp->mode != LDC_MODE_RELIABLE) {
97858283286Sha137994 		/*
97958283286Sha137994 		 * If there are no data packets on the queue, clear
98058283286Sha137994 		 * the interrupt. Otherwise, the ldc_read will clear
98158283286Sha137994 		 * interrupts after draining the queue. To indicate the
98258283286Sha137994 		 * interrupt has not yet been cleared, it is marked
98358283286Sha137994 		 * as pending.
98458283286Sha137994 		 */
98558283286Sha137994 		if ((event & LDC_EVT_READ) == 0) {
98658283286Sha137994 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
98758283286Sha137994 		} else {
98858283286Sha137994 			ldcp->rx_intr_state = LDC_INTR_PEND;
98958283286Sha137994 		}
99058283286Sha137994 	}
99158283286Sha137994 
99258283286Sha137994 	/* if callbacks are disabled, do not notify */
99358283286Sha137994 	if (notify && ldcp->cb_enabled) {
99458283286Sha137994 		ldcp->cb_inprogress = B_TRUE;
99558283286Sha137994 		mutex_exit(&ldcp->lock);
99658283286Sha137994 		rv = ldcp->cb(event, ldcp->cb_arg);
99758283286Sha137994 		if (rv) {
99858283286Sha137994 			DWARN(ldcp->id,
99958283286Sha137994 			    "i_ldc_rx_hdlr: (0x%llx) callback failure",
100058283286Sha137994 			    ldcp->id);
100158283286Sha137994 		}
100258283286Sha137994 		mutex_enter(&ldcp->lock);
100358283286Sha137994 		ldcp->cb_inprogress = B_FALSE;
100458283286Sha137994 	}
100558283286Sha137994 
100620ae46ebSha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
100758283286Sha137994 		/*
100858283286Sha137994 		 * If we are using a secondary data queue, clear the
100958283286Sha137994 		 * interrupt. We should have processed all CTRL packets
101058283286Sha137994 		 * and copied all DATA packets to the secondary queue.
101158283286Sha137994 		 * Even if secondary queue filled up, clear the interrupts,
101258283286Sha137994 		 * this will trigger another interrupt and force the
101358283286Sha137994 		 * handler to copy more data.
101458283286Sha137994 		 */
101558283286Sha137994 		i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
101658283286Sha137994 	}
101758283286Sha137994 
101858283286Sha137994 	mutex_exit(&ldcp->lock);
101958283286Sha137994 
102058283286Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) exiting handler", ldcp->id);
102158283286Sha137994 
102258283286Sha137994 	return (DDI_INTR_CLAIMED);
102358283286Sha137994 }
102458283286Sha137994 
102558283286Sha137994 /*
102658283286Sha137994  * Wrapper for the Rx HV queue processing function to be used when
102758283286Sha137994  * checking the Rx HV queue for data packets. Unlike the interrupt
102858283286Sha137994  * handler code flow, the Rx interrupt is not cleared here and
102958283286Sha137994  * callbacks are not made.
103058283286Sha137994  */
103158283286Sha137994 static uint_t
103258283286Sha137994 i_ldc_chkq(ldc_chan_t *ldcp)
103358283286Sha137994 {
103458283286Sha137994 	boolean_t	notify;
103558283286Sha137994 	uint64_t	event;
103658283286Sha137994 
103758283286Sha137994 	return (i_ldc_rx_process_hvq(ldcp, &notify, &event));
103858283286Sha137994 }
103958283286Sha137994 
104058283286Sha137994 /*
10411ae08745Sheppo  * Send a LDC message
10421ae08745Sheppo  */
10431ae08745Sheppo static int
10441ae08745Sheppo i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
10451ae08745Sheppo     uint8_t ctrlmsg)
10461ae08745Sheppo {
10471ae08745Sheppo 	int		rv;
10481ae08745Sheppo 	ldc_msg_t 	*pkt;
10491ae08745Sheppo 	uint64_t	tx_tail;
105022f747efSnarayan 	uint32_t	curr_seqid;
10511ae08745Sheppo 
1052d10e4ef2Snarayan 	/* Obtain Tx lock */
1053d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
1054d10e4ef2Snarayan 
105522f747efSnarayan 	curr_seqid = ldcp->last_msg_snt;
105622f747efSnarayan 
10571ae08745Sheppo 	/* get the current tail for the message */
10581ae08745Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
10591ae08745Sheppo 	if (rv) {
10601ae08745Sheppo 		DWARN(ldcp->id,
10611ae08745Sheppo 		    "i_ldc_send_pkt: (0x%llx) error sending pkt, "
10621ae08745Sheppo 		    "type=0x%x,subtype=0x%x,ctrl=0x%x\n",
10631ae08745Sheppo 		    ldcp->id, pkttype, subtype, ctrlmsg);
1064d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
10651ae08745Sheppo 		return (rv);
10661ae08745Sheppo 	}
10671ae08745Sheppo 
10681ae08745Sheppo 	pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
10691ae08745Sheppo 	ZERO_PKT(pkt);
10701ae08745Sheppo 
10711ae08745Sheppo 	/* Initialize the packet */
10721ae08745Sheppo 	pkt->type = pkttype;
10731ae08745Sheppo 	pkt->stype = subtype;
10741ae08745Sheppo 	pkt->ctrl = ctrlmsg;
10751ae08745Sheppo 
10761ae08745Sheppo 	/* Store ackid/seqid iff it is RELIABLE mode & not a RTS/RTR message */
10771ae08745Sheppo 	if (((ctrlmsg & LDC_CTRL_MASK) != LDC_RTS) &&
10781ae08745Sheppo 	    ((ctrlmsg & LDC_CTRL_MASK) != LDC_RTR)) {
10791ae08745Sheppo 		curr_seqid++;
10801ae08745Sheppo 		if (ldcp->mode != LDC_MODE_RAW) {
10811ae08745Sheppo 			pkt->seqid = curr_seqid;
10821ae08745Sheppo 			pkt->ackid = ldcp->last_msg_rcd;
10831ae08745Sheppo 		}
10841ae08745Sheppo 	}
10851ae08745Sheppo 	DUMP_LDC_PKT(ldcp, "i_ldc_send_pkt", (uint64_t)pkt);
10861ae08745Sheppo 
10871ae08745Sheppo 	/* initiate the send by calling into HV and set the new tail */
10881ae08745Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
10891ae08745Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
10901ae08745Sheppo 
10911ae08745Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
10921ae08745Sheppo 	if (rv) {
10931ae08745Sheppo 		DWARN(ldcp->id,
10941ae08745Sheppo 		    "i_ldc_send_pkt:(0x%llx) error sending pkt, "
10951ae08745Sheppo 		    "type=0x%x,stype=0x%x,ctrl=0x%x\n",
10961ae08745Sheppo 		    ldcp->id, pkttype, subtype, ctrlmsg);
1097d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
10981ae08745Sheppo 		return (EIO);
10991ae08745Sheppo 	}
11001ae08745Sheppo 
11011ae08745Sheppo 	ldcp->last_msg_snt = curr_seqid;
11021ae08745Sheppo 	ldcp->tx_tail = tx_tail;
11031ae08745Sheppo 
1104d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
11051ae08745Sheppo 	return (0);
11061ae08745Sheppo }
11071ae08745Sheppo 
11081ae08745Sheppo /*
11091ae08745Sheppo  * Checks if packet was received in right order
1110e1ebb9ecSlm66018  * in the case of a reliable link.
11111ae08745Sheppo  * Returns 0 if in order, else EIO
11121ae08745Sheppo  */
11131ae08745Sheppo static int
11141ae08745Sheppo i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *msg)
11151ae08745Sheppo {
11161ae08745Sheppo 	/* No seqid checking for RAW mode */
11171ae08745Sheppo 	if (ldcp->mode == LDC_MODE_RAW)
11181ae08745Sheppo 		return (0);
11191ae08745Sheppo 
11201ae08745Sheppo 	/* No seqid checking for version, RTS, RTR message */
11211ae08745Sheppo 	if (msg->ctrl == LDC_VER ||
11221ae08745Sheppo 	    msg->ctrl == LDC_RTS ||
11231ae08745Sheppo 	    msg->ctrl == LDC_RTR)
11241ae08745Sheppo 		return (0);
11251ae08745Sheppo 
11261ae08745Sheppo 	/* Initial seqid to use is sent in RTS/RTR and saved in last_msg_rcd */
11271ae08745Sheppo 	if (msg->seqid != (ldcp->last_msg_rcd + 1)) {
11281ae08745Sheppo 		DWARN(ldcp->id,
11291ae08745Sheppo 		    "i_ldc_check_seqid: (0x%llx) out-of-order pkt, got 0x%x, "
11301ae08745Sheppo 		    "expecting 0x%x\n", ldcp->id, msg->seqid,
11311ae08745Sheppo 		    (ldcp->last_msg_rcd + 1));
11321ae08745Sheppo 		return (EIO);
11331ae08745Sheppo 	}
11341ae08745Sheppo 
113583d3bc6fSnarayan #ifdef DEBUG
113683d3bc6fSnarayan 	if (LDC_INJECT_PKTLOSS(ldcp)) {
113783d3bc6fSnarayan 		DWARN(ldcp->id,
113883d3bc6fSnarayan 		    "i_ldc_check_seqid: (0x%llx) inject pkt loss\n", ldcp->id);
113983d3bc6fSnarayan 		return (EIO);
114083d3bc6fSnarayan 	}
114183d3bc6fSnarayan #endif
114283d3bc6fSnarayan 
11431ae08745Sheppo 	return (0);
11441ae08745Sheppo }
11451ae08745Sheppo 
11461ae08745Sheppo 
11471ae08745Sheppo /*
11481ae08745Sheppo  * Process an incoming version ctrl message
11491ae08745Sheppo  */
11501ae08745Sheppo static int
11511ae08745Sheppo i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg)
11521ae08745Sheppo {
11531ae08745Sheppo 	int 		rv = 0, idx = ldcp->next_vidx;
11541ae08745Sheppo 	ldc_msg_t 	*pkt;
11551ae08745Sheppo 	uint64_t	tx_tail;
11561ae08745Sheppo 	ldc_ver_t	*rcvd_ver;
11571ae08745Sheppo 
11581ae08745Sheppo 	/* get the received version */
11591ae08745Sheppo 	rcvd_ver = (ldc_ver_t *)((uint64_t)msg + LDC_PAYLOAD_VER_OFF);
11601ae08745Sheppo 
11611ae08745Sheppo 	D2(ldcp->id, "i_ldc_process_VER: (0x%llx) received VER v%u.%u\n",
11621ae08745Sheppo 	    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
11631ae08745Sheppo 
1164d10e4ef2Snarayan 	/* Obtain Tx lock */
1165d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
1166d10e4ef2Snarayan 
11671ae08745Sheppo 	switch (msg->stype) {
11681ae08745Sheppo 	case LDC_INFO:
11691ae08745Sheppo 
11703af08d82Slm66018 		if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) {
11713af08d82Slm66018 			(void) i_ldc_txq_reconf(ldcp);
11723af08d82Slm66018 			i_ldc_reset_state(ldcp);
11733af08d82Slm66018 			mutex_exit(&ldcp->tx_lock);
11743af08d82Slm66018 			return (EAGAIN);
11753af08d82Slm66018 		}
11763af08d82Slm66018 
11771ae08745Sheppo 		/* get the current tail and pkt for the response */
11781ae08745Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
11791ae08745Sheppo 		if (rv != 0) {
11801ae08745Sheppo 			DWARN(ldcp->id,
11811ae08745Sheppo 			    "i_ldc_process_VER: (0x%llx) err sending "
11821ae08745Sheppo 			    "version ACK/NACK\n", ldcp->id);
11833af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1184d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
11851ae08745Sheppo 			return (ECONNRESET);
11861ae08745Sheppo 		}
11871ae08745Sheppo 
11881ae08745Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
11891ae08745Sheppo 		ZERO_PKT(pkt);
11901ae08745Sheppo 
11911ae08745Sheppo 		/* initialize the packet */
11921ae08745Sheppo 		pkt->type = LDC_CTRL;
11931ae08745Sheppo 		pkt->ctrl = LDC_VER;
11941ae08745Sheppo 
11951ae08745Sheppo 		for (;;) {
11961ae08745Sheppo 
11971ae08745Sheppo 			D1(ldcp->id, "i_ldc_process_VER: got %u.%u chk %u.%u\n",
11981ae08745Sheppo 			    rcvd_ver->major, rcvd_ver->minor,
11991ae08745Sheppo 			    ldc_versions[idx].major, ldc_versions[idx].minor);
12001ae08745Sheppo 
12011ae08745Sheppo 			if (rcvd_ver->major == ldc_versions[idx].major) {
12021ae08745Sheppo 				/* major version match - ACK version */
12031ae08745Sheppo 				pkt->stype = LDC_ACK;
12041ae08745Sheppo 
12051ae08745Sheppo 				/*
12061ae08745Sheppo 				 * lower minor version to the one this endpt
12071ae08745Sheppo 				 * supports, if necessary
12081ae08745Sheppo 				 */
12091ae08745Sheppo 				if (rcvd_ver->minor > ldc_versions[idx].minor)
12101ae08745Sheppo 					rcvd_ver->minor =
12111ae08745Sheppo 					    ldc_versions[idx].minor;
12121ae08745Sheppo 				bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver));
12131ae08745Sheppo 
12141ae08745Sheppo 				break;
12151ae08745Sheppo 			}
12161ae08745Sheppo 
12171ae08745Sheppo 			if (rcvd_ver->major > ldc_versions[idx].major) {
12181ae08745Sheppo 
12191ae08745Sheppo 				D1(ldcp->id, "i_ldc_process_VER: using next"
12201ae08745Sheppo 				    " lower idx=%d, v%u.%u\n", idx,
12211ae08745Sheppo 				    ldc_versions[idx].major,
12221ae08745Sheppo 				    ldc_versions[idx].minor);
12231ae08745Sheppo 
12241ae08745Sheppo 				/* nack with next lower version */
12251ae08745Sheppo 				pkt->stype = LDC_NACK;
12261ae08745Sheppo 				bcopy(&ldc_versions[idx], pkt->udata,
12271ae08745Sheppo 				    sizeof (ldc_versions[idx]));
12281ae08745Sheppo 				ldcp->next_vidx = idx;
12291ae08745Sheppo 				break;
12301ae08745Sheppo 			}
12311ae08745Sheppo 
12321ae08745Sheppo 			/* next major version */
12331ae08745Sheppo 			idx++;
12341ae08745Sheppo 
12351ae08745Sheppo 			D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx);
12361ae08745Sheppo 
12371ae08745Sheppo 			if (idx == LDC_NUM_VERS) {
12381ae08745Sheppo 				/* no version match - send NACK */
12391ae08745Sheppo 				pkt->stype = LDC_NACK;
12401ae08745Sheppo 				bzero(pkt->udata, sizeof (ldc_ver_t));
12411ae08745Sheppo 				ldcp->next_vidx = 0;
12421ae08745Sheppo 				break;
12431ae08745Sheppo 			}
12441ae08745Sheppo 		}
12451ae08745Sheppo 
12461ae08745Sheppo 		/* initiate the send by calling into HV and set the new tail */
12471ae08745Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
12481ae08745Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
12491ae08745Sheppo 
12501ae08745Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
12511ae08745Sheppo 		if (rv == 0) {
12521ae08745Sheppo 			ldcp->tx_tail = tx_tail;
12531ae08745Sheppo 			if (pkt->stype == LDC_ACK) {
12541ae08745Sheppo 				D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent"
12551ae08745Sheppo 				    " version ACK\n", ldcp->id);
12561ae08745Sheppo 				/* Save the ACK'd version */
12571ae08745Sheppo 				ldcp->version.major = rcvd_ver->major;
12581ae08745Sheppo 				ldcp->version.minor = rcvd_ver->minor;
12590a55fbb7Slm66018 				ldcp->hstate |= TS_RCVD_VER;
12601ae08745Sheppo 				ldcp->tstate |= TS_VER_DONE;
126183d3bc6fSnarayan 				D1(DBG_ALL_LDCS,
12623af08d82Slm66018 				    "(0x%llx) Sent ACK, "
12633af08d82Slm66018 				    "Agreed on version v%u.%u\n",
12641ae08745Sheppo 				    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
12651ae08745Sheppo 			}
12661ae08745Sheppo 		} else {
12671ae08745Sheppo 			DWARN(ldcp->id,
12681ae08745Sheppo 			    "i_ldc_process_VER: (0x%llx) error sending "
12691ae08745Sheppo 			    "ACK/NACK\n", ldcp->id);
12703af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1271d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
12721ae08745Sheppo 			return (ECONNRESET);
12731ae08745Sheppo 		}
12741ae08745Sheppo 
12751ae08745Sheppo 		break;
12761ae08745Sheppo 
12771ae08745Sheppo 	case LDC_ACK:
12783af08d82Slm66018 		if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) {
12793af08d82Slm66018 			if (ldcp->version.major != rcvd_ver->major ||
12803af08d82Slm66018 			    ldcp->version.minor != rcvd_ver->minor) {
12813af08d82Slm66018 
12823af08d82Slm66018 				/* mismatched version - reset connection */
12833af08d82Slm66018 				DWARN(ldcp->id,
12843af08d82Slm66018 				    "i_ldc_process_VER: (0x%llx) recvd"
12853af08d82Slm66018 				    " ACK ver != sent ACK ver\n", ldcp->id);
12863af08d82Slm66018 				i_ldc_reset(ldcp, B_TRUE);
12873af08d82Slm66018 				mutex_exit(&ldcp->tx_lock);
12883af08d82Slm66018 				return (ECONNRESET);
12893af08d82Slm66018 			}
12903af08d82Slm66018 		} else {
12911ae08745Sheppo 			/* SUCCESS - we have agreed on a version */
12921ae08745Sheppo 			ldcp->version.major = rcvd_ver->major;
12931ae08745Sheppo 			ldcp->version.minor = rcvd_ver->minor;
12941ae08745Sheppo 			ldcp->tstate |= TS_VER_DONE;
12953af08d82Slm66018 		}
12961ae08745Sheppo 
1297cb112a14Slm66018 		D1(ldcp->id, "(0x%llx) Got ACK, Agreed on version v%u.%u\n",
12981ae08745Sheppo 		    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
12991ae08745Sheppo 
13001ae08745Sheppo 		/* initiate RTS-RTR-RDX handshake */
13011ae08745Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
13021ae08745Sheppo 		if (rv) {
13031ae08745Sheppo 			DWARN(ldcp->id,
13041ae08745Sheppo 		    "i_ldc_process_VER: (0x%llx) cannot send RTS\n",
13051ae08745Sheppo 			    ldcp->id);
13063af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1307d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
13081ae08745Sheppo 			return (ECONNRESET);
13091ae08745Sheppo 		}
13101ae08745Sheppo 
13111ae08745Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
13121ae08745Sheppo 		ZERO_PKT(pkt);
13131ae08745Sheppo 
13141ae08745Sheppo 		pkt->type = LDC_CTRL;
13151ae08745Sheppo 		pkt->stype = LDC_INFO;
13161ae08745Sheppo 		pkt->ctrl = LDC_RTS;
13171ae08745Sheppo 		pkt->env = ldcp->mode;
13181ae08745Sheppo 		if (ldcp->mode != LDC_MODE_RAW)
13191ae08745Sheppo 			pkt->seqid = LDC_INIT_SEQID;
13201ae08745Sheppo 
13211ae08745Sheppo 		ldcp->last_msg_rcd = LDC_INIT_SEQID;
13221ae08745Sheppo 
13231ae08745Sheppo 		DUMP_LDC_PKT(ldcp, "i_ldc_process_VER snd rts", (uint64_t)pkt);
13241ae08745Sheppo 
13251ae08745Sheppo 		/* initiate the send by calling into HV and set the new tail */
13261ae08745Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
13271ae08745Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
13281ae08745Sheppo 
13291ae08745Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
13301ae08745Sheppo 		if (rv) {
13311ae08745Sheppo 			D2(ldcp->id,
13321ae08745Sheppo 			    "i_ldc_process_VER: (0x%llx) no listener\n",
13331ae08745Sheppo 			    ldcp->id);
13343af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1335d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
13361ae08745Sheppo 			return (ECONNRESET);
13371ae08745Sheppo 		}
13381ae08745Sheppo 
13391ae08745Sheppo 		ldcp->tx_tail = tx_tail;
13401ae08745Sheppo 		ldcp->hstate |= TS_SENT_RTS;
13411ae08745Sheppo 
13421ae08745Sheppo 		break;
13431ae08745Sheppo 
13441ae08745Sheppo 	case LDC_NACK:
13451ae08745Sheppo 		/* check if version in NACK is zero */
13461ae08745Sheppo 		if (rcvd_ver->major == 0 && rcvd_ver->minor == 0) {
13471ae08745Sheppo 			/* version handshake failure */
13481ae08745Sheppo 			DWARN(DBG_ALL_LDCS,
13491ae08745Sheppo 			    "i_ldc_process_VER: (0x%llx) no version match\n",
13501ae08745Sheppo 			    ldcp->id);
13513af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1352d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
13531ae08745Sheppo 			return (ECONNRESET);
13541ae08745Sheppo 		}
13551ae08745Sheppo 
13561ae08745Sheppo 		/* get the current tail and pkt for the response */
13571ae08745Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
13581ae08745Sheppo 		if (rv != 0) {
13591ae08745Sheppo 			cmn_err(CE_NOTE,
13601ae08745Sheppo 			    "i_ldc_process_VER: (0x%lx) err sending "
13611ae08745Sheppo 			    "version ACK/NACK\n", ldcp->id);
13623af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1363d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
13641ae08745Sheppo 			return (ECONNRESET);
13651ae08745Sheppo 		}
13661ae08745Sheppo 
13671ae08745Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
13681ae08745Sheppo 		ZERO_PKT(pkt);
13691ae08745Sheppo 
13701ae08745Sheppo 		/* initialize the packet */
13711ae08745Sheppo 		pkt->type = LDC_CTRL;
13721ae08745Sheppo 		pkt->ctrl = LDC_VER;
13731ae08745Sheppo 		pkt->stype = LDC_INFO;
13741ae08745Sheppo 
13751ae08745Sheppo 		/* check ver in NACK msg has a match */
13761ae08745Sheppo 		for (;;) {
13771ae08745Sheppo 			if (rcvd_ver->major == ldc_versions[idx].major) {
13781ae08745Sheppo 				/*
13791ae08745Sheppo 				 * major version match - resubmit request
13801ae08745Sheppo 				 * if lower minor version to the one this endpt
13811ae08745Sheppo 				 * supports, if necessary
13821ae08745Sheppo 				 */
13831ae08745Sheppo 				if (rcvd_ver->minor > ldc_versions[idx].minor)
13841ae08745Sheppo 					rcvd_ver->minor =
13851ae08745Sheppo 					    ldc_versions[idx].minor;
13861ae08745Sheppo 				bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver));
13871ae08745Sheppo 				break;
13881ae08745Sheppo 			}
13891ae08745Sheppo 
13901ae08745Sheppo 			if (rcvd_ver->major > ldc_versions[idx].major) {
13911ae08745Sheppo 
13921ae08745Sheppo 				D1(ldcp->id, "i_ldc_process_VER: using next"
13931ae08745Sheppo 				    " lower idx=%d, v%u.%u\n", idx,
13941ae08745Sheppo 				    ldc_versions[idx].major,
13951ae08745Sheppo 				    ldc_versions[idx].minor);
13961ae08745Sheppo 
13971ae08745Sheppo 				/* send next lower version */
13981ae08745Sheppo 				bcopy(&ldc_versions[idx], pkt->udata,
13991ae08745Sheppo 				    sizeof (ldc_versions[idx]));
14001ae08745Sheppo 				ldcp->next_vidx = idx;
14011ae08745Sheppo 				break;
14021ae08745Sheppo 			}
14031ae08745Sheppo 
14041ae08745Sheppo 			/* next version */
14051ae08745Sheppo 			idx++;
14061ae08745Sheppo 
14071ae08745Sheppo 			D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx);
14081ae08745Sheppo 
14091ae08745Sheppo 			if (idx == LDC_NUM_VERS) {
14101ae08745Sheppo 				/* no version match - terminate */
14111ae08745Sheppo 				ldcp->next_vidx = 0;
1412d10e4ef2Snarayan 				mutex_exit(&ldcp->tx_lock);
14131ae08745Sheppo 				return (ECONNRESET);
14141ae08745Sheppo 			}
14151ae08745Sheppo 		}
14161ae08745Sheppo 
14171ae08745Sheppo 		/* initiate the send by calling into HV and set the new tail */
14181ae08745Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
14191ae08745Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
14201ae08745Sheppo 
14211ae08745Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
14221ae08745Sheppo 		if (rv == 0) {
14231ae08745Sheppo 			D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent version"
14241ae08745Sheppo 			    "INFO v%u.%u\n", ldcp->id, ldc_versions[idx].major,
14251ae08745Sheppo 			    ldc_versions[idx].minor);
14261ae08745Sheppo 			ldcp->tx_tail = tx_tail;
14271ae08745Sheppo 		} else {
14281ae08745Sheppo 			cmn_err(CE_NOTE,
14291ae08745Sheppo 			    "i_ldc_process_VER: (0x%lx) error sending version"
14301ae08745Sheppo 			    "INFO\n", ldcp->id);
14313af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1432d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
14331ae08745Sheppo 			return (ECONNRESET);
14341ae08745Sheppo 		}
14351ae08745Sheppo 
14361ae08745Sheppo 		break;
14371ae08745Sheppo 	}
14381ae08745Sheppo 
1439d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
14401ae08745Sheppo 	return (rv);
14411ae08745Sheppo }
14421ae08745Sheppo 
14431ae08745Sheppo 
14441ae08745Sheppo /*
14451ae08745Sheppo  * Process an incoming RTS ctrl message
14461ae08745Sheppo  */
14471ae08745Sheppo static int
14481ae08745Sheppo i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg)
14491ae08745Sheppo {
14501ae08745Sheppo 	int 		rv = 0;
14511ae08745Sheppo 	ldc_msg_t 	*pkt;
14521ae08745Sheppo 	uint64_t	tx_tail;
14531ae08745Sheppo 	boolean_t	sent_NACK = B_FALSE;
14541ae08745Sheppo 
14551ae08745Sheppo 	D2(ldcp->id, "i_ldc_process_RTS: (0x%llx) received RTS\n", ldcp->id);
14561ae08745Sheppo 
14571ae08745Sheppo 	switch (msg->stype) {
14581ae08745Sheppo 	case LDC_NACK:
14591ae08745Sheppo 		DWARN(ldcp->id,
14601ae08745Sheppo 		    "i_ldc_process_RTS: (0x%llx) RTS NACK received\n",
14611ae08745Sheppo 		    ldcp->id);
14621ae08745Sheppo 
14631ae08745Sheppo 		/* Reset the channel -- as we cannot continue */
1464d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
14653af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1466d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
14671ae08745Sheppo 		rv = ECONNRESET;
14681ae08745Sheppo 		break;
14691ae08745Sheppo 
14701ae08745Sheppo 	case LDC_INFO:
14711ae08745Sheppo 
14721ae08745Sheppo 		/* check mode */
14731ae08745Sheppo 		if (ldcp->mode != (ldc_mode_t)msg->env) {
14741ae08745Sheppo 			cmn_err(CE_NOTE,
14751ae08745Sheppo 			    "i_ldc_process_RTS: (0x%lx) mode mismatch\n",
14761ae08745Sheppo 			    ldcp->id);
14771ae08745Sheppo 			/*
14781ae08745Sheppo 			 * send NACK in response to MODE message
14791ae08745Sheppo 			 * get the current tail for the response
14801ae08745Sheppo 			 */
14811ae08745Sheppo 			rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTS);
14821ae08745Sheppo 			if (rv) {
14831ae08745Sheppo 				/* if cannot send NACK - reset channel */
1484d10e4ef2Snarayan 				mutex_enter(&ldcp->tx_lock);
14853af08d82Slm66018 				i_ldc_reset(ldcp, B_TRUE);
1486d10e4ef2Snarayan 				mutex_exit(&ldcp->tx_lock);
14871ae08745Sheppo 				rv = ECONNRESET;
14881ae08745Sheppo 				break;
14891ae08745Sheppo 			}
14901ae08745Sheppo 			sent_NACK = B_TRUE;
14911ae08745Sheppo 		}
14921ae08745Sheppo 		break;
14931ae08745Sheppo 	default:
14941ae08745Sheppo 		DWARN(ldcp->id, "i_ldc_process_RTS: (0x%llx) unexp ACK\n",
14951ae08745Sheppo 		    ldcp->id);
1496d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
14973af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1498d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
14991ae08745Sheppo 		rv = ECONNRESET;
15001ae08745Sheppo 		break;
15011ae08745Sheppo 	}
15021ae08745Sheppo 
15031ae08745Sheppo 	/*
15041ae08745Sheppo 	 * If either the connection was reset (when rv != 0) or
15051ae08745Sheppo 	 * a NACK was sent, we return. In the case of a NACK
15061ae08745Sheppo 	 * we dont want to consume the packet that came in but
15071ae08745Sheppo 	 * not record that we received the RTS
15081ae08745Sheppo 	 */
15091ae08745Sheppo 	if (rv || sent_NACK)
15101ae08745Sheppo 		return (rv);
15111ae08745Sheppo 
15121ae08745Sheppo 	/* record RTS received */
15131ae08745Sheppo 	ldcp->hstate |= TS_RCVD_RTS;
15141ae08745Sheppo 
15151ae08745Sheppo 	/* store initial SEQID info */
15161ae08745Sheppo 	ldcp->last_msg_snt = msg->seqid;
15171ae08745Sheppo 
1518d10e4ef2Snarayan 	/* Obtain Tx lock */
1519d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
1520d10e4ef2Snarayan 
15211ae08745Sheppo 	/* get the current tail for the response */
15221ae08745Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
15231ae08745Sheppo 	if (rv != 0) {
15241ae08745Sheppo 		cmn_err(CE_NOTE,
15251ae08745Sheppo 		    "i_ldc_process_RTS: (0x%lx) err sending RTR\n",
15261ae08745Sheppo 		    ldcp->id);
15273af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1528d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
15291ae08745Sheppo 		return (ECONNRESET);
15301ae08745Sheppo 	}
15311ae08745Sheppo 
15321ae08745Sheppo 	pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
15331ae08745Sheppo 	ZERO_PKT(pkt);
15341ae08745Sheppo 
15351ae08745Sheppo 	/* initialize the packet */
15361ae08745Sheppo 	pkt->type = LDC_CTRL;
15371ae08745Sheppo 	pkt->stype = LDC_INFO;
15381ae08745Sheppo 	pkt->ctrl = LDC_RTR;
15391ae08745Sheppo 	pkt->env = ldcp->mode;
15401ae08745Sheppo 	if (ldcp->mode != LDC_MODE_RAW)
15411ae08745Sheppo 		pkt->seqid = LDC_INIT_SEQID;
15421ae08745Sheppo 
15431ae08745Sheppo 	ldcp->last_msg_rcd = msg->seqid;
15441ae08745Sheppo 
15451ae08745Sheppo 	/* initiate the send by calling into HV and set the new tail */
15461ae08745Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
15471ae08745Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
15481ae08745Sheppo 
15491ae08745Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
15501ae08745Sheppo 	if (rv == 0) {
15511ae08745Sheppo 		D2(ldcp->id,
15521ae08745Sheppo 		    "i_ldc_process_RTS: (0x%llx) sent RTR\n", ldcp->id);
15531ae08745Sheppo 		DUMP_LDC_PKT(ldcp, "i_ldc_process_RTS sent rtr", (uint64_t)pkt);
15541ae08745Sheppo 
15551ae08745Sheppo 		ldcp->tx_tail = tx_tail;
15561ae08745Sheppo 		ldcp->hstate |= TS_SENT_RTR;
15571ae08745Sheppo 
15581ae08745Sheppo 	} else {
15591ae08745Sheppo 		cmn_err(CE_NOTE,
15601ae08745Sheppo 		    "i_ldc_process_RTS: (0x%lx) error sending RTR\n",
15611ae08745Sheppo 		    ldcp->id);
15623af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1563d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
15641ae08745Sheppo 		return (ECONNRESET);
15651ae08745Sheppo 	}
15661ae08745Sheppo 
1567d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
15681ae08745Sheppo 	return (0);
15691ae08745Sheppo }
15701ae08745Sheppo 
15711ae08745Sheppo /*
15721ae08745Sheppo  * Process an incoming RTR ctrl message
15731ae08745Sheppo  */
15741ae08745Sheppo static int
15751ae08745Sheppo i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg)
15761ae08745Sheppo {
15771ae08745Sheppo 	int 		rv = 0;
15781ae08745Sheppo 	boolean_t	sent_NACK = B_FALSE;
15791ae08745Sheppo 
15801ae08745Sheppo 	D2(ldcp->id, "i_ldc_process_RTR: (0x%llx) received RTR\n", ldcp->id);
15811ae08745Sheppo 
15821ae08745Sheppo 	switch (msg->stype) {
15831ae08745Sheppo 	case LDC_NACK:
15841ae08745Sheppo 		/* RTR NACK received */
15851ae08745Sheppo 		DWARN(ldcp->id,
15861ae08745Sheppo 		    "i_ldc_process_RTR: (0x%llx) RTR NACK received\n",
15871ae08745Sheppo 		    ldcp->id);
15881ae08745Sheppo 
15891ae08745Sheppo 		/* Reset the channel -- as we cannot continue */
1590d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
15913af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1592d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
15931ae08745Sheppo 		rv = ECONNRESET;
15941ae08745Sheppo 
15951ae08745Sheppo 		break;
15961ae08745Sheppo 
15971ae08745Sheppo 	case LDC_INFO:
15981ae08745Sheppo 
15991ae08745Sheppo 		/* check mode */
16001ae08745Sheppo 		if (ldcp->mode != (ldc_mode_t)msg->env) {
16011ae08745Sheppo 			DWARN(ldcp->id,
1602cb112a14Slm66018 			    "i_ldc_process_RTR: (0x%llx) mode mismatch, "
1603cb112a14Slm66018 			    "expecting 0x%x, got 0x%x\n",
1604cb112a14Slm66018 			    ldcp->id, ldcp->mode, (ldc_mode_t)msg->env);
16051ae08745Sheppo 			/*
16061ae08745Sheppo 			 * send NACK in response to MODE message
16071ae08745Sheppo 			 * get the current tail for the response
16081ae08745Sheppo 			 */
16091ae08745Sheppo 			rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTR);
16101ae08745Sheppo 			if (rv) {
16111ae08745Sheppo 				/* if cannot send NACK - reset channel */
1612d10e4ef2Snarayan 				mutex_enter(&ldcp->tx_lock);
16133af08d82Slm66018 				i_ldc_reset(ldcp, B_TRUE);
1614d10e4ef2Snarayan 				mutex_exit(&ldcp->tx_lock);
16151ae08745Sheppo 				rv = ECONNRESET;
16161ae08745Sheppo 				break;
16171ae08745Sheppo 			}
16181ae08745Sheppo 			sent_NACK = B_TRUE;
16191ae08745Sheppo 		}
16201ae08745Sheppo 		break;
16211ae08745Sheppo 
16221ae08745Sheppo 	default:
16231ae08745Sheppo 		DWARN(ldcp->id, "i_ldc_process_RTR: (0x%llx) unexp ACK\n",
16241ae08745Sheppo 		    ldcp->id);
16251ae08745Sheppo 
16261ae08745Sheppo 		/* Reset the channel -- as we cannot continue */
1627d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
16283af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1629d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
16301ae08745Sheppo 		rv = ECONNRESET;
16311ae08745Sheppo 		break;
16321ae08745Sheppo 	}
16331ae08745Sheppo 
16341ae08745Sheppo 	/*
16351ae08745Sheppo 	 * If either the connection was reset (when rv != 0) or
16361ae08745Sheppo 	 * a NACK was sent, we return. In the case of a NACK
16371ae08745Sheppo 	 * we dont want to consume the packet that came in but
16381ae08745Sheppo 	 * not record that we received the RTR
16391ae08745Sheppo 	 */
16401ae08745Sheppo 	if (rv || sent_NACK)
16411ae08745Sheppo 		return (rv);
16421ae08745Sheppo 
16431ae08745Sheppo 	ldcp->last_msg_snt = msg->seqid;
16441ae08745Sheppo 	ldcp->hstate |= TS_RCVD_RTR;
16451ae08745Sheppo 
16461ae08745Sheppo 	rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_INFO, LDC_RDX);
16471ae08745Sheppo 	if (rv) {
16481ae08745Sheppo 		cmn_err(CE_NOTE,
16491ae08745Sheppo 		    "i_ldc_process_RTR: (0x%lx) cannot send RDX\n",
16501ae08745Sheppo 		    ldcp->id);
1651d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
16523af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1653d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
16541ae08745Sheppo 		return (ECONNRESET);
16551ae08745Sheppo 	}
16561ae08745Sheppo 	D2(ldcp->id,
16571ae08745Sheppo 	    "i_ldc_process_RTR: (0x%llx) sent RDX\n", ldcp->id);
16581ae08745Sheppo 
16591ae08745Sheppo 	ldcp->hstate |= TS_SENT_RDX;
16601ae08745Sheppo 	ldcp->tstate |= TS_HSHAKE_DONE;
16613af08d82Slm66018 	if ((ldcp->tstate & TS_IN_RESET) == 0)
16621ae08745Sheppo 		ldcp->status = LDC_UP;
16631ae08745Sheppo 
1664cb112a14Slm66018 	D1(ldcp->id, "(0x%llx) Handshake Complete\n", ldcp->id);
16651ae08745Sheppo 
16661ae08745Sheppo 	return (0);
16671ae08745Sheppo }
16681ae08745Sheppo 
16691ae08745Sheppo 
16701ae08745Sheppo /*
16711ae08745Sheppo  * Process an incoming RDX ctrl message
16721ae08745Sheppo  */
16731ae08745Sheppo static int
16741ae08745Sheppo i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg)
16751ae08745Sheppo {
16761ae08745Sheppo 	int	rv = 0;
16771ae08745Sheppo 
16781ae08745Sheppo 	D2(ldcp->id, "i_ldc_process_RDX: (0x%llx) received RDX\n", ldcp->id);
16791ae08745Sheppo 
16801ae08745Sheppo 	switch (msg->stype) {
16811ae08745Sheppo 	case LDC_NACK:
16821ae08745Sheppo 		/* RDX NACK received */
16831ae08745Sheppo 		DWARN(ldcp->id,
16841ae08745Sheppo 		    "i_ldc_process_RDX: (0x%llx) RDX NACK received\n",
16851ae08745Sheppo 		    ldcp->id);
16861ae08745Sheppo 
16871ae08745Sheppo 		/* Reset the channel -- as we cannot continue */
1688d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
16893af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1690d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
16911ae08745Sheppo 		rv = ECONNRESET;
16921ae08745Sheppo 
16931ae08745Sheppo 		break;
16941ae08745Sheppo 
16951ae08745Sheppo 	case LDC_INFO:
16961ae08745Sheppo 
16971ae08745Sheppo 		/*
16981ae08745Sheppo 		 * if channel is UP and a RDX received after data transmission
16991ae08745Sheppo 		 * has commenced it is an error
17001ae08745Sheppo 		 */
17011ae08745Sheppo 		if ((ldcp->tstate == TS_UP) && (ldcp->hstate & TS_RCVD_RDX)) {
17021ae08745Sheppo 			DWARN(DBG_ALL_LDCS,
17031ae08745Sheppo 			    "i_ldc_process_RDX: (0x%llx) unexpected RDX"
17041ae08745Sheppo 			    " - LDC reset\n", ldcp->id);
1705d10e4ef2Snarayan 			mutex_enter(&ldcp->tx_lock);
17063af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1707d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
17081ae08745Sheppo 			return (ECONNRESET);
17091ae08745Sheppo 		}
17101ae08745Sheppo 
17111ae08745Sheppo 		ldcp->hstate |= TS_RCVD_RDX;
17121ae08745Sheppo 		ldcp->tstate |= TS_HSHAKE_DONE;
17133af08d82Slm66018 		if ((ldcp->tstate & TS_IN_RESET) == 0)
17141ae08745Sheppo 			ldcp->status = LDC_UP;
17151ae08745Sheppo 
17161ae08745Sheppo 		D1(DBG_ALL_LDCS, "(0x%llx) Handshake Complete\n", ldcp->id);
17171ae08745Sheppo 		break;
17181ae08745Sheppo 
17191ae08745Sheppo 	default:
17201ae08745Sheppo 		DWARN(ldcp->id, "i_ldc_process_RDX: (0x%llx) unexp ACK\n",
17211ae08745Sheppo 		    ldcp->id);
17221ae08745Sheppo 
17231ae08745Sheppo 		/* Reset the channel -- as we cannot continue */
1724d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
17253af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1726d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
17271ae08745Sheppo 		rv = ECONNRESET;
17281ae08745Sheppo 		break;
17291ae08745Sheppo 	}
17301ae08745Sheppo 
17311ae08745Sheppo 	return (rv);
17321ae08745Sheppo }
17331ae08745Sheppo 
17341ae08745Sheppo /*
17351ae08745Sheppo  * Process an incoming ACK for a data packet
17361ae08745Sheppo  */
17371ae08745Sheppo static int
17381ae08745Sheppo i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg)
17391ae08745Sheppo {
17401ae08745Sheppo 	int		rv;
17411ae08745Sheppo 	uint64_t 	tx_head;
17421ae08745Sheppo 	ldc_msg_t	*pkt;
17431ae08745Sheppo 
1744d10e4ef2Snarayan 	/* Obtain Tx lock */
1745d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
1746d10e4ef2Snarayan 
17471ae08745Sheppo 	/*
1748d10e4ef2Snarayan 	 * Read the current Tx head and tail
17491ae08745Sheppo 	 */
17501ae08745Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
17511ae08745Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
17521ae08745Sheppo 	if (rv != 0) {
17531ae08745Sheppo 		cmn_err(CE_WARN,
17541ae08745Sheppo 		    "i_ldc_process_data_ACK: (0x%lx) cannot read qptrs\n",
17551ae08745Sheppo 		    ldcp->id);
1756d10e4ef2Snarayan 
1757d10e4ef2Snarayan 		/* Reset the channel -- as we cannot continue */
17583af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1759d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
1760d10e4ef2Snarayan 		return (ECONNRESET);
17611ae08745Sheppo 	}
17621ae08745Sheppo 
17631ae08745Sheppo 	/*
17641ae08745Sheppo 	 * loop from where the previous ACK location was to the
17651ae08745Sheppo 	 * current head location. This is how far the HV has
17661ae08745Sheppo 	 * actually send pkts. Pkts between head and tail are
17671ae08745Sheppo 	 * yet to be sent by HV.
17681ae08745Sheppo 	 */
17691ae08745Sheppo 	tx_head = ldcp->tx_ackd_head;
17701ae08745Sheppo 	for (;;) {
17711ae08745Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_head);
17721ae08745Sheppo 		tx_head = (tx_head + LDC_PACKET_SIZE) %
17731ae08745Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
17741ae08745Sheppo 
17751ae08745Sheppo 		if (pkt->seqid == msg->ackid) {
17761ae08745Sheppo 			D2(ldcp->id,
17771ae08745Sheppo 			    "i_ldc_process_data_ACK: (0x%llx) found packet\n",
17781ae08745Sheppo 			    ldcp->id);
17791ae08745Sheppo 			ldcp->last_ack_rcd = msg->ackid;
17801ae08745Sheppo 			ldcp->tx_ackd_head = tx_head;
17811ae08745Sheppo 			break;
17821ae08745Sheppo 		}
17831ae08745Sheppo 		if (tx_head == ldcp->tx_head) {
17841ae08745Sheppo 			/* could not find packet */
17851ae08745Sheppo 			DWARN(ldcp->id,
17861ae08745Sheppo 			    "i_ldc_process_data_ACK: (0x%llx) invalid ACKid\n",
17871ae08745Sheppo 			    ldcp->id);
1788d10e4ef2Snarayan 
1789d10e4ef2Snarayan 			/* Reset the channel -- as we cannot continue */
17903af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1791d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
1792d10e4ef2Snarayan 			return (ECONNRESET);
17931ae08745Sheppo 		}
17941ae08745Sheppo 	}
17951ae08745Sheppo 
1796d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
17971ae08745Sheppo 	return (0);
17981ae08745Sheppo }
17991ae08745Sheppo 
18001ae08745Sheppo /*
18011ae08745Sheppo  * Process incoming control message
18021ae08745Sheppo  * Return 0 - session can continue
18031ae08745Sheppo  *        EAGAIN - reprocess packet - state was changed
18041ae08745Sheppo  *	  ECONNRESET - channel was reset
18051ae08745Sheppo  */
18061ae08745Sheppo static int
18071ae08745Sheppo i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *msg)
18081ae08745Sheppo {
18091ae08745Sheppo 	int 		rv = 0;
18101ae08745Sheppo 
18113af08d82Slm66018 	D1(ldcp->id, "i_ldc_ctrlmsg: (%llx) tstate = %lx, hstate = %lx\n",
18123af08d82Slm66018 	    ldcp->id, ldcp->tstate, ldcp->hstate);
18133af08d82Slm66018 
18143af08d82Slm66018 	switch (ldcp->tstate & ~TS_IN_RESET) {
18151ae08745Sheppo 
18161ae08745Sheppo 	case TS_OPEN:
18171ae08745Sheppo 	case TS_READY:
18181ae08745Sheppo 
18191ae08745Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
18201ae08745Sheppo 		case LDC_VER:
18211ae08745Sheppo 			/* process version message */
18221ae08745Sheppo 			rv = i_ldc_process_VER(ldcp, msg);
18231ae08745Sheppo 			break;
18241ae08745Sheppo 		default:
18251ae08745Sheppo 			DWARN(ldcp->id,
18261ae08745Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
18271ae08745Sheppo 			    "tstate=0x%x\n", ldcp->id,
18281ae08745Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
18291ae08745Sheppo 			break;
18301ae08745Sheppo 		}
18311ae08745Sheppo 
18321ae08745Sheppo 		break;
18331ae08745Sheppo 
18341ae08745Sheppo 	case TS_VREADY:
18351ae08745Sheppo 
18361ae08745Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
18371ae08745Sheppo 		case LDC_VER:
18383af08d82Slm66018 			/* process version message */
18393af08d82Slm66018 			rv = i_ldc_process_VER(ldcp, msg);
18401ae08745Sheppo 			break;
18411ae08745Sheppo 		case LDC_RTS:
18421ae08745Sheppo 			/* process RTS message */
18431ae08745Sheppo 			rv = i_ldc_process_RTS(ldcp, msg);
18441ae08745Sheppo 			break;
18451ae08745Sheppo 		case LDC_RTR:
18461ae08745Sheppo 			/* process RTR message */
18471ae08745Sheppo 			rv = i_ldc_process_RTR(ldcp, msg);
18481ae08745Sheppo 			break;
18491ae08745Sheppo 		case LDC_RDX:
18501ae08745Sheppo 			/* process RDX message */
18511ae08745Sheppo 			rv = i_ldc_process_RDX(ldcp, msg);
18521ae08745Sheppo 			break;
18531ae08745Sheppo 		default:
18541ae08745Sheppo 			DWARN(ldcp->id,
18551ae08745Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
18561ae08745Sheppo 			    "tstate=0x%x\n", ldcp->id,
18571ae08745Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
18581ae08745Sheppo 			break;
18591ae08745Sheppo 		}
18601ae08745Sheppo 
18611ae08745Sheppo 		break;
18621ae08745Sheppo 
18631ae08745Sheppo 	case TS_UP:
18641ae08745Sheppo 
18651ae08745Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
18661ae08745Sheppo 		case LDC_VER:
18671ae08745Sheppo 			DWARN(ldcp->id,
18681ae08745Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexpected VER "
18691ae08745Sheppo 			    "- LDC reset\n", ldcp->id);
18701ae08745Sheppo 			/* peer is redoing version negotiation */
1871d10e4ef2Snarayan 			mutex_enter(&ldcp->tx_lock);
18721ae08745Sheppo 			(void) i_ldc_txq_reconf(ldcp);
18731ae08745Sheppo 			i_ldc_reset_state(ldcp);
1874d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
18751ae08745Sheppo 			rv = EAGAIN;
18761ae08745Sheppo 			break;
18771ae08745Sheppo 
18781ae08745Sheppo 		case LDC_RDX:
18791ae08745Sheppo 			/* process RDX message */
18801ae08745Sheppo 			rv = i_ldc_process_RDX(ldcp, msg);
18811ae08745Sheppo 			break;
18821ae08745Sheppo 
18831ae08745Sheppo 		default:
18841ae08745Sheppo 			DWARN(ldcp->id,
18851ae08745Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
18861ae08745Sheppo 			    "tstate=0x%x\n", ldcp->id,
18871ae08745Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
18881ae08745Sheppo 			break;
18891ae08745Sheppo 		}
18901ae08745Sheppo 	}
18911ae08745Sheppo 
18921ae08745Sheppo 	return (rv);
18931ae08745Sheppo }
18941ae08745Sheppo 
18951ae08745Sheppo /*
18961ae08745Sheppo  * Register channel with the channel nexus
18971ae08745Sheppo  */
18981ae08745Sheppo static int
18991ae08745Sheppo i_ldc_register_channel(ldc_chan_t *ldcp)
19001ae08745Sheppo {
19011ae08745Sheppo 	int		rv = 0;
19021ae08745Sheppo 	ldc_cnex_t	*cinfo = &ldcssp->cinfo;
19031ae08745Sheppo 
19041ae08745Sheppo 	if (cinfo->dip == NULL) {
19051ae08745Sheppo 		DWARN(ldcp->id,
19061ae08745Sheppo 		    "i_ldc_register_channel: cnex has not registered\n");
19071ae08745Sheppo 		return (EAGAIN);
19081ae08745Sheppo 	}
19091ae08745Sheppo 
19101ae08745Sheppo 	rv = cinfo->reg_chan(cinfo->dip, ldcp->id, ldcp->devclass);
19111ae08745Sheppo 	if (rv) {
19121ae08745Sheppo 		DWARN(ldcp->id,
19131ae08745Sheppo 		    "i_ldc_register_channel: cannot register channel\n");
19141ae08745Sheppo 		return (rv);
19151ae08745Sheppo 	}
19161ae08745Sheppo 
19171ae08745Sheppo 	rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR,
19181ae08745Sheppo 	    i_ldc_tx_hdlr, ldcp, NULL);
19191ae08745Sheppo 	if (rv) {
19201ae08745Sheppo 		DWARN(ldcp->id,
19211ae08745Sheppo 		    "i_ldc_register_channel: cannot add Tx interrupt\n");
19221ae08745Sheppo 		(void) cinfo->unreg_chan(cinfo->dip, ldcp->id);
19231ae08745Sheppo 		return (rv);
19241ae08745Sheppo 	}
19251ae08745Sheppo 
19261ae08745Sheppo 	rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR,
19271ae08745Sheppo 	    i_ldc_rx_hdlr, ldcp, NULL);
19281ae08745Sheppo 	if (rv) {
19291ae08745Sheppo 		DWARN(ldcp->id,
19301ae08745Sheppo 		    "i_ldc_register_channel: cannot add Rx interrupt\n");
19311ae08745Sheppo 		(void) cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
19321ae08745Sheppo 		(void) cinfo->unreg_chan(cinfo->dip, ldcp->id);
19331ae08745Sheppo 		return (rv);
19341ae08745Sheppo 	}
19351ae08745Sheppo 
19361ae08745Sheppo 	ldcp->tstate |= TS_CNEX_RDY;
19371ae08745Sheppo 
19381ae08745Sheppo 	return (0);
19391ae08745Sheppo }
19401ae08745Sheppo 
19411ae08745Sheppo /*
19421ae08745Sheppo  * Unregister a channel with the channel nexus
19431ae08745Sheppo  */
19441ae08745Sheppo static int
19451ae08745Sheppo i_ldc_unregister_channel(ldc_chan_t *ldcp)
19461ae08745Sheppo {
19471ae08745Sheppo 	int		rv = 0;
19481ae08745Sheppo 	ldc_cnex_t	*cinfo = &ldcssp->cinfo;
19491ae08745Sheppo 
19501ae08745Sheppo 	if (cinfo->dip == NULL) {
19511ae08745Sheppo 		DWARN(ldcp->id,
19521ae08745Sheppo 		    "i_ldc_unregister_channel: cnex has not registered\n");
19531ae08745Sheppo 		return (EAGAIN);
19541ae08745Sheppo 	}
19551ae08745Sheppo 
19561ae08745Sheppo 	if (ldcp->tstate & TS_CNEX_RDY) {
19571ae08745Sheppo 
1958d10e4ef2Snarayan 		/* Remove the Rx interrupt */
19591ae08745Sheppo 		rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR);
19601ae08745Sheppo 		if (rv) {
19613af08d82Slm66018 			if (rv != EAGAIN) {
19621ae08745Sheppo 				DWARN(ldcp->id,
19633af08d82Slm66018 				    "i_ldc_unregister_channel: err removing "
19643af08d82Slm66018 				    "Rx intr\n");
1965d10e4ef2Snarayan 				return (rv);
19661ae08745Sheppo 			}
1967d10e4ef2Snarayan 
19683af08d82Slm66018 			/*
19693af08d82Slm66018 			 * If interrupts are pending and handler has
19703af08d82Slm66018 			 * finished running, clear interrupt and try
19713af08d82Slm66018 			 * again
19723af08d82Slm66018 			 */
19733af08d82Slm66018 			if (ldcp->rx_intr_state != LDC_INTR_PEND)
19743af08d82Slm66018 				return (rv);
19753af08d82Slm66018 
19763af08d82Slm66018 			(void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
19773af08d82Slm66018 			rv = cinfo->rem_intr(cinfo->dip, ldcp->id,
19783af08d82Slm66018 			    CNEX_RX_INTR);
19793af08d82Slm66018 			if (rv) {
19803af08d82Slm66018 				DWARN(ldcp->id, "i_ldc_unregister_channel: "
19813af08d82Slm66018 				    "err removing Rx interrupt\n");
19823af08d82Slm66018 				return (rv);
19833af08d82Slm66018 			}
19843af08d82Slm66018 		}
19853af08d82Slm66018 
1986d10e4ef2Snarayan 		/* Remove the Tx interrupt */
19871ae08745Sheppo 		rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
19881ae08745Sheppo 		if (rv) {
19891ae08745Sheppo 			DWARN(ldcp->id,
19901ae08745Sheppo 			    "i_ldc_unregister_channel: err removing Tx intr\n");
1991d10e4ef2Snarayan 			return (rv);
19921ae08745Sheppo 		}
1993d10e4ef2Snarayan 
1994d10e4ef2Snarayan 		/* Unregister the channel */
19951ae08745Sheppo 		rv = cinfo->unreg_chan(ldcssp->cinfo.dip, ldcp->id);
19961ae08745Sheppo 		if (rv) {
19971ae08745Sheppo 			DWARN(ldcp->id,
19981ae08745Sheppo 			    "i_ldc_unregister_channel: cannot unreg channel\n");
1999d10e4ef2Snarayan 			return (rv);
20001ae08745Sheppo 		}
20011ae08745Sheppo 
20021ae08745Sheppo 		ldcp->tstate &= ~TS_CNEX_RDY;
20031ae08745Sheppo 	}
20041ae08745Sheppo 
20051ae08745Sheppo 	return (0);
20061ae08745Sheppo }
20071ae08745Sheppo 
20081ae08745Sheppo 
20091ae08745Sheppo /*
20101ae08745Sheppo  * LDC transmit interrupt handler
20111ae08745Sheppo  *    triggered for chanel up/down/reset events
20121ae08745Sheppo  *    and Tx queue content changes
20131ae08745Sheppo  */
20141ae08745Sheppo static uint_t
20151ae08745Sheppo i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2)
20161ae08745Sheppo {
20171ae08745Sheppo 	_NOTE(ARGUNUSED(arg2))
20181ae08745Sheppo 
20191ae08745Sheppo 	int 		rv;
20201ae08745Sheppo 	ldc_chan_t 	*ldcp;
20211ae08745Sheppo 	boolean_t 	notify_client = B_FALSE;
20223af08d82Slm66018 	uint64_t	notify_event = 0, link_state;
20231ae08745Sheppo 
20241ae08745Sheppo 	/* Get the channel for which interrupt was received */
20251ae08745Sheppo 	ASSERT(arg1 != NULL);
20261ae08745Sheppo 	ldcp = (ldc_chan_t *)arg1;
20271ae08745Sheppo 
20281ae08745Sheppo 	D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
20291ae08745Sheppo 	    ldcp->id, ldcp);
20301ae08745Sheppo 
20311ae08745Sheppo 	/* Lock channel */
20321ae08745Sheppo 	mutex_enter(&ldcp->lock);
20331ae08745Sheppo 
2034d10e4ef2Snarayan 	/* Obtain Tx lock */
2035d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
2036d10e4ef2Snarayan 
20374bac2208Snarayan 	/* mark interrupt as pending */
20383af08d82Slm66018 	ldcp->tx_intr_state = LDC_INTR_ACTIVE;
20393af08d82Slm66018 
20403af08d82Slm66018 	/* save current link state */
20413af08d82Slm66018 	link_state = ldcp->link_state;
20424bac2208Snarayan 
20431ae08745Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id, &ldcp->tx_head, &ldcp->tx_tail,
20441ae08745Sheppo 	    &ldcp->link_state);
20451ae08745Sheppo 	if (rv) {
20461ae08745Sheppo 		cmn_err(CE_WARN,
20471ae08745Sheppo 		    "i_ldc_tx_hdlr: (0x%lx) cannot read queue ptrs rv=0x%d\n",
20481ae08745Sheppo 		    ldcp->id, rv);
20494bac2208Snarayan 		i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
2050d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
20511ae08745Sheppo 		mutex_exit(&ldcp->lock);
20521ae08745Sheppo 		return (DDI_INTR_CLAIMED);
20531ae08745Sheppo 	}
20541ae08745Sheppo 
20551ae08745Sheppo 	/*
20561ae08745Sheppo 	 * reset the channel state if the channel went down
20571ae08745Sheppo 	 * (other side unconfigured queue) or channel was reset
20581ae08745Sheppo 	 * (other side reconfigured its queue)
20591ae08745Sheppo 	 */
20603af08d82Slm66018 	if (link_state != ldcp->link_state &&
20613af08d82Slm66018 	    ldcp->link_state == LDC_CHANNEL_DOWN) {
20621ae08745Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link down\n", ldcp->id);
20633af08d82Slm66018 		i_ldc_reset(ldcp, B_FALSE);
20641ae08745Sheppo 		notify_client = B_TRUE;
20651ae08745Sheppo 		notify_event = LDC_EVT_DOWN;
20661ae08745Sheppo 	}
20671ae08745Sheppo 
20683af08d82Slm66018 	if (link_state != ldcp->link_state &&
20693af08d82Slm66018 	    ldcp->link_state == LDC_CHANNEL_RESET) {
20701ae08745Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link reset\n", ldcp->id);
20713af08d82Slm66018 		i_ldc_reset(ldcp, B_FALSE);
20721ae08745Sheppo 		notify_client = B_TRUE;
20731ae08745Sheppo 		notify_event = LDC_EVT_RESET;
20741ae08745Sheppo 	}
20751ae08745Sheppo 
20763af08d82Slm66018 	if (link_state != ldcp->link_state &&
20773af08d82Slm66018 	    (ldcp->tstate & ~TS_IN_RESET) == TS_OPEN &&
20783af08d82Slm66018 	    ldcp->link_state == LDC_CHANNEL_UP) {
20791ae08745Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link up\n", ldcp->id);
20801ae08745Sheppo 		notify_client = B_TRUE;
20811ae08745Sheppo 		notify_event = LDC_EVT_RESET;
20821ae08745Sheppo 		ldcp->tstate |= TS_LINK_READY;
20831ae08745Sheppo 		ldcp->status = LDC_READY;
20841ae08745Sheppo 	}
20851ae08745Sheppo 
20861ae08745Sheppo 	/* if callbacks are disabled, do not notify */
20871ae08745Sheppo 	if (!ldcp->cb_enabled)
20881ae08745Sheppo 		notify_client = B_FALSE;
20891ae08745Sheppo 
20904d39be2bSsg70180 	i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
209122f747efSnarayan 	mutex_exit(&ldcp->tx_lock);
20921ae08745Sheppo 
20931ae08745Sheppo 	if (notify_client) {
20943af08d82Slm66018 		ldcp->cb_inprogress = B_TRUE;
20953af08d82Slm66018 		mutex_exit(&ldcp->lock);
20961ae08745Sheppo 		rv = ldcp->cb(notify_event, ldcp->cb_arg);
20971ae08745Sheppo 		if (rv) {
20981ae08745Sheppo 			DWARN(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) callback "
20991ae08745Sheppo 			    "failure", ldcp->id);
21001ae08745Sheppo 		}
21011ae08745Sheppo 		mutex_enter(&ldcp->lock);
21021ae08745Sheppo 		ldcp->cb_inprogress = B_FALSE;
21031ae08745Sheppo 	}
21041ae08745Sheppo 
21051ae08745Sheppo 	mutex_exit(&ldcp->lock);
21061ae08745Sheppo 
21071ae08745Sheppo 	D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) exiting handler", ldcp->id);
21081ae08745Sheppo 
21091ae08745Sheppo 	return (DDI_INTR_CLAIMED);
21101ae08745Sheppo }
21111ae08745Sheppo 
21121ae08745Sheppo /*
211358283286Sha137994  * Process the Rx HV queue.
211458283286Sha137994  *
211558283286Sha137994  * Returns 0 if data packets were found and no errors were encountered,
211658283286Sha137994  * otherwise returns an error. In either case, the *notify argument is
211758283286Sha137994  * set to indicate whether or not the client callback function should
211858283286Sha137994  * be invoked. The *event argument is set to contain the callback event.
211958283286Sha137994  *
212058283286Sha137994  * Depending on the channel mode, packets are handled differently:
212158283286Sha137994  *
212258283286Sha137994  * RAW MODE
212358283286Sha137994  * For raw mode channels, when a data packet is encountered,
212458283286Sha137994  * processing stops and all packets are left on the queue to be removed
212558283286Sha137994  * and processed by the ldc_read code path.
212658283286Sha137994  *
212758283286Sha137994  * UNRELIABLE MODE
212858283286Sha137994  * For unreliable mode, when a data packet is encountered, processing
212958283286Sha137994  * stops, and all packets are left on the queue to be removed and
213058283286Sha137994  * processed by the ldc_read code path. Control packets are processed
213158283286Sha137994  * inline if they are encountered before any data packets.
213258283286Sha137994  *
213320ae46ebSha137994  * RELIABLE MODE
213420ae46ebSha137994  * For reliable mode channels, all packets on the receive queue
213558283286Sha137994  * are processed: data packets are copied to the data queue and
213658283286Sha137994  * control packets are processed inline. Packets are only left on
213758283286Sha137994  * the receive queue when the data queue is full.
21381ae08745Sheppo  */
21391ae08745Sheppo static uint_t
214058283286Sha137994 i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client,
214158283286Sha137994     uint64_t *notify_event)
21421ae08745Sheppo {
21431ae08745Sheppo 	int		rv;
21441ae08745Sheppo 	uint64_t 	rx_head, rx_tail;
21451ae08745Sheppo 	ldc_msg_t 	*msg;
21463af08d82Slm66018 	uint64_t	link_state, first_fragment = 0;
214758283286Sha137994 	boolean_t	trace_length = B_TRUE;
21483af08d82Slm66018 
214958283286Sha137994 	ASSERT(MUTEX_HELD(&ldcp->lock));
215058283286Sha137994 	*notify_client = B_FALSE;
215158283286Sha137994 	*notify_event = 0;
21521ae08745Sheppo 
21531ae08745Sheppo 	/*
21541ae08745Sheppo 	 * Read packet(s) from the queue
21551ae08745Sheppo 	 */
21561ae08745Sheppo 	for (;;) {
21571ae08745Sheppo 
21583af08d82Slm66018 		link_state = ldcp->link_state;
21591ae08745Sheppo 		rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
21601ae08745Sheppo 		    &ldcp->link_state);
21611ae08745Sheppo 		if (rv) {
21621ae08745Sheppo 			cmn_err(CE_WARN,
216358283286Sha137994 			    "i_ldc_rx_process_hvq: (0x%lx) cannot read "
21641ae08745Sheppo 			    "queue ptrs, rv=0x%d\n", ldcp->id, rv);
21651ae08745Sheppo 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
216658283286Sha137994 			return (EIO);
21671ae08745Sheppo 		}
21681ae08745Sheppo 
21691ae08745Sheppo 		/*
21701ae08745Sheppo 		 * reset the channel state if the channel went down
21711ae08745Sheppo 		 * (other side unconfigured queue) or channel was reset
21723af08d82Slm66018 		 * (other side reconfigured its queue)
21731ae08745Sheppo 		 */
21743af08d82Slm66018 
21753af08d82Slm66018 		if (link_state != ldcp->link_state) {
2176cb112a14Slm66018 
21773af08d82Slm66018 			switch (ldcp->link_state) {
21783af08d82Slm66018 			case LDC_CHANNEL_DOWN:
217958283286Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: channel "
21803af08d82Slm66018 				    "link down\n", ldcp->id);
2181d10e4ef2Snarayan 				mutex_enter(&ldcp->tx_lock);
21823af08d82Slm66018 				i_ldc_reset(ldcp, B_FALSE);
2183d10e4ef2Snarayan 				mutex_exit(&ldcp->tx_lock);
218458283286Sha137994 				*notify_client = B_TRUE;
218558283286Sha137994 				*notify_event = LDC_EVT_DOWN;
21863af08d82Slm66018 				goto loop_exit;
21871ae08745Sheppo 
21883af08d82Slm66018 			case LDC_CHANNEL_UP:
218958283286Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: "
21903af08d82Slm66018 				    "channel link up\n", ldcp->id);
21913af08d82Slm66018 
21923af08d82Slm66018 				if ((ldcp->tstate & ~TS_IN_RESET) == TS_OPEN) {
219358283286Sha137994 					*notify_client = B_TRUE;
219458283286Sha137994 					*notify_event = LDC_EVT_RESET;
21951ae08745Sheppo 					ldcp->tstate |= TS_LINK_READY;
21961ae08745Sheppo 					ldcp->status = LDC_READY;
21971ae08745Sheppo 				}
21983af08d82Slm66018 				break;
21993af08d82Slm66018 
22003af08d82Slm66018 			case LDC_CHANNEL_RESET:
22013af08d82Slm66018 			default:
22023af08d82Slm66018 #ifdef DEBUG
22033af08d82Slm66018 force_reset:
22043af08d82Slm66018 #endif
220558283286Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: channel "
22063af08d82Slm66018 				    "link reset\n", ldcp->id);
22073af08d82Slm66018 				mutex_enter(&ldcp->tx_lock);
22083af08d82Slm66018 				i_ldc_reset(ldcp, B_FALSE);
22093af08d82Slm66018 				mutex_exit(&ldcp->tx_lock);
221058283286Sha137994 				*notify_client = B_TRUE;
221158283286Sha137994 				*notify_event = LDC_EVT_RESET;
22123af08d82Slm66018 				break;
22133af08d82Slm66018 			}
22143af08d82Slm66018 		}
22153af08d82Slm66018 
22163af08d82Slm66018 #ifdef DEBUG
22173af08d82Slm66018 		if (LDC_INJECT_RESET(ldcp))
22183af08d82Slm66018 			goto force_reset;
2219*bbfa0259Sha137994 		if (LDC_INJECT_DRNGCLEAR(ldcp))
2220*bbfa0259Sha137994 			i_ldc_mem_inject_dring_clear(ldcp);
22213af08d82Slm66018 #endif
222258283286Sha137994 		if (trace_length) {
222358283286Sha137994 			TRACE_RXHVQ_LENGTH(ldcp, rx_head, rx_tail);
222458283286Sha137994 			trace_length = B_FALSE;
222558283286Sha137994 		}
22261ae08745Sheppo 
22271ae08745Sheppo 		if (rx_head == rx_tail) {
222858283286Sha137994 			D2(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) "
222958283286Sha137994 			    "No packets\n", ldcp->id);
22301ae08745Sheppo 			break;
22311ae08745Sheppo 		}
22323af08d82Slm66018 
223358283286Sha137994 		D2(ldcp->id, "i_ldc_rx_process_hvq: head=0x%llx, "
223458283286Sha137994 		    "tail=0x%llx\n", rx_head, rx_tail);
223558283286Sha137994 		DUMP_LDC_PKT(ldcp, "i_ldc_rx_process_hvq rcd",
22361ae08745Sheppo 		    ldcp->rx_q_va + rx_head);
22371ae08745Sheppo 
22381ae08745Sheppo 		/* get the message */
22391ae08745Sheppo 		msg = (ldc_msg_t *)(ldcp->rx_q_va + rx_head);
22401ae08745Sheppo 
22411ae08745Sheppo 		/* if channel is in RAW mode or data pkt, notify and return */
22421ae08745Sheppo 		if (ldcp->mode == LDC_MODE_RAW) {
224358283286Sha137994 			*notify_client = B_TRUE;
224458283286Sha137994 			*notify_event |= LDC_EVT_READ;
22451ae08745Sheppo 			break;
22461ae08745Sheppo 		}
22471ae08745Sheppo 
22481ae08745Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
22491ae08745Sheppo 
22501ae08745Sheppo 			/* discard packet if channel is not up */
22513af08d82Slm66018 			if ((ldcp->tstate & ~TS_IN_RESET) != TS_UP) {
22521ae08745Sheppo 
22531ae08745Sheppo 				/* move the head one position */
22541ae08745Sheppo 				rx_head = (rx_head + LDC_PACKET_SIZE) %
22551ae08745Sheppo 				    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
22561ae08745Sheppo 
22571ae08745Sheppo 				if (rv = i_ldc_set_rx_head(ldcp, rx_head))
22581ae08745Sheppo 					break;
22591ae08745Sheppo 
22601ae08745Sheppo 				continue;
22611ae08745Sheppo 			} else {
226258283286Sha137994 				uint64_t dq_head, dq_tail;
226358283286Sha137994 
226420ae46ebSha137994 				/* process only RELIABLE mode data packets */
226520ae46ebSha137994 				if (ldcp->mode != LDC_MODE_RELIABLE) {
22663af08d82Slm66018 					if ((ldcp->tstate & TS_IN_RESET) == 0)
226758283286Sha137994 						*notify_client = B_TRUE;
226858283286Sha137994 					*notify_event |= LDC_EVT_READ;
22691ae08745Sheppo 					break;
22701ae08745Sheppo 				}
227158283286Sha137994 
227258283286Sha137994 				/* don't process packet if queue full */
227358283286Sha137994 				(void) i_ldc_dq_rx_get_state(ldcp, &dq_head,
227458283286Sha137994 				    &dq_tail, NULL);
227558283286Sha137994 				dq_tail = (dq_tail + LDC_PACKET_SIZE) %
227658283286Sha137994 				    (ldcp->rx_dq_entries << LDC_PACKET_SHIFT);
227758283286Sha137994 				if (dq_tail == dq_head ||
227858283286Sha137994 				    LDC_INJECT_DQFULL(ldcp)) {
227958283286Sha137994 					rv = ENOSPC;
228058283286Sha137994 					break;
228158283286Sha137994 				}
228258283286Sha137994 			}
22831ae08745Sheppo 		}
22841ae08745Sheppo 
22851ae08745Sheppo 		/* Check the sequence ID for the message received */
22863af08d82Slm66018 		rv = i_ldc_check_seqid(ldcp, msg);
22873af08d82Slm66018 		if (rv != 0) {
22881ae08745Sheppo 
228958283286Sha137994 			DWARN(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) "
229058283286Sha137994 			    "seqid error, q_ptrs=0x%lx,0x%lx", ldcp->id,
229158283286Sha137994 			    rx_head, rx_tail);
22921ae08745Sheppo 
22931ae08745Sheppo 			/* Reset last_msg_rcd to start of message */
2294d10e4ef2Snarayan 			if (first_fragment != 0) {
2295d10e4ef2Snarayan 				ldcp->last_msg_rcd = first_fragment - 1;
2296d10e4ef2Snarayan 				first_fragment = 0;
22971ae08745Sheppo 			}
2298d10e4ef2Snarayan 
22991ae08745Sheppo 			/*
23001ae08745Sheppo 			 * Send a NACK due to seqid mismatch
23011ae08745Sheppo 			 */
230222f747efSnarayan 			rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK,
23031ae08745Sheppo 			    (msg->ctrl & LDC_CTRL_MASK));
23041ae08745Sheppo 
23051ae08745Sheppo 			if (rv) {
230658283286Sha137994 				cmn_err(CE_NOTE, "i_ldc_rx_process_hvq: "
230758283286Sha137994 				    "(0x%lx) err sending CTRL/DATA NACK msg\n",
230858283286Sha137994 				    ldcp->id);
2309d10e4ef2Snarayan 
2310d10e4ef2Snarayan 				/* if cannot send NACK - reset channel */
2311d10e4ef2Snarayan 				mutex_enter(&ldcp->tx_lock);
23123af08d82Slm66018 				i_ldc_reset(ldcp, B_TRUE);
2313d10e4ef2Snarayan 				mutex_exit(&ldcp->tx_lock);
231483d3bc6fSnarayan 
231558283286Sha137994 				*notify_client = B_TRUE;
231658283286Sha137994 				*notify_event = LDC_EVT_RESET;
2317d10e4ef2Snarayan 				break;
23181ae08745Sheppo 			}
23191ae08745Sheppo 
23201ae08745Sheppo 			/* purge receive queue */
23211ae08745Sheppo 			(void) i_ldc_set_rx_head(ldcp, rx_tail);
23221ae08745Sheppo 			break;
23231ae08745Sheppo 		}
23241ae08745Sheppo 
23251ae08745Sheppo 		/* record the message ID */
23261ae08745Sheppo 		ldcp->last_msg_rcd = msg->seqid;
23271ae08745Sheppo 
23281ae08745Sheppo 		/* process control messages */
23291ae08745Sheppo 		if (msg->type & LDC_CTRL) {
23301ae08745Sheppo 			/* save current internal state */
23311ae08745Sheppo 			uint64_t tstate = ldcp->tstate;
23321ae08745Sheppo 
23331ae08745Sheppo 			rv = i_ldc_ctrlmsg(ldcp, msg);
23341ae08745Sheppo 			if (rv == EAGAIN) {
23351ae08745Sheppo 				/* re-process pkt - state was adjusted */
23361ae08745Sheppo 				continue;
23371ae08745Sheppo 			}
23381ae08745Sheppo 			if (rv == ECONNRESET) {
233958283286Sha137994 				*notify_client = B_TRUE;
234058283286Sha137994 				*notify_event = LDC_EVT_RESET;
23411ae08745Sheppo 				break;
23421ae08745Sheppo 			}
23431ae08745Sheppo 
23441ae08745Sheppo 			/*
23451ae08745Sheppo 			 * control message processing was successful
23461ae08745Sheppo 			 * channel transitioned to ready for communication
23471ae08745Sheppo 			 */
23481ae08745Sheppo 			if (rv == 0 && ldcp->tstate == TS_UP &&
23493af08d82Slm66018 			    (tstate & ~TS_IN_RESET) !=
23503af08d82Slm66018 			    (ldcp->tstate & ~TS_IN_RESET)) {
235158283286Sha137994 				*notify_client = B_TRUE;
235258283286Sha137994 				*notify_event = LDC_EVT_UP;
23531ae08745Sheppo 			}
23541ae08745Sheppo 		}
23551ae08745Sheppo 
235683d3bc6fSnarayan 		/* process data NACKs */
235783d3bc6fSnarayan 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) {
235883d3bc6fSnarayan 			DWARN(ldcp->id,
235958283286Sha137994 			    "i_ldc_rx_process_hvq: (0x%llx) received DATA/NACK",
236083d3bc6fSnarayan 			    ldcp->id);
236183d3bc6fSnarayan 			mutex_enter(&ldcp->tx_lock);
236283d3bc6fSnarayan 			i_ldc_reset(ldcp, B_TRUE);
236383d3bc6fSnarayan 			mutex_exit(&ldcp->tx_lock);
236458283286Sha137994 			*notify_client = B_TRUE;
236558283286Sha137994 			*notify_event = LDC_EVT_RESET;
236683d3bc6fSnarayan 			break;
236783d3bc6fSnarayan 		}
236883d3bc6fSnarayan 
23691ae08745Sheppo 		/* process data ACKs */
23701ae08745Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
2371d10e4ef2Snarayan 			if (rv = i_ldc_process_data_ACK(ldcp, msg)) {
237258283286Sha137994 				*notify_client = B_TRUE;
237358283286Sha137994 				*notify_event = LDC_EVT_RESET;
2374d10e4ef2Snarayan 				break;
2375d10e4ef2Snarayan 			}
23761ae08745Sheppo 		}
23771ae08745Sheppo 
237858283286Sha137994 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
237920ae46ebSha137994 			ASSERT(ldcp->mode == LDC_MODE_RELIABLE);
238058283286Sha137994 
238158283286Sha137994 			/*
238258283286Sha137994 			 * Copy the data packet to the data queue. Note
238358283286Sha137994 			 * that the copy routine updates the rx_head pointer.
238458283286Sha137994 			 */
238558283286Sha137994 			i_ldc_rxdq_copy(ldcp, &rx_head);
238658283286Sha137994 
238758283286Sha137994 			if ((ldcp->tstate & TS_IN_RESET) == 0)
238858283286Sha137994 				*notify_client = B_TRUE;
238958283286Sha137994 			*notify_event |= LDC_EVT_READ;
239058283286Sha137994 		} else {
23911ae08745Sheppo 			rx_head = (rx_head + LDC_PACKET_SIZE) %
23921ae08745Sheppo 			    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
239358283286Sha137994 		}
239458283286Sha137994 
239558283286Sha137994 		/* move the head one position */
23960a55fbb7Slm66018 		if (rv = i_ldc_set_rx_head(ldcp, rx_head)) {
239758283286Sha137994 			*notify_client = B_TRUE;
239858283286Sha137994 			*notify_event = LDC_EVT_RESET;
23991ae08745Sheppo 			break;
24000a55fbb7Slm66018 		}
24011ae08745Sheppo 
24021ae08745Sheppo 	} /* for */
24031ae08745Sheppo 
24043af08d82Slm66018 loop_exit:
24053af08d82Slm66018 
240620ae46ebSha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
240758283286Sha137994 		/* ACK data packets */
240858283286Sha137994 		if ((*notify_event &
240958283286Sha137994 		    (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) {
241058283286Sha137994 			int ack_rv;
241158283286Sha137994 			ack_rv = i_ldc_send_pkt(ldcp, LDC_DATA, LDC_ACK, 0);
241258283286Sha137994 			if (ack_rv && ack_rv != EWOULDBLOCK) {
241358283286Sha137994 				cmn_err(CE_NOTE,
241458283286Sha137994 				    "i_ldc_rx_process_hvq: (0x%lx) cannot "
241558283286Sha137994 				    "send ACK\n", ldcp->id);
241658283286Sha137994 
241758283286Sha137994 				mutex_enter(&ldcp->tx_lock);
241858283286Sha137994 				i_ldc_reset(ldcp, B_FALSE);
241958283286Sha137994 				mutex_exit(&ldcp->tx_lock);
242058283286Sha137994 
242158283286Sha137994 				*notify_client = B_TRUE;
242258283286Sha137994 				*notify_event = LDC_EVT_RESET;
242358283286Sha137994 				goto skip_ackpeek;
242458283286Sha137994 			}
242558283286Sha137994 		}
24261ae08745Sheppo 
24273af08d82Slm66018 		/*
242858283286Sha137994 		 * If we have no more space on the data queue, make sure
242958283286Sha137994 		 * there are no ACKs on the rx queue waiting to be processed.
24303af08d82Slm66018 		 */
243158283286Sha137994 		if (rv == ENOSPC) {
243258283286Sha137994 			if (i_ldc_rx_ackpeek(ldcp, rx_head, rx_tail) != 0) {
243358283286Sha137994 				ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
243458283286Sha137994 				*notify_client = B_TRUE;
243558283286Sha137994 				*notify_event = LDC_EVT_RESET;
24361ae08745Sheppo 			}
243758283286Sha137994 		} else {
243858283286Sha137994 			ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
243958283286Sha137994 		}
24401ae08745Sheppo 	}
24411ae08745Sheppo 
244258283286Sha137994 skip_ackpeek:
24434d39be2bSsg70180 
244458283286Sha137994 	/* Return, indicating whether or not data packets were found */
244558283286Sha137994 	if ((*notify_event & (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ)
244658283286Sha137994 		return (0);
244758283286Sha137994 
244858283286Sha137994 	return (ENOMSG);
24491ae08745Sheppo }
24501ae08745Sheppo 
245158283286Sha137994 /*
245258283286Sha137994  * Process any ACK packets on the HV receive queue.
245358283286Sha137994  *
245420ae46ebSha137994  * This function is only used by RELIABLE mode channels when the
245558283286Sha137994  * secondary data queue fills up and there are packets remaining on
245658283286Sha137994  * the HV receive queue.
245758283286Sha137994  */
245858283286Sha137994 int
245958283286Sha137994 i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, uint64_t rx_tail)
246058283286Sha137994 {
246158283286Sha137994 	int		rv = 0;
246258283286Sha137994 	ldc_msg_t	*msg;
246358283286Sha137994 
246458283286Sha137994 	if (ldcp->rx_ack_head == ACKPEEK_HEAD_INVALID)
246558283286Sha137994 		ldcp->rx_ack_head = rx_head;
246658283286Sha137994 
246758283286Sha137994 	while (ldcp->rx_ack_head != rx_tail) {
246858283286Sha137994 		msg = (ldc_msg_t *)(ldcp->rx_q_va + ldcp->rx_ack_head);
246958283286Sha137994 
247058283286Sha137994 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
247158283286Sha137994 			if (rv = i_ldc_process_data_ACK(ldcp, msg))
247258283286Sha137994 				break;
247358283286Sha137994 			msg->stype &= ~LDC_ACK;
247458283286Sha137994 		}
247558283286Sha137994 
247658283286Sha137994 		ldcp->rx_ack_head =
247758283286Sha137994 		    (ldcp->rx_ack_head + LDC_PACKET_SIZE) %
247858283286Sha137994 		    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
247958283286Sha137994 	}
248058283286Sha137994 	return (rv);
248158283286Sha137994 }
24821ae08745Sheppo 
24831ae08745Sheppo /* -------------------------------------------------------------------------- */
24841ae08745Sheppo 
24851ae08745Sheppo /*
24861ae08745Sheppo  * LDC API functions
24871ae08745Sheppo  */
24881ae08745Sheppo 
24891ae08745Sheppo /*
24901ae08745Sheppo  * Initialize the channel. Allocate internal structure and memory for
24911ae08745Sheppo  * TX/RX queues, and initialize locks.
24921ae08745Sheppo  */
24931ae08745Sheppo int
24941ae08745Sheppo ldc_init(uint64_t id, ldc_attr_t *attr, ldc_handle_t *handle)
24951ae08745Sheppo {
24961ae08745Sheppo 	ldc_chan_t 	*ldcp;
24971ae08745Sheppo 	int		rv, exit_val;
24981ae08745Sheppo 	uint64_t	ra_base, nentries;
2499e1ebb9ecSlm66018 	uint64_t	qlen;
25001ae08745Sheppo 
25011ae08745Sheppo 	exit_val = EINVAL;	/* guarantee an error if exit on failure */
25021ae08745Sheppo 
25031ae08745Sheppo 	if (attr == NULL) {
25041ae08745Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid attr\n", id);
25051ae08745Sheppo 		return (EINVAL);
25061ae08745Sheppo 	}
25071ae08745Sheppo 	if (handle == NULL) {
25081ae08745Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid handle\n", id);
25091ae08745Sheppo 		return (EINVAL);
25101ae08745Sheppo 	}
25111ae08745Sheppo 
25121ae08745Sheppo 	/* check if channel is valid */
25131ae08745Sheppo 	rv = hv_ldc_tx_qinfo(id, &ra_base, &nentries);
25141ae08745Sheppo 	if (rv == H_ECHANNEL) {
25151ae08745Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid channel id\n", id);
25161ae08745Sheppo 		return (EINVAL);
25171ae08745Sheppo 	}
25181ae08745Sheppo 
25191ae08745Sheppo 	/* check if the channel has already been initialized */
25201ae08745Sheppo 	mutex_enter(&ldcssp->lock);
25211ae08745Sheppo 	ldcp = ldcssp->chan_list;
25221ae08745Sheppo 	while (ldcp != NULL) {
25231ae08745Sheppo 		if (ldcp->id == id) {
25241ae08745Sheppo 			DWARN(id, "ldc_init: (0x%llx) already initialized\n",
25251ae08745Sheppo 			    id);
25261ae08745Sheppo 			mutex_exit(&ldcssp->lock);
25271ae08745Sheppo 			return (EADDRINUSE);
25281ae08745Sheppo 		}
25291ae08745Sheppo 		ldcp = ldcp->next;
25301ae08745Sheppo 	}
25311ae08745Sheppo 	mutex_exit(&ldcssp->lock);
25321ae08745Sheppo 
25331ae08745Sheppo 	ASSERT(ldcp == NULL);
25341ae08745Sheppo 
25351ae08745Sheppo 	*handle = 0;
25361ae08745Sheppo 
25371ae08745Sheppo 	/* Allocate an ldcp structure */
25381ae08745Sheppo 	ldcp = kmem_zalloc(sizeof (ldc_chan_t), KM_SLEEP);
25391ae08745Sheppo 
2540d10e4ef2Snarayan 	/*
2541d10e4ef2Snarayan 	 * Initialize the channel and Tx lock
2542d10e4ef2Snarayan 	 *
2543d10e4ef2Snarayan 	 * The channel 'lock' protects the entire channel and
2544d10e4ef2Snarayan 	 * should be acquired before initializing, resetting,
2545d10e4ef2Snarayan 	 * destroying or reading from a channel.
2546d10e4ef2Snarayan 	 *
2547d10e4ef2Snarayan 	 * The 'tx_lock' should be acquired prior to transmitting
2548d10e4ef2Snarayan 	 * data over the channel. The lock should also be acquired
2549d10e4ef2Snarayan 	 * prior to channel reconfiguration (in order to prevent
2550d10e4ef2Snarayan 	 * concurrent writes).
2551d10e4ef2Snarayan 	 *
2552d10e4ef2Snarayan 	 * ORDERING: When both locks are being acquired, to prevent
2553d10e4ef2Snarayan 	 * deadlocks, the channel lock should be always acquired prior
2554d10e4ef2Snarayan 	 * to the tx_lock.
2555d10e4ef2Snarayan 	 */
25561ae08745Sheppo 	mutex_init(&ldcp->lock, NULL, MUTEX_DRIVER, NULL);
2557d10e4ef2Snarayan 	mutex_init(&ldcp->tx_lock, NULL, MUTEX_DRIVER, NULL);
25581ae08745Sheppo 
25591ae08745Sheppo 	/* Initialize the channel */
25601ae08745Sheppo 	ldcp->id = id;
25611ae08745Sheppo 	ldcp->cb = NULL;
25621ae08745Sheppo 	ldcp->cb_arg = NULL;
25631ae08745Sheppo 	ldcp->cb_inprogress = B_FALSE;
25641ae08745Sheppo 	ldcp->cb_enabled = B_FALSE;
25651ae08745Sheppo 	ldcp->next = NULL;
25661ae08745Sheppo 
25671ae08745Sheppo 	/* Read attributes */
25681ae08745Sheppo 	ldcp->mode = attr->mode;
25691ae08745Sheppo 	ldcp->devclass = attr->devclass;
25701ae08745Sheppo 	ldcp->devinst = attr->instance;
2571e1ebb9ecSlm66018 	ldcp->mtu = (attr->mtu > 0) ? attr->mtu : LDC_DEFAULT_MTU;
25721ae08745Sheppo 
25731ae08745Sheppo 	D1(ldcp->id,
25741ae08745Sheppo 	    "ldc_init: (0x%llx) channel attributes, class=0x%x, "
2575e1ebb9ecSlm66018 	    "instance=0x%llx, mode=%d, mtu=%d\n",
2576e1ebb9ecSlm66018 	    ldcp->id, ldcp->devclass, ldcp->devinst, ldcp->mode, ldcp->mtu);
25771ae08745Sheppo 
25781ae08745Sheppo 	ldcp->next_vidx = 0;
25793af08d82Slm66018 	ldcp->tstate = TS_IN_RESET;
25801ae08745Sheppo 	ldcp->hstate = 0;
25811ae08745Sheppo 	ldcp->last_msg_snt = LDC_INIT_SEQID;
25821ae08745Sheppo 	ldcp->last_ack_rcd = 0;
25831ae08745Sheppo 	ldcp->last_msg_rcd = 0;
258458283286Sha137994 	ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
25851ae08745Sheppo 
25861ae08745Sheppo 	ldcp->stream_bufferp = NULL;
25871ae08745Sheppo 	ldcp->exp_dring_list = NULL;
25881ae08745Sheppo 	ldcp->imp_dring_list = NULL;
25891ae08745Sheppo 	ldcp->mhdl_list = NULL;
25901ae08745Sheppo 
25913af08d82Slm66018 	ldcp->tx_intr_state = LDC_INTR_NONE;
25923af08d82Slm66018 	ldcp->rx_intr_state = LDC_INTR_NONE;
25933af08d82Slm66018 
25941ae08745Sheppo 	/* Initialize payload size depending on whether channel is reliable */
25951ae08745Sheppo 	switch (ldcp->mode) {
25961ae08745Sheppo 	case LDC_MODE_RAW:
25971ae08745Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RAW;
25981ae08745Sheppo 		ldcp->read_p = i_ldc_read_raw;
25991ae08745Sheppo 		ldcp->write_p = i_ldc_write_raw;
26001ae08745Sheppo 		break;
26011ae08745Sheppo 	case LDC_MODE_UNRELIABLE:
26021ae08745Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_UNRELIABLE;
26031ae08745Sheppo 		ldcp->read_p = i_ldc_read_packet;
26041ae08745Sheppo 		ldcp->write_p = i_ldc_write_packet;
26051ae08745Sheppo 		break;
26061ae08745Sheppo 	case LDC_MODE_RELIABLE:
26071ae08745Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE;
26081ae08745Sheppo 
26091ae08745Sheppo 		ldcp->stream_remains = 0;
26101ae08745Sheppo 		ldcp->stream_offset = 0;
26111ae08745Sheppo 		ldcp->stream_bufferp = kmem_alloc(ldcp->mtu, KM_SLEEP);
26121ae08745Sheppo 		ldcp->read_p = i_ldc_read_stream;
26131ae08745Sheppo 		ldcp->write_p = i_ldc_write_stream;
26141ae08745Sheppo 		break;
26151ae08745Sheppo 	default:
26161ae08745Sheppo 		exit_val = EINVAL;
26171ae08745Sheppo 		goto cleanup_on_exit;
26181ae08745Sheppo 	}
26191ae08745Sheppo 
2620e1ebb9ecSlm66018 	/*
2621e1ebb9ecSlm66018 	 * qlen is (mtu * ldc_mtu_msgs) / pkt_payload. If this
2622e1ebb9ecSlm66018 	 * value is smaller than default length of ldc_queue_entries,
262322f747efSnarayan 	 * qlen is set to ldc_queue_entries. Ensure that computed
262422f747efSnarayan 	 * length is a power-of-two value.
2625e1ebb9ecSlm66018 	 */
2626e1ebb9ecSlm66018 	qlen = (ldcp->mtu * ldc_mtu_msgs) / ldcp->pkt_payload;
262722f747efSnarayan 	if (!ISP2(qlen)) {
262822f747efSnarayan 		uint64_t	tmp = 1;
262922f747efSnarayan 		while (qlen) {
263022f747efSnarayan 			qlen >>= 1; tmp <<= 1;
263122f747efSnarayan 		}
263222f747efSnarayan 		qlen = tmp;
263322f747efSnarayan 	}
263422f747efSnarayan 
2635e1ebb9ecSlm66018 	ldcp->rx_q_entries =
2636e1ebb9ecSlm66018 	    (qlen < ldc_queue_entries) ? ldc_queue_entries : qlen;
2637e1ebb9ecSlm66018 	ldcp->tx_q_entries = ldcp->rx_q_entries;
2638e1ebb9ecSlm66018 
263922f747efSnarayan 	D1(ldcp->id, "ldc_init: queue length = 0x%llx\n", ldcp->rx_q_entries);
2640e1ebb9ecSlm66018 
26411ae08745Sheppo 	/* Create a transmit queue */
26421ae08745Sheppo 	ldcp->tx_q_va = (uint64_t)
26431ae08745Sheppo 	    contig_mem_alloc(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
26441ae08745Sheppo 	if (ldcp->tx_q_va == NULL) {
26451ae08745Sheppo 		cmn_err(CE_WARN,
26461ae08745Sheppo 		    "ldc_init: (0x%lx) TX queue allocation failed\n",
26471ae08745Sheppo 		    ldcp->id);
26481ae08745Sheppo 		exit_val = ENOMEM;
26491ae08745Sheppo 		goto cleanup_on_exit;
26501ae08745Sheppo 	}
26511ae08745Sheppo 	ldcp->tx_q_ra = va_to_pa((caddr_t)ldcp->tx_q_va);
26521ae08745Sheppo 
26531ae08745Sheppo 	D2(ldcp->id, "ldc_init: txq_va=0x%llx, txq_ra=0x%llx, entries=0x%llx\n",
26541ae08745Sheppo 	    ldcp->tx_q_va, ldcp->tx_q_ra, ldcp->tx_q_entries);
26551ae08745Sheppo 
26561ae08745Sheppo 	ldcp->tstate |= TS_TXQ_RDY;
26571ae08745Sheppo 
26581ae08745Sheppo 	/* Create a receive queue */
26591ae08745Sheppo 	ldcp->rx_q_va = (uint64_t)
26601ae08745Sheppo 	    contig_mem_alloc(ldcp->rx_q_entries << LDC_PACKET_SHIFT);
26611ae08745Sheppo 	if (ldcp->rx_q_va == NULL) {
26621ae08745Sheppo 		cmn_err(CE_WARN,
26631ae08745Sheppo 		    "ldc_init: (0x%lx) RX queue allocation failed\n",
26641ae08745Sheppo 		    ldcp->id);
26651ae08745Sheppo 		exit_val = ENOMEM;
26661ae08745Sheppo 		goto cleanup_on_exit;
26671ae08745Sheppo 	}
26681ae08745Sheppo 	ldcp->rx_q_ra = va_to_pa((caddr_t)ldcp->rx_q_va);
26691ae08745Sheppo 
26701ae08745Sheppo 	D2(ldcp->id, "ldc_init: rxq_va=0x%llx, rxq_ra=0x%llx, entries=0x%llx\n",
26711ae08745Sheppo 	    ldcp->rx_q_va, ldcp->rx_q_ra, ldcp->rx_q_entries);
26721ae08745Sheppo 
26731ae08745Sheppo 	ldcp->tstate |= TS_RXQ_RDY;
26741ae08745Sheppo 
267558283286Sha137994 	/* Setup a separate read data queue */
267620ae46ebSha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
267758283286Sha137994 		ldcp->readq_get_state = i_ldc_dq_rx_get_state;
267858283286Sha137994 		ldcp->readq_set_head  = i_ldc_set_rxdq_head;
267958283286Sha137994 
268058283286Sha137994 		/* Make sure the data queue multiplier is a power of 2 */
268158283286Sha137994 		if (!ISP2(ldc_rxdq_multiplier)) {
268258283286Sha137994 			D1(ldcp->id, "ldc_init: (0x%llx) ldc_rxdq_multiplier "
268358283286Sha137994 			    "not a power of 2, resetting", ldcp->id);
268458283286Sha137994 			ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER;
268558283286Sha137994 		}
268658283286Sha137994 
268758283286Sha137994 		ldcp->rx_dq_entries = ldc_rxdq_multiplier * ldcp->rx_q_entries;
268858283286Sha137994 		ldcp->rx_dq_va = (uint64_t)
268958283286Sha137994 		    kmem_alloc(ldcp->rx_dq_entries << LDC_PACKET_SHIFT,
269058283286Sha137994 		    KM_SLEEP);
269158283286Sha137994 		if (ldcp->rx_dq_va == NULL) {
269258283286Sha137994 			cmn_err(CE_WARN,
269358283286Sha137994 			    "ldc_init: (0x%lx) RX data queue "
269458283286Sha137994 			    "allocation failed\n", ldcp->id);
269558283286Sha137994 			exit_val = ENOMEM;
269658283286Sha137994 			goto cleanup_on_exit;
269758283286Sha137994 		}
269858283286Sha137994 
269958283286Sha137994 		ldcp->rx_dq_head = ldcp->rx_dq_tail = 0;
270058283286Sha137994 
270158283286Sha137994 		D2(ldcp->id, "ldc_init: rx_dq_va=0x%llx, "
270258283286Sha137994 		    "rx_dq_entries=0x%llx\n", ldcp->rx_dq_va,
270358283286Sha137994 		    ldcp->rx_dq_entries);
270458283286Sha137994 	} else {
270558283286Sha137994 		ldcp->readq_get_state = i_ldc_hvq_rx_get_state;
270658283286Sha137994 		ldcp->readq_set_head  = i_ldc_set_rx_head;
270758283286Sha137994 	}
270858283286Sha137994 
27091ae08745Sheppo 	/* Init descriptor ring and memory handle list lock */
27101ae08745Sheppo 	mutex_init(&ldcp->exp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
27111ae08745Sheppo 	mutex_init(&ldcp->imp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
27121ae08745Sheppo 	mutex_init(&ldcp->mlist_lock, NULL, MUTEX_DRIVER, NULL);
27131ae08745Sheppo 
27141ae08745Sheppo 	/* mark status as INITialized */
27151ae08745Sheppo 	ldcp->status = LDC_INIT;
27161ae08745Sheppo 
27171ae08745Sheppo 	/* Add to channel list */
27181ae08745Sheppo 	mutex_enter(&ldcssp->lock);
27191ae08745Sheppo 	ldcp->next = ldcssp->chan_list;
27201ae08745Sheppo 	ldcssp->chan_list = ldcp;
27211ae08745Sheppo 	ldcssp->channel_count++;
27221ae08745Sheppo 	mutex_exit(&ldcssp->lock);
27231ae08745Sheppo 
27241ae08745Sheppo 	/* set the handle */
27251ae08745Sheppo 	*handle = (ldc_handle_t)ldcp;
27261ae08745Sheppo 
27271ae08745Sheppo 	D1(ldcp->id, "ldc_init: (0x%llx) channel initialized\n", ldcp->id);
27281ae08745Sheppo 
27291ae08745Sheppo 	return (0);
27301ae08745Sheppo 
27311ae08745Sheppo cleanup_on_exit:
27321ae08745Sheppo 
273320ae46ebSha137994 	if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp)
27341ae08745Sheppo 		kmem_free(ldcp->stream_bufferp, ldcp->mtu);
27351ae08745Sheppo 
27361ae08745Sheppo 	if (ldcp->tstate & TS_TXQ_RDY)
27371ae08745Sheppo 		contig_mem_free((caddr_t)ldcp->tx_q_va,
27381ae08745Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
27391ae08745Sheppo 
27401ae08745Sheppo 	if (ldcp->tstate & TS_RXQ_RDY)
27411ae08745Sheppo 		contig_mem_free((caddr_t)ldcp->rx_q_va,
27421ae08745Sheppo 		    (ldcp->rx_q_entries << LDC_PACKET_SHIFT));
27431ae08745Sheppo 
2744d10e4ef2Snarayan 	mutex_destroy(&ldcp->tx_lock);
27451ae08745Sheppo 	mutex_destroy(&ldcp->lock);
27461ae08745Sheppo 
27471ae08745Sheppo 	if (ldcp)
27481ae08745Sheppo 		kmem_free(ldcp, sizeof (ldc_chan_t));
27491ae08745Sheppo 
27501ae08745Sheppo 	return (exit_val);
27511ae08745Sheppo }
27521ae08745Sheppo 
27531ae08745Sheppo /*
27541ae08745Sheppo  * Finalizes the LDC connection. It will return EBUSY if the
27551ae08745Sheppo  * channel is open. A ldc_close() has to be done prior to
27561ae08745Sheppo  * a ldc_fini operation. It frees TX/RX queues, associated
27571ae08745Sheppo  * with the channel
27581ae08745Sheppo  */
27591ae08745Sheppo int
27601ae08745Sheppo ldc_fini(ldc_handle_t handle)
27611ae08745Sheppo {
27621ae08745Sheppo 	ldc_chan_t 	*ldcp;
27631ae08745Sheppo 	ldc_chan_t 	*tmp_ldcp;
27641ae08745Sheppo 	uint64_t 	id;
27651ae08745Sheppo 
27661ae08745Sheppo 	if (handle == NULL) {
27671ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel handle\n");
27681ae08745Sheppo 		return (EINVAL);
27691ae08745Sheppo 	}
27701ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
27711ae08745Sheppo 	id = ldcp->id;
27721ae08745Sheppo 
27731ae08745Sheppo 	mutex_enter(&ldcp->lock);
27741ae08745Sheppo 
27753af08d82Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) > TS_INIT) {
27761ae08745Sheppo 		DWARN(ldcp->id, "ldc_fini: (0x%llx) channel is open\n",
27771ae08745Sheppo 		    ldcp->id);
27781ae08745Sheppo 		mutex_exit(&ldcp->lock);
27791ae08745Sheppo 		return (EBUSY);
27801ae08745Sheppo 	}
27811ae08745Sheppo 
27821ae08745Sheppo 	/* Remove from the channel list */
27831ae08745Sheppo 	mutex_enter(&ldcssp->lock);
27841ae08745Sheppo 	tmp_ldcp = ldcssp->chan_list;
27851ae08745Sheppo 	if (tmp_ldcp == ldcp) {
27861ae08745Sheppo 		ldcssp->chan_list = ldcp->next;
27871ae08745Sheppo 		ldcp->next = NULL;
27881ae08745Sheppo 	} else {
27891ae08745Sheppo 		while (tmp_ldcp != NULL) {
27901ae08745Sheppo 			if (tmp_ldcp->next == ldcp) {
27911ae08745Sheppo 				tmp_ldcp->next = ldcp->next;
27921ae08745Sheppo 				ldcp->next = NULL;
27931ae08745Sheppo 				break;
27941ae08745Sheppo 			}
27951ae08745Sheppo 			tmp_ldcp = tmp_ldcp->next;
27961ae08745Sheppo 		}
27971ae08745Sheppo 		if (tmp_ldcp == NULL) {
27981ae08745Sheppo 			DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel hdl\n");
27991ae08745Sheppo 			mutex_exit(&ldcssp->lock);
28001ae08745Sheppo 			mutex_exit(&ldcp->lock);
28011ae08745Sheppo 			return (EINVAL);
28021ae08745Sheppo 		}
28031ae08745Sheppo 	}
28041ae08745Sheppo 
28051ae08745Sheppo 	ldcssp->channel_count--;
28061ae08745Sheppo 
28071ae08745Sheppo 	mutex_exit(&ldcssp->lock);
28081ae08745Sheppo 
28091ae08745Sheppo 	/* Free the map table for this channel */
28101ae08745Sheppo 	if (ldcp->mtbl) {
28111ae08745Sheppo 		(void) hv_ldc_set_map_table(ldcp->id, NULL, NULL);
28123af08d82Slm66018 		if (ldcp->mtbl->contigmem)
28131ae08745Sheppo 			contig_mem_free(ldcp->mtbl->table, ldcp->mtbl->size);
28143af08d82Slm66018 		else
28153af08d82Slm66018 			kmem_free(ldcp->mtbl->table, ldcp->mtbl->size);
28161ae08745Sheppo 		mutex_destroy(&ldcp->mtbl->lock);
28171ae08745Sheppo 		kmem_free(ldcp->mtbl, sizeof (ldc_mtbl_t));
28181ae08745Sheppo 	}
28191ae08745Sheppo 
28201ae08745Sheppo 	/* Destroy descriptor ring and memory handle list lock */
28211ae08745Sheppo 	mutex_destroy(&ldcp->exp_dlist_lock);
28221ae08745Sheppo 	mutex_destroy(&ldcp->imp_dlist_lock);
28231ae08745Sheppo 	mutex_destroy(&ldcp->mlist_lock);
28241ae08745Sheppo 
282520ae46ebSha137994 	/* Free the stream buffer for RELIABLE_MODE */
282620ae46ebSha137994 	if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp)
28271ae08745Sheppo 		kmem_free(ldcp->stream_bufferp, ldcp->mtu);
28281ae08745Sheppo 
28291ae08745Sheppo 	/* Free the RX queue */
28301ae08745Sheppo 	contig_mem_free((caddr_t)ldcp->rx_q_va,
28311ae08745Sheppo 	    (ldcp->rx_q_entries << LDC_PACKET_SHIFT));
28321ae08745Sheppo 	ldcp->tstate &= ~TS_RXQ_RDY;
28331ae08745Sheppo 
283458283286Sha137994 	/* Free the RX data queue */
283520ae46ebSha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
283658283286Sha137994 		kmem_free((caddr_t)ldcp->rx_dq_va,
283758283286Sha137994 		    (ldcp->rx_dq_entries << LDC_PACKET_SHIFT));
283858283286Sha137994 	}
283958283286Sha137994 
28401ae08745Sheppo 	/* Free the TX queue */
28411ae08745Sheppo 	contig_mem_free((caddr_t)ldcp->tx_q_va,
28421ae08745Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
28431ae08745Sheppo 	ldcp->tstate &= ~TS_TXQ_RDY;
28441ae08745Sheppo 
28451ae08745Sheppo 	mutex_exit(&ldcp->lock);
28461ae08745Sheppo 
28471ae08745Sheppo 	/* Destroy mutex */
2848d10e4ef2Snarayan 	mutex_destroy(&ldcp->tx_lock);
28491ae08745Sheppo 	mutex_destroy(&ldcp->lock);
28501ae08745Sheppo 
28511ae08745Sheppo 	/* free channel structure */
28521ae08745Sheppo 	kmem_free(ldcp, sizeof (ldc_chan_t));
28531ae08745Sheppo 
28541ae08745Sheppo 	D1(id, "ldc_fini: (0x%llx) channel finalized\n", id);
28551ae08745Sheppo 
28561ae08745Sheppo 	return (0);
28571ae08745Sheppo }
28581ae08745Sheppo 
28591ae08745Sheppo /*
28601ae08745Sheppo  * Open the LDC channel for use. It registers the TX/RX queues
28611ae08745Sheppo  * with the Hypervisor. It also specifies the interrupt number
28621ae08745Sheppo  * and target CPU for this channel
28631ae08745Sheppo  */
28641ae08745Sheppo int
28651ae08745Sheppo ldc_open(ldc_handle_t handle)
28661ae08745Sheppo {
28671ae08745Sheppo 	ldc_chan_t 	*ldcp;
28681ae08745Sheppo 	int 		rv;
28691ae08745Sheppo 
28701ae08745Sheppo 	if (handle == NULL) {
28711ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_open: invalid channel handle\n");
28721ae08745Sheppo 		return (EINVAL);
28731ae08745Sheppo 	}
28741ae08745Sheppo 
28751ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
28761ae08745Sheppo 
28771ae08745Sheppo 	mutex_enter(&ldcp->lock);
28781ae08745Sheppo 
28791ae08745Sheppo 	if (ldcp->tstate < TS_INIT) {
28801ae08745Sheppo 		DWARN(ldcp->id,
28811ae08745Sheppo 		    "ldc_open: (0x%llx) channel not initialized\n", ldcp->id);
28821ae08745Sheppo 		mutex_exit(&ldcp->lock);
28831ae08745Sheppo 		return (EFAULT);
28841ae08745Sheppo 	}
28853af08d82Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) >= TS_OPEN) {
28861ae08745Sheppo 		DWARN(ldcp->id,
28871ae08745Sheppo 		    "ldc_open: (0x%llx) channel is already open\n", ldcp->id);
28881ae08745Sheppo 		mutex_exit(&ldcp->lock);
28891ae08745Sheppo 		return (EFAULT);
28901ae08745Sheppo 	}
28911ae08745Sheppo 
28921ae08745Sheppo 	/*
28931ae08745Sheppo 	 * Unregister/Register the tx queue with the hypervisor
28941ae08745Sheppo 	 */
28951ae08745Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
28961ae08745Sheppo 	if (rv) {
28971ae08745Sheppo 		cmn_err(CE_WARN,
28981ae08745Sheppo 		    "ldc_open: (0x%lx) channel tx queue unconf failed\n",
28991ae08745Sheppo 		    ldcp->id);
29001ae08745Sheppo 		mutex_exit(&ldcp->lock);
29011ae08745Sheppo 		return (EIO);
29021ae08745Sheppo 	}
29031ae08745Sheppo 
29041ae08745Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
29051ae08745Sheppo 	if (rv) {
29061ae08745Sheppo 		cmn_err(CE_WARN,
29071ae08745Sheppo 		    "ldc_open: (0x%lx) channel tx queue conf failed\n",
29081ae08745Sheppo 		    ldcp->id);
29091ae08745Sheppo 		mutex_exit(&ldcp->lock);
29101ae08745Sheppo 		return (EIO);
29111ae08745Sheppo 	}
29121ae08745Sheppo 
29131ae08745Sheppo 	D2(ldcp->id, "ldc_open: (0x%llx) registered tx queue with LDC\n",
29141ae08745Sheppo 	    ldcp->id);
29151ae08745Sheppo 
29161ae08745Sheppo 	/*
29171ae08745Sheppo 	 * Unregister/Register the rx queue with the hypervisor
29181ae08745Sheppo 	 */
29191ae08745Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
29201ae08745Sheppo 	if (rv) {
29211ae08745Sheppo 		cmn_err(CE_WARN,
29221ae08745Sheppo 		    "ldc_open: (0x%lx) channel rx queue unconf failed\n",
29231ae08745Sheppo 		    ldcp->id);
29241ae08745Sheppo 		mutex_exit(&ldcp->lock);
29251ae08745Sheppo 		return (EIO);
29261ae08745Sheppo 	}
29271ae08745Sheppo 
29281ae08745Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, ldcp->rx_q_entries);
29291ae08745Sheppo 	if (rv) {
29301ae08745Sheppo 		cmn_err(CE_WARN,
29311ae08745Sheppo 		    "ldc_open: (0x%lx) channel rx queue conf failed\n",
29321ae08745Sheppo 		    ldcp->id);
29331ae08745Sheppo 		mutex_exit(&ldcp->lock);
29341ae08745Sheppo 		return (EIO);
29351ae08745Sheppo 	}
29361ae08745Sheppo 
29371ae08745Sheppo 	D2(ldcp->id, "ldc_open: (0x%llx) registered rx queue with LDC\n",
29381ae08745Sheppo 	    ldcp->id);
29391ae08745Sheppo 
29401ae08745Sheppo 	ldcp->tstate |= TS_QCONF_RDY;
29411ae08745Sheppo 
29421ae08745Sheppo 	/* Register the channel with the channel nexus */
29431ae08745Sheppo 	rv = i_ldc_register_channel(ldcp);
29441ae08745Sheppo 	if (rv && rv != EAGAIN) {
29451ae08745Sheppo 		cmn_err(CE_WARN,
29461ae08745Sheppo 		    "ldc_open: (0x%lx) channel register failed\n", ldcp->id);
29471ae08745Sheppo 		(void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
29481ae08745Sheppo 		(void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
29491ae08745Sheppo 		mutex_exit(&ldcp->lock);
29501ae08745Sheppo 		return (EIO);
29511ae08745Sheppo 	}
29521ae08745Sheppo 
29531ae08745Sheppo 	/* mark channel in OPEN state */
29541ae08745Sheppo 	ldcp->status = LDC_OPEN;
29551ae08745Sheppo 
29561ae08745Sheppo 	/* Read channel state */
29571ae08745Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
29581ae08745Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
29591ae08745Sheppo 	if (rv) {
29601ae08745Sheppo 		cmn_err(CE_WARN,
29611ae08745Sheppo 		    "ldc_open: (0x%lx) cannot read channel state\n",
29621ae08745Sheppo 		    ldcp->id);
29631ae08745Sheppo 		(void) i_ldc_unregister_channel(ldcp);
29641ae08745Sheppo 		(void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
29651ae08745Sheppo 		(void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
29661ae08745Sheppo 		mutex_exit(&ldcp->lock);
29671ae08745Sheppo 		return (EIO);
29681ae08745Sheppo 	}
29691ae08745Sheppo 
29701ae08745Sheppo 	/*
297120ae46ebSha137994 	 * set the ACKd head to current head location for reliable
29721ae08745Sheppo 	 */
29731ae08745Sheppo 	ldcp->tx_ackd_head = ldcp->tx_head;
29741ae08745Sheppo 
29751ae08745Sheppo 	/* mark channel ready if HV report link is UP (peer alloc'd Rx queue) */
29761ae08745Sheppo 	if (ldcp->link_state == LDC_CHANNEL_UP ||
29771ae08745Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
29781ae08745Sheppo 		ldcp->tstate |= TS_LINK_READY;
29791ae08745Sheppo 		ldcp->status = LDC_READY;
29801ae08745Sheppo 	}
29811ae08745Sheppo 
29821ae08745Sheppo 	/*
29831ae08745Sheppo 	 * if channel is being opened in RAW mode - no handshake is needed
29841ae08745Sheppo 	 * switch the channel READY and UP state
29851ae08745Sheppo 	 */
29861ae08745Sheppo 	if (ldcp->mode == LDC_MODE_RAW) {
29871ae08745Sheppo 		ldcp->tstate = TS_UP;	/* set bits associated with LDC UP */
29881ae08745Sheppo 		ldcp->status = LDC_UP;
29891ae08745Sheppo 	}
29901ae08745Sheppo 
29911ae08745Sheppo 	mutex_exit(&ldcp->lock);
29921ae08745Sheppo 
29931ae08745Sheppo 	/*
29941ae08745Sheppo 	 * Increment number of open channels
29951ae08745Sheppo 	 */
29961ae08745Sheppo 	mutex_enter(&ldcssp->lock);
29971ae08745Sheppo 	ldcssp->channels_open++;
29981ae08745Sheppo 	mutex_exit(&ldcssp->lock);
29991ae08745Sheppo 
3000cb112a14Slm66018 	D1(ldcp->id,
30013af08d82Slm66018 	    "ldc_open: (0x%llx) channel (0x%p) open for use "
30023af08d82Slm66018 	    "(tstate=0x%x, status=0x%x)\n",
30033af08d82Slm66018 	    ldcp->id, ldcp, ldcp->tstate, ldcp->status);
30041ae08745Sheppo 
30051ae08745Sheppo 	return (0);
30061ae08745Sheppo }
30071ae08745Sheppo 
30081ae08745Sheppo /*
30091ae08745Sheppo  * Close the LDC connection. It will return EBUSY if there
30101ae08745Sheppo  * are memory segments or descriptor rings either bound to or
30111ae08745Sheppo  * mapped over the channel
30121ae08745Sheppo  */
30131ae08745Sheppo int
30141ae08745Sheppo ldc_close(ldc_handle_t handle)
30151ae08745Sheppo {
30161ae08745Sheppo 	ldc_chan_t 	*ldcp;
3017d10e4ef2Snarayan 	int		rv = 0, retries = 0;
30181ae08745Sheppo 	boolean_t	chk_done = B_FALSE;
30191ae08745Sheppo 
30201ae08745Sheppo 	if (handle == NULL) {
30211ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_close: invalid channel handle\n");
30221ae08745Sheppo 		return (EINVAL);
30231ae08745Sheppo 	}
30241ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
30251ae08745Sheppo 
30261ae08745Sheppo 	mutex_enter(&ldcp->lock);
30271ae08745Sheppo 
30281ae08745Sheppo 	/* return error if channel is not open */
30293af08d82Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) < TS_OPEN) {
30301ae08745Sheppo 		DWARN(ldcp->id,
30311ae08745Sheppo 		    "ldc_close: (0x%llx) channel is not open\n", ldcp->id);
30321ae08745Sheppo 		mutex_exit(&ldcp->lock);
30331ae08745Sheppo 		return (EFAULT);
30341ae08745Sheppo 	}
30351ae08745Sheppo 
30361ae08745Sheppo 	/* if any memory handles, drings, are bound or mapped cannot close */
30371ae08745Sheppo 	if (ldcp->mhdl_list != NULL) {
30381ae08745Sheppo 		DWARN(ldcp->id,
30391ae08745Sheppo 		    "ldc_close: (0x%llx) channel has bound memory handles\n",
30401ae08745Sheppo 		    ldcp->id);
30411ae08745Sheppo 		mutex_exit(&ldcp->lock);
30421ae08745Sheppo 		return (EBUSY);
30431ae08745Sheppo 	}
30441ae08745Sheppo 	if (ldcp->exp_dring_list != NULL) {
30451ae08745Sheppo 		DWARN(ldcp->id,
30461ae08745Sheppo 		    "ldc_close: (0x%llx) channel has bound descriptor rings\n",
30471ae08745Sheppo 		    ldcp->id);
30481ae08745Sheppo 		mutex_exit(&ldcp->lock);
30491ae08745Sheppo 		return (EBUSY);
30501ae08745Sheppo 	}
30511ae08745Sheppo 	if (ldcp->imp_dring_list != NULL) {
30521ae08745Sheppo 		DWARN(ldcp->id,
30531ae08745Sheppo 		    "ldc_close: (0x%llx) channel has mapped descriptor rings\n",
30541ae08745Sheppo 		    ldcp->id);
30551ae08745Sheppo 		mutex_exit(&ldcp->lock);
30561ae08745Sheppo 		return (EBUSY);
30571ae08745Sheppo 	}
30581ae08745Sheppo 
30594d39be2bSsg70180 	if (ldcp->cb_inprogress) {
30604d39be2bSsg70180 		DWARN(ldcp->id, "ldc_close: (0x%llx) callback active\n",
30614d39be2bSsg70180 		    ldcp->id);
30624d39be2bSsg70180 		mutex_exit(&ldcp->lock);
30634d39be2bSsg70180 		return (EWOULDBLOCK);
30644d39be2bSsg70180 	}
30654d39be2bSsg70180 
3066d10e4ef2Snarayan 	/* Obtain Tx lock */
3067d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
3068d10e4ef2Snarayan 
30691ae08745Sheppo 	/*
30701ae08745Sheppo 	 * Wait for pending transmits to complete i.e Tx queue to drain
30711ae08745Sheppo 	 * if there are pending pkts - wait 1 ms and retry again
30721ae08745Sheppo 	 */
30731ae08745Sheppo 	for (;;) {
30741ae08745Sheppo 
30751ae08745Sheppo 		rv = hv_ldc_tx_get_state(ldcp->id,
30761ae08745Sheppo 		    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
30771ae08745Sheppo 		if (rv) {
30781ae08745Sheppo 			cmn_err(CE_WARN,
30791ae08745Sheppo 			    "ldc_close: (0x%lx) cannot read qptrs\n", ldcp->id);
3080d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
30811ae08745Sheppo 			mutex_exit(&ldcp->lock);
30821ae08745Sheppo 			return (EIO);
30831ae08745Sheppo 		}
30841ae08745Sheppo 
30851ae08745Sheppo 		if (ldcp->tx_head == ldcp->tx_tail ||
30861ae08745Sheppo 		    ldcp->link_state != LDC_CHANNEL_UP) {
30871ae08745Sheppo 			break;
30881ae08745Sheppo 		}
30891ae08745Sheppo 
30901ae08745Sheppo 		if (chk_done) {
30911ae08745Sheppo 			DWARN(ldcp->id,
30921ae08745Sheppo 			    "ldc_close: (0x%llx) Tx queue drain timeout\n",
30931ae08745Sheppo 			    ldcp->id);
30941ae08745Sheppo 			break;
30951ae08745Sheppo 		}
30961ae08745Sheppo 
30971ae08745Sheppo 		/* wait for one ms and try again */
30981ae08745Sheppo 		delay(drv_usectohz(1000));
30991ae08745Sheppo 		chk_done = B_TRUE;
31001ae08745Sheppo 	}
31011ae08745Sheppo 
31021ae08745Sheppo 	/*
3103a8ea4edeSnarayan 	 * Drain the Tx and Rx queues as we are closing the
3104a8ea4edeSnarayan 	 * channel. We dont care about any pending packets.
3105a8ea4edeSnarayan 	 * We have to also drain the queue prior to clearing
3106a8ea4edeSnarayan 	 * pending interrupts, otherwise the HV will trigger
3107a8ea4edeSnarayan 	 * an interrupt the moment the interrupt state is
3108a8ea4edeSnarayan 	 * cleared.
31093af08d82Slm66018 	 */
31103af08d82Slm66018 	(void) i_ldc_txq_reconf(ldcp);
3111a8ea4edeSnarayan 	(void) i_ldc_rxq_drain(ldcp);
31123af08d82Slm66018 
31133af08d82Slm66018 	/*
31141ae08745Sheppo 	 * Unregister the channel with the nexus
31151ae08745Sheppo 	 */
3116d10e4ef2Snarayan 	while ((rv = i_ldc_unregister_channel(ldcp)) != 0) {
3117d10e4ef2Snarayan 
3118d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
31191ae08745Sheppo 		mutex_exit(&ldcp->lock);
3120d10e4ef2Snarayan 
3121d10e4ef2Snarayan 		/* if any error other than EAGAIN return back */
3122a8ea4edeSnarayan 		if (rv != EAGAIN || retries >= ldc_max_retries) {
3123d10e4ef2Snarayan 			cmn_err(CE_WARN,
3124d10e4ef2Snarayan 			    "ldc_close: (0x%lx) unregister failed, %d\n",
3125d10e4ef2Snarayan 			    ldcp->id, rv);
31261ae08745Sheppo 			return (rv);
31271ae08745Sheppo 		}
31281ae08745Sheppo 
31291ae08745Sheppo 		/*
3130d10e4ef2Snarayan 		 * As there could be pending interrupts we need
3131d10e4ef2Snarayan 		 * to wait and try again
3132d10e4ef2Snarayan 		 */
31334d39be2bSsg70180 		drv_usecwait(ldc_close_delay);
3134d10e4ef2Snarayan 		mutex_enter(&ldcp->lock);
3135d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
3136d10e4ef2Snarayan 		retries++;
3137d10e4ef2Snarayan 	}
3138d10e4ef2Snarayan 
3139d10e4ef2Snarayan 	/*
31401ae08745Sheppo 	 * Unregister queues
31411ae08745Sheppo 	 */
31421ae08745Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
31431ae08745Sheppo 	if (rv) {
31441ae08745Sheppo 		cmn_err(CE_WARN,
31451ae08745Sheppo 		    "ldc_close: (0x%lx) channel TX queue unconf failed\n",
31461ae08745Sheppo 		    ldcp->id);
3147d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
31481ae08745Sheppo 		mutex_exit(&ldcp->lock);
31491ae08745Sheppo 		return (EIO);
31501ae08745Sheppo 	}
31511ae08745Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
31521ae08745Sheppo 	if (rv) {
31531ae08745Sheppo 		cmn_err(CE_WARN,
31541ae08745Sheppo 		    "ldc_close: (0x%lx) channel RX queue unconf failed\n",
31551ae08745Sheppo 		    ldcp->id);
3156d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
31571ae08745Sheppo 		mutex_exit(&ldcp->lock);
31581ae08745Sheppo 		return (EIO);
31591ae08745Sheppo 	}
31601ae08745Sheppo 
31611ae08745Sheppo 	ldcp->tstate &= ~TS_QCONF_RDY;
31621ae08745Sheppo 
31631ae08745Sheppo 	/* Reset channel state information */
31641ae08745Sheppo 	i_ldc_reset_state(ldcp);
31651ae08745Sheppo 
31661ae08745Sheppo 	/* Mark channel as down and in initialized state */
31671ae08745Sheppo 	ldcp->tx_ackd_head = 0;
31681ae08745Sheppo 	ldcp->tx_head = 0;
31693af08d82Slm66018 	ldcp->tstate = TS_IN_RESET|TS_INIT;
31701ae08745Sheppo 	ldcp->status = LDC_INIT;
31711ae08745Sheppo 
3172d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
31731ae08745Sheppo 	mutex_exit(&ldcp->lock);
31741ae08745Sheppo 
31751ae08745Sheppo 	/* Decrement number of open channels */
31761ae08745Sheppo 	mutex_enter(&ldcssp->lock);
31771ae08745Sheppo 	ldcssp->channels_open--;
31781ae08745Sheppo 	mutex_exit(&ldcssp->lock);
31791ae08745Sheppo 
31801ae08745Sheppo 	D1(ldcp->id, "ldc_close: (0x%llx) channel closed\n", ldcp->id);
31811ae08745Sheppo 
31821ae08745Sheppo 	return (0);
31831ae08745Sheppo }
31841ae08745Sheppo 
31851ae08745Sheppo /*
31861ae08745Sheppo  * Register channel callback
31871ae08745Sheppo  */
31881ae08745Sheppo int
31891ae08745Sheppo ldc_reg_callback(ldc_handle_t handle,
31901ae08745Sheppo     uint_t(*cb)(uint64_t event, caddr_t arg), caddr_t arg)
31911ae08745Sheppo {
31921ae08745Sheppo 	ldc_chan_t *ldcp;
31931ae08745Sheppo 
31941ae08745Sheppo 	if (handle == NULL) {
31951ae08745Sheppo 		DWARN(DBG_ALL_LDCS,
31961ae08745Sheppo 		    "ldc_reg_callback: invalid channel handle\n");
31971ae08745Sheppo 		return (EINVAL);
31981ae08745Sheppo 	}
31991ae08745Sheppo 	if (((uint64_t)cb) < KERNELBASE) {
32001ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_reg_callback: invalid callback\n");
32011ae08745Sheppo 		return (EINVAL);
32021ae08745Sheppo 	}
32031ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
32041ae08745Sheppo 
32051ae08745Sheppo 	mutex_enter(&ldcp->lock);
32061ae08745Sheppo 
32071ae08745Sheppo 	if (ldcp->cb) {
32081ae08745Sheppo 		DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback exists\n",
32091ae08745Sheppo 		    ldcp->id);
32101ae08745Sheppo 		mutex_exit(&ldcp->lock);
32111ae08745Sheppo 		return (EIO);
32121ae08745Sheppo 	}
32131ae08745Sheppo 	if (ldcp->cb_inprogress) {
32141ae08745Sheppo 		DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback active\n",
32151ae08745Sheppo 		    ldcp->id);
32161ae08745Sheppo 		mutex_exit(&ldcp->lock);
32171ae08745Sheppo 		return (EWOULDBLOCK);
32181ae08745Sheppo 	}
32191ae08745Sheppo 
32201ae08745Sheppo 	ldcp->cb = cb;
32211ae08745Sheppo 	ldcp->cb_arg = arg;
32221ae08745Sheppo 	ldcp->cb_enabled = B_TRUE;
32231ae08745Sheppo 
32241ae08745Sheppo 	D1(ldcp->id,
32251ae08745Sheppo 	    "ldc_reg_callback: (0x%llx) registered callback for channel\n",
32261ae08745Sheppo 	    ldcp->id);
32271ae08745Sheppo 
32281ae08745Sheppo 	mutex_exit(&ldcp->lock);
32291ae08745Sheppo 
32301ae08745Sheppo 	return (0);
32311ae08745Sheppo }
32321ae08745Sheppo 
32331ae08745Sheppo /*
32341ae08745Sheppo  * Unregister channel callback
32351ae08745Sheppo  */
32361ae08745Sheppo int
32371ae08745Sheppo ldc_unreg_callback(ldc_handle_t handle)
32381ae08745Sheppo {
32391ae08745Sheppo 	ldc_chan_t *ldcp;
32401ae08745Sheppo 
32411ae08745Sheppo 	if (handle == NULL) {
32421ae08745Sheppo 		DWARN(DBG_ALL_LDCS,
32431ae08745Sheppo 		    "ldc_unreg_callback: invalid channel handle\n");
32441ae08745Sheppo 		return (EINVAL);
32451ae08745Sheppo 	}
32461ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
32471ae08745Sheppo 
32481ae08745Sheppo 	mutex_enter(&ldcp->lock);
32491ae08745Sheppo 
32501ae08745Sheppo 	if (ldcp->cb == NULL) {
32511ae08745Sheppo 		DWARN(ldcp->id,
32521ae08745Sheppo 		    "ldc_unreg_callback: (0x%llx) no callback exists\n",
32531ae08745Sheppo 		    ldcp->id);
32541ae08745Sheppo 		mutex_exit(&ldcp->lock);
32551ae08745Sheppo 		return (EIO);
32561ae08745Sheppo 	}
32571ae08745Sheppo 	if (ldcp->cb_inprogress) {
32581ae08745Sheppo 		DWARN(ldcp->id,
32591ae08745Sheppo 		    "ldc_unreg_callback: (0x%llx) callback active\n",
32601ae08745Sheppo 		    ldcp->id);
32611ae08745Sheppo 		mutex_exit(&ldcp->lock);
32621ae08745Sheppo 		return (EWOULDBLOCK);
32631ae08745Sheppo 	}
32641ae08745Sheppo 
32651ae08745Sheppo 	ldcp->cb = NULL;
32661ae08745Sheppo 	ldcp->cb_arg = NULL;
32671ae08745Sheppo 	ldcp->cb_enabled = B_FALSE;
32681ae08745Sheppo 
32691ae08745Sheppo 	D1(ldcp->id,
32701ae08745Sheppo 	    "ldc_unreg_callback: (0x%llx) unregistered callback for channel\n",
32711ae08745Sheppo 	    ldcp->id);
32721ae08745Sheppo 
32731ae08745Sheppo 	mutex_exit(&ldcp->lock);
32741ae08745Sheppo 
32751ae08745Sheppo 	return (0);
32761ae08745Sheppo }
32771ae08745Sheppo 
32781ae08745Sheppo 
32791ae08745Sheppo /*
32801ae08745Sheppo  * Bring a channel up by initiating a handshake with the peer
32811ae08745Sheppo  * This call is asynchronous. It will complete at a later point
32821ae08745Sheppo  * in time when the peer responds back with an RTR.
32831ae08745Sheppo  */
32841ae08745Sheppo int
32851ae08745Sheppo ldc_up(ldc_handle_t handle)
32861ae08745Sheppo {
32871ae08745Sheppo 	int 		rv;
32881ae08745Sheppo 	ldc_chan_t 	*ldcp;
32891ae08745Sheppo 	ldc_msg_t 	*ldcmsg;
329057e6a936Ssb155480 	uint64_t 	tx_tail, tstate, link_state;
32911ae08745Sheppo 
32921ae08745Sheppo 	if (handle == NULL) {
32931ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_up: invalid channel handle\n");
32941ae08745Sheppo 		return (EINVAL);
32951ae08745Sheppo 	}
32961ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
32971ae08745Sheppo 
32981ae08745Sheppo 	mutex_enter(&ldcp->lock);
32991ae08745Sheppo 
33003af08d82Slm66018 	D1(ldcp->id, "ldc_up: (0x%llx) doing channel UP\n", ldcp->id);
33013af08d82Slm66018 
33023af08d82Slm66018 	/* clear the reset state */
33033af08d82Slm66018 	tstate = ldcp->tstate;
33043af08d82Slm66018 	ldcp->tstate &= ~TS_IN_RESET;
33053af08d82Slm66018 
33061ae08745Sheppo 	if (ldcp->tstate == TS_UP) {
33073af08d82Slm66018 		DWARN(ldcp->id,
33081ae08745Sheppo 		    "ldc_up: (0x%llx) channel is already in UP state\n",
33091ae08745Sheppo 		    ldcp->id);
33103af08d82Slm66018 
33113af08d82Slm66018 		/* mark channel as up */
33123af08d82Slm66018 		ldcp->status = LDC_UP;
33133af08d82Slm66018 
33143af08d82Slm66018 		/*
33153af08d82Slm66018 		 * if channel was in reset state and there was
33163af08d82Slm66018 		 * pending data clear interrupt state. this will
33173af08d82Slm66018 		 * trigger an interrupt, causing the RX handler to
33183af08d82Slm66018 		 * to invoke the client's callback
33193af08d82Slm66018 		 */
33203af08d82Slm66018 		if ((tstate & TS_IN_RESET) &&
33213af08d82Slm66018 		    ldcp->rx_intr_state == LDC_INTR_PEND) {
3322cb112a14Slm66018 			D1(ldcp->id,
33233af08d82Slm66018 			    "ldc_up: (0x%llx) channel has pending data, "
33243af08d82Slm66018 			    "clearing interrupt\n", ldcp->id);
33253af08d82Slm66018 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
33263af08d82Slm66018 		}
33273af08d82Slm66018 
33281ae08745Sheppo 		mutex_exit(&ldcp->lock);
33291ae08745Sheppo 		return (0);
33301ae08745Sheppo 	}
33311ae08745Sheppo 
33321ae08745Sheppo 	/* if the channel is in RAW mode - mark it as UP, if READY */
33331ae08745Sheppo 	if (ldcp->mode == LDC_MODE_RAW && ldcp->tstate >= TS_READY) {
33341ae08745Sheppo 		ldcp->tstate = TS_UP;
33351ae08745Sheppo 		mutex_exit(&ldcp->lock);
33361ae08745Sheppo 		return (0);
33371ae08745Sheppo 	}
33381ae08745Sheppo 
33391ae08745Sheppo 	/* Don't start another handshake if there is one in progress */
33401ae08745Sheppo 	if (ldcp->hstate) {
33413af08d82Slm66018 		D1(ldcp->id,
33421ae08745Sheppo 		    "ldc_up: (0x%llx) channel handshake in progress\n",
33431ae08745Sheppo 		    ldcp->id);
33441ae08745Sheppo 		mutex_exit(&ldcp->lock);
33451ae08745Sheppo 		return (0);
33461ae08745Sheppo 	}
33471ae08745Sheppo 
3348d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
3349d10e4ef2Snarayan 
335057e6a936Ssb155480 	/* save current link state */
335157e6a936Ssb155480 	link_state = ldcp->link_state;
335257e6a936Ssb155480 
33531ae08745Sheppo 	/* get the current tail for the LDC msg */
33541ae08745Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
33551ae08745Sheppo 	if (rv) {
3356cb112a14Slm66018 		D1(ldcp->id, "ldc_up: (0x%llx) cannot initiate handshake\n",
33571ae08745Sheppo 		    ldcp->id);
3358d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
33591ae08745Sheppo 		mutex_exit(&ldcp->lock);
33601ae08745Sheppo 		return (ECONNREFUSED);
33611ae08745Sheppo 	}
33621ae08745Sheppo 
336357e6a936Ssb155480 	/*
336457e6a936Ssb155480 	 * If i_ldc_get_tx_tail() changed link_state to either RESET or UP,
336557e6a936Ssb155480 	 * from a previous state of DOWN, then mark the channel as
336657e6a936Ssb155480 	 * being ready for handshake.
336757e6a936Ssb155480 	 */
336857e6a936Ssb155480 	if ((link_state == LDC_CHANNEL_DOWN) &&
336957e6a936Ssb155480 	    (link_state != ldcp->link_state)) {
337057e6a936Ssb155480 
337157e6a936Ssb155480 		ASSERT((ldcp->link_state == LDC_CHANNEL_RESET) ||
337257e6a936Ssb155480 		    (ldcp->link_state == LDC_CHANNEL_UP));
337357e6a936Ssb155480 
337457e6a936Ssb155480 		if (ldcp->mode == LDC_MODE_RAW) {
337557e6a936Ssb155480 			ldcp->status = LDC_UP;
337657e6a936Ssb155480 			ldcp->tstate = TS_UP;
337757e6a936Ssb155480 			mutex_exit(&ldcp->tx_lock);
337857e6a936Ssb155480 			mutex_exit(&ldcp->lock);
337957e6a936Ssb155480 			return (0);
338057e6a936Ssb155480 		} else {
338157e6a936Ssb155480 			ldcp->status = LDC_READY;
338257e6a936Ssb155480 			ldcp->tstate |= TS_LINK_READY;
338357e6a936Ssb155480 		}
338457e6a936Ssb155480 
338557e6a936Ssb155480 	}
338657e6a936Ssb155480 
33871ae08745Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
33881ae08745Sheppo 	ZERO_PKT(ldcmsg);
33891ae08745Sheppo 
33901ae08745Sheppo 	ldcmsg->type = LDC_CTRL;
33911ae08745Sheppo 	ldcmsg->stype = LDC_INFO;
33921ae08745Sheppo 	ldcmsg->ctrl = LDC_VER;
33931ae08745Sheppo 	ldcp->next_vidx = 0;
33941ae08745Sheppo 	bcopy(&ldc_versions[0], ldcmsg->udata, sizeof (ldc_versions[0]));
33951ae08745Sheppo 
33961ae08745Sheppo 	DUMP_LDC_PKT(ldcp, "ldc_up snd ver", (uint64_t)ldcmsg);
33971ae08745Sheppo 
33981ae08745Sheppo 	/* initiate the send by calling into HV and set the new tail */
33991ae08745Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
34001ae08745Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
34011ae08745Sheppo 
34021ae08745Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
34031ae08745Sheppo 	if (rv) {
34041ae08745Sheppo 		DWARN(ldcp->id,
34051ae08745Sheppo 		    "ldc_up: (0x%llx) cannot initiate handshake rv=%d\n",
34061ae08745Sheppo 		    ldcp->id, rv);
3407d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
34081ae08745Sheppo 		mutex_exit(&ldcp->lock);
34091ae08745Sheppo 		return (rv);
34101ae08745Sheppo 	}
34111ae08745Sheppo 
34120a55fbb7Slm66018 	ldcp->hstate |= TS_SENT_VER;
34131ae08745Sheppo 	ldcp->tx_tail = tx_tail;
34141ae08745Sheppo 	D1(ldcp->id, "ldc_up: (0x%llx) channel up initiated\n", ldcp->id);
34151ae08745Sheppo 
3416d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
34171ae08745Sheppo 	mutex_exit(&ldcp->lock);
34181ae08745Sheppo 
34191ae08745Sheppo 	return (rv);
34201ae08745Sheppo }
34211ae08745Sheppo 
34221ae08745Sheppo 
34231ae08745Sheppo /*
3424e1ebb9ecSlm66018  * Bring a channel down by resetting its state and queues
34251ae08745Sheppo  */
34261ae08745Sheppo int
3427e1ebb9ecSlm66018 ldc_down(ldc_handle_t handle)
34281ae08745Sheppo {
34291ae08745Sheppo 	ldc_chan_t 	*ldcp;
34301ae08745Sheppo 
34311ae08745Sheppo 	if (handle == NULL) {
3432e1ebb9ecSlm66018 		DWARN(DBG_ALL_LDCS, "ldc_down: invalid channel handle\n");
34331ae08745Sheppo 		return (EINVAL);
34341ae08745Sheppo 	}
34351ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
34361ae08745Sheppo 	mutex_enter(&ldcp->lock);
3437d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
34383af08d82Slm66018 	i_ldc_reset(ldcp, B_TRUE);
3439d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
34401ae08745Sheppo 	mutex_exit(&ldcp->lock);
34411ae08745Sheppo 
34421ae08745Sheppo 	return (0);
34431ae08745Sheppo }
34441ae08745Sheppo 
34451ae08745Sheppo /*
34461ae08745Sheppo  * Get the current channel status
34471ae08745Sheppo  */
34481ae08745Sheppo int
34491ae08745Sheppo ldc_status(ldc_handle_t handle, ldc_status_t *status)
34501ae08745Sheppo {
34511ae08745Sheppo 	ldc_chan_t *ldcp;
34521ae08745Sheppo 
34531ae08745Sheppo 	if (handle == NULL || status == NULL) {
34541ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_status: invalid argument\n");
34551ae08745Sheppo 		return (EINVAL);
34561ae08745Sheppo 	}
34571ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
34581ae08745Sheppo 
34591ae08745Sheppo 	*status = ((ldc_chan_t *)handle)->status;
34601ae08745Sheppo 
3461cb112a14Slm66018 	D1(ldcp->id,
34621ae08745Sheppo 	    "ldc_status: (0x%llx) returned status %d\n", ldcp->id, *status);
34631ae08745Sheppo 	return (0);
34641ae08745Sheppo }
34651ae08745Sheppo 
34661ae08745Sheppo 
34671ae08745Sheppo /*
34681ae08745Sheppo  * Set the channel's callback mode - enable/disable callbacks
34691ae08745Sheppo  */
34701ae08745Sheppo int
34711ae08745Sheppo ldc_set_cb_mode(ldc_handle_t handle, ldc_cb_mode_t cmode)
34721ae08745Sheppo {
34731ae08745Sheppo 	ldc_chan_t 	*ldcp;
34741ae08745Sheppo 
34751ae08745Sheppo 	if (handle == NULL) {
34761ae08745Sheppo 		DWARN(DBG_ALL_LDCS,
34771ae08745Sheppo 		    "ldc_set_intr_mode: invalid channel handle\n");
34781ae08745Sheppo 		return (EINVAL);
34791ae08745Sheppo 	}
34801ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
34811ae08745Sheppo 
34821ae08745Sheppo 	/*
34831ae08745Sheppo 	 * Record no callbacks should be invoked
34841ae08745Sheppo 	 */
34851ae08745Sheppo 	mutex_enter(&ldcp->lock);
34861ae08745Sheppo 
34871ae08745Sheppo 	switch (cmode) {
34881ae08745Sheppo 	case LDC_CB_DISABLE:
34891ae08745Sheppo 		if (!ldcp->cb_enabled) {
34901ae08745Sheppo 			DWARN(ldcp->id,
34911ae08745Sheppo 			    "ldc_set_cb_mode: (0x%llx) callbacks disabled\n",
34921ae08745Sheppo 			    ldcp->id);
34931ae08745Sheppo 			break;
34941ae08745Sheppo 		}
34951ae08745Sheppo 		ldcp->cb_enabled = B_FALSE;
34961ae08745Sheppo 
34971ae08745Sheppo 		D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) disabled callbacks\n",
34981ae08745Sheppo 		    ldcp->id);
34991ae08745Sheppo 		break;
35001ae08745Sheppo 
35011ae08745Sheppo 	case LDC_CB_ENABLE:
35021ae08745Sheppo 		if (ldcp->cb_enabled) {
35031ae08745Sheppo 			DWARN(ldcp->id,
35041ae08745Sheppo 			    "ldc_set_cb_mode: (0x%llx) callbacks enabled\n",
35051ae08745Sheppo 			    ldcp->id);
35061ae08745Sheppo 			break;
35071ae08745Sheppo 		}
35081ae08745Sheppo 		ldcp->cb_enabled = B_TRUE;
35091ae08745Sheppo 
35101ae08745Sheppo 		D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) enabled callbacks\n",
35111ae08745Sheppo 		    ldcp->id);
35121ae08745Sheppo 		break;
35131ae08745Sheppo 	}
35141ae08745Sheppo 
35151ae08745Sheppo 	mutex_exit(&ldcp->lock);
35161ae08745Sheppo 
35171ae08745Sheppo 	return (0);
35181ae08745Sheppo }
35191ae08745Sheppo 
35201ae08745Sheppo /*
35211ae08745Sheppo  * Check to see if there are packets on the incoming queue
3522e1ebb9ecSlm66018  * Will return hasdata = B_FALSE if there are no packets
35231ae08745Sheppo  */
35241ae08745Sheppo int
3525e1ebb9ecSlm66018 ldc_chkq(ldc_handle_t handle, boolean_t *hasdata)
35261ae08745Sheppo {
35271ae08745Sheppo 	int 		rv;
35281ae08745Sheppo 	uint64_t 	rx_head, rx_tail;
35291ae08745Sheppo 	ldc_chan_t 	*ldcp;
35301ae08745Sheppo 
35311ae08745Sheppo 	if (handle == NULL) {
35321ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_chkq: invalid channel handle\n");
35331ae08745Sheppo 		return (EINVAL);
35341ae08745Sheppo 	}
35351ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
35361ae08745Sheppo 
3537e1ebb9ecSlm66018 	*hasdata = B_FALSE;
35381ae08745Sheppo 
35391ae08745Sheppo 	mutex_enter(&ldcp->lock);
35401ae08745Sheppo 
35411ae08745Sheppo 	if (ldcp->tstate != TS_UP) {
35421ae08745Sheppo 		D1(ldcp->id,
35431ae08745Sheppo 		    "ldc_chkq: (0x%llx) channel is not up\n", ldcp->id);
35441ae08745Sheppo 		mutex_exit(&ldcp->lock);
35451ae08745Sheppo 		return (ECONNRESET);
35461ae08745Sheppo 	}
35471ae08745Sheppo 
35481ae08745Sheppo 	/* Read packet(s) from the queue */
35491ae08745Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
35501ae08745Sheppo 	    &ldcp->link_state);
35511ae08745Sheppo 	if (rv != 0) {
35521ae08745Sheppo 		cmn_err(CE_WARN,
35531ae08745Sheppo 		    "ldc_chkq: (0x%lx) unable to read queue ptrs", ldcp->id);
35541ae08745Sheppo 		mutex_exit(&ldcp->lock);
35551ae08745Sheppo 		return (EIO);
35561ae08745Sheppo 	}
355758283286Sha137994 
35581ae08745Sheppo 	/* reset the channel state if the channel went down */
35591ae08745Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
35601ae08745Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
3561d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
35623af08d82Slm66018 		i_ldc_reset(ldcp, B_FALSE);
3563d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
35641ae08745Sheppo 		mutex_exit(&ldcp->lock);
35651ae08745Sheppo 		return (ECONNRESET);
35661ae08745Sheppo 	}
35671ae08745Sheppo 
356858283286Sha137994 	switch (ldcp->mode) {
356958283286Sha137994 	case LDC_MODE_RAW:
357058283286Sha137994 		/*
357158283286Sha137994 		 * In raw mode, there are no ctrl packets, so checking
357258283286Sha137994 		 * if the queue is non-empty is sufficient.
357358283286Sha137994 		 */
357458283286Sha137994 		*hasdata = (rx_head != rx_tail);
357558283286Sha137994 		break;
357658283286Sha137994 
357758283286Sha137994 	case LDC_MODE_UNRELIABLE:
357858283286Sha137994 		/*
357958283286Sha137994 		 * In unreliable mode, if the queue is non-empty, we need
358058283286Sha137994 		 * to check if it actually contains unread data packets.
358158283286Sha137994 		 * The queue may just contain ctrl packets.
358258283286Sha137994 		 */
3583a74caf9bSha137994 		if (rx_head != rx_tail) {
358458283286Sha137994 			*hasdata = (i_ldc_chkq(ldcp) == 0);
3585a74caf9bSha137994 			/*
3586a74caf9bSha137994 			 * If no data packets were found on the queue,
3587a74caf9bSha137994 			 * all packets must have been control packets
3588a74caf9bSha137994 			 * which will now have been processed, leaving
3589a74caf9bSha137994 			 * the queue empty. If the interrupt state
3590a74caf9bSha137994 			 * is pending, we need to clear the interrupt
3591a74caf9bSha137994 			 * here.
3592a74caf9bSha137994 			 */
3593a74caf9bSha137994 			if (*hasdata == B_FALSE &&
3594a74caf9bSha137994 			    ldcp->rx_intr_state == LDC_INTR_PEND) {
3595a74caf9bSha137994 				i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
3596a74caf9bSha137994 			}
3597a74caf9bSha137994 		}
359858283286Sha137994 		break;
359958283286Sha137994 
360020ae46ebSha137994 	case LDC_MODE_RELIABLE:
360158283286Sha137994 		/*
360220ae46ebSha137994 		 * In reliable mode, first check for 'stream_remains' > 0.
360358283286Sha137994 		 * Otherwise, if the data queue head and tail pointers
360458283286Sha137994 		 * differ, there must be data to read.
360558283286Sha137994 		 */
360658283286Sha137994 		if (ldcp->stream_remains > 0)
3607e1ebb9ecSlm66018 			*hasdata = B_TRUE;
360858283286Sha137994 		else
360958283286Sha137994 			*hasdata = (ldcp->rx_dq_head != ldcp->rx_dq_tail);
361058283286Sha137994 		break;
361158283286Sha137994 
361258283286Sha137994 	default:
361358283286Sha137994 		cmn_err(CE_WARN, "ldc_chkq: (0x%lx) unexpected channel mode "
361458283286Sha137994 		    "(0x%x)", ldcp->id, ldcp->mode);
361558283286Sha137994 		mutex_exit(&ldcp->lock);
361658283286Sha137994 		return (EIO);
36171ae08745Sheppo 	}
36181ae08745Sheppo 
36191ae08745Sheppo 	mutex_exit(&ldcp->lock);
36201ae08745Sheppo 
36211ae08745Sheppo 	return (0);
36221ae08745Sheppo }
36231ae08745Sheppo 
36241ae08745Sheppo 
36251ae08745Sheppo /*
36261ae08745Sheppo  * Read 'size' amount of bytes or less. If incoming buffer
36271ae08745Sheppo  * is more than 'size', ENOBUFS is returned.
36281ae08745Sheppo  *
36291ae08745Sheppo  * On return, size contains the number of bytes read.
36301ae08745Sheppo  */
36311ae08745Sheppo int
36321ae08745Sheppo ldc_read(ldc_handle_t handle, caddr_t bufp, size_t *sizep)
36331ae08745Sheppo {
36341ae08745Sheppo 	ldc_chan_t 	*ldcp;
36351ae08745Sheppo 	uint64_t 	rx_head = 0, rx_tail = 0;
36361ae08745Sheppo 	int		rv = 0, exit_val;
36371ae08745Sheppo 
36381ae08745Sheppo 	if (handle == NULL) {
36391ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_read: invalid channel handle\n");
36401ae08745Sheppo 		return (EINVAL);
36411ae08745Sheppo 	}
36421ae08745Sheppo 
36431ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
36441ae08745Sheppo 
36451ae08745Sheppo 	/* channel lock */
36461ae08745Sheppo 	mutex_enter(&ldcp->lock);
36471ae08745Sheppo 
36481ae08745Sheppo 	if (ldcp->tstate != TS_UP) {
36491ae08745Sheppo 		DWARN(ldcp->id,
36501ae08745Sheppo 		    "ldc_read: (0x%llx) channel is not in UP state\n",
36511ae08745Sheppo 		    ldcp->id);
36521ae08745Sheppo 		exit_val = ECONNRESET;
365320ae46ebSha137994 	} else if (ldcp->mode == LDC_MODE_RELIABLE) {
365458283286Sha137994 		TRACE_RXDQ_LENGTH(ldcp);
365558283286Sha137994 		exit_val = ldcp->read_p(ldcp, bufp, sizep);
365658283286Sha137994 		mutex_exit(&ldcp->lock);
365758283286Sha137994 		return (exit_val);
36581ae08745Sheppo 	} else {
36591ae08745Sheppo 		exit_val = ldcp->read_p(ldcp, bufp, sizep);
36601ae08745Sheppo 	}
36611ae08745Sheppo 
36621ae08745Sheppo 	/*
36631ae08745Sheppo 	 * if queue has been drained - clear interrupt
36641ae08745Sheppo 	 */
36651ae08745Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
36661ae08745Sheppo 	    &ldcp->link_state);
3667cb112a14Slm66018 	if (rv != 0) {
3668cb112a14Slm66018 		cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
3669cb112a14Slm66018 		    ldcp->id);
3670cb112a14Slm66018 		mutex_enter(&ldcp->tx_lock);
3671cb112a14Slm66018 		i_ldc_reset(ldcp, B_TRUE);
3672cb112a14Slm66018 		mutex_exit(&ldcp->tx_lock);
3673bd8f0338Snarayan 		mutex_exit(&ldcp->lock);
3674cb112a14Slm66018 		return (ECONNRESET);
3675cb112a14Slm66018 	}
36763af08d82Slm66018 
36773af08d82Slm66018 	if (exit_val == 0) {
36783af08d82Slm66018 		if (ldcp->link_state == LDC_CHANNEL_DOWN ||
36793af08d82Slm66018 		    ldcp->link_state == LDC_CHANNEL_RESET) {
36803af08d82Slm66018 			mutex_enter(&ldcp->tx_lock);
36813af08d82Slm66018 			i_ldc_reset(ldcp, B_FALSE);
36823af08d82Slm66018 			exit_val = ECONNRESET;
36833af08d82Slm66018 			mutex_exit(&ldcp->tx_lock);
36843af08d82Slm66018 		}
36853af08d82Slm66018 		if ((rv == 0) &&
36863af08d82Slm66018 		    (ldcp->rx_intr_state == LDC_INTR_PEND) &&
36873af08d82Slm66018 		    (rx_head == rx_tail)) {
36881ae08745Sheppo 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
36891ae08745Sheppo 		}
36903af08d82Slm66018 	}
36911ae08745Sheppo 
36921ae08745Sheppo 	mutex_exit(&ldcp->lock);
36931ae08745Sheppo 	return (exit_val);
36941ae08745Sheppo }
36951ae08745Sheppo 
36961ae08745Sheppo /*
36971ae08745Sheppo  * Basic raw mondo read -
36981ae08745Sheppo  * no interpretation of mondo contents at all.
36991ae08745Sheppo  *
37001ae08745Sheppo  * Enter and exit with ldcp->lock held by caller
37011ae08745Sheppo  */
37021ae08745Sheppo static int
37031ae08745Sheppo i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
37041ae08745Sheppo {
37051ae08745Sheppo 	uint64_t 	q_size_mask;
37061ae08745Sheppo 	ldc_msg_t 	*msgp;
37071ae08745Sheppo 	uint8_t		*msgbufp;
37081ae08745Sheppo 	int		rv = 0, space;
37091ae08745Sheppo 	uint64_t 	rx_head, rx_tail;
37101ae08745Sheppo 
37111ae08745Sheppo 	space = *sizep;
37121ae08745Sheppo 
37131ae08745Sheppo 	if (space < LDC_PAYLOAD_SIZE_RAW)
37141ae08745Sheppo 		return (ENOBUFS);
37151ae08745Sheppo 
37161ae08745Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
37171ae08745Sheppo 
37181ae08745Sheppo 	/* compute mask for increment */
37191ae08745Sheppo 	q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
37201ae08745Sheppo 
37211ae08745Sheppo 	/*
37221ae08745Sheppo 	 * Read packet(s) from the queue
37231ae08745Sheppo 	 */
37241ae08745Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
37251ae08745Sheppo 	    &ldcp->link_state);
37261ae08745Sheppo 	if (rv != 0) {
37271ae08745Sheppo 		cmn_err(CE_WARN,
37281ae08745Sheppo 		    "ldc_read_raw: (0x%lx) unable to read queue ptrs",
37291ae08745Sheppo 		    ldcp->id);
37301ae08745Sheppo 		return (EIO);
37311ae08745Sheppo 	}
37321ae08745Sheppo 	D1(ldcp->id, "ldc_read_raw: (0x%llx) rxh=0x%llx,"
37331ae08745Sheppo 	    " rxt=0x%llx, st=0x%llx\n",
37341ae08745Sheppo 	    ldcp->id, rx_head, rx_tail, ldcp->link_state);
37351ae08745Sheppo 
37361ae08745Sheppo 	/* reset the channel state if the channel went down */
37373af08d82Slm66018 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
37383af08d82Slm66018 	    ldcp->link_state == LDC_CHANNEL_RESET) {
3739d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
37403af08d82Slm66018 		i_ldc_reset(ldcp, B_FALSE);
3741d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
37421ae08745Sheppo 		return (ECONNRESET);
37431ae08745Sheppo 	}
37441ae08745Sheppo 
37451ae08745Sheppo 	/*
37461ae08745Sheppo 	 * Check for empty queue
37471ae08745Sheppo 	 */
37481ae08745Sheppo 	if (rx_head == rx_tail) {
37491ae08745Sheppo 		*sizep = 0;
37501ae08745Sheppo 		return (0);
37511ae08745Sheppo 	}
37521ae08745Sheppo 
37531ae08745Sheppo 	/* get the message */
37541ae08745Sheppo 	msgp = (ldc_msg_t *)(ldcp->rx_q_va + rx_head);
37551ae08745Sheppo 
37561ae08745Sheppo 	/* if channel is in RAW mode, copy data and return */
37571ae08745Sheppo 	msgbufp = (uint8_t *)&(msgp->raw[0]);
37581ae08745Sheppo 
37591ae08745Sheppo 	bcopy(msgbufp, target_bufp, LDC_PAYLOAD_SIZE_RAW);
37601ae08745Sheppo 
37611ae08745Sheppo 	DUMP_PAYLOAD(ldcp->id, msgbufp);
37621ae08745Sheppo 
37631ae08745Sheppo 	*sizep = LDC_PAYLOAD_SIZE_RAW;
37641ae08745Sheppo 
37651ae08745Sheppo 	rx_head = (rx_head + LDC_PACKET_SIZE) & q_size_mask;
37660a55fbb7Slm66018 	rv = i_ldc_set_rx_head(ldcp, rx_head);
37671ae08745Sheppo 
37681ae08745Sheppo 	return (rv);
37691ae08745Sheppo }
37701ae08745Sheppo 
37711ae08745Sheppo /*
37721ae08745Sheppo  * Process LDC mondos to build larger packets
37731ae08745Sheppo  * with either un-reliable or reliable delivery.
37741ae08745Sheppo  *
37751ae08745Sheppo  * Enter and exit with ldcp->lock held by caller
37761ae08745Sheppo  */
37771ae08745Sheppo static int
37781ae08745Sheppo i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
37791ae08745Sheppo {
37801ae08745Sheppo 	int		rv = 0;
37811ae08745Sheppo 	uint64_t 	rx_head = 0, rx_tail = 0;
37821ae08745Sheppo 	uint64_t 	curr_head = 0;
37831ae08745Sheppo 	ldc_msg_t 	*msg;
37841ae08745Sheppo 	caddr_t 	target;
37851ae08745Sheppo 	size_t 		len = 0, bytes_read = 0;
37860a55fbb7Slm66018 	int 		retries = 0;
378758283286Sha137994 	uint64_t 	q_va, q_size_mask;
3788d10e4ef2Snarayan 	uint64_t	first_fragment = 0;
37891ae08745Sheppo 
37901ae08745Sheppo 	target = target_bufp;
37911ae08745Sheppo 
37921ae08745Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
37931ae08745Sheppo 
37943af08d82Slm66018 	/* check if the buffer and size are valid */
37953af08d82Slm66018 	if (target_bufp == NULL || *sizep == 0) {
37963af08d82Slm66018 		DWARN(ldcp->id, "ldc_read: (0x%llx) invalid buffer/size\n",
37973af08d82Slm66018 		    ldcp->id);
37983af08d82Slm66018 		return (EINVAL);
37993af08d82Slm66018 	}
38003af08d82Slm66018 
380158283286Sha137994 	/* Set q_va and compute increment mask for the appropriate queue */
380220ae46ebSha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
380358283286Sha137994 		q_va	    = ldcp->rx_dq_va;
380458283286Sha137994 		q_size_mask = (ldcp->rx_dq_entries-1)<<LDC_PACKET_SHIFT;
380558283286Sha137994 	} else {
380658283286Sha137994 		q_va	    = ldcp->rx_q_va;
38071ae08745Sheppo 		q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
380858283286Sha137994 	}
38091ae08745Sheppo 
38101ae08745Sheppo 	/*
38111ae08745Sheppo 	 * Read packet(s) from the queue
38121ae08745Sheppo 	 */
381358283286Sha137994 	rv = ldcp->readq_get_state(ldcp, &curr_head, &rx_tail,
38141ae08745Sheppo 	    &ldcp->link_state);
38151ae08745Sheppo 	if (rv != 0) {
38163af08d82Slm66018 		cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
38171ae08745Sheppo 		    ldcp->id);
38183af08d82Slm66018 		mutex_enter(&ldcp->tx_lock);
38193af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
38203af08d82Slm66018 		mutex_exit(&ldcp->tx_lock);
38213af08d82Slm66018 		return (ECONNRESET);
38221ae08745Sheppo 	}
38231ae08745Sheppo 	D1(ldcp->id, "ldc_read: (0x%llx) chd=0x%llx, tl=0x%llx, st=0x%llx\n",
38241ae08745Sheppo 	    ldcp->id, curr_head, rx_tail, ldcp->link_state);
38251ae08745Sheppo 
38261ae08745Sheppo 	/* reset the channel state if the channel went down */
38273af08d82Slm66018 	if (ldcp->link_state != LDC_CHANNEL_UP)
38283af08d82Slm66018 		goto channel_is_reset;
38291ae08745Sheppo 
38301ae08745Sheppo 	for (;;) {
38311ae08745Sheppo 
38321ae08745Sheppo 		if (curr_head == rx_tail) {
383358283286Sha137994 			/*
383458283286Sha137994 			 * If a data queue is being used, check the Rx HV
383558283286Sha137994 			 * queue. This will copy over any new data packets
383658283286Sha137994 			 * that have arrived.
383758283286Sha137994 			 */
383820ae46ebSha137994 			if (ldcp->mode == LDC_MODE_RELIABLE)
383958283286Sha137994 				(void) i_ldc_chkq(ldcp);
384058283286Sha137994 
384158283286Sha137994 			rv = ldcp->readq_get_state(ldcp,
38421ae08745Sheppo 			    &rx_head, &rx_tail, &ldcp->link_state);
38431ae08745Sheppo 			if (rv != 0) {
38441ae08745Sheppo 				cmn_err(CE_WARN,
38451ae08745Sheppo 				    "ldc_read: (0x%lx) cannot read queue ptrs",
38461ae08745Sheppo 				    ldcp->id);
3847d10e4ef2Snarayan 				mutex_enter(&ldcp->tx_lock);
38483af08d82Slm66018 				i_ldc_reset(ldcp, B_TRUE);
3849d10e4ef2Snarayan 				mutex_exit(&ldcp->tx_lock);
38501ae08745Sheppo 				return (ECONNRESET);
38511ae08745Sheppo 			}
385258283286Sha137994 
38533af08d82Slm66018 			if (ldcp->link_state != LDC_CHANNEL_UP)
38543af08d82Slm66018 				goto channel_is_reset;
38551ae08745Sheppo 
38561ae08745Sheppo 			if (curr_head == rx_tail) {
38571ae08745Sheppo 
38581ae08745Sheppo 				/* If in the middle of a fragmented xfer */
3859d10e4ef2Snarayan 				if (first_fragment != 0) {
38600a55fbb7Slm66018 
38610a55fbb7Slm66018 					/* wait for ldc_delay usecs */
38620a55fbb7Slm66018 					drv_usecwait(ldc_delay);
38630a55fbb7Slm66018 
38640a55fbb7Slm66018 					if (++retries < ldc_max_retries)
38651ae08745Sheppo 						continue;
38660a55fbb7Slm66018 
38671ae08745Sheppo 					*sizep = 0;
386820ae46ebSha137994 					if (ldcp->mode != LDC_MODE_RELIABLE)
386958283286Sha137994 						ldcp->last_msg_rcd =
387058283286Sha137994 						    first_fragment - 1;
38713af08d82Slm66018 					DWARN(DBG_ALL_LDCS, "ldc_read: "
387222f747efSnarayan 					    "(0x%llx) read timeout", ldcp->id);
38733af08d82Slm66018 					return (EAGAIN);
38741ae08745Sheppo 				}
38751ae08745Sheppo 				*sizep = 0;
38761ae08745Sheppo 				break;
38771ae08745Sheppo 			}
38783af08d82Slm66018 		}
38790a55fbb7Slm66018 		retries = 0;
38801ae08745Sheppo 
38811ae08745Sheppo 		D2(ldcp->id,
38821ae08745Sheppo 		    "ldc_read: (0x%llx) chd=0x%llx, rxhd=0x%llx, rxtl=0x%llx\n",
38831ae08745Sheppo 		    ldcp->id, curr_head, rx_head, rx_tail);
38841ae08745Sheppo 
38851ae08745Sheppo 		/* get the message */
388658283286Sha137994 		msg = (ldc_msg_t *)(q_va + curr_head);
38871ae08745Sheppo 
38881ae08745Sheppo 		DUMP_LDC_PKT(ldcp, "ldc_read received pkt",
38891ae08745Sheppo 		    ldcp->rx_q_va + curr_head);
38901ae08745Sheppo 
38911ae08745Sheppo 		/* Check the message ID for the message received */
389220ae46ebSha137994 		if (ldcp->mode != LDC_MODE_RELIABLE) {
38931ae08745Sheppo 			if ((rv = i_ldc_check_seqid(ldcp, msg)) != 0) {
38941ae08745Sheppo 
389558283286Sha137994 				DWARN(ldcp->id, "ldc_read: (0x%llx) seqid "
389658283286Sha137994 				    "error, q_ptrs=0x%lx,0x%lx",
389758283286Sha137994 				    ldcp->id, rx_head, rx_tail);
38981ae08745Sheppo 
38990a55fbb7Slm66018 				/* throw away data */
39000a55fbb7Slm66018 				bytes_read = 0;
39010a55fbb7Slm66018 
39021ae08745Sheppo 				/* Reset last_msg_rcd to start of message */
3903d10e4ef2Snarayan 				if (first_fragment != 0) {
3904d10e4ef2Snarayan 					ldcp->last_msg_rcd = first_fragment - 1;
3905d10e4ef2Snarayan 					first_fragment = 0;
39061ae08745Sheppo 				}
39071ae08745Sheppo 				/*
39081ae08745Sheppo 				 * Send a NACK -- invalid seqid
39091ae08745Sheppo 				 * get the current tail for the response
39101ae08745Sheppo 				 */
39111ae08745Sheppo 				rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK,
39121ae08745Sheppo 				    (msg->ctrl & LDC_CTRL_MASK));
39131ae08745Sheppo 				if (rv) {
39141ae08745Sheppo 					cmn_err(CE_NOTE,
39151ae08745Sheppo 					    "ldc_read: (0x%lx) err sending "
39161ae08745Sheppo 					    "NACK msg\n", ldcp->id);
3917d10e4ef2Snarayan 
391858283286Sha137994 					/* if cannot send NACK - reset chan */
3919d10e4ef2Snarayan 					mutex_enter(&ldcp->tx_lock);
39203af08d82Slm66018 					i_ldc_reset(ldcp, B_FALSE);
3921d10e4ef2Snarayan 					mutex_exit(&ldcp->tx_lock);
3922d10e4ef2Snarayan 					rv = ECONNRESET;
3923d10e4ef2Snarayan 					break;
39241ae08745Sheppo 				}
39251ae08745Sheppo 
39261ae08745Sheppo 				/* purge receive queue */
39270a55fbb7Slm66018 				rv = i_ldc_set_rx_head(ldcp, rx_tail);
39281ae08745Sheppo 
39291ae08745Sheppo 				break;
39301ae08745Sheppo 			}
39311ae08745Sheppo 
39321ae08745Sheppo 			/*
39331ae08745Sheppo 			 * Process any messages of type CTRL messages
3934e1ebb9ecSlm66018 			 * Future implementations should try to pass these
3935e1ebb9ecSlm66018 			 * to LDC link by resetting the intr state.
39361ae08745Sheppo 			 *
393758283286Sha137994 			 * NOTE: not done as a switch() as type can be
393858283286Sha137994 			 * both ctrl+data
39391ae08745Sheppo 			 */
39401ae08745Sheppo 			if (msg->type & LDC_CTRL) {
39411ae08745Sheppo 				if (rv = i_ldc_ctrlmsg(ldcp, msg)) {
39421ae08745Sheppo 					if (rv == EAGAIN)
39431ae08745Sheppo 						continue;
39440a55fbb7Slm66018 					rv = i_ldc_set_rx_head(ldcp, rx_tail);
39451ae08745Sheppo 					*sizep = 0;
39461ae08745Sheppo 					bytes_read = 0;
39471ae08745Sheppo 					break;
39481ae08745Sheppo 				}
39491ae08745Sheppo 			}
39501ae08745Sheppo 
39511ae08745Sheppo 			/* process data ACKs */
39521ae08745Sheppo 			if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
3953d10e4ef2Snarayan 				if (rv = i_ldc_process_data_ACK(ldcp, msg)) {
3954d10e4ef2Snarayan 					*sizep = 0;
3955d10e4ef2Snarayan 					bytes_read = 0;
3956d10e4ef2Snarayan 					break;
3957d10e4ef2Snarayan 				}
39581ae08745Sheppo 			}
39591ae08745Sheppo 
396083d3bc6fSnarayan 			/* process data NACKs */
396183d3bc6fSnarayan 			if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) {
396283d3bc6fSnarayan 				DWARN(ldcp->id,
396358283286Sha137994 				    "ldc_read: (0x%llx) received DATA/NACK",
396458283286Sha137994 				    ldcp->id);
396583d3bc6fSnarayan 				mutex_enter(&ldcp->tx_lock);
396683d3bc6fSnarayan 				i_ldc_reset(ldcp, B_TRUE);
396783d3bc6fSnarayan 				mutex_exit(&ldcp->tx_lock);
396883d3bc6fSnarayan 				return (ECONNRESET);
396983d3bc6fSnarayan 			}
397058283286Sha137994 		}
397183d3bc6fSnarayan 
39721ae08745Sheppo 		/* process data messages */
39731ae08745Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
39741ae08745Sheppo 
39751ae08745Sheppo 			uint8_t *msgbuf = (uint8_t *)(
397620ae46ebSha137994 			    (ldcp->mode == LDC_MODE_RELIABLE) ?
397722f747efSnarayan 			    msg->rdata : msg->udata);
39781ae08745Sheppo 
39791ae08745Sheppo 			D2(ldcp->id,
39801ae08745Sheppo 			    "ldc_read: (0x%llx) received data msg\n", ldcp->id);
39811ae08745Sheppo 
39821ae08745Sheppo 			/* get the packet length */
39831ae08745Sheppo 			len = (msg->env & LDC_LEN_MASK);
39841ae08745Sheppo 
39851ae08745Sheppo 				/*
39861ae08745Sheppo 				 * FUTURE OPTIMIZATION:
39871ae08745Sheppo 				 * dont need to set q head for every
39881ae08745Sheppo 				 * packet we read just need to do this when
39891ae08745Sheppo 				 * we are done or need to wait for more
39901ae08745Sheppo 				 * mondos to make a full packet - this is
39911ae08745Sheppo 				 * currently expensive.
39921ae08745Sheppo 				 */
39931ae08745Sheppo 
3994d10e4ef2Snarayan 			if (first_fragment == 0) {
39951ae08745Sheppo 
39961ae08745Sheppo 				/*
39971ae08745Sheppo 				 * first packets should always have the start
39981ae08745Sheppo 				 * bit set (even for a single packet). If not
39991ae08745Sheppo 				 * throw away the packet
40001ae08745Sheppo 				 */
40011ae08745Sheppo 				if (!(msg->env & LDC_FRAG_START)) {
40021ae08745Sheppo 
40031ae08745Sheppo 					DWARN(DBG_ALL_LDCS,
40041ae08745Sheppo 					    "ldc_read: (0x%llx) not start - "
40051ae08745Sheppo 					    "frag=%x\n", ldcp->id,
40061ae08745Sheppo 					    (msg->env) & LDC_FRAG_MASK);
40071ae08745Sheppo 
40081ae08745Sheppo 					/* toss pkt, inc head, cont reading */
40091ae08745Sheppo 					bytes_read = 0;
40101ae08745Sheppo 					target = target_bufp;
40111ae08745Sheppo 					curr_head =
40121ae08745Sheppo 					    (curr_head + LDC_PACKET_SIZE)
40131ae08745Sheppo 					    & q_size_mask;
401458283286Sha137994 					if (rv = ldcp->readq_set_head(ldcp,
40151ae08745Sheppo 					    curr_head))
40161ae08745Sheppo 						break;
40171ae08745Sheppo 
40181ae08745Sheppo 					continue;
40191ae08745Sheppo 				}
40201ae08745Sheppo 
4021d10e4ef2Snarayan 				first_fragment = msg->seqid;
40221ae08745Sheppo 			} else {
40231ae08745Sheppo 				/* check to see if this is a pkt w/ START bit */
40241ae08745Sheppo 				if (msg->env & LDC_FRAG_START) {
40251ae08745Sheppo 					DWARN(DBG_ALL_LDCS,
40261ae08745Sheppo 					    "ldc_read:(0x%llx) unexpected pkt"
40271ae08745Sheppo 					    " env=0x%x discarding %d bytes,"
40281ae08745Sheppo 					    " lastmsg=%d, currentmsg=%d\n",
40291ae08745Sheppo 					    ldcp->id, msg->env&LDC_FRAG_MASK,
40301ae08745Sheppo 					    bytes_read, ldcp->last_msg_rcd,
40311ae08745Sheppo 					    msg->seqid);
40321ae08745Sheppo 
40331ae08745Sheppo 					/* throw data we have read so far */
40341ae08745Sheppo 					bytes_read = 0;
40351ae08745Sheppo 					target = target_bufp;
4036d10e4ef2Snarayan 					first_fragment = msg->seqid;
40371ae08745Sheppo 
403858283286Sha137994 					if (rv = ldcp->readq_set_head(ldcp,
40391ae08745Sheppo 					    curr_head))
40401ae08745Sheppo 						break;
40411ae08745Sheppo 				}
40421ae08745Sheppo 			}
40431ae08745Sheppo 
40441ae08745Sheppo 			/* copy (next) pkt into buffer */
40451ae08745Sheppo 			if (len <= (*sizep - bytes_read)) {
40461ae08745Sheppo 				bcopy(msgbuf, target, len);
40471ae08745Sheppo 				target += len;
40481ae08745Sheppo 				bytes_read += len;
40491ae08745Sheppo 			} else {
40501ae08745Sheppo 				/*
40511ae08745Sheppo 				 * there is not enough space in the buffer to
40521ae08745Sheppo 				 * read this pkt. throw message away & continue
40531ae08745Sheppo 				 * reading data from queue
40541ae08745Sheppo 				 */
40551ae08745Sheppo 				DWARN(DBG_ALL_LDCS,
40561ae08745Sheppo 				    "ldc_read: (0x%llx) buffer too small, "
40571ae08745Sheppo 				    "head=0x%lx, expect=%d, got=%d\n", ldcp->id,
40581ae08745Sheppo 				    curr_head, *sizep, bytes_read+len);
40591ae08745Sheppo 
4060d10e4ef2Snarayan 				first_fragment = 0;
40611ae08745Sheppo 				target = target_bufp;
40621ae08745Sheppo 				bytes_read = 0;
40631ae08745Sheppo 
40641ae08745Sheppo 				/* throw away everything received so far */
406558283286Sha137994 				if (rv = ldcp->readq_set_head(ldcp, curr_head))
40661ae08745Sheppo 					break;
40671ae08745Sheppo 
40681ae08745Sheppo 				/* continue reading remaining pkts */
40691ae08745Sheppo 				continue;
40701ae08745Sheppo 			}
40711ae08745Sheppo 		}
40721ae08745Sheppo 
40731ae08745Sheppo 		/* set the message id */
407420ae46ebSha137994 		if (ldcp->mode != LDC_MODE_RELIABLE)
40751ae08745Sheppo 			ldcp->last_msg_rcd = msg->seqid;
40761ae08745Sheppo 
40771ae08745Sheppo 		/* move the head one position */
40781ae08745Sheppo 		curr_head = (curr_head + LDC_PACKET_SIZE) & q_size_mask;
40791ae08745Sheppo 
40801ae08745Sheppo 		if (msg->env & LDC_FRAG_STOP) {
40811ae08745Sheppo 
40821ae08745Sheppo 			/*
40831ae08745Sheppo 			 * All pkts that are part of this fragmented transfer
40841ae08745Sheppo 			 * have been read or this was a single pkt read
40851ae08745Sheppo 			 * or there was an error
40861ae08745Sheppo 			 */
40871ae08745Sheppo 
40881ae08745Sheppo 			/* set the queue head */
408958283286Sha137994 			if (rv = ldcp->readq_set_head(ldcp, curr_head))
40901ae08745Sheppo 				bytes_read = 0;
40911ae08745Sheppo 
40921ae08745Sheppo 			*sizep = bytes_read;
40931ae08745Sheppo 
40941ae08745Sheppo 			break;
40951ae08745Sheppo 		}
40961ae08745Sheppo 
4097332608acSnarayan 		/* advance head if it is a CTRL packet or a DATA ACK packet */
4098332608acSnarayan 		if ((msg->type & LDC_CTRL) ||
4099332608acSnarayan 		    ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK))) {
41001ae08745Sheppo 
41011ae08745Sheppo 			/* set the queue head */
410258283286Sha137994 			if (rv = ldcp->readq_set_head(ldcp, curr_head)) {
41031ae08745Sheppo 				bytes_read = 0;
41041ae08745Sheppo 				break;
41051ae08745Sheppo 			}
41061ae08745Sheppo 
41071ae08745Sheppo 			D2(ldcp->id, "ldc_read: (0x%llx) set ACK qhead 0x%llx",
41081ae08745Sheppo 			    ldcp->id, curr_head);
41091ae08745Sheppo 		}
41101ae08745Sheppo 
41111ae08745Sheppo 	} /* for (;;) */
41121ae08745Sheppo 
41131ae08745Sheppo 	D2(ldcp->id, "ldc_read: (0x%llx) end size=%d", ldcp->id, *sizep);
41141ae08745Sheppo 
41151ae08745Sheppo 	return (rv);
41163af08d82Slm66018 
41173af08d82Slm66018 channel_is_reset:
41183af08d82Slm66018 	mutex_enter(&ldcp->tx_lock);
41193af08d82Slm66018 	i_ldc_reset(ldcp, B_FALSE);
41203af08d82Slm66018 	mutex_exit(&ldcp->tx_lock);
41213af08d82Slm66018 	return (ECONNRESET);
41221ae08745Sheppo }
41231ae08745Sheppo 
41241ae08745Sheppo /*
412520ae46ebSha137994  * Fetch and buffer incoming packets so we can hand them back as
41261ae08745Sheppo  * a basic byte stream.
41271ae08745Sheppo  *
41281ae08745Sheppo  * Enter and exit with ldcp->lock held by caller
41291ae08745Sheppo  */
41301ae08745Sheppo static int
41311ae08745Sheppo i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
41321ae08745Sheppo {
41331ae08745Sheppo 	int	rv;
41341ae08745Sheppo 	size_t	size;
41351ae08745Sheppo 
41361ae08745Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
41371ae08745Sheppo 
41381ae08745Sheppo 	D2(ldcp->id, "i_ldc_read_stream: (0x%llx) buffer size=%d",
41391ae08745Sheppo 	    ldcp->id, *sizep);
41401ae08745Sheppo 
41411ae08745Sheppo 	if (ldcp->stream_remains == 0) {
41421ae08745Sheppo 		size = ldcp->mtu;
41431ae08745Sheppo 		rv = i_ldc_read_packet(ldcp,
41441ae08745Sheppo 		    (caddr_t)ldcp->stream_bufferp, &size);
41451ae08745Sheppo 		D2(ldcp->id, "i_ldc_read_stream: read packet (0x%llx) size=%d",
41461ae08745Sheppo 		    ldcp->id, size);
41471ae08745Sheppo 
41481ae08745Sheppo 		if (rv != 0)
41491ae08745Sheppo 			return (rv);
41501ae08745Sheppo 
41511ae08745Sheppo 		ldcp->stream_remains = size;
41521ae08745Sheppo 		ldcp->stream_offset = 0;
41531ae08745Sheppo 	}
41541ae08745Sheppo 
41551ae08745Sheppo 	size = MIN(ldcp->stream_remains, *sizep);
41561ae08745Sheppo 
41571ae08745Sheppo 	bcopy(ldcp->stream_bufferp + ldcp->stream_offset, target_bufp, size);
41581ae08745Sheppo 	ldcp->stream_offset += size;
41591ae08745Sheppo 	ldcp->stream_remains -= size;
41601ae08745Sheppo 
41611ae08745Sheppo 	D2(ldcp->id, "i_ldc_read_stream: (0x%llx) fill from buffer size=%d",
41621ae08745Sheppo 	    ldcp->id, size);
41631ae08745Sheppo 
41641ae08745Sheppo 	*sizep = size;
41651ae08745Sheppo 	return (0);
41661ae08745Sheppo }
41671ae08745Sheppo 
41681ae08745Sheppo /*
41691ae08745Sheppo  * Write specified amount of bytes to the channel
41701ae08745Sheppo  * in multiple pkts of pkt_payload size. Each
41711ae08745Sheppo  * packet is tagged with an unique packet ID in
4172e1ebb9ecSlm66018  * the case of a reliable link.
41731ae08745Sheppo  *
41741ae08745Sheppo  * On return, size contains the number of bytes written.
41751ae08745Sheppo  */
41761ae08745Sheppo int
41771ae08745Sheppo ldc_write(ldc_handle_t handle, caddr_t buf, size_t *sizep)
41781ae08745Sheppo {
41791ae08745Sheppo 	ldc_chan_t	*ldcp;
41801ae08745Sheppo 	int		rv = 0;
41811ae08745Sheppo 
41821ae08745Sheppo 	if (handle == NULL) {
41831ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_write: invalid channel handle\n");
41841ae08745Sheppo 		return (EINVAL);
41851ae08745Sheppo 	}
41861ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
41871ae08745Sheppo 
4188d10e4ef2Snarayan 	/* check if writes can occur */
4189d10e4ef2Snarayan 	if (!mutex_tryenter(&ldcp->tx_lock)) {
4190d10e4ef2Snarayan 		/*
4191d10e4ef2Snarayan 		 * Could not get the lock - channel could
4192d10e4ef2Snarayan 		 * be in the process of being unconfigured
4193d10e4ef2Snarayan 		 * or reader has encountered an error
4194d10e4ef2Snarayan 		 */
4195d10e4ef2Snarayan 		return (EAGAIN);
4196d10e4ef2Snarayan 	}
41971ae08745Sheppo 
41981ae08745Sheppo 	/* check if non-zero data to write */
41991ae08745Sheppo 	if (buf == NULL || sizep == NULL) {
42001ae08745Sheppo 		DWARN(ldcp->id, "ldc_write: (0x%llx) invalid data write\n",
42011ae08745Sheppo 		    ldcp->id);
4202d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
42031ae08745Sheppo 		return (EINVAL);
42041ae08745Sheppo 	}
42051ae08745Sheppo 
42061ae08745Sheppo 	if (*sizep == 0) {
42071ae08745Sheppo 		DWARN(ldcp->id, "ldc_write: (0x%llx) write size of zero\n",
42081ae08745Sheppo 		    ldcp->id);
4209d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
42101ae08745Sheppo 		return (0);
42111ae08745Sheppo 	}
42121ae08745Sheppo 
42131ae08745Sheppo 	/* Check if channel is UP for data exchange */
42141ae08745Sheppo 	if (ldcp->tstate != TS_UP) {
42151ae08745Sheppo 		DWARN(ldcp->id,
42161ae08745Sheppo 		    "ldc_write: (0x%llx) channel is not in UP state\n",
42171ae08745Sheppo 		    ldcp->id);
42181ae08745Sheppo 		*sizep = 0;
42191ae08745Sheppo 		rv = ECONNRESET;
42201ae08745Sheppo 	} else {
42211ae08745Sheppo 		rv = ldcp->write_p(ldcp, buf, sizep);
42221ae08745Sheppo 	}
42231ae08745Sheppo 
4224d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
42251ae08745Sheppo 
42261ae08745Sheppo 	return (rv);
42271ae08745Sheppo }
42281ae08745Sheppo 
42291ae08745Sheppo /*
42301ae08745Sheppo  * Write a raw packet to the channel
42311ae08745Sheppo  * On return, size contains the number of bytes written.
42321ae08745Sheppo  */
42331ae08745Sheppo static int
42341ae08745Sheppo i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
42351ae08745Sheppo {
42361ae08745Sheppo 	ldc_msg_t 	*ldcmsg;
42371ae08745Sheppo 	uint64_t 	tx_head, tx_tail, new_tail;
42381ae08745Sheppo 	int		rv = 0;
42391ae08745Sheppo 	size_t		size;
42401ae08745Sheppo 
4241d10e4ef2Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
42421ae08745Sheppo 	ASSERT(ldcp->mode == LDC_MODE_RAW);
42431ae08745Sheppo 
42441ae08745Sheppo 	size = *sizep;
42451ae08745Sheppo 
42461ae08745Sheppo 	/*
42471ae08745Sheppo 	 * Check to see if the packet size is less than or
42481ae08745Sheppo 	 * equal to packet size support in raw mode
42491ae08745Sheppo 	 */
42501ae08745Sheppo 	if (size > ldcp->pkt_payload) {
42511ae08745Sheppo 		DWARN(ldcp->id,
42521ae08745Sheppo 		    "ldc_write: (0x%llx) invalid size (0x%llx) for RAW mode\n",
42531ae08745Sheppo 		    ldcp->id, *sizep);
42541ae08745Sheppo 		*sizep = 0;
42551ae08745Sheppo 		return (EMSGSIZE);
42561ae08745Sheppo 	}
42571ae08745Sheppo 
42581ae08745Sheppo 	/* get the qptrs for the tx queue */
42591ae08745Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
42601ae08745Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
42611ae08745Sheppo 	if (rv != 0) {
42621ae08745Sheppo 		cmn_err(CE_WARN,
42631ae08745Sheppo 		    "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
42641ae08745Sheppo 		*sizep = 0;
42651ae08745Sheppo 		return (EIO);
42661ae08745Sheppo 	}
42671ae08745Sheppo 
42681ae08745Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
42691ae08745Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
42701ae08745Sheppo 		DWARN(ldcp->id,
42711ae08745Sheppo 		    "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
4272d10e4ef2Snarayan 
42731ae08745Sheppo 		*sizep = 0;
4274d10e4ef2Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
42753af08d82Slm66018 			i_ldc_reset(ldcp, B_FALSE);
4276d10e4ef2Snarayan 			mutex_exit(&ldcp->lock);
4277d10e4ef2Snarayan 		} else {
4278d10e4ef2Snarayan 			/*
4279d10e4ef2Snarayan 			 * Release Tx lock, and then reacquire channel
4280d10e4ef2Snarayan 			 * and Tx lock in correct order
4281d10e4ef2Snarayan 			 */
4282d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
4283d10e4ef2Snarayan 			mutex_enter(&ldcp->lock);
4284d10e4ef2Snarayan 			mutex_enter(&ldcp->tx_lock);
42853af08d82Slm66018 			i_ldc_reset(ldcp, B_FALSE);
4286d10e4ef2Snarayan 			mutex_exit(&ldcp->lock);
4287d10e4ef2Snarayan 		}
42881ae08745Sheppo 		return (ECONNRESET);
42891ae08745Sheppo 	}
42901ae08745Sheppo 
42911ae08745Sheppo 	tx_tail = ldcp->tx_tail;
42921ae08745Sheppo 	tx_head = ldcp->tx_head;
42931ae08745Sheppo 	new_tail = (tx_tail + LDC_PACKET_SIZE) &
42941ae08745Sheppo 	    ((ldcp->tx_q_entries-1) << LDC_PACKET_SHIFT);
42951ae08745Sheppo 
42961ae08745Sheppo 	if (new_tail == tx_head) {
42971ae08745Sheppo 		DWARN(DBG_ALL_LDCS,
42981ae08745Sheppo 		    "ldc_write: (0x%llx) TX queue is full\n", ldcp->id);
42991ae08745Sheppo 		*sizep = 0;
43001ae08745Sheppo 		return (EWOULDBLOCK);
43011ae08745Sheppo 	}
43021ae08745Sheppo 
43031ae08745Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
43041ae08745Sheppo 	    ldcp->id, size);
43051ae08745Sheppo 
43061ae08745Sheppo 	/* Send the data now */
43071ae08745Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
43081ae08745Sheppo 
43091ae08745Sheppo 	/* copy the data into pkt */
43101ae08745Sheppo 	bcopy((uint8_t *)buf, ldcmsg, size);
43111ae08745Sheppo 
43121ae08745Sheppo 	/* increment tail */
43131ae08745Sheppo 	tx_tail = new_tail;
43141ae08745Sheppo 
43151ae08745Sheppo 	/*
43161ae08745Sheppo 	 * All packets have been copied into the TX queue
43171ae08745Sheppo 	 * update the tail ptr in the HV
43181ae08745Sheppo 	 */
43191ae08745Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
43201ae08745Sheppo 	if (rv) {
43211ae08745Sheppo 		if (rv == EWOULDBLOCK) {
43221ae08745Sheppo 			DWARN(ldcp->id, "ldc_write: (0x%llx) write timed out\n",
43231ae08745Sheppo 			    ldcp->id);
43241ae08745Sheppo 			*sizep = 0;
43251ae08745Sheppo 			return (EWOULDBLOCK);
43261ae08745Sheppo 		}
43271ae08745Sheppo 
43281ae08745Sheppo 		*sizep = 0;
4329d10e4ef2Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
43303af08d82Slm66018 			i_ldc_reset(ldcp, B_FALSE);
4331d10e4ef2Snarayan 			mutex_exit(&ldcp->lock);
4332d10e4ef2Snarayan 		} else {
4333d10e4ef2Snarayan 			/*
4334d10e4ef2Snarayan 			 * Release Tx lock, and then reacquire channel
4335d10e4ef2Snarayan 			 * and Tx lock in correct order
4336d10e4ef2Snarayan 			 */
4337d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
4338d10e4ef2Snarayan 			mutex_enter(&ldcp->lock);
4339d10e4ef2Snarayan 			mutex_enter(&ldcp->tx_lock);
43403af08d82Slm66018 			i_ldc_reset(ldcp, B_FALSE);
4341d10e4ef2Snarayan 			mutex_exit(&ldcp->lock);
4342d10e4ef2Snarayan 		}
43431ae08745Sheppo 		return (ECONNRESET);
43441ae08745Sheppo 	}
43451ae08745Sheppo 
43461ae08745Sheppo 	ldcp->tx_tail = tx_tail;
43471ae08745Sheppo 	*sizep = size;
43481ae08745Sheppo 
43491ae08745Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, size);
43501ae08745Sheppo 
43511ae08745Sheppo 	return (rv);
43521ae08745Sheppo }
43531ae08745Sheppo 
43541ae08745Sheppo 
43551ae08745Sheppo /*
43561ae08745Sheppo  * Write specified amount of bytes to the channel
43571ae08745Sheppo  * in multiple pkts of pkt_payload size. Each
43581ae08745Sheppo  * packet is tagged with an unique packet ID in
4359e1ebb9ecSlm66018  * the case of a reliable link.
43601ae08745Sheppo  *
43611ae08745Sheppo  * On return, size contains the number of bytes written.
43621ae08745Sheppo  * This function needs to ensure that the write size is < MTU size
43631ae08745Sheppo  */
43641ae08745Sheppo static int
43651ae08745Sheppo i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t buf, size_t *size)
43661ae08745Sheppo {
43671ae08745Sheppo 	ldc_msg_t 	*ldcmsg;
43681ae08745Sheppo 	uint64_t 	tx_head, tx_tail, new_tail, start;
43691ae08745Sheppo 	uint64_t	txq_size_mask, numavail;
43701ae08745Sheppo 	uint8_t 	*msgbuf, *source = (uint8_t *)buf;
43711ae08745Sheppo 	size_t 		len, bytes_written = 0, remaining;
43721ae08745Sheppo 	int		rv;
43731ae08745Sheppo 	uint32_t	curr_seqid;
43741ae08745Sheppo 
4375d10e4ef2Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
43761ae08745Sheppo 
43771ae08745Sheppo 	ASSERT(ldcp->mode == LDC_MODE_RELIABLE ||
437820ae46ebSha137994 	    ldcp->mode == LDC_MODE_UNRELIABLE);
43791ae08745Sheppo 
43801ae08745Sheppo 	/* compute mask for increment */
43811ae08745Sheppo 	txq_size_mask = (ldcp->tx_q_entries - 1) << LDC_PACKET_SHIFT;
43821ae08745Sheppo 
43831ae08745Sheppo 	/* get the qptrs for the tx queue */
43841ae08745Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
43851ae08745Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
43861ae08745Sheppo 	if (rv != 0) {
43871ae08745Sheppo 		cmn_err(CE_WARN,
43881ae08745Sheppo 		    "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
43891ae08745Sheppo 		*size = 0;
43901ae08745Sheppo 		return (EIO);
43911ae08745Sheppo 	}
43921ae08745Sheppo 
43931ae08745Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
43941ae08745Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
43951ae08745Sheppo 		DWARN(ldcp->id,
43961ae08745Sheppo 		    "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
43971ae08745Sheppo 		*size = 0;
4398d10e4ef2Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
43993af08d82Slm66018 			i_ldc_reset(ldcp, B_FALSE);
4400d10e4ef2Snarayan 			mutex_exit(&ldcp->lock);
4401d10e4ef2Snarayan 		} else {
4402d10e4ef2Snarayan 			/*
4403d10e4ef2Snarayan 			 * Release Tx lock, and then reacquire channel
4404d10e4ef2Snarayan 			 * and Tx lock in correct order
4405d10e4ef2Snarayan 			 */
4406d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
4407d10e4ef2Snarayan 			mutex_enter(&ldcp->lock);
4408d10e4ef2Snarayan 			mutex_enter(&ldcp->tx_lock);
44093af08d82Slm66018 			i_ldc_reset(ldcp, B_FALSE);
4410d10e4ef2Snarayan 			mutex_exit(&ldcp->lock);
4411d10e4ef2Snarayan 		}
44121ae08745Sheppo 		return (ECONNRESET);
44131ae08745Sheppo 	}
44141ae08745Sheppo 
44151ae08745Sheppo 	tx_tail = ldcp->tx_tail;
44161ae08745Sheppo 	new_tail = (tx_tail + LDC_PACKET_SIZE) %
44171ae08745Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
44181ae08745Sheppo 
44191ae08745Sheppo 	/*
442022f747efSnarayan 	 * Check to see if the queue is full. The check is done using
442122f747efSnarayan 	 * the appropriate head based on the link mode.
44221ae08745Sheppo 	 */
442322f747efSnarayan 	i_ldc_get_tx_head(ldcp, &tx_head);
442422f747efSnarayan 
44251ae08745Sheppo 	if (new_tail == tx_head) {
44261ae08745Sheppo 		DWARN(DBG_ALL_LDCS,
44271ae08745Sheppo 		    "ldc_write: (0x%llx) TX queue is full\n", ldcp->id);
44281ae08745Sheppo 		*size = 0;
44291ae08745Sheppo 		return (EWOULDBLOCK);
44301ae08745Sheppo 	}
44311ae08745Sheppo 
44321ae08745Sheppo 	/*
44331ae08745Sheppo 	 * Make sure that the LDC Tx queue has enough space
44341ae08745Sheppo 	 */
44351ae08745Sheppo 	numavail = (tx_head >> LDC_PACKET_SHIFT) - (tx_tail >> LDC_PACKET_SHIFT)
44361ae08745Sheppo 	    + ldcp->tx_q_entries - 1;
44371ae08745Sheppo 	numavail %= ldcp->tx_q_entries;
44381ae08745Sheppo 
44391ae08745Sheppo 	if (*size > (numavail * ldcp->pkt_payload)) {
44401ae08745Sheppo 		DWARN(DBG_ALL_LDCS,
44411ae08745Sheppo 		    "ldc_write: (0x%llx) TX queue has no space\n", ldcp->id);
44421ae08745Sheppo 		return (EWOULDBLOCK);
44431ae08745Sheppo 	}
44441ae08745Sheppo 
44451ae08745Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
44461ae08745Sheppo 	    ldcp->id, *size);
44471ae08745Sheppo 
44481ae08745Sheppo 	/* Send the data now */
44491ae08745Sheppo 	bytes_written = 0;
44501ae08745Sheppo 	curr_seqid = ldcp->last_msg_snt;
44511ae08745Sheppo 	start = tx_tail;
44521ae08745Sheppo 
44531ae08745Sheppo 	while (*size > bytes_written) {
44541ae08745Sheppo 
44551ae08745Sheppo 		ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
44561ae08745Sheppo 
445720ae46ebSha137994 		msgbuf = (uint8_t *)((ldcp->mode == LDC_MODE_RELIABLE) ?
445822f747efSnarayan 		    ldcmsg->rdata : ldcmsg->udata);
44591ae08745Sheppo 
44601ae08745Sheppo 		ldcmsg->type = LDC_DATA;
44611ae08745Sheppo 		ldcmsg->stype = LDC_INFO;
44621ae08745Sheppo 		ldcmsg->ctrl = 0;
44631ae08745Sheppo 
44641ae08745Sheppo 		remaining = *size - bytes_written;
44651ae08745Sheppo 		len = min(ldcp->pkt_payload, remaining);
44661ae08745Sheppo 		ldcmsg->env = (uint8_t)len;
44671ae08745Sheppo 
44681ae08745Sheppo 		curr_seqid++;
44691ae08745Sheppo 		ldcmsg->seqid = curr_seqid;
44701ae08745Sheppo 
44711ae08745Sheppo 		/* copy the data into pkt */
44721ae08745Sheppo 		bcopy(source, msgbuf, len);
44731ae08745Sheppo 
44741ae08745Sheppo 		source += len;
44751ae08745Sheppo 		bytes_written += len;
44761ae08745Sheppo 
44771ae08745Sheppo 		/* increment tail */
44781ae08745Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) & txq_size_mask;
44791ae08745Sheppo 
44801ae08745Sheppo 		ASSERT(tx_tail != tx_head);
44811ae08745Sheppo 	}
44821ae08745Sheppo 
44831ae08745Sheppo 	/* Set the start and stop bits */
44841ae08745Sheppo 	ldcmsg->env |= LDC_FRAG_STOP;
44851ae08745Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + start);
44861ae08745Sheppo 	ldcmsg->env |= LDC_FRAG_START;
44871ae08745Sheppo 
44881ae08745Sheppo 	/*
44891ae08745Sheppo 	 * All packets have been copied into the TX queue
44901ae08745Sheppo 	 * update the tail ptr in the HV
44911ae08745Sheppo 	 */
44921ae08745Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
44931ae08745Sheppo 	if (rv == 0) {
44941ae08745Sheppo 		ldcp->tx_tail = tx_tail;
44951ae08745Sheppo 		ldcp->last_msg_snt = curr_seqid;
44961ae08745Sheppo 		*size = bytes_written;
44971ae08745Sheppo 	} else {
44981ae08745Sheppo 		int rv2;
44991ae08745Sheppo 
45001ae08745Sheppo 		if (rv != EWOULDBLOCK) {
45011ae08745Sheppo 			*size = 0;
4502d10e4ef2Snarayan 			if (mutex_tryenter(&ldcp->lock)) {
45033af08d82Slm66018 				i_ldc_reset(ldcp, B_FALSE);
4504d10e4ef2Snarayan 				mutex_exit(&ldcp->lock);
4505d10e4ef2Snarayan 			} else {
4506d10e4ef2Snarayan 				/*
4507d10e4ef2Snarayan 				 * Release Tx lock, and then reacquire channel
4508d10e4ef2Snarayan 				 * and Tx lock in correct order
4509d10e4ef2Snarayan 				 */
4510d10e4ef2Snarayan 				mutex_exit(&ldcp->tx_lock);
4511d10e4ef2Snarayan 				mutex_enter(&ldcp->lock);
4512d10e4ef2Snarayan 				mutex_enter(&ldcp->tx_lock);
45133af08d82Slm66018 				i_ldc_reset(ldcp, B_FALSE);
4514d10e4ef2Snarayan 				mutex_exit(&ldcp->lock);
4515d10e4ef2Snarayan 			}
45161ae08745Sheppo 			return (ECONNRESET);
45171ae08745Sheppo 		}
45181ae08745Sheppo 
4519cb112a14Slm66018 		D1(ldcp->id, "hv_tx_set_tail returns 0x%x (head 0x%x, "
45201ae08745Sheppo 		    "old tail 0x%x, new tail 0x%x, qsize=0x%x)\n",
45211ae08745Sheppo 		    rv, ldcp->tx_head, ldcp->tx_tail, tx_tail,
45221ae08745Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
45231ae08745Sheppo 
45241ae08745Sheppo 		rv2 = hv_ldc_tx_get_state(ldcp->id,
45251ae08745Sheppo 		    &tx_head, &tx_tail, &ldcp->link_state);
45261ae08745Sheppo 
4527cb112a14Slm66018 		D1(ldcp->id, "hv_ldc_tx_get_state returns 0x%x "
45281ae08745Sheppo 		    "(head 0x%x, tail 0x%x state 0x%x)\n",
45291ae08745Sheppo 		    rv2, tx_head, tx_tail, ldcp->link_state);
45301ae08745Sheppo 
45311ae08745Sheppo 		*size = 0;
45321ae08745Sheppo 	}
45331ae08745Sheppo 
45341ae08745Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, *size);
45351ae08745Sheppo 
45361ae08745Sheppo 	return (rv);
45371ae08745Sheppo }
45381ae08745Sheppo 
45391ae08745Sheppo /*
45401ae08745Sheppo  * Write specified amount of bytes to the channel
45411ae08745Sheppo  * in multiple pkts of pkt_payload size. Each
45421ae08745Sheppo  * packet is tagged with an unique packet ID in
4543e1ebb9ecSlm66018  * the case of a reliable link.
45441ae08745Sheppo  *
45451ae08745Sheppo  * On return, size contains the number of bytes written.
45461ae08745Sheppo  * This function needs to ensure that the write size is < MTU size
45471ae08745Sheppo  */
45481ae08745Sheppo static int
45491ae08745Sheppo i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
45501ae08745Sheppo {
4551d10e4ef2Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
455220ae46ebSha137994 	ASSERT(ldcp->mode == LDC_MODE_RELIABLE);
45531ae08745Sheppo 
45541ae08745Sheppo 	/* Truncate packet to max of MTU size */
45551ae08745Sheppo 	if (*sizep > ldcp->mtu) *sizep = ldcp->mtu;
45561ae08745Sheppo 	return (i_ldc_write_packet(ldcp, buf, sizep));
45571ae08745Sheppo }
45581ae08745Sheppo 
45591ae08745Sheppo 
45601ae08745Sheppo /*
45611ae08745Sheppo  * Interfaces for channel nexus to register/unregister with LDC module
45621ae08745Sheppo  * The nexus will register functions to be used to register individual
45631ae08745Sheppo  * channels with the nexus and enable interrupts for the channels
45641ae08745Sheppo  */
45651ae08745Sheppo int
45661ae08745Sheppo ldc_register(ldc_cnex_t *cinfo)
45671ae08745Sheppo {
45681ae08745Sheppo 	ldc_chan_t	*ldcp;
45691ae08745Sheppo 
45701ae08745Sheppo 	if (cinfo == NULL || cinfo->dip == NULL ||
45711ae08745Sheppo 	    cinfo->reg_chan == NULL || cinfo->unreg_chan == NULL ||
45721ae08745Sheppo 	    cinfo->add_intr == NULL || cinfo->rem_intr == NULL ||
45731ae08745Sheppo 	    cinfo->clr_intr == NULL) {
45741ae08745Sheppo 
45751ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_register: invalid nexus info\n");
45761ae08745Sheppo 		return (EINVAL);
45771ae08745Sheppo 	}
45781ae08745Sheppo 
45791ae08745Sheppo 	mutex_enter(&ldcssp->lock);
45801ae08745Sheppo 
45811ae08745Sheppo 	/* nexus registration */
45821ae08745Sheppo 	ldcssp->cinfo.dip = cinfo->dip;
45831ae08745Sheppo 	ldcssp->cinfo.reg_chan = cinfo->reg_chan;
45841ae08745Sheppo 	ldcssp->cinfo.unreg_chan = cinfo->unreg_chan;
45851ae08745Sheppo 	ldcssp->cinfo.add_intr = cinfo->add_intr;
45861ae08745Sheppo 	ldcssp->cinfo.rem_intr = cinfo->rem_intr;
45871ae08745Sheppo 	ldcssp->cinfo.clr_intr = cinfo->clr_intr;
45881ae08745Sheppo 
45891ae08745Sheppo 	/* register any channels that might have been previously initialized */
45901ae08745Sheppo 	ldcp = ldcssp->chan_list;
45911ae08745Sheppo 	while (ldcp) {
45921ae08745Sheppo 		if ((ldcp->tstate & TS_QCONF_RDY) &&
45931ae08745Sheppo 		    (ldcp->tstate & TS_CNEX_RDY) == 0)
45941ae08745Sheppo 			(void) i_ldc_register_channel(ldcp);
45951ae08745Sheppo 
45961ae08745Sheppo 		ldcp = ldcp->next;
45971ae08745Sheppo 	}
45981ae08745Sheppo 
45991ae08745Sheppo 	mutex_exit(&ldcssp->lock);
46001ae08745Sheppo 
46011ae08745Sheppo 	return (0);
46021ae08745Sheppo }
46031ae08745Sheppo 
46041ae08745Sheppo int
46051ae08745Sheppo ldc_unregister(ldc_cnex_t *cinfo)
46061ae08745Sheppo {
46071ae08745Sheppo 	if (cinfo == NULL || cinfo->dip == NULL) {
46081ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid nexus info\n");
46091ae08745Sheppo 		return (EINVAL);
46101ae08745Sheppo 	}
46111ae08745Sheppo 
46121ae08745Sheppo 	mutex_enter(&ldcssp->lock);
46131ae08745Sheppo 
46141ae08745Sheppo 	if (cinfo->dip != ldcssp->cinfo.dip) {
46151ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid dip\n");
46161ae08745Sheppo 		mutex_exit(&ldcssp->lock);
46171ae08745Sheppo 		return (EINVAL);
46181ae08745Sheppo 	}
46191ae08745Sheppo 
46201ae08745Sheppo 	/* nexus unregister */
46211ae08745Sheppo 	ldcssp->cinfo.dip = NULL;
46221ae08745Sheppo 	ldcssp->cinfo.reg_chan = NULL;
46231ae08745Sheppo 	ldcssp->cinfo.unreg_chan = NULL;
46241ae08745Sheppo 	ldcssp->cinfo.add_intr = NULL;
46251ae08745Sheppo 	ldcssp->cinfo.rem_intr = NULL;
46261ae08745Sheppo 	ldcssp->cinfo.clr_intr = NULL;
46271ae08745Sheppo 
46281ae08745Sheppo 	mutex_exit(&ldcssp->lock);
46291ae08745Sheppo 
46301ae08745Sheppo 	return (0);
46311ae08745Sheppo }
4632