xref: /illumos-gate/usr/src/uts/sun4v/io/ldc.c (revision a704fb2d43b34f92d7dcac9c06204ea48237612d)
11ae08745Sheppo /*
21ae08745Sheppo  * CDDL HEADER START
31ae08745Sheppo  *
41ae08745Sheppo  * The contents of this file are subject to the terms of the
51ae08745Sheppo  * Common Development and Distribution License (the "License").
61ae08745Sheppo  * You may not use this file except in compliance with the License.
71ae08745Sheppo  *
81ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
101ae08745Sheppo  * See the License for the specific language governing permissions
111ae08745Sheppo  * and limitations under the License.
121ae08745Sheppo  *
131ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181ae08745Sheppo  *
191ae08745Sheppo  * CDDL HEADER END
201ae08745Sheppo  */
211ae08745Sheppo 
221ae08745Sheppo /*
2334f94fbcSWENTAO YANG  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
241ae08745Sheppo  */
251ae08745Sheppo 
261ae08745Sheppo /*
27e1ebb9ecSlm66018  * sun4v LDC Link Layer
281ae08745Sheppo  */
291ae08745Sheppo #include <sys/types.h>
301ae08745Sheppo #include <sys/file.h>
311ae08745Sheppo #include <sys/errno.h>
321ae08745Sheppo #include <sys/open.h>
331ae08745Sheppo #include <sys/cred.h>
341ae08745Sheppo #include <sys/kmem.h>
351ae08745Sheppo #include <sys/conf.h>
361ae08745Sheppo #include <sys/cmn_err.h>
371ae08745Sheppo #include <sys/ksynch.h>
381ae08745Sheppo #include <sys/modctl.h>
391ae08745Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */
401ae08745Sheppo #include <sys/debug.h>
411ae08745Sheppo #include <sys/cred.h>
421ae08745Sheppo #include <sys/promif.h>
431ae08745Sheppo #include <sys/ddi.h>
441ae08745Sheppo #include <sys/sunddi.h>
451ae08745Sheppo #include <sys/cyclic.h>
461ae08745Sheppo #include <sys/machsystm.h>
471ae08745Sheppo #include <sys/vm.h>
481ae08745Sheppo #include <sys/cpu.h>
491ae08745Sheppo #include <sys/intreg.h>
501ae08745Sheppo #include <sys/machcpuvar.h>
514bac2208Snarayan #include <sys/mmu.h>
524bac2208Snarayan #include <sys/pte.h>
534bac2208Snarayan #include <vm/hat.h>
544bac2208Snarayan #include <vm/as.h>
554bac2208Snarayan #include <vm/hat_sfmmu.h>
564bac2208Snarayan #include <sys/vm_machparam.h>
574bac2208Snarayan #include <vm/seg_kmem.h>
584bac2208Snarayan #include <vm/seg_kpm.h>
591ae08745Sheppo #include <sys/note.h>
601ae08745Sheppo #include <sys/ivintr.h>
611ae08745Sheppo #include <sys/hypervisor_api.h>
621ae08745Sheppo #include <sys/ldc.h>
631ae08745Sheppo #include <sys/ldc_impl.h>
641ae08745Sheppo #include <sys/cnex.h>
651ae08745Sheppo #include <sys/hsvc.h>
6658283286Sha137994 #include <sys/sdt.h>
675699897cSHaik Aftandilian #include <sys/kldc.h>
681ae08745Sheppo 
691ae08745Sheppo /* Core internal functions */
7020ae46ebSha137994 int i_ldc_h2v_error(int h_error);
7120ae46ebSha137994 void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset);
7220ae46ebSha137994 
731ae08745Sheppo static int i_ldc_txq_reconf(ldc_chan_t *ldcp);
743af08d82Slm66018 static int i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset);
75305dbad4SKevin Crowe static void i_ldc_rxq_drain(ldc_chan_t *ldcp);
761ae08745Sheppo static void i_ldc_reset_state(ldc_chan_t *ldcp);
775699897cSHaik Aftandilian static void i_ldc_debug_enter(void);
781ae08745Sheppo 
791ae08745Sheppo static int i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail);
8022f747efSnarayan static void i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head);
811ae08745Sheppo static int i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail);
821ae08745Sheppo static int i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head);
831ae08745Sheppo static int i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
841ae08745Sheppo     uint8_t ctrlmsg);
851ae08745Sheppo 
8658283286Sha137994 static int  i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head);
8758283286Sha137994 static void i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head);
8858283286Sha137994 static uint64_t i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head,
8958283286Sha137994     uint64_t *tail, uint64_t *link_state);
9058283286Sha137994 static uint64_t i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head,
9158283286Sha137994     uint64_t *tail, uint64_t *link_state);
9258283286Sha137994 static int i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head,
9358283286Sha137994     uint64_t rx_tail);
9458283286Sha137994 static uint_t i_ldc_chkq(ldc_chan_t *ldcp);
9558283286Sha137994 
961ae08745Sheppo /* Interrupt handling functions */
971ae08745Sheppo static uint_t i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2);
981ae08745Sheppo static uint_t i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2);
9958283286Sha137994 static uint_t i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client,
10058283286Sha137994     uint64_t *notify_event);
1011ae08745Sheppo static void i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype);
1021ae08745Sheppo 
1031ae08745Sheppo /* Read method functions */
1041ae08745Sheppo static int i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep);
1051ae08745Sheppo static int i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp,
1061ae08745Sheppo 	size_t *sizep);
1071ae08745Sheppo static int i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp,
1081ae08745Sheppo 	size_t *sizep);
1091ae08745Sheppo 
1101ae08745Sheppo /* Write method functions */
1111ae08745Sheppo static int i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t target_bufp,
1121ae08745Sheppo 	size_t *sizep);
1131ae08745Sheppo static int i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t target_bufp,
1141ae08745Sheppo 	size_t *sizep);
1151ae08745Sheppo static int i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t target_bufp,
1161ae08745Sheppo 	size_t *sizep);
1171ae08745Sheppo 
1181ae08745Sheppo /* Pkt processing internal functions */
1191ae08745Sheppo static int i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg);
1201ae08745Sheppo static int i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg);
1211ae08745Sheppo static int i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg);
1221ae08745Sheppo static int i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg);
1231ae08745Sheppo static int i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg);
1241ae08745Sheppo static int i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg);
1251ae08745Sheppo static int i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg);
1261ae08745Sheppo 
12734f94fbcSWENTAO YANG /* Imported functions */
12834f94fbcSWENTAO YANG extern void i_ldc_mem_set_hsvc_vers(uint64_t major, uint64_t minor);
12934f94fbcSWENTAO YANG extern void i_ldc_init_mapin(ldc_soft_state_t *ldcssp, uint64_t major,
13034f94fbcSWENTAO YANG 	uint64_t minor);
13134f94fbcSWENTAO YANG 
1321ae08745Sheppo /* LDC Version */
1331ae08745Sheppo static ldc_ver_t ldc_versions[] = { {1, 0} };
1341ae08745Sheppo 
1351ae08745Sheppo /* number of supported versions */
1361ae08745Sheppo #define	LDC_NUM_VERS	(sizeof (ldc_versions) / sizeof (ldc_versions[0]))
1371ae08745Sheppo 
13858283286Sha137994 /* Invalid value for the ldc_chan_t rx_ack_head field */
13958283286Sha137994 #define	ACKPEEK_HEAD_INVALID	((uint64_t)-1)
14058283286Sha137994 
14158283286Sha137994 
1421ae08745Sheppo /* Module State Pointer */
14320ae46ebSha137994 ldc_soft_state_t *ldcssp;
1441ae08745Sheppo 
1451ae08745Sheppo static struct modldrv md = {
1461ae08745Sheppo 	&mod_miscops,			/* This is a misc module */
147f500b196SRichard Bean 	"sun4v LDC module",		/* Name of the module */
1481ae08745Sheppo };
1491ae08745Sheppo 
1501ae08745Sheppo static struct modlinkage ml = {
1511ae08745Sheppo 	MODREV_1,
1521ae08745Sheppo 	&md,
1531ae08745Sheppo 	NULL
1541ae08745Sheppo };
1551ae08745Sheppo 
1561ae08745Sheppo static uint64_t ldc_sup_minor;		/* Supported minor number */
1571ae08745Sheppo static hsvc_info_t ldc_hsvc = {
15834f94fbcSWENTAO YANG 	HSVC_REV_1, NULL, HSVC_GROUP_LDC, 1, 2, "ldc"
1591ae08745Sheppo };
1601ae08745Sheppo 
1614bac2208Snarayan /*
162e1ebb9ecSlm66018  * The no. of MTU size messages that can be stored in
163e1ebb9ecSlm66018  * the LDC Tx queue. The number of Tx queue entries is
164e1ebb9ecSlm66018  * then computed as (mtu * mtu_msgs)/sizeof(queue_entry)
165e1ebb9ecSlm66018  */
166e1ebb9ecSlm66018 uint64_t ldc_mtu_msgs = LDC_MTU_MSGS;
167e1ebb9ecSlm66018 
168e1ebb9ecSlm66018 /*
169e1ebb9ecSlm66018  * The minimum queue length. This is the size of the smallest
170e1ebb9ecSlm66018  * LDC queue. If the computed value is less than this default,
171e1ebb9ecSlm66018  * the queue length is rounded up to 'ldc_queue_entries'.
172e1ebb9ecSlm66018  */
173e1ebb9ecSlm66018 uint64_t ldc_queue_entries = LDC_QUEUE_ENTRIES;
174e1ebb9ecSlm66018 
175e1ebb9ecSlm66018 /*
17658283286Sha137994  * The length of the reliable-mode data queue in terms of the LDC
17758283286Sha137994  * receive queue length. i.e., the number of times larger than the
17858283286Sha137994  * LDC receive queue that the data queue should be. The HV receive
17958283286Sha137994  * queue is required to be a power of 2 and this implementation
18058283286Sha137994  * assumes the data queue will also be a power of 2. By making the
18158283286Sha137994  * multiplier a power of 2, we ensure the data queue will be a
18258283286Sha137994  * power of 2. We use a multiplier because the receive queue is
18358283286Sha137994  * sized to be sane relative to the MTU and the same is needed for
18458283286Sha137994  * the data queue.
18558283286Sha137994  */
18658283286Sha137994 uint64_t ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER;
18758283286Sha137994 
18858283286Sha137994 /*
189e1ebb9ecSlm66018  * LDC retry count and delay - when the HV returns EWOULDBLOCK
190e1ebb9ecSlm66018  * the operation is retried 'ldc_max_retries' times with a
191e1ebb9ecSlm66018  * wait of 'ldc_delay' usecs between each retry.
1920a55fbb7Slm66018  */
1930a55fbb7Slm66018 int ldc_max_retries = LDC_MAX_RETRIES;
1940a55fbb7Slm66018 clock_t ldc_delay = LDC_DELAY;
1950a55fbb7Slm66018 
1964d39be2bSsg70180 /*
1975699897cSHaik Aftandilian  * Channels which have a devclass satisfying the following
1985699897cSHaik Aftandilian  * will be reset when entering the prom or kmdb.
1995699897cSHaik Aftandilian  *
2005699897cSHaik Aftandilian  *   LDC_DEVCLASS_PROM_RESET(devclass) != 0
2015699897cSHaik Aftandilian  *
2025699897cSHaik Aftandilian  * By default, only block device service channels are reset.
2035699897cSHaik Aftandilian  */
2045699897cSHaik Aftandilian #define	LDC_DEVCLASS_BIT(dc)		(0x1 << (dc))
2055699897cSHaik Aftandilian #define	LDC_DEVCLASS_PROM_RESET(dc)	\
2065699897cSHaik Aftandilian 	(LDC_DEVCLASS_BIT(dc) & ldc_debug_reset_mask)
207d16449dbSZach Kissel static uint64_t ldc_debug_reset_mask = LDC_DEVCLASS_BIT(LDC_DEV_BLK_SVC) |
208d16449dbSZach Kissel     LDC_DEVCLASS_BIT(LDC_DEV_GENERIC);
2095699897cSHaik Aftandilian 
2105699897cSHaik Aftandilian /*
2114d39be2bSsg70180  * delay between each retry of channel unregistration in
2124d39be2bSsg70180  * ldc_close(), to wait for pending interrupts to complete.
2134d39be2bSsg70180  */
2144d39be2bSsg70180 clock_t ldc_close_delay = LDC_CLOSE_DELAY;
2154d39be2bSsg70180 
21634f94fbcSWENTAO YANG 
21734f94fbcSWENTAO YANG /*
21834f94fbcSWENTAO YANG  * Reserved mapin space for descriptor rings.
21934f94fbcSWENTAO YANG  */
22034f94fbcSWENTAO YANG uint64_t ldc_dring_direct_map_rsvd = LDC_DIRECT_MAP_SIZE_DEFAULT;
22134f94fbcSWENTAO YANG 
22234f94fbcSWENTAO YANG /*
22334f94fbcSWENTAO YANG  * Maximum direct map space allowed per channel.
22434f94fbcSWENTAO YANG  */
22534f94fbcSWENTAO YANG uint64_t	ldc_direct_map_size_max = (16 * 1024 * 1024);	/* 16 MB */
22634f94fbcSWENTAO YANG 
2271ae08745Sheppo #ifdef DEBUG
2281ae08745Sheppo 
2291ae08745Sheppo /*
2301ae08745Sheppo  * Print debug messages
2311ae08745Sheppo  *
2321ae08745Sheppo  * set ldcdbg to 0x7 for enabling all msgs
2331ae08745Sheppo  * 0x4 - Warnings
2341ae08745Sheppo  * 0x2 - All debug messages
2351ae08745Sheppo  * 0x1 - Minimal debug messages
2361ae08745Sheppo  *
2371ae08745Sheppo  * set ldcdbgchan to the channel number you want to debug
2381ae08745Sheppo  * setting it to -1 prints debug messages for all channels
2391ae08745Sheppo  * NOTE: ldcdbgchan has no effect on error messages
2401ae08745Sheppo  */
2411ae08745Sheppo 
2421ae08745Sheppo int ldcdbg = 0x0;
2431ae08745Sheppo int64_t ldcdbgchan = DBG_ALL_LDCS;
24483d3bc6fSnarayan uint64_t ldc_inject_err_flag = 0;
2451ae08745Sheppo 
24620ae46ebSha137994 void
ldcdebug(int64_t id,const char * fmt,...)2471ae08745Sheppo ldcdebug(int64_t id, const char *fmt, ...)
2481ae08745Sheppo {
2491ae08745Sheppo 	char buf[512];
2501ae08745Sheppo 	va_list ap;
2511ae08745Sheppo 
2521ae08745Sheppo 	/*
2531ae08745Sheppo 	 * Do not return if,
2541ae08745Sheppo 	 * caller wants to print it anyway - (id == DBG_ALL_LDCS)
2551ae08745Sheppo 	 * debug channel is set to all LDCs - (ldcdbgchan == DBG_ALL_LDCS)
2561ae08745Sheppo 	 * debug channel = caller specified channel
2571ae08745Sheppo 	 */
2581ae08745Sheppo 	if ((id != DBG_ALL_LDCS) &&
2591ae08745Sheppo 	    (ldcdbgchan != DBG_ALL_LDCS) &&
2601ae08745Sheppo 	    (ldcdbgchan != id)) {
2611ae08745Sheppo 		return;
2621ae08745Sheppo 	}
2631ae08745Sheppo 
2641ae08745Sheppo 	va_start(ap, fmt);
2651ae08745Sheppo 	(void) vsprintf(buf, fmt, ap);
2661ae08745Sheppo 	va_end(ap);
2671ae08745Sheppo 
2683af08d82Slm66018 	cmn_err(CE_CONT, "?%s", buf);
2693af08d82Slm66018 }
2703af08d82Slm66018 
27183d3bc6fSnarayan #define	LDC_ERR_RESET		0x1
27283d3bc6fSnarayan #define	LDC_ERR_PKTLOSS		0x2
27358283286Sha137994 #define	LDC_ERR_DQFULL		0x4
274bbfa0259Sha137994 #define	LDC_ERR_DRNGCLEAR	0x8
27583d3bc6fSnarayan 
2763af08d82Slm66018 static boolean_t
ldc_inject_error(ldc_chan_t * ldcp,uint64_t error)27783d3bc6fSnarayan ldc_inject_error(ldc_chan_t *ldcp, uint64_t error)
2783af08d82Slm66018 {
2793af08d82Slm66018 	if ((ldcdbgchan != DBG_ALL_LDCS) && (ldcdbgchan != ldcp->id))
2803af08d82Slm66018 		return (B_FALSE);
2813af08d82Slm66018 
28283d3bc6fSnarayan 	if ((ldc_inject_err_flag & error) == 0)
2833af08d82Slm66018 		return (B_FALSE);
2843af08d82Slm66018 
2853af08d82Slm66018 	/* clear the injection state */
28683d3bc6fSnarayan 	ldc_inject_err_flag &= ~error;
2873af08d82Slm66018 
2883af08d82Slm66018 	return (B_TRUE);
2891ae08745Sheppo }
2901ae08745Sheppo 
2911ae08745Sheppo #define	DUMP_PAYLOAD(id, addr)						\
2921ae08745Sheppo {									\
2931ae08745Sheppo 	char buf[65*3];							\
2941ae08745Sheppo 	int i;								\
2951ae08745Sheppo 	uint8_t *src = (uint8_t *)addr;					\
2961ae08745Sheppo 	for (i = 0; i < 64; i++, src++)					\
2971ae08745Sheppo 		(void) sprintf(&buf[i * 3], "|%02x", *src);		\
2981ae08745Sheppo 	(void) sprintf(&buf[i * 3], "|\n");				\
2991ae08745Sheppo 	D2((id), "payload: %s", buf);					\
3001ae08745Sheppo }
3011ae08745Sheppo 
3021ae08745Sheppo #define	DUMP_LDC_PKT(c, s, addr)					\
3031ae08745Sheppo {									\
3041ae08745Sheppo 	ldc_msg_t *msg = (ldc_msg_t *)(addr);				\
3051ae08745Sheppo 	uint32_t mid = ((c)->mode != LDC_MODE_RAW) ? msg->seqid : 0;	\
3061ae08745Sheppo 	if (msg->type == LDC_DATA) {                                    \
3071ae08745Sheppo 	    D2((c)->id, "%s: msg%d (/%x/%x/%x/,env[%c%c,sz=%d])",	\
3081ae08745Sheppo 	    (s), mid, msg->type, msg->stype, msg->ctrl,			\
3091ae08745Sheppo 	    (msg->env & LDC_FRAG_START) ? 'B' : ' ',                    \
3101ae08745Sheppo 	    (msg->env & LDC_FRAG_STOP) ? 'E' : ' ',                     \
3111ae08745Sheppo 	    (msg->env & LDC_LEN_MASK));					\
3121ae08745Sheppo 	} else {							\
3131ae08745Sheppo 	    D2((c)->id, "%s: msg%d (/%x/%x/%x/,env=%x)", (s),		\
3141ae08745Sheppo 	    mid, msg->type, msg->stype, msg->ctrl, msg->env);		\
3151ae08745Sheppo 	}								\
3161ae08745Sheppo }
3171ae08745Sheppo 
31883d3bc6fSnarayan #define	LDC_INJECT_RESET(_ldcp)	ldc_inject_error(_ldcp, LDC_ERR_RESET)
31983d3bc6fSnarayan #define	LDC_INJECT_PKTLOSS(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_PKTLOSS)
32058283286Sha137994 #define	LDC_INJECT_DQFULL(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DQFULL)
321bbfa0259Sha137994 #define	LDC_INJECT_DRNGCLEAR(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DRNGCLEAR)
322bbfa0259Sha137994 extern void i_ldc_mem_inject_dring_clear(ldc_chan_t *ldcp);
3233af08d82Slm66018 
3241ae08745Sheppo #else
3251ae08745Sheppo 
3261ae08745Sheppo #define	DBG_ALL_LDCS -1
3271ae08745Sheppo 
3281ae08745Sheppo #define	DUMP_PAYLOAD(id, addr)
3291ae08745Sheppo #define	DUMP_LDC_PKT(c, s, addr)
3301ae08745Sheppo 
3313af08d82Slm66018 #define	LDC_INJECT_RESET(_ldcp)	(B_FALSE)
33283d3bc6fSnarayan #define	LDC_INJECT_PKTLOSS(_ldcp) (B_FALSE)
33358283286Sha137994 #define	LDC_INJECT_DQFULL(_ldcp) (B_FALSE)
334bbfa0259Sha137994 #define	LDC_INJECT_DRNGCLEAR(_ldcp) (B_FALSE)
3353af08d82Slm66018 
3361ae08745Sheppo #endif
3371ae08745Sheppo 
33858283286Sha137994 /*
33958283286Sha137994  * dtrace SDT probes to ease tracing of the rx data queue and HV queue
34058283286Sha137994  * lengths. Just pass the head, tail, and entries values so that the
34158283286Sha137994  * length can be calculated in a dtrace script when the probe is enabled.
34258283286Sha137994  */
34358283286Sha137994 #define	TRACE_RXDQ_LENGTH(ldcp)						\
34458283286Sha137994 	DTRACE_PROBE4(rxdq__size,					\
34558283286Sha137994 	uint64_t, ldcp->id,						\
34658283286Sha137994 	uint64_t, ldcp->rx_dq_head,					\
34758283286Sha137994 	uint64_t, ldcp->rx_dq_tail,					\
34858283286Sha137994 	uint64_t, ldcp->rx_dq_entries)
34958283286Sha137994 
35058283286Sha137994 #define	TRACE_RXHVQ_LENGTH(ldcp, head, tail)				\
35158283286Sha137994 	DTRACE_PROBE4(rxhvq__size,					\
35258283286Sha137994 	uint64_t, ldcp->id,						\
35358283286Sha137994 	uint64_t, head,							\
35458283286Sha137994 	uint64_t, tail,							\
35558283286Sha137994 	uint64_t, ldcp->rx_q_entries)
35658283286Sha137994 
35758283286Sha137994 /* A dtrace SDT probe to ease tracing of data queue copy operations */
35858283286Sha137994 #define	TRACE_RXDQ_COPY(ldcp, bytes)					\
35958283286Sha137994 	DTRACE_PROBE2(rxdq__copy, uint64_t, ldcp->id, uint64_t, bytes)	\
36058283286Sha137994 
36158283286Sha137994 /* The amount of contiguous space at the tail of the queue */
36258283286Sha137994 #define	Q_CONTIG_SPACE(head, tail, size)				\
36358283286Sha137994 	((head) <= (tail) ? ((size) - (tail)) :				\
36458283286Sha137994 	((head) - (tail) - LDC_PACKET_SIZE))
36558283286Sha137994 
3661ae08745Sheppo #define	ZERO_PKT(p)			\
3671ae08745Sheppo 	bzero((p), sizeof (ldc_msg_t));
3681ae08745Sheppo 
3691ae08745Sheppo #define	IDX2COOKIE(idx, pg_szc, pg_shift)				\
3701ae08745Sheppo 	(((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift)))
3711ae08745Sheppo 
3721ae08745Sheppo int
_init(void)3731ae08745Sheppo _init(void)
3741ae08745Sheppo {
3751ae08745Sheppo 	int status;
3761ae08745Sheppo 
3771ae08745Sheppo 	status = hsvc_register(&ldc_hsvc, &ldc_sup_minor);
3781ae08745Sheppo 	if (status != 0) {
379d66f8315Sjb145095 		cmn_err(CE_NOTE, "!%s: cannot negotiate hypervisor LDC services"
3801ae08745Sheppo 		    " group: 0x%lx major: %ld minor: %ld errno: %d",
3811ae08745Sheppo 		    ldc_hsvc.hsvc_modname, ldc_hsvc.hsvc_group,
3821ae08745Sheppo 		    ldc_hsvc.hsvc_major, ldc_hsvc.hsvc_minor, status);
3831ae08745Sheppo 		return (-1);
3841ae08745Sheppo 	}
3851ae08745Sheppo 
386bbfa0259Sha137994 	/* Initialize shared memory HV API version checking */
387bbfa0259Sha137994 	i_ldc_mem_set_hsvc_vers(ldc_hsvc.hsvc_major, ldc_sup_minor);
388bbfa0259Sha137994 
3891ae08745Sheppo 	/* allocate soft state structure */
3901ae08745Sheppo 	ldcssp = kmem_zalloc(sizeof (ldc_soft_state_t), KM_SLEEP);
3911ae08745Sheppo 
39234f94fbcSWENTAO YANG 	i_ldc_init_mapin(ldcssp, ldc_hsvc.hsvc_major, ldc_sup_minor);
39334f94fbcSWENTAO YANG 
3941ae08745Sheppo 	/* Link the module into the system */
3951ae08745Sheppo 	status = mod_install(&ml);
3961ae08745Sheppo 	if (status != 0) {
3971ae08745Sheppo 		kmem_free(ldcssp, sizeof (ldc_soft_state_t));
3981ae08745Sheppo 		return (status);
3991ae08745Sheppo 	}
4001ae08745Sheppo 
4011ae08745Sheppo 	/* Initialize the LDC state structure */
4021ae08745Sheppo 	mutex_init(&ldcssp->lock, NULL, MUTEX_DRIVER, NULL);
4031ae08745Sheppo 
4041ae08745Sheppo 	mutex_enter(&ldcssp->lock);
4051ae08745Sheppo 
4064bac2208Snarayan 	/* Create a cache for memory handles */
4074bac2208Snarayan 	ldcssp->memhdl_cache = kmem_cache_create("ldc_memhdl_cache",
4084bac2208Snarayan 	    sizeof (ldc_mhdl_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
4094bac2208Snarayan 	if (ldcssp->memhdl_cache == NULL) {
4104bac2208Snarayan 		DWARN(DBG_ALL_LDCS, "_init: ldc_memhdl cache create failed\n");
4114bac2208Snarayan 		mutex_exit(&ldcssp->lock);
4124bac2208Snarayan 		return (-1);
4134bac2208Snarayan 	}
4144bac2208Snarayan 
4154bac2208Snarayan 	/* Create cache for memory segment structures */
4164bac2208Snarayan 	ldcssp->memseg_cache = kmem_cache_create("ldc_memseg_cache",
4174bac2208Snarayan 	    sizeof (ldc_memseg_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
4184bac2208Snarayan 	if (ldcssp->memseg_cache == NULL) {
4194bac2208Snarayan 		DWARN(DBG_ALL_LDCS, "_init: ldc_memseg cache create failed\n");
4204bac2208Snarayan 		mutex_exit(&ldcssp->lock);
4214bac2208Snarayan 		return (-1);
4224bac2208Snarayan 	}
4234bac2208Snarayan 
4244bac2208Snarayan 
4251ae08745Sheppo 	ldcssp->channel_count = 0;
4261ae08745Sheppo 	ldcssp->channels_open = 0;
4271ae08745Sheppo 	ldcssp->chan_list = NULL;
4281ae08745Sheppo 	ldcssp->dring_list = NULL;
4291ae08745Sheppo 
4305699897cSHaik Aftandilian 	/* Register debug_enter callback */
4315699897cSHaik Aftandilian 	kldc_set_debug_cb(&i_ldc_debug_enter);
4325699897cSHaik Aftandilian 
4331ae08745Sheppo 	mutex_exit(&ldcssp->lock);
4341ae08745Sheppo 
4351ae08745Sheppo 	return (0);
4361ae08745Sheppo }
4371ae08745Sheppo 
4381ae08745Sheppo int
_info(struct modinfo * modinfop)4391ae08745Sheppo _info(struct modinfo *modinfop)
4401ae08745Sheppo {
4411ae08745Sheppo 	/* Report status of the dynamically loadable driver module */
4421ae08745Sheppo 	return (mod_info(&ml, modinfop));
4431ae08745Sheppo }
4441ae08745Sheppo 
4451ae08745Sheppo int
_fini(void)4461ae08745Sheppo _fini(void)
4471ae08745Sheppo {
4481ae08745Sheppo 	int		rv, status;
44922f747efSnarayan 	ldc_chan_t	*tmp_ldcp, *ldcp;
45022f747efSnarayan 	ldc_dring_t	*tmp_dringp, *dringp;
4511ae08745Sheppo 	ldc_mem_info_t	minfo;
4521ae08745Sheppo 
4531ae08745Sheppo 	/* Unlink the driver module from the system */
4541ae08745Sheppo 	status = mod_remove(&ml);
4551ae08745Sheppo 	if (status) {
4561ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "_fini: mod_remove failed\n");
4571ae08745Sheppo 		return (EIO);
4581ae08745Sheppo 	}
4591ae08745Sheppo 
4605699897cSHaik Aftandilian 	/* Unregister debug_enter callback */
4615699897cSHaik Aftandilian 	kldc_set_debug_cb(NULL);
4625699897cSHaik Aftandilian 
4631ae08745Sheppo 	/* Free descriptor rings */
4641ae08745Sheppo 	dringp = ldcssp->dring_list;
4651ae08745Sheppo 	while (dringp != NULL) {
46622f747efSnarayan 		tmp_dringp = dringp->next;
4671ae08745Sheppo 
4681ae08745Sheppo 		rv = ldc_mem_dring_info((ldc_dring_handle_t)dringp, &minfo);
4691ae08745Sheppo 		if (rv == 0 && minfo.status != LDC_UNBOUND) {
4701ae08745Sheppo 			if (minfo.status == LDC_BOUND) {
4711ae08745Sheppo 				(void) ldc_mem_dring_unbind(
4721ae08745Sheppo 				    (ldc_dring_handle_t)dringp);
4731ae08745Sheppo 			}
4741ae08745Sheppo 			if (minfo.status == LDC_MAPPED) {
4751ae08745Sheppo 				(void) ldc_mem_dring_unmap(
4761ae08745Sheppo 				    (ldc_dring_handle_t)dringp);
4771ae08745Sheppo 			}
4781ae08745Sheppo 		}
4791ae08745Sheppo 
4801ae08745Sheppo 		(void) ldc_mem_dring_destroy((ldc_dring_handle_t)dringp);
48122f747efSnarayan 		dringp = tmp_dringp;
4821ae08745Sheppo 	}
4831ae08745Sheppo 	ldcssp->dring_list = NULL;
4841ae08745Sheppo 
48522f747efSnarayan 	/* close and finalize channels */
48622f747efSnarayan 	ldcp = ldcssp->chan_list;
48722f747efSnarayan 	while (ldcp != NULL) {
48822f747efSnarayan 		tmp_ldcp = ldcp->next;
48922f747efSnarayan 
49022f747efSnarayan 		(void) ldc_close((ldc_handle_t)ldcp);
49122f747efSnarayan 		(void) ldc_fini((ldc_handle_t)ldcp);
49222f747efSnarayan 
49322f747efSnarayan 		ldcp = tmp_ldcp;
49422f747efSnarayan 	}
49522f747efSnarayan 	ldcssp->chan_list = NULL;
49622f747efSnarayan 
4974bac2208Snarayan 	/* Destroy kmem caches */
4984bac2208Snarayan 	kmem_cache_destroy(ldcssp->memhdl_cache);
4994bac2208Snarayan 	kmem_cache_destroy(ldcssp->memseg_cache);
5004bac2208Snarayan 
5011ae08745Sheppo 	/*
5021ae08745Sheppo 	 * We have successfully "removed" the driver.
5031ae08745Sheppo 	 * Destroying soft states
5041ae08745Sheppo 	 */
5051ae08745Sheppo 	mutex_destroy(&ldcssp->lock);
5061ae08745Sheppo 	kmem_free(ldcssp, sizeof (ldc_soft_state_t));
5071ae08745Sheppo 
5081ae08745Sheppo 	(void) hsvc_unregister(&ldc_hsvc);
5091ae08745Sheppo 
5101ae08745Sheppo 	return (status);
5111ae08745Sheppo }
5121ae08745Sheppo 
5131ae08745Sheppo /* -------------------------------------------------------------------------- */
5141ae08745Sheppo 
5151ae08745Sheppo /*
516e1ebb9ecSlm66018  * LDC Link Layer Internal Functions
5171ae08745Sheppo  */
5181ae08745Sheppo 
5191ae08745Sheppo /*
5201ae08745Sheppo  * Translate HV Errors to sun4v error codes
5211ae08745Sheppo  */
52220ae46ebSha137994 int
i_ldc_h2v_error(int h_error)5231ae08745Sheppo i_ldc_h2v_error(int h_error)
5241ae08745Sheppo {
5251ae08745Sheppo 	switch (h_error) {
5261ae08745Sheppo 
5271ae08745Sheppo 	case	H_EOK:
5281ae08745Sheppo 		return (0);
5291ae08745Sheppo 
5301ae08745Sheppo 	case	H_ENORADDR:
5311ae08745Sheppo 		return (EFAULT);
5321ae08745Sheppo 
5331ae08745Sheppo 	case	H_EBADPGSZ:
5341ae08745Sheppo 	case	H_EINVAL:
5351ae08745Sheppo 		return (EINVAL);
5361ae08745Sheppo 
5371ae08745Sheppo 	case	H_EWOULDBLOCK:
5381ae08745Sheppo 		return (EWOULDBLOCK);
5391ae08745Sheppo 
5401ae08745Sheppo 	case	H_ENOACCESS:
5411ae08745Sheppo 	case	H_ENOMAP:
5421ae08745Sheppo 		return (EACCES);
5431ae08745Sheppo 
5441ae08745Sheppo 	case	H_EIO:
5451ae08745Sheppo 	case	H_ECPUERROR:
5461ae08745Sheppo 		return (EIO);
5471ae08745Sheppo 
5481ae08745Sheppo 	case	H_ENOTSUPPORTED:
5491ae08745Sheppo 		return (ENOTSUP);
5501ae08745Sheppo 
5511ae08745Sheppo 	case	H_ETOOMANY:
5521ae08745Sheppo 		return (ENOSPC);
5531ae08745Sheppo 
5541ae08745Sheppo 	case	H_ECHANNEL:
5551ae08745Sheppo 		return (ECHRNG);
5561ae08745Sheppo 	default:
5571ae08745Sheppo 		break;
5581ae08745Sheppo 	}
5591ae08745Sheppo 
5601ae08745Sheppo 	return (EIO);
5611ae08745Sheppo }
5621ae08745Sheppo 
5631ae08745Sheppo /*
5641ae08745Sheppo  * Reconfigure the transmit queue
5651ae08745Sheppo  */
5661ae08745Sheppo static int
i_ldc_txq_reconf(ldc_chan_t * ldcp)5671ae08745Sheppo i_ldc_txq_reconf(ldc_chan_t *ldcp)
5681ae08745Sheppo {
5691ae08745Sheppo 	int rv;
5701ae08745Sheppo 
5711ae08745Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
572d10e4ef2Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
573d10e4ef2Snarayan 
5741ae08745Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
5751ae08745Sheppo 	if (rv) {
5761ae08745Sheppo 		cmn_err(CE_WARN,
5773af08d82Slm66018 		    "i_ldc_txq_reconf: (0x%lx) cannot set qconf", ldcp->id);
5781ae08745Sheppo 		return (EIO);
5791ae08745Sheppo 	}
5801ae08745Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id, &(ldcp->tx_head),
5811ae08745Sheppo 	    &(ldcp->tx_tail), &(ldcp->link_state));
5821ae08745Sheppo 	if (rv) {
5831ae08745Sheppo 		cmn_err(CE_WARN,
5843af08d82Slm66018 		    "i_ldc_txq_reconf: (0x%lx) cannot get qptrs", ldcp->id);
5851ae08745Sheppo 		return (EIO);
5861ae08745Sheppo 	}
5873af08d82Slm66018 	D1(ldcp->id, "i_ldc_txq_reconf: (0x%llx) h=0x%llx,t=0x%llx,"
5881ae08745Sheppo 	    "s=0x%llx\n", ldcp->id, ldcp->tx_head, ldcp->tx_tail,
5891ae08745Sheppo 	    ldcp->link_state);
5901ae08745Sheppo 
5911ae08745Sheppo 	return (0);
5921ae08745Sheppo }
5931ae08745Sheppo 
5941ae08745Sheppo /*
5951ae08745Sheppo  * Reconfigure the receive queue
5961ae08745Sheppo  */
5971ae08745Sheppo static int
i_ldc_rxq_reconf(ldc_chan_t * ldcp,boolean_t force_reset)5983af08d82Slm66018 i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset)
5991ae08745Sheppo {
6001ae08745Sheppo 	int rv;
6011ae08745Sheppo 	uint64_t rx_head, rx_tail;
6021ae08745Sheppo 
6031ae08745Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
6041ae08745Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
6051ae08745Sheppo 	    &(ldcp->link_state));
6061ae08745Sheppo 	if (rv) {
6071ae08745Sheppo 		cmn_err(CE_WARN,
6083af08d82Slm66018 		    "i_ldc_rxq_reconf: (0x%lx) cannot get state",
6091ae08745Sheppo 		    ldcp->id);
6101ae08745Sheppo 		return (EIO);
6111ae08745Sheppo 	}
6121ae08745Sheppo 
6133af08d82Slm66018 	if (force_reset || (ldcp->tstate & ~TS_IN_RESET) == TS_UP) {
6141ae08745Sheppo 		rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra,
6151ae08745Sheppo 		    ldcp->rx_q_entries);
6161ae08745Sheppo 		if (rv) {
6171ae08745Sheppo 			cmn_err(CE_WARN,
6183af08d82Slm66018 			    "i_ldc_rxq_reconf: (0x%lx) cannot set qconf",
6191ae08745Sheppo 			    ldcp->id);
6201ae08745Sheppo 			return (EIO);
6211ae08745Sheppo 		}
6223af08d82Slm66018 		D1(ldcp->id, "i_ldc_rxq_reconf: (0x%llx) completed q reconf",
6231ae08745Sheppo 		    ldcp->id);
6241ae08745Sheppo 	}
6251ae08745Sheppo 
6261ae08745Sheppo 	return (0);
6271ae08745Sheppo }
6281ae08745Sheppo 
629a8ea4edeSnarayan 
630a8ea4edeSnarayan /*
631a8ea4edeSnarayan  * Drain the contents of the receive queue
632a8ea4edeSnarayan  */
633305dbad4SKevin Crowe static void
i_ldc_rxq_drain(ldc_chan_t * ldcp)634a8ea4edeSnarayan i_ldc_rxq_drain(ldc_chan_t *ldcp)
635a8ea4edeSnarayan {
636a8ea4edeSnarayan 	int rv;
637a8ea4edeSnarayan 	uint64_t rx_head, rx_tail;
638305dbad4SKevin Crowe 	int retries = 0;
639a8ea4edeSnarayan 
640a8ea4edeSnarayan 	ASSERT(MUTEX_HELD(&ldcp->lock));
641a8ea4edeSnarayan 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
642a8ea4edeSnarayan 	    &(ldcp->link_state));
643a8ea4edeSnarayan 	if (rv) {
644305dbad4SKevin Crowe 		cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot get state, "
645305dbad4SKevin Crowe 		    "rv = 0x%x", ldcp->id, rv);
646305dbad4SKevin Crowe 		return;
647a8ea4edeSnarayan 	}
648a8ea4edeSnarayan 
64932225099SZach Kissel 	/* If the queue is already empty just return success. */
65032225099SZach Kissel 	if (rx_head == rx_tail)
651305dbad4SKevin Crowe 		return;
65232225099SZach Kissel 
653305dbad4SKevin Crowe 	/*
654305dbad4SKevin Crowe 	 * We are draining the queue in order to close the channel.
655305dbad4SKevin Crowe 	 * Call hv_ldc_rx_set_qhead directly instead of i_ldc_set_rx_head
656305dbad4SKevin Crowe 	 * because we do not need to reset the channel if the set
657305dbad4SKevin Crowe 	 * qhead fails.
658305dbad4SKevin Crowe 	 */
659305dbad4SKevin Crowe 	if ((rv = hv_ldc_rx_set_qhead(ldcp->id, rx_tail)) == 0)
660305dbad4SKevin Crowe 		return;
661305dbad4SKevin Crowe 
662305dbad4SKevin Crowe 	while ((rv == H_EWOULDBLOCK) && (retries++ < ldc_max_retries)) {
663305dbad4SKevin Crowe 		drv_usecwait(ldc_delay);
664305dbad4SKevin Crowe 		if ((rv = hv_ldc_rx_set_qhead(ldcp->id, rx_tail)) == 0)
665305dbad4SKevin Crowe 			return;
666305dbad4SKevin Crowe 	}
667305dbad4SKevin Crowe 
668305dbad4SKevin Crowe 	cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot set qhead 0x%lx, "
669305dbad4SKevin Crowe 	    "rv = 0x%x", ldcp->id, rx_tail, rv);
670a8ea4edeSnarayan }
671a8ea4edeSnarayan 
672a8ea4edeSnarayan 
6731ae08745Sheppo /*
6741ae08745Sheppo  * Reset LDC state structure and its contents
6751ae08745Sheppo  */
6761ae08745Sheppo static void
i_ldc_reset_state(ldc_chan_t * ldcp)6771ae08745Sheppo i_ldc_reset_state(ldc_chan_t *ldcp)
6781ae08745Sheppo {
6791ae08745Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
6801ae08745Sheppo 	ldcp->last_msg_snt = LDC_INIT_SEQID;
6811ae08745Sheppo 	ldcp->last_ack_rcd = 0;
6821ae08745Sheppo 	ldcp->last_msg_rcd = 0;
6831ae08745Sheppo 	ldcp->tx_ackd_head = ldcp->tx_head;
68458283286Sha137994 	ldcp->stream_remains = 0;
6851ae08745Sheppo 	ldcp->next_vidx = 0;
6861ae08745Sheppo 	ldcp->hstate = 0;
6871ae08745Sheppo 	ldcp->tstate = TS_OPEN;
6881ae08745Sheppo 	ldcp->status = LDC_OPEN;
68958283286Sha137994 	ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
69058283286Sha137994 	ldcp->rx_dq_head = 0;
69158283286Sha137994 	ldcp->rx_dq_tail = 0;
6921ae08745Sheppo 
6931ae08745Sheppo 	if (ldcp->link_state == LDC_CHANNEL_UP ||
6941ae08745Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
6951ae08745Sheppo 
6961ae08745Sheppo 		if (ldcp->mode == LDC_MODE_RAW) {
6971ae08745Sheppo 			ldcp->status = LDC_UP;
6981ae08745Sheppo 			ldcp->tstate = TS_UP;
6991ae08745Sheppo 		} else {
7001ae08745Sheppo 			ldcp->status = LDC_READY;
7011ae08745Sheppo 			ldcp->tstate |= TS_LINK_READY;
7021ae08745Sheppo 		}
7031ae08745Sheppo 	}
7041ae08745Sheppo }
7051ae08745Sheppo 
7061ae08745Sheppo /*
7071ae08745Sheppo  * Reset a LDC channel
7081ae08745Sheppo  */
70920ae46ebSha137994 void
i_ldc_reset(ldc_chan_t * ldcp,boolean_t force_reset)7103af08d82Slm66018 i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset)
7111ae08745Sheppo {
71283d3bc6fSnarayan 	DWARN(ldcp->id, "i_ldc_reset: (0x%llx) channel reset\n", ldcp->id);
7131ae08745Sheppo 
714d10e4ef2Snarayan 	ASSERT(MUTEX_HELD(&ldcp->lock));
715d10e4ef2Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
716d10e4ef2Snarayan 
7173af08d82Slm66018 	/* reconfig Tx and Rx queues */
7181ae08745Sheppo 	(void) i_ldc_txq_reconf(ldcp);
7193af08d82Slm66018 	(void) i_ldc_rxq_reconf(ldcp, force_reset);
7203af08d82Slm66018 
7213af08d82Slm66018 	/* Clear Tx and Rx interrupts */
7223af08d82Slm66018 	(void) i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
7233af08d82Slm66018 	(void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
7243af08d82Slm66018 
7253af08d82Slm66018 	/* Reset channel state */
7261ae08745Sheppo 	i_ldc_reset_state(ldcp);
7273af08d82Slm66018 
7283af08d82Slm66018 	/* Mark channel in reset */
7293af08d82Slm66018 	ldcp->tstate |= TS_IN_RESET;
7301ae08745Sheppo }
7311ae08745Sheppo 
7325699897cSHaik Aftandilian /*
7335699897cSHaik Aftandilian  * Walk the channel list and reset channels if they are of the right
7345699897cSHaik Aftandilian  * devclass and their Rx queues have been configured. No locks are
7355699897cSHaik Aftandilian  * taken because the function is only invoked by the kernel just before
7365699897cSHaik Aftandilian  * entering the prom or debugger when the system is single-threaded.
7375699897cSHaik Aftandilian  */
7385699897cSHaik Aftandilian static void
i_ldc_debug_enter(void)7395699897cSHaik Aftandilian i_ldc_debug_enter(void)
7405699897cSHaik Aftandilian {
7415699897cSHaik Aftandilian 	ldc_chan_t *ldcp;
7425699897cSHaik Aftandilian 
7435699897cSHaik Aftandilian 	ldcp = ldcssp->chan_list;
7445699897cSHaik Aftandilian 	while (ldcp != NULL) {
7455699897cSHaik Aftandilian 		if (((ldcp->tstate & TS_QCONF_RDY) == TS_QCONF_RDY) &&
7465699897cSHaik Aftandilian 		    (LDC_DEVCLASS_PROM_RESET(ldcp->devclass) != 0)) {
7475699897cSHaik Aftandilian 			(void) hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra,
7485699897cSHaik Aftandilian 			    ldcp->rx_q_entries);
7495699897cSHaik Aftandilian 		}
7505699897cSHaik Aftandilian 		ldcp = ldcp->next;
7515699897cSHaik Aftandilian 	}
7525699897cSHaik Aftandilian }
7534bac2208Snarayan 
7541ae08745Sheppo /*
7551ae08745Sheppo  * Clear pending interrupts
7561ae08745Sheppo  */
7571ae08745Sheppo static void
i_ldc_clear_intr(ldc_chan_t * ldcp,cnex_intrtype_t itype)7581ae08745Sheppo i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype)
7591ae08745Sheppo {
7601ae08745Sheppo 	ldc_cnex_t *cinfo = &ldcssp->cinfo;
7611ae08745Sheppo 
7621ae08745Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
7633af08d82Slm66018 	ASSERT(cinfo->dip != NULL);
7644bac2208Snarayan 
7653af08d82Slm66018 	switch (itype) {
7663af08d82Slm66018 	case CNEX_TX_INTR:
7674bac2208Snarayan 		/* check Tx interrupt */
7683af08d82Slm66018 		if (ldcp->tx_intr_state)
7693af08d82Slm66018 			ldcp->tx_intr_state = LDC_INTR_NONE;
7704bac2208Snarayan 		else
7714bac2208Snarayan 			return;
7723af08d82Slm66018 		break;
7733af08d82Slm66018 
7743af08d82Slm66018 	case CNEX_RX_INTR:
7754bac2208Snarayan 		/* check Rx interrupt */
7763af08d82Slm66018 		if (ldcp->rx_intr_state)
7773af08d82Slm66018 			ldcp->rx_intr_state = LDC_INTR_NONE;
7784bac2208Snarayan 		else
7794bac2208Snarayan 			return;
7803af08d82Slm66018 		break;
7814bac2208Snarayan 	}
7824bac2208Snarayan 
7831ae08745Sheppo 	(void) cinfo->clr_intr(cinfo->dip, ldcp->id, itype);
7844bac2208Snarayan 	D2(ldcp->id,
7854bac2208Snarayan 	    "i_ldc_clear_intr: (0x%llx) cleared 0x%x intr\n",
7864bac2208Snarayan 	    ldcp->id, itype);
7871ae08745Sheppo }
7881ae08745Sheppo 
7891ae08745Sheppo /*
7901ae08745Sheppo  * Set the receive queue head
7910a55fbb7Slm66018  * Resets connection and returns an error if it fails.
7921ae08745Sheppo  */
7931ae08745Sheppo static int
i_ldc_set_rx_head(ldc_chan_t * ldcp,uint64_t head)7941ae08745Sheppo i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head)
7951ae08745Sheppo {
7961ae08745Sheppo 	int	rv;
7970a55fbb7Slm66018 	int	retries;
7981ae08745Sheppo 
7991ae08745Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
8000a55fbb7Slm66018 	for (retries = 0; retries < ldc_max_retries; retries++) {
8010a55fbb7Slm66018 
8020a55fbb7Slm66018 		if ((rv = hv_ldc_rx_set_qhead(ldcp->id, head)) == 0)
8030a55fbb7Slm66018 			return (0);
8040a55fbb7Slm66018 
8050a55fbb7Slm66018 		if (rv != H_EWOULDBLOCK)
8060a55fbb7Slm66018 			break;
8070a55fbb7Slm66018 
8080a55fbb7Slm66018 		/* wait for ldc_delay usecs */
8090a55fbb7Slm66018 		drv_usecwait(ldc_delay);
8101ae08745Sheppo 	}
8111ae08745Sheppo 
812305dbad4SKevin Crowe 	cmn_err(CE_WARN, "ldc_set_rx_qhead: (0x%lx) cannot set qhead 0x%lx, "
813305dbad4SKevin Crowe 	    "rv = 0x%x", ldcp->id, head, rv);
814d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
8153af08d82Slm66018 	i_ldc_reset(ldcp, B_TRUE);
816d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
8170a55fbb7Slm66018 
8180a55fbb7Slm66018 	return (ECONNRESET);
8191ae08745Sheppo }
8201ae08745Sheppo 
82122f747efSnarayan /*
82222f747efSnarayan  * Returns the tx_head to be used for transfer
82322f747efSnarayan  */
82422f747efSnarayan static void
i_ldc_get_tx_head(ldc_chan_t * ldcp,uint64_t * head)82522f747efSnarayan i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head)
82622f747efSnarayan {
82722f747efSnarayan 	ldc_msg_t	*pkt;
82822f747efSnarayan 
82922f747efSnarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
83022f747efSnarayan 
83122f747efSnarayan 	/* get current Tx head */
83222f747efSnarayan 	*head = ldcp->tx_head;
83322f747efSnarayan 
83422f747efSnarayan 	/*
83522f747efSnarayan 	 * Reliable mode will use the ACKd head instead of the regular tx_head.
83622f747efSnarayan 	 * Also in Reliable mode, advance ackd_head for all non DATA/INFO pkts,
83722f747efSnarayan 	 * up to the current location of tx_head. This needs to be done
83822f747efSnarayan 	 * as the peer will only ACK DATA/INFO pkts.
83922f747efSnarayan 	 */
84020ae46ebSha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
84122f747efSnarayan 		while (ldcp->tx_ackd_head != ldcp->tx_head) {
84222f747efSnarayan 			pkt = (ldc_msg_t *)(ldcp->tx_q_va + ldcp->tx_ackd_head);
84322f747efSnarayan 			if ((pkt->type & LDC_DATA) && (pkt->stype & LDC_INFO)) {
84422f747efSnarayan 				break;
84522f747efSnarayan 			}
84622f747efSnarayan 			/* advance ACKd head */
84722f747efSnarayan 			ldcp->tx_ackd_head =
84822f747efSnarayan 			    (ldcp->tx_ackd_head + LDC_PACKET_SIZE) %
84922f747efSnarayan 			    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
85022f747efSnarayan 		}
85122f747efSnarayan 		*head = ldcp->tx_ackd_head;
85222f747efSnarayan 	}
85322f747efSnarayan }
8541ae08745Sheppo 
8551ae08745Sheppo /*
8561ae08745Sheppo  * Returns the tx_tail to be used for transfer
8571ae08745Sheppo  * Re-reads the TX queue ptrs if and only if the
8581ae08745Sheppo  * the cached head and tail are equal (queue is full)
8591ae08745Sheppo  */
8601ae08745Sheppo static int
i_ldc_get_tx_tail(ldc_chan_t * ldcp,uint64_t * tail)8611ae08745Sheppo i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail)
8621ae08745Sheppo {
8631ae08745Sheppo 	int		rv;
8641ae08745Sheppo 	uint64_t	current_head, new_tail;
8651ae08745Sheppo 
866d10e4ef2Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
8671ae08745Sheppo 	/* Read the head and tail ptrs from HV */
8681ae08745Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
8691ae08745Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
8701ae08745Sheppo 	if (rv) {
8711ae08745Sheppo 		cmn_err(CE_WARN,
8721ae08745Sheppo 		    "i_ldc_get_tx_tail: (0x%lx) cannot read qptrs\n",
8731ae08745Sheppo 		    ldcp->id);
8741ae08745Sheppo 		return (EIO);
8751ae08745Sheppo 	}
8761ae08745Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN) {
877cb112a14Slm66018 		D1(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) channel not ready\n",
8781ae08745Sheppo 		    ldcp->id);
8791ae08745Sheppo 		return (ECONNRESET);
8801ae08745Sheppo 	}
8811ae08745Sheppo 
88222f747efSnarayan 	i_ldc_get_tx_head(ldcp, &current_head);
8831ae08745Sheppo 
8841ae08745Sheppo 	/* increment the tail */
8851ae08745Sheppo 	new_tail = (ldcp->tx_tail + LDC_PACKET_SIZE) %
8861ae08745Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
8871ae08745Sheppo 
8881ae08745Sheppo 	if (new_tail == current_head) {
8891ae08745Sheppo 		DWARN(ldcp->id,
8901ae08745Sheppo 		    "i_ldc_get_tx_tail: (0x%llx) TX queue is full\n",
8911ae08745Sheppo 		    ldcp->id);
8921ae08745Sheppo 		return (EWOULDBLOCK);
8931ae08745Sheppo 	}
8941ae08745Sheppo 
8951ae08745Sheppo 	D2(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) head=0x%llx, tail=0x%llx\n",
8961ae08745Sheppo 	    ldcp->id, ldcp->tx_head, ldcp->tx_tail);
8971ae08745Sheppo 
8981ae08745Sheppo 	*tail = ldcp->tx_tail;
8991ae08745Sheppo 	return (0);
9001ae08745Sheppo }
9011ae08745Sheppo 
9021ae08745Sheppo /*
9031ae08745Sheppo  * Set the tail pointer. If HV returns EWOULDBLOCK, it will back off
9040a55fbb7Slm66018  * and retry ldc_max_retries times before returning an error.
9051ae08745Sheppo  * Returns 0, EWOULDBLOCK or EIO
9061ae08745Sheppo  */
9071ae08745Sheppo static int
i_ldc_set_tx_tail(ldc_chan_t * ldcp,uint64_t tail)9081ae08745Sheppo i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail)
9091ae08745Sheppo {
9101ae08745Sheppo 	int		rv, retval = EWOULDBLOCK;
9110a55fbb7Slm66018 	int		retries;
9121ae08745Sheppo 
913d10e4ef2Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
9140a55fbb7Slm66018 	for (retries = 0; retries < ldc_max_retries; retries++) {
9151ae08745Sheppo 
9161ae08745Sheppo 		if ((rv = hv_ldc_tx_set_qtail(ldcp->id, tail)) == 0) {
9171ae08745Sheppo 			retval = 0;
9181ae08745Sheppo 			break;
9191ae08745Sheppo 		}
9201ae08745Sheppo 		if (rv != H_EWOULDBLOCK) {
9211ae08745Sheppo 			DWARN(ldcp->id, "i_ldc_set_tx_tail: (0x%llx) set "
9221ae08745Sheppo 			    "qtail=0x%llx failed, rv=%d\n", ldcp->id, tail, rv);
9231ae08745Sheppo 			retval = EIO;
9241ae08745Sheppo 			break;
9251ae08745Sheppo 		}
9261ae08745Sheppo 
9270a55fbb7Slm66018 		/* wait for ldc_delay usecs */
9280a55fbb7Slm66018 		drv_usecwait(ldc_delay);
9291ae08745Sheppo 	}
9301ae08745Sheppo 	return (retval);
9311ae08745Sheppo }
9321ae08745Sheppo 
9331ae08745Sheppo /*
93458283286Sha137994  * Copy a data packet from the HV receive queue to the data queue.
93558283286Sha137994  * Caller must ensure that the data queue is not already full.
93658283286Sha137994  *
93758283286Sha137994  * The *head argument represents the current head pointer for the HV
93858283286Sha137994  * receive queue. After copying a packet from the HV receive queue,
93958283286Sha137994  * the *head pointer will be updated. This allows the caller to update
94058283286Sha137994  * the head pointer in HV using the returned *head value.
94158283286Sha137994  */
94258283286Sha137994 void
i_ldc_rxdq_copy(ldc_chan_t * ldcp,uint64_t * head)94358283286Sha137994 i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head)
94458283286Sha137994 {
94558283286Sha137994 	uint64_t	q_size, dq_size;
94658283286Sha137994 
94758283286Sha137994 	ASSERT(MUTEX_HELD(&ldcp->lock));
94858283286Sha137994 
94958283286Sha137994 	q_size  = ldcp->rx_q_entries << LDC_PACKET_SHIFT;
95058283286Sha137994 	dq_size = ldcp->rx_dq_entries << LDC_PACKET_SHIFT;
95158283286Sha137994 
95258283286Sha137994 	ASSERT(Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail,
95358283286Sha137994 	    dq_size) >= LDC_PACKET_SIZE);
95458283286Sha137994 
95558283286Sha137994 	bcopy((void *)(ldcp->rx_q_va + *head),
95658283286Sha137994 	    (void *)(ldcp->rx_dq_va + ldcp->rx_dq_tail), LDC_PACKET_SIZE);
95758283286Sha137994 	TRACE_RXDQ_COPY(ldcp, LDC_PACKET_SIZE);
95858283286Sha137994 
95958283286Sha137994 	/* Update rx head */
96058283286Sha137994 	*head = (*head + LDC_PACKET_SIZE) % q_size;
96158283286Sha137994 
96258283286Sha137994 	/* Update dq tail */
96358283286Sha137994 	ldcp->rx_dq_tail = (ldcp->rx_dq_tail + LDC_PACKET_SIZE) % dq_size;
96458283286Sha137994 }
96558283286Sha137994 
96658283286Sha137994 /*
96758283286Sha137994  * Update the Rx data queue head pointer
96858283286Sha137994  */
96958283286Sha137994 static int
i_ldc_set_rxdq_head(ldc_chan_t * ldcp,uint64_t head)97058283286Sha137994 i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head)
97158283286Sha137994 {
97258283286Sha137994 	ldcp->rx_dq_head = head;
97358283286Sha137994 	return (0);
97458283286Sha137994 }
97558283286Sha137994 
97658283286Sha137994 /*
97758283286Sha137994  * Get the Rx data queue head and tail pointers
97858283286Sha137994  */
97958283286Sha137994 static uint64_t
i_ldc_dq_rx_get_state(ldc_chan_t * ldcp,uint64_t * head,uint64_t * tail,uint64_t * link_state)98058283286Sha137994 i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail,
98158283286Sha137994     uint64_t *link_state)
98258283286Sha137994 {
98358283286Sha137994 	_NOTE(ARGUNUSED(link_state))
98458283286Sha137994 	*head = ldcp->rx_dq_head;
98558283286Sha137994 	*tail = ldcp->rx_dq_tail;
98658283286Sha137994 	return (0);
98758283286Sha137994 }
98858283286Sha137994 
98958283286Sha137994 /*
99058283286Sha137994  * Wrapper for the Rx HV queue set head function. Giving the
99158283286Sha137994  * data queue and HV queue set head functions the same type.
99258283286Sha137994  */
99358283286Sha137994 static uint64_t
i_ldc_hvq_rx_get_state(ldc_chan_t * ldcp,uint64_t * head,uint64_t * tail,uint64_t * link_state)99458283286Sha137994 i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail,
99558283286Sha137994     uint64_t *link_state)
99658283286Sha137994 {
99758283286Sha137994 	return (i_ldc_h2v_error(hv_ldc_rx_get_state(ldcp->id, head, tail,
99858283286Sha137994 	    link_state)));
99958283286Sha137994 }
100058283286Sha137994 
100158283286Sha137994 /*
100258283286Sha137994  * LDC receive interrupt handler
100358283286Sha137994  *    triggered for channel with data pending to read
100458283286Sha137994  *    i.e. Rx queue content changes
100558283286Sha137994  */
100658283286Sha137994 static uint_t
i_ldc_rx_hdlr(caddr_t arg1,caddr_t arg2)100758283286Sha137994 i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2)
100858283286Sha137994 {
100958283286Sha137994 	_NOTE(ARGUNUSED(arg2))
101058283286Sha137994 
101158283286Sha137994 	ldc_chan_t	*ldcp;
101258283286Sha137994 	boolean_t	notify;
101358283286Sha137994 	uint64_t	event;
101412f80fa6Sha137994 	int		rv, status;
101558283286Sha137994 
101658283286Sha137994 	/* Get the channel for which interrupt was received */
101758283286Sha137994 	if (arg1 == NULL) {
101858283286Sha137994 		cmn_err(CE_WARN, "i_ldc_rx_hdlr: invalid arg\n");
101958283286Sha137994 		return (DDI_INTR_UNCLAIMED);
102058283286Sha137994 	}
102158283286Sha137994 
102258283286Sha137994 	ldcp = (ldc_chan_t *)arg1;
102358283286Sha137994 
102458283286Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
102558283286Sha137994 	    ldcp->id, ldcp);
102658283286Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (%llx) USR%lx/TS%lx/HS%lx, LSTATE=%lx\n",
102758283286Sha137994 	    ldcp->id, ldcp->status, ldcp->tstate, ldcp->hstate,
102858283286Sha137994 	    ldcp->link_state);
102958283286Sha137994 
103058283286Sha137994 	/* Lock channel */
103158283286Sha137994 	mutex_enter(&ldcp->lock);
103258283286Sha137994 
103358283286Sha137994 	/* Mark the interrupt as being actively handled */
103458283286Sha137994 	ldcp->rx_intr_state = LDC_INTR_ACTIVE;
103558283286Sha137994 
103612f80fa6Sha137994 	status = i_ldc_rx_process_hvq(ldcp, &notify, &event);
103758283286Sha137994 
103820ae46ebSha137994 	if (ldcp->mode != LDC_MODE_RELIABLE) {
103958283286Sha137994 		/*
104058283286Sha137994 		 * If there are no data packets on the queue, clear
104158283286Sha137994 		 * the interrupt. Otherwise, the ldc_read will clear
104258283286Sha137994 		 * interrupts after draining the queue. To indicate the
104358283286Sha137994 		 * interrupt has not yet been cleared, it is marked
104458283286Sha137994 		 * as pending.
104558283286Sha137994 		 */
104658283286Sha137994 		if ((event & LDC_EVT_READ) == 0) {
104758283286Sha137994 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
104858283286Sha137994 		} else {
104958283286Sha137994 			ldcp->rx_intr_state = LDC_INTR_PEND;
105058283286Sha137994 		}
105158283286Sha137994 	}
105258283286Sha137994 
105358283286Sha137994 	/* if callbacks are disabled, do not notify */
105458283286Sha137994 	if (notify && ldcp->cb_enabled) {
105558283286Sha137994 		ldcp->cb_inprogress = B_TRUE;
105658283286Sha137994 		mutex_exit(&ldcp->lock);
105758283286Sha137994 		rv = ldcp->cb(event, ldcp->cb_arg);
105858283286Sha137994 		if (rv) {
105958283286Sha137994 			DWARN(ldcp->id,
106058283286Sha137994 			    "i_ldc_rx_hdlr: (0x%llx) callback failure",
106158283286Sha137994 			    ldcp->id);
106258283286Sha137994 		}
106358283286Sha137994 		mutex_enter(&ldcp->lock);
106458283286Sha137994 		ldcp->cb_inprogress = B_FALSE;
106558283286Sha137994 	}
106658283286Sha137994 
106720ae46ebSha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
106812f80fa6Sha137994 		if (status == ENOSPC) {
106958283286Sha137994 			/*
107012f80fa6Sha137994 			 * Here, ENOSPC indicates the secondary data
107112f80fa6Sha137994 			 * queue is full and the Rx queue is non-empty.
107212f80fa6Sha137994 			 * Much like how reliable and raw modes are
107312f80fa6Sha137994 			 * handled above, since the Rx queue is non-
107412f80fa6Sha137994 			 * empty, we mark the interrupt as pending to
107512f80fa6Sha137994 			 * indicate it has not yet been cleared.
107612f80fa6Sha137994 			 */
107712f80fa6Sha137994 			ldcp->rx_intr_state = LDC_INTR_PEND;
107812f80fa6Sha137994 		} else {
107912f80fa6Sha137994 			/*
108012f80fa6Sha137994 			 * We have processed all CTRL packets and
108112f80fa6Sha137994 			 * copied all DATA packets to the secondary
108212f80fa6Sha137994 			 * queue. Clear the interrupt.
108358283286Sha137994 			 */
108458283286Sha137994 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
108558283286Sha137994 		}
108612f80fa6Sha137994 	}
108758283286Sha137994 
108858283286Sha137994 	mutex_exit(&ldcp->lock);
108958283286Sha137994 
109058283286Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) exiting handler", ldcp->id);
109158283286Sha137994 
109258283286Sha137994 	return (DDI_INTR_CLAIMED);
109358283286Sha137994 }
109458283286Sha137994 
109558283286Sha137994 /*
109658283286Sha137994  * Wrapper for the Rx HV queue processing function to be used when
109758283286Sha137994  * checking the Rx HV queue for data packets. Unlike the interrupt
109858283286Sha137994  * handler code flow, the Rx interrupt is not cleared here and
109958283286Sha137994  * callbacks are not made.
110058283286Sha137994  */
110158283286Sha137994 static uint_t
i_ldc_chkq(ldc_chan_t * ldcp)110258283286Sha137994 i_ldc_chkq(ldc_chan_t *ldcp)
110358283286Sha137994 {
110458283286Sha137994 	boolean_t	notify;
110558283286Sha137994 	uint64_t	event;
110658283286Sha137994 
110758283286Sha137994 	return (i_ldc_rx_process_hvq(ldcp, &notify, &event));
110858283286Sha137994 }
110958283286Sha137994 
111058283286Sha137994 /*
11111ae08745Sheppo  * Send a LDC message
11121ae08745Sheppo  */
11131ae08745Sheppo static int
i_ldc_send_pkt(ldc_chan_t * ldcp,uint8_t pkttype,uint8_t subtype,uint8_t ctrlmsg)11141ae08745Sheppo i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
11151ae08745Sheppo     uint8_t ctrlmsg)
11161ae08745Sheppo {
11171ae08745Sheppo 	int		rv;
11181ae08745Sheppo 	ldc_msg_t	*pkt;
11191ae08745Sheppo 	uint64_t	tx_tail;
112022f747efSnarayan 	uint32_t	curr_seqid;
11211ae08745Sheppo 
1122d10e4ef2Snarayan 	/* Obtain Tx lock */
1123d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
1124d10e4ef2Snarayan 
112522f747efSnarayan 	curr_seqid = ldcp->last_msg_snt;
112622f747efSnarayan 
11271ae08745Sheppo 	/* get the current tail for the message */
11281ae08745Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
11291ae08745Sheppo 	if (rv) {
11301ae08745Sheppo 		DWARN(ldcp->id,
11311ae08745Sheppo 		    "i_ldc_send_pkt: (0x%llx) error sending pkt, "
11321ae08745Sheppo 		    "type=0x%x,subtype=0x%x,ctrl=0x%x\n",
11331ae08745Sheppo 		    ldcp->id, pkttype, subtype, ctrlmsg);
1134d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
11351ae08745Sheppo 		return (rv);
11361ae08745Sheppo 	}
11371ae08745Sheppo 
11381ae08745Sheppo 	pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
11391ae08745Sheppo 	ZERO_PKT(pkt);
11401ae08745Sheppo 
11411ae08745Sheppo 	/* Initialize the packet */
11421ae08745Sheppo 	pkt->type = pkttype;
11431ae08745Sheppo 	pkt->stype = subtype;
11441ae08745Sheppo 	pkt->ctrl = ctrlmsg;
11451ae08745Sheppo 
11461ae08745Sheppo 	/* Store ackid/seqid iff it is RELIABLE mode & not a RTS/RTR message */
11471ae08745Sheppo 	if (((ctrlmsg & LDC_CTRL_MASK) != LDC_RTS) &&
11481ae08745Sheppo 	    ((ctrlmsg & LDC_CTRL_MASK) != LDC_RTR)) {
11491ae08745Sheppo 		curr_seqid++;
11501ae08745Sheppo 		if (ldcp->mode != LDC_MODE_RAW) {
11511ae08745Sheppo 			pkt->seqid = curr_seqid;
11521ae08745Sheppo 			pkt->ackid = ldcp->last_msg_rcd;
11531ae08745Sheppo 		}
11541ae08745Sheppo 	}
11551ae08745Sheppo 	DUMP_LDC_PKT(ldcp, "i_ldc_send_pkt", (uint64_t)pkt);
11561ae08745Sheppo 
11571ae08745Sheppo 	/* initiate the send by calling into HV and set the new tail */
11581ae08745Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
11591ae08745Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
11601ae08745Sheppo 
11611ae08745Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
11621ae08745Sheppo 	if (rv) {
11631ae08745Sheppo 		DWARN(ldcp->id,
11641ae08745Sheppo 		    "i_ldc_send_pkt:(0x%llx) error sending pkt, "
11651ae08745Sheppo 		    "type=0x%x,stype=0x%x,ctrl=0x%x\n",
11661ae08745Sheppo 		    ldcp->id, pkttype, subtype, ctrlmsg);
1167d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
11681ae08745Sheppo 		return (EIO);
11691ae08745Sheppo 	}
11701ae08745Sheppo 
11711ae08745Sheppo 	ldcp->last_msg_snt = curr_seqid;
11721ae08745Sheppo 	ldcp->tx_tail = tx_tail;
11731ae08745Sheppo 
1174d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
11751ae08745Sheppo 	return (0);
11761ae08745Sheppo }
11771ae08745Sheppo 
11781ae08745Sheppo /*
11791ae08745Sheppo  * Checks if packet was received in right order
1180e1ebb9ecSlm66018  * in the case of a reliable link.
11811ae08745Sheppo  * Returns 0 if in order, else EIO
11821ae08745Sheppo  */
11831ae08745Sheppo static int
i_ldc_check_seqid(ldc_chan_t * ldcp,ldc_msg_t * msg)11841ae08745Sheppo i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *msg)
11851ae08745Sheppo {
11861ae08745Sheppo 	/* No seqid checking for RAW mode */
11871ae08745Sheppo 	if (ldcp->mode == LDC_MODE_RAW)
11881ae08745Sheppo 		return (0);
11891ae08745Sheppo 
11901ae08745Sheppo 	/* No seqid checking for version, RTS, RTR message */
11911ae08745Sheppo 	if (msg->ctrl == LDC_VER ||
11921ae08745Sheppo 	    msg->ctrl == LDC_RTS ||
11931ae08745Sheppo 	    msg->ctrl == LDC_RTR)
11941ae08745Sheppo 		return (0);
11951ae08745Sheppo 
11961ae08745Sheppo 	/* Initial seqid to use is sent in RTS/RTR and saved in last_msg_rcd */
11971ae08745Sheppo 	if (msg->seqid != (ldcp->last_msg_rcd + 1)) {
11981ae08745Sheppo 		DWARN(ldcp->id,
11991ae08745Sheppo 		    "i_ldc_check_seqid: (0x%llx) out-of-order pkt, got 0x%x, "
12001ae08745Sheppo 		    "expecting 0x%x\n", ldcp->id, msg->seqid,
12011ae08745Sheppo 		    (ldcp->last_msg_rcd + 1));
12021ae08745Sheppo 		return (EIO);
12031ae08745Sheppo 	}
12041ae08745Sheppo 
120583d3bc6fSnarayan #ifdef DEBUG
120683d3bc6fSnarayan 	if (LDC_INJECT_PKTLOSS(ldcp)) {
120783d3bc6fSnarayan 		DWARN(ldcp->id,
120883d3bc6fSnarayan 		    "i_ldc_check_seqid: (0x%llx) inject pkt loss\n", ldcp->id);
120983d3bc6fSnarayan 		return (EIO);
121083d3bc6fSnarayan 	}
121183d3bc6fSnarayan #endif
121283d3bc6fSnarayan 
12131ae08745Sheppo 	return (0);
12141ae08745Sheppo }
12151ae08745Sheppo 
12161ae08745Sheppo 
12171ae08745Sheppo /*
12181ae08745Sheppo  * Process an incoming version ctrl message
12191ae08745Sheppo  */
12201ae08745Sheppo static int
i_ldc_process_VER(ldc_chan_t * ldcp,ldc_msg_t * msg)12211ae08745Sheppo i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg)
12221ae08745Sheppo {
12231ae08745Sheppo 	int		rv = 0, idx = ldcp->next_vidx;
12241ae08745Sheppo 	ldc_msg_t	*pkt;
12251ae08745Sheppo 	uint64_t	tx_tail;
12261ae08745Sheppo 	ldc_ver_t	*rcvd_ver;
12271ae08745Sheppo 
12281ae08745Sheppo 	/* get the received version */
12291ae08745Sheppo 	rcvd_ver = (ldc_ver_t *)((uint64_t)msg + LDC_PAYLOAD_VER_OFF);
12301ae08745Sheppo 
12311ae08745Sheppo 	D2(ldcp->id, "i_ldc_process_VER: (0x%llx) received VER v%u.%u\n",
12321ae08745Sheppo 	    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
12331ae08745Sheppo 
1234d10e4ef2Snarayan 	/* Obtain Tx lock */
1235d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
1236d10e4ef2Snarayan 
12371ae08745Sheppo 	switch (msg->stype) {
12381ae08745Sheppo 	case LDC_INFO:
12391ae08745Sheppo 
12403af08d82Slm66018 		if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) {
12413af08d82Slm66018 			(void) i_ldc_txq_reconf(ldcp);
12423af08d82Slm66018 			i_ldc_reset_state(ldcp);
12433af08d82Slm66018 			mutex_exit(&ldcp->tx_lock);
12443af08d82Slm66018 			return (EAGAIN);
12453af08d82Slm66018 		}
12463af08d82Slm66018 
12471ae08745Sheppo 		/* get the current tail and pkt for the response */
12481ae08745Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
12491ae08745Sheppo 		if (rv != 0) {
12501ae08745Sheppo 			DWARN(ldcp->id,
12511ae08745Sheppo 			    "i_ldc_process_VER: (0x%llx) err sending "
12521ae08745Sheppo 			    "version ACK/NACK\n", ldcp->id);
12533af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1254d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
12551ae08745Sheppo 			return (ECONNRESET);
12561ae08745Sheppo 		}
12571ae08745Sheppo 
12581ae08745Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
12591ae08745Sheppo 		ZERO_PKT(pkt);
12601ae08745Sheppo 
12611ae08745Sheppo 		/* initialize the packet */
12621ae08745Sheppo 		pkt->type = LDC_CTRL;
12631ae08745Sheppo 		pkt->ctrl = LDC_VER;
12641ae08745Sheppo 
12651ae08745Sheppo 		for (;;) {
12661ae08745Sheppo 
12671ae08745Sheppo 			D1(ldcp->id, "i_ldc_process_VER: got %u.%u chk %u.%u\n",
12681ae08745Sheppo 			    rcvd_ver->major, rcvd_ver->minor,
12691ae08745Sheppo 			    ldc_versions[idx].major, ldc_versions[idx].minor);
12701ae08745Sheppo 
12711ae08745Sheppo 			if (rcvd_ver->major == ldc_versions[idx].major) {
12721ae08745Sheppo 				/* major version match - ACK version */
12731ae08745Sheppo 				pkt->stype = LDC_ACK;
12741ae08745Sheppo 
12751ae08745Sheppo 				/*
12761ae08745Sheppo 				 * lower minor version to the one this endpt
12771ae08745Sheppo 				 * supports, if necessary
12781ae08745Sheppo 				 */
12791ae08745Sheppo 				if (rcvd_ver->minor > ldc_versions[idx].minor)
12801ae08745Sheppo 					rcvd_ver->minor =
12811ae08745Sheppo 					    ldc_versions[idx].minor;
12821ae08745Sheppo 				bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver));
12831ae08745Sheppo 
12841ae08745Sheppo 				break;
12851ae08745Sheppo 			}
12861ae08745Sheppo 
12871ae08745Sheppo 			if (rcvd_ver->major > ldc_versions[idx].major) {
12881ae08745Sheppo 
12891ae08745Sheppo 				D1(ldcp->id, "i_ldc_process_VER: using next"
12901ae08745Sheppo 				    " lower idx=%d, v%u.%u\n", idx,
12911ae08745Sheppo 				    ldc_versions[idx].major,
12921ae08745Sheppo 				    ldc_versions[idx].minor);
12931ae08745Sheppo 
12941ae08745Sheppo 				/* nack with next lower version */
12951ae08745Sheppo 				pkt->stype = LDC_NACK;
12961ae08745Sheppo 				bcopy(&ldc_versions[idx], pkt->udata,
12971ae08745Sheppo 				    sizeof (ldc_versions[idx]));
12981ae08745Sheppo 				ldcp->next_vidx = idx;
12991ae08745Sheppo 				break;
13001ae08745Sheppo 			}
13011ae08745Sheppo 
13021ae08745Sheppo 			/* next major version */
13031ae08745Sheppo 			idx++;
13041ae08745Sheppo 
13051ae08745Sheppo 			D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx);
13061ae08745Sheppo 
13071ae08745Sheppo 			if (idx == LDC_NUM_VERS) {
13081ae08745Sheppo 				/* no version match - send NACK */
13091ae08745Sheppo 				pkt->stype = LDC_NACK;
13101ae08745Sheppo 				bzero(pkt->udata, sizeof (ldc_ver_t));
13111ae08745Sheppo 				ldcp->next_vidx = 0;
13121ae08745Sheppo 				break;
13131ae08745Sheppo 			}
13141ae08745Sheppo 		}
13151ae08745Sheppo 
13161ae08745Sheppo 		/* initiate the send by calling into HV and set the new tail */
13171ae08745Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
13181ae08745Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
13191ae08745Sheppo 
13201ae08745Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
13211ae08745Sheppo 		if (rv == 0) {
13221ae08745Sheppo 			ldcp->tx_tail = tx_tail;
13231ae08745Sheppo 			if (pkt->stype == LDC_ACK) {
13241ae08745Sheppo 				D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent"
13251ae08745Sheppo 				    " version ACK\n", ldcp->id);
13261ae08745Sheppo 				/* Save the ACK'd version */
13271ae08745Sheppo 				ldcp->version.major = rcvd_ver->major;
13281ae08745Sheppo 				ldcp->version.minor = rcvd_ver->minor;
13290a55fbb7Slm66018 				ldcp->hstate |= TS_RCVD_VER;
13301ae08745Sheppo 				ldcp->tstate |= TS_VER_DONE;
133183d3bc6fSnarayan 				D1(DBG_ALL_LDCS,
13323af08d82Slm66018 				    "(0x%llx) Sent ACK, "
13333af08d82Slm66018 				    "Agreed on version v%u.%u\n",
13341ae08745Sheppo 				    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
13351ae08745Sheppo 			}
13361ae08745Sheppo 		} else {
13371ae08745Sheppo 			DWARN(ldcp->id,
13381ae08745Sheppo 			    "i_ldc_process_VER: (0x%llx) error sending "
13391ae08745Sheppo 			    "ACK/NACK\n", ldcp->id);
13403af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1341d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
13421ae08745Sheppo 			return (ECONNRESET);
13431ae08745Sheppo 		}
13441ae08745Sheppo 
13451ae08745Sheppo 		break;
13461ae08745Sheppo 
13471ae08745Sheppo 	case LDC_ACK:
13483af08d82Slm66018 		if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) {
13493af08d82Slm66018 			if (ldcp->version.major != rcvd_ver->major ||
13503af08d82Slm66018 			    ldcp->version.minor != rcvd_ver->minor) {
13513af08d82Slm66018 
13523af08d82Slm66018 				/* mismatched version - reset connection */
13533af08d82Slm66018 				DWARN(ldcp->id,
13543af08d82Slm66018 				    "i_ldc_process_VER: (0x%llx) recvd"
13553af08d82Slm66018 				    " ACK ver != sent ACK ver\n", ldcp->id);
13563af08d82Slm66018 				i_ldc_reset(ldcp, B_TRUE);
13573af08d82Slm66018 				mutex_exit(&ldcp->tx_lock);
13583af08d82Slm66018 				return (ECONNRESET);
13593af08d82Slm66018 			}
13603af08d82Slm66018 		} else {
13611ae08745Sheppo 			/* SUCCESS - we have agreed on a version */
13621ae08745Sheppo 			ldcp->version.major = rcvd_ver->major;
13631ae08745Sheppo 			ldcp->version.minor = rcvd_ver->minor;
13641ae08745Sheppo 			ldcp->tstate |= TS_VER_DONE;
13653af08d82Slm66018 		}
13661ae08745Sheppo 
1367cb112a14Slm66018 		D1(ldcp->id, "(0x%llx) Got ACK, Agreed on version v%u.%u\n",
13681ae08745Sheppo 		    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
13691ae08745Sheppo 
13701ae08745Sheppo 		/* initiate RTS-RTR-RDX handshake */
13711ae08745Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
13721ae08745Sheppo 		if (rv) {
13731ae08745Sheppo 			DWARN(ldcp->id,
13741ae08745Sheppo 		    "i_ldc_process_VER: (0x%llx) cannot send RTS\n",
13751ae08745Sheppo 			    ldcp->id);
13763af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1377d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
13781ae08745Sheppo 			return (ECONNRESET);
13791ae08745Sheppo 		}
13801ae08745Sheppo 
13811ae08745Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
13821ae08745Sheppo 		ZERO_PKT(pkt);
13831ae08745Sheppo 
13841ae08745Sheppo 		pkt->type = LDC_CTRL;
13851ae08745Sheppo 		pkt->stype = LDC_INFO;
13861ae08745Sheppo 		pkt->ctrl = LDC_RTS;
13871ae08745Sheppo 		pkt->env = ldcp->mode;
13881ae08745Sheppo 		if (ldcp->mode != LDC_MODE_RAW)
13891ae08745Sheppo 			pkt->seqid = LDC_INIT_SEQID;
13901ae08745Sheppo 
13911ae08745Sheppo 		ldcp->last_msg_rcd = LDC_INIT_SEQID;
13921ae08745Sheppo 
13931ae08745Sheppo 		DUMP_LDC_PKT(ldcp, "i_ldc_process_VER snd rts", (uint64_t)pkt);
13941ae08745Sheppo 
13951ae08745Sheppo 		/* initiate the send by calling into HV and set the new tail */
13961ae08745Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
13971ae08745Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
13981ae08745Sheppo 
13991ae08745Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
14001ae08745Sheppo 		if (rv) {
14011ae08745Sheppo 			D2(ldcp->id,
14021ae08745Sheppo 			    "i_ldc_process_VER: (0x%llx) no listener\n",
14031ae08745Sheppo 			    ldcp->id);
14043af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1405d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
14061ae08745Sheppo 			return (ECONNRESET);
14071ae08745Sheppo 		}
14081ae08745Sheppo 
14091ae08745Sheppo 		ldcp->tx_tail = tx_tail;
14101ae08745Sheppo 		ldcp->hstate |= TS_SENT_RTS;
14111ae08745Sheppo 
14121ae08745Sheppo 		break;
14131ae08745Sheppo 
14141ae08745Sheppo 	case LDC_NACK:
14151ae08745Sheppo 		/* check if version in NACK is zero */
14161ae08745Sheppo 		if (rcvd_ver->major == 0 && rcvd_ver->minor == 0) {
14171ae08745Sheppo 			/* version handshake failure */
14181ae08745Sheppo 			DWARN(DBG_ALL_LDCS,
14191ae08745Sheppo 			    "i_ldc_process_VER: (0x%llx) no version match\n",
14201ae08745Sheppo 			    ldcp->id);
14213af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1422d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
14231ae08745Sheppo 			return (ECONNRESET);
14241ae08745Sheppo 		}
14251ae08745Sheppo 
14261ae08745Sheppo 		/* get the current tail and pkt for the response */
14271ae08745Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
14281ae08745Sheppo 		if (rv != 0) {
14291ae08745Sheppo 			cmn_err(CE_NOTE,
14301ae08745Sheppo 			    "i_ldc_process_VER: (0x%lx) err sending "
14311ae08745Sheppo 			    "version ACK/NACK\n", ldcp->id);
14323af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1433d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
14341ae08745Sheppo 			return (ECONNRESET);
14351ae08745Sheppo 		}
14361ae08745Sheppo 
14371ae08745Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
14381ae08745Sheppo 		ZERO_PKT(pkt);
14391ae08745Sheppo 
14401ae08745Sheppo 		/* initialize the packet */
14411ae08745Sheppo 		pkt->type = LDC_CTRL;
14421ae08745Sheppo 		pkt->ctrl = LDC_VER;
14431ae08745Sheppo 		pkt->stype = LDC_INFO;
14441ae08745Sheppo 
14451ae08745Sheppo 		/* check ver in NACK msg has a match */
14461ae08745Sheppo 		for (;;) {
14471ae08745Sheppo 			if (rcvd_ver->major == ldc_versions[idx].major) {
14481ae08745Sheppo 				/*
14491ae08745Sheppo 				 * major version match - resubmit request
14501ae08745Sheppo 				 * if lower minor version to the one this endpt
14511ae08745Sheppo 				 * supports, if necessary
14521ae08745Sheppo 				 */
14531ae08745Sheppo 				if (rcvd_ver->minor > ldc_versions[idx].minor)
14541ae08745Sheppo 					rcvd_ver->minor =
14551ae08745Sheppo 					    ldc_versions[idx].minor;
14561ae08745Sheppo 				bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver));
14571ae08745Sheppo 				break;
14581ae08745Sheppo 			}
14591ae08745Sheppo 
14601ae08745Sheppo 			if (rcvd_ver->major > ldc_versions[idx].major) {
14611ae08745Sheppo 
14621ae08745Sheppo 				D1(ldcp->id, "i_ldc_process_VER: using next"
14631ae08745Sheppo 				    " lower idx=%d, v%u.%u\n", idx,
14641ae08745Sheppo 				    ldc_versions[idx].major,
14651ae08745Sheppo 				    ldc_versions[idx].minor);
14661ae08745Sheppo 
14671ae08745Sheppo 				/* send next lower version */
14681ae08745Sheppo 				bcopy(&ldc_versions[idx], pkt->udata,
14691ae08745Sheppo 				    sizeof (ldc_versions[idx]));
14701ae08745Sheppo 				ldcp->next_vidx = idx;
14711ae08745Sheppo 				break;
14721ae08745Sheppo 			}
14731ae08745Sheppo 
14741ae08745Sheppo 			/* next version */
14751ae08745Sheppo 			idx++;
14761ae08745Sheppo 
14771ae08745Sheppo 			D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx);
14781ae08745Sheppo 
14791ae08745Sheppo 			if (idx == LDC_NUM_VERS) {
14801ae08745Sheppo 				/* no version match - terminate */
14811ae08745Sheppo 				ldcp->next_vidx = 0;
1482d10e4ef2Snarayan 				mutex_exit(&ldcp->tx_lock);
14831ae08745Sheppo 				return (ECONNRESET);
14841ae08745Sheppo 			}
14851ae08745Sheppo 		}
14861ae08745Sheppo 
14871ae08745Sheppo 		/* initiate the send by calling into HV and set the new tail */
14881ae08745Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
14891ae08745Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
14901ae08745Sheppo 
14911ae08745Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
14921ae08745Sheppo 		if (rv == 0) {
14931ae08745Sheppo 			D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent version"
14941ae08745Sheppo 			    "INFO v%u.%u\n", ldcp->id, ldc_versions[idx].major,
14951ae08745Sheppo 			    ldc_versions[idx].minor);
14961ae08745Sheppo 			ldcp->tx_tail = tx_tail;
14971ae08745Sheppo 		} else {
14981ae08745Sheppo 			cmn_err(CE_NOTE,
14991ae08745Sheppo 			    "i_ldc_process_VER: (0x%lx) error sending version"
15001ae08745Sheppo 			    "INFO\n", ldcp->id);
15013af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1502d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
15031ae08745Sheppo 			return (ECONNRESET);
15041ae08745Sheppo 		}
15051ae08745Sheppo 
15061ae08745Sheppo 		break;
15071ae08745Sheppo 	}
15081ae08745Sheppo 
1509d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
15101ae08745Sheppo 	return (rv);
15111ae08745Sheppo }
15121ae08745Sheppo 
15131ae08745Sheppo 
15141ae08745Sheppo /*
15151ae08745Sheppo  * Process an incoming RTS ctrl message
15161ae08745Sheppo  */
15171ae08745Sheppo static int
i_ldc_process_RTS(ldc_chan_t * ldcp,ldc_msg_t * msg)15181ae08745Sheppo i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg)
15191ae08745Sheppo {
15201ae08745Sheppo 	int		rv = 0;
15211ae08745Sheppo 	ldc_msg_t	*pkt;
15221ae08745Sheppo 	uint64_t	tx_tail;
15231ae08745Sheppo 	boolean_t	sent_NACK = B_FALSE;
15241ae08745Sheppo 
15251ae08745Sheppo 	D2(ldcp->id, "i_ldc_process_RTS: (0x%llx) received RTS\n", ldcp->id);
15261ae08745Sheppo 
15271ae08745Sheppo 	switch (msg->stype) {
15281ae08745Sheppo 	case LDC_NACK:
15291ae08745Sheppo 		DWARN(ldcp->id,
15301ae08745Sheppo 		    "i_ldc_process_RTS: (0x%llx) RTS NACK received\n",
15311ae08745Sheppo 		    ldcp->id);
15321ae08745Sheppo 
15331ae08745Sheppo 		/* Reset the channel -- as we cannot continue */
1534d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
15353af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1536d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
15371ae08745Sheppo 		rv = ECONNRESET;
15381ae08745Sheppo 		break;
15391ae08745Sheppo 
15401ae08745Sheppo 	case LDC_INFO:
15411ae08745Sheppo 
15421ae08745Sheppo 		/* check mode */
15431ae08745Sheppo 		if (ldcp->mode != (ldc_mode_t)msg->env) {
15441ae08745Sheppo 			cmn_err(CE_NOTE,
15451ae08745Sheppo 			    "i_ldc_process_RTS: (0x%lx) mode mismatch\n",
15461ae08745Sheppo 			    ldcp->id);
15471ae08745Sheppo 			/*
15481ae08745Sheppo 			 * send NACK in response to MODE message
15491ae08745Sheppo 			 * get the current tail for the response
15501ae08745Sheppo 			 */
15511ae08745Sheppo 			rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTS);
15521ae08745Sheppo 			if (rv) {
15531ae08745Sheppo 				/* if cannot send NACK - reset channel */
1554d10e4ef2Snarayan 				mutex_enter(&ldcp->tx_lock);
15553af08d82Slm66018 				i_ldc_reset(ldcp, B_TRUE);
1556d10e4ef2Snarayan 				mutex_exit(&ldcp->tx_lock);
15571ae08745Sheppo 				rv = ECONNRESET;
15581ae08745Sheppo 				break;
15591ae08745Sheppo 			}
15601ae08745Sheppo 			sent_NACK = B_TRUE;
15611ae08745Sheppo 		}
15621ae08745Sheppo 		break;
15631ae08745Sheppo 	default:
15641ae08745Sheppo 		DWARN(ldcp->id, "i_ldc_process_RTS: (0x%llx) unexp ACK\n",
15651ae08745Sheppo 		    ldcp->id);
1566d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
15673af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1568d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
15691ae08745Sheppo 		rv = ECONNRESET;
15701ae08745Sheppo 		break;
15711ae08745Sheppo 	}
15721ae08745Sheppo 
15731ae08745Sheppo 	/*
15741ae08745Sheppo 	 * If either the connection was reset (when rv != 0) or
15751ae08745Sheppo 	 * a NACK was sent, we return. In the case of a NACK
15761ae08745Sheppo 	 * we dont want to consume the packet that came in but
15771ae08745Sheppo 	 * not record that we received the RTS
15781ae08745Sheppo 	 */
15791ae08745Sheppo 	if (rv || sent_NACK)
15801ae08745Sheppo 		return (rv);
15811ae08745Sheppo 
15821ae08745Sheppo 	/* record RTS received */
15831ae08745Sheppo 	ldcp->hstate |= TS_RCVD_RTS;
15841ae08745Sheppo 
15851ae08745Sheppo 	/* store initial SEQID info */
15861ae08745Sheppo 	ldcp->last_msg_snt = msg->seqid;
15871ae08745Sheppo 
1588d10e4ef2Snarayan 	/* Obtain Tx lock */
1589d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
1590d10e4ef2Snarayan 
15911ae08745Sheppo 	/* get the current tail for the response */
15921ae08745Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
15931ae08745Sheppo 	if (rv != 0) {
15941ae08745Sheppo 		cmn_err(CE_NOTE,
15951ae08745Sheppo 		    "i_ldc_process_RTS: (0x%lx) err sending RTR\n",
15961ae08745Sheppo 		    ldcp->id);
15973af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1598d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
15991ae08745Sheppo 		return (ECONNRESET);
16001ae08745Sheppo 	}
16011ae08745Sheppo 
16021ae08745Sheppo 	pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
16031ae08745Sheppo 	ZERO_PKT(pkt);
16041ae08745Sheppo 
16051ae08745Sheppo 	/* initialize the packet */
16061ae08745Sheppo 	pkt->type = LDC_CTRL;
16071ae08745Sheppo 	pkt->stype = LDC_INFO;
16081ae08745Sheppo 	pkt->ctrl = LDC_RTR;
16091ae08745Sheppo 	pkt->env = ldcp->mode;
16101ae08745Sheppo 	if (ldcp->mode != LDC_MODE_RAW)
16111ae08745Sheppo 		pkt->seqid = LDC_INIT_SEQID;
16121ae08745Sheppo 
16131ae08745Sheppo 	ldcp->last_msg_rcd = msg->seqid;
16141ae08745Sheppo 
16151ae08745Sheppo 	/* initiate the send by calling into HV and set the new tail */
16161ae08745Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
16171ae08745Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
16181ae08745Sheppo 
16191ae08745Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
16201ae08745Sheppo 	if (rv == 0) {
16211ae08745Sheppo 		D2(ldcp->id,
16221ae08745Sheppo 		    "i_ldc_process_RTS: (0x%llx) sent RTR\n", ldcp->id);
16231ae08745Sheppo 		DUMP_LDC_PKT(ldcp, "i_ldc_process_RTS sent rtr", (uint64_t)pkt);
16241ae08745Sheppo 
16251ae08745Sheppo 		ldcp->tx_tail = tx_tail;
16261ae08745Sheppo 		ldcp->hstate |= TS_SENT_RTR;
16271ae08745Sheppo 
16281ae08745Sheppo 	} else {
16291ae08745Sheppo 		cmn_err(CE_NOTE,
16301ae08745Sheppo 		    "i_ldc_process_RTS: (0x%lx) error sending RTR\n",
16311ae08745Sheppo 		    ldcp->id);
16323af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1633d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
16341ae08745Sheppo 		return (ECONNRESET);
16351ae08745Sheppo 	}
16361ae08745Sheppo 
1637d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
16381ae08745Sheppo 	return (0);
16391ae08745Sheppo }
16401ae08745Sheppo 
16411ae08745Sheppo /*
16421ae08745Sheppo  * Process an incoming RTR ctrl message
16431ae08745Sheppo  */
16441ae08745Sheppo static int
i_ldc_process_RTR(ldc_chan_t * ldcp,ldc_msg_t * msg)16451ae08745Sheppo i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg)
16461ae08745Sheppo {
16471ae08745Sheppo 	int		rv = 0;
16481ae08745Sheppo 	boolean_t	sent_NACK = B_FALSE;
16491ae08745Sheppo 
16501ae08745Sheppo 	D2(ldcp->id, "i_ldc_process_RTR: (0x%llx) received RTR\n", ldcp->id);
16511ae08745Sheppo 
16521ae08745Sheppo 	switch (msg->stype) {
16531ae08745Sheppo 	case LDC_NACK:
16541ae08745Sheppo 		/* RTR NACK received */
16551ae08745Sheppo 		DWARN(ldcp->id,
16561ae08745Sheppo 		    "i_ldc_process_RTR: (0x%llx) RTR NACK received\n",
16571ae08745Sheppo 		    ldcp->id);
16581ae08745Sheppo 
16591ae08745Sheppo 		/* Reset the channel -- as we cannot continue */
1660d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
16613af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1662d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
16631ae08745Sheppo 		rv = ECONNRESET;
16641ae08745Sheppo 
16651ae08745Sheppo 		break;
16661ae08745Sheppo 
16671ae08745Sheppo 	case LDC_INFO:
16681ae08745Sheppo 
16691ae08745Sheppo 		/* check mode */
16701ae08745Sheppo 		if (ldcp->mode != (ldc_mode_t)msg->env) {
16711ae08745Sheppo 			DWARN(ldcp->id,
1672cb112a14Slm66018 			    "i_ldc_process_RTR: (0x%llx) mode mismatch, "
1673cb112a14Slm66018 			    "expecting 0x%x, got 0x%x\n",
1674cb112a14Slm66018 			    ldcp->id, ldcp->mode, (ldc_mode_t)msg->env);
16751ae08745Sheppo 			/*
16761ae08745Sheppo 			 * send NACK in response to MODE message
16771ae08745Sheppo 			 * get the current tail for the response
16781ae08745Sheppo 			 */
16791ae08745Sheppo 			rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTR);
16801ae08745Sheppo 			if (rv) {
16811ae08745Sheppo 				/* if cannot send NACK - reset channel */
1682d10e4ef2Snarayan 				mutex_enter(&ldcp->tx_lock);
16833af08d82Slm66018 				i_ldc_reset(ldcp, B_TRUE);
1684d10e4ef2Snarayan 				mutex_exit(&ldcp->tx_lock);
16851ae08745Sheppo 				rv = ECONNRESET;
16861ae08745Sheppo 				break;
16871ae08745Sheppo 			}
16881ae08745Sheppo 			sent_NACK = B_TRUE;
16891ae08745Sheppo 		}
16901ae08745Sheppo 		break;
16911ae08745Sheppo 
16921ae08745Sheppo 	default:
16931ae08745Sheppo 		DWARN(ldcp->id, "i_ldc_process_RTR: (0x%llx) unexp ACK\n",
16941ae08745Sheppo 		    ldcp->id);
16951ae08745Sheppo 
16961ae08745Sheppo 		/* Reset the channel -- as we cannot continue */
1697d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
16983af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1699d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
17001ae08745Sheppo 		rv = ECONNRESET;
17011ae08745Sheppo 		break;
17021ae08745Sheppo 	}
17031ae08745Sheppo 
17041ae08745Sheppo 	/*
17051ae08745Sheppo 	 * If either the connection was reset (when rv != 0) or
17061ae08745Sheppo 	 * a NACK was sent, we return. In the case of a NACK
17071ae08745Sheppo 	 * we dont want to consume the packet that came in but
17081ae08745Sheppo 	 * not record that we received the RTR
17091ae08745Sheppo 	 */
17101ae08745Sheppo 	if (rv || sent_NACK)
17111ae08745Sheppo 		return (rv);
17121ae08745Sheppo 
17131ae08745Sheppo 	ldcp->last_msg_snt = msg->seqid;
17141ae08745Sheppo 	ldcp->hstate |= TS_RCVD_RTR;
17151ae08745Sheppo 
17161ae08745Sheppo 	rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_INFO, LDC_RDX);
17171ae08745Sheppo 	if (rv) {
17181ae08745Sheppo 		cmn_err(CE_NOTE,
17191ae08745Sheppo 		    "i_ldc_process_RTR: (0x%lx) cannot send RDX\n",
17201ae08745Sheppo 		    ldcp->id);
1721d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
17223af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1723d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
17241ae08745Sheppo 		return (ECONNRESET);
17251ae08745Sheppo 	}
17261ae08745Sheppo 	D2(ldcp->id,
17271ae08745Sheppo 	    "i_ldc_process_RTR: (0x%llx) sent RDX\n", ldcp->id);
17281ae08745Sheppo 
17291ae08745Sheppo 	ldcp->hstate |= TS_SENT_RDX;
17301ae08745Sheppo 	ldcp->tstate |= TS_HSHAKE_DONE;
17313af08d82Slm66018 	if ((ldcp->tstate & TS_IN_RESET) == 0)
17321ae08745Sheppo 		ldcp->status = LDC_UP;
17331ae08745Sheppo 
1734cb112a14Slm66018 	D1(ldcp->id, "(0x%llx) Handshake Complete\n", ldcp->id);
17351ae08745Sheppo 
17361ae08745Sheppo 	return (0);
17371ae08745Sheppo }
17381ae08745Sheppo 
17391ae08745Sheppo 
17401ae08745Sheppo /*
17411ae08745Sheppo  * Process an incoming RDX ctrl message
17421ae08745Sheppo  */
17431ae08745Sheppo static int
i_ldc_process_RDX(ldc_chan_t * ldcp,ldc_msg_t * msg)17441ae08745Sheppo i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg)
17451ae08745Sheppo {
17461ae08745Sheppo 	int	rv = 0;
17471ae08745Sheppo 
17481ae08745Sheppo 	D2(ldcp->id, "i_ldc_process_RDX: (0x%llx) received RDX\n", ldcp->id);
17491ae08745Sheppo 
17501ae08745Sheppo 	switch (msg->stype) {
17511ae08745Sheppo 	case LDC_NACK:
17521ae08745Sheppo 		/* RDX NACK received */
17531ae08745Sheppo 		DWARN(ldcp->id,
17541ae08745Sheppo 		    "i_ldc_process_RDX: (0x%llx) RDX NACK received\n",
17551ae08745Sheppo 		    ldcp->id);
17561ae08745Sheppo 
17571ae08745Sheppo 		/* Reset the channel -- as we cannot continue */
1758d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
17593af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1760d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
17611ae08745Sheppo 		rv = ECONNRESET;
17621ae08745Sheppo 
17631ae08745Sheppo 		break;
17641ae08745Sheppo 
17651ae08745Sheppo 	case LDC_INFO:
17661ae08745Sheppo 
17671ae08745Sheppo 		/*
17681ae08745Sheppo 		 * if channel is UP and a RDX received after data transmission
17691ae08745Sheppo 		 * has commenced it is an error
17701ae08745Sheppo 		 */
17711ae08745Sheppo 		if ((ldcp->tstate == TS_UP) && (ldcp->hstate & TS_RCVD_RDX)) {
17721ae08745Sheppo 			DWARN(DBG_ALL_LDCS,
17731ae08745Sheppo 			    "i_ldc_process_RDX: (0x%llx) unexpected RDX"
17741ae08745Sheppo 			    " - LDC reset\n", ldcp->id);
1775d10e4ef2Snarayan 			mutex_enter(&ldcp->tx_lock);
17763af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1777d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
17781ae08745Sheppo 			return (ECONNRESET);
17791ae08745Sheppo 		}
17801ae08745Sheppo 
17811ae08745Sheppo 		ldcp->hstate |= TS_RCVD_RDX;
17821ae08745Sheppo 		ldcp->tstate |= TS_HSHAKE_DONE;
17833af08d82Slm66018 		if ((ldcp->tstate & TS_IN_RESET) == 0)
17841ae08745Sheppo 			ldcp->status = LDC_UP;
17851ae08745Sheppo 
17861ae08745Sheppo 		D1(DBG_ALL_LDCS, "(0x%llx) Handshake Complete\n", ldcp->id);
17871ae08745Sheppo 		break;
17881ae08745Sheppo 
17891ae08745Sheppo 	default:
17901ae08745Sheppo 		DWARN(ldcp->id, "i_ldc_process_RDX: (0x%llx) unexp ACK\n",
17911ae08745Sheppo 		    ldcp->id);
17921ae08745Sheppo 
17931ae08745Sheppo 		/* Reset the channel -- as we cannot continue */
1794d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
17953af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1796d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
17971ae08745Sheppo 		rv = ECONNRESET;
17981ae08745Sheppo 		break;
17991ae08745Sheppo 	}
18001ae08745Sheppo 
18011ae08745Sheppo 	return (rv);
18021ae08745Sheppo }
18031ae08745Sheppo 
18041ae08745Sheppo /*
18051ae08745Sheppo  * Process an incoming ACK for a data packet
18061ae08745Sheppo  */
18071ae08745Sheppo static int
i_ldc_process_data_ACK(ldc_chan_t * ldcp,ldc_msg_t * msg)18081ae08745Sheppo i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg)
18091ae08745Sheppo {
18101ae08745Sheppo 	int		rv;
18111ae08745Sheppo 	uint64_t	tx_head;
18121ae08745Sheppo 	ldc_msg_t	*pkt;
18131ae08745Sheppo 
1814d10e4ef2Snarayan 	/* Obtain Tx lock */
1815d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
1816d10e4ef2Snarayan 
18171ae08745Sheppo 	/*
1818d10e4ef2Snarayan 	 * Read the current Tx head and tail
18191ae08745Sheppo 	 */
18201ae08745Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
18211ae08745Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
18221ae08745Sheppo 	if (rv != 0) {
18231ae08745Sheppo 		cmn_err(CE_WARN,
18241ae08745Sheppo 		    "i_ldc_process_data_ACK: (0x%lx) cannot read qptrs\n",
18251ae08745Sheppo 		    ldcp->id);
1826d10e4ef2Snarayan 
1827d10e4ef2Snarayan 		/* Reset the channel -- as we cannot continue */
18283af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
1829d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
1830d10e4ef2Snarayan 		return (ECONNRESET);
18311ae08745Sheppo 	}
18321ae08745Sheppo 
18331ae08745Sheppo 	/*
18341ae08745Sheppo 	 * loop from where the previous ACK location was to the
18351ae08745Sheppo 	 * current head location. This is how far the HV has
18361ae08745Sheppo 	 * actually send pkts. Pkts between head and tail are
18371ae08745Sheppo 	 * yet to be sent by HV.
18381ae08745Sheppo 	 */
18391ae08745Sheppo 	tx_head = ldcp->tx_ackd_head;
18401ae08745Sheppo 	for (;;) {
18411ae08745Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_head);
18421ae08745Sheppo 		tx_head = (tx_head + LDC_PACKET_SIZE) %
18431ae08745Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
18441ae08745Sheppo 
18451ae08745Sheppo 		if (pkt->seqid == msg->ackid) {
18461ae08745Sheppo 			D2(ldcp->id,
18471ae08745Sheppo 			    "i_ldc_process_data_ACK: (0x%llx) found packet\n",
18481ae08745Sheppo 			    ldcp->id);
18491ae08745Sheppo 			ldcp->last_ack_rcd = msg->ackid;
18501ae08745Sheppo 			ldcp->tx_ackd_head = tx_head;
18511ae08745Sheppo 			break;
18521ae08745Sheppo 		}
18531ae08745Sheppo 		if (tx_head == ldcp->tx_head) {
18541ae08745Sheppo 			/* could not find packet */
18551ae08745Sheppo 			DWARN(ldcp->id,
18561ae08745Sheppo 			    "i_ldc_process_data_ACK: (0x%llx) invalid ACKid\n",
18571ae08745Sheppo 			    ldcp->id);
1858d10e4ef2Snarayan 
1859d10e4ef2Snarayan 			/* Reset the channel -- as we cannot continue */
18603af08d82Slm66018 			i_ldc_reset(ldcp, B_TRUE);
1861d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
1862d10e4ef2Snarayan 			return (ECONNRESET);
18631ae08745Sheppo 		}
18641ae08745Sheppo 	}
18651ae08745Sheppo 
1866d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
18671ae08745Sheppo 	return (0);
18681ae08745Sheppo }
18691ae08745Sheppo 
18701ae08745Sheppo /*
18711ae08745Sheppo  * Process incoming control message
18721ae08745Sheppo  * Return 0 - session can continue
18731ae08745Sheppo  *        EAGAIN - reprocess packet - state was changed
18741ae08745Sheppo  *	  ECONNRESET - channel was reset
18751ae08745Sheppo  */
18761ae08745Sheppo static int
i_ldc_ctrlmsg(ldc_chan_t * ldcp,ldc_msg_t * msg)18771ae08745Sheppo i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *msg)
18781ae08745Sheppo {
18791ae08745Sheppo 	int		rv = 0;
18801ae08745Sheppo 
18813af08d82Slm66018 	D1(ldcp->id, "i_ldc_ctrlmsg: (%llx) tstate = %lx, hstate = %lx\n",
18823af08d82Slm66018 	    ldcp->id, ldcp->tstate, ldcp->hstate);
18833af08d82Slm66018 
18843af08d82Slm66018 	switch (ldcp->tstate & ~TS_IN_RESET) {
18851ae08745Sheppo 
18861ae08745Sheppo 	case TS_OPEN:
18871ae08745Sheppo 	case TS_READY:
18881ae08745Sheppo 
18891ae08745Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
18901ae08745Sheppo 		case LDC_VER:
18911ae08745Sheppo 			/* process version message */
18921ae08745Sheppo 			rv = i_ldc_process_VER(ldcp, msg);
18931ae08745Sheppo 			break;
18941ae08745Sheppo 		default:
18951ae08745Sheppo 			DWARN(ldcp->id,
18961ae08745Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
18971ae08745Sheppo 			    "tstate=0x%x\n", ldcp->id,
18981ae08745Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
18991ae08745Sheppo 			break;
19001ae08745Sheppo 		}
19011ae08745Sheppo 
19021ae08745Sheppo 		break;
19031ae08745Sheppo 
19041ae08745Sheppo 	case TS_VREADY:
19051ae08745Sheppo 
19061ae08745Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
19071ae08745Sheppo 		case LDC_VER:
19083af08d82Slm66018 			/* process version message */
19093af08d82Slm66018 			rv = i_ldc_process_VER(ldcp, msg);
19101ae08745Sheppo 			break;
19111ae08745Sheppo 		case LDC_RTS:
19121ae08745Sheppo 			/* process RTS message */
19131ae08745Sheppo 			rv = i_ldc_process_RTS(ldcp, msg);
19141ae08745Sheppo 			break;
19151ae08745Sheppo 		case LDC_RTR:
19161ae08745Sheppo 			/* process RTR message */
19171ae08745Sheppo 			rv = i_ldc_process_RTR(ldcp, msg);
19181ae08745Sheppo 			break;
19191ae08745Sheppo 		case LDC_RDX:
19201ae08745Sheppo 			/* process RDX message */
19211ae08745Sheppo 			rv = i_ldc_process_RDX(ldcp, msg);
19221ae08745Sheppo 			break;
19231ae08745Sheppo 		default:
19241ae08745Sheppo 			DWARN(ldcp->id,
19251ae08745Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
19261ae08745Sheppo 			    "tstate=0x%x\n", ldcp->id,
19271ae08745Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
19281ae08745Sheppo 			break;
19291ae08745Sheppo 		}
19301ae08745Sheppo 
19311ae08745Sheppo 		break;
19321ae08745Sheppo 
19331ae08745Sheppo 	case TS_UP:
19341ae08745Sheppo 
19351ae08745Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
19361ae08745Sheppo 		case LDC_VER:
19371ae08745Sheppo 			DWARN(ldcp->id,
19381ae08745Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexpected VER "
19391ae08745Sheppo 			    "- LDC reset\n", ldcp->id);
19401ae08745Sheppo 			/* peer is redoing version negotiation */
1941d10e4ef2Snarayan 			mutex_enter(&ldcp->tx_lock);
19421ae08745Sheppo 			(void) i_ldc_txq_reconf(ldcp);
19431ae08745Sheppo 			i_ldc_reset_state(ldcp);
1944d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
19451ae08745Sheppo 			rv = EAGAIN;
19461ae08745Sheppo 			break;
19471ae08745Sheppo 
19481ae08745Sheppo 		case LDC_RDX:
19491ae08745Sheppo 			/* process RDX message */
19501ae08745Sheppo 			rv = i_ldc_process_RDX(ldcp, msg);
19511ae08745Sheppo 			break;
19521ae08745Sheppo 
19531ae08745Sheppo 		default:
19541ae08745Sheppo 			DWARN(ldcp->id,
19551ae08745Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
19561ae08745Sheppo 			    "tstate=0x%x\n", ldcp->id,
19571ae08745Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
19581ae08745Sheppo 			break;
19591ae08745Sheppo 		}
19601ae08745Sheppo 	}
19611ae08745Sheppo 
19621ae08745Sheppo 	return (rv);
19631ae08745Sheppo }
19641ae08745Sheppo 
19651ae08745Sheppo /*
19661ae08745Sheppo  * Register channel with the channel nexus
19671ae08745Sheppo  */
19681ae08745Sheppo static int
i_ldc_register_channel(ldc_chan_t * ldcp)19691ae08745Sheppo i_ldc_register_channel(ldc_chan_t *ldcp)
19701ae08745Sheppo {
19711ae08745Sheppo 	int		rv = 0;
19721ae08745Sheppo 	ldc_cnex_t	*cinfo = &ldcssp->cinfo;
19731ae08745Sheppo 
19741ae08745Sheppo 	if (cinfo->dip == NULL) {
19751ae08745Sheppo 		DWARN(ldcp->id,
19761ae08745Sheppo 		    "i_ldc_register_channel: cnex has not registered\n");
19771ae08745Sheppo 		return (EAGAIN);
19781ae08745Sheppo 	}
19791ae08745Sheppo 
19801ae08745Sheppo 	rv = cinfo->reg_chan(cinfo->dip, ldcp->id, ldcp->devclass);
19811ae08745Sheppo 	if (rv) {
19821ae08745Sheppo 		DWARN(ldcp->id,
19831ae08745Sheppo 		    "i_ldc_register_channel: cannot register channel\n");
19841ae08745Sheppo 		return (rv);
19851ae08745Sheppo 	}
19861ae08745Sheppo 
19871ae08745Sheppo 	rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR,
19881ae08745Sheppo 	    i_ldc_tx_hdlr, ldcp, NULL);
19891ae08745Sheppo 	if (rv) {
19901ae08745Sheppo 		DWARN(ldcp->id,
19911ae08745Sheppo 		    "i_ldc_register_channel: cannot add Tx interrupt\n");
19921ae08745Sheppo 		(void) cinfo->unreg_chan(cinfo->dip, ldcp->id);
19931ae08745Sheppo 		return (rv);
19941ae08745Sheppo 	}
19951ae08745Sheppo 
19961ae08745Sheppo 	rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR,
19971ae08745Sheppo 	    i_ldc_rx_hdlr, ldcp, NULL);
19981ae08745Sheppo 	if (rv) {
19991ae08745Sheppo 		DWARN(ldcp->id,
20001ae08745Sheppo 		    "i_ldc_register_channel: cannot add Rx interrupt\n");
20011ae08745Sheppo 		(void) cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
20021ae08745Sheppo 		(void) cinfo->unreg_chan(cinfo->dip, ldcp->id);
20031ae08745Sheppo 		return (rv);
20041ae08745Sheppo 	}
20051ae08745Sheppo 
20061ae08745Sheppo 	ldcp->tstate |= TS_CNEX_RDY;
20071ae08745Sheppo 
20081ae08745Sheppo 	return (0);
20091ae08745Sheppo }
20101ae08745Sheppo 
20111ae08745Sheppo /*
20121ae08745Sheppo  * Unregister a channel with the channel nexus
20131ae08745Sheppo  */
20141ae08745Sheppo static int
i_ldc_unregister_channel(ldc_chan_t * ldcp)20151ae08745Sheppo i_ldc_unregister_channel(ldc_chan_t *ldcp)
20161ae08745Sheppo {
20171ae08745Sheppo 	int		rv = 0;
20181ae08745Sheppo 	ldc_cnex_t	*cinfo = &ldcssp->cinfo;
20191ae08745Sheppo 
20201ae08745Sheppo 	if (cinfo->dip == NULL) {
20211ae08745Sheppo 		DWARN(ldcp->id,
20221ae08745Sheppo 		    "i_ldc_unregister_channel: cnex has not registered\n");
20231ae08745Sheppo 		return (EAGAIN);
20241ae08745Sheppo 	}
20251ae08745Sheppo 
20261ae08745Sheppo 	if (ldcp->tstate & TS_CNEX_RDY) {
20271ae08745Sheppo 
2028d10e4ef2Snarayan 		/* Remove the Rx interrupt */
20291ae08745Sheppo 		rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR);
20301ae08745Sheppo 		if (rv) {
20313af08d82Slm66018 			if (rv != EAGAIN) {
20321ae08745Sheppo 				DWARN(ldcp->id,
20333af08d82Slm66018 				    "i_ldc_unregister_channel: err removing "
20343af08d82Slm66018 				    "Rx intr\n");
2035d10e4ef2Snarayan 				return (rv);
20361ae08745Sheppo 			}
2037d10e4ef2Snarayan 
20383af08d82Slm66018 			/*
20393af08d82Slm66018 			 * If interrupts are pending and handler has
20403af08d82Slm66018 			 * finished running, clear interrupt and try
20413af08d82Slm66018 			 * again
20423af08d82Slm66018 			 */
20433af08d82Slm66018 			if (ldcp->rx_intr_state != LDC_INTR_PEND)
20443af08d82Slm66018 				return (rv);
20453af08d82Slm66018 
20463af08d82Slm66018 			(void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
20473af08d82Slm66018 			rv = cinfo->rem_intr(cinfo->dip, ldcp->id,
20483af08d82Slm66018 			    CNEX_RX_INTR);
20493af08d82Slm66018 			if (rv) {
20503af08d82Slm66018 				DWARN(ldcp->id, "i_ldc_unregister_channel: "
20513af08d82Slm66018 				    "err removing Rx interrupt\n");
20523af08d82Slm66018 				return (rv);
20533af08d82Slm66018 			}
20543af08d82Slm66018 		}
20553af08d82Slm66018 
2056d10e4ef2Snarayan 		/* Remove the Tx interrupt */
20571ae08745Sheppo 		rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
20581ae08745Sheppo 		if (rv) {
20591ae08745Sheppo 			DWARN(ldcp->id,
20601ae08745Sheppo 			    "i_ldc_unregister_channel: err removing Tx intr\n");
2061d10e4ef2Snarayan 			return (rv);
20621ae08745Sheppo 		}
2063d10e4ef2Snarayan 
2064d10e4ef2Snarayan 		/* Unregister the channel */
20651ae08745Sheppo 		rv = cinfo->unreg_chan(ldcssp->cinfo.dip, ldcp->id);
20661ae08745Sheppo 		if (rv) {
20671ae08745Sheppo 			DWARN(ldcp->id,
20681ae08745Sheppo 			    "i_ldc_unregister_channel: cannot unreg channel\n");
2069d10e4ef2Snarayan 			return (rv);
20701ae08745Sheppo 		}
20711ae08745Sheppo 
20721ae08745Sheppo 		ldcp->tstate &= ~TS_CNEX_RDY;
20731ae08745Sheppo 	}
20741ae08745Sheppo 
20751ae08745Sheppo 	return (0);
20761ae08745Sheppo }
20771ae08745Sheppo 
20781ae08745Sheppo 
20791ae08745Sheppo /*
20801ae08745Sheppo  * LDC transmit interrupt handler
20811ae08745Sheppo  *    triggered for chanel up/down/reset events
20821ae08745Sheppo  *    and Tx queue content changes
20831ae08745Sheppo  */
20841ae08745Sheppo static uint_t
i_ldc_tx_hdlr(caddr_t arg1,caddr_t arg2)20851ae08745Sheppo i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2)
20861ae08745Sheppo {
20871ae08745Sheppo 	_NOTE(ARGUNUSED(arg2))
20881ae08745Sheppo 
20891ae08745Sheppo 	int		rv;
20901ae08745Sheppo 	ldc_chan_t	*ldcp;
20911ae08745Sheppo 	boolean_t	notify_client = B_FALSE;
20923af08d82Slm66018 	uint64_t	notify_event = 0, link_state;
20931ae08745Sheppo 
20941ae08745Sheppo 	/* Get the channel for which interrupt was received */
20951ae08745Sheppo 	ASSERT(arg1 != NULL);
20961ae08745Sheppo 	ldcp = (ldc_chan_t *)arg1;
20971ae08745Sheppo 
20981ae08745Sheppo 	D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
20991ae08745Sheppo 	    ldcp->id, ldcp);
21001ae08745Sheppo 
21011ae08745Sheppo 	/* Lock channel */
21021ae08745Sheppo 	mutex_enter(&ldcp->lock);
21031ae08745Sheppo 
2104d10e4ef2Snarayan 	/* Obtain Tx lock */
2105d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
2106d10e4ef2Snarayan 
21074bac2208Snarayan 	/* mark interrupt as pending */
21083af08d82Slm66018 	ldcp->tx_intr_state = LDC_INTR_ACTIVE;
21093af08d82Slm66018 
21103af08d82Slm66018 	/* save current link state */
21113af08d82Slm66018 	link_state = ldcp->link_state;
21124bac2208Snarayan 
21131ae08745Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id, &ldcp->tx_head, &ldcp->tx_tail,
21141ae08745Sheppo 	    &ldcp->link_state);
21151ae08745Sheppo 	if (rv) {
21161ae08745Sheppo 		cmn_err(CE_WARN,
21171ae08745Sheppo 		    "i_ldc_tx_hdlr: (0x%lx) cannot read queue ptrs rv=0x%d\n",
21181ae08745Sheppo 		    ldcp->id, rv);
21194bac2208Snarayan 		i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
2120d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
21211ae08745Sheppo 		mutex_exit(&ldcp->lock);
21221ae08745Sheppo 		return (DDI_INTR_CLAIMED);
21231ae08745Sheppo 	}
21241ae08745Sheppo 
21251ae08745Sheppo 	/*
21261ae08745Sheppo 	 * reset the channel state if the channel went down
21271ae08745Sheppo 	 * (other side unconfigured queue) or channel was reset
21281ae08745Sheppo 	 * (other side reconfigured its queue)
21291ae08745Sheppo 	 */
21303af08d82Slm66018 	if (link_state != ldcp->link_state &&
21313af08d82Slm66018 	    ldcp->link_state == LDC_CHANNEL_DOWN) {
21321ae08745Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link down\n", ldcp->id);
21333af08d82Slm66018 		i_ldc_reset(ldcp, B_FALSE);
21341ae08745Sheppo 		notify_client = B_TRUE;
21351ae08745Sheppo 		notify_event = LDC_EVT_DOWN;
21361ae08745Sheppo 	}
21371ae08745Sheppo 
21383af08d82Slm66018 	if (link_state != ldcp->link_state &&
21393af08d82Slm66018 	    ldcp->link_state == LDC_CHANNEL_RESET) {
21401ae08745Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link reset\n", ldcp->id);
21413af08d82Slm66018 		i_ldc_reset(ldcp, B_FALSE);
21421ae08745Sheppo 		notify_client = B_TRUE;
21431ae08745Sheppo 		notify_event = LDC_EVT_RESET;
21441ae08745Sheppo 	}
21451ae08745Sheppo 
21463af08d82Slm66018 	if (link_state != ldcp->link_state &&
21473af08d82Slm66018 	    (ldcp->tstate & ~TS_IN_RESET) == TS_OPEN &&
21483af08d82Slm66018 	    ldcp->link_state == LDC_CHANNEL_UP) {
21491ae08745Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link up\n", ldcp->id);
21501ae08745Sheppo 		notify_client = B_TRUE;
21511ae08745Sheppo 		notify_event = LDC_EVT_RESET;
21521ae08745Sheppo 		ldcp->tstate |= TS_LINK_READY;
21531ae08745Sheppo 		ldcp->status = LDC_READY;
21541ae08745Sheppo 	}
21551ae08745Sheppo 
21561ae08745Sheppo 	/* if callbacks are disabled, do not notify */
21571ae08745Sheppo 	if (!ldcp->cb_enabled)
21581ae08745Sheppo 		notify_client = B_FALSE;
21591ae08745Sheppo 
21604d39be2bSsg70180 	i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
216122f747efSnarayan 	mutex_exit(&ldcp->tx_lock);
21621ae08745Sheppo 
21631ae08745Sheppo 	if (notify_client) {
21643af08d82Slm66018 		ldcp->cb_inprogress = B_TRUE;
21653af08d82Slm66018 		mutex_exit(&ldcp->lock);
21661ae08745Sheppo 		rv = ldcp->cb(notify_event, ldcp->cb_arg);
21671ae08745Sheppo 		if (rv) {
21681ae08745Sheppo 			DWARN(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) callback "
21691ae08745Sheppo 			    "failure", ldcp->id);
21701ae08745Sheppo 		}
21711ae08745Sheppo 		mutex_enter(&ldcp->lock);
21721ae08745Sheppo 		ldcp->cb_inprogress = B_FALSE;
21731ae08745Sheppo 	}
21741ae08745Sheppo 
21751ae08745Sheppo 	mutex_exit(&ldcp->lock);
21761ae08745Sheppo 
21771ae08745Sheppo 	D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) exiting handler", ldcp->id);
21781ae08745Sheppo 
21791ae08745Sheppo 	return (DDI_INTR_CLAIMED);
21801ae08745Sheppo }
21811ae08745Sheppo 
21821ae08745Sheppo /*
218358283286Sha137994  * Process the Rx HV queue.
218458283286Sha137994  *
218558283286Sha137994  * Returns 0 if data packets were found and no errors were encountered,
218658283286Sha137994  * otherwise returns an error. In either case, the *notify argument is
218758283286Sha137994  * set to indicate whether or not the client callback function should
218858283286Sha137994  * be invoked. The *event argument is set to contain the callback event.
218958283286Sha137994  *
219058283286Sha137994  * Depending on the channel mode, packets are handled differently:
219158283286Sha137994  *
219258283286Sha137994  * RAW MODE
219358283286Sha137994  * For raw mode channels, when a data packet is encountered,
219458283286Sha137994  * processing stops and all packets are left on the queue to be removed
219558283286Sha137994  * and processed by the ldc_read code path.
219658283286Sha137994  *
219758283286Sha137994  * UNRELIABLE MODE
219858283286Sha137994  * For unreliable mode, when a data packet is encountered, processing
219958283286Sha137994  * stops, and all packets are left on the queue to be removed and
220058283286Sha137994  * processed by the ldc_read code path. Control packets are processed
220158283286Sha137994  * inline if they are encountered before any data packets.
220258283286Sha137994  *
220320ae46ebSha137994  * RELIABLE MODE
220420ae46ebSha137994  * For reliable mode channels, all packets on the receive queue
220558283286Sha137994  * are processed: data packets are copied to the data queue and
220658283286Sha137994  * control packets are processed inline. Packets are only left on
220758283286Sha137994  * the receive queue when the data queue is full.
22081ae08745Sheppo  */
22091ae08745Sheppo static uint_t
i_ldc_rx_process_hvq(ldc_chan_t * ldcp,boolean_t * notify_client,uint64_t * notify_event)221058283286Sha137994 i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client,
221158283286Sha137994     uint64_t *notify_event)
22121ae08745Sheppo {
22131ae08745Sheppo 	int		rv;
22141ae08745Sheppo 	uint64_t	rx_head, rx_tail;
22151ae08745Sheppo 	ldc_msg_t	*msg;
22163af08d82Slm66018 	uint64_t	link_state, first_fragment = 0;
221758283286Sha137994 	boolean_t	trace_length = B_TRUE;
22183af08d82Slm66018 
221958283286Sha137994 	ASSERT(MUTEX_HELD(&ldcp->lock));
222058283286Sha137994 	*notify_client = B_FALSE;
222158283286Sha137994 	*notify_event = 0;
22221ae08745Sheppo 
22231ae08745Sheppo 	/*
22241ae08745Sheppo 	 * Read packet(s) from the queue
22251ae08745Sheppo 	 */
22261ae08745Sheppo 	for (;;) {
22271ae08745Sheppo 
22283af08d82Slm66018 		link_state = ldcp->link_state;
22291ae08745Sheppo 		rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
22301ae08745Sheppo 		    &ldcp->link_state);
22311ae08745Sheppo 		if (rv) {
22321ae08745Sheppo 			cmn_err(CE_WARN,
223358283286Sha137994 			    "i_ldc_rx_process_hvq: (0x%lx) cannot read "
22341ae08745Sheppo 			    "queue ptrs, rv=0x%d\n", ldcp->id, rv);
22351ae08745Sheppo 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
223658283286Sha137994 			return (EIO);
22371ae08745Sheppo 		}
22381ae08745Sheppo 
22391ae08745Sheppo 		/*
22401ae08745Sheppo 		 * reset the channel state if the channel went down
22411ae08745Sheppo 		 * (other side unconfigured queue) or channel was reset
22423af08d82Slm66018 		 * (other side reconfigured its queue)
22431ae08745Sheppo 		 */
22443af08d82Slm66018 
22453af08d82Slm66018 		if (link_state != ldcp->link_state) {
2246cb112a14Slm66018 
22473af08d82Slm66018 			switch (ldcp->link_state) {
22483af08d82Slm66018 			case LDC_CHANNEL_DOWN:
224958283286Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: channel "
22503af08d82Slm66018 				    "link down\n", ldcp->id);
2251d10e4ef2Snarayan 				mutex_enter(&ldcp->tx_lock);
22523af08d82Slm66018 				i_ldc_reset(ldcp, B_FALSE);
2253d10e4ef2Snarayan 				mutex_exit(&ldcp->tx_lock);
225458283286Sha137994 				*notify_client = B_TRUE;
225558283286Sha137994 				*notify_event = LDC_EVT_DOWN;
22563af08d82Slm66018 				goto loop_exit;
22571ae08745Sheppo 
22583af08d82Slm66018 			case LDC_CHANNEL_UP:
225958283286Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: "
22603af08d82Slm66018 				    "channel link up\n", ldcp->id);
22613af08d82Slm66018 
22623af08d82Slm66018 				if ((ldcp->tstate & ~TS_IN_RESET) == TS_OPEN) {
226358283286Sha137994 					*notify_client = B_TRUE;
226458283286Sha137994 					*notify_event = LDC_EVT_RESET;
22651ae08745Sheppo 					ldcp->tstate |= TS_LINK_READY;
22661ae08745Sheppo 					ldcp->status = LDC_READY;
22671ae08745Sheppo 				}
22683af08d82Slm66018 				break;
22693af08d82Slm66018 
22703af08d82Slm66018 			case LDC_CHANNEL_RESET:
22713af08d82Slm66018 			default:
22723af08d82Slm66018 #ifdef DEBUG
22733af08d82Slm66018 force_reset:
22743af08d82Slm66018 #endif
227558283286Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: channel "
22763af08d82Slm66018 				    "link reset\n", ldcp->id);
22773af08d82Slm66018 				mutex_enter(&ldcp->tx_lock);
22783af08d82Slm66018 				i_ldc_reset(ldcp, B_FALSE);
22793af08d82Slm66018 				mutex_exit(&ldcp->tx_lock);
228058283286Sha137994 				*notify_client = B_TRUE;
228158283286Sha137994 				*notify_event = LDC_EVT_RESET;
22823af08d82Slm66018 				break;
22833af08d82Slm66018 			}
22843af08d82Slm66018 		}
22853af08d82Slm66018 
22863af08d82Slm66018 #ifdef DEBUG
22873af08d82Slm66018 		if (LDC_INJECT_RESET(ldcp))
22883af08d82Slm66018 			goto force_reset;
2289bbfa0259Sha137994 		if (LDC_INJECT_DRNGCLEAR(ldcp))
2290bbfa0259Sha137994 			i_ldc_mem_inject_dring_clear(ldcp);
22913af08d82Slm66018 #endif
229258283286Sha137994 		if (trace_length) {
229358283286Sha137994 			TRACE_RXHVQ_LENGTH(ldcp, rx_head, rx_tail);
229458283286Sha137994 			trace_length = B_FALSE;
229558283286Sha137994 		}
22961ae08745Sheppo 
22971ae08745Sheppo 		if (rx_head == rx_tail) {
229858283286Sha137994 			D2(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) "
229958283286Sha137994 			    "No packets\n", ldcp->id);
23001ae08745Sheppo 			break;
23011ae08745Sheppo 		}
23023af08d82Slm66018 
230358283286Sha137994 		D2(ldcp->id, "i_ldc_rx_process_hvq: head=0x%llx, "
230458283286Sha137994 		    "tail=0x%llx\n", rx_head, rx_tail);
230558283286Sha137994 		DUMP_LDC_PKT(ldcp, "i_ldc_rx_process_hvq rcd",
23061ae08745Sheppo 		    ldcp->rx_q_va + rx_head);
23071ae08745Sheppo 
23081ae08745Sheppo 		/* get the message */
23091ae08745Sheppo 		msg = (ldc_msg_t *)(ldcp->rx_q_va + rx_head);
23101ae08745Sheppo 
23111ae08745Sheppo 		/* if channel is in RAW mode or data pkt, notify and return */
23121ae08745Sheppo 		if (ldcp->mode == LDC_MODE_RAW) {
231358283286Sha137994 			*notify_client = B_TRUE;
231458283286Sha137994 			*notify_event |= LDC_EVT_READ;
23151ae08745Sheppo 			break;
23161ae08745Sheppo 		}
23171ae08745Sheppo 
23181ae08745Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
23191ae08745Sheppo 
23201ae08745Sheppo 			/* discard packet if channel is not up */
23213af08d82Slm66018 			if ((ldcp->tstate & ~TS_IN_RESET) != TS_UP) {
23221ae08745Sheppo 
23231ae08745Sheppo 				/* move the head one position */
23241ae08745Sheppo 				rx_head = (rx_head + LDC_PACKET_SIZE) %
23251ae08745Sheppo 				    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
23261ae08745Sheppo 
23271ae08745Sheppo 				if (rv = i_ldc_set_rx_head(ldcp, rx_head))
23281ae08745Sheppo 					break;
23291ae08745Sheppo 
23301ae08745Sheppo 				continue;
23311ae08745Sheppo 			} else {
233258283286Sha137994 				uint64_t dq_head, dq_tail;
233358283286Sha137994 
233420ae46ebSha137994 				/* process only RELIABLE mode data packets */
233520ae46ebSha137994 				if (ldcp->mode != LDC_MODE_RELIABLE) {
23363af08d82Slm66018 					if ((ldcp->tstate & TS_IN_RESET) == 0)
233758283286Sha137994 						*notify_client = B_TRUE;
233858283286Sha137994 					*notify_event |= LDC_EVT_READ;
23391ae08745Sheppo 					break;
23401ae08745Sheppo 				}
234158283286Sha137994 
234258283286Sha137994 				/* don't process packet if queue full */
234358283286Sha137994 				(void) i_ldc_dq_rx_get_state(ldcp, &dq_head,
234458283286Sha137994 				    &dq_tail, NULL);
234558283286Sha137994 				dq_tail = (dq_tail + LDC_PACKET_SIZE) %
234658283286Sha137994 				    (ldcp->rx_dq_entries << LDC_PACKET_SHIFT);
234758283286Sha137994 				if (dq_tail == dq_head ||
234858283286Sha137994 				    LDC_INJECT_DQFULL(ldcp)) {
234958283286Sha137994 					rv = ENOSPC;
235058283286Sha137994 					break;
235158283286Sha137994 				}
235258283286Sha137994 			}
23531ae08745Sheppo 		}
23541ae08745Sheppo 
23551ae08745Sheppo 		/* Check the sequence ID for the message received */
23563af08d82Slm66018 		rv = i_ldc_check_seqid(ldcp, msg);
23573af08d82Slm66018 		if (rv != 0) {
23581ae08745Sheppo 
235958283286Sha137994 			DWARN(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) "
236058283286Sha137994 			    "seqid error, q_ptrs=0x%lx,0x%lx", ldcp->id,
236158283286Sha137994 			    rx_head, rx_tail);
23621ae08745Sheppo 
23631ae08745Sheppo 			/* Reset last_msg_rcd to start of message */
2364d10e4ef2Snarayan 			if (first_fragment != 0) {
2365d10e4ef2Snarayan 				ldcp->last_msg_rcd = first_fragment - 1;
2366d10e4ef2Snarayan 				first_fragment = 0;
23671ae08745Sheppo 			}
2368d10e4ef2Snarayan 
23691ae08745Sheppo 			/*
23701ae08745Sheppo 			 * Send a NACK due to seqid mismatch
23711ae08745Sheppo 			 */
237222f747efSnarayan 			rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK,
23731ae08745Sheppo 			    (msg->ctrl & LDC_CTRL_MASK));
23741ae08745Sheppo 
23751ae08745Sheppo 			if (rv) {
237658283286Sha137994 				cmn_err(CE_NOTE, "i_ldc_rx_process_hvq: "
237758283286Sha137994 				    "(0x%lx) err sending CTRL/DATA NACK msg\n",
237858283286Sha137994 				    ldcp->id);
2379d10e4ef2Snarayan 
2380d10e4ef2Snarayan 				/* if cannot send NACK - reset channel */
2381d10e4ef2Snarayan 				mutex_enter(&ldcp->tx_lock);
23823af08d82Slm66018 				i_ldc_reset(ldcp, B_TRUE);
2383d10e4ef2Snarayan 				mutex_exit(&ldcp->tx_lock);
238483d3bc6fSnarayan 
238558283286Sha137994 				*notify_client = B_TRUE;
238658283286Sha137994 				*notify_event = LDC_EVT_RESET;
2387d10e4ef2Snarayan 				break;
23881ae08745Sheppo 			}
23891ae08745Sheppo 
23901ae08745Sheppo 			/* purge receive queue */
23911ae08745Sheppo 			(void) i_ldc_set_rx_head(ldcp, rx_tail);
23921ae08745Sheppo 			break;
23931ae08745Sheppo 		}
23941ae08745Sheppo 
23951ae08745Sheppo 		/* record the message ID */
23961ae08745Sheppo 		ldcp->last_msg_rcd = msg->seqid;
23971ae08745Sheppo 
23981ae08745Sheppo 		/* process control messages */
23991ae08745Sheppo 		if (msg->type & LDC_CTRL) {
24001ae08745Sheppo 			/* save current internal state */
24011ae08745Sheppo 			uint64_t tstate = ldcp->tstate;
24021ae08745Sheppo 
24031ae08745Sheppo 			rv = i_ldc_ctrlmsg(ldcp, msg);
24041ae08745Sheppo 			if (rv == EAGAIN) {
24051ae08745Sheppo 				/* re-process pkt - state was adjusted */
24061ae08745Sheppo 				continue;
24071ae08745Sheppo 			}
24081ae08745Sheppo 			if (rv == ECONNRESET) {
240958283286Sha137994 				*notify_client = B_TRUE;
241058283286Sha137994 				*notify_event = LDC_EVT_RESET;
24111ae08745Sheppo 				break;
24121ae08745Sheppo 			}
24131ae08745Sheppo 
24141ae08745Sheppo 			/*
24151ae08745Sheppo 			 * control message processing was successful
24161ae08745Sheppo 			 * channel transitioned to ready for communication
24171ae08745Sheppo 			 */
24181ae08745Sheppo 			if (rv == 0 && ldcp->tstate == TS_UP &&
24193af08d82Slm66018 			    (tstate & ~TS_IN_RESET) !=
24203af08d82Slm66018 			    (ldcp->tstate & ~TS_IN_RESET)) {
242158283286Sha137994 				*notify_client = B_TRUE;
242258283286Sha137994 				*notify_event = LDC_EVT_UP;
24231ae08745Sheppo 			}
24241ae08745Sheppo 		}
24251ae08745Sheppo 
242683d3bc6fSnarayan 		/* process data NACKs */
242783d3bc6fSnarayan 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) {
242883d3bc6fSnarayan 			DWARN(ldcp->id,
242958283286Sha137994 			    "i_ldc_rx_process_hvq: (0x%llx) received DATA/NACK",
243083d3bc6fSnarayan 			    ldcp->id);
243183d3bc6fSnarayan 			mutex_enter(&ldcp->tx_lock);
243283d3bc6fSnarayan 			i_ldc_reset(ldcp, B_TRUE);
243383d3bc6fSnarayan 			mutex_exit(&ldcp->tx_lock);
243458283286Sha137994 			*notify_client = B_TRUE;
243558283286Sha137994 			*notify_event = LDC_EVT_RESET;
243683d3bc6fSnarayan 			break;
243783d3bc6fSnarayan 		}
243883d3bc6fSnarayan 
24391ae08745Sheppo 		/* process data ACKs */
24401ae08745Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
2441d10e4ef2Snarayan 			if (rv = i_ldc_process_data_ACK(ldcp, msg)) {
244258283286Sha137994 				*notify_client = B_TRUE;
244358283286Sha137994 				*notify_event = LDC_EVT_RESET;
2444d10e4ef2Snarayan 				break;
2445d10e4ef2Snarayan 			}
24461ae08745Sheppo 		}
24471ae08745Sheppo 
244858283286Sha137994 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
244920ae46ebSha137994 			ASSERT(ldcp->mode == LDC_MODE_RELIABLE);
245058283286Sha137994 
245158283286Sha137994 			/*
245258283286Sha137994 			 * Copy the data packet to the data queue. Note
245358283286Sha137994 			 * that the copy routine updates the rx_head pointer.
245458283286Sha137994 			 */
245558283286Sha137994 			i_ldc_rxdq_copy(ldcp, &rx_head);
245658283286Sha137994 
245758283286Sha137994 			if ((ldcp->tstate & TS_IN_RESET) == 0)
245858283286Sha137994 				*notify_client = B_TRUE;
245958283286Sha137994 			*notify_event |= LDC_EVT_READ;
246058283286Sha137994 		} else {
24611ae08745Sheppo 			rx_head = (rx_head + LDC_PACKET_SIZE) %
24621ae08745Sheppo 			    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
246358283286Sha137994 		}
246458283286Sha137994 
246558283286Sha137994 		/* move the head one position */
24660a55fbb7Slm66018 		if (rv = i_ldc_set_rx_head(ldcp, rx_head)) {
246758283286Sha137994 			*notify_client = B_TRUE;
246858283286Sha137994 			*notify_event = LDC_EVT_RESET;
24691ae08745Sheppo 			break;
24700a55fbb7Slm66018 		}
24711ae08745Sheppo 
24721ae08745Sheppo 	} /* for */
24731ae08745Sheppo 
24743af08d82Slm66018 loop_exit:
24753af08d82Slm66018 
247620ae46ebSha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
247758283286Sha137994 		/* ACK data packets */
247858283286Sha137994 		if ((*notify_event &
247958283286Sha137994 		    (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) {
248058283286Sha137994 			int ack_rv;
248158283286Sha137994 			ack_rv = i_ldc_send_pkt(ldcp, LDC_DATA, LDC_ACK, 0);
248258283286Sha137994 			if (ack_rv && ack_rv != EWOULDBLOCK) {
248358283286Sha137994 				cmn_err(CE_NOTE,
248458283286Sha137994 				    "i_ldc_rx_process_hvq: (0x%lx) cannot "
248558283286Sha137994 				    "send ACK\n", ldcp->id);
248658283286Sha137994 
248758283286Sha137994 				mutex_enter(&ldcp->tx_lock);
248858283286Sha137994 				i_ldc_reset(ldcp, B_FALSE);
248958283286Sha137994 				mutex_exit(&ldcp->tx_lock);
249058283286Sha137994 
249158283286Sha137994 				*notify_client = B_TRUE;
249258283286Sha137994 				*notify_event = LDC_EVT_RESET;
249358283286Sha137994 				goto skip_ackpeek;
249458283286Sha137994 			}
249558283286Sha137994 		}
24961ae08745Sheppo 
24973af08d82Slm66018 		/*
249858283286Sha137994 		 * If we have no more space on the data queue, make sure
249958283286Sha137994 		 * there are no ACKs on the rx queue waiting to be processed.
25003af08d82Slm66018 		 */
250158283286Sha137994 		if (rv == ENOSPC) {
250258283286Sha137994 			if (i_ldc_rx_ackpeek(ldcp, rx_head, rx_tail) != 0) {
250358283286Sha137994 				ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
250458283286Sha137994 				*notify_client = B_TRUE;
250558283286Sha137994 				*notify_event = LDC_EVT_RESET;
25061ae08745Sheppo 			}
250712f80fa6Sha137994 			return (rv);
250858283286Sha137994 		} else {
250958283286Sha137994 			ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
251058283286Sha137994 		}
25111ae08745Sheppo 	}
25121ae08745Sheppo 
251358283286Sha137994 skip_ackpeek:
25144d39be2bSsg70180 
251558283286Sha137994 	/* Return, indicating whether or not data packets were found */
251658283286Sha137994 	if ((*notify_event & (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ)
251758283286Sha137994 		return (0);
251858283286Sha137994 
251958283286Sha137994 	return (ENOMSG);
25201ae08745Sheppo }
25211ae08745Sheppo 
252258283286Sha137994 /*
252358283286Sha137994  * Process any ACK packets on the HV receive queue.
252458283286Sha137994  *
252520ae46ebSha137994  * This function is only used by RELIABLE mode channels when the
252658283286Sha137994  * secondary data queue fills up and there are packets remaining on
252758283286Sha137994  * the HV receive queue.
252858283286Sha137994  */
252958283286Sha137994 int
i_ldc_rx_ackpeek(ldc_chan_t * ldcp,uint64_t rx_head,uint64_t rx_tail)253058283286Sha137994 i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, uint64_t rx_tail)
253158283286Sha137994 {
253258283286Sha137994 	int		rv = 0;
253358283286Sha137994 	ldc_msg_t	*msg;
253458283286Sha137994 
253558283286Sha137994 	if (ldcp->rx_ack_head == ACKPEEK_HEAD_INVALID)
253658283286Sha137994 		ldcp->rx_ack_head = rx_head;
253758283286Sha137994 
253858283286Sha137994 	while (ldcp->rx_ack_head != rx_tail) {
253958283286Sha137994 		msg = (ldc_msg_t *)(ldcp->rx_q_va + ldcp->rx_ack_head);
254058283286Sha137994 
254158283286Sha137994 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
254258283286Sha137994 			if (rv = i_ldc_process_data_ACK(ldcp, msg))
254358283286Sha137994 				break;
254458283286Sha137994 			msg->stype &= ~LDC_ACK;
254558283286Sha137994 		}
254658283286Sha137994 
254758283286Sha137994 		ldcp->rx_ack_head =
254858283286Sha137994 		    (ldcp->rx_ack_head + LDC_PACKET_SIZE) %
254958283286Sha137994 		    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
255058283286Sha137994 	}
255158283286Sha137994 	return (rv);
255258283286Sha137994 }
25531ae08745Sheppo 
25541ae08745Sheppo /* -------------------------------------------------------------------------- */
25551ae08745Sheppo 
25561ae08745Sheppo /*
25571ae08745Sheppo  * LDC API functions
25581ae08745Sheppo  */
25591ae08745Sheppo 
25601ae08745Sheppo /*
25611ae08745Sheppo  * Initialize the channel. Allocate internal structure and memory for
25621ae08745Sheppo  * TX/RX queues, and initialize locks.
25631ae08745Sheppo  */
25641ae08745Sheppo int
ldc_init(uint64_t id,ldc_attr_t * attr,ldc_handle_t * handle)25651ae08745Sheppo ldc_init(uint64_t id, ldc_attr_t *attr, ldc_handle_t *handle)
25661ae08745Sheppo {
25671ae08745Sheppo 	ldc_chan_t	*ldcp;
25681ae08745Sheppo 	int		rv, exit_val;
25691ae08745Sheppo 	uint64_t	ra_base, nentries;
2570e1ebb9ecSlm66018 	uint64_t	qlen;
25711ae08745Sheppo 
25721ae08745Sheppo 	exit_val = EINVAL;	/* guarantee an error if exit on failure */
25731ae08745Sheppo 
25741ae08745Sheppo 	if (attr == NULL) {
25751ae08745Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid attr\n", id);
25761ae08745Sheppo 		return (EINVAL);
25771ae08745Sheppo 	}
25781ae08745Sheppo 	if (handle == NULL) {
25791ae08745Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid handle\n", id);
25801ae08745Sheppo 		return (EINVAL);
25811ae08745Sheppo 	}
25821ae08745Sheppo 
25831ae08745Sheppo 	/* check if channel is valid */
25841ae08745Sheppo 	rv = hv_ldc_tx_qinfo(id, &ra_base, &nentries);
25851ae08745Sheppo 	if (rv == H_ECHANNEL) {
25861ae08745Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid channel id\n", id);
25871ae08745Sheppo 		return (EINVAL);
25881ae08745Sheppo 	}
25891ae08745Sheppo 
25901ae08745Sheppo 	/* check if the channel has already been initialized */
25911ae08745Sheppo 	mutex_enter(&ldcssp->lock);
25921ae08745Sheppo 	ldcp = ldcssp->chan_list;
25931ae08745Sheppo 	while (ldcp != NULL) {
25941ae08745Sheppo 		if (ldcp->id == id) {
25951ae08745Sheppo 			DWARN(id, "ldc_init: (0x%llx) already initialized\n",
25961ae08745Sheppo 			    id);
25971ae08745Sheppo 			mutex_exit(&ldcssp->lock);
25981ae08745Sheppo 			return (EADDRINUSE);
25991ae08745Sheppo 		}
26001ae08745Sheppo 		ldcp = ldcp->next;
26011ae08745Sheppo 	}
26021ae08745Sheppo 	mutex_exit(&ldcssp->lock);
26031ae08745Sheppo 
26041ae08745Sheppo 	ASSERT(ldcp == NULL);
26051ae08745Sheppo 
26061ae08745Sheppo 	*handle = 0;
26071ae08745Sheppo 
26081ae08745Sheppo 	/* Allocate an ldcp structure */
26091ae08745Sheppo 	ldcp = kmem_zalloc(sizeof (ldc_chan_t), KM_SLEEP);
26101ae08745Sheppo 
2611d10e4ef2Snarayan 	/*
2612d10e4ef2Snarayan 	 * Initialize the channel and Tx lock
2613d10e4ef2Snarayan 	 *
2614d10e4ef2Snarayan 	 * The channel 'lock' protects the entire channel and
2615d10e4ef2Snarayan 	 * should be acquired before initializing, resetting,
2616d10e4ef2Snarayan 	 * destroying or reading from a channel.
2617d10e4ef2Snarayan 	 *
2618d10e4ef2Snarayan 	 * The 'tx_lock' should be acquired prior to transmitting
2619d10e4ef2Snarayan 	 * data over the channel. The lock should also be acquired
2620d10e4ef2Snarayan 	 * prior to channel reconfiguration (in order to prevent
2621d10e4ef2Snarayan 	 * concurrent writes).
2622d10e4ef2Snarayan 	 *
2623d10e4ef2Snarayan 	 * ORDERING: When both locks are being acquired, to prevent
2624d10e4ef2Snarayan 	 * deadlocks, the channel lock should be always acquired prior
2625d10e4ef2Snarayan 	 * to the tx_lock.
2626d10e4ef2Snarayan 	 */
26271ae08745Sheppo 	mutex_init(&ldcp->lock, NULL, MUTEX_DRIVER, NULL);
2628d10e4ef2Snarayan 	mutex_init(&ldcp->tx_lock, NULL, MUTEX_DRIVER, NULL);
26291ae08745Sheppo 
26301ae08745Sheppo 	/* Initialize the channel */
26311ae08745Sheppo 	ldcp->id = id;
26321ae08745Sheppo 	ldcp->cb = NULL;
26331ae08745Sheppo 	ldcp->cb_arg = NULL;
26341ae08745Sheppo 	ldcp->cb_inprogress = B_FALSE;
26351ae08745Sheppo 	ldcp->cb_enabled = B_FALSE;
26361ae08745Sheppo 	ldcp->next = NULL;
26371ae08745Sheppo 
26381ae08745Sheppo 	/* Read attributes */
26391ae08745Sheppo 	ldcp->mode = attr->mode;
26401ae08745Sheppo 	ldcp->devclass = attr->devclass;
26411ae08745Sheppo 	ldcp->devinst = attr->instance;
2642e1ebb9ecSlm66018 	ldcp->mtu = (attr->mtu > 0) ? attr->mtu : LDC_DEFAULT_MTU;
26431ae08745Sheppo 
26441ae08745Sheppo 	D1(ldcp->id,
26451ae08745Sheppo 	    "ldc_init: (0x%llx) channel attributes, class=0x%x, "
2646e1ebb9ecSlm66018 	    "instance=0x%llx, mode=%d, mtu=%d\n",
2647e1ebb9ecSlm66018 	    ldcp->id, ldcp->devclass, ldcp->devinst, ldcp->mode, ldcp->mtu);
26481ae08745Sheppo 
26491ae08745Sheppo 	ldcp->next_vidx = 0;
26503af08d82Slm66018 	ldcp->tstate = TS_IN_RESET;
26511ae08745Sheppo 	ldcp->hstate = 0;
26521ae08745Sheppo 	ldcp->last_msg_snt = LDC_INIT_SEQID;
26531ae08745Sheppo 	ldcp->last_ack_rcd = 0;
26541ae08745Sheppo 	ldcp->last_msg_rcd = 0;
265558283286Sha137994 	ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
26561ae08745Sheppo 
26571ae08745Sheppo 	ldcp->stream_bufferp = NULL;
26581ae08745Sheppo 	ldcp->exp_dring_list = NULL;
26591ae08745Sheppo 	ldcp->imp_dring_list = NULL;
26601ae08745Sheppo 	ldcp->mhdl_list = NULL;
26611ae08745Sheppo 
26623af08d82Slm66018 	ldcp->tx_intr_state = LDC_INTR_NONE;
26633af08d82Slm66018 	ldcp->rx_intr_state = LDC_INTR_NONE;
26643af08d82Slm66018 
26651ae08745Sheppo 	/* Initialize payload size depending on whether channel is reliable */
26661ae08745Sheppo 	switch (ldcp->mode) {
26671ae08745Sheppo 	case LDC_MODE_RAW:
26681ae08745Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RAW;
26691ae08745Sheppo 		ldcp->read_p = i_ldc_read_raw;
26701ae08745Sheppo 		ldcp->write_p = i_ldc_write_raw;
26711ae08745Sheppo 		break;
26721ae08745Sheppo 	case LDC_MODE_UNRELIABLE:
26731ae08745Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_UNRELIABLE;
26741ae08745Sheppo 		ldcp->read_p = i_ldc_read_packet;
26751ae08745Sheppo 		ldcp->write_p = i_ldc_write_packet;
26761ae08745Sheppo 		break;
26771ae08745Sheppo 	case LDC_MODE_RELIABLE:
26781ae08745Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE;
26791ae08745Sheppo 
26801ae08745Sheppo 		ldcp->stream_remains = 0;
26811ae08745Sheppo 		ldcp->stream_offset = 0;
26821ae08745Sheppo 		ldcp->stream_bufferp = kmem_alloc(ldcp->mtu, KM_SLEEP);
26831ae08745Sheppo 		ldcp->read_p = i_ldc_read_stream;
26841ae08745Sheppo 		ldcp->write_p = i_ldc_write_stream;
26851ae08745Sheppo 		break;
26861ae08745Sheppo 	default:
26871ae08745Sheppo 		exit_val = EINVAL;
26881ae08745Sheppo 		goto cleanup_on_exit;
26891ae08745Sheppo 	}
26901ae08745Sheppo 
2691e1ebb9ecSlm66018 	/*
2692e1ebb9ecSlm66018 	 * qlen is (mtu * ldc_mtu_msgs) / pkt_payload. If this
2693e1ebb9ecSlm66018 	 * value is smaller than default length of ldc_queue_entries,
269422f747efSnarayan 	 * qlen is set to ldc_queue_entries. Ensure that computed
269522f747efSnarayan 	 * length is a power-of-two value.
2696e1ebb9ecSlm66018 	 */
2697e1ebb9ecSlm66018 	qlen = (ldcp->mtu * ldc_mtu_msgs) / ldcp->pkt_payload;
269822f747efSnarayan 	if (!ISP2(qlen)) {
269922f747efSnarayan 		uint64_t	tmp = 1;
270022f747efSnarayan 		while (qlen) {
270122f747efSnarayan 			qlen >>= 1; tmp <<= 1;
270222f747efSnarayan 		}
270322f747efSnarayan 		qlen = tmp;
270422f747efSnarayan 	}
270522f747efSnarayan 
2706e1ebb9ecSlm66018 	ldcp->rx_q_entries =
2707e1ebb9ecSlm66018 	    (qlen < ldc_queue_entries) ? ldc_queue_entries : qlen;
2708e1ebb9ecSlm66018 	ldcp->tx_q_entries = ldcp->rx_q_entries;
2709e1ebb9ecSlm66018 
271022f747efSnarayan 	D1(ldcp->id, "ldc_init: queue length = 0x%llx\n", ldcp->rx_q_entries);
2711e1ebb9ecSlm66018 
27121ae08745Sheppo 	/* Create a transmit queue */
27131ae08745Sheppo 	ldcp->tx_q_va = (uint64_t)
27141ae08745Sheppo 	    contig_mem_alloc(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
2715*a704fb2dSToomas Soome 	if (ldcp->tx_q_va == 0) {
27161ae08745Sheppo 		cmn_err(CE_WARN,
27171ae08745Sheppo 		    "ldc_init: (0x%lx) TX queue allocation failed\n",
27181ae08745Sheppo 		    ldcp->id);
27191ae08745Sheppo 		exit_val = ENOMEM;
27201ae08745Sheppo 		goto cleanup_on_exit;
27211ae08745Sheppo 	}
27221ae08745Sheppo 	ldcp->tx_q_ra = va_to_pa((caddr_t)ldcp->tx_q_va);
27231ae08745Sheppo 
27241ae08745Sheppo 	D2(ldcp->id, "ldc_init: txq_va=0x%llx, txq_ra=0x%llx, entries=0x%llx\n",
27251ae08745Sheppo 	    ldcp->tx_q_va, ldcp->tx_q_ra, ldcp->tx_q_entries);
27261ae08745Sheppo 
27271ae08745Sheppo 	ldcp->tstate |= TS_TXQ_RDY;
27281ae08745Sheppo 
27291ae08745Sheppo 	/* Create a receive queue */
27301ae08745Sheppo 	ldcp->rx_q_va = (uint64_t)
27311ae08745Sheppo 	    contig_mem_alloc(ldcp->rx_q_entries << LDC_PACKET_SHIFT);
2732*a704fb2dSToomas Soome 	if (ldcp->rx_q_va == 0) {
27331ae08745Sheppo 		cmn_err(CE_WARN,
27341ae08745Sheppo 		    "ldc_init: (0x%lx) RX queue allocation failed\n",
27351ae08745Sheppo 		    ldcp->id);
27361ae08745Sheppo 		exit_val = ENOMEM;
27371ae08745Sheppo 		goto cleanup_on_exit;
27381ae08745Sheppo 	}
27391ae08745Sheppo 	ldcp->rx_q_ra = va_to_pa((caddr_t)ldcp->rx_q_va);
27401ae08745Sheppo 
27411ae08745Sheppo 	D2(ldcp->id, "ldc_init: rxq_va=0x%llx, rxq_ra=0x%llx, entries=0x%llx\n",
27421ae08745Sheppo 	    ldcp->rx_q_va, ldcp->rx_q_ra, ldcp->rx_q_entries);
27431ae08745Sheppo 
27441ae08745Sheppo 	ldcp->tstate |= TS_RXQ_RDY;
27451ae08745Sheppo 
274658283286Sha137994 	/* Setup a separate read data queue */
274720ae46ebSha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
274858283286Sha137994 		ldcp->readq_get_state = i_ldc_dq_rx_get_state;
274958283286Sha137994 		ldcp->readq_set_head  = i_ldc_set_rxdq_head;
275058283286Sha137994 
275158283286Sha137994 		/* Make sure the data queue multiplier is a power of 2 */
275258283286Sha137994 		if (!ISP2(ldc_rxdq_multiplier)) {
275358283286Sha137994 			D1(ldcp->id, "ldc_init: (0x%llx) ldc_rxdq_multiplier "
275458283286Sha137994 			    "not a power of 2, resetting", ldcp->id);
275558283286Sha137994 			ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER;
275658283286Sha137994 		}
275758283286Sha137994 
275858283286Sha137994 		ldcp->rx_dq_entries = ldc_rxdq_multiplier * ldcp->rx_q_entries;
275958283286Sha137994 		ldcp->rx_dq_va = (uint64_t)
276058283286Sha137994 		    kmem_alloc(ldcp->rx_dq_entries << LDC_PACKET_SHIFT,
276158283286Sha137994 		    KM_SLEEP);
2762*a704fb2dSToomas Soome 		if (ldcp->rx_dq_va == 0) {
276358283286Sha137994 			cmn_err(CE_WARN,
276458283286Sha137994 			    "ldc_init: (0x%lx) RX data queue "
276558283286Sha137994 			    "allocation failed\n", ldcp->id);
276658283286Sha137994 			exit_val = ENOMEM;
276758283286Sha137994 			goto cleanup_on_exit;
276858283286Sha137994 		}
276958283286Sha137994 
277058283286Sha137994 		ldcp->rx_dq_head = ldcp->rx_dq_tail = 0;
277158283286Sha137994 
277258283286Sha137994 		D2(ldcp->id, "ldc_init: rx_dq_va=0x%llx, "
277358283286Sha137994 		    "rx_dq_entries=0x%llx\n", ldcp->rx_dq_va,
277458283286Sha137994 		    ldcp->rx_dq_entries);
277558283286Sha137994 	} else {
277658283286Sha137994 		ldcp->readq_get_state = i_ldc_hvq_rx_get_state;
277758283286Sha137994 		ldcp->readq_set_head  = i_ldc_set_rx_head;
277858283286Sha137994 	}
277958283286Sha137994 
27801ae08745Sheppo 	/* Init descriptor ring and memory handle list lock */
27811ae08745Sheppo 	mutex_init(&ldcp->exp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
27821ae08745Sheppo 	mutex_init(&ldcp->imp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
27831ae08745Sheppo 	mutex_init(&ldcp->mlist_lock, NULL, MUTEX_DRIVER, NULL);
27841ae08745Sheppo 
27851ae08745Sheppo 	/* mark status as INITialized */
27861ae08745Sheppo 	ldcp->status = LDC_INIT;
27871ae08745Sheppo 
27881ae08745Sheppo 	/* Add to channel list */
27891ae08745Sheppo 	mutex_enter(&ldcssp->lock);
27901ae08745Sheppo 	ldcp->next = ldcssp->chan_list;
27911ae08745Sheppo 	ldcssp->chan_list = ldcp;
27921ae08745Sheppo 	ldcssp->channel_count++;
27931ae08745Sheppo 	mutex_exit(&ldcssp->lock);
27941ae08745Sheppo 
27951ae08745Sheppo 	/* set the handle */
27961ae08745Sheppo 	*handle = (ldc_handle_t)ldcp;
27971ae08745Sheppo 
27981ae08745Sheppo 	D1(ldcp->id, "ldc_init: (0x%llx) channel initialized\n", ldcp->id);
27991ae08745Sheppo 
28001ae08745Sheppo 	return (0);
28011ae08745Sheppo 
28021ae08745Sheppo cleanup_on_exit:
28031ae08745Sheppo 
280420ae46ebSha137994 	if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp)
28051ae08745Sheppo 		kmem_free(ldcp->stream_bufferp, ldcp->mtu);
28061ae08745Sheppo 
28071ae08745Sheppo 	if (ldcp->tstate & TS_TXQ_RDY)
28081ae08745Sheppo 		contig_mem_free((caddr_t)ldcp->tx_q_va,
28091ae08745Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
28101ae08745Sheppo 
28111ae08745Sheppo 	if (ldcp->tstate & TS_RXQ_RDY)
28121ae08745Sheppo 		contig_mem_free((caddr_t)ldcp->rx_q_va,
28131ae08745Sheppo 		    (ldcp->rx_q_entries << LDC_PACKET_SHIFT));
28141ae08745Sheppo 
2815d10e4ef2Snarayan 	mutex_destroy(&ldcp->tx_lock);
28161ae08745Sheppo 	mutex_destroy(&ldcp->lock);
28171ae08745Sheppo 
28181ae08745Sheppo 	kmem_free(ldcp, sizeof (ldc_chan_t));
28191ae08745Sheppo 
28201ae08745Sheppo 	return (exit_val);
28211ae08745Sheppo }
28221ae08745Sheppo 
28231ae08745Sheppo /*
28241ae08745Sheppo  * Finalizes the LDC connection. It will return EBUSY if the
28251ae08745Sheppo  * channel is open. A ldc_close() has to be done prior to
28261ae08745Sheppo  * a ldc_fini operation. It frees TX/RX queues, associated
28271ae08745Sheppo  * with the channel
28281ae08745Sheppo  */
28291ae08745Sheppo int
ldc_fini(ldc_handle_t handle)28301ae08745Sheppo ldc_fini(ldc_handle_t handle)
28311ae08745Sheppo {
28321ae08745Sheppo 	ldc_chan_t	*ldcp;
28331ae08745Sheppo 	ldc_chan_t	*tmp_ldcp;
28341ae08745Sheppo 	uint64_t	id;
28351ae08745Sheppo 
2836*a704fb2dSToomas Soome 	if (handle == 0) {
28371ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel handle\n");
28381ae08745Sheppo 		return (EINVAL);
28391ae08745Sheppo 	}
28401ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
28411ae08745Sheppo 	id = ldcp->id;
28421ae08745Sheppo 
28431ae08745Sheppo 	mutex_enter(&ldcp->lock);
28441ae08745Sheppo 
28453af08d82Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) > TS_INIT) {
28461ae08745Sheppo 		DWARN(ldcp->id, "ldc_fini: (0x%llx) channel is open\n",
28471ae08745Sheppo 		    ldcp->id);
28481ae08745Sheppo 		mutex_exit(&ldcp->lock);
28491ae08745Sheppo 		return (EBUSY);
28501ae08745Sheppo 	}
28511ae08745Sheppo 
28521ae08745Sheppo 	/* Remove from the channel list */
28531ae08745Sheppo 	mutex_enter(&ldcssp->lock);
28541ae08745Sheppo 	tmp_ldcp = ldcssp->chan_list;
28551ae08745Sheppo 	if (tmp_ldcp == ldcp) {
28561ae08745Sheppo 		ldcssp->chan_list = ldcp->next;
28571ae08745Sheppo 		ldcp->next = NULL;
28581ae08745Sheppo 	} else {
28591ae08745Sheppo 		while (tmp_ldcp != NULL) {
28601ae08745Sheppo 			if (tmp_ldcp->next == ldcp) {
28611ae08745Sheppo 				tmp_ldcp->next = ldcp->next;
28621ae08745Sheppo 				ldcp->next = NULL;
28631ae08745Sheppo 				break;
28641ae08745Sheppo 			}
28651ae08745Sheppo 			tmp_ldcp = tmp_ldcp->next;
28661ae08745Sheppo 		}
28671ae08745Sheppo 		if (tmp_ldcp == NULL) {
28681ae08745Sheppo 			DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel hdl\n");
28691ae08745Sheppo 			mutex_exit(&ldcssp->lock);
28701ae08745Sheppo 			mutex_exit(&ldcp->lock);
28711ae08745Sheppo 			return (EINVAL);
28721ae08745Sheppo 		}
28731ae08745Sheppo 	}
28741ae08745Sheppo 
28751ae08745Sheppo 	ldcssp->channel_count--;
28761ae08745Sheppo 
28771ae08745Sheppo 	mutex_exit(&ldcssp->lock);
28781ae08745Sheppo 
28791ae08745Sheppo 	/* Free the map table for this channel */
28801ae08745Sheppo 	if (ldcp->mtbl) {
2881*a704fb2dSToomas Soome 		(void) hv_ldc_set_map_table(ldcp->id, 0, 0);
28823af08d82Slm66018 		if (ldcp->mtbl->contigmem)
28831ae08745Sheppo 			contig_mem_free(ldcp->mtbl->table, ldcp->mtbl->size);
28843af08d82Slm66018 		else
28853af08d82Slm66018 			kmem_free(ldcp->mtbl->table, ldcp->mtbl->size);
28861ae08745Sheppo 		mutex_destroy(&ldcp->mtbl->lock);
28871ae08745Sheppo 		kmem_free(ldcp->mtbl, sizeof (ldc_mtbl_t));
28881ae08745Sheppo 	}
28891ae08745Sheppo 
28901ae08745Sheppo 	/* Destroy descriptor ring and memory handle list lock */
28911ae08745Sheppo 	mutex_destroy(&ldcp->exp_dlist_lock);
28921ae08745Sheppo 	mutex_destroy(&ldcp->imp_dlist_lock);
28931ae08745Sheppo 	mutex_destroy(&ldcp->mlist_lock);
28941ae08745Sheppo 
289520ae46ebSha137994 	/* Free the stream buffer for RELIABLE_MODE */
289620ae46ebSha137994 	if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp)
28971ae08745Sheppo 		kmem_free(ldcp->stream_bufferp, ldcp->mtu);
28981ae08745Sheppo 
28991ae08745Sheppo 	/* Free the RX queue */
29001ae08745Sheppo 	contig_mem_free((caddr_t)ldcp->rx_q_va,
29011ae08745Sheppo 	    (ldcp->rx_q_entries << LDC_PACKET_SHIFT));
29021ae08745Sheppo 	ldcp->tstate &= ~TS_RXQ_RDY;
29031ae08745Sheppo 
290458283286Sha137994 	/* Free the RX data queue */
290520ae46ebSha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
290658283286Sha137994 		kmem_free((caddr_t)ldcp->rx_dq_va,
290758283286Sha137994 		    (ldcp->rx_dq_entries << LDC_PACKET_SHIFT));
290858283286Sha137994 	}
290958283286Sha137994 
29101ae08745Sheppo 	/* Free the TX queue */
29111ae08745Sheppo 	contig_mem_free((caddr_t)ldcp->tx_q_va,
29121ae08745Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
29131ae08745Sheppo 	ldcp->tstate &= ~TS_TXQ_RDY;
29141ae08745Sheppo 
29151ae08745Sheppo 	mutex_exit(&ldcp->lock);
29161ae08745Sheppo 
29171ae08745Sheppo 	/* Destroy mutex */
2918d10e4ef2Snarayan 	mutex_destroy(&ldcp->tx_lock);
29191ae08745Sheppo 	mutex_destroy(&ldcp->lock);
29201ae08745Sheppo 
29211ae08745Sheppo 	/* free channel structure */
29221ae08745Sheppo 	kmem_free(ldcp, sizeof (ldc_chan_t));
29231ae08745Sheppo 
29241ae08745Sheppo 	D1(id, "ldc_fini: (0x%llx) channel finalized\n", id);
29251ae08745Sheppo 
29261ae08745Sheppo 	return (0);
29271ae08745Sheppo }
29281ae08745Sheppo 
29291ae08745Sheppo /*
29301ae08745Sheppo  * Open the LDC channel for use. It registers the TX/RX queues
29311ae08745Sheppo  * with the Hypervisor. It also specifies the interrupt number
29321ae08745Sheppo  * and target CPU for this channel
29331ae08745Sheppo  */
29341ae08745Sheppo int
ldc_open(ldc_handle_t handle)29351ae08745Sheppo ldc_open(ldc_handle_t handle)
29361ae08745Sheppo {
29371ae08745Sheppo 	ldc_chan_t	*ldcp;
29381ae08745Sheppo 	int		rv;
29391ae08745Sheppo 
2940*a704fb2dSToomas Soome 	if (handle == 0) {
29411ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_open: invalid channel handle\n");
29421ae08745Sheppo 		return (EINVAL);
29431ae08745Sheppo 	}
29441ae08745Sheppo 
29451ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
29461ae08745Sheppo 
29471ae08745Sheppo 	mutex_enter(&ldcp->lock);
29481ae08745Sheppo 
29491ae08745Sheppo 	if (ldcp->tstate < TS_INIT) {
29501ae08745Sheppo 		DWARN(ldcp->id,
29511ae08745Sheppo 		    "ldc_open: (0x%llx) channel not initialized\n", ldcp->id);
29521ae08745Sheppo 		mutex_exit(&ldcp->lock);
29531ae08745Sheppo 		return (EFAULT);
29541ae08745Sheppo 	}
29553af08d82Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) >= TS_OPEN) {
29561ae08745Sheppo 		DWARN(ldcp->id,
29571ae08745Sheppo 		    "ldc_open: (0x%llx) channel is already open\n", ldcp->id);
29581ae08745Sheppo 		mutex_exit(&ldcp->lock);
29591ae08745Sheppo 		return (EFAULT);
29601ae08745Sheppo 	}
29611ae08745Sheppo 
29621ae08745Sheppo 	/*
29631ae08745Sheppo 	 * Unregister/Register the tx queue with the hypervisor
29641ae08745Sheppo 	 */
2965*a704fb2dSToomas Soome 	rv = hv_ldc_tx_qconf(ldcp->id, 0, 0);
29661ae08745Sheppo 	if (rv) {
29671ae08745Sheppo 		cmn_err(CE_WARN,
29681ae08745Sheppo 		    "ldc_open: (0x%lx) channel tx queue unconf failed\n",
29691ae08745Sheppo 		    ldcp->id);
29701ae08745Sheppo 		mutex_exit(&ldcp->lock);
29711ae08745Sheppo 		return (EIO);
29721ae08745Sheppo 	}
29731ae08745Sheppo 
29741ae08745Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
29751ae08745Sheppo 	if (rv) {
29761ae08745Sheppo 		cmn_err(CE_WARN,
29771ae08745Sheppo 		    "ldc_open: (0x%lx) channel tx queue conf failed\n",
29781ae08745Sheppo 		    ldcp->id);
29791ae08745Sheppo 		mutex_exit(&ldcp->lock);
29801ae08745Sheppo 		return (EIO);
29811ae08745Sheppo 	}
29821ae08745Sheppo 
29831ae08745Sheppo 	D2(ldcp->id, "ldc_open: (0x%llx) registered tx queue with LDC\n",
29841ae08745Sheppo 	    ldcp->id);
29851ae08745Sheppo 
29861ae08745Sheppo 	/*
29871ae08745Sheppo 	 * Unregister/Register the rx queue with the hypervisor
29881ae08745Sheppo 	 */
2989*a704fb2dSToomas Soome 	rv = hv_ldc_rx_qconf(ldcp->id, 0, 0);
29901ae08745Sheppo 	if (rv) {
29911ae08745Sheppo 		cmn_err(CE_WARN,
29921ae08745Sheppo 		    "ldc_open: (0x%lx) channel rx queue unconf failed\n",
29931ae08745Sheppo 		    ldcp->id);
29941ae08745Sheppo 		mutex_exit(&ldcp->lock);
29951ae08745Sheppo 		return (EIO);
29961ae08745Sheppo 	}
29971ae08745Sheppo 
29981ae08745Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, ldcp->rx_q_entries);
29991ae08745Sheppo 	if (rv) {
30001ae08745Sheppo 		cmn_err(CE_WARN,
30011ae08745Sheppo 		    "ldc_open: (0x%lx) channel rx queue conf failed\n",
30021ae08745Sheppo 		    ldcp->id);
30031ae08745Sheppo 		mutex_exit(&ldcp->lock);
30041ae08745Sheppo 		return (EIO);
30051ae08745Sheppo 	}
30061ae08745Sheppo 
30071ae08745Sheppo 	D2(ldcp->id, "ldc_open: (0x%llx) registered rx queue with LDC\n",
30081ae08745Sheppo 	    ldcp->id);
30091ae08745Sheppo 
30101ae08745Sheppo 	ldcp->tstate |= TS_QCONF_RDY;
30111ae08745Sheppo 
30121ae08745Sheppo 	/* Register the channel with the channel nexus */
30131ae08745Sheppo 	rv = i_ldc_register_channel(ldcp);
30141ae08745Sheppo 	if (rv && rv != EAGAIN) {
30151ae08745Sheppo 		cmn_err(CE_WARN,
30161ae08745Sheppo 		    "ldc_open: (0x%lx) channel register failed\n", ldcp->id);
30175699897cSHaik Aftandilian 		ldcp->tstate &= ~TS_QCONF_RDY;
3018*a704fb2dSToomas Soome 		(void) hv_ldc_tx_qconf(ldcp->id, 0, 0);
3019*a704fb2dSToomas Soome 		(void) hv_ldc_rx_qconf(ldcp->id, 0, 0);
30201ae08745Sheppo 		mutex_exit(&ldcp->lock);
30211ae08745Sheppo 		return (EIO);
30221ae08745Sheppo 	}
30231ae08745Sheppo 
30241ae08745Sheppo 	/* mark channel in OPEN state */
30251ae08745Sheppo 	ldcp->status = LDC_OPEN;
30261ae08745Sheppo 
30271ae08745Sheppo 	/* Read channel state */
30281ae08745Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
30291ae08745Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
30301ae08745Sheppo 	if (rv) {
30311ae08745Sheppo 		cmn_err(CE_WARN,
30321ae08745Sheppo 		    "ldc_open: (0x%lx) cannot read channel state\n",
30331ae08745Sheppo 		    ldcp->id);
30341ae08745Sheppo 		(void) i_ldc_unregister_channel(ldcp);
30355699897cSHaik Aftandilian 		ldcp->tstate &= ~TS_QCONF_RDY;
3036*a704fb2dSToomas Soome 		(void) hv_ldc_tx_qconf(ldcp->id, 0, 0);
3037*a704fb2dSToomas Soome 		(void) hv_ldc_rx_qconf(ldcp->id, 0, 0);
30381ae08745Sheppo 		mutex_exit(&ldcp->lock);
30391ae08745Sheppo 		return (EIO);
30401ae08745Sheppo 	}
30411ae08745Sheppo 
30421ae08745Sheppo 	/*
304320ae46ebSha137994 	 * set the ACKd head to current head location for reliable
30441ae08745Sheppo 	 */
30451ae08745Sheppo 	ldcp->tx_ackd_head = ldcp->tx_head;
30461ae08745Sheppo 
30471ae08745Sheppo 	/* mark channel ready if HV report link is UP (peer alloc'd Rx queue) */
30481ae08745Sheppo 	if (ldcp->link_state == LDC_CHANNEL_UP ||
30491ae08745Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
30501ae08745Sheppo 		ldcp->tstate |= TS_LINK_READY;
30511ae08745Sheppo 		ldcp->status = LDC_READY;
30521ae08745Sheppo 	}
30531ae08745Sheppo 
30541ae08745Sheppo 	/*
30551ae08745Sheppo 	 * if channel is being opened in RAW mode - no handshake is needed
30561ae08745Sheppo 	 * switch the channel READY and UP state
30571ae08745Sheppo 	 */
30581ae08745Sheppo 	if (ldcp->mode == LDC_MODE_RAW) {
30591ae08745Sheppo 		ldcp->tstate = TS_UP;	/* set bits associated with LDC UP */
30601ae08745Sheppo 		ldcp->status = LDC_UP;
30611ae08745Sheppo 	}
30621ae08745Sheppo 
30631ae08745Sheppo 	mutex_exit(&ldcp->lock);
30641ae08745Sheppo 
30651ae08745Sheppo 	/*
30661ae08745Sheppo 	 * Increment number of open channels
30671ae08745Sheppo 	 */
30681ae08745Sheppo 	mutex_enter(&ldcssp->lock);
30691ae08745Sheppo 	ldcssp->channels_open++;
30701ae08745Sheppo 	mutex_exit(&ldcssp->lock);
30711ae08745Sheppo 
3072cb112a14Slm66018 	D1(ldcp->id,
30733af08d82Slm66018 	    "ldc_open: (0x%llx) channel (0x%p) open for use "
30743af08d82Slm66018 	    "(tstate=0x%x, status=0x%x)\n",
30753af08d82Slm66018 	    ldcp->id, ldcp, ldcp->tstate, ldcp->status);
30761ae08745Sheppo 
30771ae08745Sheppo 	return (0);
30781ae08745Sheppo }
30791ae08745Sheppo 
30801ae08745Sheppo /*
30811ae08745Sheppo  * Close the LDC connection. It will return EBUSY if there
30821ae08745Sheppo  * are memory segments or descriptor rings either bound to or
30831ae08745Sheppo  * mapped over the channel
30841ae08745Sheppo  */
30851ae08745Sheppo int
ldc_close(ldc_handle_t handle)30861ae08745Sheppo ldc_close(ldc_handle_t handle)
30871ae08745Sheppo {
30881ae08745Sheppo 	ldc_chan_t	*ldcp;
3089d10e4ef2Snarayan 	int		rv = 0, retries = 0;
30901ae08745Sheppo 	boolean_t	chk_done = B_FALSE;
30911ae08745Sheppo 
3092*a704fb2dSToomas Soome 	if (handle == 0) {
30931ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_close: invalid channel handle\n");
30941ae08745Sheppo 		return (EINVAL);
30951ae08745Sheppo 	}
30961ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
30971ae08745Sheppo 
30981ae08745Sheppo 	mutex_enter(&ldcp->lock);
30991ae08745Sheppo 
31001ae08745Sheppo 	/* return error if channel is not open */
31013af08d82Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) < TS_OPEN) {
31021ae08745Sheppo 		DWARN(ldcp->id,
31031ae08745Sheppo 		    "ldc_close: (0x%llx) channel is not open\n", ldcp->id);
31041ae08745Sheppo 		mutex_exit(&ldcp->lock);
31051ae08745Sheppo 		return (EFAULT);
31061ae08745Sheppo 	}
31071ae08745Sheppo 
31081ae08745Sheppo 	/* if any memory handles, drings, are bound or mapped cannot close */
31091ae08745Sheppo 	if (ldcp->mhdl_list != NULL) {
31101ae08745Sheppo 		DWARN(ldcp->id,
31111ae08745Sheppo 		    "ldc_close: (0x%llx) channel has bound memory handles\n",
31121ae08745Sheppo 		    ldcp->id);
31131ae08745Sheppo 		mutex_exit(&ldcp->lock);
31141ae08745Sheppo 		return (EBUSY);
31151ae08745Sheppo 	}
31161ae08745Sheppo 	if (ldcp->exp_dring_list != NULL) {
31171ae08745Sheppo 		DWARN(ldcp->id,
31181ae08745Sheppo 		    "ldc_close: (0x%llx) channel has bound descriptor rings\n",
31191ae08745Sheppo 		    ldcp->id);
31201ae08745Sheppo 		mutex_exit(&ldcp->lock);
31211ae08745Sheppo 		return (EBUSY);
31221ae08745Sheppo 	}
31231ae08745Sheppo 	if (ldcp->imp_dring_list != NULL) {
31241ae08745Sheppo 		DWARN(ldcp->id,
31251ae08745Sheppo 		    "ldc_close: (0x%llx) channel has mapped descriptor rings\n",
31261ae08745Sheppo 		    ldcp->id);
31271ae08745Sheppo 		mutex_exit(&ldcp->lock);
31281ae08745Sheppo 		return (EBUSY);
31291ae08745Sheppo 	}
31301ae08745Sheppo 
31314d39be2bSsg70180 	if (ldcp->cb_inprogress) {
31324d39be2bSsg70180 		DWARN(ldcp->id, "ldc_close: (0x%llx) callback active\n",
31334d39be2bSsg70180 		    ldcp->id);
31344d39be2bSsg70180 		mutex_exit(&ldcp->lock);
31354d39be2bSsg70180 		return (EWOULDBLOCK);
31364d39be2bSsg70180 	}
31374d39be2bSsg70180 
3138d10e4ef2Snarayan 	/* Obtain Tx lock */
3139d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
3140d10e4ef2Snarayan 
31411ae08745Sheppo 	/*
31421ae08745Sheppo 	 * Wait for pending transmits to complete i.e Tx queue to drain
31431ae08745Sheppo 	 * if there are pending pkts - wait 1 ms and retry again
31441ae08745Sheppo 	 */
31451ae08745Sheppo 	for (;;) {
31461ae08745Sheppo 
31471ae08745Sheppo 		rv = hv_ldc_tx_get_state(ldcp->id,
31481ae08745Sheppo 		    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
31491ae08745Sheppo 		if (rv) {
31501ae08745Sheppo 			cmn_err(CE_WARN,
31511ae08745Sheppo 			    "ldc_close: (0x%lx) cannot read qptrs\n", ldcp->id);
3152d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
31531ae08745Sheppo 			mutex_exit(&ldcp->lock);
31541ae08745Sheppo 			return (EIO);
31551ae08745Sheppo 		}
31561ae08745Sheppo 
31571ae08745Sheppo 		if (ldcp->tx_head == ldcp->tx_tail ||
31581ae08745Sheppo 		    ldcp->link_state != LDC_CHANNEL_UP) {
31591ae08745Sheppo 			break;
31601ae08745Sheppo 		}
31611ae08745Sheppo 
31621ae08745Sheppo 		if (chk_done) {
31631ae08745Sheppo 			DWARN(ldcp->id,
31641ae08745Sheppo 			    "ldc_close: (0x%llx) Tx queue drain timeout\n",
31651ae08745Sheppo 			    ldcp->id);
31661ae08745Sheppo 			break;
31671ae08745Sheppo 		}
31681ae08745Sheppo 
31691ae08745Sheppo 		/* wait for one ms and try again */
31701ae08745Sheppo 		delay(drv_usectohz(1000));
31711ae08745Sheppo 		chk_done = B_TRUE;
31721ae08745Sheppo 	}
31731ae08745Sheppo 
31741ae08745Sheppo 	/*
3175a8ea4edeSnarayan 	 * Drain the Tx and Rx queues as we are closing the
3176a8ea4edeSnarayan 	 * channel. We dont care about any pending packets.
3177a8ea4edeSnarayan 	 * We have to also drain the queue prior to clearing
3178a8ea4edeSnarayan 	 * pending interrupts, otherwise the HV will trigger
3179a8ea4edeSnarayan 	 * an interrupt the moment the interrupt state is
3180a8ea4edeSnarayan 	 * cleared.
31813af08d82Slm66018 	 */
31823af08d82Slm66018 	(void) i_ldc_txq_reconf(ldcp);
3183305dbad4SKevin Crowe 	i_ldc_rxq_drain(ldcp);
31843af08d82Slm66018 
31853af08d82Slm66018 	/*
31861ae08745Sheppo 	 * Unregister the channel with the nexus
31871ae08745Sheppo 	 */
3188d10e4ef2Snarayan 	while ((rv = i_ldc_unregister_channel(ldcp)) != 0) {
3189d10e4ef2Snarayan 
3190d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
31911ae08745Sheppo 		mutex_exit(&ldcp->lock);
3192d10e4ef2Snarayan 
3193d10e4ef2Snarayan 		/* if any error other than EAGAIN return back */
3194a8ea4edeSnarayan 		if (rv != EAGAIN || retries >= ldc_max_retries) {
3195d10e4ef2Snarayan 			cmn_err(CE_WARN,
3196d10e4ef2Snarayan 			    "ldc_close: (0x%lx) unregister failed, %d\n",
3197d10e4ef2Snarayan 			    ldcp->id, rv);
31981ae08745Sheppo 			return (rv);
31991ae08745Sheppo 		}
32001ae08745Sheppo 
32011ae08745Sheppo 		/*
3202d10e4ef2Snarayan 		 * As there could be pending interrupts we need
3203d10e4ef2Snarayan 		 * to wait and try again
3204d10e4ef2Snarayan 		 */
32054d39be2bSsg70180 		drv_usecwait(ldc_close_delay);
3206d10e4ef2Snarayan 		mutex_enter(&ldcp->lock);
3207d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
3208d10e4ef2Snarayan 		retries++;
3209d10e4ef2Snarayan 	}
3210d10e4ef2Snarayan 
32115699897cSHaik Aftandilian 	ldcp->tstate &= ~TS_QCONF_RDY;
32125699897cSHaik Aftandilian 
3213d10e4ef2Snarayan 	/*
32141ae08745Sheppo 	 * Unregister queues
32151ae08745Sheppo 	 */
3216*a704fb2dSToomas Soome 	rv = hv_ldc_tx_qconf(ldcp->id, 0, 0);
32171ae08745Sheppo 	if (rv) {
32181ae08745Sheppo 		cmn_err(CE_WARN,
32191ae08745Sheppo 		    "ldc_close: (0x%lx) channel TX queue unconf failed\n",
32201ae08745Sheppo 		    ldcp->id);
3221d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
32221ae08745Sheppo 		mutex_exit(&ldcp->lock);
32231ae08745Sheppo 		return (EIO);
32241ae08745Sheppo 	}
3225*a704fb2dSToomas Soome 	rv = hv_ldc_rx_qconf(ldcp->id, 0, 0);
32261ae08745Sheppo 	if (rv) {
32271ae08745Sheppo 		cmn_err(CE_WARN,
32281ae08745Sheppo 		    "ldc_close: (0x%lx) channel RX queue unconf failed\n",
32291ae08745Sheppo 		    ldcp->id);
3230d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
32311ae08745Sheppo 		mutex_exit(&ldcp->lock);
32321ae08745Sheppo 		return (EIO);
32331ae08745Sheppo 	}
32341ae08745Sheppo 
32351ae08745Sheppo 	/* Reset channel state information */
32361ae08745Sheppo 	i_ldc_reset_state(ldcp);
32371ae08745Sheppo 
32381ae08745Sheppo 	/* Mark channel as down and in initialized state */
32391ae08745Sheppo 	ldcp->tx_ackd_head = 0;
32401ae08745Sheppo 	ldcp->tx_head = 0;
32413af08d82Slm66018 	ldcp->tstate = TS_IN_RESET|TS_INIT;
32421ae08745Sheppo 	ldcp->status = LDC_INIT;
32431ae08745Sheppo 
3244d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
32451ae08745Sheppo 	mutex_exit(&ldcp->lock);
32461ae08745Sheppo 
32471ae08745Sheppo 	/* Decrement number of open channels */
32481ae08745Sheppo 	mutex_enter(&ldcssp->lock);
32491ae08745Sheppo 	ldcssp->channels_open--;
32501ae08745Sheppo 	mutex_exit(&ldcssp->lock);
32511ae08745Sheppo 
32521ae08745Sheppo 	D1(ldcp->id, "ldc_close: (0x%llx) channel closed\n", ldcp->id);
32531ae08745Sheppo 
32541ae08745Sheppo 	return (0);
32551ae08745Sheppo }
32561ae08745Sheppo 
32571ae08745Sheppo /*
32581ae08745Sheppo  * Register channel callback
32591ae08745Sheppo  */
32601ae08745Sheppo int
ldc_reg_callback(ldc_handle_t handle,uint_t (* cb)(uint64_t event,caddr_t arg),caddr_t arg)32611ae08745Sheppo ldc_reg_callback(ldc_handle_t handle,
32621ae08745Sheppo     uint_t(*cb)(uint64_t event, caddr_t arg), caddr_t arg)
32631ae08745Sheppo {
32641ae08745Sheppo 	ldc_chan_t *ldcp;
32651ae08745Sheppo 
3266*a704fb2dSToomas Soome 	if (handle == 0) {
32671ae08745Sheppo 		DWARN(DBG_ALL_LDCS,
32681ae08745Sheppo 		    "ldc_reg_callback: invalid channel handle\n");
32691ae08745Sheppo 		return (EINVAL);
32701ae08745Sheppo 	}
32711ae08745Sheppo 	if (((uint64_t)cb) < KERNELBASE) {
32721ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_reg_callback: invalid callback\n");
32731ae08745Sheppo 		return (EINVAL);
32741ae08745Sheppo 	}
32751ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
32761ae08745Sheppo 
32771ae08745Sheppo 	mutex_enter(&ldcp->lock);
32781ae08745Sheppo 
32791ae08745Sheppo 	if (ldcp->cb) {
32801ae08745Sheppo 		DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback exists\n",
32811ae08745Sheppo 		    ldcp->id);
32821ae08745Sheppo 		mutex_exit(&ldcp->lock);
32831ae08745Sheppo 		return (EIO);
32841ae08745Sheppo 	}
32851ae08745Sheppo 	if (ldcp->cb_inprogress) {
32861ae08745Sheppo 		DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback active\n",
32871ae08745Sheppo 		    ldcp->id);
32881ae08745Sheppo 		mutex_exit(&ldcp->lock);
32891ae08745Sheppo 		return (EWOULDBLOCK);
32901ae08745Sheppo 	}
32911ae08745Sheppo 
32921ae08745Sheppo 	ldcp->cb = cb;
32931ae08745Sheppo 	ldcp->cb_arg = arg;
32941ae08745Sheppo 	ldcp->cb_enabled = B_TRUE;
32951ae08745Sheppo 
32961ae08745Sheppo 	D1(ldcp->id,
32971ae08745Sheppo 	    "ldc_reg_callback: (0x%llx) registered callback for channel\n",
32981ae08745Sheppo 	    ldcp->id);
32991ae08745Sheppo 
33001ae08745Sheppo 	mutex_exit(&ldcp->lock);
33011ae08745Sheppo 
33021ae08745Sheppo 	return (0);
33031ae08745Sheppo }
33041ae08745Sheppo 
33051ae08745Sheppo /*
33061ae08745Sheppo  * Unregister channel callback
33071ae08745Sheppo  */
33081ae08745Sheppo int
ldc_unreg_callback(ldc_handle_t handle)33091ae08745Sheppo ldc_unreg_callback(ldc_handle_t handle)
33101ae08745Sheppo {
33111ae08745Sheppo 	ldc_chan_t *ldcp;
33121ae08745Sheppo 
3313*a704fb2dSToomas Soome 	if (handle == 0) {
33141ae08745Sheppo 		DWARN(DBG_ALL_LDCS,
33151ae08745Sheppo 		    "ldc_unreg_callback: invalid channel handle\n");
33161ae08745Sheppo 		return (EINVAL);
33171ae08745Sheppo 	}
33181ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
33191ae08745Sheppo 
33201ae08745Sheppo 	mutex_enter(&ldcp->lock);
33211ae08745Sheppo 
33221ae08745Sheppo 	if (ldcp->cb == NULL) {
33231ae08745Sheppo 		DWARN(ldcp->id,
33241ae08745Sheppo 		    "ldc_unreg_callback: (0x%llx) no callback exists\n",
33251ae08745Sheppo 		    ldcp->id);
33261ae08745Sheppo 		mutex_exit(&ldcp->lock);
33271ae08745Sheppo 		return (EIO);
33281ae08745Sheppo 	}
33291ae08745Sheppo 	if (ldcp->cb_inprogress) {
33301ae08745Sheppo 		DWARN(ldcp->id,
33311ae08745Sheppo 		    "ldc_unreg_callback: (0x%llx) callback active\n",
33321ae08745Sheppo 		    ldcp->id);
33331ae08745Sheppo 		mutex_exit(&ldcp->lock);
33341ae08745Sheppo 		return (EWOULDBLOCK);
33351ae08745Sheppo 	}
33361ae08745Sheppo 
33371ae08745Sheppo 	ldcp->cb = NULL;
33381ae08745Sheppo 	ldcp->cb_arg = NULL;
33391ae08745Sheppo 	ldcp->cb_enabled = B_FALSE;
33401ae08745Sheppo 
33411ae08745Sheppo 	D1(ldcp->id,
33421ae08745Sheppo 	    "ldc_unreg_callback: (0x%llx) unregistered callback for channel\n",
33431ae08745Sheppo 	    ldcp->id);
33441ae08745Sheppo 
33451ae08745Sheppo 	mutex_exit(&ldcp->lock);
33461ae08745Sheppo 
33471ae08745Sheppo 	return (0);
33481ae08745Sheppo }
33491ae08745Sheppo 
33501ae08745Sheppo 
33511ae08745Sheppo /*
33521ae08745Sheppo  * Bring a channel up by initiating a handshake with the peer
33531ae08745Sheppo  * This call is asynchronous. It will complete at a later point
33541ae08745Sheppo  * in time when the peer responds back with an RTR.
33551ae08745Sheppo  */
33561ae08745Sheppo int
ldc_up(ldc_handle_t handle)33571ae08745Sheppo ldc_up(ldc_handle_t handle)
33581ae08745Sheppo {
33591ae08745Sheppo 	int		rv;
33601ae08745Sheppo 	ldc_chan_t	*ldcp;
33611ae08745Sheppo 	ldc_msg_t	*ldcmsg;
336257e6a936Ssb155480 	uint64_t	tx_tail, tstate, link_state;
33631ae08745Sheppo 
3364*a704fb2dSToomas Soome 	if (handle == 0) {
33651ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_up: invalid channel handle\n");
33661ae08745Sheppo 		return (EINVAL);
33671ae08745Sheppo 	}
33681ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
33691ae08745Sheppo 
33701ae08745Sheppo 	mutex_enter(&ldcp->lock);
33711ae08745Sheppo 
33723af08d82Slm66018 	D1(ldcp->id, "ldc_up: (0x%llx) doing channel UP\n", ldcp->id);
33733af08d82Slm66018 
33743af08d82Slm66018 	/* clear the reset state */
33753af08d82Slm66018 	tstate = ldcp->tstate;
33763af08d82Slm66018 	ldcp->tstate &= ~TS_IN_RESET;
33773af08d82Slm66018 
33781ae08745Sheppo 	if (ldcp->tstate == TS_UP) {
33793af08d82Slm66018 		DWARN(ldcp->id,
33801ae08745Sheppo 		    "ldc_up: (0x%llx) channel is already in UP state\n",
33811ae08745Sheppo 		    ldcp->id);
33823af08d82Slm66018 
33833af08d82Slm66018 		/* mark channel as up */
33843af08d82Slm66018 		ldcp->status = LDC_UP;
33853af08d82Slm66018 
33863af08d82Slm66018 		/*
33873af08d82Slm66018 		 * if channel was in reset state and there was
33883af08d82Slm66018 		 * pending data clear interrupt state. this will
33893af08d82Slm66018 		 * trigger an interrupt, causing the RX handler to
33903af08d82Slm66018 		 * to invoke the client's callback
33913af08d82Slm66018 		 */
33923af08d82Slm66018 		if ((tstate & TS_IN_RESET) &&
33933af08d82Slm66018 		    ldcp->rx_intr_state == LDC_INTR_PEND) {
3394cb112a14Slm66018 			D1(ldcp->id,
33953af08d82Slm66018 			    "ldc_up: (0x%llx) channel has pending data, "
33963af08d82Slm66018 			    "clearing interrupt\n", ldcp->id);
33973af08d82Slm66018 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
33983af08d82Slm66018 		}
33993af08d82Slm66018 
34001ae08745Sheppo 		mutex_exit(&ldcp->lock);
34011ae08745Sheppo 		return (0);
34021ae08745Sheppo 	}
34031ae08745Sheppo 
34041ae08745Sheppo 	/* if the channel is in RAW mode - mark it as UP, if READY */
34051ae08745Sheppo 	if (ldcp->mode == LDC_MODE_RAW && ldcp->tstate >= TS_READY) {
34061ae08745Sheppo 		ldcp->tstate = TS_UP;
34071ae08745Sheppo 		mutex_exit(&ldcp->lock);
34081ae08745Sheppo 		return (0);
34091ae08745Sheppo 	}
34101ae08745Sheppo 
34111ae08745Sheppo 	/* Don't start another handshake if there is one in progress */
34121ae08745Sheppo 	if (ldcp->hstate) {
34133af08d82Slm66018 		D1(ldcp->id,
34141ae08745Sheppo 		    "ldc_up: (0x%llx) channel handshake in progress\n",
34151ae08745Sheppo 		    ldcp->id);
34161ae08745Sheppo 		mutex_exit(&ldcp->lock);
34171ae08745Sheppo 		return (0);
34181ae08745Sheppo 	}
34191ae08745Sheppo 
3420d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
3421d10e4ef2Snarayan 
342257e6a936Ssb155480 	/* save current link state */
342357e6a936Ssb155480 	link_state = ldcp->link_state;
342457e6a936Ssb155480 
34251ae08745Sheppo 	/* get the current tail for the LDC msg */
34261ae08745Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
34271ae08745Sheppo 	if (rv) {
3428cb112a14Slm66018 		D1(ldcp->id, "ldc_up: (0x%llx) cannot initiate handshake\n",
34291ae08745Sheppo 		    ldcp->id);
3430d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
34311ae08745Sheppo 		mutex_exit(&ldcp->lock);
34321ae08745Sheppo 		return (ECONNREFUSED);
34331ae08745Sheppo 	}
34341ae08745Sheppo 
343557e6a936Ssb155480 	/*
343657e6a936Ssb155480 	 * If i_ldc_get_tx_tail() changed link_state to either RESET or UP,
343757e6a936Ssb155480 	 * from a previous state of DOWN, then mark the channel as
343857e6a936Ssb155480 	 * being ready for handshake.
343957e6a936Ssb155480 	 */
344057e6a936Ssb155480 	if ((link_state == LDC_CHANNEL_DOWN) &&
344157e6a936Ssb155480 	    (link_state != ldcp->link_state)) {
344257e6a936Ssb155480 
344357e6a936Ssb155480 		ASSERT((ldcp->link_state == LDC_CHANNEL_RESET) ||
344457e6a936Ssb155480 		    (ldcp->link_state == LDC_CHANNEL_UP));
344557e6a936Ssb155480 
344657e6a936Ssb155480 		if (ldcp->mode == LDC_MODE_RAW) {
344757e6a936Ssb155480 			ldcp->status = LDC_UP;
344857e6a936Ssb155480 			ldcp->tstate = TS_UP;
344957e6a936Ssb155480 			mutex_exit(&ldcp->tx_lock);
345057e6a936Ssb155480 			mutex_exit(&ldcp->lock);
345157e6a936Ssb155480 			return (0);
345257e6a936Ssb155480 		} else {
345357e6a936Ssb155480 			ldcp->status = LDC_READY;
345457e6a936Ssb155480 			ldcp->tstate |= TS_LINK_READY;
345557e6a936Ssb155480 		}
345657e6a936Ssb155480 
345757e6a936Ssb155480 	}
345857e6a936Ssb155480 
34591ae08745Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
34601ae08745Sheppo 	ZERO_PKT(ldcmsg);
34611ae08745Sheppo 
34621ae08745Sheppo 	ldcmsg->type = LDC_CTRL;
34631ae08745Sheppo 	ldcmsg->stype = LDC_INFO;
34641ae08745Sheppo 	ldcmsg->ctrl = LDC_VER;
34651ae08745Sheppo 	ldcp->next_vidx = 0;
34661ae08745Sheppo 	bcopy(&ldc_versions[0], ldcmsg->udata, sizeof (ldc_versions[0]));
34671ae08745Sheppo 
34681ae08745Sheppo 	DUMP_LDC_PKT(ldcp, "ldc_up snd ver", (uint64_t)ldcmsg);
34691ae08745Sheppo 
34701ae08745Sheppo 	/* initiate the send by calling into HV and set the new tail */
34711ae08745Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
34721ae08745Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
34731ae08745Sheppo 
34741ae08745Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
34751ae08745Sheppo 	if (rv) {
34761ae08745Sheppo 		DWARN(ldcp->id,
34771ae08745Sheppo 		    "ldc_up: (0x%llx) cannot initiate handshake rv=%d\n",
34781ae08745Sheppo 		    ldcp->id, rv);
3479d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
34801ae08745Sheppo 		mutex_exit(&ldcp->lock);
34811ae08745Sheppo 		return (rv);
34821ae08745Sheppo 	}
34831ae08745Sheppo 
34840a55fbb7Slm66018 	ldcp->hstate |= TS_SENT_VER;
34851ae08745Sheppo 	ldcp->tx_tail = tx_tail;
34861ae08745Sheppo 	D1(ldcp->id, "ldc_up: (0x%llx) channel up initiated\n", ldcp->id);
34871ae08745Sheppo 
3488d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
34891ae08745Sheppo 	mutex_exit(&ldcp->lock);
34901ae08745Sheppo 
34911ae08745Sheppo 	return (rv);
34921ae08745Sheppo }
34931ae08745Sheppo 
34941ae08745Sheppo 
34951ae08745Sheppo /*
3496e1ebb9ecSlm66018  * Bring a channel down by resetting its state and queues
34971ae08745Sheppo  */
34981ae08745Sheppo int
ldc_down(ldc_handle_t handle)3499e1ebb9ecSlm66018 ldc_down(ldc_handle_t handle)
35001ae08745Sheppo {
35011ae08745Sheppo 	ldc_chan_t	*ldcp;
35021ae08745Sheppo 
3503*a704fb2dSToomas Soome 	if (handle == 0) {
3504e1ebb9ecSlm66018 		DWARN(DBG_ALL_LDCS, "ldc_down: invalid channel handle\n");
35051ae08745Sheppo 		return (EINVAL);
35061ae08745Sheppo 	}
35071ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
35081ae08745Sheppo 	mutex_enter(&ldcp->lock);
3509d10e4ef2Snarayan 	mutex_enter(&ldcp->tx_lock);
35103af08d82Slm66018 	i_ldc_reset(ldcp, B_TRUE);
3511d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
35121ae08745Sheppo 	mutex_exit(&ldcp->lock);
35131ae08745Sheppo 
35141ae08745Sheppo 	return (0);
35151ae08745Sheppo }
35161ae08745Sheppo 
35171ae08745Sheppo /*
35181ae08745Sheppo  * Get the current channel status
35191ae08745Sheppo  */
35201ae08745Sheppo int
ldc_status(ldc_handle_t handle,ldc_status_t * status)35211ae08745Sheppo ldc_status(ldc_handle_t handle, ldc_status_t *status)
35221ae08745Sheppo {
35231ae08745Sheppo 	ldc_chan_t *ldcp;
35241ae08745Sheppo 
3525*a704fb2dSToomas Soome 	if (handle == 0 || status == NULL) {
35261ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_status: invalid argument\n");
35271ae08745Sheppo 		return (EINVAL);
35281ae08745Sheppo 	}
35291ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
35301ae08745Sheppo 
35311ae08745Sheppo 	*status = ((ldc_chan_t *)handle)->status;
35321ae08745Sheppo 
3533cb112a14Slm66018 	D1(ldcp->id,
35341ae08745Sheppo 	    "ldc_status: (0x%llx) returned status %d\n", ldcp->id, *status);
35351ae08745Sheppo 	return (0);
35361ae08745Sheppo }
35371ae08745Sheppo 
35381ae08745Sheppo 
35391ae08745Sheppo /*
35401ae08745Sheppo  * Set the channel's callback mode - enable/disable callbacks
35411ae08745Sheppo  */
35421ae08745Sheppo int
ldc_set_cb_mode(ldc_handle_t handle,ldc_cb_mode_t cmode)35431ae08745Sheppo ldc_set_cb_mode(ldc_handle_t handle, ldc_cb_mode_t cmode)
35441ae08745Sheppo {
35451ae08745Sheppo 	ldc_chan_t	*ldcp;
35461ae08745Sheppo 
3547*a704fb2dSToomas Soome 	if (handle == 0) {
35481ae08745Sheppo 		DWARN(DBG_ALL_LDCS,
35491ae08745Sheppo 		    "ldc_set_intr_mode: invalid channel handle\n");
35501ae08745Sheppo 		return (EINVAL);
35511ae08745Sheppo 	}
35521ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
35531ae08745Sheppo 
35541ae08745Sheppo 	/*
35551ae08745Sheppo 	 * Record no callbacks should be invoked
35561ae08745Sheppo 	 */
35571ae08745Sheppo 	mutex_enter(&ldcp->lock);
35581ae08745Sheppo 
35591ae08745Sheppo 	switch (cmode) {
35601ae08745Sheppo 	case LDC_CB_DISABLE:
35611ae08745Sheppo 		if (!ldcp->cb_enabled) {
35621ae08745Sheppo 			DWARN(ldcp->id,
35631ae08745Sheppo 			    "ldc_set_cb_mode: (0x%llx) callbacks disabled\n",
35641ae08745Sheppo 			    ldcp->id);
35651ae08745Sheppo 			break;
35661ae08745Sheppo 		}
35671ae08745Sheppo 		ldcp->cb_enabled = B_FALSE;
35681ae08745Sheppo 
35691ae08745Sheppo 		D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) disabled callbacks\n",
35701ae08745Sheppo 		    ldcp->id);
35711ae08745Sheppo 		break;
35721ae08745Sheppo 
35731ae08745Sheppo 	case LDC_CB_ENABLE:
35741ae08745Sheppo 		if (ldcp->cb_enabled) {
35751ae08745Sheppo 			DWARN(ldcp->id,
35761ae08745Sheppo 			    "ldc_set_cb_mode: (0x%llx) callbacks enabled\n",
35771ae08745Sheppo 			    ldcp->id);
35781ae08745Sheppo 			break;
35791ae08745Sheppo 		}
35801ae08745Sheppo 		ldcp->cb_enabled = B_TRUE;
35811ae08745Sheppo 
35821ae08745Sheppo 		D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) enabled callbacks\n",
35831ae08745Sheppo 		    ldcp->id);
35841ae08745Sheppo 		break;
35851ae08745Sheppo 	}
35861ae08745Sheppo 
35871ae08745Sheppo 	mutex_exit(&ldcp->lock);
35881ae08745Sheppo 
35891ae08745Sheppo 	return (0);
35901ae08745Sheppo }
35911ae08745Sheppo 
35921ae08745Sheppo /*
35931ae08745Sheppo  * Check to see if there are packets on the incoming queue
3594e1ebb9ecSlm66018  * Will return hasdata = B_FALSE if there are no packets
35951ae08745Sheppo  */
35961ae08745Sheppo int
ldc_chkq(ldc_handle_t handle,boolean_t * hasdata)3597e1ebb9ecSlm66018 ldc_chkq(ldc_handle_t handle, boolean_t *hasdata)
35981ae08745Sheppo {
35991ae08745Sheppo 	int		rv;
36001ae08745Sheppo 	uint64_t	rx_head, rx_tail;
36011ae08745Sheppo 	ldc_chan_t	*ldcp;
36021ae08745Sheppo 
3603*a704fb2dSToomas Soome 	if (handle == 0) {
36041ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_chkq: invalid channel handle\n");
36051ae08745Sheppo 		return (EINVAL);
36061ae08745Sheppo 	}
36071ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
36081ae08745Sheppo 
3609e1ebb9ecSlm66018 	*hasdata = B_FALSE;
36101ae08745Sheppo 
36111ae08745Sheppo 	mutex_enter(&ldcp->lock);
36121ae08745Sheppo 
36131ae08745Sheppo 	if (ldcp->tstate != TS_UP) {
36141ae08745Sheppo 		D1(ldcp->id,
36151ae08745Sheppo 		    "ldc_chkq: (0x%llx) channel is not up\n", ldcp->id);
36161ae08745Sheppo 		mutex_exit(&ldcp->lock);
36171ae08745Sheppo 		return (ECONNRESET);
36181ae08745Sheppo 	}
36191ae08745Sheppo 
36201ae08745Sheppo 	/* Read packet(s) from the queue */
36211ae08745Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
36221ae08745Sheppo 	    &ldcp->link_state);
36231ae08745Sheppo 	if (rv != 0) {
36241ae08745Sheppo 		cmn_err(CE_WARN,
36251ae08745Sheppo 		    "ldc_chkq: (0x%lx) unable to read queue ptrs", ldcp->id);
36261ae08745Sheppo 		mutex_exit(&ldcp->lock);
36271ae08745Sheppo 		return (EIO);
36281ae08745Sheppo 	}
362958283286Sha137994 
36301ae08745Sheppo 	/* reset the channel state if the channel went down */
36311ae08745Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
36321ae08745Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
3633d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
36343af08d82Slm66018 		i_ldc_reset(ldcp, B_FALSE);
3635d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
36361ae08745Sheppo 		mutex_exit(&ldcp->lock);
36371ae08745Sheppo 		return (ECONNRESET);
36381ae08745Sheppo 	}
36391ae08745Sheppo 
364058283286Sha137994 	switch (ldcp->mode) {
364158283286Sha137994 	case LDC_MODE_RAW:
364258283286Sha137994 		/*
364358283286Sha137994 		 * In raw mode, there are no ctrl packets, so checking
364458283286Sha137994 		 * if the queue is non-empty is sufficient.
364558283286Sha137994 		 */
364658283286Sha137994 		*hasdata = (rx_head != rx_tail);
364758283286Sha137994 		break;
364858283286Sha137994 
364958283286Sha137994 	case LDC_MODE_UNRELIABLE:
365058283286Sha137994 		/*
365158283286Sha137994 		 * In unreliable mode, if the queue is non-empty, we need
365258283286Sha137994 		 * to check if it actually contains unread data packets.
365358283286Sha137994 		 * The queue may just contain ctrl packets.
365458283286Sha137994 		 */
3655a74caf9bSha137994 		if (rx_head != rx_tail) {
365658283286Sha137994 			*hasdata = (i_ldc_chkq(ldcp) == 0);
3657a74caf9bSha137994 			/*
3658a74caf9bSha137994 			 * If no data packets were found on the queue,
3659a74caf9bSha137994 			 * all packets must have been control packets
3660a74caf9bSha137994 			 * which will now have been processed, leaving
3661a74caf9bSha137994 			 * the queue empty. If the interrupt state
3662a74caf9bSha137994 			 * is pending, we need to clear the interrupt
3663a74caf9bSha137994 			 * here.
3664a74caf9bSha137994 			 */
3665a74caf9bSha137994 			if (*hasdata == B_FALSE &&
3666a74caf9bSha137994 			    ldcp->rx_intr_state == LDC_INTR_PEND) {
3667a74caf9bSha137994 				i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
3668a74caf9bSha137994 			}
3669a74caf9bSha137994 		}
367058283286Sha137994 		break;
367158283286Sha137994 
367220ae46ebSha137994 	case LDC_MODE_RELIABLE:
367358283286Sha137994 		/*
367420ae46ebSha137994 		 * In reliable mode, first check for 'stream_remains' > 0.
367558283286Sha137994 		 * Otherwise, if the data queue head and tail pointers
367658283286Sha137994 		 * differ, there must be data to read.
367758283286Sha137994 		 */
367858283286Sha137994 		if (ldcp->stream_remains > 0)
3679e1ebb9ecSlm66018 			*hasdata = B_TRUE;
368058283286Sha137994 		else
368158283286Sha137994 			*hasdata = (ldcp->rx_dq_head != ldcp->rx_dq_tail);
368258283286Sha137994 		break;
368358283286Sha137994 
368458283286Sha137994 	default:
368558283286Sha137994 		cmn_err(CE_WARN, "ldc_chkq: (0x%lx) unexpected channel mode "
368658283286Sha137994 		    "(0x%x)", ldcp->id, ldcp->mode);
368758283286Sha137994 		mutex_exit(&ldcp->lock);
368858283286Sha137994 		return (EIO);
36891ae08745Sheppo 	}
36901ae08745Sheppo 
36911ae08745Sheppo 	mutex_exit(&ldcp->lock);
36921ae08745Sheppo 
36931ae08745Sheppo 	return (0);
36941ae08745Sheppo }
36951ae08745Sheppo 
36961ae08745Sheppo 
36971ae08745Sheppo /*
36981ae08745Sheppo  * Read 'size' amount of bytes or less. If incoming buffer
36991ae08745Sheppo  * is more than 'size', ENOBUFS is returned.
37001ae08745Sheppo  *
37011ae08745Sheppo  * On return, size contains the number of bytes read.
37021ae08745Sheppo  */
37031ae08745Sheppo int
ldc_read(ldc_handle_t handle,caddr_t bufp,size_t * sizep)37041ae08745Sheppo ldc_read(ldc_handle_t handle, caddr_t bufp, size_t *sizep)
37051ae08745Sheppo {
37061ae08745Sheppo 	ldc_chan_t	*ldcp;
37071ae08745Sheppo 	uint64_t	rx_head = 0, rx_tail = 0;
37081ae08745Sheppo 	int		rv = 0, exit_val;
37091ae08745Sheppo 
3710*a704fb2dSToomas Soome 	if (handle == 0) {
37111ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_read: invalid channel handle\n");
37121ae08745Sheppo 		return (EINVAL);
37131ae08745Sheppo 	}
37141ae08745Sheppo 
37151ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
37161ae08745Sheppo 
37171ae08745Sheppo 	/* channel lock */
37181ae08745Sheppo 	mutex_enter(&ldcp->lock);
37191ae08745Sheppo 
37201ae08745Sheppo 	if (ldcp->tstate != TS_UP) {
37211ae08745Sheppo 		DWARN(ldcp->id,
37221ae08745Sheppo 		    "ldc_read: (0x%llx) channel is not in UP state\n",
37231ae08745Sheppo 		    ldcp->id);
37241ae08745Sheppo 		exit_val = ECONNRESET;
372520ae46ebSha137994 	} else if (ldcp->mode == LDC_MODE_RELIABLE) {
372658283286Sha137994 		TRACE_RXDQ_LENGTH(ldcp);
372758283286Sha137994 		exit_val = ldcp->read_p(ldcp, bufp, sizep);
372812f80fa6Sha137994 
372912f80fa6Sha137994 		/*
373012f80fa6Sha137994 		 * For reliable mode channels, the interrupt
373112f80fa6Sha137994 		 * state is only set to pending during
373212f80fa6Sha137994 		 * interrupt handling when the secondary data
373312f80fa6Sha137994 		 * queue became full, leaving unprocessed
373412f80fa6Sha137994 		 * packets on the Rx queue. If the interrupt
373512f80fa6Sha137994 		 * state is pending and space is now available
373612f80fa6Sha137994 		 * on the data queue, clear the interrupt.
373712f80fa6Sha137994 		 */
373812f80fa6Sha137994 		if (ldcp->rx_intr_state == LDC_INTR_PEND &&
373912f80fa6Sha137994 		    Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail,
374012f80fa6Sha137994 		    ldcp->rx_dq_entries << LDC_PACKET_SHIFT) >=
374112f80fa6Sha137994 		    LDC_PACKET_SIZE) {
374212f80fa6Sha137994 			/* data queue is not full */
374312f80fa6Sha137994 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
374412f80fa6Sha137994 		}
374512f80fa6Sha137994 
374658283286Sha137994 		mutex_exit(&ldcp->lock);
374758283286Sha137994 		return (exit_val);
37481ae08745Sheppo 	} else {
37491ae08745Sheppo 		exit_val = ldcp->read_p(ldcp, bufp, sizep);
37501ae08745Sheppo 	}
37511ae08745Sheppo 
37521ae08745Sheppo 	/*
37531ae08745Sheppo 	 * if queue has been drained - clear interrupt
37541ae08745Sheppo 	 */
37551ae08745Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
37561ae08745Sheppo 	    &ldcp->link_state);
3757cb112a14Slm66018 	if (rv != 0) {
3758cb112a14Slm66018 		cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
3759cb112a14Slm66018 		    ldcp->id);
3760cb112a14Slm66018 		mutex_enter(&ldcp->tx_lock);
3761cb112a14Slm66018 		i_ldc_reset(ldcp, B_TRUE);
3762cb112a14Slm66018 		mutex_exit(&ldcp->tx_lock);
3763bd8f0338Snarayan 		mutex_exit(&ldcp->lock);
3764cb112a14Slm66018 		return (ECONNRESET);
3765cb112a14Slm66018 	}
37663af08d82Slm66018 
37673af08d82Slm66018 	if (exit_val == 0) {
37683af08d82Slm66018 		if (ldcp->link_state == LDC_CHANNEL_DOWN ||
37693af08d82Slm66018 		    ldcp->link_state == LDC_CHANNEL_RESET) {
37703af08d82Slm66018 			mutex_enter(&ldcp->tx_lock);
37713af08d82Slm66018 			i_ldc_reset(ldcp, B_FALSE);
37723af08d82Slm66018 			exit_val = ECONNRESET;
37733af08d82Slm66018 			mutex_exit(&ldcp->tx_lock);
37743af08d82Slm66018 		}
37753af08d82Slm66018 		if ((rv == 0) &&
37763af08d82Slm66018 		    (ldcp->rx_intr_state == LDC_INTR_PEND) &&
37773af08d82Slm66018 		    (rx_head == rx_tail)) {
37781ae08745Sheppo 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
37791ae08745Sheppo 		}
37803af08d82Slm66018 	}
37811ae08745Sheppo 
37821ae08745Sheppo 	mutex_exit(&ldcp->lock);
37831ae08745Sheppo 	return (exit_val);
37841ae08745Sheppo }
37851ae08745Sheppo 
37861ae08745Sheppo /*
37871ae08745Sheppo  * Basic raw mondo read -
37881ae08745Sheppo  * no interpretation of mondo contents at all.
37891ae08745Sheppo  *
37901ae08745Sheppo  * Enter and exit with ldcp->lock held by caller
37911ae08745Sheppo  */
37921ae08745Sheppo static int
i_ldc_read_raw(ldc_chan_t * ldcp,caddr_t target_bufp,size_t * sizep)37931ae08745Sheppo i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
37941ae08745Sheppo {
37951ae08745Sheppo 	uint64_t	q_size_mask;
37961ae08745Sheppo 	ldc_msg_t	*msgp;
37971ae08745Sheppo 	uint8_t		*msgbufp;
37981ae08745Sheppo 	int		rv = 0, space;
37991ae08745Sheppo 	uint64_t	rx_head, rx_tail;
38001ae08745Sheppo 
38011ae08745Sheppo 	space = *sizep;
38021ae08745Sheppo 
38031ae08745Sheppo 	if (space < LDC_PAYLOAD_SIZE_RAW)
38041ae08745Sheppo 		return (ENOBUFS);
38051ae08745Sheppo 
38061ae08745Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
38071ae08745Sheppo 
38081ae08745Sheppo 	/* compute mask for increment */
38091ae08745Sheppo 	q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
38101ae08745Sheppo 
38111ae08745Sheppo 	/*
38121ae08745Sheppo 	 * Read packet(s) from the queue
38131ae08745Sheppo 	 */
38141ae08745Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
38151ae08745Sheppo 	    &ldcp->link_state);
38161ae08745Sheppo 	if (rv != 0) {
38171ae08745Sheppo 		cmn_err(CE_WARN,
38181ae08745Sheppo 		    "ldc_read_raw: (0x%lx) unable to read queue ptrs",
38191ae08745Sheppo 		    ldcp->id);
38201ae08745Sheppo 		return (EIO);
38211ae08745Sheppo 	}
38221ae08745Sheppo 	D1(ldcp->id, "ldc_read_raw: (0x%llx) rxh=0x%llx,"
38231ae08745Sheppo 	    " rxt=0x%llx, st=0x%llx\n",
38241ae08745Sheppo 	    ldcp->id, rx_head, rx_tail, ldcp->link_state);
38251ae08745Sheppo 
38261ae08745Sheppo 	/* reset the channel state if the channel went down */
38273af08d82Slm66018 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
38283af08d82Slm66018 	    ldcp->link_state == LDC_CHANNEL_RESET) {
3829d10e4ef2Snarayan 		mutex_enter(&ldcp->tx_lock);
38303af08d82Slm66018 		i_ldc_reset(ldcp, B_FALSE);
3831d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
38321ae08745Sheppo 		return (ECONNRESET);
38331ae08745Sheppo 	}
38341ae08745Sheppo 
38351ae08745Sheppo 	/*
38361ae08745Sheppo 	 * Check for empty queue
38371ae08745Sheppo 	 */
38381ae08745Sheppo 	if (rx_head == rx_tail) {
38391ae08745Sheppo 		*sizep = 0;
38401ae08745Sheppo 		return (0);
38411ae08745Sheppo 	}
38421ae08745Sheppo 
38431ae08745Sheppo 	/* get the message */
38441ae08745Sheppo 	msgp = (ldc_msg_t *)(ldcp->rx_q_va + rx_head);
38451ae08745Sheppo 
38461ae08745Sheppo 	/* if channel is in RAW mode, copy data and return */
38471ae08745Sheppo 	msgbufp = (uint8_t *)&(msgp->raw[0]);
38481ae08745Sheppo 
38491ae08745Sheppo 	bcopy(msgbufp, target_bufp, LDC_PAYLOAD_SIZE_RAW);
38501ae08745Sheppo 
38511ae08745Sheppo 	DUMP_PAYLOAD(ldcp->id, msgbufp);
38521ae08745Sheppo 
38531ae08745Sheppo 	*sizep = LDC_PAYLOAD_SIZE_RAW;
38541ae08745Sheppo 
38551ae08745Sheppo 	rx_head = (rx_head + LDC_PACKET_SIZE) & q_size_mask;
38560a55fbb7Slm66018 	rv = i_ldc_set_rx_head(ldcp, rx_head);
38571ae08745Sheppo 
38581ae08745Sheppo 	return (rv);
38591ae08745Sheppo }
38601ae08745Sheppo 
38611ae08745Sheppo /*
38621ae08745Sheppo  * Process LDC mondos to build larger packets
38631ae08745Sheppo  * with either un-reliable or reliable delivery.
38641ae08745Sheppo  *
38651ae08745Sheppo  * Enter and exit with ldcp->lock held by caller
38661ae08745Sheppo  */
38671ae08745Sheppo static int
i_ldc_read_packet(ldc_chan_t * ldcp,caddr_t target_bufp,size_t * sizep)38681ae08745Sheppo i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
38691ae08745Sheppo {
38701ae08745Sheppo 	int		rv = 0;
38711ae08745Sheppo 	uint64_t	rx_head = 0, rx_tail = 0;
38721ae08745Sheppo 	uint64_t	curr_head = 0;
38731ae08745Sheppo 	ldc_msg_t	*msg;
38741ae08745Sheppo 	caddr_t		target;
38751ae08745Sheppo 	size_t		len = 0, bytes_read = 0;
38760a55fbb7Slm66018 	int		retries = 0;
387758283286Sha137994 	uint64_t	q_va, q_size_mask;
3878d10e4ef2Snarayan 	uint64_t	first_fragment = 0;
38791ae08745Sheppo 
38801ae08745Sheppo 	target = target_bufp;
38811ae08745Sheppo 
38821ae08745Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
38831ae08745Sheppo 
38843af08d82Slm66018 	/* check if the buffer and size are valid */
38853af08d82Slm66018 	if (target_bufp == NULL || *sizep == 0) {
38863af08d82Slm66018 		DWARN(ldcp->id, "ldc_read: (0x%llx) invalid buffer/size\n",
38873af08d82Slm66018 		    ldcp->id);
38883af08d82Slm66018 		return (EINVAL);
38893af08d82Slm66018 	}
38903af08d82Slm66018 
389158283286Sha137994 	/* Set q_va and compute increment mask for the appropriate queue */
389220ae46ebSha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
389358283286Sha137994 		q_va	    = ldcp->rx_dq_va;
389458283286Sha137994 		q_size_mask = (ldcp->rx_dq_entries-1)<<LDC_PACKET_SHIFT;
389558283286Sha137994 	} else {
389658283286Sha137994 		q_va	    = ldcp->rx_q_va;
38971ae08745Sheppo 		q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
389858283286Sha137994 	}
38991ae08745Sheppo 
39001ae08745Sheppo 	/*
39011ae08745Sheppo 	 * Read packet(s) from the queue
39021ae08745Sheppo 	 */
390358283286Sha137994 	rv = ldcp->readq_get_state(ldcp, &curr_head, &rx_tail,
39041ae08745Sheppo 	    &ldcp->link_state);
39051ae08745Sheppo 	if (rv != 0) {
39063af08d82Slm66018 		cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
39071ae08745Sheppo 		    ldcp->id);
39083af08d82Slm66018 		mutex_enter(&ldcp->tx_lock);
39093af08d82Slm66018 		i_ldc_reset(ldcp, B_TRUE);
39103af08d82Slm66018 		mutex_exit(&ldcp->tx_lock);
39113af08d82Slm66018 		return (ECONNRESET);
39121ae08745Sheppo 	}
39131ae08745Sheppo 	D1(ldcp->id, "ldc_read: (0x%llx) chd=0x%llx, tl=0x%llx, st=0x%llx\n",
39141ae08745Sheppo 	    ldcp->id, curr_head, rx_tail, ldcp->link_state);
39151ae08745Sheppo 
39161ae08745Sheppo 	/* reset the channel state if the channel went down */
39173af08d82Slm66018 	if (ldcp->link_state != LDC_CHANNEL_UP)
39183af08d82Slm66018 		goto channel_is_reset;
39191ae08745Sheppo 
39201ae08745Sheppo 	for (;;) {
39211ae08745Sheppo 
39221ae08745Sheppo 		if (curr_head == rx_tail) {
392358283286Sha137994 			/*
392458283286Sha137994 			 * If a data queue is being used, check the Rx HV
392558283286Sha137994 			 * queue. This will copy over any new data packets
392658283286Sha137994 			 * that have arrived.
392758283286Sha137994 			 */
392820ae46ebSha137994 			if (ldcp->mode == LDC_MODE_RELIABLE)
392958283286Sha137994 				(void) i_ldc_chkq(ldcp);
393058283286Sha137994 
393158283286Sha137994 			rv = ldcp->readq_get_state(ldcp,
39321ae08745Sheppo 			    &rx_head, &rx_tail, &ldcp->link_state);
39331ae08745Sheppo 			if (rv != 0) {
39341ae08745Sheppo 				cmn_err(CE_WARN,
39351ae08745Sheppo 				    "ldc_read: (0x%lx) cannot read queue ptrs",
39361ae08745Sheppo 				    ldcp->id);
3937d10e4ef2Snarayan 				mutex_enter(&ldcp->tx_lock);
39383af08d82Slm66018 				i_ldc_reset(ldcp, B_TRUE);
3939d10e4ef2Snarayan 				mutex_exit(&ldcp->tx_lock);
39401ae08745Sheppo 				return (ECONNRESET);
39411ae08745Sheppo 			}
394258283286Sha137994 
39433af08d82Slm66018 			if (ldcp->link_state != LDC_CHANNEL_UP)
39443af08d82Slm66018 				goto channel_is_reset;
39451ae08745Sheppo 
39461ae08745Sheppo 			if (curr_head == rx_tail) {
39471ae08745Sheppo 
39481ae08745Sheppo 				/* If in the middle of a fragmented xfer */
3949d10e4ef2Snarayan 				if (first_fragment != 0) {
39500a55fbb7Slm66018 
39510a55fbb7Slm66018 					/* wait for ldc_delay usecs */
39520a55fbb7Slm66018 					drv_usecwait(ldc_delay);
39530a55fbb7Slm66018 
39540a55fbb7Slm66018 					if (++retries < ldc_max_retries)
39551ae08745Sheppo 						continue;
39560a55fbb7Slm66018 
39571ae08745Sheppo 					*sizep = 0;
395820ae46ebSha137994 					if (ldcp->mode != LDC_MODE_RELIABLE)
395958283286Sha137994 						ldcp->last_msg_rcd =
396058283286Sha137994 						    first_fragment - 1;
39613af08d82Slm66018 					DWARN(DBG_ALL_LDCS, "ldc_read: "
396222f747efSnarayan 					    "(0x%llx) read timeout", ldcp->id);
39633af08d82Slm66018 					return (EAGAIN);
39641ae08745Sheppo 				}
39651ae08745Sheppo 				*sizep = 0;
39661ae08745Sheppo 				break;
39671ae08745Sheppo 			}
39683af08d82Slm66018 		}
39690a55fbb7Slm66018 		retries = 0;
39701ae08745Sheppo 
39711ae08745Sheppo 		D2(ldcp->id,
39721ae08745Sheppo 		    "ldc_read: (0x%llx) chd=0x%llx, rxhd=0x%llx, rxtl=0x%llx\n",
39731ae08745Sheppo 		    ldcp->id, curr_head, rx_head, rx_tail);
39741ae08745Sheppo 
39751ae08745Sheppo 		/* get the message */
397658283286Sha137994 		msg = (ldc_msg_t *)(q_va + curr_head);
39771ae08745Sheppo 
39781ae08745Sheppo 		DUMP_LDC_PKT(ldcp, "ldc_read received pkt",
39791ae08745Sheppo 		    ldcp->rx_q_va + curr_head);
39801ae08745Sheppo 
39811ae08745Sheppo 		/* Check the message ID for the message received */
398220ae46ebSha137994 		if (ldcp->mode != LDC_MODE_RELIABLE) {
39831ae08745Sheppo 			if ((rv = i_ldc_check_seqid(ldcp, msg)) != 0) {
39841ae08745Sheppo 
398558283286Sha137994 				DWARN(ldcp->id, "ldc_read: (0x%llx) seqid "
398658283286Sha137994 				    "error, q_ptrs=0x%lx,0x%lx",
398758283286Sha137994 				    ldcp->id, rx_head, rx_tail);
39881ae08745Sheppo 
39890a55fbb7Slm66018 				/* throw away data */
39900a55fbb7Slm66018 				bytes_read = 0;
39910a55fbb7Slm66018 
39921ae08745Sheppo 				/* Reset last_msg_rcd to start of message */
3993d10e4ef2Snarayan 				if (first_fragment != 0) {
3994d10e4ef2Snarayan 					ldcp->last_msg_rcd = first_fragment - 1;
3995d10e4ef2Snarayan 					first_fragment = 0;
39961ae08745Sheppo 				}
39971ae08745Sheppo 				/*
39981ae08745Sheppo 				 * Send a NACK -- invalid seqid
39991ae08745Sheppo 				 * get the current tail for the response
40001ae08745Sheppo 				 */
40011ae08745Sheppo 				rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK,
40021ae08745Sheppo 				    (msg->ctrl & LDC_CTRL_MASK));
40031ae08745Sheppo 				if (rv) {
40041ae08745Sheppo 					cmn_err(CE_NOTE,
40051ae08745Sheppo 					    "ldc_read: (0x%lx) err sending "
40061ae08745Sheppo 					    "NACK msg\n", ldcp->id);
4007d10e4ef2Snarayan 
400858283286Sha137994 					/* if cannot send NACK - reset chan */
4009d10e4ef2Snarayan 					mutex_enter(&ldcp->tx_lock);
40103af08d82Slm66018 					i_ldc_reset(ldcp, B_FALSE);
4011d10e4ef2Snarayan 					mutex_exit(&ldcp->tx_lock);
4012d10e4ef2Snarayan 					rv = ECONNRESET;
4013d10e4ef2Snarayan 					break;
40141ae08745Sheppo 				}
40151ae08745Sheppo 
40161ae08745Sheppo 				/* purge receive queue */
40170a55fbb7Slm66018 				rv = i_ldc_set_rx_head(ldcp, rx_tail);
40181ae08745Sheppo 
40191ae08745Sheppo 				break;
40201ae08745Sheppo 			}
40211ae08745Sheppo 
40221ae08745Sheppo 			/*
40231ae08745Sheppo 			 * Process any messages of type CTRL messages
4024e1ebb9ecSlm66018 			 * Future implementations should try to pass these
4025e1ebb9ecSlm66018 			 * to LDC link by resetting the intr state.
40261ae08745Sheppo 			 *
402758283286Sha137994 			 * NOTE: not done as a switch() as type can be
402858283286Sha137994 			 * both ctrl+data
40291ae08745Sheppo 			 */
40301ae08745Sheppo 			if (msg->type & LDC_CTRL) {
40311ae08745Sheppo 				if (rv = i_ldc_ctrlmsg(ldcp, msg)) {
40321ae08745Sheppo 					if (rv == EAGAIN)
40331ae08745Sheppo 						continue;
40340a55fbb7Slm66018 					rv = i_ldc_set_rx_head(ldcp, rx_tail);
40351ae08745Sheppo 					*sizep = 0;
40361ae08745Sheppo 					bytes_read = 0;
40371ae08745Sheppo 					break;
40381ae08745Sheppo 				}
40391ae08745Sheppo 			}
40401ae08745Sheppo 
40411ae08745Sheppo 			/* process data ACKs */
40421ae08745Sheppo 			if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
4043d10e4ef2Snarayan 				if (rv = i_ldc_process_data_ACK(ldcp, msg)) {
4044d10e4ef2Snarayan 					*sizep = 0;
4045d10e4ef2Snarayan 					bytes_read = 0;
4046d10e4ef2Snarayan 					break;
4047d10e4ef2Snarayan 				}
40481ae08745Sheppo 			}
40491ae08745Sheppo 
405083d3bc6fSnarayan 			/* process data NACKs */
405183d3bc6fSnarayan 			if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) {
405283d3bc6fSnarayan 				DWARN(ldcp->id,
405358283286Sha137994 				    "ldc_read: (0x%llx) received DATA/NACK",
405458283286Sha137994 				    ldcp->id);
405583d3bc6fSnarayan 				mutex_enter(&ldcp->tx_lock);
405683d3bc6fSnarayan 				i_ldc_reset(ldcp, B_TRUE);
405783d3bc6fSnarayan 				mutex_exit(&ldcp->tx_lock);
405883d3bc6fSnarayan 				return (ECONNRESET);
405983d3bc6fSnarayan 			}
406058283286Sha137994 		}
406183d3bc6fSnarayan 
40621ae08745Sheppo 		/* process data messages */
40631ae08745Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
40641ae08745Sheppo 
40651ae08745Sheppo 			uint8_t *msgbuf = (uint8_t *)(
406620ae46ebSha137994 			    (ldcp->mode == LDC_MODE_RELIABLE) ?
406722f747efSnarayan 			    msg->rdata : msg->udata);
40681ae08745Sheppo 
40691ae08745Sheppo 			D2(ldcp->id,
40701ae08745Sheppo 			    "ldc_read: (0x%llx) received data msg\n", ldcp->id);
40711ae08745Sheppo 
40721ae08745Sheppo 			/* get the packet length */
40731ae08745Sheppo 			len = (msg->env & LDC_LEN_MASK);
40741ae08745Sheppo 
40751ae08745Sheppo 				/*
40761ae08745Sheppo 				 * FUTURE OPTIMIZATION:
40771ae08745Sheppo 				 * dont need to set q head for every
40781ae08745Sheppo 				 * packet we read just need to do this when
40791ae08745Sheppo 				 * we are done or need to wait for more
40801ae08745Sheppo 				 * mondos to make a full packet - this is
40811ae08745Sheppo 				 * currently expensive.
40821ae08745Sheppo 				 */
40831ae08745Sheppo 
4084d10e4ef2Snarayan 			if (first_fragment == 0) {
40851ae08745Sheppo 
40861ae08745Sheppo 				/*
40871ae08745Sheppo 				 * first packets should always have the start
40881ae08745Sheppo 				 * bit set (even for a single packet). If not
40891ae08745Sheppo 				 * throw away the packet
40901ae08745Sheppo 				 */
40911ae08745Sheppo 				if (!(msg->env & LDC_FRAG_START)) {
40921ae08745Sheppo 
40931ae08745Sheppo 					DWARN(DBG_ALL_LDCS,
40941ae08745Sheppo 					    "ldc_read: (0x%llx) not start - "
40951ae08745Sheppo 					    "frag=%x\n", ldcp->id,
40961ae08745Sheppo 					    (msg->env) & LDC_FRAG_MASK);
40971ae08745Sheppo 
40981ae08745Sheppo 					/* toss pkt, inc head, cont reading */
40991ae08745Sheppo 					bytes_read = 0;
41001ae08745Sheppo 					target = target_bufp;
41011ae08745Sheppo 					curr_head =
41021ae08745Sheppo 					    (curr_head + LDC_PACKET_SIZE)
41031ae08745Sheppo 					    & q_size_mask;
410458283286Sha137994 					if (rv = ldcp->readq_set_head(ldcp,
41051ae08745Sheppo 					    curr_head))
41061ae08745Sheppo 						break;
41071ae08745Sheppo 
41081ae08745Sheppo 					continue;
41091ae08745Sheppo 				}
41101ae08745Sheppo 
4111d10e4ef2Snarayan 				first_fragment = msg->seqid;
41121ae08745Sheppo 			} else {
41131ae08745Sheppo 				/* check to see if this is a pkt w/ START bit */
41141ae08745Sheppo 				if (msg->env & LDC_FRAG_START) {
41151ae08745Sheppo 					DWARN(DBG_ALL_LDCS,
41161ae08745Sheppo 					    "ldc_read:(0x%llx) unexpected pkt"
41171ae08745Sheppo 					    " env=0x%x discarding %d bytes,"
41181ae08745Sheppo 					    " lastmsg=%d, currentmsg=%d\n",
41191ae08745Sheppo 					    ldcp->id, msg->env&LDC_FRAG_MASK,
41201ae08745Sheppo 					    bytes_read, ldcp->last_msg_rcd,
41211ae08745Sheppo 					    msg->seqid);
41221ae08745Sheppo 
41231ae08745Sheppo 					/* throw data we have read so far */
41241ae08745Sheppo 					bytes_read = 0;
41251ae08745Sheppo 					target = target_bufp;
4126d10e4ef2Snarayan 					first_fragment = msg->seqid;
41271ae08745Sheppo 
412858283286Sha137994 					if (rv = ldcp->readq_set_head(ldcp,
41291ae08745Sheppo 					    curr_head))
41301ae08745Sheppo 						break;
41311ae08745Sheppo 				}
41321ae08745Sheppo 			}
41331ae08745Sheppo 
41341ae08745Sheppo 			/* copy (next) pkt into buffer */
41351ae08745Sheppo 			if (len <= (*sizep - bytes_read)) {
41361ae08745Sheppo 				bcopy(msgbuf, target, len);
41371ae08745Sheppo 				target += len;
41381ae08745Sheppo 				bytes_read += len;
41391ae08745Sheppo 			} else {
41401ae08745Sheppo 				/*
41411ae08745Sheppo 				 * there is not enough space in the buffer to
41421ae08745Sheppo 				 * read this pkt. throw message away & continue
41431ae08745Sheppo 				 * reading data from queue
41441ae08745Sheppo 				 */
41451ae08745Sheppo 				DWARN(DBG_ALL_LDCS,
41461ae08745Sheppo 				    "ldc_read: (0x%llx) buffer too small, "
41471ae08745Sheppo 				    "head=0x%lx, expect=%d, got=%d\n", ldcp->id,
41481ae08745Sheppo 				    curr_head, *sizep, bytes_read+len);
41491ae08745Sheppo 
4150d10e4ef2Snarayan 				first_fragment = 0;
41511ae08745Sheppo 				target = target_bufp;
41521ae08745Sheppo 				bytes_read = 0;
41531ae08745Sheppo 
41541ae08745Sheppo 				/* throw away everything received so far */
415558283286Sha137994 				if (rv = ldcp->readq_set_head(ldcp, curr_head))
41561ae08745Sheppo 					break;
41571ae08745Sheppo 
41581ae08745Sheppo 				/* continue reading remaining pkts */
41591ae08745Sheppo 				continue;
41601ae08745Sheppo 			}
41611ae08745Sheppo 		}
41621ae08745Sheppo 
41631ae08745Sheppo 		/* set the message id */
416420ae46ebSha137994 		if (ldcp->mode != LDC_MODE_RELIABLE)
41651ae08745Sheppo 			ldcp->last_msg_rcd = msg->seqid;
41661ae08745Sheppo 
41671ae08745Sheppo 		/* move the head one position */
41681ae08745Sheppo 		curr_head = (curr_head + LDC_PACKET_SIZE) & q_size_mask;
41691ae08745Sheppo 
41701ae08745Sheppo 		if (msg->env & LDC_FRAG_STOP) {
41711ae08745Sheppo 
41721ae08745Sheppo 			/*
41731ae08745Sheppo 			 * All pkts that are part of this fragmented transfer
41741ae08745Sheppo 			 * have been read or this was a single pkt read
41751ae08745Sheppo 			 * or there was an error
41761ae08745Sheppo 			 */
41771ae08745Sheppo 
41781ae08745Sheppo 			/* set the queue head */
417958283286Sha137994 			if (rv = ldcp->readq_set_head(ldcp, curr_head))
41801ae08745Sheppo 				bytes_read = 0;
41811ae08745Sheppo 
41821ae08745Sheppo 			*sizep = bytes_read;
41831ae08745Sheppo 
41841ae08745Sheppo 			break;
41851ae08745Sheppo 		}
41861ae08745Sheppo 
4187332608acSnarayan 		/* advance head if it is a CTRL packet or a DATA ACK packet */
4188332608acSnarayan 		if ((msg->type & LDC_CTRL) ||
4189332608acSnarayan 		    ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK))) {
41901ae08745Sheppo 
41911ae08745Sheppo 			/* set the queue head */
419258283286Sha137994 			if (rv = ldcp->readq_set_head(ldcp, curr_head)) {
41931ae08745Sheppo 				bytes_read = 0;
41941ae08745Sheppo 				break;
41951ae08745Sheppo 			}
41961ae08745Sheppo 
41971ae08745Sheppo 			D2(ldcp->id, "ldc_read: (0x%llx) set ACK qhead 0x%llx",
41981ae08745Sheppo 			    ldcp->id, curr_head);
41991ae08745Sheppo 		}
42001ae08745Sheppo 
42011ae08745Sheppo 	} /* for (;;) */
42021ae08745Sheppo 
42031ae08745Sheppo 	D2(ldcp->id, "ldc_read: (0x%llx) end size=%d", ldcp->id, *sizep);
42041ae08745Sheppo 
42051ae08745Sheppo 	return (rv);
42063af08d82Slm66018 
42073af08d82Slm66018 channel_is_reset:
42083af08d82Slm66018 	mutex_enter(&ldcp->tx_lock);
42093af08d82Slm66018 	i_ldc_reset(ldcp, B_FALSE);
42103af08d82Slm66018 	mutex_exit(&ldcp->tx_lock);
42113af08d82Slm66018 	return (ECONNRESET);
42121ae08745Sheppo }
42131ae08745Sheppo 
42141ae08745Sheppo /*
421520ae46ebSha137994  * Fetch and buffer incoming packets so we can hand them back as
42161ae08745Sheppo  * a basic byte stream.
42171ae08745Sheppo  *
42181ae08745Sheppo  * Enter and exit with ldcp->lock held by caller
42191ae08745Sheppo  */
42201ae08745Sheppo static int
i_ldc_read_stream(ldc_chan_t * ldcp,caddr_t target_bufp,size_t * sizep)42211ae08745Sheppo i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
42221ae08745Sheppo {
42231ae08745Sheppo 	int	rv;
42241ae08745Sheppo 	size_t	size;
42251ae08745Sheppo 
42261ae08745Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
42271ae08745Sheppo 
42281ae08745Sheppo 	D2(ldcp->id, "i_ldc_read_stream: (0x%llx) buffer size=%d",
42291ae08745Sheppo 	    ldcp->id, *sizep);
42301ae08745Sheppo 
42311ae08745Sheppo 	if (ldcp->stream_remains == 0) {
42321ae08745Sheppo 		size = ldcp->mtu;
42331ae08745Sheppo 		rv = i_ldc_read_packet(ldcp,
42341ae08745Sheppo 		    (caddr_t)ldcp->stream_bufferp, &size);
42351ae08745Sheppo 		D2(ldcp->id, "i_ldc_read_stream: read packet (0x%llx) size=%d",
42361ae08745Sheppo 		    ldcp->id, size);
42371ae08745Sheppo 
42381ae08745Sheppo 		if (rv != 0)
42391ae08745Sheppo 			return (rv);
42401ae08745Sheppo 
42411ae08745Sheppo 		ldcp->stream_remains = size;
42421ae08745Sheppo 		ldcp->stream_offset = 0;
42431ae08745Sheppo 	}
42441ae08745Sheppo 
42451ae08745Sheppo 	size = MIN(ldcp->stream_remains, *sizep);
42461ae08745Sheppo 
42471ae08745Sheppo 	bcopy(ldcp->stream_bufferp + ldcp->stream_offset, target_bufp, size);
42481ae08745Sheppo 	ldcp->stream_offset += size;
42491ae08745Sheppo 	ldcp->stream_remains -= size;
42501ae08745Sheppo 
42511ae08745Sheppo 	D2(ldcp->id, "i_ldc_read_stream: (0x%llx) fill from buffer size=%d",
42521ae08745Sheppo 	    ldcp->id, size);
42531ae08745Sheppo 
42541ae08745Sheppo 	*sizep = size;
42551ae08745Sheppo 	return (0);
42561ae08745Sheppo }
42571ae08745Sheppo 
42581ae08745Sheppo /*
42591ae08745Sheppo  * Write specified amount of bytes to the channel
42601ae08745Sheppo  * in multiple pkts of pkt_payload size. Each
42611ae08745Sheppo  * packet is tagged with an unique packet ID in
4262e1ebb9ecSlm66018  * the case of a reliable link.
42631ae08745Sheppo  *
42641ae08745Sheppo  * On return, size contains the number of bytes written.
42651ae08745Sheppo  */
42661ae08745Sheppo int
ldc_write(ldc_handle_t handle,caddr_t buf,size_t * sizep)42671ae08745Sheppo ldc_write(ldc_handle_t handle, caddr_t buf, size_t *sizep)
42681ae08745Sheppo {
42691ae08745Sheppo 	ldc_chan_t	*ldcp;
42701ae08745Sheppo 	int		rv = 0;
42711ae08745Sheppo 
4272*a704fb2dSToomas Soome 	if (handle == 0) {
42731ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_write: invalid channel handle\n");
42741ae08745Sheppo 		return (EINVAL);
42751ae08745Sheppo 	}
42761ae08745Sheppo 	ldcp = (ldc_chan_t *)handle;
42771ae08745Sheppo 
42787bd3a2e2SSriharsha Basavapatna 	mutex_enter(&ldcp->tx_lock);
42791ae08745Sheppo 
42801ae08745Sheppo 	/* check if non-zero data to write */
42811ae08745Sheppo 	if (buf == NULL || sizep == NULL) {
42821ae08745Sheppo 		DWARN(ldcp->id, "ldc_write: (0x%llx) invalid data write\n",
42831ae08745Sheppo 		    ldcp->id);
4284d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
42851ae08745Sheppo 		return (EINVAL);
42861ae08745Sheppo 	}
42871ae08745Sheppo 
42881ae08745Sheppo 	if (*sizep == 0) {
42891ae08745Sheppo 		DWARN(ldcp->id, "ldc_write: (0x%llx) write size of zero\n",
42901ae08745Sheppo 		    ldcp->id);
4291d10e4ef2Snarayan 		mutex_exit(&ldcp->tx_lock);
42921ae08745Sheppo 		return (0);
42931ae08745Sheppo 	}
42941ae08745Sheppo 
42951ae08745Sheppo 	/* Check if channel is UP for data exchange */
42961ae08745Sheppo 	if (ldcp->tstate != TS_UP) {
42971ae08745Sheppo 		DWARN(ldcp->id,
42981ae08745Sheppo 		    "ldc_write: (0x%llx) channel is not in UP state\n",
42991ae08745Sheppo 		    ldcp->id);
43001ae08745Sheppo 		*sizep = 0;
43011ae08745Sheppo 		rv = ECONNRESET;
43021ae08745Sheppo 	} else {
43031ae08745Sheppo 		rv = ldcp->write_p(ldcp, buf, sizep);
43041ae08745Sheppo 	}
43051ae08745Sheppo 
4306d10e4ef2Snarayan 	mutex_exit(&ldcp->tx_lock);
43071ae08745Sheppo 
43081ae08745Sheppo 	return (rv);
43091ae08745Sheppo }
43101ae08745Sheppo 
43111ae08745Sheppo /*
43121ae08745Sheppo  * Write a raw packet to the channel
43131ae08745Sheppo  * On return, size contains the number of bytes written.
43141ae08745Sheppo  */
43151ae08745Sheppo static int
i_ldc_write_raw(ldc_chan_t * ldcp,caddr_t buf,size_t * sizep)43161ae08745Sheppo i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
43171ae08745Sheppo {
43181ae08745Sheppo 	ldc_msg_t	*ldcmsg;
43191ae08745Sheppo 	uint64_t	tx_head, tx_tail, new_tail;
43201ae08745Sheppo 	int		rv = 0;
43211ae08745Sheppo 	size_t		size;
43221ae08745Sheppo 
4323d10e4ef2Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
43241ae08745Sheppo 	ASSERT(ldcp->mode == LDC_MODE_RAW);
43251ae08745Sheppo 
43261ae08745Sheppo 	size = *sizep;
43271ae08745Sheppo 
43281ae08745Sheppo 	/*
43291ae08745Sheppo 	 * Check to see if the packet size is less than or
43301ae08745Sheppo 	 * equal to packet size support in raw mode
43311ae08745Sheppo 	 */
43321ae08745Sheppo 	if (size > ldcp->pkt_payload) {
43331ae08745Sheppo 		DWARN(ldcp->id,
43341ae08745Sheppo 		    "ldc_write: (0x%llx) invalid size (0x%llx) for RAW mode\n",
43351ae08745Sheppo 		    ldcp->id, *sizep);
43361ae08745Sheppo 		*sizep = 0;
43371ae08745Sheppo 		return (EMSGSIZE);
43381ae08745Sheppo 	}
43391ae08745Sheppo 
43401ae08745Sheppo 	/* get the qptrs for the tx queue */
43411ae08745Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
43421ae08745Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
43431ae08745Sheppo 	if (rv != 0) {
43441ae08745Sheppo 		cmn_err(CE_WARN,
43451ae08745Sheppo 		    "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
43461ae08745Sheppo 		*sizep = 0;
43471ae08745Sheppo 		return (EIO);
43481ae08745Sheppo 	}
43491ae08745Sheppo 
43501ae08745Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
43511ae08745Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
43521ae08745Sheppo 		DWARN(ldcp->id,
43531ae08745Sheppo 		    "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
4354d10e4ef2Snarayan 
43551ae08745Sheppo 		*sizep = 0;
4356d10e4ef2Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
43573af08d82Slm66018 			i_ldc_reset(ldcp, B_FALSE);
4358d10e4ef2Snarayan 			mutex_exit(&ldcp->lock);
4359d10e4ef2Snarayan 		} else {
4360d10e4ef2Snarayan 			/*
4361d10e4ef2Snarayan 			 * Release Tx lock, and then reacquire channel
4362d10e4ef2Snarayan 			 * and Tx lock in correct order
4363d10e4ef2Snarayan 			 */
4364d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
4365d10e4ef2Snarayan 			mutex_enter(&ldcp->lock);
4366d10e4ef2Snarayan 			mutex_enter(&ldcp->tx_lock);
43673af08d82Slm66018 			i_ldc_reset(ldcp, B_FALSE);
4368d10e4ef2Snarayan 			mutex_exit(&ldcp->lock);
4369d10e4ef2Snarayan 		}
43701ae08745Sheppo 		return (ECONNRESET);
43711ae08745Sheppo 	}
43721ae08745Sheppo 
43731ae08745Sheppo 	tx_tail = ldcp->tx_tail;
43741ae08745Sheppo 	tx_head = ldcp->tx_head;
43751ae08745Sheppo 	new_tail = (tx_tail + LDC_PACKET_SIZE) &
43761ae08745Sheppo 	    ((ldcp->tx_q_entries-1) << LDC_PACKET_SHIFT);
43771ae08745Sheppo 
43781ae08745Sheppo 	if (new_tail == tx_head) {
43791ae08745Sheppo 		DWARN(DBG_ALL_LDCS,
43801ae08745Sheppo 		    "ldc_write: (0x%llx) TX queue is full\n", ldcp->id);
43811ae08745Sheppo 		*sizep = 0;
43821ae08745Sheppo 		return (EWOULDBLOCK);
43831ae08745Sheppo 	}
43841ae08745Sheppo 
43851ae08745Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
43861ae08745Sheppo 	    ldcp->id, size);
43871ae08745Sheppo 
43881ae08745Sheppo 	/* Send the data now */
43891ae08745Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
43901ae08745Sheppo 
43911ae08745Sheppo 	/* copy the data into pkt */
43921ae08745Sheppo 	bcopy((uint8_t *)buf, ldcmsg, size);
43931ae08745Sheppo 
43941ae08745Sheppo 	/* increment tail */
43951ae08745Sheppo 	tx_tail = new_tail;
43961ae08745Sheppo 
43971ae08745Sheppo 	/*
43981ae08745Sheppo 	 * All packets have been copied into the TX queue
43991ae08745Sheppo 	 * update the tail ptr in the HV
44001ae08745Sheppo 	 */
44011ae08745Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
44021ae08745Sheppo 	if (rv) {
44031ae08745Sheppo 		if (rv == EWOULDBLOCK) {
44041ae08745Sheppo 			DWARN(ldcp->id, "ldc_write: (0x%llx) write timed out\n",
44051ae08745Sheppo 			    ldcp->id);
44061ae08745Sheppo 			*sizep = 0;
44071ae08745Sheppo 			return (EWOULDBLOCK);
44081ae08745Sheppo 		}
44091ae08745Sheppo 
44101ae08745Sheppo 		*sizep = 0;
4411d10e4ef2Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
44123af08d82Slm66018 			i_ldc_reset(ldcp, B_FALSE);
4413d10e4ef2Snarayan 			mutex_exit(&ldcp->lock);
4414d10e4ef2Snarayan 		} else {
4415d10e4ef2Snarayan 			/*
4416d10e4ef2Snarayan 			 * Release Tx lock, and then reacquire channel
4417d10e4ef2Snarayan 			 * and Tx lock in correct order
4418d10e4ef2Snarayan 			 */
4419d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
4420d10e4ef2Snarayan 			mutex_enter(&ldcp->lock);
4421d10e4ef2Snarayan 			mutex_enter(&ldcp->tx_lock);
44223af08d82Slm66018 			i_ldc_reset(ldcp, B_FALSE);
4423d10e4ef2Snarayan 			mutex_exit(&ldcp->lock);
4424d10e4ef2Snarayan 		}
44251ae08745Sheppo 		return (ECONNRESET);
44261ae08745Sheppo 	}
44271ae08745Sheppo 
44281ae08745Sheppo 	ldcp->tx_tail = tx_tail;
44291ae08745Sheppo 	*sizep = size;
44301ae08745Sheppo 
44311ae08745Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, size);
44321ae08745Sheppo 
44331ae08745Sheppo 	return (rv);
44341ae08745Sheppo }
44351ae08745Sheppo 
44361ae08745Sheppo 
44371ae08745Sheppo /*
44381ae08745Sheppo  * Write specified amount of bytes to the channel
44391ae08745Sheppo  * in multiple pkts of pkt_payload size. Each
44401ae08745Sheppo  * packet is tagged with an unique packet ID in
4441e1ebb9ecSlm66018  * the case of a reliable link.
44421ae08745Sheppo  *
44431ae08745Sheppo  * On return, size contains the number of bytes written.
44441ae08745Sheppo  * This function needs to ensure that the write size is < MTU size
44451ae08745Sheppo  */
44461ae08745Sheppo static int
i_ldc_write_packet(ldc_chan_t * ldcp,caddr_t buf,size_t * size)44471ae08745Sheppo i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t buf, size_t *size)
44481ae08745Sheppo {
44491ae08745Sheppo 	ldc_msg_t	*ldcmsg;
44501ae08745Sheppo 	uint64_t	tx_head, tx_tail, new_tail, start;
44511ae08745Sheppo 	uint64_t	txq_size_mask, numavail;
44521ae08745Sheppo 	uint8_t		*msgbuf, *source = (uint8_t *)buf;
44531ae08745Sheppo 	size_t		len, bytes_written = 0, remaining;
44541ae08745Sheppo 	int		rv;
44551ae08745Sheppo 	uint32_t	curr_seqid;
44561ae08745Sheppo 
4457d10e4ef2Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
44581ae08745Sheppo 
44591ae08745Sheppo 	ASSERT(ldcp->mode == LDC_MODE_RELIABLE ||
446020ae46ebSha137994 	    ldcp->mode == LDC_MODE_UNRELIABLE);
44611ae08745Sheppo 
44621ae08745Sheppo 	/* compute mask for increment */
44631ae08745Sheppo 	txq_size_mask = (ldcp->tx_q_entries - 1) << LDC_PACKET_SHIFT;
44641ae08745Sheppo 
44651ae08745Sheppo 	/* get the qptrs for the tx queue */
44661ae08745Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
44671ae08745Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
44681ae08745Sheppo 	if (rv != 0) {
44691ae08745Sheppo 		cmn_err(CE_WARN,
44701ae08745Sheppo 		    "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
44711ae08745Sheppo 		*size = 0;
44721ae08745Sheppo 		return (EIO);
44731ae08745Sheppo 	}
44741ae08745Sheppo 
44751ae08745Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
44761ae08745Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
44771ae08745Sheppo 		DWARN(ldcp->id,
44781ae08745Sheppo 		    "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
44791ae08745Sheppo 		*size = 0;
4480d10e4ef2Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
44813af08d82Slm66018 			i_ldc_reset(ldcp, B_FALSE);
4482d10e4ef2Snarayan 			mutex_exit(&ldcp->lock);
4483d10e4ef2Snarayan 		} else {
4484d10e4ef2Snarayan 			/*
4485d10e4ef2Snarayan 			 * Release Tx lock, and then reacquire channel
4486d10e4ef2Snarayan 			 * and Tx lock in correct order
4487d10e4ef2Snarayan 			 */
4488d10e4ef2Snarayan 			mutex_exit(&ldcp->tx_lock);
4489d10e4ef2Snarayan 			mutex_enter(&ldcp->lock);
4490d10e4ef2Snarayan 			mutex_enter(&ldcp->tx_lock);
44913af08d82Slm66018 			i_ldc_reset(ldcp, B_FALSE);
4492d10e4ef2Snarayan 			mutex_exit(&ldcp->lock);
4493d10e4ef2Snarayan 		}
44941ae08745Sheppo 		return (ECONNRESET);
44951ae08745Sheppo 	}
44961ae08745Sheppo 
44971ae08745Sheppo 	tx_tail = ldcp->tx_tail;
44981ae08745Sheppo 	new_tail = (tx_tail + LDC_PACKET_SIZE) %
44991ae08745Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
45001ae08745Sheppo 
45011ae08745Sheppo 	/*
450222f747efSnarayan 	 * Check to see if the queue is full. The check is done using
450322f747efSnarayan 	 * the appropriate head based on the link mode.
45041ae08745Sheppo 	 */
450522f747efSnarayan 	i_ldc_get_tx_head(ldcp, &tx_head);
450622f747efSnarayan 
45071ae08745Sheppo 	if (new_tail == tx_head) {
45081ae08745Sheppo 		DWARN(DBG_ALL_LDCS,
45091ae08745Sheppo 		    "ldc_write: (0x%llx) TX queue is full\n", ldcp->id);
45101ae08745Sheppo 		*size = 0;
45111ae08745Sheppo 		return (EWOULDBLOCK);
45121ae08745Sheppo 	}
45131ae08745Sheppo 
45141ae08745Sheppo 	/*
45151ae08745Sheppo 	 * Make sure that the LDC Tx queue has enough space
45161ae08745Sheppo 	 */
45171ae08745Sheppo 	numavail = (tx_head >> LDC_PACKET_SHIFT) - (tx_tail >> LDC_PACKET_SHIFT)
45181ae08745Sheppo 	    + ldcp->tx_q_entries - 1;
45191ae08745Sheppo 	numavail %= ldcp->tx_q_entries;
45201ae08745Sheppo 
45211ae08745Sheppo 	if (*size > (numavail * ldcp->pkt_payload)) {
45221ae08745Sheppo 		DWARN(DBG_ALL_LDCS,
45231ae08745Sheppo 		    "ldc_write: (0x%llx) TX queue has no space\n", ldcp->id);
45241ae08745Sheppo 		return (EWOULDBLOCK);
45251ae08745Sheppo 	}
45261ae08745Sheppo 
45271ae08745Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
45281ae08745Sheppo 	    ldcp->id, *size);
45291ae08745Sheppo 
45301ae08745Sheppo 	/* Send the data now */
45311ae08745Sheppo 	bytes_written = 0;
45321ae08745Sheppo 	curr_seqid = ldcp->last_msg_snt;
45331ae08745Sheppo 	start = tx_tail;
45341ae08745Sheppo 
45351ae08745Sheppo 	while (*size > bytes_written) {
45361ae08745Sheppo 
45371ae08745Sheppo 		ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
45381ae08745Sheppo 
453920ae46ebSha137994 		msgbuf = (uint8_t *)((ldcp->mode == LDC_MODE_RELIABLE) ?
454022f747efSnarayan 		    ldcmsg->rdata : ldcmsg->udata);
45411ae08745Sheppo 
45421ae08745Sheppo 		ldcmsg->type = LDC_DATA;
45431ae08745Sheppo 		ldcmsg->stype = LDC_INFO;
45441ae08745Sheppo 		ldcmsg->ctrl = 0;
45451ae08745Sheppo 
45461ae08745Sheppo 		remaining = *size - bytes_written;
45471ae08745Sheppo 		len = min(ldcp->pkt_payload, remaining);
45481ae08745Sheppo 		ldcmsg->env = (uint8_t)len;
45491ae08745Sheppo 
45501ae08745Sheppo 		curr_seqid++;
45511ae08745Sheppo 		ldcmsg->seqid = curr_seqid;
45521ae08745Sheppo 
45531ae08745Sheppo 		/* copy the data into pkt */
45541ae08745Sheppo 		bcopy(source, msgbuf, len);
45551ae08745Sheppo 
45561ae08745Sheppo 		source += len;
45571ae08745Sheppo 		bytes_written += len;
45581ae08745Sheppo 
45591ae08745Sheppo 		/* increment tail */
45601ae08745Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) & txq_size_mask;
45611ae08745Sheppo 
45621ae08745Sheppo 		ASSERT(tx_tail != tx_head);
45631ae08745Sheppo 	}
45641ae08745Sheppo 
45651ae08745Sheppo 	/* Set the start and stop bits */
45661ae08745Sheppo 	ldcmsg->env |= LDC_FRAG_STOP;
45671ae08745Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + start);
45681ae08745Sheppo 	ldcmsg->env |= LDC_FRAG_START;
45691ae08745Sheppo 
45701ae08745Sheppo 	/*
45711ae08745Sheppo 	 * All packets have been copied into the TX queue
45721ae08745Sheppo 	 * update the tail ptr in the HV
45731ae08745Sheppo 	 */
45741ae08745Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
45751ae08745Sheppo 	if (rv == 0) {
45761ae08745Sheppo 		ldcp->tx_tail = tx_tail;
45771ae08745Sheppo 		ldcp->last_msg_snt = curr_seqid;
45781ae08745Sheppo 		*size = bytes_written;
45791ae08745Sheppo 	} else {
45801ae08745Sheppo 		int rv2;
45811ae08745Sheppo 
45821ae08745Sheppo 		if (rv != EWOULDBLOCK) {
45831ae08745Sheppo 			*size = 0;
4584d10e4ef2Snarayan 			if (mutex_tryenter(&ldcp->lock)) {
45853af08d82Slm66018 				i_ldc_reset(ldcp, B_FALSE);
4586d10e4ef2Snarayan 				mutex_exit(&ldcp->lock);
4587d10e4ef2Snarayan 			} else {
4588d10e4ef2Snarayan 				/*
4589d10e4ef2Snarayan 				 * Release Tx lock, and then reacquire channel
4590d10e4ef2Snarayan 				 * and Tx lock in correct order
4591d10e4ef2Snarayan 				 */
4592d10e4ef2Snarayan 				mutex_exit(&ldcp->tx_lock);
4593d10e4ef2Snarayan 				mutex_enter(&ldcp->lock);
4594d10e4ef2Snarayan 				mutex_enter(&ldcp->tx_lock);
45953af08d82Slm66018 				i_ldc_reset(ldcp, B_FALSE);
4596d10e4ef2Snarayan 				mutex_exit(&ldcp->lock);
4597d10e4ef2Snarayan 			}
45981ae08745Sheppo 			return (ECONNRESET);
45991ae08745Sheppo 		}
46001ae08745Sheppo 
4601cb112a14Slm66018 		D1(ldcp->id, "hv_tx_set_tail returns 0x%x (head 0x%x, "
46021ae08745Sheppo 		    "old tail 0x%x, new tail 0x%x, qsize=0x%x)\n",
46031ae08745Sheppo 		    rv, ldcp->tx_head, ldcp->tx_tail, tx_tail,
46041ae08745Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
46051ae08745Sheppo 
46061ae08745Sheppo 		rv2 = hv_ldc_tx_get_state(ldcp->id,
46071ae08745Sheppo 		    &tx_head, &tx_tail, &ldcp->link_state);
46081ae08745Sheppo 
4609cb112a14Slm66018 		D1(ldcp->id, "hv_ldc_tx_get_state returns 0x%x "
46101ae08745Sheppo 		    "(head 0x%x, tail 0x%x state 0x%x)\n",
46111ae08745Sheppo 		    rv2, tx_head, tx_tail, ldcp->link_state);
46121ae08745Sheppo 
46131ae08745Sheppo 		*size = 0;
46141ae08745Sheppo 	}
46151ae08745Sheppo 
46161ae08745Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, *size);
46171ae08745Sheppo 
46181ae08745Sheppo 	return (rv);
46191ae08745Sheppo }
46201ae08745Sheppo 
46211ae08745Sheppo /*
46221ae08745Sheppo  * Write specified amount of bytes to the channel
46231ae08745Sheppo  * in multiple pkts of pkt_payload size. Each
46241ae08745Sheppo  * packet is tagged with an unique packet ID in
4625e1ebb9ecSlm66018  * the case of a reliable link.
46261ae08745Sheppo  *
46271ae08745Sheppo  * On return, size contains the number of bytes written.
46281ae08745Sheppo  * This function needs to ensure that the write size is < MTU size
46291ae08745Sheppo  */
46301ae08745Sheppo static int
i_ldc_write_stream(ldc_chan_t * ldcp,caddr_t buf,size_t * sizep)46311ae08745Sheppo i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
46321ae08745Sheppo {
4633d10e4ef2Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
463420ae46ebSha137994 	ASSERT(ldcp->mode == LDC_MODE_RELIABLE);
46351ae08745Sheppo 
46361ae08745Sheppo 	/* Truncate packet to max of MTU size */
46371ae08745Sheppo 	if (*sizep > ldcp->mtu) *sizep = ldcp->mtu;
46381ae08745Sheppo 	return (i_ldc_write_packet(ldcp, buf, sizep));
46391ae08745Sheppo }
46401ae08745Sheppo 
46411ae08745Sheppo 
46421ae08745Sheppo /*
46431ae08745Sheppo  * Interfaces for channel nexus to register/unregister with LDC module
46441ae08745Sheppo  * The nexus will register functions to be used to register individual
46451ae08745Sheppo  * channels with the nexus and enable interrupts for the channels
46461ae08745Sheppo  */
46471ae08745Sheppo int
ldc_register(ldc_cnex_t * cinfo)46481ae08745Sheppo ldc_register(ldc_cnex_t *cinfo)
46491ae08745Sheppo {
46501ae08745Sheppo 	ldc_chan_t	*ldcp;
46511ae08745Sheppo 
46521ae08745Sheppo 	if (cinfo == NULL || cinfo->dip == NULL ||
46531ae08745Sheppo 	    cinfo->reg_chan == NULL || cinfo->unreg_chan == NULL ||
46541ae08745Sheppo 	    cinfo->add_intr == NULL || cinfo->rem_intr == NULL ||
46551ae08745Sheppo 	    cinfo->clr_intr == NULL) {
46561ae08745Sheppo 
46571ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_register: invalid nexus info\n");
46581ae08745Sheppo 		return (EINVAL);
46591ae08745Sheppo 	}
46601ae08745Sheppo 
46611ae08745Sheppo 	mutex_enter(&ldcssp->lock);
46621ae08745Sheppo 
46631ae08745Sheppo 	/* nexus registration */
46641ae08745Sheppo 	ldcssp->cinfo.dip = cinfo->dip;
46651ae08745Sheppo 	ldcssp->cinfo.reg_chan = cinfo->reg_chan;
46661ae08745Sheppo 	ldcssp->cinfo.unreg_chan = cinfo->unreg_chan;
46671ae08745Sheppo 	ldcssp->cinfo.add_intr = cinfo->add_intr;
46681ae08745Sheppo 	ldcssp->cinfo.rem_intr = cinfo->rem_intr;
46691ae08745Sheppo 	ldcssp->cinfo.clr_intr = cinfo->clr_intr;
46701ae08745Sheppo 
46711ae08745Sheppo 	/* register any channels that might have been previously initialized */
46721ae08745Sheppo 	ldcp = ldcssp->chan_list;
46731ae08745Sheppo 	while (ldcp) {
46741ae08745Sheppo 		if ((ldcp->tstate & TS_QCONF_RDY) &&
46751ae08745Sheppo 		    (ldcp->tstate & TS_CNEX_RDY) == 0)
46761ae08745Sheppo 			(void) i_ldc_register_channel(ldcp);
46771ae08745Sheppo 
46781ae08745Sheppo 		ldcp = ldcp->next;
46791ae08745Sheppo 	}
46801ae08745Sheppo 
46811ae08745Sheppo 	mutex_exit(&ldcssp->lock);
46821ae08745Sheppo 
46831ae08745Sheppo 	return (0);
46841ae08745Sheppo }
46851ae08745Sheppo 
46861ae08745Sheppo int
ldc_unregister(ldc_cnex_t * cinfo)46871ae08745Sheppo ldc_unregister(ldc_cnex_t *cinfo)
46881ae08745Sheppo {
46891ae08745Sheppo 	if (cinfo == NULL || cinfo->dip == NULL) {
46901ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid nexus info\n");
46911ae08745Sheppo 		return (EINVAL);
46921ae08745Sheppo 	}
46931ae08745Sheppo 
46941ae08745Sheppo 	mutex_enter(&ldcssp->lock);
46951ae08745Sheppo 
46961ae08745Sheppo 	if (cinfo->dip != ldcssp->cinfo.dip) {
46971ae08745Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid dip\n");
46981ae08745Sheppo 		mutex_exit(&ldcssp->lock);
46991ae08745Sheppo 		return (EINVAL);
47001ae08745Sheppo 	}
47011ae08745Sheppo 
47021ae08745Sheppo 	/* nexus unregister */
47031ae08745Sheppo 	ldcssp->cinfo.dip = NULL;
47041ae08745Sheppo 	ldcssp->cinfo.reg_chan = NULL;
47051ae08745Sheppo 	ldcssp->cinfo.unreg_chan = NULL;
47061ae08745Sheppo 	ldcssp->cinfo.add_intr = NULL;
47071ae08745Sheppo 	ldcssp->cinfo.rem_intr = NULL;
47081ae08745Sheppo 	ldcssp->cinfo.clr_intr = NULL;
47091ae08745Sheppo 
47101ae08745Sheppo 	mutex_exit(&ldcssp->lock);
47111ae08745Sheppo 
47121ae08745Sheppo 	return (0);
47131ae08745Sheppo }
471434f94fbcSWENTAO YANG 
471534f94fbcSWENTAO YANG int
ldc_info(ldc_handle_t handle,ldc_info_t * info)471634f94fbcSWENTAO YANG ldc_info(ldc_handle_t handle, ldc_info_t *info)
471734f94fbcSWENTAO YANG {
471834f94fbcSWENTAO YANG 	ldc_chan_t	*ldcp;
471934f94fbcSWENTAO YANG 	uint64_t	avail;
472034f94fbcSWENTAO YANG 
4721*a704fb2dSToomas Soome 	if (handle == 0 || info == NULL) {
472234f94fbcSWENTAO YANG 		DWARN(DBG_ALL_LDCS, "ldc_get_info: invalid args\n");
472334f94fbcSWENTAO YANG 		return (EINVAL);
472434f94fbcSWENTAO YANG 	}
472534f94fbcSWENTAO YANG 
472634f94fbcSWENTAO YANG 	ldcp = (ldc_chan_t *)handle;
472734f94fbcSWENTAO YANG 
472834f94fbcSWENTAO YANG 	mutex_enter(&ldcp->lock);
472934f94fbcSWENTAO YANG 
473034f94fbcSWENTAO YANG 	/* check to see if channel is initalized */
473134f94fbcSWENTAO YANG 	if ((ldcp->tstate & ~TS_IN_RESET) < TS_INIT) {
473234f94fbcSWENTAO YANG 		DWARN(ldcp->id,
473334f94fbcSWENTAO YANG 		    "ldc_get_info: (0x%llx) channel not initialized\n",
473434f94fbcSWENTAO YANG 		    ldcp->id);
473534f94fbcSWENTAO YANG 		mutex_exit(&ldcp->lock);
473634f94fbcSWENTAO YANG 		return (EINVAL);
473734f94fbcSWENTAO YANG 	}
473834f94fbcSWENTAO YANG 
473934f94fbcSWENTAO YANG 	mutex_exit(&ldcp->lock);
474034f94fbcSWENTAO YANG 
474134f94fbcSWENTAO YANG 	/*
474234f94fbcSWENTAO YANG 	 * ldcssp->mapin_size is the max amount of shared memory supported by
474334f94fbcSWENTAO YANG 	 * the Hypervisor per guest. e.g, legacy HV supports 64MB; latest HV
474434f94fbcSWENTAO YANG 	 * support 1GB. This size is read during ldc module initialization.
474534f94fbcSWENTAO YANG 	 *
474634f94fbcSWENTAO YANG 	 * ldc_dring_direct_map_rsvd is the amount of memory reserved for
474734f94fbcSWENTAO YANG 	 * mapping in descriptor rings. In the initial implementation, we use a
474834f94fbcSWENTAO YANG 	 * simple approach to determine the amount of mapin space available per
474934f94fbcSWENTAO YANG 	 * channel. In future, we may implement strict accounting of the actual
475034f94fbcSWENTAO YANG 	 * memory consumed to determine the exact amount available per channel.
475134f94fbcSWENTAO YANG 	 */
475234f94fbcSWENTAO YANG 	if (ldcssp->mapin_size <= ldc_dring_direct_map_rsvd) {
475334f94fbcSWENTAO YANG 		info->direct_map_size_max = 0;
475434f94fbcSWENTAO YANG 		return (0);
475534f94fbcSWENTAO YANG 	}
475634f94fbcSWENTAO YANG 
475734f94fbcSWENTAO YANG 	avail = ldcssp->mapin_size - ldc_dring_direct_map_rsvd;
475834f94fbcSWENTAO YANG 	if (avail >= ldc_direct_map_size_max) {
475934f94fbcSWENTAO YANG 		info->direct_map_size_max = ldc_direct_map_size_max;
476034f94fbcSWENTAO YANG 	} else {
476134f94fbcSWENTAO YANG 		info->direct_map_size_max = 0;
476234f94fbcSWENTAO YANG 	}
476334f94fbcSWENTAO YANG 
476434f94fbcSWENTAO YANG 	return (0);
476534f94fbcSWENTAO YANG }
4766