xref: /onnv-gate/usr/src/uts/sun4v/io/ldc.c (revision 6408:2dba2c05f7fb)
11991Sheppo /*
21991Sheppo  * CDDL HEADER START
31991Sheppo  *
41991Sheppo  * The contents of this file are subject to the terms of the
51991Sheppo  * Common Development and Distribution License (the "License").
61991Sheppo  * You may not use this file except in compliance with the License.
71991Sheppo  *
81991Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91991Sheppo  * or http://www.opensolaris.org/os/licensing.
101991Sheppo  * See the License for the specific language governing permissions
111991Sheppo  * and limitations under the License.
121991Sheppo  *
131991Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141991Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151991Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161991Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171991Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181991Sheppo  *
191991Sheppo  * CDDL HEADER END
201991Sheppo  */
211991Sheppo 
221991Sheppo /*
235944Sha137994  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241991Sheppo  * Use is subject to license terms.
251991Sheppo  */
261991Sheppo 
271991Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
281991Sheppo 
291991Sheppo /*
302410Slm66018  * sun4v LDC Link Layer
311991Sheppo  */
321991Sheppo #include <sys/types.h>
331991Sheppo #include <sys/file.h>
341991Sheppo #include <sys/errno.h>
351991Sheppo #include <sys/open.h>
361991Sheppo #include <sys/cred.h>
371991Sheppo #include <sys/kmem.h>
381991Sheppo #include <sys/conf.h>
391991Sheppo #include <sys/cmn_err.h>
401991Sheppo #include <sys/ksynch.h>
411991Sheppo #include <sys/modctl.h>
421991Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */
431991Sheppo #include <sys/debug.h>
441991Sheppo #include <sys/cred.h>
451991Sheppo #include <sys/promif.h>
461991Sheppo #include <sys/ddi.h>
471991Sheppo #include <sys/sunddi.h>
481991Sheppo #include <sys/cyclic.h>
491991Sheppo #include <sys/machsystm.h>
501991Sheppo #include <sys/vm.h>
511991Sheppo #include <sys/cpu.h>
521991Sheppo #include <sys/intreg.h>
531991Sheppo #include <sys/machcpuvar.h>
542531Snarayan #include <sys/mmu.h>
552531Snarayan #include <sys/pte.h>
562531Snarayan #include <vm/hat.h>
572531Snarayan #include <vm/as.h>
582531Snarayan #include <vm/hat_sfmmu.h>
592531Snarayan #include <sys/vm_machparam.h>
602531Snarayan #include <vm/seg_kmem.h>
612531Snarayan #include <vm/seg_kpm.h>
621991Sheppo #include <sys/note.h>
631991Sheppo #include <sys/ivintr.h>
641991Sheppo #include <sys/hypervisor_api.h>
651991Sheppo #include <sys/ldc.h>
661991Sheppo #include <sys/ldc_impl.h>
671991Sheppo #include <sys/cnex.h>
681991Sheppo #include <sys/hsvc.h>
695944Sha137994 #include <sys/sdt.h>
701991Sheppo 
711991Sheppo /* Core internal functions */
72*6408Sha137994 int i_ldc_h2v_error(int h_error);
73*6408Sha137994 void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset);
74*6408Sha137994 
751991Sheppo static int i_ldc_txq_reconf(ldc_chan_t *ldcp);
762793Slm66018 static int i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset);
772841Snarayan static int i_ldc_rxq_drain(ldc_chan_t *ldcp);
781991Sheppo static void i_ldc_reset_state(ldc_chan_t *ldcp);
791991Sheppo 
801991Sheppo static int i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail);
814690Snarayan static void i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head);
821991Sheppo static int i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail);
831991Sheppo static int i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head);
841991Sheppo static int i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
851991Sheppo     uint8_t ctrlmsg);
861991Sheppo 
875944Sha137994 static int  i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head);
885944Sha137994 static void i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head);
895944Sha137994 static uint64_t i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head,
905944Sha137994     uint64_t *tail, uint64_t *link_state);
915944Sha137994 static uint64_t i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head,
925944Sha137994     uint64_t *tail, uint64_t *link_state);
935944Sha137994 static int i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head,
945944Sha137994     uint64_t rx_tail);
955944Sha137994 static uint_t i_ldc_chkq(ldc_chan_t *ldcp);
965944Sha137994 
971991Sheppo /* Interrupt handling functions */
981991Sheppo static uint_t i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2);
991991Sheppo static uint_t i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2);
1005944Sha137994 static uint_t i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client,
1015944Sha137994     uint64_t *notify_event);
1021991Sheppo static void i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype);
1031991Sheppo 
1041991Sheppo /* Read method functions */
1051991Sheppo static int i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep);
1061991Sheppo static int i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp,
1071991Sheppo 	size_t *sizep);
1081991Sheppo static int i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp,
1091991Sheppo 	size_t *sizep);
1101991Sheppo 
1111991Sheppo /* Write method functions */
1121991Sheppo static int i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t target_bufp,
1131991Sheppo 	size_t *sizep);
1141991Sheppo static int i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t target_bufp,
1151991Sheppo 	size_t *sizep);
1161991Sheppo static int i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t target_bufp,
1171991Sheppo 	size_t *sizep);
1181991Sheppo 
1191991Sheppo /* Pkt processing internal functions */
1201991Sheppo static int i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg);
1211991Sheppo static int i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg);
1221991Sheppo static int i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg);
1231991Sheppo static int i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg);
1241991Sheppo static int i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg);
1251991Sheppo static int i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg);
1261991Sheppo static int i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg);
1271991Sheppo 
1281991Sheppo /* LDC Version */
1291991Sheppo static ldc_ver_t ldc_versions[] = { {1, 0} };
1301991Sheppo 
1311991Sheppo /* number of supported versions */
1321991Sheppo #define	LDC_NUM_VERS	(sizeof (ldc_versions) / sizeof (ldc_versions[0]))
1331991Sheppo 
1345944Sha137994 /* Invalid value for the ldc_chan_t rx_ack_head field */
1355944Sha137994 #define	ACKPEEK_HEAD_INVALID	((uint64_t)-1)
1365944Sha137994 
1375944Sha137994 
1381991Sheppo /* Module State Pointer */
139*6408Sha137994 ldc_soft_state_t *ldcssp;
1401991Sheppo 
1411991Sheppo static struct modldrv md = {
1421991Sheppo 	&mod_miscops,			/* This is a misc module */
1431991Sheppo 	"sun4v LDC module v%I%",	/* Name of the module */
1441991Sheppo };
1451991Sheppo 
1461991Sheppo static struct modlinkage ml = {
1471991Sheppo 	MODREV_1,
1481991Sheppo 	&md,
1491991Sheppo 	NULL
1501991Sheppo };
1511991Sheppo 
1521991Sheppo static uint64_t ldc_sup_minor;		/* Supported minor number */
1531991Sheppo static hsvc_info_t ldc_hsvc = {
1541991Sheppo 	HSVC_REV_1, NULL, HSVC_GROUP_LDC, 1, 0, "ldc"
1551991Sheppo };
1561991Sheppo 
1572531Snarayan /*
1582410Slm66018  * The no. of MTU size messages that can be stored in
1592410Slm66018  * the LDC Tx queue. The number of Tx queue entries is
1602410Slm66018  * then computed as (mtu * mtu_msgs)/sizeof(queue_entry)
1612410Slm66018  */
1622410Slm66018 uint64_t ldc_mtu_msgs = LDC_MTU_MSGS;
1632410Slm66018 
1642410Slm66018 /*
1652410Slm66018  * The minimum queue length. This is the size of the smallest
1662410Slm66018  * LDC queue. If the computed value is less than this default,
1672410Slm66018  * the queue length is rounded up to 'ldc_queue_entries'.
1682410Slm66018  */
1692410Slm66018 uint64_t ldc_queue_entries = LDC_QUEUE_ENTRIES;
1702410Slm66018 
1712410Slm66018 /*
1725944Sha137994  * The length of the reliable-mode data queue in terms of the LDC
1735944Sha137994  * receive queue length. i.e., the number of times larger than the
1745944Sha137994  * LDC receive queue that the data queue should be. The HV receive
1755944Sha137994  * queue is required to be a power of 2 and this implementation
1765944Sha137994  * assumes the data queue will also be a power of 2. By making the
1775944Sha137994  * multiplier a power of 2, we ensure the data queue will be a
1785944Sha137994  * power of 2. We use a multiplier because the receive queue is
1795944Sha137994  * sized to be sane relative to the MTU and the same is needed for
1805944Sha137994  * the data queue.
1815944Sha137994  */
1825944Sha137994 uint64_t ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER;
1835944Sha137994 
1845944Sha137994 /*
1852410Slm66018  * LDC retry count and delay - when the HV returns EWOULDBLOCK
1862410Slm66018  * the operation is retried 'ldc_max_retries' times with a
1872410Slm66018  * wait of 'ldc_delay' usecs between each retry.
1882032Slm66018  */
1892032Slm66018 int ldc_max_retries = LDC_MAX_RETRIES;
1902032Slm66018 clock_t ldc_delay = LDC_DELAY;
1912032Slm66018 
1923151Ssg70180 /*
1933151Ssg70180  * delay between each retry of channel unregistration in
1943151Ssg70180  * ldc_close(), to wait for pending interrupts to complete.
1953151Ssg70180  */
1963151Ssg70180 clock_t ldc_close_delay = LDC_CLOSE_DELAY;
1973151Ssg70180 
1981991Sheppo #ifdef DEBUG
1991991Sheppo 
2001991Sheppo /*
2011991Sheppo  * Print debug messages
2021991Sheppo  *
2031991Sheppo  * set ldcdbg to 0x7 for enabling all msgs
2041991Sheppo  * 0x4 - Warnings
2051991Sheppo  * 0x2 - All debug messages
2061991Sheppo  * 0x1 - Minimal debug messages
2071991Sheppo  *
2081991Sheppo  * set ldcdbgchan to the channel number you want to debug
2091991Sheppo  * setting it to -1 prints debug messages for all channels
2101991Sheppo  * NOTE: ldcdbgchan has no effect on error messages
2111991Sheppo  */
2121991Sheppo 
2131991Sheppo int ldcdbg = 0x0;
2141991Sheppo int64_t ldcdbgchan = DBG_ALL_LDCS;
2153560Snarayan uint64_t ldc_inject_err_flag = 0;
2161991Sheppo 
217*6408Sha137994 void
2181991Sheppo ldcdebug(int64_t id, const char *fmt, ...)
2191991Sheppo {
2201991Sheppo 	char buf[512];
2211991Sheppo 	va_list ap;
2221991Sheppo 
2231991Sheppo 	/*
2241991Sheppo 	 * Do not return if,
2251991Sheppo 	 * caller wants to print it anyway - (id == DBG_ALL_LDCS)
2261991Sheppo 	 * debug channel is set to all LDCs - (ldcdbgchan == DBG_ALL_LDCS)
2271991Sheppo 	 * debug channel = caller specified channel
2281991Sheppo 	 */
2291991Sheppo 	if ((id != DBG_ALL_LDCS) &&
2301991Sheppo 	    (ldcdbgchan != DBG_ALL_LDCS) &&
2311991Sheppo 	    (ldcdbgchan != id)) {
2321991Sheppo 		return;
2331991Sheppo 	}
2341991Sheppo 
2351991Sheppo 	va_start(ap, fmt);
2361991Sheppo 	(void) vsprintf(buf, fmt, ap);
2371991Sheppo 	va_end(ap);
2381991Sheppo 
2392793Slm66018 	cmn_err(CE_CONT, "?%s", buf);
2402793Slm66018 }
2412793Slm66018 
2423560Snarayan #define	LDC_ERR_RESET	0x1
2433560Snarayan #define	LDC_ERR_PKTLOSS	0x2
2445944Sha137994 #define	LDC_ERR_DQFULL	0x4
2453560Snarayan 
2462793Slm66018 static boolean_t
2473560Snarayan ldc_inject_error(ldc_chan_t *ldcp, uint64_t error)
2482793Slm66018 {
2492793Slm66018 	if ((ldcdbgchan != DBG_ALL_LDCS) && (ldcdbgchan != ldcp->id))
2502793Slm66018 		return (B_FALSE);
2512793Slm66018 
2523560Snarayan 	if ((ldc_inject_err_flag & error) == 0)
2532793Slm66018 		return (B_FALSE);
2542793Slm66018 
2552793Slm66018 	/* clear the injection state */
2563560Snarayan 	ldc_inject_err_flag &= ~error;
2572793Slm66018 
2582793Slm66018 	return (B_TRUE);
2591991Sheppo }
2601991Sheppo 
2611991Sheppo #define	D1		\
2621991Sheppo if (ldcdbg & 0x01)	\
2631991Sheppo 	ldcdebug
2641991Sheppo 
2651991Sheppo #define	D2		\
2661991Sheppo if (ldcdbg & 0x02)	\
2671991Sheppo 	ldcdebug
2681991Sheppo 
2691991Sheppo #define	DWARN		\
2701991Sheppo if (ldcdbg & 0x04)	\
2711991Sheppo 	ldcdebug
2721991Sheppo 
2731991Sheppo #define	DUMP_PAYLOAD(id, addr)						\
2741991Sheppo {									\
2751991Sheppo 	char buf[65*3];							\
2761991Sheppo 	int i;								\
2771991Sheppo 	uint8_t *src = (uint8_t *)addr;					\
2781991Sheppo 	for (i = 0; i < 64; i++, src++)					\
2791991Sheppo 		(void) sprintf(&buf[i * 3], "|%02x", *src);		\
2801991Sheppo 	(void) sprintf(&buf[i * 3], "|\n");				\
2811991Sheppo 	D2((id), "payload: %s", buf);					\
2821991Sheppo }
2831991Sheppo 
2841991Sheppo #define	DUMP_LDC_PKT(c, s, addr)					\
2851991Sheppo {									\
2861991Sheppo 	ldc_msg_t *msg = (ldc_msg_t *)(addr);				\
2871991Sheppo 	uint32_t mid = ((c)->mode != LDC_MODE_RAW) ? msg->seqid : 0;	\
2881991Sheppo 	if (msg->type == LDC_DATA) {                                    \
2891991Sheppo 	    D2((c)->id, "%s: msg%d (/%x/%x/%x/,env[%c%c,sz=%d])",	\
2901991Sheppo 	    (s), mid, msg->type, msg->stype, msg->ctrl,			\
2911991Sheppo 	    (msg->env & LDC_FRAG_START) ? 'B' : ' ',                    \
2921991Sheppo 	    (msg->env & LDC_FRAG_STOP) ? 'E' : ' ',                     \
2931991Sheppo 	    (msg->env & LDC_LEN_MASK));					\
2941991Sheppo 	} else { 							\
2951991Sheppo 	    D2((c)->id, "%s: msg%d (/%x/%x/%x/,env=%x)", (s),		\
2961991Sheppo 	    mid, msg->type, msg->stype, msg->ctrl, msg->env);		\
2971991Sheppo 	} 								\
2981991Sheppo }
2991991Sheppo 
3003560Snarayan #define	LDC_INJECT_RESET(_ldcp)	ldc_inject_error(_ldcp, LDC_ERR_RESET)
3013560Snarayan #define	LDC_INJECT_PKTLOSS(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_PKTLOSS)
3025944Sha137994 #define	LDC_INJECT_DQFULL(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DQFULL)
3032793Slm66018 
3041991Sheppo #else
3051991Sheppo 
3061991Sheppo #define	DBG_ALL_LDCS -1
3071991Sheppo 
3081991Sheppo #define	D1
3091991Sheppo #define	D2
3101991Sheppo #define	DWARN
3111991Sheppo 
3121991Sheppo #define	DUMP_PAYLOAD(id, addr)
3131991Sheppo #define	DUMP_LDC_PKT(c, s, addr)
3141991Sheppo 
3152793Slm66018 #define	LDC_INJECT_RESET(_ldcp)	(B_FALSE)
3163560Snarayan #define	LDC_INJECT_PKTLOSS(_ldcp) (B_FALSE)
3175944Sha137994 #define	LDC_INJECT_DQFULL(_ldcp) (B_FALSE)
3182793Slm66018 
3191991Sheppo #endif
3201991Sheppo 
3215944Sha137994 /*
3225944Sha137994  * dtrace SDT probes to ease tracing of the rx data queue and HV queue
3235944Sha137994  * lengths. Just pass the head, tail, and entries values so that the
3245944Sha137994  * length can be calculated in a dtrace script when the probe is enabled.
3255944Sha137994  */
3265944Sha137994 #define	TRACE_RXDQ_LENGTH(ldcp)						\
3275944Sha137994 	DTRACE_PROBE4(rxdq__size,					\
3285944Sha137994 	uint64_t, ldcp->id,						\
3295944Sha137994 	uint64_t, ldcp->rx_dq_head,					\
3305944Sha137994 	uint64_t, ldcp->rx_dq_tail,					\
3315944Sha137994 	uint64_t, ldcp->rx_dq_entries)
3325944Sha137994 
3335944Sha137994 #define	TRACE_RXHVQ_LENGTH(ldcp, head, tail)				\
3345944Sha137994 	DTRACE_PROBE4(rxhvq__size,					\
3355944Sha137994 	uint64_t, ldcp->id,						\
3365944Sha137994 	uint64_t, head,							\
3375944Sha137994 	uint64_t, tail,							\
3385944Sha137994 	uint64_t, ldcp->rx_q_entries)
3395944Sha137994 
3405944Sha137994 /* A dtrace SDT probe to ease tracing of data queue copy operations */
3415944Sha137994 #define	TRACE_RXDQ_COPY(ldcp, bytes)					\
3425944Sha137994 	DTRACE_PROBE2(rxdq__copy, uint64_t, ldcp->id, uint64_t, bytes)	\
3435944Sha137994 
3445944Sha137994 /* The amount of contiguous space at the tail of the queue */
3455944Sha137994 #define	Q_CONTIG_SPACE(head, tail, size)				\
3465944Sha137994 	((head) <= (tail) ? ((size) - (tail)) :				\
3475944Sha137994 	((head) - (tail) - LDC_PACKET_SIZE))
3485944Sha137994 
3491991Sheppo #define	ZERO_PKT(p)			\
3501991Sheppo 	bzero((p), sizeof (ldc_msg_t));
3511991Sheppo 
3521991Sheppo #define	IDX2COOKIE(idx, pg_szc, pg_shift)				\
3531991Sheppo 	(((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift)))
3541991Sheppo 
3551991Sheppo int
3561991Sheppo _init(void)
3571991Sheppo {
3581991Sheppo 	int status;
3591991Sheppo 
3601991Sheppo 	status = hsvc_register(&ldc_hsvc, &ldc_sup_minor);
3611991Sheppo 	if (status != 0) {
3624423Sjb145095 		cmn_err(CE_NOTE, "!%s: cannot negotiate hypervisor LDC services"
3631991Sheppo 		    " group: 0x%lx major: %ld minor: %ld errno: %d",
3641991Sheppo 		    ldc_hsvc.hsvc_modname, ldc_hsvc.hsvc_group,
3651991Sheppo 		    ldc_hsvc.hsvc_major, ldc_hsvc.hsvc_minor, status);
3661991Sheppo 		return (-1);
3671991Sheppo 	}
3681991Sheppo 
3691991Sheppo 	/* allocate soft state structure */
3701991Sheppo 	ldcssp = kmem_zalloc(sizeof (ldc_soft_state_t), KM_SLEEP);
3711991Sheppo 
3721991Sheppo 	/* Link the module into the system */
3731991Sheppo 	status = mod_install(&ml);
3741991Sheppo 	if (status != 0) {
3751991Sheppo 		kmem_free(ldcssp, sizeof (ldc_soft_state_t));
3761991Sheppo 		return (status);
3771991Sheppo 	}
3781991Sheppo 
3791991Sheppo 	/* Initialize the LDC state structure */
3801991Sheppo 	mutex_init(&ldcssp->lock, NULL, MUTEX_DRIVER, NULL);
3811991Sheppo 
3821991Sheppo 	mutex_enter(&ldcssp->lock);
3831991Sheppo 
3842531Snarayan 	/* Create a cache for memory handles */
3852531Snarayan 	ldcssp->memhdl_cache = kmem_cache_create("ldc_memhdl_cache",
3862531Snarayan 	    sizeof (ldc_mhdl_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
3872531Snarayan 	if (ldcssp->memhdl_cache == NULL) {
3882531Snarayan 		DWARN(DBG_ALL_LDCS, "_init: ldc_memhdl cache create failed\n");
3892531Snarayan 		mutex_exit(&ldcssp->lock);
3902531Snarayan 		return (-1);
3912531Snarayan 	}
3922531Snarayan 
3932531Snarayan 	/* Create cache for memory segment structures */
3942531Snarayan 	ldcssp->memseg_cache = kmem_cache_create("ldc_memseg_cache",
3952531Snarayan 	    sizeof (ldc_memseg_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
3962531Snarayan 	if (ldcssp->memseg_cache == NULL) {
3972531Snarayan 		DWARN(DBG_ALL_LDCS, "_init: ldc_memseg cache create failed\n");
3982531Snarayan 		mutex_exit(&ldcssp->lock);
3992531Snarayan 		return (-1);
4002531Snarayan 	}
4012531Snarayan 
4022531Snarayan 
4031991Sheppo 	ldcssp->channel_count = 0;
4041991Sheppo 	ldcssp->channels_open = 0;
4051991Sheppo 	ldcssp->chan_list = NULL;
4061991Sheppo 	ldcssp->dring_list = NULL;
4071991Sheppo 
4081991Sheppo 	mutex_exit(&ldcssp->lock);
4091991Sheppo 
4101991Sheppo 	return (0);
4111991Sheppo }
4121991Sheppo 
4131991Sheppo int
4141991Sheppo _info(struct modinfo *modinfop)
4151991Sheppo {
4161991Sheppo 	/* Report status of the dynamically loadable driver module */
4171991Sheppo 	return (mod_info(&ml, modinfop));
4181991Sheppo }
4191991Sheppo 
4201991Sheppo int
4211991Sheppo _fini(void)
4221991Sheppo {
4231991Sheppo 	int 		rv, status;
4244690Snarayan 	ldc_chan_t 	*tmp_ldcp, *ldcp;
4254690Snarayan 	ldc_dring_t 	*tmp_dringp, *dringp;
4261991Sheppo 	ldc_mem_info_t 	minfo;
4271991Sheppo 
4281991Sheppo 	/* Unlink the driver module from the system */
4291991Sheppo 	status = mod_remove(&ml);
4301991Sheppo 	if (status) {
4311991Sheppo 		DWARN(DBG_ALL_LDCS, "_fini: mod_remove failed\n");
4321991Sheppo 		return (EIO);
4331991Sheppo 	}
4341991Sheppo 
4351991Sheppo 	/* Free descriptor rings */
4361991Sheppo 	dringp = ldcssp->dring_list;
4371991Sheppo 	while (dringp != NULL) {
4384690Snarayan 		tmp_dringp = dringp->next;
4391991Sheppo 
4401991Sheppo 		rv = ldc_mem_dring_info((ldc_dring_handle_t)dringp, &minfo);
4411991Sheppo 		if (rv == 0 && minfo.status != LDC_UNBOUND) {
4421991Sheppo 			if (minfo.status == LDC_BOUND) {
4431991Sheppo 				(void) ldc_mem_dring_unbind(
4444690Snarayan 				    (ldc_dring_handle_t)dringp);
4451991Sheppo 			}
4461991Sheppo 			if (minfo.status == LDC_MAPPED) {
4471991Sheppo 				(void) ldc_mem_dring_unmap(
4484690Snarayan 				    (ldc_dring_handle_t)dringp);
4491991Sheppo 			}
4501991Sheppo 		}
4511991Sheppo 
4521991Sheppo 		(void) ldc_mem_dring_destroy((ldc_dring_handle_t)dringp);
4534690Snarayan 		dringp = tmp_dringp;
4541991Sheppo 	}
4551991Sheppo 	ldcssp->dring_list = NULL;
4561991Sheppo 
4574690Snarayan 	/* close and finalize channels */
4584690Snarayan 	ldcp = ldcssp->chan_list;
4594690Snarayan 	while (ldcp != NULL) {
4604690Snarayan 		tmp_ldcp = ldcp->next;
4614690Snarayan 
4624690Snarayan 		(void) ldc_close((ldc_handle_t)ldcp);
4634690Snarayan 		(void) ldc_fini((ldc_handle_t)ldcp);
4644690Snarayan 
4654690Snarayan 		ldcp = tmp_ldcp;
4664690Snarayan 	}
4674690Snarayan 	ldcssp->chan_list = NULL;
4684690Snarayan 
4692531Snarayan 	/* Destroy kmem caches */
4702531Snarayan 	kmem_cache_destroy(ldcssp->memhdl_cache);
4712531Snarayan 	kmem_cache_destroy(ldcssp->memseg_cache);
4722531Snarayan 
4731991Sheppo 	/*
4741991Sheppo 	 * We have successfully "removed" the driver.
4751991Sheppo 	 * Destroying soft states
4761991Sheppo 	 */
4771991Sheppo 	mutex_destroy(&ldcssp->lock);
4781991Sheppo 	kmem_free(ldcssp, sizeof (ldc_soft_state_t));
4791991Sheppo 
4801991Sheppo 	(void) hsvc_unregister(&ldc_hsvc);
4811991Sheppo 
4821991Sheppo 	return (status);
4831991Sheppo }
4841991Sheppo 
4851991Sheppo /* -------------------------------------------------------------------------- */
4861991Sheppo 
4871991Sheppo /*
4882410Slm66018  * LDC Link Layer Internal Functions
4891991Sheppo  */
4901991Sheppo 
4911991Sheppo /*
4921991Sheppo  * Translate HV Errors to sun4v error codes
4931991Sheppo  */
494*6408Sha137994 int
4951991Sheppo i_ldc_h2v_error(int h_error)
4961991Sheppo {
4971991Sheppo 	switch (h_error) {
4981991Sheppo 
4991991Sheppo 	case	H_EOK:
5001991Sheppo 		return (0);
5011991Sheppo 
5021991Sheppo 	case	H_ENORADDR:
5031991Sheppo 		return (EFAULT);
5041991Sheppo 
5051991Sheppo 	case	H_EBADPGSZ:
5061991Sheppo 	case	H_EINVAL:
5071991Sheppo 		return (EINVAL);
5081991Sheppo 
5091991Sheppo 	case	H_EWOULDBLOCK:
5101991Sheppo 		return (EWOULDBLOCK);
5111991Sheppo 
5121991Sheppo 	case	H_ENOACCESS:
5131991Sheppo 	case	H_ENOMAP:
5141991Sheppo 		return (EACCES);
5151991Sheppo 
5161991Sheppo 	case	H_EIO:
5171991Sheppo 	case	H_ECPUERROR:
5181991Sheppo 		return (EIO);
5191991Sheppo 
5201991Sheppo 	case	H_ENOTSUPPORTED:
5211991Sheppo 		return (ENOTSUP);
5221991Sheppo 
5231991Sheppo 	case 	H_ETOOMANY:
5241991Sheppo 		return (ENOSPC);
5251991Sheppo 
5261991Sheppo 	case	H_ECHANNEL:
5271991Sheppo 		return (ECHRNG);
5281991Sheppo 	default:
5291991Sheppo 		break;
5301991Sheppo 	}
5311991Sheppo 
5321991Sheppo 	return (EIO);
5331991Sheppo }
5341991Sheppo 
5351991Sheppo /*
5361991Sheppo  * Reconfigure the transmit queue
5371991Sheppo  */
5381991Sheppo static int
5391991Sheppo i_ldc_txq_reconf(ldc_chan_t *ldcp)
5401991Sheppo {
5411991Sheppo 	int rv;
5421991Sheppo 
5431991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
5442336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
5452336Snarayan 
5461991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
5471991Sheppo 	if (rv) {
5481991Sheppo 		cmn_err(CE_WARN,
5492793Slm66018 		    "i_ldc_txq_reconf: (0x%lx) cannot set qconf", ldcp->id);
5501991Sheppo 		return (EIO);
5511991Sheppo 	}
5521991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id, &(ldcp->tx_head),
5531991Sheppo 	    &(ldcp->tx_tail), &(ldcp->link_state));
5541991Sheppo 	if (rv) {
5551991Sheppo 		cmn_err(CE_WARN,
5562793Slm66018 		    "i_ldc_txq_reconf: (0x%lx) cannot get qptrs", ldcp->id);
5571991Sheppo 		return (EIO);
5581991Sheppo 	}
5592793Slm66018 	D1(ldcp->id, "i_ldc_txq_reconf: (0x%llx) h=0x%llx,t=0x%llx,"
5601991Sheppo 	    "s=0x%llx\n", ldcp->id, ldcp->tx_head, ldcp->tx_tail,
5611991Sheppo 	    ldcp->link_state);
5621991Sheppo 
5631991Sheppo 	return (0);
5641991Sheppo }
5651991Sheppo 
5661991Sheppo /*
5671991Sheppo  * Reconfigure the receive queue
5681991Sheppo  */
5691991Sheppo static int
5702793Slm66018 i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset)
5711991Sheppo {
5721991Sheppo 	int rv;
5731991Sheppo 	uint64_t rx_head, rx_tail;
5741991Sheppo 
5751991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
5761991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
5771991Sheppo 	    &(ldcp->link_state));
5781991Sheppo 	if (rv) {
5791991Sheppo 		cmn_err(CE_WARN,
5802793Slm66018 		    "i_ldc_rxq_reconf: (0x%lx) cannot get state",
5811991Sheppo 		    ldcp->id);
5821991Sheppo 		return (EIO);
5831991Sheppo 	}
5841991Sheppo 
5852793Slm66018 	if (force_reset || (ldcp->tstate & ~TS_IN_RESET) == TS_UP) {
5861991Sheppo 		rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra,
5874690Snarayan 		    ldcp->rx_q_entries);
5881991Sheppo 		if (rv) {
5891991Sheppo 			cmn_err(CE_WARN,
5902793Slm66018 			    "i_ldc_rxq_reconf: (0x%lx) cannot set qconf",
5911991Sheppo 			    ldcp->id);
5921991Sheppo 			return (EIO);
5931991Sheppo 		}
5942793Slm66018 		D1(ldcp->id, "i_ldc_rxq_reconf: (0x%llx) completed q reconf",
5951991Sheppo 		    ldcp->id);
5961991Sheppo 	}
5971991Sheppo 
5981991Sheppo 	return (0);
5991991Sheppo }
6001991Sheppo 
6012841Snarayan 
6022841Snarayan /*
6032841Snarayan  * Drain the contents of the receive queue
6042841Snarayan  */
6052841Snarayan static int
6062841Snarayan i_ldc_rxq_drain(ldc_chan_t *ldcp)
6072841Snarayan {
6082841Snarayan 	int rv;
6092841Snarayan 	uint64_t rx_head, rx_tail;
6102841Snarayan 
6112841Snarayan 	ASSERT(MUTEX_HELD(&ldcp->lock));
6122841Snarayan 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
6132841Snarayan 	    &(ldcp->link_state));
6142841Snarayan 	if (rv) {
6152841Snarayan 		cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot get state",
6162841Snarayan 		    ldcp->id);
6172841Snarayan 		return (EIO);
6182841Snarayan 	}
6192841Snarayan 
6202841Snarayan 	/* flush contents by setting the head = tail */
6212841Snarayan 	return (i_ldc_set_rx_head(ldcp, rx_tail));
6222841Snarayan }
6232841Snarayan 
6242841Snarayan 
6251991Sheppo /*
6261991Sheppo  * Reset LDC state structure and its contents
6271991Sheppo  */
6281991Sheppo static void
6291991Sheppo i_ldc_reset_state(ldc_chan_t *ldcp)
6301991Sheppo {
6311991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
6321991Sheppo 	ldcp->last_msg_snt = LDC_INIT_SEQID;
6331991Sheppo 	ldcp->last_ack_rcd = 0;
6341991Sheppo 	ldcp->last_msg_rcd = 0;
6351991Sheppo 	ldcp->tx_ackd_head = ldcp->tx_head;
6365944Sha137994 	ldcp->stream_remains = 0;
6371991Sheppo 	ldcp->next_vidx = 0;
6381991Sheppo 	ldcp->hstate = 0;
6391991Sheppo 	ldcp->tstate = TS_OPEN;
6401991Sheppo 	ldcp->status = LDC_OPEN;
6415944Sha137994 	ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
6425944Sha137994 	ldcp->rx_dq_head = 0;
6435944Sha137994 	ldcp->rx_dq_tail = 0;
6441991Sheppo 
6451991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_UP ||
6461991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
6471991Sheppo 
6481991Sheppo 		if (ldcp->mode == LDC_MODE_RAW) {
6491991Sheppo 			ldcp->status = LDC_UP;
6501991Sheppo 			ldcp->tstate = TS_UP;
6511991Sheppo 		} else {
6521991Sheppo 			ldcp->status = LDC_READY;
6531991Sheppo 			ldcp->tstate |= TS_LINK_READY;
6541991Sheppo 		}
6551991Sheppo 	}
6561991Sheppo }
6571991Sheppo 
6581991Sheppo /*
6591991Sheppo  * Reset a LDC channel
6601991Sheppo  */
661*6408Sha137994 void
6622793Slm66018 i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset)
6631991Sheppo {
6643560Snarayan 	DWARN(ldcp->id, "i_ldc_reset: (0x%llx) channel reset\n", ldcp->id);
6651991Sheppo 
6662336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->lock));
6672336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
6682336Snarayan 
6692793Slm66018 	/* reconfig Tx and Rx queues */
6701991Sheppo 	(void) i_ldc_txq_reconf(ldcp);
6712793Slm66018 	(void) i_ldc_rxq_reconf(ldcp, force_reset);
6722793Slm66018 
6732793Slm66018 	/* Clear Tx and Rx interrupts */
6742793Slm66018 	(void) i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
6752793Slm66018 	(void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
6762793Slm66018 
6772793Slm66018 	/* Reset channel state */
6781991Sheppo 	i_ldc_reset_state(ldcp);
6792793Slm66018 
6802793Slm66018 	/* Mark channel in reset */
6812793Slm66018 	ldcp->tstate |= TS_IN_RESET;
6821991Sheppo }
6831991Sheppo 
6842531Snarayan 
6851991Sheppo /*
6861991Sheppo  * Clear pending interrupts
6871991Sheppo  */
6881991Sheppo static void
6891991Sheppo i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype)
6901991Sheppo {
6911991Sheppo 	ldc_cnex_t *cinfo = &ldcssp->cinfo;
6921991Sheppo 
6931991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
6942793Slm66018 	ASSERT(cinfo->dip != NULL);
6952793Slm66018 
6962793Slm66018 	switch (itype) {
6972793Slm66018 	case CNEX_TX_INTR:
6982531Snarayan 		/* check Tx interrupt */
6992793Slm66018 		if (ldcp->tx_intr_state)
7002793Slm66018 			ldcp->tx_intr_state = LDC_INTR_NONE;
7012793Slm66018 		else
7022793Slm66018 			return;
7032793Slm66018 		break;
7042793Slm66018 
7052793Slm66018 	case CNEX_RX_INTR:
7062531Snarayan 		/* check Rx interrupt */
7072793Slm66018 		if (ldcp->rx_intr_state)
7082793Slm66018 			ldcp->rx_intr_state = LDC_INTR_NONE;
7092793Slm66018 		else
7102793Slm66018 			return;
7112793Slm66018 		break;
7122793Slm66018 	}
7132793Slm66018 
7142793Slm66018 	(void) cinfo->clr_intr(cinfo->dip, ldcp->id, itype);
7152793Slm66018 	D2(ldcp->id,
7162793Slm66018 	    "i_ldc_clear_intr: (0x%llx) cleared 0x%x intr\n",
7172793Slm66018 	    ldcp->id, itype);
7181991Sheppo }
7191991Sheppo 
7201991Sheppo /*
7211991Sheppo  * Set the receive queue head
7222032Slm66018  * Resets connection and returns an error if it fails.
7231991Sheppo  */
7241991Sheppo static int
7251991Sheppo i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head)
7261991Sheppo {
7272032Slm66018 	int 	rv;
7282032Slm66018 	int 	retries;
7291991Sheppo 
7301991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
7312032Slm66018 	for (retries = 0; retries < ldc_max_retries; retries++) {
7322032Slm66018 
7332032Slm66018 		if ((rv = hv_ldc_rx_set_qhead(ldcp->id, head)) == 0)
7342032Slm66018 			return (0);
7352032Slm66018 
7362032Slm66018 		if (rv != H_EWOULDBLOCK)
7372032Slm66018 			break;
7382032Slm66018 
7392032Slm66018 		/* wait for ldc_delay usecs */
7402032Slm66018 		drv_usecwait(ldc_delay);
7412032Slm66018 	}
7422032Slm66018 
7432032Slm66018 	cmn_err(CE_WARN, "ldc_rx_set_qhead: (0x%lx) cannot set qhead 0x%lx",
7444690Snarayan 	    ldcp->id, head);
7452336Snarayan 	mutex_enter(&ldcp->tx_lock);
7462793Slm66018 	i_ldc_reset(ldcp, B_TRUE);
7472336Snarayan 	mutex_exit(&ldcp->tx_lock);
7482032Slm66018 
7492032Slm66018 	return (ECONNRESET);
7501991Sheppo }
7511991Sheppo 
7524690Snarayan /*
7534690Snarayan  * Returns the tx_head to be used for transfer
7544690Snarayan  */
7554690Snarayan static void
7564690Snarayan i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head)
7574690Snarayan {
7584690Snarayan 	ldc_msg_t 	*pkt;
7594690Snarayan 
7604690Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
7614690Snarayan 
7624690Snarayan 	/* get current Tx head */
7634690Snarayan 	*head = ldcp->tx_head;
7644690Snarayan 
7654690Snarayan 	/*
7664690Snarayan 	 * Reliable mode will use the ACKd head instead of the regular tx_head.
7674690Snarayan 	 * Also in Reliable mode, advance ackd_head for all non DATA/INFO pkts,
7684690Snarayan 	 * up to the current location of tx_head. This needs to be done
7694690Snarayan 	 * as the peer will only ACK DATA/INFO pkts.
7704690Snarayan 	 */
771*6408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
7724690Snarayan 		while (ldcp->tx_ackd_head != ldcp->tx_head) {
7734690Snarayan 			pkt = (ldc_msg_t *)(ldcp->tx_q_va + ldcp->tx_ackd_head);
7744690Snarayan 			if ((pkt->type & LDC_DATA) && (pkt->stype & LDC_INFO)) {
7754690Snarayan 				break;
7764690Snarayan 			}
7774690Snarayan 			/* advance ACKd head */
7784690Snarayan 			ldcp->tx_ackd_head =
7794690Snarayan 			    (ldcp->tx_ackd_head + LDC_PACKET_SIZE) %
7804690Snarayan 			    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
7814690Snarayan 		}
7824690Snarayan 		*head = ldcp->tx_ackd_head;
7834690Snarayan 	}
7844690Snarayan }
7851991Sheppo 
7861991Sheppo /*
7871991Sheppo  * Returns the tx_tail to be used for transfer
7881991Sheppo  * Re-reads the TX queue ptrs if and only if the
7891991Sheppo  * the cached head and tail are equal (queue is full)
7901991Sheppo  */
7911991Sheppo static int
7921991Sheppo i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail)
7931991Sheppo {
7941991Sheppo 	int 		rv;
7951991Sheppo 	uint64_t 	current_head, new_tail;
7961991Sheppo 
7972336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
7981991Sheppo 	/* Read the head and tail ptrs from HV */
7991991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
8001991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
8011991Sheppo 	if (rv) {
8021991Sheppo 		cmn_err(CE_WARN,
8031991Sheppo 		    "i_ldc_get_tx_tail: (0x%lx) cannot read qptrs\n",
8041991Sheppo 		    ldcp->id);
8051991Sheppo 		return (EIO);
8061991Sheppo 	}
8071991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN) {
8083010Slm66018 		D1(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) channel not ready\n",
8091991Sheppo 		    ldcp->id);
8101991Sheppo 		return (ECONNRESET);
8111991Sheppo 	}
8121991Sheppo 
8134690Snarayan 	i_ldc_get_tx_head(ldcp, &current_head);
8141991Sheppo 
8151991Sheppo 	/* increment the tail */
8161991Sheppo 	new_tail = (ldcp->tx_tail + LDC_PACKET_SIZE) %
8174690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
8181991Sheppo 
8191991Sheppo 	if (new_tail == current_head) {
8201991Sheppo 		DWARN(ldcp->id,
8211991Sheppo 		    "i_ldc_get_tx_tail: (0x%llx) TX queue is full\n",
8221991Sheppo 		    ldcp->id);
8231991Sheppo 		return (EWOULDBLOCK);
8241991Sheppo 	}
8251991Sheppo 
8261991Sheppo 	D2(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) head=0x%llx, tail=0x%llx\n",
8271991Sheppo 	    ldcp->id, ldcp->tx_head, ldcp->tx_tail);
8281991Sheppo 
8291991Sheppo 	*tail = ldcp->tx_tail;
8301991Sheppo 	return (0);
8311991Sheppo }
8321991Sheppo 
8331991Sheppo /*
8341991Sheppo  * Set the tail pointer. If HV returns EWOULDBLOCK, it will back off
8352032Slm66018  * and retry ldc_max_retries times before returning an error.
8361991Sheppo  * Returns 0, EWOULDBLOCK or EIO
8371991Sheppo  */
8381991Sheppo static int
8391991Sheppo i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail)
8401991Sheppo {
8411991Sheppo 	int		rv, retval = EWOULDBLOCK;
8422032Slm66018 	int 		retries;
8431991Sheppo 
8442336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
8452032Slm66018 	for (retries = 0; retries < ldc_max_retries; retries++) {
8461991Sheppo 
8471991Sheppo 		if ((rv = hv_ldc_tx_set_qtail(ldcp->id, tail)) == 0) {
8481991Sheppo 			retval = 0;
8491991Sheppo 			break;
8501991Sheppo 		}
8511991Sheppo 		if (rv != H_EWOULDBLOCK) {
8521991Sheppo 			DWARN(ldcp->id, "i_ldc_set_tx_tail: (0x%llx) set "
8531991Sheppo 			    "qtail=0x%llx failed, rv=%d\n", ldcp->id, tail, rv);
8541991Sheppo 			retval = EIO;
8551991Sheppo 			break;
8561991Sheppo 		}
8571991Sheppo 
8582032Slm66018 		/* wait for ldc_delay usecs */
8592032Slm66018 		drv_usecwait(ldc_delay);
8601991Sheppo 	}
8611991Sheppo 	return (retval);
8621991Sheppo }
8631991Sheppo 
8641991Sheppo /*
8655944Sha137994  * Copy a data packet from the HV receive queue to the data queue.
8665944Sha137994  * Caller must ensure that the data queue is not already full.
8675944Sha137994  *
8685944Sha137994  * The *head argument represents the current head pointer for the HV
8695944Sha137994  * receive queue. After copying a packet from the HV receive queue,
8705944Sha137994  * the *head pointer will be updated. This allows the caller to update
8715944Sha137994  * the head pointer in HV using the returned *head value.
8725944Sha137994  */
8735944Sha137994 void
8745944Sha137994 i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head)
8755944Sha137994 {
8765944Sha137994 	uint64_t	q_size, dq_size;
8775944Sha137994 
8785944Sha137994 	ASSERT(MUTEX_HELD(&ldcp->lock));
8795944Sha137994 
8805944Sha137994 	q_size  = ldcp->rx_q_entries << LDC_PACKET_SHIFT;
8815944Sha137994 	dq_size = ldcp->rx_dq_entries << LDC_PACKET_SHIFT;
8825944Sha137994 
8835944Sha137994 	ASSERT(Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail,
8845944Sha137994 	    dq_size) >= LDC_PACKET_SIZE);
8855944Sha137994 
8865944Sha137994 	bcopy((void *)(ldcp->rx_q_va + *head),
8875944Sha137994 	    (void *)(ldcp->rx_dq_va + ldcp->rx_dq_tail), LDC_PACKET_SIZE);
8885944Sha137994 	TRACE_RXDQ_COPY(ldcp, LDC_PACKET_SIZE);
8895944Sha137994 
8905944Sha137994 	/* Update rx head */
8915944Sha137994 	*head = (*head + LDC_PACKET_SIZE) % q_size;
8925944Sha137994 
8935944Sha137994 	/* Update dq tail */
8945944Sha137994 	ldcp->rx_dq_tail = (ldcp->rx_dq_tail + LDC_PACKET_SIZE) % dq_size;
8955944Sha137994 }
8965944Sha137994 
8975944Sha137994 /*
8985944Sha137994  * Update the Rx data queue head pointer
8995944Sha137994  */
9005944Sha137994 static int
9015944Sha137994 i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head)
9025944Sha137994 {
9035944Sha137994 	ldcp->rx_dq_head = head;
9045944Sha137994 	return (0);
9055944Sha137994 }
9065944Sha137994 
9075944Sha137994 /*
9085944Sha137994  * Get the Rx data queue head and tail pointers
9095944Sha137994  */
9105944Sha137994 static uint64_t
9115944Sha137994 i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail,
9125944Sha137994     uint64_t *link_state)
9135944Sha137994 {
9145944Sha137994 	_NOTE(ARGUNUSED(link_state))
9155944Sha137994 	*head = ldcp->rx_dq_head;
9165944Sha137994 	*tail = ldcp->rx_dq_tail;
9175944Sha137994 	return (0);
9185944Sha137994 }
9195944Sha137994 
9205944Sha137994 /*
9215944Sha137994  * Wrapper for the Rx HV queue set head function. Giving the
9225944Sha137994  * data queue and HV queue set head functions the same type.
9235944Sha137994  */
9245944Sha137994 static uint64_t
9255944Sha137994 i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail,
9265944Sha137994     uint64_t *link_state)
9275944Sha137994 {
9285944Sha137994 	return (i_ldc_h2v_error(hv_ldc_rx_get_state(ldcp->id, head, tail,
9295944Sha137994 	    link_state)));
9305944Sha137994 }
9315944Sha137994 
9325944Sha137994 /*
9335944Sha137994  * LDC receive interrupt handler
9345944Sha137994  *    triggered for channel with data pending to read
9355944Sha137994  *    i.e. Rx queue content changes
9365944Sha137994  */
9375944Sha137994 static uint_t
9385944Sha137994 i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2)
9395944Sha137994 {
9405944Sha137994 	_NOTE(ARGUNUSED(arg2))
9415944Sha137994 
9425944Sha137994 	ldc_chan_t	*ldcp;
9435944Sha137994 	boolean_t	notify;
9445944Sha137994 	uint64_t	event;
9455944Sha137994 	int		rv;
9465944Sha137994 
9475944Sha137994 	/* Get the channel for which interrupt was received */
9485944Sha137994 	if (arg1 == NULL) {
9495944Sha137994 		cmn_err(CE_WARN, "i_ldc_rx_hdlr: invalid arg\n");
9505944Sha137994 		return (DDI_INTR_UNCLAIMED);
9515944Sha137994 	}
9525944Sha137994 
9535944Sha137994 	ldcp = (ldc_chan_t *)arg1;
9545944Sha137994 
9555944Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
9565944Sha137994 	    ldcp->id, ldcp);
9575944Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (%llx) USR%lx/TS%lx/HS%lx, LSTATE=%lx\n",
9585944Sha137994 	    ldcp->id, ldcp->status, ldcp->tstate, ldcp->hstate,
9595944Sha137994 	    ldcp->link_state);
9605944Sha137994 
9615944Sha137994 	/* Lock channel */
9625944Sha137994 	mutex_enter(&ldcp->lock);
9635944Sha137994 
9645944Sha137994 	/* Mark the interrupt as being actively handled */
9655944Sha137994 	ldcp->rx_intr_state = LDC_INTR_ACTIVE;
9665944Sha137994 
9675944Sha137994 	(void) i_ldc_rx_process_hvq(ldcp, &notify, &event);
9685944Sha137994 
969*6408Sha137994 	if (ldcp->mode != LDC_MODE_RELIABLE) {
9705944Sha137994 		/*
9715944Sha137994 		 * If there are no data packets on the queue, clear
9725944Sha137994 		 * the interrupt. Otherwise, the ldc_read will clear
9735944Sha137994 		 * interrupts after draining the queue. To indicate the
9745944Sha137994 		 * interrupt has not yet been cleared, it is marked
9755944Sha137994 		 * as pending.
9765944Sha137994 		 */
9775944Sha137994 		if ((event & LDC_EVT_READ) == 0) {
9785944Sha137994 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
9795944Sha137994 		} else {
9805944Sha137994 			ldcp->rx_intr_state = LDC_INTR_PEND;
9815944Sha137994 		}
9825944Sha137994 	}
9835944Sha137994 
9845944Sha137994 	/* if callbacks are disabled, do not notify */
9855944Sha137994 	if (notify && ldcp->cb_enabled) {
9865944Sha137994 		ldcp->cb_inprogress = B_TRUE;
9875944Sha137994 		mutex_exit(&ldcp->lock);
9885944Sha137994 		rv = ldcp->cb(event, ldcp->cb_arg);
9895944Sha137994 		if (rv) {
9905944Sha137994 			DWARN(ldcp->id,
9915944Sha137994 			    "i_ldc_rx_hdlr: (0x%llx) callback failure",
9925944Sha137994 			    ldcp->id);
9935944Sha137994 		}
9945944Sha137994 		mutex_enter(&ldcp->lock);
9955944Sha137994 		ldcp->cb_inprogress = B_FALSE;
9965944Sha137994 	}
9975944Sha137994 
998*6408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
9995944Sha137994 		/*
10005944Sha137994 		 * If we are using a secondary data queue, clear the
10015944Sha137994 		 * interrupt. We should have processed all CTRL packets
10025944Sha137994 		 * and copied all DATA packets to the secondary queue.
10035944Sha137994 		 * Even if secondary queue filled up, clear the interrupts,
10045944Sha137994 		 * this will trigger another interrupt and force the
10055944Sha137994 		 * handler to copy more data.
10065944Sha137994 		 */
10075944Sha137994 		i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
10085944Sha137994 	}
10095944Sha137994 
10105944Sha137994 	mutex_exit(&ldcp->lock);
10115944Sha137994 
10125944Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) exiting handler", ldcp->id);
10135944Sha137994 
10145944Sha137994 	return (DDI_INTR_CLAIMED);
10155944Sha137994 }
10165944Sha137994 
10175944Sha137994 /*
10185944Sha137994  * Wrapper for the Rx HV queue processing function to be used when
10195944Sha137994  * checking the Rx HV queue for data packets. Unlike the interrupt
10205944Sha137994  * handler code flow, the Rx interrupt is not cleared here and
10215944Sha137994  * callbacks are not made.
10225944Sha137994  */
10235944Sha137994 static uint_t
10245944Sha137994 i_ldc_chkq(ldc_chan_t *ldcp)
10255944Sha137994 {
10265944Sha137994 	boolean_t	notify;
10275944Sha137994 	uint64_t	event;
10285944Sha137994 
10295944Sha137994 	return (i_ldc_rx_process_hvq(ldcp, &notify, &event));
10305944Sha137994 }
10315944Sha137994 
10325944Sha137994 /*
10331991Sheppo  * Send a LDC message
10341991Sheppo  */
10351991Sheppo static int
10361991Sheppo i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
10371991Sheppo     uint8_t ctrlmsg)
10381991Sheppo {
10391991Sheppo 	int		rv;
10401991Sheppo 	ldc_msg_t 	*pkt;
10411991Sheppo 	uint64_t	tx_tail;
10424690Snarayan 	uint32_t	curr_seqid;
10431991Sheppo 
10442336Snarayan 	/* Obtain Tx lock */
10452336Snarayan 	mutex_enter(&ldcp->tx_lock);
10462336Snarayan 
10474690Snarayan 	curr_seqid = ldcp->last_msg_snt;
10484690Snarayan 
10491991Sheppo 	/* get the current tail for the message */
10501991Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
10511991Sheppo 	if (rv) {
10521991Sheppo 		DWARN(ldcp->id,
10531991Sheppo 		    "i_ldc_send_pkt: (0x%llx) error sending pkt, "
10541991Sheppo 		    "type=0x%x,subtype=0x%x,ctrl=0x%x\n",
10551991Sheppo 		    ldcp->id, pkttype, subtype, ctrlmsg);
10562336Snarayan 		mutex_exit(&ldcp->tx_lock);
10571991Sheppo 		return (rv);
10581991Sheppo 	}
10591991Sheppo 
10601991Sheppo 	pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
10611991Sheppo 	ZERO_PKT(pkt);
10621991Sheppo 
10631991Sheppo 	/* Initialize the packet */
10641991Sheppo 	pkt->type = pkttype;
10651991Sheppo 	pkt->stype = subtype;
10661991Sheppo 	pkt->ctrl = ctrlmsg;
10671991Sheppo 
10681991Sheppo 	/* Store ackid/seqid iff it is RELIABLE mode & not a RTS/RTR message */
10691991Sheppo 	if (((ctrlmsg & LDC_CTRL_MASK) != LDC_RTS) &&
10701991Sheppo 	    ((ctrlmsg & LDC_CTRL_MASK) != LDC_RTR)) {
10711991Sheppo 		curr_seqid++;
10721991Sheppo 		if (ldcp->mode != LDC_MODE_RAW) {
10731991Sheppo 			pkt->seqid = curr_seqid;
10741991Sheppo 			pkt->ackid = ldcp->last_msg_rcd;
10751991Sheppo 		}
10761991Sheppo 	}
10771991Sheppo 	DUMP_LDC_PKT(ldcp, "i_ldc_send_pkt", (uint64_t)pkt);
10781991Sheppo 
10791991Sheppo 	/* initiate the send by calling into HV and set the new tail */
10801991Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
10814690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
10821991Sheppo 
10831991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
10841991Sheppo 	if (rv) {
10851991Sheppo 		DWARN(ldcp->id,
10861991Sheppo 		    "i_ldc_send_pkt:(0x%llx) error sending pkt, "
10871991Sheppo 		    "type=0x%x,stype=0x%x,ctrl=0x%x\n",
10881991Sheppo 		    ldcp->id, pkttype, subtype, ctrlmsg);
10892336Snarayan 		mutex_exit(&ldcp->tx_lock);
10901991Sheppo 		return (EIO);
10911991Sheppo 	}
10921991Sheppo 
10931991Sheppo 	ldcp->last_msg_snt = curr_seqid;
10941991Sheppo 	ldcp->tx_tail = tx_tail;
10951991Sheppo 
10962336Snarayan 	mutex_exit(&ldcp->tx_lock);
10971991Sheppo 	return (0);
10981991Sheppo }
10991991Sheppo 
11001991Sheppo /*
11011991Sheppo  * Checks if packet was received in right order
11022410Slm66018  * in the case of a reliable link.
11031991Sheppo  * Returns 0 if in order, else EIO
11041991Sheppo  */
11051991Sheppo static int
11061991Sheppo i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *msg)
11071991Sheppo {
11081991Sheppo 	/* No seqid checking for RAW mode */
11091991Sheppo 	if (ldcp->mode == LDC_MODE_RAW)
11101991Sheppo 		return (0);
11111991Sheppo 
11121991Sheppo 	/* No seqid checking for version, RTS, RTR message */
11131991Sheppo 	if (msg->ctrl == LDC_VER ||
11141991Sheppo 	    msg->ctrl == LDC_RTS ||
11151991Sheppo 	    msg->ctrl == LDC_RTR)
11161991Sheppo 		return (0);
11171991Sheppo 
11181991Sheppo 	/* Initial seqid to use is sent in RTS/RTR and saved in last_msg_rcd */
11191991Sheppo 	if (msg->seqid != (ldcp->last_msg_rcd + 1)) {
11201991Sheppo 		DWARN(ldcp->id,
11211991Sheppo 		    "i_ldc_check_seqid: (0x%llx) out-of-order pkt, got 0x%x, "
11221991Sheppo 		    "expecting 0x%x\n", ldcp->id, msg->seqid,
11231991Sheppo 		    (ldcp->last_msg_rcd + 1));
11241991Sheppo 		return (EIO);
11251991Sheppo 	}
11261991Sheppo 
11273560Snarayan #ifdef DEBUG
11283560Snarayan 	if (LDC_INJECT_PKTLOSS(ldcp)) {
11293560Snarayan 		DWARN(ldcp->id,
11303560Snarayan 		    "i_ldc_check_seqid: (0x%llx) inject pkt loss\n", ldcp->id);
11313560Snarayan 		return (EIO);
11323560Snarayan 	}
11333560Snarayan #endif
11343560Snarayan 
11351991Sheppo 	return (0);
11361991Sheppo }
11371991Sheppo 
11381991Sheppo 
11391991Sheppo /*
11401991Sheppo  * Process an incoming version ctrl message
11411991Sheppo  */
11421991Sheppo static int
11431991Sheppo i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg)
11441991Sheppo {
11451991Sheppo 	int 		rv = 0, idx = ldcp->next_vidx;
11461991Sheppo 	ldc_msg_t 	*pkt;
11471991Sheppo 	uint64_t	tx_tail;
11481991Sheppo 	ldc_ver_t	*rcvd_ver;
11491991Sheppo 
11501991Sheppo 	/* get the received version */
11511991Sheppo 	rcvd_ver = (ldc_ver_t *)((uint64_t)msg + LDC_PAYLOAD_VER_OFF);
11521991Sheppo 
11531991Sheppo 	D2(ldcp->id, "i_ldc_process_VER: (0x%llx) received VER v%u.%u\n",
11541991Sheppo 	    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
11551991Sheppo 
11562336Snarayan 	/* Obtain Tx lock */
11572336Snarayan 	mutex_enter(&ldcp->tx_lock);
11582336Snarayan 
11591991Sheppo 	switch (msg->stype) {
11601991Sheppo 	case LDC_INFO:
11611991Sheppo 
11622793Slm66018 		if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) {
11632793Slm66018 			(void) i_ldc_txq_reconf(ldcp);
11642793Slm66018 			i_ldc_reset_state(ldcp);
11652793Slm66018 			mutex_exit(&ldcp->tx_lock);
11662793Slm66018 			return (EAGAIN);
11672793Slm66018 		}
11682793Slm66018 
11691991Sheppo 		/* get the current tail and pkt for the response */
11701991Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
11711991Sheppo 		if (rv != 0) {
11721991Sheppo 			DWARN(ldcp->id,
11731991Sheppo 			    "i_ldc_process_VER: (0x%llx) err sending "
11741991Sheppo 			    "version ACK/NACK\n", ldcp->id);
11752793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
11762336Snarayan 			mutex_exit(&ldcp->tx_lock);
11771991Sheppo 			return (ECONNRESET);
11781991Sheppo 		}
11791991Sheppo 
11801991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
11811991Sheppo 		ZERO_PKT(pkt);
11821991Sheppo 
11831991Sheppo 		/* initialize the packet */
11841991Sheppo 		pkt->type = LDC_CTRL;
11851991Sheppo 		pkt->ctrl = LDC_VER;
11861991Sheppo 
11871991Sheppo 		for (;;) {
11881991Sheppo 
11891991Sheppo 			D1(ldcp->id, "i_ldc_process_VER: got %u.%u chk %u.%u\n",
11901991Sheppo 			    rcvd_ver->major, rcvd_ver->minor,
11911991Sheppo 			    ldc_versions[idx].major, ldc_versions[idx].minor);
11921991Sheppo 
11931991Sheppo 			if (rcvd_ver->major == ldc_versions[idx].major) {
11941991Sheppo 				/* major version match - ACK version */
11951991Sheppo 				pkt->stype = LDC_ACK;
11961991Sheppo 
11971991Sheppo 				/*
11981991Sheppo 				 * lower minor version to the one this endpt
11991991Sheppo 				 * supports, if necessary
12001991Sheppo 				 */
12011991Sheppo 				if (rcvd_ver->minor > ldc_versions[idx].minor)
12021991Sheppo 					rcvd_ver->minor =
12034690Snarayan 					    ldc_versions[idx].minor;
12041991Sheppo 				bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver));
12051991Sheppo 
12061991Sheppo 				break;
12071991Sheppo 			}
12081991Sheppo 
12091991Sheppo 			if (rcvd_ver->major > ldc_versions[idx].major) {
12101991Sheppo 
12111991Sheppo 				D1(ldcp->id, "i_ldc_process_VER: using next"
12121991Sheppo 				    " lower idx=%d, v%u.%u\n", idx,
12131991Sheppo 				    ldc_versions[idx].major,
12141991Sheppo 				    ldc_versions[idx].minor);
12151991Sheppo 
12161991Sheppo 				/* nack with next lower version */
12171991Sheppo 				pkt->stype = LDC_NACK;
12181991Sheppo 				bcopy(&ldc_versions[idx], pkt->udata,
12191991Sheppo 				    sizeof (ldc_versions[idx]));
12201991Sheppo 				ldcp->next_vidx = idx;
12211991Sheppo 				break;
12221991Sheppo 			}
12231991Sheppo 
12241991Sheppo 			/* next major version */
12251991Sheppo 			idx++;
12261991Sheppo 
12271991Sheppo 			D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx);
12281991Sheppo 
12291991Sheppo 			if (idx == LDC_NUM_VERS) {
12301991Sheppo 				/* no version match - send NACK */
12311991Sheppo 				pkt->stype = LDC_NACK;
12321991Sheppo 				bzero(pkt->udata, sizeof (ldc_ver_t));
12331991Sheppo 				ldcp->next_vidx = 0;
12341991Sheppo 				break;
12351991Sheppo 			}
12361991Sheppo 		}
12371991Sheppo 
12381991Sheppo 		/* initiate the send by calling into HV and set the new tail */
12391991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
12404690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
12411991Sheppo 
12421991Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
12431991Sheppo 		if (rv == 0) {
12441991Sheppo 			ldcp->tx_tail = tx_tail;
12451991Sheppo 			if (pkt->stype == LDC_ACK) {
12461991Sheppo 				D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent"
12471991Sheppo 				    " version ACK\n", ldcp->id);
12481991Sheppo 				/* Save the ACK'd version */
12491991Sheppo 				ldcp->version.major = rcvd_ver->major;
12501991Sheppo 				ldcp->version.minor = rcvd_ver->minor;
12512032Slm66018 				ldcp->hstate |= TS_RCVD_VER;
12521991Sheppo 				ldcp->tstate |= TS_VER_DONE;
12533560Snarayan 				D1(DBG_ALL_LDCS,
12542793Slm66018 				    "(0x%llx) Sent ACK, "
12552793Slm66018 				    "Agreed on version v%u.%u\n",
12561991Sheppo 				    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
12571991Sheppo 			}
12581991Sheppo 		} else {
12591991Sheppo 			DWARN(ldcp->id,
12601991Sheppo 			    "i_ldc_process_VER: (0x%llx) error sending "
12611991Sheppo 			    "ACK/NACK\n", ldcp->id);
12622793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
12632336Snarayan 			mutex_exit(&ldcp->tx_lock);
12641991Sheppo 			return (ECONNRESET);
12651991Sheppo 		}
12661991Sheppo 
12671991Sheppo 		break;
12681991Sheppo 
12691991Sheppo 	case LDC_ACK:
12702793Slm66018 		if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) {
12712793Slm66018 			if (ldcp->version.major != rcvd_ver->major ||
12724690Snarayan 			    ldcp->version.minor != rcvd_ver->minor) {
12732793Slm66018 
12742793Slm66018 				/* mismatched version - reset connection */
12752793Slm66018 				DWARN(ldcp->id,
12764690Snarayan 				    "i_ldc_process_VER: (0x%llx) recvd"
12774690Snarayan 				    " ACK ver != sent ACK ver\n", ldcp->id);
12782793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
12792793Slm66018 				mutex_exit(&ldcp->tx_lock);
12802793Slm66018 				return (ECONNRESET);
12812793Slm66018 			}
12822793Slm66018 		} else {
12832793Slm66018 			/* SUCCESS - we have agreed on a version */
12842793Slm66018 			ldcp->version.major = rcvd_ver->major;
12852793Slm66018 			ldcp->version.minor = rcvd_ver->minor;
12862793Slm66018 			ldcp->tstate |= TS_VER_DONE;
12872793Slm66018 		}
12882793Slm66018 
12893010Slm66018 		D1(ldcp->id, "(0x%llx) Got ACK, Agreed on version v%u.%u\n",
12901991Sheppo 		    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
12911991Sheppo 
12921991Sheppo 		/* initiate RTS-RTR-RDX handshake */
12931991Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
12941991Sheppo 		if (rv) {
12951991Sheppo 			DWARN(ldcp->id,
12962793Slm66018 		    "i_ldc_process_VER: (0x%llx) cannot send RTS\n",
12971991Sheppo 			    ldcp->id);
12982793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
12992336Snarayan 			mutex_exit(&ldcp->tx_lock);
13001991Sheppo 			return (ECONNRESET);
13011991Sheppo 		}
13021991Sheppo 
13031991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
13041991Sheppo 		ZERO_PKT(pkt);
13051991Sheppo 
13061991Sheppo 		pkt->type = LDC_CTRL;
13071991Sheppo 		pkt->stype = LDC_INFO;
13081991Sheppo 		pkt->ctrl = LDC_RTS;
13091991Sheppo 		pkt->env = ldcp->mode;
13101991Sheppo 		if (ldcp->mode != LDC_MODE_RAW)
13111991Sheppo 			pkt->seqid = LDC_INIT_SEQID;
13121991Sheppo 
13131991Sheppo 		ldcp->last_msg_rcd = LDC_INIT_SEQID;
13141991Sheppo 
13151991Sheppo 		DUMP_LDC_PKT(ldcp, "i_ldc_process_VER snd rts", (uint64_t)pkt);
13161991Sheppo 
13171991Sheppo 		/* initiate the send by calling into HV and set the new tail */
13181991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
13194690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
13201991Sheppo 
13211991Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
13221991Sheppo 		if (rv) {
13231991Sheppo 			D2(ldcp->id,
13241991Sheppo 			    "i_ldc_process_VER: (0x%llx) no listener\n",
13251991Sheppo 			    ldcp->id);
13262793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
13272336Snarayan 			mutex_exit(&ldcp->tx_lock);
13281991Sheppo 			return (ECONNRESET);
13291991Sheppo 		}
13301991Sheppo 
13311991Sheppo 		ldcp->tx_tail = tx_tail;
13321991Sheppo 		ldcp->hstate |= TS_SENT_RTS;
13331991Sheppo 
13341991Sheppo 		break;
13351991Sheppo 
13361991Sheppo 	case LDC_NACK:
13371991Sheppo 		/* check if version in NACK is zero */
13381991Sheppo 		if (rcvd_ver->major == 0 && rcvd_ver->minor == 0) {
13391991Sheppo 			/* version handshake failure */
13401991Sheppo 			DWARN(DBG_ALL_LDCS,
13411991Sheppo 			    "i_ldc_process_VER: (0x%llx) no version match\n",
13421991Sheppo 			    ldcp->id);
13432793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
13442336Snarayan 			mutex_exit(&ldcp->tx_lock);
13451991Sheppo 			return (ECONNRESET);
13461991Sheppo 		}
13471991Sheppo 
13481991Sheppo 		/* get the current tail and pkt for the response */
13491991Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
13501991Sheppo 		if (rv != 0) {
13511991Sheppo 			cmn_err(CE_NOTE,
13521991Sheppo 			    "i_ldc_process_VER: (0x%lx) err sending "
13531991Sheppo 			    "version ACK/NACK\n", ldcp->id);
13542793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
13552336Snarayan 			mutex_exit(&ldcp->tx_lock);
13561991Sheppo 			return (ECONNRESET);
13571991Sheppo 		}
13581991Sheppo 
13591991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
13601991Sheppo 		ZERO_PKT(pkt);
13611991Sheppo 
13621991Sheppo 		/* initialize the packet */
13631991Sheppo 		pkt->type = LDC_CTRL;
13641991Sheppo 		pkt->ctrl = LDC_VER;
13651991Sheppo 		pkt->stype = LDC_INFO;
13661991Sheppo 
13671991Sheppo 		/* check ver in NACK msg has a match */
13681991Sheppo 		for (;;) {
13691991Sheppo 			if (rcvd_ver->major == ldc_versions[idx].major) {
13701991Sheppo 				/*
13711991Sheppo 				 * major version match - resubmit request
13721991Sheppo 				 * if lower minor version to the one this endpt
13731991Sheppo 				 * supports, if necessary
13741991Sheppo 				 */
13751991Sheppo 				if (rcvd_ver->minor > ldc_versions[idx].minor)
13761991Sheppo 					rcvd_ver->minor =
13774690Snarayan 					    ldc_versions[idx].minor;
13781991Sheppo 				bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver));
13791991Sheppo 				break;
13801991Sheppo 			}
13811991Sheppo 
13821991Sheppo 			if (rcvd_ver->major > ldc_versions[idx].major) {
13831991Sheppo 
13841991Sheppo 				D1(ldcp->id, "i_ldc_process_VER: using next"
13851991Sheppo 				    " lower idx=%d, v%u.%u\n", idx,
13861991Sheppo 				    ldc_versions[idx].major,
13871991Sheppo 				    ldc_versions[idx].minor);
13881991Sheppo 
13891991Sheppo 				/* send next lower version */
13901991Sheppo 				bcopy(&ldc_versions[idx], pkt->udata,
13911991Sheppo 				    sizeof (ldc_versions[idx]));
13921991Sheppo 				ldcp->next_vidx = idx;
13931991Sheppo 				break;
13941991Sheppo 			}
13951991Sheppo 
13961991Sheppo 			/* next version */
13971991Sheppo 			idx++;
13981991Sheppo 
13991991Sheppo 			D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx);
14001991Sheppo 
14011991Sheppo 			if (idx == LDC_NUM_VERS) {
14021991Sheppo 				/* no version match - terminate */
14031991Sheppo 				ldcp->next_vidx = 0;
14042336Snarayan 				mutex_exit(&ldcp->tx_lock);
14051991Sheppo 				return (ECONNRESET);
14061991Sheppo 			}
14071991Sheppo 		}
14081991Sheppo 
14091991Sheppo 		/* initiate the send by calling into HV and set the new tail */
14101991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
14114690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
14121991Sheppo 
14131991Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
14141991Sheppo 		if (rv == 0) {
14151991Sheppo 			D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent version"
14161991Sheppo 			    "INFO v%u.%u\n", ldcp->id, ldc_versions[idx].major,
14171991Sheppo 			    ldc_versions[idx].minor);
14181991Sheppo 			ldcp->tx_tail = tx_tail;
14191991Sheppo 		} else {
14201991Sheppo 			cmn_err(CE_NOTE,
14211991Sheppo 			    "i_ldc_process_VER: (0x%lx) error sending version"
14221991Sheppo 			    "INFO\n", ldcp->id);
14232793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
14242336Snarayan 			mutex_exit(&ldcp->tx_lock);
14251991Sheppo 			return (ECONNRESET);
14261991Sheppo 		}
14271991Sheppo 
14281991Sheppo 		break;
14291991Sheppo 	}
14301991Sheppo 
14312336Snarayan 	mutex_exit(&ldcp->tx_lock);
14321991Sheppo 	return (rv);
14331991Sheppo }
14341991Sheppo 
14351991Sheppo 
14361991Sheppo /*
14371991Sheppo  * Process an incoming RTS ctrl message
14381991Sheppo  */
14391991Sheppo static int
14401991Sheppo i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg)
14411991Sheppo {
14421991Sheppo 	int 		rv = 0;
14431991Sheppo 	ldc_msg_t 	*pkt;
14441991Sheppo 	uint64_t	tx_tail;
14451991Sheppo 	boolean_t	sent_NACK = B_FALSE;
14461991Sheppo 
14471991Sheppo 	D2(ldcp->id, "i_ldc_process_RTS: (0x%llx) received RTS\n", ldcp->id);
14481991Sheppo 
14491991Sheppo 	switch (msg->stype) {
14501991Sheppo 	case LDC_NACK:
14511991Sheppo 		DWARN(ldcp->id,
14521991Sheppo 		    "i_ldc_process_RTS: (0x%llx) RTS NACK received\n",
14531991Sheppo 		    ldcp->id);
14541991Sheppo 
14551991Sheppo 		/* Reset the channel -- as we cannot continue */
14562336Snarayan 		mutex_enter(&ldcp->tx_lock);
14572793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
14582336Snarayan 		mutex_exit(&ldcp->tx_lock);
14591991Sheppo 		rv = ECONNRESET;
14601991Sheppo 		break;
14611991Sheppo 
14621991Sheppo 	case LDC_INFO:
14631991Sheppo 
14641991Sheppo 		/* check mode */
14651991Sheppo 		if (ldcp->mode != (ldc_mode_t)msg->env) {
14661991Sheppo 			cmn_err(CE_NOTE,
14671991Sheppo 			    "i_ldc_process_RTS: (0x%lx) mode mismatch\n",
14681991Sheppo 			    ldcp->id);
14691991Sheppo 			/*
14701991Sheppo 			 * send NACK in response to MODE message
14711991Sheppo 			 * get the current tail for the response
14721991Sheppo 			 */
14731991Sheppo 			rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTS);
14741991Sheppo 			if (rv) {
14751991Sheppo 				/* if cannot send NACK - reset channel */
14762336Snarayan 				mutex_enter(&ldcp->tx_lock);
14772793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
14782336Snarayan 				mutex_exit(&ldcp->tx_lock);
14791991Sheppo 				rv = ECONNRESET;
14801991Sheppo 				break;
14811991Sheppo 			}
14821991Sheppo 			sent_NACK = B_TRUE;
14831991Sheppo 		}
14841991Sheppo 		break;
14851991Sheppo 	default:
14861991Sheppo 		DWARN(ldcp->id, "i_ldc_process_RTS: (0x%llx) unexp ACK\n",
14871991Sheppo 		    ldcp->id);
14882336Snarayan 		mutex_enter(&ldcp->tx_lock);
14892793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
14902336Snarayan 		mutex_exit(&ldcp->tx_lock);
14911991Sheppo 		rv = ECONNRESET;
14921991Sheppo 		break;
14931991Sheppo 	}
14941991Sheppo 
14951991Sheppo 	/*
14961991Sheppo 	 * If either the connection was reset (when rv != 0) or
14971991Sheppo 	 * a NACK was sent, we return. In the case of a NACK
14981991Sheppo 	 * we dont want to consume the packet that came in but
14991991Sheppo 	 * not record that we received the RTS
15001991Sheppo 	 */
15011991Sheppo 	if (rv || sent_NACK)
15021991Sheppo 		return (rv);
15031991Sheppo 
15041991Sheppo 	/* record RTS received */
15051991Sheppo 	ldcp->hstate |= TS_RCVD_RTS;
15061991Sheppo 
15071991Sheppo 	/* store initial SEQID info */
15081991Sheppo 	ldcp->last_msg_snt = msg->seqid;
15091991Sheppo 
15102336Snarayan 	/* Obtain Tx lock */
15112336Snarayan 	mutex_enter(&ldcp->tx_lock);
15122336Snarayan 
15131991Sheppo 	/* get the current tail for the response */
15141991Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
15151991Sheppo 	if (rv != 0) {
15161991Sheppo 		cmn_err(CE_NOTE,
15171991Sheppo 		    "i_ldc_process_RTS: (0x%lx) err sending RTR\n",
15181991Sheppo 		    ldcp->id);
15192793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
15202336Snarayan 		mutex_exit(&ldcp->tx_lock);
15211991Sheppo 		return (ECONNRESET);
15221991Sheppo 	}
15231991Sheppo 
15241991Sheppo 	pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
15251991Sheppo 	ZERO_PKT(pkt);
15261991Sheppo 
15271991Sheppo 	/* initialize the packet */
15281991Sheppo 	pkt->type = LDC_CTRL;
15291991Sheppo 	pkt->stype = LDC_INFO;
15301991Sheppo 	pkt->ctrl = LDC_RTR;
15311991Sheppo 	pkt->env = ldcp->mode;
15321991Sheppo 	if (ldcp->mode != LDC_MODE_RAW)
15331991Sheppo 		pkt->seqid = LDC_INIT_SEQID;
15341991Sheppo 
15351991Sheppo 	ldcp->last_msg_rcd = msg->seqid;
15361991Sheppo 
15371991Sheppo 	/* initiate the send by calling into HV and set the new tail */
15381991Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
15394690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
15401991Sheppo 
15411991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
15421991Sheppo 	if (rv == 0) {
15431991Sheppo 		D2(ldcp->id,
15441991Sheppo 		    "i_ldc_process_RTS: (0x%llx) sent RTR\n", ldcp->id);
15451991Sheppo 		DUMP_LDC_PKT(ldcp, "i_ldc_process_RTS sent rtr", (uint64_t)pkt);
15461991Sheppo 
15471991Sheppo 		ldcp->tx_tail = tx_tail;
15481991Sheppo 		ldcp->hstate |= TS_SENT_RTR;
15491991Sheppo 
15501991Sheppo 	} else {
15511991Sheppo 		cmn_err(CE_NOTE,
15521991Sheppo 		    "i_ldc_process_RTS: (0x%lx) error sending RTR\n",
15531991Sheppo 		    ldcp->id);
15542793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
15552336Snarayan 		mutex_exit(&ldcp->tx_lock);
15561991Sheppo 		return (ECONNRESET);
15571991Sheppo 	}
15581991Sheppo 
15592336Snarayan 	mutex_exit(&ldcp->tx_lock);
15601991Sheppo 	return (0);
15611991Sheppo }
15621991Sheppo 
15631991Sheppo /*
15641991Sheppo  * Process an incoming RTR ctrl message
15651991Sheppo  */
15661991Sheppo static int
15671991Sheppo i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg)
15681991Sheppo {
15691991Sheppo 	int 		rv = 0;
15701991Sheppo 	boolean_t	sent_NACK = B_FALSE;
15711991Sheppo 
15721991Sheppo 	D2(ldcp->id, "i_ldc_process_RTR: (0x%llx) received RTR\n", ldcp->id);
15731991Sheppo 
15741991Sheppo 	switch (msg->stype) {
15751991Sheppo 	case LDC_NACK:
15761991Sheppo 		/* RTR NACK received */
15771991Sheppo 		DWARN(ldcp->id,
15781991Sheppo 		    "i_ldc_process_RTR: (0x%llx) RTR NACK received\n",
15791991Sheppo 		    ldcp->id);
15801991Sheppo 
15811991Sheppo 		/* Reset the channel -- as we cannot continue */
15822336Snarayan 		mutex_enter(&ldcp->tx_lock);
15832793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
15842336Snarayan 		mutex_exit(&ldcp->tx_lock);
15851991Sheppo 		rv = ECONNRESET;
15861991Sheppo 
15871991Sheppo 		break;
15881991Sheppo 
15891991Sheppo 	case LDC_INFO:
15901991Sheppo 
15911991Sheppo 		/* check mode */
15921991Sheppo 		if (ldcp->mode != (ldc_mode_t)msg->env) {
15931991Sheppo 			DWARN(ldcp->id,
15943010Slm66018 			    "i_ldc_process_RTR: (0x%llx) mode mismatch, "
15953010Slm66018 			    "expecting 0x%x, got 0x%x\n",
15963010Slm66018 			    ldcp->id, ldcp->mode, (ldc_mode_t)msg->env);
15971991Sheppo 			/*
15981991Sheppo 			 * send NACK in response to MODE message
15991991Sheppo 			 * get the current tail for the response
16001991Sheppo 			 */
16011991Sheppo 			rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTR);
16021991Sheppo 			if (rv) {
16031991Sheppo 				/* if cannot send NACK - reset channel */
16042336Snarayan 				mutex_enter(&ldcp->tx_lock);
16052793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
16062336Snarayan 				mutex_exit(&ldcp->tx_lock);
16071991Sheppo 				rv = ECONNRESET;
16081991Sheppo 				break;
16091991Sheppo 			}
16101991Sheppo 			sent_NACK = B_TRUE;
16111991Sheppo 		}
16121991Sheppo 		break;
16131991Sheppo 
16141991Sheppo 	default:
16151991Sheppo 		DWARN(ldcp->id, "i_ldc_process_RTR: (0x%llx) unexp ACK\n",
16161991Sheppo 		    ldcp->id);
16171991Sheppo 
16181991Sheppo 		/* Reset the channel -- as we cannot continue */
16192336Snarayan 		mutex_enter(&ldcp->tx_lock);
16202793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
16212336Snarayan 		mutex_exit(&ldcp->tx_lock);
16221991Sheppo 		rv = ECONNRESET;
16231991Sheppo 		break;
16241991Sheppo 	}
16251991Sheppo 
16261991Sheppo 	/*
16271991Sheppo 	 * If either the connection was reset (when rv != 0) or
16281991Sheppo 	 * a NACK was sent, we return. In the case of a NACK
16291991Sheppo 	 * we dont want to consume the packet that came in but
16301991Sheppo 	 * not record that we received the RTR
16311991Sheppo 	 */
16321991Sheppo 	if (rv || sent_NACK)
16331991Sheppo 		return (rv);
16341991Sheppo 
16351991Sheppo 	ldcp->last_msg_snt = msg->seqid;
16361991Sheppo 	ldcp->hstate |= TS_RCVD_RTR;
16371991Sheppo 
16381991Sheppo 	rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_INFO, LDC_RDX);
16391991Sheppo 	if (rv) {
16401991Sheppo 		cmn_err(CE_NOTE,
16411991Sheppo 		    "i_ldc_process_RTR: (0x%lx) cannot send RDX\n",
16421991Sheppo 		    ldcp->id);
16432336Snarayan 		mutex_enter(&ldcp->tx_lock);
16442793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
16452336Snarayan 		mutex_exit(&ldcp->tx_lock);
16461991Sheppo 		return (ECONNRESET);
16471991Sheppo 	}
16481991Sheppo 	D2(ldcp->id,
16491991Sheppo 	    "i_ldc_process_RTR: (0x%llx) sent RDX\n", ldcp->id);
16501991Sheppo 
16511991Sheppo 	ldcp->hstate |= TS_SENT_RDX;
16521991Sheppo 	ldcp->tstate |= TS_HSHAKE_DONE;
16532793Slm66018 	if ((ldcp->tstate & TS_IN_RESET) == 0)
16542793Slm66018 		ldcp->status = LDC_UP;
16551991Sheppo 
16563010Slm66018 	D1(ldcp->id, "(0x%llx) Handshake Complete\n", ldcp->id);
16571991Sheppo 
16581991Sheppo 	return (0);
16591991Sheppo }
16601991Sheppo 
16611991Sheppo 
16621991Sheppo /*
16631991Sheppo  * Process an incoming RDX ctrl message
16641991Sheppo  */
16651991Sheppo static int
16661991Sheppo i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg)
16671991Sheppo {
16681991Sheppo 	int	rv = 0;
16691991Sheppo 
16701991Sheppo 	D2(ldcp->id, "i_ldc_process_RDX: (0x%llx) received RDX\n", ldcp->id);
16711991Sheppo 
16721991Sheppo 	switch (msg->stype) {
16731991Sheppo 	case LDC_NACK:
16741991Sheppo 		/* RDX NACK received */
16751991Sheppo 		DWARN(ldcp->id,
16761991Sheppo 		    "i_ldc_process_RDX: (0x%llx) RDX NACK received\n",
16771991Sheppo 		    ldcp->id);
16781991Sheppo 
16791991Sheppo 		/* Reset the channel -- as we cannot continue */
16802336Snarayan 		mutex_enter(&ldcp->tx_lock);
16812793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
16822336Snarayan 		mutex_exit(&ldcp->tx_lock);
16831991Sheppo 		rv = ECONNRESET;
16841991Sheppo 
16851991Sheppo 		break;
16861991Sheppo 
16871991Sheppo 	case LDC_INFO:
16881991Sheppo 
16891991Sheppo 		/*
16901991Sheppo 		 * if channel is UP and a RDX received after data transmission
16911991Sheppo 		 * has commenced it is an error
16921991Sheppo 		 */
16931991Sheppo 		if ((ldcp->tstate == TS_UP) && (ldcp->hstate & TS_RCVD_RDX)) {
16941991Sheppo 			DWARN(DBG_ALL_LDCS,
16951991Sheppo 			    "i_ldc_process_RDX: (0x%llx) unexpected RDX"
16961991Sheppo 			    " - LDC reset\n", ldcp->id);
16972336Snarayan 			mutex_enter(&ldcp->tx_lock);
16982793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
16992336Snarayan 			mutex_exit(&ldcp->tx_lock);
17001991Sheppo 			return (ECONNRESET);
17011991Sheppo 		}
17021991Sheppo 
17031991Sheppo 		ldcp->hstate |= TS_RCVD_RDX;
17041991Sheppo 		ldcp->tstate |= TS_HSHAKE_DONE;
17052793Slm66018 		if ((ldcp->tstate & TS_IN_RESET) == 0)
17062793Slm66018 			ldcp->status = LDC_UP;
17071991Sheppo 
17081991Sheppo 		D1(DBG_ALL_LDCS, "(0x%llx) Handshake Complete\n", ldcp->id);
17091991Sheppo 		break;
17101991Sheppo 
17111991Sheppo 	default:
17121991Sheppo 		DWARN(ldcp->id, "i_ldc_process_RDX: (0x%llx) unexp ACK\n",
17131991Sheppo 		    ldcp->id);
17141991Sheppo 
17151991Sheppo 		/* Reset the channel -- as we cannot continue */
17162336Snarayan 		mutex_enter(&ldcp->tx_lock);
17172793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
17182336Snarayan 		mutex_exit(&ldcp->tx_lock);
17191991Sheppo 		rv = ECONNRESET;
17201991Sheppo 		break;
17211991Sheppo 	}
17221991Sheppo 
17231991Sheppo 	return (rv);
17241991Sheppo }
17251991Sheppo 
17261991Sheppo /*
17271991Sheppo  * Process an incoming ACK for a data packet
17281991Sheppo  */
17291991Sheppo static int
17301991Sheppo i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg)
17311991Sheppo {
17321991Sheppo 	int		rv;
17331991Sheppo 	uint64_t 	tx_head;
17341991Sheppo 	ldc_msg_t	*pkt;
17351991Sheppo 
17362336Snarayan 	/* Obtain Tx lock */
17372336Snarayan 	mutex_enter(&ldcp->tx_lock);
17382336Snarayan 
17391991Sheppo 	/*
17402336Snarayan 	 * Read the current Tx head and tail
17411991Sheppo 	 */
17421991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
17431991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
17441991Sheppo 	if (rv != 0) {
17451991Sheppo 		cmn_err(CE_WARN,
17461991Sheppo 		    "i_ldc_process_data_ACK: (0x%lx) cannot read qptrs\n",
17471991Sheppo 		    ldcp->id);
17482336Snarayan 
17492336Snarayan 		/* Reset the channel -- as we cannot continue */
17502793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
17512336Snarayan 		mutex_exit(&ldcp->tx_lock);
17522336Snarayan 		return (ECONNRESET);
17531991Sheppo 	}
17541991Sheppo 
17551991Sheppo 	/*
17561991Sheppo 	 * loop from where the previous ACK location was to the
17571991Sheppo 	 * current head location. This is how far the HV has
17581991Sheppo 	 * actually send pkts. Pkts between head and tail are
17591991Sheppo 	 * yet to be sent by HV.
17601991Sheppo 	 */
17611991Sheppo 	tx_head = ldcp->tx_ackd_head;
17621991Sheppo 	for (;;) {
17631991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_head);
17641991Sheppo 		tx_head = (tx_head + LDC_PACKET_SIZE) %
17654690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
17661991Sheppo 
17671991Sheppo 		if (pkt->seqid == msg->ackid) {
17681991Sheppo 			D2(ldcp->id,
17691991Sheppo 			    "i_ldc_process_data_ACK: (0x%llx) found packet\n",
17701991Sheppo 			    ldcp->id);
17711991Sheppo 			ldcp->last_ack_rcd = msg->ackid;
17721991Sheppo 			ldcp->tx_ackd_head = tx_head;
17731991Sheppo 			break;
17741991Sheppo 		}
17751991Sheppo 		if (tx_head == ldcp->tx_head) {
17761991Sheppo 			/* could not find packet */
17771991Sheppo 			DWARN(ldcp->id,
17781991Sheppo 			    "i_ldc_process_data_ACK: (0x%llx) invalid ACKid\n",
17791991Sheppo 			    ldcp->id);
17802336Snarayan 
17812336Snarayan 			/* Reset the channel -- as we cannot continue */
17822793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
17832336Snarayan 			mutex_exit(&ldcp->tx_lock);
17842336Snarayan 			return (ECONNRESET);
17851991Sheppo 		}
17861991Sheppo 	}
17871991Sheppo 
17882336Snarayan 	mutex_exit(&ldcp->tx_lock);
17891991Sheppo 	return (0);
17901991Sheppo }
17911991Sheppo 
17921991Sheppo /*
17931991Sheppo  * Process incoming control message
17941991Sheppo  * Return 0 - session can continue
17951991Sheppo  *        EAGAIN - reprocess packet - state was changed
17961991Sheppo  *	  ECONNRESET - channel was reset
17971991Sheppo  */
17981991Sheppo static int
17991991Sheppo i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *msg)
18001991Sheppo {
18011991Sheppo 	int 		rv = 0;
18021991Sheppo 
18032793Slm66018 	D1(ldcp->id, "i_ldc_ctrlmsg: (%llx) tstate = %lx, hstate = %lx\n",
18042793Slm66018 	    ldcp->id, ldcp->tstate, ldcp->hstate);
18052793Slm66018 
18062793Slm66018 	switch (ldcp->tstate & ~TS_IN_RESET) {
18071991Sheppo 
18081991Sheppo 	case TS_OPEN:
18091991Sheppo 	case TS_READY:
18101991Sheppo 
18111991Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
18121991Sheppo 		case LDC_VER:
18131991Sheppo 			/* process version message */
18141991Sheppo 			rv = i_ldc_process_VER(ldcp, msg);
18151991Sheppo 			break;
18161991Sheppo 		default:
18171991Sheppo 			DWARN(ldcp->id,
18181991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
18191991Sheppo 			    "tstate=0x%x\n", ldcp->id,
18201991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
18211991Sheppo 			break;
18221991Sheppo 		}
18231991Sheppo 
18241991Sheppo 		break;
18251991Sheppo 
18261991Sheppo 	case TS_VREADY:
18271991Sheppo 
18281991Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
18291991Sheppo 		case LDC_VER:
18302793Slm66018 			/* process version message */
18312793Slm66018 			rv = i_ldc_process_VER(ldcp, msg);
18321991Sheppo 			break;
18331991Sheppo 		case LDC_RTS:
18341991Sheppo 			/* process RTS message */
18351991Sheppo 			rv = i_ldc_process_RTS(ldcp, msg);
18361991Sheppo 			break;
18371991Sheppo 		case LDC_RTR:
18381991Sheppo 			/* process RTR message */
18391991Sheppo 			rv = i_ldc_process_RTR(ldcp, msg);
18401991Sheppo 			break;
18411991Sheppo 		case LDC_RDX:
18421991Sheppo 			/* process RDX message */
18431991Sheppo 			rv = i_ldc_process_RDX(ldcp, msg);
18441991Sheppo 			break;
18451991Sheppo 		default:
18461991Sheppo 			DWARN(ldcp->id,
18471991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
18481991Sheppo 			    "tstate=0x%x\n", ldcp->id,
18491991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
18501991Sheppo 			break;
18511991Sheppo 		}
18521991Sheppo 
18531991Sheppo 		break;
18541991Sheppo 
18551991Sheppo 	case TS_UP:
18561991Sheppo 
18571991Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
18581991Sheppo 		case LDC_VER:
18591991Sheppo 			DWARN(ldcp->id,
18601991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexpected VER "
18611991Sheppo 			    "- LDC reset\n", ldcp->id);
18621991Sheppo 			/* peer is redoing version negotiation */
18632336Snarayan 			mutex_enter(&ldcp->tx_lock);
18641991Sheppo 			(void) i_ldc_txq_reconf(ldcp);
18651991Sheppo 			i_ldc_reset_state(ldcp);
18662336Snarayan 			mutex_exit(&ldcp->tx_lock);
18671991Sheppo 			rv = EAGAIN;
18681991Sheppo 			break;
18691991Sheppo 
18701991Sheppo 		case LDC_RDX:
18711991Sheppo 			/* process RDX message */
18721991Sheppo 			rv = i_ldc_process_RDX(ldcp, msg);
18731991Sheppo 			break;
18741991Sheppo 
18751991Sheppo 		default:
18761991Sheppo 			DWARN(ldcp->id,
18771991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
18781991Sheppo 			    "tstate=0x%x\n", ldcp->id,
18791991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
18801991Sheppo 			break;
18811991Sheppo 		}
18821991Sheppo 	}
18831991Sheppo 
18841991Sheppo 	return (rv);
18851991Sheppo }
18861991Sheppo 
18871991Sheppo /*
18881991Sheppo  * Register channel with the channel nexus
18891991Sheppo  */
18901991Sheppo static int
18911991Sheppo i_ldc_register_channel(ldc_chan_t *ldcp)
18921991Sheppo {
18931991Sheppo 	int		rv = 0;
18941991Sheppo 	ldc_cnex_t	*cinfo = &ldcssp->cinfo;
18951991Sheppo 
18961991Sheppo 	if (cinfo->dip == NULL) {
18971991Sheppo 		DWARN(ldcp->id,
18981991Sheppo 		    "i_ldc_register_channel: cnex has not registered\n");
18991991Sheppo 		return (EAGAIN);
19001991Sheppo 	}
19011991Sheppo 
19021991Sheppo 	rv = cinfo->reg_chan(cinfo->dip, ldcp->id, ldcp->devclass);
19031991Sheppo 	if (rv) {
19041991Sheppo 		DWARN(ldcp->id,
19051991Sheppo 		    "i_ldc_register_channel: cannot register channel\n");
19061991Sheppo 		return (rv);
19071991Sheppo 	}
19081991Sheppo 
19091991Sheppo 	rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR,
19101991Sheppo 	    i_ldc_tx_hdlr, ldcp, NULL);
19111991Sheppo 	if (rv) {
19121991Sheppo 		DWARN(ldcp->id,
19131991Sheppo 		    "i_ldc_register_channel: cannot add Tx interrupt\n");
19141991Sheppo 		(void) cinfo->unreg_chan(cinfo->dip, ldcp->id);
19151991Sheppo 		return (rv);
19161991Sheppo 	}
19171991Sheppo 
19181991Sheppo 	rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR,
19191991Sheppo 	    i_ldc_rx_hdlr, ldcp, NULL);
19201991Sheppo 	if (rv) {
19211991Sheppo 		DWARN(ldcp->id,
19221991Sheppo 		    "i_ldc_register_channel: cannot add Rx interrupt\n");
19231991Sheppo 		(void) cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
19241991Sheppo 		(void) cinfo->unreg_chan(cinfo->dip, ldcp->id);
19251991Sheppo 		return (rv);
19261991Sheppo 	}
19271991Sheppo 
19281991Sheppo 	ldcp->tstate |= TS_CNEX_RDY;
19291991Sheppo 
19301991Sheppo 	return (0);
19311991Sheppo }
19321991Sheppo 
19331991Sheppo /*
19341991Sheppo  * Unregister a channel with the channel nexus
19351991Sheppo  */
19361991Sheppo static int
19371991Sheppo i_ldc_unregister_channel(ldc_chan_t *ldcp)
19381991Sheppo {
19391991Sheppo 	int		rv = 0;
19401991Sheppo 	ldc_cnex_t	*cinfo = &ldcssp->cinfo;
19411991Sheppo 
19421991Sheppo 	if (cinfo->dip == NULL) {
19431991Sheppo 		DWARN(ldcp->id,
19441991Sheppo 		    "i_ldc_unregister_channel: cnex has not registered\n");
19451991Sheppo 		return (EAGAIN);
19461991Sheppo 	}
19471991Sheppo 
19481991Sheppo 	if (ldcp->tstate & TS_CNEX_RDY) {
19491991Sheppo 
19502336Snarayan 		/* Remove the Rx interrupt */
19511991Sheppo 		rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR);
19521991Sheppo 		if (rv) {
19532793Slm66018 			if (rv != EAGAIN) {
19542793Slm66018 				DWARN(ldcp->id,
19552793Slm66018 				    "i_ldc_unregister_channel: err removing "
19562793Slm66018 				    "Rx intr\n");
19572793Slm66018 				return (rv);
19582793Slm66018 			}
19592793Slm66018 
19602793Slm66018 			/*
19612793Slm66018 			 * If interrupts are pending and handler has
19622793Slm66018 			 * finished running, clear interrupt and try
19632793Slm66018 			 * again
19642793Slm66018 			 */
19652793Slm66018 			if (ldcp->rx_intr_state != LDC_INTR_PEND)
19662793Slm66018 				return (rv);
19672793Slm66018 
19682793Slm66018 			(void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
19692793Slm66018 			rv = cinfo->rem_intr(cinfo->dip, ldcp->id,
19702793Slm66018 			    CNEX_RX_INTR);
19712793Slm66018 			if (rv) {
19722793Slm66018 				DWARN(ldcp->id, "i_ldc_unregister_channel: "
19732793Slm66018 				    "err removing Rx interrupt\n");
19742793Slm66018 				return (rv);
19752793Slm66018 			}
19761991Sheppo 		}
19772336Snarayan 
19782336Snarayan 		/* Remove the Tx interrupt */
19791991Sheppo 		rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
19801991Sheppo 		if (rv) {
19811991Sheppo 			DWARN(ldcp->id,
19821991Sheppo 			    "i_ldc_unregister_channel: err removing Tx intr\n");
19832336Snarayan 			return (rv);
19841991Sheppo 		}
19852336Snarayan 
19862336Snarayan 		/* Unregister the channel */
19871991Sheppo 		rv = cinfo->unreg_chan(ldcssp->cinfo.dip, ldcp->id);
19881991Sheppo 		if (rv) {
19891991Sheppo 			DWARN(ldcp->id,
19901991Sheppo 			    "i_ldc_unregister_channel: cannot unreg channel\n");
19912336Snarayan 			return (rv);
19921991Sheppo 		}
19931991Sheppo 
19941991Sheppo 		ldcp->tstate &= ~TS_CNEX_RDY;
19951991Sheppo 	}
19961991Sheppo 
19971991Sheppo 	return (0);
19981991Sheppo }
19991991Sheppo 
20001991Sheppo 
20011991Sheppo /*
20021991Sheppo  * LDC transmit interrupt handler
20031991Sheppo  *    triggered for chanel up/down/reset events
20041991Sheppo  *    and Tx queue content changes
20051991Sheppo  */
20061991Sheppo static uint_t
20071991Sheppo i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2)
20081991Sheppo {
20091991Sheppo 	_NOTE(ARGUNUSED(arg2))
20101991Sheppo 
20111991Sheppo 	int 		rv;
20121991Sheppo 	ldc_chan_t 	*ldcp;
20131991Sheppo 	boolean_t 	notify_client = B_FALSE;
20142793Slm66018 	uint64_t	notify_event = 0, link_state;
20151991Sheppo 
20161991Sheppo 	/* Get the channel for which interrupt was received */
20171991Sheppo 	ASSERT(arg1 != NULL);
20181991Sheppo 	ldcp = (ldc_chan_t *)arg1;
20191991Sheppo 
20201991Sheppo 	D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
20211991Sheppo 	    ldcp->id, ldcp);
20221991Sheppo 
20231991Sheppo 	/* Lock channel */
20241991Sheppo 	mutex_enter(&ldcp->lock);
20251991Sheppo 
20262336Snarayan 	/* Obtain Tx lock */
20272336Snarayan 	mutex_enter(&ldcp->tx_lock);
20282336Snarayan 
20292531Snarayan 	/* mark interrupt as pending */
20302793Slm66018 	ldcp->tx_intr_state = LDC_INTR_ACTIVE;
20312793Slm66018 
20322793Slm66018 	/* save current link state */
20332793Slm66018 	link_state = ldcp->link_state;
20342531Snarayan 
20351991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id, &ldcp->tx_head, &ldcp->tx_tail,
20361991Sheppo 	    &ldcp->link_state);
20371991Sheppo 	if (rv) {
20381991Sheppo 		cmn_err(CE_WARN,
20391991Sheppo 		    "i_ldc_tx_hdlr: (0x%lx) cannot read queue ptrs rv=0x%d\n",
20401991Sheppo 		    ldcp->id, rv);
20412531Snarayan 		i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
20422336Snarayan 		mutex_exit(&ldcp->tx_lock);
20431991Sheppo 		mutex_exit(&ldcp->lock);
20441991Sheppo 		return (DDI_INTR_CLAIMED);
20451991Sheppo 	}
20461991Sheppo 
20471991Sheppo 	/*
20481991Sheppo 	 * reset the channel state if the channel went down
20491991Sheppo 	 * (other side unconfigured queue) or channel was reset
20501991Sheppo 	 * (other side reconfigured its queue)
20511991Sheppo 	 */
20522793Slm66018 	if (link_state != ldcp->link_state &&
20532793Slm66018 	    ldcp->link_state == LDC_CHANNEL_DOWN) {
20541991Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link down\n", ldcp->id);
20552793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
20561991Sheppo 		notify_client = B_TRUE;
20571991Sheppo 		notify_event = LDC_EVT_DOWN;
20581991Sheppo 	}
20591991Sheppo 
20602793Slm66018 	if (link_state != ldcp->link_state &&
20612793Slm66018 	    ldcp->link_state == LDC_CHANNEL_RESET) {
20621991Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link reset\n", ldcp->id);
20632793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
20641991Sheppo 		notify_client = B_TRUE;
20651991Sheppo 		notify_event = LDC_EVT_RESET;
20661991Sheppo 	}
20671991Sheppo 
20682793Slm66018 	if (link_state != ldcp->link_state &&
20692793Slm66018 	    (ldcp->tstate & ~TS_IN_RESET) == TS_OPEN &&
20702793Slm66018 	    ldcp->link_state == LDC_CHANNEL_UP) {
20711991Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link up\n", ldcp->id);
20721991Sheppo 		notify_client = B_TRUE;
20731991Sheppo 		notify_event = LDC_EVT_RESET;
20741991Sheppo 		ldcp->tstate |= TS_LINK_READY;
20751991Sheppo 		ldcp->status = LDC_READY;
20761991Sheppo 	}
20771991Sheppo 
20781991Sheppo 	/* if callbacks are disabled, do not notify */
20791991Sheppo 	if (!ldcp->cb_enabled)
20801991Sheppo 		notify_client = B_FALSE;
20811991Sheppo 
20823151Ssg70180 	i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
20834690Snarayan 	mutex_exit(&ldcp->tx_lock);
20841991Sheppo 
20851991Sheppo 	if (notify_client) {
20862793Slm66018 		ldcp->cb_inprogress = B_TRUE;
20872793Slm66018 		mutex_exit(&ldcp->lock);
20881991Sheppo 		rv = ldcp->cb(notify_event, ldcp->cb_arg);
20891991Sheppo 		if (rv) {
20901991Sheppo 			DWARN(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) callback "
20911991Sheppo 			    "failure", ldcp->id);
20921991Sheppo 		}
20931991Sheppo 		mutex_enter(&ldcp->lock);
20941991Sheppo 		ldcp->cb_inprogress = B_FALSE;
20952793Slm66018 	}
20962793Slm66018 
20971991Sheppo 	mutex_exit(&ldcp->lock);
20981991Sheppo 
20991991Sheppo 	D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) exiting handler", ldcp->id);
21001991Sheppo 
21011991Sheppo 	return (DDI_INTR_CLAIMED);
21021991Sheppo }
21031991Sheppo 
21041991Sheppo /*
21055944Sha137994  * Process the Rx HV queue.
21065944Sha137994  *
21075944Sha137994  * Returns 0 if data packets were found and no errors were encountered,
21085944Sha137994  * otherwise returns an error. In either case, the *notify argument is
21095944Sha137994  * set to indicate whether or not the client callback function should
21105944Sha137994  * be invoked. The *event argument is set to contain the callback event.
21115944Sha137994  *
21125944Sha137994  * Depending on the channel mode, packets are handled differently:
21135944Sha137994  *
21145944Sha137994  * RAW MODE
21155944Sha137994  * For raw mode channels, when a data packet is encountered,
21165944Sha137994  * processing stops and all packets are left on the queue to be removed
21175944Sha137994  * and processed by the ldc_read code path.
21185944Sha137994  *
21195944Sha137994  * UNRELIABLE MODE
21205944Sha137994  * For unreliable mode, when a data packet is encountered, processing
21215944Sha137994  * stops, and all packets are left on the queue to be removed and
21225944Sha137994  * processed by the ldc_read code path. Control packets are processed
21235944Sha137994  * inline if they are encountered before any data packets.
21245944Sha137994  *
2125*6408Sha137994  * RELIABLE MODE
2126*6408Sha137994  * For reliable mode channels, all packets on the receive queue
21275944Sha137994  * are processed: data packets are copied to the data queue and
21285944Sha137994  * control packets are processed inline. Packets are only left on
21295944Sha137994  * the receive queue when the data queue is full.
21301991Sheppo  */
21311991Sheppo static uint_t
21325944Sha137994 i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client,
21335944Sha137994     uint64_t *notify_event)
21341991Sheppo {
21351991Sheppo 	int		rv;
21361991Sheppo 	uint64_t 	rx_head, rx_tail;
21371991Sheppo 	ldc_msg_t 	*msg;
21382793Slm66018 	uint64_t	link_state, first_fragment = 0;
21395944Sha137994 	boolean_t	trace_length = B_TRUE;
21405944Sha137994 
21415944Sha137994 	ASSERT(MUTEX_HELD(&ldcp->lock));
21425944Sha137994 	*notify_client = B_FALSE;
21435944Sha137994 	*notify_event = 0;
21441991Sheppo 
21451991Sheppo 	/*
21461991Sheppo 	 * Read packet(s) from the queue
21471991Sheppo 	 */
21481991Sheppo 	for (;;) {
21491991Sheppo 
21502793Slm66018 		link_state = ldcp->link_state;
21511991Sheppo 		rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
21521991Sheppo 		    &ldcp->link_state);
21531991Sheppo 		if (rv) {
21541991Sheppo 			cmn_err(CE_WARN,
21555944Sha137994 			    "i_ldc_rx_process_hvq: (0x%lx) cannot read "
21561991Sheppo 			    "queue ptrs, rv=0x%d\n", ldcp->id, rv);
21571991Sheppo 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
21585944Sha137994 			return (EIO);
21591991Sheppo 		}
21601991Sheppo 
21611991Sheppo 		/*
21621991Sheppo 		 * reset the channel state if the channel went down
21631991Sheppo 		 * (other side unconfigured queue) or channel was reset
21642793Slm66018 		 * (other side reconfigured its queue)
21651991Sheppo 		 */
21662793Slm66018 
21672793Slm66018 		if (link_state != ldcp->link_state) {
21683010Slm66018 
21692793Slm66018 			switch (ldcp->link_state) {
21702793Slm66018 			case LDC_CHANNEL_DOWN:
21715944Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: channel "
21722793Slm66018 				    "link down\n", ldcp->id);
21732793Slm66018 				mutex_enter(&ldcp->tx_lock);
21742793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
21752793Slm66018 				mutex_exit(&ldcp->tx_lock);
21765944Sha137994 				*notify_client = B_TRUE;
21775944Sha137994 				*notify_event = LDC_EVT_DOWN;
21782793Slm66018 				goto loop_exit;
21792793Slm66018 
21802793Slm66018 			case LDC_CHANNEL_UP:
21815944Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: "
21822793Slm66018 				    "channel link up\n", ldcp->id);
21832793Slm66018 
21842793Slm66018 				if ((ldcp->tstate & ~TS_IN_RESET) == TS_OPEN) {
21855944Sha137994 					*notify_client = B_TRUE;
21865944Sha137994 					*notify_event = LDC_EVT_RESET;
21872793Slm66018 					ldcp->tstate |= TS_LINK_READY;
21882793Slm66018 					ldcp->status = LDC_READY;
21892793Slm66018 				}
21902793Slm66018 				break;
21912793Slm66018 
21922793Slm66018 			case LDC_CHANNEL_RESET:
21932793Slm66018 			default:
21942793Slm66018 #ifdef DEBUG
21952793Slm66018 force_reset:
21962793Slm66018 #endif
21975944Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: channel "
21982793Slm66018 				    "link reset\n", ldcp->id);
21992793Slm66018 				mutex_enter(&ldcp->tx_lock);
22002793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
22012793Slm66018 				mutex_exit(&ldcp->tx_lock);
22025944Sha137994 				*notify_client = B_TRUE;
22035944Sha137994 				*notify_event = LDC_EVT_RESET;
22042793Slm66018 				break;
22052793Slm66018 			}
22061991Sheppo 		}
22072793Slm66018 
22082793Slm66018 #ifdef DEBUG
22092793Slm66018 		if (LDC_INJECT_RESET(ldcp))
22102793Slm66018 			goto force_reset;
22112793Slm66018 #endif
22125944Sha137994 		if (trace_length) {
22135944Sha137994 			TRACE_RXHVQ_LENGTH(ldcp, rx_head, rx_tail);
22145944Sha137994 			trace_length = B_FALSE;
22155944Sha137994 		}
22161991Sheppo 
22171991Sheppo 		if (rx_head == rx_tail) {
22185944Sha137994 			D2(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) "
22195944Sha137994 			    "No packets\n", ldcp->id);
22201991Sheppo 			break;
22211991Sheppo 		}
22222793Slm66018 
22235944Sha137994 		D2(ldcp->id, "i_ldc_rx_process_hvq: head=0x%llx, "
22245944Sha137994 		    "tail=0x%llx\n", rx_head, rx_tail);
22255944Sha137994 		DUMP_LDC_PKT(ldcp, "i_ldc_rx_process_hvq rcd",
22261991Sheppo 		    ldcp->rx_q_va + rx_head);
22271991Sheppo 
22281991Sheppo 		/* get the message */
22291991Sheppo 		msg = (ldc_msg_t *)(ldcp->rx_q_va + rx_head);
22301991Sheppo 
22311991Sheppo 		/* if channel is in RAW mode or data pkt, notify and return */
22321991Sheppo 		if (ldcp->mode == LDC_MODE_RAW) {
22335944Sha137994 			*notify_client = B_TRUE;
22345944Sha137994 			*notify_event |= LDC_EVT_READ;
22351991Sheppo 			break;
22361991Sheppo 		}
22371991Sheppo 
22381991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
22391991Sheppo 
22401991Sheppo 			/* discard packet if channel is not up */
22412793Slm66018 			if ((ldcp->tstate & ~TS_IN_RESET) != TS_UP) {
22421991Sheppo 
22431991Sheppo 				/* move the head one position */
22441991Sheppo 				rx_head = (rx_head + LDC_PACKET_SIZE) %
22454690Snarayan 				    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
22461991Sheppo 
22471991Sheppo 				if (rv = i_ldc_set_rx_head(ldcp, rx_head))
22481991Sheppo 					break;
22491991Sheppo 
22501991Sheppo 				continue;
22511991Sheppo 			} else {
22525944Sha137994 				uint64_t dq_head, dq_tail;
22535944Sha137994 
2254*6408Sha137994 				/* process only RELIABLE mode data packets */
2255*6408Sha137994 				if (ldcp->mode != LDC_MODE_RELIABLE) {
22565944Sha137994 					if ((ldcp->tstate & TS_IN_RESET) == 0)
22575944Sha137994 						*notify_client = B_TRUE;
22585944Sha137994 					*notify_event |= LDC_EVT_READ;
22595944Sha137994 					break;
22605944Sha137994 				}
22615944Sha137994 
22625944Sha137994 				/* don't process packet if queue full */
22635944Sha137994 				(void) i_ldc_dq_rx_get_state(ldcp, &dq_head,
22645944Sha137994 				    &dq_tail, NULL);
22655944Sha137994 				dq_tail = (dq_tail + LDC_PACKET_SIZE) %
22665944Sha137994 				    (ldcp->rx_dq_entries << LDC_PACKET_SHIFT);
22675944Sha137994 				if (dq_tail == dq_head ||
22685944Sha137994 				    LDC_INJECT_DQFULL(ldcp)) {
22695944Sha137994 					rv = ENOSPC;
22705944Sha137994 					break;
22715944Sha137994 				}
22721991Sheppo 			}
22731991Sheppo 		}
22741991Sheppo 
22751991Sheppo 		/* Check the sequence ID for the message received */
22762793Slm66018 		rv = i_ldc_check_seqid(ldcp, msg);
22772793Slm66018 		if (rv != 0) {
22781991Sheppo 
22795944Sha137994 			DWARN(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) "
22805944Sha137994 			    "seqid error, q_ptrs=0x%lx,0x%lx", ldcp->id,
22815944Sha137994 			    rx_head, rx_tail);
22821991Sheppo 
22831991Sheppo 			/* Reset last_msg_rcd to start of message */
22842336Snarayan 			if (first_fragment != 0) {
22852336Snarayan 				ldcp->last_msg_rcd = first_fragment - 1;
22862336Snarayan 				first_fragment = 0;
22871991Sheppo 			}
22882336Snarayan 
22891991Sheppo 			/*
22901991Sheppo 			 * Send a NACK due to seqid mismatch
22911991Sheppo 			 */
22924690Snarayan 			rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK,
22931991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK));
22941991Sheppo 
22951991Sheppo 			if (rv) {
22965944Sha137994 				cmn_err(CE_NOTE, "i_ldc_rx_process_hvq: "
22975944Sha137994 				    "(0x%lx) err sending CTRL/DATA NACK msg\n",
22985944Sha137994 				    ldcp->id);
22992336Snarayan 
23002336Snarayan 				/* if cannot send NACK - reset channel */
23012336Snarayan 				mutex_enter(&ldcp->tx_lock);
23022793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
23032336Snarayan 				mutex_exit(&ldcp->tx_lock);
23043560Snarayan 
23055944Sha137994 				*notify_client = B_TRUE;
23065944Sha137994 				*notify_event = LDC_EVT_RESET;
23072336Snarayan 				break;
23081991Sheppo 			}
23091991Sheppo 
23101991Sheppo 			/* purge receive queue */
23111991Sheppo 			(void) i_ldc_set_rx_head(ldcp, rx_tail);
23121991Sheppo 			break;
23131991Sheppo 		}
23141991Sheppo 
23151991Sheppo 		/* record the message ID */
23161991Sheppo 		ldcp->last_msg_rcd = msg->seqid;
23171991Sheppo 
23181991Sheppo 		/* process control messages */
23191991Sheppo 		if (msg->type & LDC_CTRL) {
23201991Sheppo 			/* save current internal state */
23211991Sheppo 			uint64_t tstate = ldcp->tstate;
23221991Sheppo 
23231991Sheppo 			rv = i_ldc_ctrlmsg(ldcp, msg);
23241991Sheppo 			if (rv == EAGAIN) {
23251991Sheppo 				/* re-process pkt - state was adjusted */
23261991Sheppo 				continue;
23271991Sheppo 			}
23281991Sheppo 			if (rv == ECONNRESET) {
23295944Sha137994 				*notify_client = B_TRUE;
23305944Sha137994 				*notify_event = LDC_EVT_RESET;
23311991Sheppo 				break;
23321991Sheppo 			}
23331991Sheppo 
23341991Sheppo 			/*
23351991Sheppo 			 * control message processing was successful
23361991Sheppo 			 * channel transitioned to ready for communication
23371991Sheppo 			 */
23381991Sheppo 			if (rv == 0 && ldcp->tstate == TS_UP &&
23392793Slm66018 			    (tstate & ~TS_IN_RESET) !=
23402793Slm66018 			    (ldcp->tstate & ~TS_IN_RESET)) {
23415944Sha137994 				*notify_client = B_TRUE;
23425944Sha137994 				*notify_event = LDC_EVT_UP;
23431991Sheppo 			}
23441991Sheppo 		}
23451991Sheppo 
23463560Snarayan 		/* process data NACKs */
23473560Snarayan 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) {
23483560Snarayan 			DWARN(ldcp->id,
23495944Sha137994 			    "i_ldc_rx_process_hvq: (0x%llx) received DATA/NACK",
23503560Snarayan 			    ldcp->id);
23513560Snarayan 			mutex_enter(&ldcp->tx_lock);
23523560Snarayan 			i_ldc_reset(ldcp, B_TRUE);
23533560Snarayan 			mutex_exit(&ldcp->tx_lock);
23545944Sha137994 			*notify_client = B_TRUE;
23555944Sha137994 			*notify_event = LDC_EVT_RESET;
23563560Snarayan 			break;
23573560Snarayan 		}
23583560Snarayan 
23591991Sheppo 		/* process data ACKs */
23601991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
23612336Snarayan 			if (rv = i_ldc_process_data_ACK(ldcp, msg)) {
23625944Sha137994 				*notify_client = B_TRUE;
23635944Sha137994 				*notify_event = LDC_EVT_RESET;
23642336Snarayan 				break;
23652336Snarayan 			}
23661991Sheppo 		}
23671991Sheppo 
23685944Sha137994 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
2369*6408Sha137994 			ASSERT(ldcp->mode == LDC_MODE_RELIABLE);
23705944Sha137994 
23715944Sha137994 			/*
23725944Sha137994 			 * Copy the data packet to the data queue. Note
23735944Sha137994 			 * that the copy routine updates the rx_head pointer.
23745944Sha137994 			 */
23755944Sha137994 			i_ldc_rxdq_copy(ldcp, &rx_head);
23765944Sha137994 
23775944Sha137994 			if ((ldcp->tstate & TS_IN_RESET) == 0)
23785944Sha137994 				*notify_client = B_TRUE;
23795944Sha137994 			*notify_event |= LDC_EVT_READ;
23805944Sha137994 		} else {
23815944Sha137994 			rx_head = (rx_head + LDC_PACKET_SIZE) %
23825944Sha137994 			    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
23835944Sha137994 		}
23845944Sha137994 
23851991Sheppo 		/* move the head one position */
23862032Slm66018 		if (rv = i_ldc_set_rx_head(ldcp, rx_head)) {
23875944Sha137994 			*notify_client = B_TRUE;
23885944Sha137994 			*notify_event = LDC_EVT_RESET;
23891991Sheppo 			break;
23902032Slm66018 		}
23911991Sheppo 
23921991Sheppo 	} /* for */
23931991Sheppo 
23942793Slm66018 loop_exit:
23952793Slm66018 
2396*6408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
23975944Sha137994 		/* ACK data packets */
23985944Sha137994 		if ((*notify_event &
23995944Sha137994 		    (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) {
24005944Sha137994 			int ack_rv;
24015944Sha137994 			ack_rv = i_ldc_send_pkt(ldcp, LDC_DATA, LDC_ACK, 0);
24025944Sha137994 			if (ack_rv && ack_rv != EWOULDBLOCK) {
24035944Sha137994 				cmn_err(CE_NOTE,
24045944Sha137994 				    "i_ldc_rx_process_hvq: (0x%lx) cannot "
24055944Sha137994 				    "send ACK\n", ldcp->id);
24065944Sha137994 
24075944Sha137994 				mutex_enter(&ldcp->tx_lock);
24085944Sha137994 				i_ldc_reset(ldcp, B_FALSE);
24095944Sha137994 				mutex_exit(&ldcp->tx_lock);
24105944Sha137994 
24115944Sha137994 				*notify_client = B_TRUE;
24125944Sha137994 				*notify_event = LDC_EVT_RESET;
24135944Sha137994 				goto skip_ackpeek;
24145944Sha137994 			}
24155944Sha137994 		}
24165944Sha137994 
24175944Sha137994 		/*
24185944Sha137994 		 * If we have no more space on the data queue, make sure
24195944Sha137994 		 * there are no ACKs on the rx queue waiting to be processed.
24205944Sha137994 		 */
24215944Sha137994 		if (rv == ENOSPC) {
24225944Sha137994 			if (i_ldc_rx_ackpeek(ldcp, rx_head, rx_tail) != 0) {
24235944Sha137994 				ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
24245944Sha137994 				*notify_client = B_TRUE;
24255944Sha137994 				*notify_event = LDC_EVT_RESET;
24265944Sha137994 			}
24275944Sha137994 		} else {
24285944Sha137994 			ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
24291991Sheppo 		}
24305944Sha137994 	}
24315944Sha137994 
24325944Sha137994 skip_ackpeek:
24335944Sha137994 
24345944Sha137994 	/* Return, indicating whether or not data packets were found */
24355944Sha137994 	if ((*notify_event & (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ)
24365944Sha137994 		return (0);
24375944Sha137994 
24385944Sha137994 	return (ENOMSG);
24391991Sheppo }
24401991Sheppo 
24415944Sha137994 /*
24425944Sha137994  * Process any ACK packets on the HV receive queue.
24435944Sha137994  *
2444*6408Sha137994  * This function is only used by RELIABLE mode channels when the
24455944Sha137994  * secondary data queue fills up and there are packets remaining on
24465944Sha137994  * the HV receive queue.
24475944Sha137994  */
24485944Sha137994 int
24495944Sha137994 i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, uint64_t rx_tail)
24505944Sha137994 {
24515944Sha137994 	int		rv = 0;
24525944Sha137994 	ldc_msg_t	*msg;
24535944Sha137994 
24545944Sha137994 	if (ldcp->rx_ack_head == ACKPEEK_HEAD_INVALID)
24555944Sha137994 		ldcp->rx_ack_head = rx_head;
24565944Sha137994 
24575944Sha137994 	while (ldcp->rx_ack_head != rx_tail) {
24585944Sha137994 		msg = (ldc_msg_t *)(ldcp->rx_q_va + ldcp->rx_ack_head);
24595944Sha137994 
24605944Sha137994 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
24615944Sha137994 			if (rv = i_ldc_process_data_ACK(ldcp, msg))
24625944Sha137994 				break;
24635944Sha137994 			msg->stype &= ~LDC_ACK;
24645944Sha137994 		}
24655944Sha137994 
24665944Sha137994 		ldcp->rx_ack_head =
24675944Sha137994 		    (ldcp->rx_ack_head + LDC_PACKET_SIZE) %
24685944Sha137994 		    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
24695944Sha137994 	}
24705944Sha137994 	return (rv);
24715944Sha137994 }
24721991Sheppo 
24731991Sheppo /* -------------------------------------------------------------------------- */
24741991Sheppo 
24751991Sheppo /*
24761991Sheppo  * LDC API functions
24771991Sheppo  */
24781991Sheppo 
24791991Sheppo /*
24801991Sheppo  * Initialize the channel. Allocate internal structure and memory for
24811991Sheppo  * TX/RX queues, and initialize locks.
24821991Sheppo  */
24831991Sheppo int
24841991Sheppo ldc_init(uint64_t id, ldc_attr_t *attr, ldc_handle_t *handle)
24851991Sheppo {
24861991Sheppo 	ldc_chan_t 	*ldcp;
24871991Sheppo 	int		rv, exit_val;
24881991Sheppo 	uint64_t	ra_base, nentries;
24892410Slm66018 	uint64_t	qlen;
24901991Sheppo 
24911991Sheppo 	exit_val = EINVAL;	/* guarantee an error if exit on failure */
24921991Sheppo 
24931991Sheppo 	if (attr == NULL) {
24941991Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid attr\n", id);
24951991Sheppo 		return (EINVAL);
24961991Sheppo 	}
24971991Sheppo 	if (handle == NULL) {
24981991Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid handle\n", id);
24991991Sheppo 		return (EINVAL);
25001991Sheppo 	}
25011991Sheppo 
25021991Sheppo 	/* check if channel is valid */
25031991Sheppo 	rv = hv_ldc_tx_qinfo(id, &ra_base, &nentries);
25041991Sheppo 	if (rv == H_ECHANNEL) {
25051991Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid channel id\n", id);
25061991Sheppo 		return (EINVAL);
25071991Sheppo 	}
25081991Sheppo 
25091991Sheppo 	/* check if the channel has already been initialized */
25101991Sheppo 	mutex_enter(&ldcssp->lock);
25111991Sheppo 	ldcp = ldcssp->chan_list;
25121991Sheppo 	while (ldcp != NULL) {
25131991Sheppo 		if (ldcp->id == id) {
25141991Sheppo 			DWARN(id, "ldc_init: (0x%llx) already initialized\n",
25151991Sheppo 			    id);
25161991Sheppo 			mutex_exit(&ldcssp->lock);
25171991Sheppo 			return (EADDRINUSE);
25181991Sheppo 		}
25191991Sheppo 		ldcp = ldcp->next;
25201991Sheppo 	}
25211991Sheppo 	mutex_exit(&ldcssp->lock);
25221991Sheppo 
25231991Sheppo 	ASSERT(ldcp == NULL);
25241991Sheppo 
25251991Sheppo 	*handle = 0;
25261991Sheppo 
25271991Sheppo 	/* Allocate an ldcp structure */
25281991Sheppo 	ldcp = kmem_zalloc(sizeof (ldc_chan_t), KM_SLEEP);
25291991Sheppo 
25302336Snarayan 	/*
25312336Snarayan 	 * Initialize the channel and Tx lock
25322336Snarayan 	 *
25332336Snarayan 	 * The channel 'lock' protects the entire channel and
25342336Snarayan 	 * should be acquired before initializing, resetting,
25352336Snarayan 	 * destroying or reading from a channel.
25362336Snarayan 	 *
25372336Snarayan 	 * The 'tx_lock' should be acquired prior to transmitting
25382336Snarayan 	 * data over the channel. The lock should also be acquired
25392336Snarayan 	 * prior to channel reconfiguration (in order to prevent
25402336Snarayan 	 * concurrent writes).
25412336Snarayan 	 *
25422336Snarayan 	 * ORDERING: When both locks are being acquired, to prevent
25432336Snarayan 	 * deadlocks, the channel lock should be always acquired prior
25442336Snarayan 	 * to the tx_lock.
25452336Snarayan 	 */
25461991Sheppo 	mutex_init(&ldcp->lock, NULL, MUTEX_DRIVER, NULL);
25472336Snarayan 	mutex_init(&ldcp->tx_lock, NULL, MUTEX_DRIVER, NULL);
25481991Sheppo 
25491991Sheppo 	/* Initialize the channel */
25501991Sheppo 	ldcp->id = id;
25511991Sheppo 	ldcp->cb = NULL;
25521991Sheppo 	ldcp->cb_arg = NULL;
25531991Sheppo 	ldcp->cb_inprogress = B_FALSE;
25541991Sheppo 	ldcp->cb_enabled = B_FALSE;
25551991Sheppo 	ldcp->next = NULL;
25561991Sheppo 
25571991Sheppo 	/* Read attributes */
25581991Sheppo 	ldcp->mode = attr->mode;
25591991Sheppo 	ldcp->devclass = attr->devclass;
25601991Sheppo 	ldcp->devinst = attr->instance;
25612410Slm66018 	ldcp->mtu = (attr->mtu > 0) ? attr->mtu : LDC_DEFAULT_MTU;
25621991Sheppo 
25631991Sheppo 	D1(ldcp->id,
25641991Sheppo 	    "ldc_init: (0x%llx) channel attributes, class=0x%x, "
25652410Slm66018 	    "instance=0x%llx, mode=%d, mtu=%d\n",
25662410Slm66018 	    ldcp->id, ldcp->devclass, ldcp->devinst, ldcp->mode, ldcp->mtu);
25671991Sheppo 
25681991Sheppo 	ldcp->next_vidx = 0;
25692793Slm66018 	ldcp->tstate = TS_IN_RESET;
25701991Sheppo 	ldcp->hstate = 0;
25711991Sheppo 	ldcp->last_msg_snt = LDC_INIT_SEQID;
25721991Sheppo 	ldcp->last_ack_rcd = 0;
25731991Sheppo 	ldcp->last_msg_rcd = 0;
25745944Sha137994 	ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
25751991Sheppo 
25761991Sheppo 	ldcp->stream_bufferp = NULL;
25771991Sheppo 	ldcp->exp_dring_list = NULL;
25781991Sheppo 	ldcp->imp_dring_list = NULL;
25791991Sheppo 	ldcp->mhdl_list = NULL;
25801991Sheppo 
25812793Slm66018 	ldcp->tx_intr_state = LDC_INTR_NONE;
25822793Slm66018 	ldcp->rx_intr_state = LDC_INTR_NONE;
25832793Slm66018 
25841991Sheppo 	/* Initialize payload size depending on whether channel is reliable */
25851991Sheppo 	switch (ldcp->mode) {
25861991Sheppo 	case LDC_MODE_RAW:
25871991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RAW;
25881991Sheppo 		ldcp->read_p = i_ldc_read_raw;
25891991Sheppo 		ldcp->write_p = i_ldc_write_raw;
25901991Sheppo 		break;
25911991Sheppo 	case LDC_MODE_UNRELIABLE:
25921991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_UNRELIABLE;
25931991Sheppo 		ldcp->read_p = i_ldc_read_packet;
25941991Sheppo 		ldcp->write_p = i_ldc_write_packet;
25951991Sheppo 		break;
25961991Sheppo 	case LDC_MODE_RELIABLE:
25971991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE;
25981991Sheppo 
25991991Sheppo 		ldcp->stream_remains = 0;
26001991Sheppo 		ldcp->stream_offset = 0;
26011991Sheppo 		ldcp->stream_bufferp = kmem_alloc(ldcp->mtu, KM_SLEEP);
26021991Sheppo 		ldcp->read_p = i_ldc_read_stream;
26031991Sheppo 		ldcp->write_p = i_ldc_write_stream;
26041991Sheppo 		break;
26051991Sheppo 	default:
26061991Sheppo 		exit_val = EINVAL;
26071991Sheppo 		goto cleanup_on_exit;
26081991Sheppo 	}
26091991Sheppo 
26102410Slm66018 	/*
26112410Slm66018 	 * qlen is (mtu * ldc_mtu_msgs) / pkt_payload. If this
26122410Slm66018 	 * value is smaller than default length of ldc_queue_entries,
26134690Snarayan 	 * qlen is set to ldc_queue_entries. Ensure that computed
26144690Snarayan 	 * length is a power-of-two value.
26152410Slm66018 	 */
26162410Slm66018 	qlen = (ldcp->mtu * ldc_mtu_msgs) / ldcp->pkt_payload;
26174690Snarayan 	if (!ISP2(qlen)) {
26184690Snarayan 		uint64_t	tmp = 1;
26194690Snarayan 		while (qlen) {
26204690Snarayan 			qlen >>= 1; tmp <<= 1;
26214690Snarayan 		}
26224690Snarayan 		qlen = tmp;
26234690Snarayan 	}
26244690Snarayan 
26252410Slm66018 	ldcp->rx_q_entries =
26264690Snarayan 	    (qlen < ldc_queue_entries) ? ldc_queue_entries : qlen;
26272410Slm66018 	ldcp->tx_q_entries = ldcp->rx_q_entries;
26282410Slm66018 
26294690Snarayan 	D1(ldcp->id, "ldc_init: queue length = 0x%llx\n", ldcp->rx_q_entries);
26302410Slm66018 
26311991Sheppo 	/* Create a transmit queue */
26321991Sheppo 	ldcp->tx_q_va = (uint64_t)
26334690Snarayan 	    contig_mem_alloc(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
26341991Sheppo 	if (ldcp->tx_q_va == NULL) {
26351991Sheppo 		cmn_err(CE_WARN,
26361991Sheppo 		    "ldc_init: (0x%lx) TX queue allocation failed\n",
26371991Sheppo 		    ldcp->id);
26381991Sheppo 		exit_val = ENOMEM;
26391991Sheppo 		goto cleanup_on_exit;
26401991Sheppo 	}
26411991Sheppo 	ldcp->tx_q_ra = va_to_pa((caddr_t)ldcp->tx_q_va);
26421991Sheppo 
26431991Sheppo 	D2(ldcp->id, "ldc_init: txq_va=0x%llx, txq_ra=0x%llx, entries=0x%llx\n",
26441991Sheppo 	    ldcp->tx_q_va, ldcp->tx_q_ra, ldcp->tx_q_entries);
26451991Sheppo 
26461991Sheppo 	ldcp->tstate |= TS_TXQ_RDY;
26471991Sheppo 
26481991Sheppo 	/* Create a receive queue */
26491991Sheppo 	ldcp->rx_q_va = (uint64_t)
26504690Snarayan 	    contig_mem_alloc(ldcp->rx_q_entries << LDC_PACKET_SHIFT);
26511991Sheppo 	if (ldcp->rx_q_va == NULL) {
26521991Sheppo 		cmn_err(CE_WARN,
26531991Sheppo 		    "ldc_init: (0x%lx) RX queue allocation failed\n",
26541991Sheppo 		    ldcp->id);
26551991Sheppo 		exit_val = ENOMEM;
26561991Sheppo 		goto cleanup_on_exit;
26571991Sheppo 	}
26581991Sheppo 	ldcp->rx_q_ra = va_to_pa((caddr_t)ldcp->rx_q_va);
26591991Sheppo 
26601991Sheppo 	D2(ldcp->id, "ldc_init: rxq_va=0x%llx, rxq_ra=0x%llx, entries=0x%llx\n",
26611991Sheppo 	    ldcp->rx_q_va, ldcp->rx_q_ra, ldcp->rx_q_entries);
26621991Sheppo 
26631991Sheppo 	ldcp->tstate |= TS_RXQ_RDY;
26641991Sheppo 
26655944Sha137994 	/* Setup a separate read data queue */
2666*6408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
26675944Sha137994 		ldcp->readq_get_state = i_ldc_dq_rx_get_state;
26685944Sha137994 		ldcp->readq_set_head  = i_ldc_set_rxdq_head;
26695944Sha137994 
26705944Sha137994 		/* Make sure the data queue multiplier is a power of 2 */
26715944Sha137994 		if (!ISP2(ldc_rxdq_multiplier)) {
26725944Sha137994 			D1(ldcp->id, "ldc_init: (0x%llx) ldc_rxdq_multiplier "
26735944Sha137994 			    "not a power of 2, resetting", ldcp->id);
26745944Sha137994 			ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER;
26755944Sha137994 		}
26765944Sha137994 
26775944Sha137994 		ldcp->rx_dq_entries = ldc_rxdq_multiplier * ldcp->rx_q_entries;
26785944Sha137994 		ldcp->rx_dq_va = (uint64_t)
26795944Sha137994 		    kmem_alloc(ldcp->rx_dq_entries << LDC_PACKET_SHIFT,
26805944Sha137994 		    KM_SLEEP);
26815944Sha137994 		if (ldcp->rx_dq_va == NULL) {
26825944Sha137994 			cmn_err(CE_WARN,
26835944Sha137994 			    "ldc_init: (0x%lx) RX data queue "
26845944Sha137994 			    "allocation failed\n", ldcp->id);
26855944Sha137994 			exit_val = ENOMEM;
26865944Sha137994 			goto cleanup_on_exit;
26875944Sha137994 		}
26885944Sha137994 
26895944Sha137994 		ldcp->rx_dq_head = ldcp->rx_dq_tail = 0;
26905944Sha137994 
26915944Sha137994 		D2(ldcp->id, "ldc_init: rx_dq_va=0x%llx, "
26925944Sha137994 		    "rx_dq_entries=0x%llx\n", ldcp->rx_dq_va,
26935944Sha137994 		    ldcp->rx_dq_entries);
26945944Sha137994 	} else {
26955944Sha137994 		ldcp->readq_get_state = i_ldc_hvq_rx_get_state;
26965944Sha137994 		ldcp->readq_set_head  = i_ldc_set_rx_head;
26975944Sha137994 	}
26985944Sha137994 
26991991Sheppo 	/* Init descriptor ring and memory handle list lock */
27001991Sheppo 	mutex_init(&ldcp->exp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
27011991Sheppo 	mutex_init(&ldcp->imp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
27021991Sheppo 	mutex_init(&ldcp->mlist_lock, NULL, MUTEX_DRIVER, NULL);
27031991Sheppo 
27041991Sheppo 	/* mark status as INITialized */
27051991Sheppo 	ldcp->status = LDC_INIT;
27061991Sheppo 
27071991Sheppo 	/* Add to channel list */
27081991Sheppo 	mutex_enter(&ldcssp->lock);
27091991Sheppo 	ldcp->next = ldcssp->chan_list;
27101991Sheppo 	ldcssp->chan_list = ldcp;
27111991Sheppo 	ldcssp->channel_count++;
27121991Sheppo 	mutex_exit(&ldcssp->lock);
27131991Sheppo 
27141991Sheppo 	/* set the handle */
27151991Sheppo 	*handle = (ldc_handle_t)ldcp;
27161991Sheppo 
27171991Sheppo 	D1(ldcp->id, "ldc_init: (0x%llx) channel initialized\n", ldcp->id);
27181991Sheppo 
27191991Sheppo 	return (0);
27201991Sheppo 
27211991Sheppo cleanup_on_exit:
27221991Sheppo 
2723*6408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp)
27241991Sheppo 		kmem_free(ldcp->stream_bufferp, ldcp->mtu);
27251991Sheppo 
27261991Sheppo 	if (ldcp->tstate & TS_TXQ_RDY)
27271991Sheppo 		contig_mem_free((caddr_t)ldcp->tx_q_va,
27281991Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
27291991Sheppo 
27301991Sheppo 	if (ldcp->tstate & TS_RXQ_RDY)
27311991Sheppo 		contig_mem_free((caddr_t)ldcp->rx_q_va,
27321991Sheppo 		    (ldcp->rx_q_entries << LDC_PACKET_SHIFT));
27331991Sheppo 
27342336Snarayan 	mutex_destroy(&ldcp->tx_lock);
27351991Sheppo 	mutex_destroy(&ldcp->lock);
27361991Sheppo 
27371991Sheppo 	if (ldcp)
27381991Sheppo 		kmem_free(ldcp, sizeof (ldc_chan_t));
27391991Sheppo 
27401991Sheppo 	return (exit_val);
27411991Sheppo }
27421991Sheppo 
27431991Sheppo /*
27441991Sheppo  * Finalizes the LDC connection. It will return EBUSY if the
27451991Sheppo  * channel is open. A ldc_close() has to be done prior to
27461991Sheppo  * a ldc_fini operation. It frees TX/RX queues, associated
27471991Sheppo  * with the channel
27481991Sheppo  */
27491991Sheppo int
27501991Sheppo ldc_fini(ldc_handle_t handle)
27511991Sheppo {
27521991Sheppo 	ldc_chan_t 	*ldcp;
27531991Sheppo 	ldc_chan_t 	*tmp_ldcp;
27541991Sheppo 	uint64_t 	id;
27551991Sheppo 
27561991Sheppo 	if (handle == NULL) {
27571991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel handle\n");
27581991Sheppo 		return (EINVAL);
27591991Sheppo 	}
27601991Sheppo 	ldcp = (ldc_chan_t *)handle;
27611991Sheppo 	id = ldcp->id;
27621991Sheppo 
27631991Sheppo 	mutex_enter(&ldcp->lock);
27641991Sheppo 
27652793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) > TS_INIT) {
27661991Sheppo 		DWARN(ldcp->id, "ldc_fini: (0x%llx) channel is open\n",
27671991Sheppo 		    ldcp->id);
27681991Sheppo 		mutex_exit(&ldcp->lock);
27691991Sheppo 		return (EBUSY);
27701991Sheppo 	}
27711991Sheppo 
27721991Sheppo 	/* Remove from the channel list */
27731991Sheppo 	mutex_enter(&ldcssp->lock);
27741991Sheppo 	tmp_ldcp = ldcssp->chan_list;
27751991Sheppo 	if (tmp_ldcp == ldcp) {
27761991Sheppo 		ldcssp->chan_list = ldcp->next;
27771991Sheppo 		ldcp->next = NULL;
27781991Sheppo 	} else {
27791991Sheppo 		while (tmp_ldcp != NULL) {
27801991Sheppo 			if (tmp_ldcp->next == ldcp) {
27811991Sheppo 				tmp_ldcp->next = ldcp->next;
27821991Sheppo 				ldcp->next = NULL;
27831991Sheppo 				break;
27841991Sheppo 			}
27851991Sheppo 			tmp_ldcp = tmp_ldcp->next;
27861991Sheppo 		}
27871991Sheppo 		if (tmp_ldcp == NULL) {
27881991Sheppo 			DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel hdl\n");
27891991Sheppo 			mutex_exit(&ldcssp->lock);
27901991Sheppo 			mutex_exit(&ldcp->lock);
27911991Sheppo 			return (EINVAL);
27921991Sheppo 		}
27931991Sheppo 	}
27941991Sheppo 
27951991Sheppo 	ldcssp->channel_count--;
27961991Sheppo 
27971991Sheppo 	mutex_exit(&ldcssp->lock);
27981991Sheppo 
27991991Sheppo 	/* Free the map table for this channel */
28001991Sheppo 	if (ldcp->mtbl) {
28011991Sheppo 		(void) hv_ldc_set_map_table(ldcp->id, NULL, NULL);
28022793Slm66018 		if (ldcp->mtbl->contigmem)
28032793Slm66018 			contig_mem_free(ldcp->mtbl->table, ldcp->mtbl->size);
28042793Slm66018 		else
28052793Slm66018 			kmem_free(ldcp->mtbl->table, ldcp->mtbl->size);
28061991Sheppo 		mutex_destroy(&ldcp->mtbl->lock);
28071991Sheppo 		kmem_free(ldcp->mtbl, sizeof (ldc_mtbl_t));
28081991Sheppo 	}
28091991Sheppo 
28101991Sheppo 	/* Destroy descriptor ring and memory handle list lock */
28111991Sheppo 	mutex_destroy(&ldcp->exp_dlist_lock);
28121991Sheppo 	mutex_destroy(&ldcp->imp_dlist_lock);
28131991Sheppo 	mutex_destroy(&ldcp->mlist_lock);
28141991Sheppo 
2815*6408Sha137994 	/* Free the stream buffer for RELIABLE_MODE */
2816*6408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp)
28171991Sheppo 		kmem_free(ldcp->stream_bufferp, ldcp->mtu);
28181991Sheppo 
28191991Sheppo 	/* Free the RX queue */
28201991Sheppo 	contig_mem_free((caddr_t)ldcp->rx_q_va,
28211991Sheppo 	    (ldcp->rx_q_entries << LDC_PACKET_SHIFT));
28221991Sheppo 	ldcp->tstate &= ~TS_RXQ_RDY;
28231991Sheppo 
28245944Sha137994 	/* Free the RX data queue */
2825*6408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
28265944Sha137994 		kmem_free((caddr_t)ldcp->rx_dq_va,
28275944Sha137994 		    (ldcp->rx_dq_entries << LDC_PACKET_SHIFT));
28285944Sha137994 	}
28295944Sha137994 
28301991Sheppo 	/* Free the TX queue */
28311991Sheppo 	contig_mem_free((caddr_t)ldcp->tx_q_va,
28321991Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
28331991Sheppo 	ldcp->tstate &= ~TS_TXQ_RDY;
28341991Sheppo 
28351991Sheppo 	mutex_exit(&ldcp->lock);
28361991Sheppo 
28371991Sheppo 	/* Destroy mutex */
28382336Snarayan 	mutex_destroy(&ldcp->tx_lock);
28391991Sheppo 	mutex_destroy(&ldcp->lock);
28401991Sheppo 
28411991Sheppo 	/* free channel structure */
28421991Sheppo 	kmem_free(ldcp, sizeof (ldc_chan_t));
28431991Sheppo 
28441991Sheppo 	D1(id, "ldc_fini: (0x%llx) channel finalized\n", id);
28451991Sheppo 
28461991Sheppo 	return (0);
28471991Sheppo }
28481991Sheppo 
28491991Sheppo /*
28501991Sheppo  * Open the LDC channel for use. It registers the TX/RX queues
28511991Sheppo  * with the Hypervisor. It also specifies the interrupt number
28521991Sheppo  * and target CPU for this channel
28531991Sheppo  */
28541991Sheppo int
28551991Sheppo ldc_open(ldc_handle_t handle)
28561991Sheppo {
28571991Sheppo 	ldc_chan_t 	*ldcp;
28581991Sheppo 	int 		rv;
28591991Sheppo 
28601991Sheppo 	if (handle == NULL) {
28611991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_open: invalid channel handle\n");
28621991Sheppo 		return (EINVAL);
28631991Sheppo 	}
28641991Sheppo 
28651991Sheppo 	ldcp = (ldc_chan_t *)handle;
28661991Sheppo 
28671991Sheppo 	mutex_enter(&ldcp->lock);
28681991Sheppo 
28691991Sheppo 	if (ldcp->tstate < TS_INIT) {
28701991Sheppo 		DWARN(ldcp->id,
28711991Sheppo 		    "ldc_open: (0x%llx) channel not initialized\n", ldcp->id);
28721991Sheppo 		mutex_exit(&ldcp->lock);
28731991Sheppo 		return (EFAULT);
28741991Sheppo 	}
28752793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) >= TS_OPEN) {
28761991Sheppo 		DWARN(ldcp->id,
28771991Sheppo 		    "ldc_open: (0x%llx) channel is already open\n", ldcp->id);
28781991Sheppo 		mutex_exit(&ldcp->lock);
28791991Sheppo 		return (EFAULT);
28801991Sheppo 	}
28811991Sheppo 
28821991Sheppo 	/*
28831991Sheppo 	 * Unregister/Register the tx queue with the hypervisor
28841991Sheppo 	 */
28851991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
28861991Sheppo 	if (rv) {
28871991Sheppo 		cmn_err(CE_WARN,
28881991Sheppo 		    "ldc_open: (0x%lx) channel tx queue unconf failed\n",
28891991Sheppo 		    ldcp->id);
28901991Sheppo 		mutex_exit(&ldcp->lock);
28911991Sheppo 		return (EIO);
28921991Sheppo 	}
28931991Sheppo 
28941991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
28951991Sheppo 	if (rv) {
28961991Sheppo 		cmn_err(CE_WARN,
28971991Sheppo 		    "ldc_open: (0x%lx) channel tx queue conf failed\n",
28981991Sheppo 		    ldcp->id);
28991991Sheppo 		mutex_exit(&ldcp->lock);
29001991Sheppo 		return (EIO);
29011991Sheppo 	}
29021991Sheppo 
29031991Sheppo 	D2(ldcp->id, "ldc_open: (0x%llx) registered tx queue with LDC\n",
29041991Sheppo 	    ldcp->id);
29051991Sheppo 
29061991Sheppo 	/*
29071991Sheppo 	 * Unregister/Register the rx queue with the hypervisor
29081991Sheppo 	 */
29091991Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
29101991Sheppo 	if (rv) {
29111991Sheppo 		cmn_err(CE_WARN,
29121991Sheppo 		    "ldc_open: (0x%lx) channel rx queue unconf failed\n",
29131991Sheppo 		    ldcp->id);
29141991Sheppo 		mutex_exit(&ldcp->lock);
29151991Sheppo 		return (EIO);
29161991Sheppo 	}
29171991Sheppo 
29181991Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, ldcp->rx_q_entries);
29191991Sheppo 	if (rv) {
29201991Sheppo 		cmn_err(CE_WARN,
29211991Sheppo 		    "ldc_open: (0x%lx) channel rx queue conf failed\n",
29221991Sheppo 		    ldcp->id);
29231991Sheppo 		mutex_exit(&ldcp->lock);
29241991Sheppo 		return (EIO);
29251991Sheppo 	}
29261991Sheppo 
29271991Sheppo 	D2(ldcp->id, "ldc_open: (0x%llx) registered rx queue with LDC\n",
29281991Sheppo 	    ldcp->id);
29291991Sheppo 
29301991Sheppo 	ldcp->tstate |= TS_QCONF_RDY;
29311991Sheppo 
29321991Sheppo 	/* Register the channel with the channel nexus */
29331991Sheppo 	rv = i_ldc_register_channel(ldcp);
29341991Sheppo 	if (rv && rv != EAGAIN) {
29351991Sheppo 		cmn_err(CE_WARN,
29361991Sheppo 		    "ldc_open: (0x%lx) channel register failed\n", ldcp->id);
29371991Sheppo 		(void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
29381991Sheppo 		(void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
29391991Sheppo 		mutex_exit(&ldcp->lock);
29401991Sheppo 		return (EIO);
29411991Sheppo 	}
29421991Sheppo 
29431991Sheppo 	/* mark channel in OPEN state */
29441991Sheppo 	ldcp->status = LDC_OPEN;
29451991Sheppo 
29461991Sheppo 	/* Read channel state */
29471991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
29481991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
29491991Sheppo 	if (rv) {
29501991Sheppo 		cmn_err(CE_WARN,
29511991Sheppo 		    "ldc_open: (0x%lx) cannot read channel state\n",
29521991Sheppo 		    ldcp->id);
29531991Sheppo 		(void) i_ldc_unregister_channel(ldcp);
29541991Sheppo 		(void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
29551991Sheppo 		(void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
29561991Sheppo 		mutex_exit(&ldcp->lock);
29571991Sheppo 		return (EIO);
29581991Sheppo 	}
29591991Sheppo 
29601991Sheppo 	/*
2961*6408Sha137994 	 * set the ACKd head to current head location for reliable
29621991Sheppo 	 */
29631991Sheppo 	ldcp->tx_ackd_head = ldcp->tx_head;
29641991Sheppo 
29651991Sheppo 	/* mark channel ready if HV report link is UP (peer alloc'd Rx queue) */
29661991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_UP ||
29671991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
29681991Sheppo 		ldcp->tstate |= TS_LINK_READY;
29691991Sheppo 		ldcp->status = LDC_READY;
29701991Sheppo 	}
29711991Sheppo 
29721991Sheppo 	/*
29731991Sheppo 	 * if channel is being opened in RAW mode - no handshake is needed
29741991Sheppo 	 * switch the channel READY and UP state
29751991Sheppo 	 */
29761991Sheppo 	if (ldcp->mode == LDC_MODE_RAW) {
29771991Sheppo 		ldcp->tstate = TS_UP;	/* set bits associated with LDC UP */
29781991Sheppo 		ldcp->status = LDC_UP;
29791991Sheppo 	}
29801991Sheppo 
29811991Sheppo 	mutex_exit(&ldcp->lock);
29821991Sheppo 
29831991Sheppo 	/*
29841991Sheppo 	 * Increment number of open channels
29851991Sheppo 	 */
29861991Sheppo 	mutex_enter(&ldcssp->lock);
29871991Sheppo 	ldcssp->channels_open++;
29881991Sheppo 	mutex_exit(&ldcssp->lock);
29891991Sheppo 
29903010Slm66018 	D1(ldcp->id,
29912793Slm66018 	    "ldc_open: (0x%llx) channel (0x%p) open for use "
29922793Slm66018 	    "(tstate=0x%x, status=0x%x)\n",
29932793Slm66018 	    ldcp->id, ldcp, ldcp->tstate, ldcp->status);
29941991Sheppo 
29951991Sheppo 	return (0);
29961991Sheppo }
29971991Sheppo 
29981991Sheppo /*
29991991Sheppo  * Close the LDC connection. It will return EBUSY if there
30001991Sheppo  * are memory segments or descriptor rings either bound to or
30011991Sheppo  * mapped over the channel
30021991Sheppo  */
30031991Sheppo int
30041991Sheppo ldc_close(ldc_handle_t handle)
30051991Sheppo {
30061991Sheppo 	ldc_chan_t 	*ldcp;
30072336Snarayan 	int		rv = 0, retries = 0;
30081991Sheppo 	boolean_t	chk_done = B_FALSE;
30091991Sheppo 
30101991Sheppo 	if (handle == NULL) {
30111991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_close: invalid channel handle\n");
30121991Sheppo 		return (EINVAL);
30131991Sheppo 	}
30141991Sheppo 	ldcp = (ldc_chan_t *)handle;
30151991Sheppo 
30161991Sheppo 	mutex_enter(&ldcp->lock);
30171991Sheppo 
30181991Sheppo 	/* return error if channel is not open */
30192793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) < TS_OPEN) {
30201991Sheppo 		DWARN(ldcp->id,
30211991Sheppo 		    "ldc_close: (0x%llx) channel is not open\n", ldcp->id);
30221991Sheppo 		mutex_exit(&ldcp->lock);
30231991Sheppo 		return (EFAULT);
30241991Sheppo 	}
30251991Sheppo 
30261991Sheppo 	/* if any memory handles, drings, are bound or mapped cannot close */
30271991Sheppo 	if (ldcp->mhdl_list != NULL) {
30281991Sheppo 		DWARN(ldcp->id,
30291991Sheppo 		    "ldc_close: (0x%llx) channel has bound memory handles\n",
30301991Sheppo 		    ldcp->id);
30311991Sheppo 		mutex_exit(&ldcp->lock);
30321991Sheppo 		return (EBUSY);
30331991Sheppo 	}
30341991Sheppo 	if (ldcp->exp_dring_list != NULL) {
30351991Sheppo 		DWARN(ldcp->id,
30361991Sheppo 		    "ldc_close: (0x%llx) channel has bound descriptor rings\n",
30371991Sheppo 		    ldcp->id);
30381991Sheppo 		mutex_exit(&ldcp->lock);
30391991Sheppo 		return (EBUSY);
30401991Sheppo 	}
30411991Sheppo 	if (ldcp->imp_dring_list != NULL) {
30421991Sheppo 		DWARN(ldcp->id,
30431991Sheppo 		    "ldc_close: (0x%llx) channel has mapped descriptor rings\n",
30441991Sheppo 		    ldcp->id);
30451991Sheppo 		mutex_exit(&ldcp->lock);
30461991Sheppo 		return (EBUSY);
30471991Sheppo 	}
30481991Sheppo 
30493151Ssg70180 	if (ldcp->cb_inprogress) {
30503151Ssg70180 		DWARN(ldcp->id, "ldc_close: (0x%llx) callback active\n",
30513151Ssg70180 		    ldcp->id);
30523151Ssg70180 		mutex_exit(&ldcp->lock);
30533151Ssg70180 		return (EWOULDBLOCK);
30543151Ssg70180 	}
30553151Ssg70180 
30562336Snarayan 	/* Obtain Tx lock */
30572336Snarayan 	mutex_enter(&ldcp->tx_lock);
30582336Snarayan 
30591991Sheppo 	/*
30601991Sheppo 	 * Wait for pending transmits to complete i.e Tx queue to drain
30611991Sheppo 	 * if there are pending pkts - wait 1 ms and retry again
30621991Sheppo 	 */
30631991Sheppo 	for (;;) {
30641991Sheppo 
30651991Sheppo 		rv = hv_ldc_tx_get_state(ldcp->id,
30661991Sheppo 		    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
30671991Sheppo 		if (rv) {
30681991Sheppo 			cmn_err(CE_WARN,
30691991Sheppo 			    "ldc_close: (0x%lx) cannot read qptrs\n", ldcp->id);
30702336Snarayan 			mutex_exit(&ldcp->tx_lock);
30711991Sheppo 			mutex_exit(&ldcp->lock);
30721991Sheppo 			return (EIO);
30731991Sheppo 		}
30741991Sheppo 
30751991Sheppo 		if (ldcp->tx_head == ldcp->tx_tail ||
30761991Sheppo 		    ldcp->link_state != LDC_CHANNEL_UP) {
30771991Sheppo 			break;
30781991Sheppo 		}
30791991Sheppo 
30801991Sheppo 		if (chk_done) {
30811991Sheppo 			DWARN(ldcp->id,
30821991Sheppo 			    "ldc_close: (0x%llx) Tx queue drain timeout\n",
30831991Sheppo 			    ldcp->id);
30841991Sheppo 			break;
30851991Sheppo 		}
30861991Sheppo 
30871991Sheppo 		/* wait for one ms and try again */
30881991Sheppo 		delay(drv_usectohz(1000));
30891991Sheppo 		chk_done = B_TRUE;
30901991Sheppo 	}
30911991Sheppo 
30921991Sheppo 	/*
30932841Snarayan 	 * Drain the Tx and Rx queues as we are closing the
30942841Snarayan 	 * channel. We dont care about any pending packets.
30952841Snarayan 	 * We have to also drain the queue prior to clearing
30962841Snarayan 	 * pending interrupts, otherwise the HV will trigger
30972841Snarayan 	 * an interrupt the moment the interrupt state is
30982841Snarayan 	 * cleared.
30992793Slm66018 	 */
31002793Slm66018 	(void) i_ldc_txq_reconf(ldcp);
31012841Snarayan 	(void) i_ldc_rxq_drain(ldcp);
31022793Slm66018 
31032793Slm66018 	/*
31041991Sheppo 	 * Unregister the channel with the nexus
31051991Sheppo 	 */
31062336Snarayan 	while ((rv = i_ldc_unregister_channel(ldcp)) != 0) {
31072336Snarayan 
31082336Snarayan 		mutex_exit(&ldcp->tx_lock);
31091991Sheppo 		mutex_exit(&ldcp->lock);
31102336Snarayan 
31112336Snarayan 		/* if any error other than EAGAIN return back */
31122841Snarayan 		if (rv != EAGAIN || retries >= ldc_max_retries) {
31132336Snarayan 			cmn_err(CE_WARN,
31142336Snarayan 			    "ldc_close: (0x%lx) unregister failed, %d\n",
31152336Snarayan 			    ldcp->id, rv);
31162336Snarayan 			return (rv);
31172336Snarayan 		}
31182336Snarayan 
31192336Snarayan 		/*
31202336Snarayan 		 * As there could be pending interrupts we need
31212336Snarayan 		 * to wait and try again
31222336Snarayan 		 */
31233151Ssg70180 		drv_usecwait(ldc_close_delay);
31242336Snarayan 		mutex_enter(&ldcp->lock);
31252336Snarayan 		mutex_enter(&ldcp->tx_lock);
31262336Snarayan 		retries++;
31271991Sheppo 	}
31281991Sheppo 
31291991Sheppo 	/*
31301991Sheppo 	 * Unregister queues
31311991Sheppo 	 */
31321991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
31331991Sheppo 	if (rv) {
31341991Sheppo 		cmn_err(CE_WARN,
31351991Sheppo 		    "ldc_close: (0x%lx) channel TX queue unconf failed\n",
31361991Sheppo 		    ldcp->id);
31372336Snarayan 		mutex_exit(&ldcp->tx_lock);
31381991Sheppo 		mutex_exit(&ldcp->lock);
31391991Sheppo 		return (EIO);
31401991Sheppo 	}
31411991Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
31421991Sheppo 	if (rv) {
31431991Sheppo 		cmn_err(CE_WARN,
31441991Sheppo 		    "ldc_close: (0x%lx) channel RX queue unconf failed\n",
31451991Sheppo 		    ldcp->id);
31462336Snarayan 		mutex_exit(&ldcp->tx_lock);
31471991Sheppo 		mutex_exit(&ldcp->lock);
31481991Sheppo 		return (EIO);
31491991Sheppo 	}
31501991Sheppo 
31511991Sheppo 	ldcp->tstate &= ~TS_QCONF_RDY;
31521991Sheppo 
31531991Sheppo 	/* Reset channel state information */
31541991Sheppo 	i_ldc_reset_state(ldcp);
31551991Sheppo 
31561991Sheppo 	/* Mark channel as down and in initialized state */
31571991Sheppo 	ldcp->tx_ackd_head = 0;
31581991Sheppo 	ldcp->tx_head = 0;
31592793Slm66018 	ldcp->tstate = TS_IN_RESET|TS_INIT;
31601991Sheppo 	ldcp->status = LDC_INIT;
31611991Sheppo 
31622336Snarayan 	mutex_exit(&ldcp->tx_lock);
31631991Sheppo 	mutex_exit(&ldcp->lock);
31641991Sheppo 
31651991Sheppo 	/* Decrement number of open channels */
31661991Sheppo 	mutex_enter(&ldcssp->lock);
31671991Sheppo 	ldcssp->channels_open--;
31681991Sheppo 	mutex_exit(&ldcssp->lock);
31691991Sheppo 
31701991Sheppo 	D1(ldcp->id, "ldc_close: (0x%llx) channel closed\n", ldcp->id);
31711991Sheppo 
31721991Sheppo 	return (0);
31731991Sheppo }
31741991Sheppo 
31751991Sheppo /*
31761991Sheppo  * Register channel callback
31771991Sheppo  */
31781991Sheppo int
31791991Sheppo ldc_reg_callback(ldc_handle_t handle,
31801991Sheppo     uint_t(*cb)(uint64_t event, caddr_t arg), caddr_t arg)
31811991Sheppo {
31821991Sheppo 	ldc_chan_t *ldcp;
31831991Sheppo 
31841991Sheppo 	if (handle == NULL) {
31851991Sheppo 		DWARN(DBG_ALL_LDCS,
31861991Sheppo 		    "ldc_reg_callback: invalid channel handle\n");
31871991Sheppo 		return (EINVAL);
31881991Sheppo 	}
31891991Sheppo 	if (((uint64_t)cb) < KERNELBASE) {
31901991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_reg_callback: invalid callback\n");
31911991Sheppo 		return (EINVAL);
31921991Sheppo 	}
31931991Sheppo 	ldcp = (ldc_chan_t *)handle;
31941991Sheppo 
31951991Sheppo 	mutex_enter(&ldcp->lock);
31961991Sheppo 
31971991Sheppo 	if (ldcp->cb) {
31981991Sheppo 		DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback exists\n",
31991991Sheppo 		    ldcp->id);
32001991Sheppo 		mutex_exit(&ldcp->lock);
32011991Sheppo 		return (EIO);
32021991Sheppo 	}
32031991Sheppo 	if (ldcp->cb_inprogress) {
32041991Sheppo 		DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback active\n",
32051991Sheppo 		    ldcp->id);
32061991Sheppo 		mutex_exit(&ldcp->lock);
32071991Sheppo 		return (EWOULDBLOCK);
32081991Sheppo 	}
32091991Sheppo 
32101991Sheppo 	ldcp->cb = cb;
32111991Sheppo 	ldcp->cb_arg = arg;
32121991Sheppo 	ldcp->cb_enabled = B_TRUE;
32131991Sheppo 
32141991Sheppo 	D1(ldcp->id,
32151991Sheppo 	    "ldc_reg_callback: (0x%llx) registered callback for channel\n",
32161991Sheppo 	    ldcp->id);
32171991Sheppo 
32181991Sheppo 	mutex_exit(&ldcp->lock);
32191991Sheppo 
32201991Sheppo 	return (0);
32211991Sheppo }
32221991Sheppo 
32231991Sheppo /*
32241991Sheppo  * Unregister channel callback
32251991Sheppo  */
32261991Sheppo int
32271991Sheppo ldc_unreg_callback(ldc_handle_t handle)
32281991Sheppo {
32291991Sheppo 	ldc_chan_t *ldcp;
32301991Sheppo 
32311991Sheppo 	if (handle == NULL) {
32321991Sheppo 		DWARN(DBG_ALL_LDCS,
32331991Sheppo 		    "ldc_unreg_callback: invalid channel handle\n");
32341991Sheppo 		return (EINVAL);
32351991Sheppo 	}
32361991Sheppo 	ldcp = (ldc_chan_t *)handle;
32371991Sheppo 
32381991Sheppo 	mutex_enter(&ldcp->lock);
32391991Sheppo 
32401991Sheppo 	if (ldcp->cb == NULL) {
32411991Sheppo 		DWARN(ldcp->id,
32421991Sheppo 		    "ldc_unreg_callback: (0x%llx) no callback exists\n",
32431991Sheppo 		    ldcp->id);
32441991Sheppo 		mutex_exit(&ldcp->lock);
32451991Sheppo 		return (EIO);
32461991Sheppo 	}
32471991Sheppo 	if (ldcp->cb_inprogress) {
32481991Sheppo 		DWARN(ldcp->id,
32491991Sheppo 		    "ldc_unreg_callback: (0x%llx) callback active\n",
32501991Sheppo 		    ldcp->id);
32511991Sheppo 		mutex_exit(&ldcp->lock);
32521991Sheppo 		return (EWOULDBLOCK);
32531991Sheppo 	}
32541991Sheppo 
32551991Sheppo 	ldcp->cb = NULL;
32561991Sheppo 	ldcp->cb_arg = NULL;
32571991Sheppo 	ldcp->cb_enabled = B_FALSE;
32581991Sheppo 
32591991Sheppo 	D1(ldcp->id,
32601991Sheppo 	    "ldc_unreg_callback: (0x%llx) unregistered callback for channel\n",
32611991Sheppo 	    ldcp->id);
32621991Sheppo 
32631991Sheppo 	mutex_exit(&ldcp->lock);
32641991Sheppo 
32651991Sheppo 	return (0);
32661991Sheppo }
32671991Sheppo 
32681991Sheppo 
32691991Sheppo /*
32701991Sheppo  * Bring a channel up by initiating a handshake with the peer
32711991Sheppo  * This call is asynchronous. It will complete at a later point
32721991Sheppo  * in time when the peer responds back with an RTR.
32731991Sheppo  */
32741991Sheppo int
32751991Sheppo ldc_up(ldc_handle_t handle)
32761991Sheppo {
32771991Sheppo 	int 		rv;
32781991Sheppo 	ldc_chan_t 	*ldcp;
32791991Sheppo 	ldc_msg_t 	*ldcmsg;
32803808Ssb155480 	uint64_t 	tx_tail, tstate, link_state;
32811991Sheppo 
32821991Sheppo 	if (handle == NULL) {
32831991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_up: invalid channel handle\n");
32841991Sheppo 		return (EINVAL);
32851991Sheppo 	}
32861991Sheppo 	ldcp = (ldc_chan_t *)handle;
32871991Sheppo 
32881991Sheppo 	mutex_enter(&ldcp->lock);
32891991Sheppo 
32902793Slm66018 	D1(ldcp->id, "ldc_up: (0x%llx) doing channel UP\n", ldcp->id);
32912793Slm66018 
32922793Slm66018 	/* clear the reset state */
32932793Slm66018 	tstate = ldcp->tstate;
32942793Slm66018 	ldcp->tstate &= ~TS_IN_RESET;
32952793Slm66018 
32961991Sheppo 	if (ldcp->tstate == TS_UP) {
32972793Slm66018 		DWARN(ldcp->id,
32981991Sheppo 		    "ldc_up: (0x%llx) channel is already in UP state\n",
32991991Sheppo 		    ldcp->id);
33002793Slm66018 
33012793Slm66018 		/* mark channel as up */
33022793Slm66018 		ldcp->status = LDC_UP;
33032793Slm66018 
33042793Slm66018 		/*
33052793Slm66018 		 * if channel was in reset state and there was
33062793Slm66018 		 * pending data clear interrupt state. this will
33072793Slm66018 		 * trigger an interrupt, causing the RX handler to
33082793Slm66018 		 * to invoke the client's callback
33092793Slm66018 		 */
33102793Slm66018 		if ((tstate & TS_IN_RESET) &&
33112793Slm66018 		    ldcp->rx_intr_state == LDC_INTR_PEND) {
33123010Slm66018 			D1(ldcp->id,
33132793Slm66018 			    "ldc_up: (0x%llx) channel has pending data, "
33142793Slm66018 			    "clearing interrupt\n", ldcp->id);
33152793Slm66018 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
33162793Slm66018 		}
33172793Slm66018 
33181991Sheppo 		mutex_exit(&ldcp->lock);
33191991Sheppo 		return (0);
33201991Sheppo 	}
33211991Sheppo 
33221991Sheppo 	/* if the channel is in RAW mode - mark it as UP, if READY */
33231991Sheppo 	if (ldcp->mode == LDC_MODE_RAW && ldcp->tstate >= TS_READY) {
33241991Sheppo 		ldcp->tstate = TS_UP;
33251991Sheppo 		mutex_exit(&ldcp->lock);
33261991Sheppo 		return (0);
33271991Sheppo 	}
33281991Sheppo 
33291991Sheppo 	/* Don't start another handshake if there is one in progress */
33301991Sheppo 	if (ldcp->hstate) {
33312793Slm66018 		D1(ldcp->id,
33321991Sheppo 		    "ldc_up: (0x%llx) channel handshake in progress\n",
33331991Sheppo 		    ldcp->id);
33341991Sheppo 		mutex_exit(&ldcp->lock);
33351991Sheppo 		return (0);
33361991Sheppo 	}
33371991Sheppo 
33382336Snarayan 	mutex_enter(&ldcp->tx_lock);
33392336Snarayan 
33403808Ssb155480 	/* save current link state */
33413808Ssb155480 	link_state = ldcp->link_state;
33423808Ssb155480 
33431991Sheppo 	/* get the current tail for the LDC msg */
33441991Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
33451991Sheppo 	if (rv) {
33463010Slm66018 		D1(ldcp->id, "ldc_up: (0x%llx) cannot initiate handshake\n",
33471991Sheppo 		    ldcp->id);
33482336Snarayan 		mutex_exit(&ldcp->tx_lock);
33491991Sheppo 		mutex_exit(&ldcp->lock);
33501991Sheppo 		return (ECONNREFUSED);
33511991Sheppo 	}
33521991Sheppo 
33533808Ssb155480 	/*
33543808Ssb155480 	 * If i_ldc_get_tx_tail() changed link_state to either RESET or UP,
33553808Ssb155480 	 * from a previous state of DOWN, then mark the channel as
33563808Ssb155480 	 * being ready for handshake.
33573808Ssb155480 	 */
33583808Ssb155480 	if ((link_state == LDC_CHANNEL_DOWN) &&
33593808Ssb155480 	    (link_state != ldcp->link_state)) {
33603808Ssb155480 
33613808Ssb155480 		ASSERT((ldcp->link_state == LDC_CHANNEL_RESET) ||
33623808Ssb155480 		    (ldcp->link_state == LDC_CHANNEL_UP));
33633808Ssb155480 
33643808Ssb155480 		if (ldcp->mode == LDC_MODE_RAW) {
33653808Ssb155480 			ldcp->status = LDC_UP;
33663808Ssb155480 			ldcp->tstate = TS_UP;
33673808Ssb155480 			mutex_exit(&ldcp->tx_lock);
33683808Ssb155480 			mutex_exit(&ldcp->lock);
33693808Ssb155480 			return (0);
33703808Ssb155480 		} else {
33713808Ssb155480 			ldcp->status = LDC_READY;
33723808Ssb155480 			ldcp->tstate |= TS_LINK_READY;
33733808Ssb155480 		}
33743808Ssb155480 
33753808Ssb155480 	}
33763808Ssb155480 
33771991Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
33781991Sheppo 	ZERO_PKT(ldcmsg);
33791991Sheppo 
33801991Sheppo 	ldcmsg->type = LDC_CTRL;
33811991Sheppo 	ldcmsg->stype = LDC_INFO;
33821991Sheppo 	ldcmsg->ctrl = LDC_VER;
33831991Sheppo 	ldcp->next_vidx = 0;
33841991Sheppo 	bcopy(&ldc_versions[0], ldcmsg->udata, sizeof (ldc_versions[0]));
33851991Sheppo 
33861991Sheppo 	DUMP_LDC_PKT(ldcp, "ldc_up snd ver", (uint64_t)ldcmsg);
33871991Sheppo 
33881991Sheppo 	/* initiate the send by calling into HV and set the new tail */
33891991Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
33904690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
33911991Sheppo 
33921991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
33931991Sheppo 	if (rv) {
33941991Sheppo 		DWARN(ldcp->id,
33951991Sheppo 		    "ldc_up: (0x%llx) cannot initiate handshake rv=%d\n",
33961991Sheppo 		    ldcp->id, rv);
33972336Snarayan 		mutex_exit(&ldcp->tx_lock);
33981991Sheppo 		mutex_exit(&ldcp->lock);
33991991Sheppo 		return (rv);
34001991Sheppo 	}
34011991Sheppo 
34022032Slm66018 	ldcp->hstate |= TS_SENT_VER;
34031991Sheppo 	ldcp->tx_tail = tx_tail;
34041991Sheppo 	D1(ldcp->id, "ldc_up: (0x%llx) channel up initiated\n", ldcp->id);
34051991Sheppo 
34062336Snarayan 	mutex_exit(&ldcp->tx_lock);
34071991Sheppo 	mutex_exit(&ldcp->lock);
34081991Sheppo 
34091991Sheppo 	return (rv);
34101991Sheppo }
34111991Sheppo 
34121991Sheppo 
34131991Sheppo /*
34142410Slm66018  * Bring a channel down by resetting its state and queues
34151991Sheppo  */
34161991Sheppo int
34172410Slm66018 ldc_down(ldc_handle_t handle)
34181991Sheppo {
34191991Sheppo 	ldc_chan_t 	*ldcp;
34201991Sheppo 
34211991Sheppo 	if (handle == NULL) {
34222410Slm66018 		DWARN(DBG_ALL_LDCS, "ldc_down: invalid channel handle\n");
34231991Sheppo 		return (EINVAL);
34241991Sheppo 	}
34251991Sheppo 	ldcp = (ldc_chan_t *)handle;
34261991Sheppo 	mutex_enter(&ldcp->lock);
34272336Snarayan 	mutex_enter(&ldcp->tx_lock);
34282793Slm66018 	i_ldc_reset(ldcp, B_TRUE);
34292336Snarayan 	mutex_exit(&ldcp->tx_lock);
34301991Sheppo 	mutex_exit(&ldcp->lock);
34311991Sheppo 
34321991Sheppo 	return (0);
34331991Sheppo }
34341991Sheppo 
34351991Sheppo /*
34361991Sheppo  * Get the current channel status
34371991Sheppo  */
34381991Sheppo int
34391991Sheppo ldc_status(ldc_handle_t handle, ldc_status_t *status)
34401991Sheppo {
34411991Sheppo 	ldc_chan_t *ldcp;
34421991Sheppo 
34431991Sheppo 	if (handle == NULL || status == NULL) {
34441991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_status: invalid argument\n");
34451991Sheppo 		return (EINVAL);
34461991Sheppo 	}
34471991Sheppo 	ldcp = (ldc_chan_t *)handle;
34481991Sheppo 
34491991Sheppo 	*status = ((ldc_chan_t *)handle)->status;
34501991Sheppo 
34513010Slm66018 	D1(ldcp->id,
34521991Sheppo 	    "ldc_status: (0x%llx) returned status %d\n", ldcp->id, *status);
34531991Sheppo 	return (0);
34541991Sheppo }
34551991Sheppo 
34561991Sheppo 
34571991Sheppo /*
34581991Sheppo  * Set the channel's callback mode - enable/disable callbacks
34591991Sheppo  */
34601991Sheppo int
34611991Sheppo ldc_set_cb_mode(ldc_handle_t handle, ldc_cb_mode_t cmode)
34621991Sheppo {
34631991Sheppo 	ldc_chan_t 	*ldcp;
34641991Sheppo 
34651991Sheppo 	if (handle == NULL) {
34661991Sheppo 		DWARN(DBG_ALL_LDCS,
34671991Sheppo 		    "ldc_set_intr_mode: invalid channel handle\n");
34681991Sheppo 		return (EINVAL);
34691991Sheppo 	}
34701991Sheppo 	ldcp = (ldc_chan_t *)handle;
34711991Sheppo 
34721991Sheppo 	/*
34731991Sheppo 	 * Record no callbacks should be invoked
34741991Sheppo 	 */
34751991Sheppo 	mutex_enter(&ldcp->lock);
34761991Sheppo 
34771991Sheppo 	switch (cmode) {
34781991Sheppo 	case LDC_CB_DISABLE:
34791991Sheppo 		if (!ldcp->cb_enabled) {
34801991Sheppo 			DWARN(ldcp->id,
34811991Sheppo 			    "ldc_set_cb_mode: (0x%llx) callbacks disabled\n",
34821991Sheppo 			    ldcp->id);
34831991Sheppo 			break;
34841991Sheppo 		}
34851991Sheppo 		ldcp->cb_enabled = B_FALSE;
34861991Sheppo 
34871991Sheppo 		D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) disabled callbacks\n",
34881991Sheppo 		    ldcp->id);
34891991Sheppo 		break;
34901991Sheppo 
34911991Sheppo 	case LDC_CB_ENABLE:
34921991Sheppo 		if (ldcp->cb_enabled) {
34931991Sheppo 			DWARN(ldcp->id,
34941991Sheppo 			    "ldc_set_cb_mode: (0x%llx) callbacks enabled\n",
34951991Sheppo 			    ldcp->id);
34961991Sheppo 			break;
34971991Sheppo 		}
34981991Sheppo 		ldcp->cb_enabled = B_TRUE;
34991991Sheppo 
35001991Sheppo 		D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) enabled callbacks\n",
35011991Sheppo 		    ldcp->id);
35021991Sheppo 		break;
35031991Sheppo 	}
35041991Sheppo 
35051991Sheppo 	mutex_exit(&ldcp->lock);
35061991Sheppo 
35071991Sheppo 	return (0);
35081991Sheppo }
35091991Sheppo 
35101991Sheppo /*
35111991Sheppo  * Check to see if there are packets on the incoming queue
35122410Slm66018  * Will return hasdata = B_FALSE if there are no packets
35131991Sheppo  */
35141991Sheppo int
35152410Slm66018 ldc_chkq(ldc_handle_t handle, boolean_t *hasdata)
35161991Sheppo {
35171991Sheppo 	int 		rv;
35181991Sheppo 	uint64_t 	rx_head, rx_tail;
35191991Sheppo 	ldc_chan_t 	*ldcp;
35201991Sheppo 
35211991Sheppo 	if (handle == NULL) {
35221991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_chkq: invalid channel handle\n");
35231991Sheppo 		return (EINVAL);
35241991Sheppo 	}
35251991Sheppo 	ldcp = (ldc_chan_t *)handle;
35261991Sheppo 
35272410Slm66018 	*hasdata = B_FALSE;
35281991Sheppo 
35291991Sheppo 	mutex_enter(&ldcp->lock);
35301991Sheppo 
35311991Sheppo 	if (ldcp->tstate != TS_UP) {
35321991Sheppo 		D1(ldcp->id,
35331991Sheppo 		    "ldc_chkq: (0x%llx) channel is not up\n", ldcp->id);
35341991Sheppo 		mutex_exit(&ldcp->lock);
35351991Sheppo 		return (ECONNRESET);
35361991Sheppo 	}
35371991Sheppo 
35381991Sheppo 	/* Read packet(s) from the queue */
35391991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
35401991Sheppo 	    &ldcp->link_state);
35411991Sheppo 	if (rv != 0) {
35421991Sheppo 		cmn_err(CE_WARN,
35431991Sheppo 		    "ldc_chkq: (0x%lx) unable to read queue ptrs", ldcp->id);
35441991Sheppo 		mutex_exit(&ldcp->lock);
35451991Sheppo 		return (EIO);
35461991Sheppo 	}
35475944Sha137994 
35481991Sheppo 	/* reset the channel state if the channel went down */
35491991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
35501991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
35512336Snarayan 		mutex_enter(&ldcp->tx_lock);
35522793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
35532336Snarayan 		mutex_exit(&ldcp->tx_lock);
35541991Sheppo 		mutex_exit(&ldcp->lock);
35551991Sheppo 		return (ECONNRESET);
35561991Sheppo 	}
35571991Sheppo 
35585944Sha137994 	switch (ldcp->mode) {
35595944Sha137994 	case LDC_MODE_RAW:
35605944Sha137994 		/*
35615944Sha137994 		 * In raw mode, there are no ctrl packets, so checking
35625944Sha137994 		 * if the queue is non-empty is sufficient.
35635944Sha137994 		 */
35645944Sha137994 		*hasdata = (rx_head != rx_tail);
35655944Sha137994 		break;
35665944Sha137994 
35675944Sha137994 	case LDC_MODE_UNRELIABLE:
35685944Sha137994 		/*
35695944Sha137994 		 * In unreliable mode, if the queue is non-empty, we need
35705944Sha137994 		 * to check if it actually contains unread data packets.
35715944Sha137994 		 * The queue may just contain ctrl packets.
35725944Sha137994 		 */
35735944Sha137994 		if (rx_head != rx_tail)
35745944Sha137994 			*hasdata = (i_ldc_chkq(ldcp) == 0);
35755944Sha137994 		break;
35765944Sha137994 
3577*6408Sha137994 	case LDC_MODE_RELIABLE:
35785944Sha137994 		/*
3579*6408Sha137994 		 * In reliable mode, first check for 'stream_remains' > 0.
35805944Sha137994 		 * Otherwise, if the data queue head and tail pointers
35815944Sha137994 		 * differ, there must be data to read.
35825944Sha137994 		 */
35835944Sha137994 		if (ldcp->stream_remains > 0)
35845944Sha137994 			*hasdata = B_TRUE;
35855944Sha137994 		else
35865944Sha137994 			*hasdata = (ldcp->rx_dq_head != ldcp->rx_dq_tail);
35875944Sha137994 		break;
35885944Sha137994 
35895944Sha137994 	default:
35905944Sha137994 		cmn_err(CE_WARN, "ldc_chkq: (0x%lx) unexpected channel mode "
35915944Sha137994 		    "(0x%x)", ldcp->id, ldcp->mode);
35925944Sha137994 		mutex_exit(&ldcp->lock);
35935944Sha137994 		return (EIO);
35941991Sheppo 	}
35951991Sheppo 
35961991Sheppo 	mutex_exit(&ldcp->lock);
35971991Sheppo 
35981991Sheppo 	return (0);
35991991Sheppo }
36001991Sheppo 
36011991Sheppo 
36021991Sheppo /*
36031991Sheppo  * Read 'size' amount of bytes or less. If incoming buffer
36041991Sheppo  * is more than 'size', ENOBUFS is returned.
36051991Sheppo  *
36061991Sheppo  * On return, size contains the number of bytes read.
36071991Sheppo  */
36081991Sheppo int
36091991Sheppo ldc_read(ldc_handle_t handle, caddr_t bufp, size_t *sizep)
36101991Sheppo {
36111991Sheppo 	ldc_chan_t 	*ldcp;
36121991Sheppo 	uint64_t 	rx_head = 0, rx_tail = 0;
36131991Sheppo 	int		rv = 0, exit_val;
36141991Sheppo 
36151991Sheppo 	if (handle == NULL) {
36161991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_read: invalid channel handle\n");
36171991Sheppo 		return (EINVAL);
36181991Sheppo 	}
36191991Sheppo 
36201991Sheppo 	ldcp = (ldc_chan_t *)handle;
36211991Sheppo 
36221991Sheppo 	/* channel lock */
36231991Sheppo 	mutex_enter(&ldcp->lock);
36241991Sheppo 
36251991Sheppo 	if (ldcp->tstate != TS_UP) {
36261991Sheppo 		DWARN(ldcp->id,
36271991Sheppo 		    "ldc_read: (0x%llx) channel is not in UP state\n",
36281991Sheppo 		    ldcp->id);
36291991Sheppo 		exit_val = ECONNRESET;
3630*6408Sha137994 	} else if (ldcp->mode == LDC_MODE_RELIABLE) {
36315944Sha137994 		TRACE_RXDQ_LENGTH(ldcp);
36325944Sha137994 		exit_val = ldcp->read_p(ldcp, bufp, sizep);
36335944Sha137994 		mutex_exit(&ldcp->lock);
36345944Sha137994 		return (exit_val);
36351991Sheppo 	} else {
36361991Sheppo 		exit_val = ldcp->read_p(ldcp, bufp, sizep);
36371991Sheppo 	}
36381991Sheppo 
36391991Sheppo 	/*
36401991Sheppo 	 * if queue has been drained - clear interrupt
36411991Sheppo 	 */
36421991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
36431991Sheppo 	    &ldcp->link_state);
36443010Slm66018 	if (rv != 0) {
36453010Slm66018 		cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
36463010Slm66018 		    ldcp->id);
36473010Slm66018 		mutex_enter(&ldcp->tx_lock);
36483010Slm66018 		i_ldc_reset(ldcp, B_TRUE);
36493010Slm66018 		mutex_exit(&ldcp->tx_lock);
36503653Snarayan 		mutex_exit(&ldcp->lock);
36513010Slm66018 		return (ECONNRESET);
36523010Slm66018 	}
36532793Slm66018 
36542793Slm66018 	if (exit_val == 0) {
36552793Slm66018 		if (ldcp->link_state == LDC_CHANNEL_DOWN ||
36562793Slm66018 		    ldcp->link_state == LDC_CHANNEL_RESET) {
36572793Slm66018 			mutex_enter(&ldcp->tx_lock);
36582793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
36592793Slm66018 			exit_val = ECONNRESET;
36602793Slm66018 			mutex_exit(&ldcp->tx_lock);
36612793Slm66018 		}
36622793Slm66018 		if ((rv == 0) &&
36632793Slm66018 		    (ldcp->rx_intr_state == LDC_INTR_PEND) &&
36642793Slm66018 		    (rx_head == rx_tail)) {
36652793Slm66018 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
36662793Slm66018 		}
36671991Sheppo 	}
36681991Sheppo 
36691991Sheppo 	mutex_exit(&ldcp->lock);
36701991Sheppo 	return (exit_val);
36711991Sheppo }
36721991Sheppo 
36731991Sheppo /*
36741991Sheppo  * Basic raw mondo read -
36751991Sheppo  * no interpretation of mondo contents at all.
36761991Sheppo  *
36771991Sheppo  * Enter and exit with ldcp->lock held by caller
36781991Sheppo  */
36791991Sheppo static int
36801991Sheppo i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
36811991Sheppo {
36821991Sheppo 	uint64_t 	q_size_mask;
36831991Sheppo 	ldc_msg_t 	*msgp;
36841991Sheppo 	uint8_t		*msgbufp;
36851991Sheppo 	int		rv = 0, space;
36861991Sheppo 	uint64_t 	rx_head, rx_tail;
36871991Sheppo 
36881991Sheppo 	space = *sizep;
36891991Sheppo 
36901991Sheppo 	if (space < LDC_PAYLOAD_SIZE_RAW)
36911991Sheppo 		return (ENOBUFS);
36921991Sheppo 
36931991Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
36941991Sheppo 
36951991Sheppo 	/* compute mask for increment */
36961991Sheppo 	q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
36971991Sheppo 
36981991Sheppo 	/*
36991991Sheppo 	 * Read packet(s) from the queue
37001991Sheppo 	 */
37011991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
37021991Sheppo 	    &ldcp->link_state);
37031991Sheppo 	if (rv != 0) {
37041991Sheppo 		cmn_err(CE_WARN,
37051991Sheppo 		    "ldc_read_raw: (0x%lx) unable to read queue ptrs",
37061991Sheppo 		    ldcp->id);
37071991Sheppo 		return (EIO);
37081991Sheppo 	}
37091991Sheppo 	D1(ldcp->id, "ldc_read_raw: (0x%llx) rxh=0x%llx,"
37104690Snarayan 	    " rxt=0x%llx, st=0x%llx\n",
37114690Snarayan 	    ldcp->id, rx_head, rx_tail, ldcp->link_state);
37121991Sheppo 
37131991Sheppo 	/* reset the channel state if the channel went down */
37142793Slm66018 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
37152793Slm66018 	    ldcp->link_state == LDC_CHANNEL_RESET) {
37162336Snarayan 		mutex_enter(&ldcp->tx_lock);
37172793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
37182336Snarayan 		mutex_exit(&ldcp->tx_lock);
37191991Sheppo 		return (ECONNRESET);
37201991Sheppo 	}
37211991Sheppo 
37221991Sheppo 	/*
37231991Sheppo 	 * Check for empty queue
37241991Sheppo 	 */
37251991Sheppo 	if (rx_head == rx_tail) {
37261991Sheppo 		*sizep = 0;
37271991Sheppo 		return (0);
37281991Sheppo 	}
37291991Sheppo 
37301991Sheppo 	/* get the message */
37311991Sheppo 	msgp = (ldc_msg_t *)(ldcp->rx_q_va + rx_head);
37321991Sheppo 
37331991Sheppo 	/* if channel is in RAW mode, copy data and return */
37341991Sheppo 	msgbufp = (uint8_t *)&(msgp->raw[0]);
37351991Sheppo 
37361991Sheppo 	bcopy(msgbufp, target_bufp, LDC_PAYLOAD_SIZE_RAW);
37371991Sheppo 
37381991Sheppo 	DUMP_PAYLOAD(ldcp->id, msgbufp);
37391991Sheppo 
37401991Sheppo 	*sizep = LDC_PAYLOAD_SIZE_RAW;
37411991Sheppo 
37421991Sheppo 	rx_head = (rx_head + LDC_PACKET_SIZE) & q_size_mask;
37432032Slm66018 	rv = i_ldc_set_rx_head(ldcp, rx_head);
37441991Sheppo 
37451991Sheppo 	return (rv);
37461991Sheppo }
37471991Sheppo 
37481991Sheppo /*
37491991Sheppo  * Process LDC mondos to build larger packets
37501991Sheppo  * with either un-reliable or reliable delivery.
37511991Sheppo  *
37521991Sheppo  * Enter and exit with ldcp->lock held by caller
37531991Sheppo  */
37541991Sheppo static int
37551991Sheppo i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
37561991Sheppo {
37571991Sheppo 	int		rv = 0;
37581991Sheppo 	uint64_t 	rx_head = 0, rx_tail = 0;
37591991Sheppo 	uint64_t 	curr_head = 0;
37601991Sheppo 	ldc_msg_t 	*msg;
37611991Sheppo 	caddr_t 	target;
37621991Sheppo 	size_t 		len = 0, bytes_read = 0;
37632032Slm66018 	int 		retries = 0;
37645944Sha137994 	uint64_t 	q_va, q_size_mask;
37652336Snarayan 	uint64_t	first_fragment = 0;
37661991Sheppo 
37671991Sheppo 	target = target_bufp;
37681991Sheppo 
37691991Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
37701991Sheppo 
37712793Slm66018 	/* check if the buffer and size are valid */
37722793Slm66018 	if (target_bufp == NULL || *sizep == 0) {
37732793Slm66018 		DWARN(ldcp->id, "ldc_read: (0x%llx) invalid buffer/size\n",
37742793Slm66018 		    ldcp->id);
37752793Slm66018 		return (EINVAL);
37762793Slm66018 	}
37772793Slm66018 
37785944Sha137994 	/* Set q_va and compute increment mask for the appropriate queue */
3779*6408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
37805944Sha137994 		q_va	    = ldcp->rx_dq_va;
37815944Sha137994 		q_size_mask = (ldcp->rx_dq_entries-1)<<LDC_PACKET_SHIFT;
37825944Sha137994 	} else {
37835944Sha137994 		q_va	    = ldcp->rx_q_va;
37845944Sha137994 		q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
37855944Sha137994 	}
37861991Sheppo 
37871991Sheppo 	/*
37881991Sheppo 	 * Read packet(s) from the queue
37891991Sheppo 	 */
37905944Sha137994 	rv = ldcp->readq_get_state(ldcp, &curr_head, &rx_tail,
37911991Sheppo 	    &ldcp->link_state);
37921991Sheppo 	if (rv != 0) {
37932793Slm66018 		cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
37941991Sheppo 		    ldcp->id);
37952793Slm66018 		mutex_enter(&ldcp->tx_lock);
37962793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
37972793Slm66018 		mutex_exit(&ldcp->tx_lock);
37982793Slm66018 		return (ECONNRESET);
37991991Sheppo 	}
38001991Sheppo 	D1(ldcp->id, "ldc_read: (0x%llx) chd=0x%llx, tl=0x%llx, st=0x%llx\n",
38011991Sheppo 	    ldcp->id, curr_head, rx_tail, ldcp->link_state);
38021991Sheppo 
38031991Sheppo 	/* reset the channel state if the channel went down */
38042793Slm66018 	if (ldcp->link_state != LDC_CHANNEL_UP)
38052793Slm66018 		goto channel_is_reset;
38061991Sheppo 
38071991Sheppo 	for (;;) {
38081991Sheppo 
38091991Sheppo 		if (curr_head == rx_tail) {
38105944Sha137994 			/*
38115944Sha137994 			 * If a data queue is being used, check the Rx HV
38125944Sha137994 			 * queue. This will copy over any new data packets
38135944Sha137994 			 * that have arrived.
38145944Sha137994 			 */
3815*6408Sha137994 			if (ldcp->mode == LDC_MODE_RELIABLE)
38165944Sha137994 				(void) i_ldc_chkq(ldcp);
38175944Sha137994 
38185944Sha137994 			rv = ldcp->readq_get_state(ldcp,
38191991Sheppo 			    &rx_head, &rx_tail, &ldcp->link_state);
38201991Sheppo 			if (rv != 0) {
38211991Sheppo 				cmn_err(CE_WARN,
38221991Sheppo 				    "ldc_read: (0x%lx) cannot read queue ptrs",
38231991Sheppo 				    ldcp->id);
38242336Snarayan 				mutex_enter(&ldcp->tx_lock);
38252793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
38262336Snarayan 				mutex_exit(&ldcp->tx_lock);
38271991Sheppo 				return (ECONNRESET);
38281991Sheppo 			}
38295944Sha137994 
38302793Slm66018 			if (ldcp->link_state != LDC_CHANNEL_UP)
38312793Slm66018 				goto channel_is_reset;
38322793Slm66018 
38332793Slm66018 			if (curr_head == rx_tail) {
38342793Slm66018 
38352793Slm66018 				/* If in the middle of a fragmented xfer */
38362793Slm66018 				if (first_fragment != 0) {
38372793Slm66018 
38382793Slm66018 					/* wait for ldc_delay usecs */
38392793Slm66018 					drv_usecwait(ldc_delay);
38402793Slm66018 
38412793Slm66018 					if (++retries < ldc_max_retries)
38422793Slm66018 						continue;
38432793Slm66018 
38442793Slm66018 					*sizep = 0;
3845*6408Sha137994 					if (ldcp->mode != LDC_MODE_RELIABLE)
38465944Sha137994 						ldcp->last_msg_rcd =
38475944Sha137994 						    first_fragment - 1;
38482793Slm66018 					DWARN(DBG_ALL_LDCS, "ldc_read: "
38494690Snarayan 					    "(0x%llx) read timeout", ldcp->id);
38502793Slm66018 					return (EAGAIN);
38512793Slm66018 				}
38522032Slm66018 				*sizep = 0;
38532793Slm66018 				break;
38541991Sheppo 			}
38551991Sheppo 		}
38562032Slm66018 		retries = 0;
38571991Sheppo 
38581991Sheppo 		D2(ldcp->id,
38591991Sheppo 		    "ldc_read: (0x%llx) chd=0x%llx, rxhd=0x%llx, rxtl=0x%llx\n",
38601991Sheppo 		    ldcp->id, curr_head, rx_head, rx_tail);
38611991Sheppo 
38621991Sheppo 		/* get the message */
38635944Sha137994 		msg = (ldc_msg_t *)(q_va + curr_head);
38641991Sheppo 
38651991Sheppo 		DUMP_LDC_PKT(ldcp, "ldc_read received pkt",
38661991Sheppo 		    ldcp->rx_q_va + curr_head);
38671991Sheppo 
38681991Sheppo 		/* Check the message ID for the message received */
3869*6408Sha137994 		if (ldcp->mode != LDC_MODE_RELIABLE) {
38705944Sha137994 			if ((rv = i_ldc_check_seqid(ldcp, msg)) != 0) {
38715944Sha137994 
38725944Sha137994 				DWARN(ldcp->id, "ldc_read: (0x%llx) seqid "
38735944Sha137994 				    "error, q_ptrs=0x%lx,0x%lx",
38745944Sha137994 				    ldcp->id, rx_head, rx_tail);
38755944Sha137994 
38765944Sha137994 				/* throw away data */
38775944Sha137994 				bytes_read = 0;
38785944Sha137994 
38795944Sha137994 				/* Reset last_msg_rcd to start of message */
38805944Sha137994 				if (first_fragment != 0) {
38815944Sha137994 					ldcp->last_msg_rcd = first_fragment - 1;
38825944Sha137994 					first_fragment = 0;
38835944Sha137994 				}
38845944Sha137994 				/*
38855944Sha137994 				 * Send a NACK -- invalid seqid
38865944Sha137994 				 * get the current tail for the response
38875944Sha137994 				 */
38885944Sha137994 				rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK,
38895944Sha137994 				    (msg->ctrl & LDC_CTRL_MASK));
38905944Sha137994 				if (rv) {
38915944Sha137994 					cmn_err(CE_NOTE,
38925944Sha137994 					    "ldc_read: (0x%lx) err sending "
38935944Sha137994 					    "NACK msg\n", ldcp->id);
38945944Sha137994 
38955944Sha137994 					/* if cannot send NACK - reset chan */
38965944Sha137994 					mutex_enter(&ldcp->tx_lock);
38975944Sha137994 					i_ldc_reset(ldcp, B_FALSE);
38985944Sha137994 					mutex_exit(&ldcp->tx_lock);
38995944Sha137994 					rv = ECONNRESET;
39005944Sha137994 					break;
39015944Sha137994 				}
39025944Sha137994 
39035944Sha137994 				/* purge receive queue */
39045944Sha137994 				rv = i_ldc_set_rx_head(ldcp, rx_tail);
39055944Sha137994 
39062336Snarayan 				break;
39071991Sheppo 			}
39081991Sheppo 
39095944Sha137994 			/*
39105944Sha137994 			 * Process any messages of type CTRL messages
39115944Sha137994 			 * Future implementations should try to pass these
39125944Sha137994 			 * to LDC link by resetting the intr state.
39135944Sha137994 			 *
39145944Sha137994 			 * NOTE: not done as a switch() as type can be
39155944Sha137994 			 * both ctrl+data
39165944Sha137994 			 */
39175944Sha137994 			if (msg->type & LDC_CTRL) {
39185944Sha137994 				if (rv = i_ldc_ctrlmsg(ldcp, msg)) {
39195944Sha137994 					if (rv == EAGAIN)
39205944Sha137994 						continue;
39215944Sha137994 					rv = i_ldc_set_rx_head(ldcp, rx_tail);
39225944Sha137994 					*sizep = 0;
39235944Sha137994 					bytes_read = 0;
39245944Sha137994 					break;
39255944Sha137994 				}
39261991Sheppo 			}
39275944Sha137994 
39285944Sha137994 			/* process data ACKs */
39295944Sha137994 			if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
39305944Sha137994 				if (rv = i_ldc_process_data_ACK(ldcp, msg)) {
39315944Sha137994 					*sizep = 0;
39325944Sha137994 					bytes_read = 0;
39335944Sha137994 					break;
39345944Sha137994 				}
39352336Snarayan 			}
39365944Sha137994 
39375944Sha137994 			/* process data NACKs */
39385944Sha137994 			if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) {
39395944Sha137994 				DWARN(ldcp->id,
39405944Sha137994 				    "ldc_read: (0x%llx) received DATA/NACK",
39415944Sha137994 				    ldcp->id);
39425944Sha137994 				mutex_enter(&ldcp->tx_lock);
39435944Sha137994 				i_ldc_reset(ldcp, B_TRUE);
39445944Sha137994 				mutex_exit(&ldcp->tx_lock);
39455944Sha137994 				return (ECONNRESET);
39465944Sha137994 			}
39473560Snarayan 		}
39483560Snarayan 
39491991Sheppo 		/* process data messages */
39501991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
39511991Sheppo 
39521991Sheppo 			uint8_t *msgbuf = (uint8_t *)(
3953*6408Sha137994 			    (ldcp->mode == LDC_MODE_RELIABLE) ?
39544690Snarayan 			    msg->rdata : msg->udata);
39551991Sheppo 
39561991Sheppo 			D2(ldcp->id,
39571991Sheppo 			    "ldc_read: (0x%llx) received data msg\n", ldcp->id);
39581991Sheppo 
39591991Sheppo 			/* get the packet length */
39601991Sheppo 			len = (msg->env & LDC_LEN_MASK);
39611991Sheppo 
39621991Sheppo 				/*
39631991Sheppo 				 * FUTURE OPTIMIZATION:
39641991Sheppo 				 * dont need to set q head for every
39651991Sheppo 				 * packet we read just need to do this when
39661991Sheppo 				 * we are done or need to wait for more
39671991Sheppo 				 * mondos to make a full packet - this is
39681991Sheppo 				 * currently expensive.
39691991Sheppo 				 */
39701991Sheppo 
39712336Snarayan 			if (first_fragment == 0) {
39721991Sheppo 
39731991Sheppo 				/*
39741991Sheppo 				 * first packets should always have the start
39751991Sheppo 				 * bit set (even for a single packet). If not
39761991Sheppo 				 * throw away the packet
39771991Sheppo 				 */
39781991Sheppo 				if (!(msg->env & LDC_FRAG_START)) {
39791991Sheppo 
39801991Sheppo 					DWARN(DBG_ALL_LDCS,
39811991Sheppo 					    "ldc_read: (0x%llx) not start - "
39821991Sheppo 					    "frag=%x\n", ldcp->id,
39831991Sheppo 					    (msg->env) & LDC_FRAG_MASK);
39841991Sheppo 
39851991Sheppo 					/* toss pkt, inc head, cont reading */
39861991Sheppo 					bytes_read = 0;
39871991Sheppo 					target = target_bufp;
39881991Sheppo 					curr_head =
39894690Snarayan 					    (curr_head + LDC_PACKET_SIZE)
39904690Snarayan 					    & q_size_mask;
39915944Sha137994 					if (rv = ldcp->readq_set_head(ldcp,
39924690Snarayan 					    curr_head))
39931991Sheppo 						break;
39941991Sheppo 
39951991Sheppo 					continue;
39961991Sheppo 				}
39971991Sheppo 
39982336Snarayan 				first_fragment = msg->seqid;
39991991Sheppo 			} else {
40001991Sheppo 				/* check to see if this is a pkt w/ START bit */
40011991Sheppo 				if (msg->env & LDC_FRAG_START) {
40021991Sheppo 					DWARN(DBG_ALL_LDCS,
40031991Sheppo 					    "ldc_read:(0x%llx) unexpected pkt"
40041991Sheppo 					    " env=0x%x discarding %d bytes,"
40051991Sheppo 					    " lastmsg=%d, currentmsg=%d\n",
40061991Sheppo 					    ldcp->id, msg->env&LDC_FRAG_MASK,
40071991Sheppo 					    bytes_read, ldcp->last_msg_rcd,
40081991Sheppo 					    msg->seqid);
40091991Sheppo 
40101991Sheppo 					/* throw data we have read so far */
40111991Sheppo 					bytes_read = 0;
40121991Sheppo 					target = target_bufp;
40132336Snarayan 					first_fragment = msg->seqid;
40141991Sheppo 
40155944Sha137994 					if (rv = ldcp->readq_set_head(ldcp,
40164690Snarayan 					    curr_head))
40171991Sheppo 						break;
40181991Sheppo 				}
40191991Sheppo 			}
40201991Sheppo 
40211991Sheppo 			/* copy (next) pkt into buffer */
40221991Sheppo 			if (len <= (*sizep - bytes_read)) {
40231991Sheppo 				bcopy(msgbuf, target, len);
40241991Sheppo 				target += len;
40251991Sheppo 				bytes_read += len;
40261991Sheppo 			} else {
40271991Sheppo 				/*
40281991Sheppo 				 * there is not enough space in the buffer to
40291991Sheppo 				 * read this pkt. throw message away & continue
40301991Sheppo 				 * reading data from queue
40311991Sheppo 				 */
40321991Sheppo 				DWARN(DBG_ALL_LDCS,
40331991Sheppo 				    "ldc_read: (0x%llx) buffer too small, "
40341991Sheppo 				    "head=0x%lx, expect=%d, got=%d\n", ldcp->id,
40351991Sheppo 				    curr_head, *sizep, bytes_read+len);
40361991Sheppo 
40372336Snarayan 				first_fragment = 0;
40381991Sheppo 				target = target_bufp;
40391991Sheppo 				bytes_read = 0;
40401991Sheppo 
40411991Sheppo 				/* throw away everything received so far */
40425944Sha137994 				if (rv = ldcp->readq_set_head(ldcp, curr_head))
40431991Sheppo 					break;
40441991Sheppo 
40451991Sheppo 				/* continue reading remaining pkts */
40461991Sheppo 				continue;
40471991Sheppo 			}
40481991Sheppo 		}
40491991Sheppo 
40501991Sheppo 		/* set the message id */
4051*6408Sha137994 		if (ldcp->mode != LDC_MODE_RELIABLE)
40525944Sha137994 			ldcp->last_msg_rcd = msg->seqid;
40531991Sheppo 
40541991Sheppo 		/* move the head one position */
40551991Sheppo 		curr_head = (curr_head + LDC_PACKET_SIZE) & q_size_mask;
40561991Sheppo 
40571991Sheppo 		if (msg->env & LDC_FRAG_STOP) {
40581991Sheppo 
40591991Sheppo 			/*
40601991Sheppo 			 * All pkts that are part of this fragmented transfer
40611991Sheppo 			 * have been read or this was a single pkt read
40621991Sheppo 			 * or there was an error
40631991Sheppo 			 */
40641991Sheppo 
40651991Sheppo 			/* set the queue head */
40665944Sha137994 			if (rv = ldcp->readq_set_head(ldcp, curr_head))
40671991Sheppo 				bytes_read = 0;
40681991Sheppo 
40691991Sheppo 			*sizep = bytes_read;
40701991Sheppo 
40711991Sheppo 			break;
40721991Sheppo 		}
40731991Sheppo 
40744890Snarayan 		/* advance head if it is a CTRL packet or a DATA ACK packet */
40754890Snarayan 		if ((msg->type & LDC_CTRL) ||
40764890Snarayan 		    ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK))) {
40771991Sheppo 
40781991Sheppo 			/* set the queue head */
40795944Sha137994 			if (rv = ldcp->readq_set_head(ldcp, curr_head)) {
40801991Sheppo 				bytes_read = 0;
40811991Sheppo 				break;
40821991Sheppo 			}
40831991Sheppo 
40841991Sheppo 			D2(ldcp->id, "ldc_read: (0x%llx) set ACK qhead 0x%llx",
40851991Sheppo 			    ldcp->id, curr_head);
40861991Sheppo 		}
40871991Sheppo 
40881991Sheppo 	} /* for (;;) */
40891991Sheppo 
40901991Sheppo 	D2(ldcp->id, "ldc_read: (0x%llx) end size=%d", ldcp->id, *sizep);
40911991Sheppo 
40921991Sheppo 	return (rv);
40932793Slm66018 
40942793Slm66018 channel_is_reset:
40952793Slm66018 	mutex_enter(&ldcp->tx_lock);
40962793Slm66018 	i_ldc_reset(ldcp, B_FALSE);
40972793Slm66018 	mutex_exit(&ldcp->tx_lock);
40982793Slm66018 	return (ECONNRESET);
40991991Sheppo }
41001991Sheppo 
41011991Sheppo /*
4102*6408Sha137994  * Fetch and buffer incoming packets so we can hand them back as
41031991Sheppo  * a basic byte stream.
41041991Sheppo  *
41051991Sheppo  * Enter and exit with ldcp->lock held by caller
41061991Sheppo  */
41071991Sheppo static int
41081991Sheppo i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
41091991Sheppo {
41101991Sheppo 	int	rv;
41111991Sheppo 	size_t	size;
41121991Sheppo 
41131991Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
41141991Sheppo 
41151991Sheppo 	D2(ldcp->id, "i_ldc_read_stream: (0x%llx) buffer size=%d",
41164690Snarayan 	    ldcp->id, *sizep);
41171991Sheppo 
41181991Sheppo 	if (ldcp->stream_remains == 0) {
41191991Sheppo 		size = ldcp->mtu;
41201991Sheppo 		rv = i_ldc_read_packet(ldcp,
41214690Snarayan 		    (caddr_t)ldcp->stream_bufferp, &size);
41221991Sheppo 		D2(ldcp->id, "i_ldc_read_stream: read packet (0x%llx) size=%d",
41234690Snarayan 		    ldcp->id, size);
41241991Sheppo 
41251991Sheppo 		if (rv != 0)
41261991Sheppo 			return (rv);
41271991Sheppo 
41281991Sheppo 		ldcp->stream_remains = size;
41291991Sheppo 		ldcp->stream_offset = 0;
41301991Sheppo 	}
41311991Sheppo 
41321991Sheppo 	size = MIN(ldcp->stream_remains, *sizep);
41331991Sheppo 
41341991Sheppo 	bcopy(ldcp->stream_bufferp + ldcp->stream_offset, target_bufp, size);
41351991Sheppo 	ldcp->stream_offset += size;
41361991Sheppo 	ldcp->stream_remains -= size;
41371991Sheppo 
41381991Sheppo 	D2(ldcp->id, "i_ldc_read_stream: (0x%llx) fill from buffer size=%d",
41394690Snarayan 	    ldcp->id, size);
41401991Sheppo 
41411991Sheppo 	*sizep = size;
41421991Sheppo 	return (0);
41431991Sheppo }
41441991Sheppo 
41451991Sheppo /*
41461991Sheppo  * Write specified amount of bytes to the channel
41471991Sheppo  * in multiple pkts of pkt_payload size. Each
41481991Sheppo  * packet is tagged with an unique packet ID in
41492410Slm66018  * the case of a reliable link.
41501991Sheppo  *
41511991Sheppo  * On return, size contains the number of bytes written.
41521991Sheppo  */
41531991Sheppo int
41541991Sheppo ldc_write(ldc_handle_t handle, caddr_t buf, size_t *sizep)
41551991Sheppo {
41561991Sheppo 	ldc_chan_t	*ldcp;
41571991Sheppo 	int		rv = 0;
41581991Sheppo 
41591991Sheppo 	if (handle == NULL) {
41601991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_write: invalid channel handle\n");
41611991Sheppo 		return (EINVAL);
41621991Sheppo 	}
41631991Sheppo 	ldcp = (ldc_chan_t *)handle;
41641991Sheppo 
41652336Snarayan 	/* check if writes can occur */
41662336Snarayan 	if (!mutex_tryenter(&ldcp->tx_lock)) {
41672336Snarayan 		/*
41682336Snarayan 		 * Could not get the lock - channel could
41692336Snarayan 		 * be in the process of being unconfigured
41702336Snarayan 		 * or reader has encountered an error
41712336Snarayan 		 */
41722336Snarayan 		return (EAGAIN);
41732336Snarayan 	}
41741991Sheppo 
41751991Sheppo 	/* check if non-zero data to write */
41761991Sheppo 	if (buf == NULL || sizep == NULL) {
41771991Sheppo 		DWARN(ldcp->id, "ldc_write: (0x%llx) invalid data write\n",
41781991Sheppo 		    ldcp->id);
41792336Snarayan 		mutex_exit(&ldcp->tx_lock);
41801991Sheppo 		return (EINVAL);
41811991Sheppo 	}
41821991Sheppo 
41831991Sheppo 	if (*sizep == 0) {
41841991Sheppo 		DWARN(ldcp->id, "ldc_write: (0x%llx) write size of zero\n",
41851991Sheppo 		    ldcp->id);
41862336Snarayan 		mutex_exit(&ldcp->tx_lock);
41871991Sheppo 		return (0);
41881991Sheppo 	}
41891991Sheppo 
41901991Sheppo 	/* Check if channel is UP for data exchange */
41911991Sheppo 	if (ldcp->tstate != TS_UP) {
41921991Sheppo 		DWARN(ldcp->id,
41931991Sheppo 		    "ldc_write: (0x%llx) channel is not in UP state\n",
41941991Sheppo 		    ldcp->id);
41951991Sheppo 		*sizep = 0;
41961991Sheppo 		rv = ECONNRESET;
41971991Sheppo 	} else {
41981991Sheppo 		rv = ldcp->write_p(ldcp, buf, sizep);
41991991Sheppo 	}
42001991Sheppo 
42012336Snarayan 	mutex_exit(&ldcp->tx_lock);
42021991Sheppo 
42031991Sheppo 	return (rv);
42041991Sheppo }
42051991Sheppo 
42061991Sheppo /*
42071991Sheppo  * Write a raw packet to the channel
42081991Sheppo  * On return, size contains the number of bytes written.
42091991Sheppo  */
42101991Sheppo static int
42111991Sheppo i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
42121991Sheppo {
42131991Sheppo 	ldc_msg_t 	*ldcmsg;
42141991Sheppo 	uint64_t 	tx_head, tx_tail, new_tail;
42151991Sheppo 	int		rv = 0;
42161991Sheppo 	size_t		size;
42171991Sheppo 
42182336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
42191991Sheppo 	ASSERT(ldcp->mode == LDC_MODE_RAW);
42201991Sheppo 
42211991Sheppo 	size = *sizep;
42221991Sheppo 
42231991Sheppo 	/*
42241991Sheppo 	 * Check to see if the packet size is less than or
42251991Sheppo 	 * equal to packet size support in raw mode
42261991Sheppo 	 */
42271991Sheppo 	if (size > ldcp->pkt_payload) {
42281991Sheppo 		DWARN(ldcp->id,
42291991Sheppo 		    "ldc_write: (0x%llx) invalid size (0x%llx) for RAW mode\n",
42301991Sheppo 		    ldcp->id, *sizep);
42311991Sheppo 		*sizep = 0;
42321991Sheppo 		return (EMSGSIZE);
42331991Sheppo 	}
42341991Sheppo 
42351991Sheppo 	/* get the qptrs for the tx queue */
42361991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
42371991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
42381991Sheppo 	if (rv != 0) {
42391991Sheppo 		cmn_err(CE_WARN,
42401991Sheppo 		    "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
42411991Sheppo 		*sizep = 0;
42421991Sheppo 		return (EIO);
42431991Sheppo 	}
42441991Sheppo 
42451991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
42461991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
42471991Sheppo 		DWARN(ldcp->id,
42481991Sheppo 		    "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
42492336Snarayan 
42501991Sheppo 		*sizep = 0;
42512336Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
42522793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
42532336Snarayan 			mutex_exit(&ldcp->lock);
42542336Snarayan 		} else {
42552336Snarayan 			/*
42562336Snarayan 			 * Release Tx lock, and then reacquire channel
42572336Snarayan 			 * and Tx lock in correct order
42582336Snarayan 			 */
42592336Snarayan 			mutex_exit(&ldcp->tx_lock);
42602336Snarayan 			mutex_enter(&ldcp->lock);
42612336Snarayan 			mutex_enter(&ldcp->tx_lock);
42622793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
42632336Snarayan 			mutex_exit(&ldcp->lock);
42642336Snarayan 		}
42651991Sheppo 		return (ECONNRESET);
42661991Sheppo 	}
42671991Sheppo 
42681991Sheppo 	tx_tail = ldcp->tx_tail;
42691991Sheppo 	tx_head = ldcp->tx_head;
42701991Sheppo 	new_tail = (tx_tail + LDC_PACKET_SIZE) &
42714690Snarayan 	    ((ldcp->tx_q_entries-1) << LDC_PACKET_SHIFT);
42721991Sheppo 
42731991Sheppo 	if (new_tail == tx_head) {
42741991Sheppo 		DWARN(DBG_ALL_LDCS,
42751991Sheppo 		    "ldc_write: (0x%llx) TX queue is full\n", ldcp->id);
42761991Sheppo 		*sizep = 0;
42771991Sheppo 		return (EWOULDBLOCK);
42781991Sheppo 	}
42791991Sheppo 
42801991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
42811991Sheppo 	    ldcp->id, size);
42821991Sheppo 
42831991Sheppo 	/* Send the data now */
42841991Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
42851991Sheppo 
42862336Snarayan 	/* copy the data into pkt */
42871991Sheppo 	bcopy((uint8_t *)buf, ldcmsg, size);
42881991Sheppo 
42892336Snarayan 	/* increment tail */
42901991Sheppo 	tx_tail = new_tail;
42911991Sheppo 
42921991Sheppo 	/*
42931991Sheppo 	 * All packets have been copied into the TX queue
42941991Sheppo 	 * update the tail ptr in the HV
42951991Sheppo 	 */
42961991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
42971991Sheppo 	if (rv) {
42981991Sheppo 		if (rv == EWOULDBLOCK) {
42991991Sheppo 			DWARN(ldcp->id, "ldc_write: (0x%llx) write timed out\n",
43001991Sheppo 			    ldcp->id);
43011991Sheppo 			*sizep = 0;
43021991Sheppo 			return (EWOULDBLOCK);
43031991Sheppo 		}
43041991Sheppo 
43051991Sheppo 		*sizep = 0;
43062336Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
43072793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
43082336Snarayan 			mutex_exit(&ldcp->lock);
43092336Snarayan 		} else {
43102336Snarayan 			/*
43112336Snarayan 			 * Release Tx lock, and then reacquire channel
43122336Snarayan 			 * and Tx lock in correct order
43132336Snarayan 			 */
43142336Snarayan 			mutex_exit(&ldcp->tx_lock);
43152336Snarayan 			mutex_enter(&ldcp->lock);
43162336Snarayan 			mutex_enter(&ldcp->tx_lock);
43172793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
43182336Snarayan 			mutex_exit(&ldcp->lock);
43192336Snarayan 		}
43201991Sheppo 		return (ECONNRESET);
43211991Sheppo 	}
43221991Sheppo 
43231991Sheppo 	ldcp->tx_tail = tx_tail;
43241991Sheppo 	*sizep = size;
43251991Sheppo 
43261991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, size);
43271991Sheppo 
43281991Sheppo 	return (rv);
43291991Sheppo }
43301991Sheppo 
43311991Sheppo 
43321991Sheppo /*
43331991Sheppo  * Write specified amount of bytes to the channel
43341991Sheppo  * in multiple pkts of pkt_payload size. Each
43351991Sheppo  * packet is tagged with an unique packet ID in
43362410Slm66018  * the case of a reliable link.
43371991Sheppo  *
43381991Sheppo  * On return, size contains the number of bytes written.
43391991Sheppo  * This function needs to ensure that the write size is < MTU size
43401991Sheppo  */
43411991Sheppo static int
43421991Sheppo i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t buf, size_t *size)
43431991Sheppo {
43441991Sheppo 	ldc_msg_t 	*ldcmsg;
43451991Sheppo 	uint64_t 	tx_head, tx_tail, new_tail, start;
43461991Sheppo 	uint64_t	txq_size_mask, numavail;
43471991Sheppo 	uint8_t 	*msgbuf, *source = (uint8_t *)buf;
43481991Sheppo 	size_t 		len, bytes_written = 0, remaining;
43491991Sheppo 	int		rv;
43501991Sheppo 	uint32_t	curr_seqid;
43511991Sheppo 
43522336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
43531991Sheppo 
43541991Sheppo 	ASSERT(ldcp->mode == LDC_MODE_RELIABLE ||
4355*6408Sha137994 	    ldcp->mode == LDC_MODE_UNRELIABLE);
43561991Sheppo 
43571991Sheppo 	/* compute mask for increment */
43581991Sheppo 	txq_size_mask = (ldcp->tx_q_entries - 1) << LDC_PACKET_SHIFT;
43591991Sheppo 
43601991Sheppo 	/* get the qptrs for the tx queue */
43611991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
43621991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
43631991Sheppo 	if (rv != 0) {
43641991Sheppo 		cmn_err(CE_WARN,
43651991Sheppo 		    "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
43661991Sheppo 		*size = 0;
43671991Sheppo 		return (EIO);
43681991Sheppo 	}
43691991Sheppo 
43701991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
43711991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
43721991Sheppo 		DWARN(ldcp->id,
43731991Sheppo 		    "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
43741991Sheppo 		*size = 0;
43752336Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
43762793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
43772336Snarayan 			mutex_exit(&ldcp->lock);
43782336Snarayan 		} else {
43792336Snarayan 			/*
43802336Snarayan 			 * Release Tx lock, and then reacquire channel
43812336Snarayan 			 * and Tx lock in correct order
43822336Snarayan 			 */
43832336Snarayan 			mutex_exit(&ldcp->tx_lock);
43842336Snarayan 			mutex_enter(&ldcp->lock);
43852336Snarayan 			mutex_enter(&ldcp->tx_lock);
43862793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
43872336Snarayan 			mutex_exit(&ldcp->lock);
43882336Snarayan 		}
43891991Sheppo 		return (ECONNRESET);
43901991Sheppo 	}
43911991Sheppo 
43921991Sheppo 	tx_tail = ldcp->tx_tail;
43931991Sheppo 	new_tail = (tx_tail + LDC_PACKET_SIZE) %
43944690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
43951991Sheppo 
43961991Sheppo 	/*
43974690Snarayan 	 * Check to see if the queue is full. The check is done using
43984690Snarayan 	 * the appropriate head based on the link mode.
43991991Sheppo 	 */
44004690Snarayan 	i_ldc_get_tx_head(ldcp, &tx_head);
44014690Snarayan 
44021991Sheppo 	if (new_tail == tx_head) {
44031991Sheppo 		DWARN(DBG_ALL_LDCS,
44041991Sheppo 		    "ldc_write: (0x%llx) TX queue is full\n", ldcp->id);
44051991Sheppo 		*size = 0;
44061991Sheppo 		return (EWOULDBLOCK);
44071991Sheppo 	}
44081991Sheppo 
44091991Sheppo 	/*
44101991Sheppo 	 * Make sure that the LDC Tx queue has enough space
44111991Sheppo 	 */
44121991Sheppo 	numavail = (tx_head >> LDC_PACKET_SHIFT) - (tx_tail >> LDC_PACKET_SHIFT)
44134690Snarayan 	    + ldcp->tx_q_entries - 1;
44141991Sheppo 	numavail %= ldcp->tx_q_entries;
44151991Sheppo 
44161991Sheppo 	if (*size > (numavail * ldcp->pkt_payload)) {
44171991Sheppo 		DWARN(DBG_ALL_LDCS,
44181991Sheppo 		    "ldc_write: (0x%llx) TX queue has no space\n", ldcp->id);
44191991Sheppo 		return (EWOULDBLOCK);
44201991Sheppo 	}
44211991Sheppo 
44221991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
44231991Sheppo 	    ldcp->id, *size);
44241991Sheppo 
44251991Sheppo 	/* Send the data now */
44261991Sheppo 	bytes_written = 0;
44271991Sheppo 	curr_seqid = ldcp->last_msg_snt;
44281991Sheppo 	start = tx_tail;
44291991Sheppo 
44301991Sheppo 	while (*size > bytes_written) {
44311991Sheppo 
44321991Sheppo 		ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
44331991Sheppo 
4434*6408Sha137994 		msgbuf = (uint8_t *)((ldcp->mode == LDC_MODE_RELIABLE) ?
44354690Snarayan 		    ldcmsg->rdata : ldcmsg->udata);
44361991Sheppo 
44371991Sheppo 		ldcmsg->type = LDC_DATA;
44381991Sheppo 		ldcmsg->stype = LDC_INFO;
44391991Sheppo 		ldcmsg->ctrl = 0;
44401991Sheppo 
44411991Sheppo 		remaining = *size - bytes_written;
44421991Sheppo 		len = min(ldcp->pkt_payload, remaining);
44431991Sheppo 		ldcmsg->env = (uint8_t)len;
44441991Sheppo 
44451991Sheppo 		curr_seqid++;
44461991Sheppo 		ldcmsg->seqid = curr_seqid;
44471991Sheppo 
44481991Sheppo 		/* copy the data into pkt */
44491991Sheppo 		bcopy(source, msgbuf, len);
44501991Sheppo 
44511991Sheppo 		source += len;
44521991Sheppo 		bytes_written += len;
44531991Sheppo 
44541991Sheppo 		/* increment tail */
44551991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) & txq_size_mask;
44561991Sheppo 
44571991Sheppo 		ASSERT(tx_tail != tx_head);
44581991Sheppo 	}
44591991Sheppo 
44601991Sheppo 	/* Set the start and stop bits */
44611991Sheppo 	ldcmsg->env |= LDC_FRAG_STOP;
44621991Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + start);
44631991Sheppo 	ldcmsg->env |= LDC_FRAG_START;
44641991Sheppo 
44651991Sheppo 	/*
44661991Sheppo 	 * All packets have been copied into the TX queue
44671991Sheppo 	 * update the tail ptr in the HV
44681991Sheppo 	 */
44691991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
44701991Sheppo 	if (rv == 0) {
44711991Sheppo 		ldcp->tx_tail = tx_tail;
44721991Sheppo 		ldcp->last_msg_snt = curr_seqid;
44731991Sheppo 		*size = bytes_written;
44741991Sheppo 	} else {
44751991Sheppo 		int rv2;
44761991Sheppo 
44771991Sheppo 		if (rv != EWOULDBLOCK) {
44781991Sheppo 			*size = 0;
44792336Snarayan 			if (mutex_tryenter(&ldcp->lock)) {
44802793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
44812336Snarayan 				mutex_exit(&ldcp->lock);
44822336Snarayan 			} else {
44832336Snarayan 				/*
44842336Snarayan 				 * Release Tx lock, and then reacquire channel
44852336Snarayan 				 * and Tx lock in correct order
44862336Snarayan 				 */
44872336Snarayan 				mutex_exit(&ldcp->tx_lock);
44882336Snarayan 				mutex_enter(&ldcp->lock);
44892336Snarayan 				mutex_enter(&ldcp->tx_lock);
44902793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
44912336Snarayan 				mutex_exit(&ldcp->lock);
44922336Snarayan 			}
44931991Sheppo 			return (ECONNRESET);
44941991Sheppo 		}
44951991Sheppo 
44963010Slm66018 		D1(ldcp->id, "hv_tx_set_tail returns 0x%x (head 0x%x, "
44974690Snarayan 		    "old tail 0x%x, new tail 0x%x, qsize=0x%x)\n",
44984690Snarayan 		    rv, ldcp->tx_head, ldcp->tx_tail, tx_tail,
44994690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
45001991Sheppo 
45011991Sheppo 		rv2 = hv_ldc_tx_get_state(ldcp->id,
45021991Sheppo 		    &tx_head, &tx_tail, &ldcp->link_state);
45031991Sheppo 
45043010Slm66018 		D1(ldcp->id, "hv_ldc_tx_get_state returns 0x%x "
45054690Snarayan 		    "(head 0x%x, tail 0x%x state 0x%x)\n",
45064690Snarayan 		    rv2, tx_head, tx_tail, ldcp->link_state);
45071991Sheppo 
45081991Sheppo 		*size = 0;
45091991Sheppo 	}
45101991Sheppo 
45111991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, *size);
45121991Sheppo 
45131991Sheppo 	return (rv);
45141991Sheppo }
45151991Sheppo 
45161991Sheppo /*
45171991Sheppo  * Write specified amount of bytes to the channel
45181991Sheppo  * in multiple pkts of pkt_payload size. Each
45191991Sheppo  * packet is tagged with an unique packet ID in
45202410Slm66018  * the case of a reliable link.
45211991Sheppo  *
45221991Sheppo  * On return, size contains the number of bytes written.
45231991Sheppo  * This function needs to ensure that the write size is < MTU size
45241991Sheppo  */
45251991Sheppo static int
45261991Sheppo i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
45271991Sheppo {
45282336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
4529*6408Sha137994 	ASSERT(ldcp->mode == LDC_MODE_RELIABLE);
45301991Sheppo 
45311991Sheppo 	/* Truncate packet to max of MTU size */
45321991Sheppo 	if (*sizep > ldcp->mtu) *sizep = ldcp->mtu;
45331991Sheppo 	return (i_ldc_write_packet(ldcp, buf, sizep));
45341991Sheppo }
45351991Sheppo 
45361991Sheppo 
45371991Sheppo /*
45381991Sheppo  * Interfaces for channel nexus to register/unregister with LDC module
45391991Sheppo  * The nexus will register functions to be used to register individual
45401991Sheppo  * channels with the nexus and enable interrupts for the channels
45411991Sheppo  */
45421991Sheppo int
45431991Sheppo ldc_register(ldc_cnex_t *cinfo)
45441991Sheppo {
45451991Sheppo 	ldc_chan_t	*ldcp;
45461991Sheppo 
45471991Sheppo 	if (cinfo == NULL || cinfo->dip == NULL ||
45481991Sheppo 	    cinfo->reg_chan == NULL || cinfo->unreg_chan == NULL ||
45491991Sheppo 	    cinfo->add_intr == NULL || cinfo->rem_intr == NULL ||
45501991Sheppo 	    cinfo->clr_intr == NULL) {
45511991Sheppo 
45521991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_register: invalid nexus info\n");
45531991Sheppo 		return (EINVAL);
45541991Sheppo 	}
45551991Sheppo 
45561991Sheppo 	mutex_enter(&ldcssp->lock);
45571991Sheppo 
45581991Sheppo 	/* nexus registration */
45591991Sheppo 	ldcssp->cinfo.dip = cinfo->dip;
45601991Sheppo 	ldcssp->cinfo.reg_chan = cinfo->reg_chan;
45611991Sheppo 	ldcssp->cinfo.unreg_chan = cinfo->unreg_chan;
45621991Sheppo 	ldcssp->cinfo.add_intr = cinfo->add_intr;
45631991Sheppo 	ldcssp->cinfo.rem_intr = cinfo->rem_intr;
45641991Sheppo 	ldcssp->cinfo.clr_intr = cinfo->clr_intr;
45651991Sheppo 
45661991Sheppo 	/* register any channels that might have been previously initialized */
45671991Sheppo 	ldcp = ldcssp->chan_list;
45681991Sheppo 	while (ldcp) {
45691991Sheppo 		if ((ldcp->tstate & TS_QCONF_RDY) &&
45701991Sheppo 		    (ldcp->tstate & TS_CNEX_RDY) == 0)
45711991Sheppo 			(void) i_ldc_register_channel(ldcp);
45721991Sheppo 
45731991Sheppo 		ldcp = ldcp->next;
45741991Sheppo 	}
45751991Sheppo 
45761991Sheppo 	mutex_exit(&ldcssp->lock);
45771991Sheppo 
45781991Sheppo 	return (0);
45791991Sheppo }
45801991Sheppo 
45811991Sheppo int
45821991Sheppo ldc_unregister(ldc_cnex_t *cinfo)
45831991Sheppo {
45841991Sheppo 	if (cinfo == NULL || cinfo->dip == NULL) {
45851991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid nexus info\n");
45861991Sheppo 		return (EINVAL);
45871991Sheppo 	}
45881991Sheppo 
45891991Sheppo 	mutex_enter(&ldcssp->lock);
45901991Sheppo 
45911991Sheppo 	if (cinfo->dip != ldcssp->cinfo.dip) {
45921991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid dip\n");
45931991Sheppo 		mutex_exit(&ldcssp->lock);
45941991Sheppo 		return (EINVAL);
45951991Sheppo 	}
45961991Sheppo 
45971991Sheppo 	/* nexus unregister */
45981991Sheppo 	ldcssp->cinfo.dip = NULL;
45991991Sheppo 	ldcssp->cinfo.reg_chan = NULL;
46001991Sheppo 	ldcssp->cinfo.unreg_chan = NULL;
46011991Sheppo 	ldcssp->cinfo.add_intr = NULL;
46021991Sheppo 	ldcssp->cinfo.rem_intr = NULL;
46031991Sheppo 	ldcssp->cinfo.clr_intr = NULL;
46041991Sheppo 
46051991Sheppo 	mutex_exit(&ldcssp->lock);
46061991Sheppo 
46071991Sheppo 	return (0);
46081991Sheppo }
4609