xref: /onnv-gate/usr/src/uts/sun4v/io/ldc.c (revision 13098:496fd9979cfc)
11991Sheppo /*
21991Sheppo  * CDDL HEADER START
31991Sheppo  *
41991Sheppo  * The contents of this file are subject to the terms of the
51991Sheppo  * Common Development and Distribution License (the "License").
61991Sheppo  * You may not use this file except in compliance with the License.
71991Sheppo  *
81991Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91991Sheppo  * or http://www.opensolaris.org/os/licensing.
101991Sheppo  * See the License for the specific language governing permissions
111991Sheppo  * and limitations under the License.
121991Sheppo  *
131991Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141991Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151991Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161991Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171991Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181991Sheppo  *
191991Sheppo  * CDDL HEADER END
201991Sheppo  */
211991Sheppo 
221991Sheppo /*
23*13098SWentao.Yang@Sun.COM  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
241991Sheppo  */
251991Sheppo 
261991Sheppo /*
272410Slm66018  * sun4v LDC Link Layer
281991Sheppo  */
291991Sheppo #include <sys/types.h>
301991Sheppo #include <sys/file.h>
311991Sheppo #include <sys/errno.h>
321991Sheppo #include <sys/open.h>
331991Sheppo #include <sys/cred.h>
341991Sheppo #include <sys/kmem.h>
351991Sheppo #include <sys/conf.h>
361991Sheppo #include <sys/cmn_err.h>
371991Sheppo #include <sys/ksynch.h>
381991Sheppo #include <sys/modctl.h>
391991Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */
401991Sheppo #include <sys/debug.h>
411991Sheppo #include <sys/cred.h>
421991Sheppo #include <sys/promif.h>
431991Sheppo #include <sys/ddi.h>
441991Sheppo #include <sys/sunddi.h>
451991Sheppo #include <sys/cyclic.h>
461991Sheppo #include <sys/machsystm.h>
471991Sheppo #include <sys/vm.h>
481991Sheppo #include <sys/cpu.h>
491991Sheppo #include <sys/intreg.h>
501991Sheppo #include <sys/machcpuvar.h>
512531Snarayan #include <sys/mmu.h>
522531Snarayan #include <sys/pte.h>
532531Snarayan #include <vm/hat.h>
542531Snarayan #include <vm/as.h>
552531Snarayan #include <vm/hat_sfmmu.h>
562531Snarayan #include <sys/vm_machparam.h>
572531Snarayan #include <vm/seg_kmem.h>
582531Snarayan #include <vm/seg_kpm.h>
591991Sheppo #include <sys/note.h>
601991Sheppo #include <sys/ivintr.h>
611991Sheppo #include <sys/hypervisor_api.h>
621991Sheppo #include <sys/ldc.h>
631991Sheppo #include <sys/ldc_impl.h>
641991Sheppo #include <sys/cnex.h>
651991Sheppo #include <sys/hsvc.h>
665944Sha137994 #include <sys/sdt.h>
678542SHaik.Aftandilian@Sun.COM #include <sys/kldc.h>
681991Sheppo 
691991Sheppo /* Core internal functions */
706408Sha137994 int i_ldc_h2v_error(int h_error);
716408Sha137994 void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset);
726408Sha137994 
731991Sheppo static int i_ldc_txq_reconf(ldc_chan_t *ldcp);
742793Slm66018 static int i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset);
7510055SKevin.Crowe@Sun.COM static void i_ldc_rxq_drain(ldc_chan_t *ldcp);
761991Sheppo static void i_ldc_reset_state(ldc_chan_t *ldcp);
778542SHaik.Aftandilian@Sun.COM static void i_ldc_debug_enter(void);
781991Sheppo 
791991Sheppo static int i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail);
804690Snarayan static void i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head);
811991Sheppo static int i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail);
821991Sheppo static int i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head);
831991Sheppo static int i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
841991Sheppo     uint8_t ctrlmsg);
851991Sheppo 
865944Sha137994 static int  i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head);
875944Sha137994 static void i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head);
885944Sha137994 static uint64_t i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head,
895944Sha137994     uint64_t *tail, uint64_t *link_state);
905944Sha137994 static uint64_t i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head,
915944Sha137994     uint64_t *tail, uint64_t *link_state);
925944Sha137994 static int i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head,
935944Sha137994     uint64_t rx_tail);
945944Sha137994 static uint_t i_ldc_chkq(ldc_chan_t *ldcp);
955944Sha137994 
961991Sheppo /* Interrupt handling functions */
971991Sheppo static uint_t i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2);
981991Sheppo static uint_t i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2);
995944Sha137994 static uint_t i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client,
1005944Sha137994     uint64_t *notify_event);
1011991Sheppo static void i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype);
1021991Sheppo 
1031991Sheppo /* Read method functions */
1041991Sheppo static int i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep);
1051991Sheppo static int i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp,
1061991Sheppo 	size_t *sizep);
1071991Sheppo static int i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp,
1081991Sheppo 	size_t *sizep);
1091991Sheppo 
1101991Sheppo /* Write method functions */
1111991Sheppo static int i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t target_bufp,
1121991Sheppo 	size_t *sizep);
1131991Sheppo static int i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t target_bufp,
1141991Sheppo 	size_t *sizep);
1151991Sheppo static int i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t target_bufp,
1161991Sheppo 	size_t *sizep);
1171991Sheppo 
1181991Sheppo /* Pkt processing internal functions */
1191991Sheppo static int i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg);
1201991Sheppo static int i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg);
1211991Sheppo static int i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg);
1221991Sheppo static int i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg);
1231991Sheppo static int i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg);
1241991Sheppo static int i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg);
1251991Sheppo static int i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg);
1261991Sheppo 
127*13098SWentao.Yang@Sun.COM /* Imported functions */
128*13098SWentao.Yang@Sun.COM extern void i_ldc_mem_set_hsvc_vers(uint64_t major, uint64_t minor);
129*13098SWentao.Yang@Sun.COM extern void i_ldc_init_mapin(ldc_soft_state_t *ldcssp, uint64_t major,
130*13098SWentao.Yang@Sun.COM 	uint64_t minor);
131*13098SWentao.Yang@Sun.COM 
1321991Sheppo /* LDC Version */
1331991Sheppo static ldc_ver_t ldc_versions[] = { {1, 0} };
1341991Sheppo 
1351991Sheppo /* number of supported versions */
1361991Sheppo #define	LDC_NUM_VERS	(sizeof (ldc_versions) / sizeof (ldc_versions[0]))
1371991Sheppo 
1385944Sha137994 /* Invalid value for the ldc_chan_t rx_ack_head field */
1395944Sha137994 #define	ACKPEEK_HEAD_INVALID	((uint64_t)-1)
1405944Sha137994 
1415944Sha137994 
1421991Sheppo /* Module State Pointer */
1436408Sha137994 ldc_soft_state_t *ldcssp;
1441991Sheppo 
1451991Sheppo static struct modldrv md = {
1461991Sheppo 	&mod_miscops,			/* This is a misc module */
1477799SRichard.Bean@Sun.COM 	"sun4v LDC module",		/* Name of the module */
1481991Sheppo };
1491991Sheppo 
1501991Sheppo static struct modlinkage ml = {
1511991Sheppo 	MODREV_1,
1521991Sheppo 	&md,
1531991Sheppo 	NULL
1541991Sheppo };
1551991Sheppo 
1561991Sheppo static uint64_t ldc_sup_minor;		/* Supported minor number */
1571991Sheppo static hsvc_info_t ldc_hsvc = {
158*13098SWentao.Yang@Sun.COM 	HSVC_REV_1, NULL, HSVC_GROUP_LDC, 1, 2, "ldc"
1591991Sheppo };
1601991Sheppo 
1612531Snarayan /*
1622410Slm66018  * The no. of MTU size messages that can be stored in
1632410Slm66018  * the LDC Tx queue. The number of Tx queue entries is
1642410Slm66018  * then computed as (mtu * mtu_msgs)/sizeof(queue_entry)
1652410Slm66018  */
1662410Slm66018 uint64_t ldc_mtu_msgs = LDC_MTU_MSGS;
1672410Slm66018 
1682410Slm66018 /*
1692410Slm66018  * The minimum queue length. This is the size of the smallest
1702410Slm66018  * LDC queue. If the computed value is less than this default,
1712410Slm66018  * the queue length is rounded up to 'ldc_queue_entries'.
1722410Slm66018  */
1732410Slm66018 uint64_t ldc_queue_entries = LDC_QUEUE_ENTRIES;
1742410Slm66018 
1752410Slm66018 /*
1765944Sha137994  * The length of the reliable-mode data queue in terms of the LDC
1775944Sha137994  * receive queue length. i.e., the number of times larger than the
1785944Sha137994  * LDC receive queue that the data queue should be. The HV receive
1795944Sha137994  * queue is required to be a power of 2 and this implementation
1805944Sha137994  * assumes the data queue will also be a power of 2. By making the
1815944Sha137994  * multiplier a power of 2, we ensure the data queue will be a
1825944Sha137994  * power of 2. We use a multiplier because the receive queue is
1835944Sha137994  * sized to be sane relative to the MTU and the same is needed for
1845944Sha137994  * the data queue.
1855944Sha137994  */
1865944Sha137994 uint64_t ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER;
1875944Sha137994 
1885944Sha137994 /*
1892410Slm66018  * LDC retry count and delay - when the HV returns EWOULDBLOCK
1902410Slm66018  * the operation is retried 'ldc_max_retries' times with a
1912410Slm66018  * wait of 'ldc_delay' usecs between each retry.
1922032Slm66018  */
1932032Slm66018 int ldc_max_retries = LDC_MAX_RETRIES;
1942032Slm66018 clock_t ldc_delay = LDC_DELAY;
1952032Slm66018 
1963151Ssg70180 /*
1978542SHaik.Aftandilian@Sun.COM  * Channels which have a devclass satisfying the following
1988542SHaik.Aftandilian@Sun.COM  * will be reset when entering the prom or kmdb.
1998542SHaik.Aftandilian@Sun.COM  *
2008542SHaik.Aftandilian@Sun.COM  *   LDC_DEVCLASS_PROM_RESET(devclass) != 0
2018542SHaik.Aftandilian@Sun.COM  *
2028542SHaik.Aftandilian@Sun.COM  * By default, only block device service channels are reset.
2038542SHaik.Aftandilian@Sun.COM  */
2048542SHaik.Aftandilian@Sun.COM #define	LDC_DEVCLASS_BIT(dc)		(0x1 << (dc))
2058542SHaik.Aftandilian@Sun.COM #define	LDC_DEVCLASS_PROM_RESET(dc)	\
2068542SHaik.Aftandilian@Sun.COM 	(LDC_DEVCLASS_BIT(dc) & ldc_debug_reset_mask)
20711057SZachary.Kissel@Sun.COM static uint64_t ldc_debug_reset_mask = LDC_DEVCLASS_BIT(LDC_DEV_BLK_SVC) |
20811057SZachary.Kissel@Sun.COM     LDC_DEVCLASS_BIT(LDC_DEV_GENERIC);
2098542SHaik.Aftandilian@Sun.COM 
2108542SHaik.Aftandilian@Sun.COM /*
2113151Ssg70180  * delay between each retry of channel unregistration in
2123151Ssg70180  * ldc_close(), to wait for pending interrupts to complete.
2133151Ssg70180  */
2143151Ssg70180 clock_t ldc_close_delay = LDC_CLOSE_DELAY;
2153151Ssg70180 
216*13098SWentao.Yang@Sun.COM 
217*13098SWentao.Yang@Sun.COM /*
218*13098SWentao.Yang@Sun.COM  * Reserved mapin space for descriptor rings.
219*13098SWentao.Yang@Sun.COM  */
220*13098SWentao.Yang@Sun.COM uint64_t ldc_dring_direct_map_rsvd = LDC_DIRECT_MAP_SIZE_DEFAULT;
221*13098SWentao.Yang@Sun.COM 
222*13098SWentao.Yang@Sun.COM /*
223*13098SWentao.Yang@Sun.COM  * Maximum direct map space allowed per channel.
224*13098SWentao.Yang@Sun.COM  */
225*13098SWentao.Yang@Sun.COM uint64_t	ldc_direct_map_size_max = (16 * 1024 * 1024);	/* 16 MB */
226*13098SWentao.Yang@Sun.COM 
2271991Sheppo #ifdef DEBUG
2281991Sheppo 
2291991Sheppo /*
2301991Sheppo  * Print debug messages
2311991Sheppo  *
2321991Sheppo  * set ldcdbg to 0x7 for enabling all msgs
2331991Sheppo  * 0x4 - Warnings
2341991Sheppo  * 0x2 - All debug messages
2351991Sheppo  * 0x1 - Minimal debug messages
2361991Sheppo  *
2371991Sheppo  * set ldcdbgchan to the channel number you want to debug
2381991Sheppo  * setting it to -1 prints debug messages for all channels
2391991Sheppo  * NOTE: ldcdbgchan has no effect on error messages
2401991Sheppo  */
2411991Sheppo 
2421991Sheppo int ldcdbg = 0x0;
2431991Sheppo int64_t ldcdbgchan = DBG_ALL_LDCS;
2443560Snarayan uint64_t ldc_inject_err_flag = 0;
2451991Sheppo 
2466408Sha137994 void
ldcdebug(int64_t id,const char * fmt,...)2471991Sheppo ldcdebug(int64_t id, const char *fmt, ...)
2481991Sheppo {
2491991Sheppo 	char buf[512];
2501991Sheppo 	va_list ap;
2511991Sheppo 
2521991Sheppo 	/*
2531991Sheppo 	 * Do not return if,
2541991Sheppo 	 * caller wants to print it anyway - (id == DBG_ALL_LDCS)
2551991Sheppo 	 * debug channel is set to all LDCs - (ldcdbgchan == DBG_ALL_LDCS)
2561991Sheppo 	 * debug channel = caller specified channel
2571991Sheppo 	 */
2581991Sheppo 	if ((id != DBG_ALL_LDCS) &&
2591991Sheppo 	    (ldcdbgchan != DBG_ALL_LDCS) &&
2601991Sheppo 	    (ldcdbgchan != id)) {
2611991Sheppo 		return;
2621991Sheppo 	}
2631991Sheppo 
2641991Sheppo 	va_start(ap, fmt);
2651991Sheppo 	(void) vsprintf(buf, fmt, ap);
2661991Sheppo 	va_end(ap);
2671991Sheppo 
2682793Slm66018 	cmn_err(CE_CONT, "?%s", buf);
2692793Slm66018 }
2702793Slm66018 
2716845Sha137994 #define	LDC_ERR_RESET		0x1
2726845Sha137994 #define	LDC_ERR_PKTLOSS		0x2
2736845Sha137994 #define	LDC_ERR_DQFULL		0x4
2746845Sha137994 #define	LDC_ERR_DRNGCLEAR	0x8
2753560Snarayan 
2762793Slm66018 static boolean_t
ldc_inject_error(ldc_chan_t * ldcp,uint64_t error)2773560Snarayan ldc_inject_error(ldc_chan_t *ldcp, uint64_t error)
2782793Slm66018 {
2792793Slm66018 	if ((ldcdbgchan != DBG_ALL_LDCS) && (ldcdbgchan != ldcp->id))
2802793Slm66018 		return (B_FALSE);
2812793Slm66018 
2823560Snarayan 	if ((ldc_inject_err_flag & error) == 0)
2832793Slm66018 		return (B_FALSE);
2842793Slm66018 
2852793Slm66018 	/* clear the injection state */
2863560Snarayan 	ldc_inject_err_flag &= ~error;
2872793Slm66018 
2882793Slm66018 	return (B_TRUE);
2891991Sheppo }
2901991Sheppo 
2911991Sheppo #define	D1		\
2921991Sheppo if (ldcdbg & 0x01)	\
2931991Sheppo 	ldcdebug
2941991Sheppo 
2951991Sheppo #define	D2		\
2961991Sheppo if (ldcdbg & 0x02)	\
2971991Sheppo 	ldcdebug
2981991Sheppo 
2991991Sheppo #define	DWARN		\
3001991Sheppo if (ldcdbg & 0x04)	\
3011991Sheppo 	ldcdebug
3021991Sheppo 
3031991Sheppo #define	DUMP_PAYLOAD(id, addr)						\
3041991Sheppo {									\
3051991Sheppo 	char buf[65*3];							\
3061991Sheppo 	int i;								\
3071991Sheppo 	uint8_t *src = (uint8_t *)addr;					\
3081991Sheppo 	for (i = 0; i < 64; i++, src++)					\
3091991Sheppo 		(void) sprintf(&buf[i * 3], "|%02x", *src);		\
3101991Sheppo 	(void) sprintf(&buf[i * 3], "|\n");				\
3111991Sheppo 	D2((id), "payload: %s", buf);					\
3121991Sheppo }
3131991Sheppo 
3141991Sheppo #define	DUMP_LDC_PKT(c, s, addr)					\
3151991Sheppo {									\
3161991Sheppo 	ldc_msg_t *msg = (ldc_msg_t *)(addr);				\
3171991Sheppo 	uint32_t mid = ((c)->mode != LDC_MODE_RAW) ? msg->seqid : 0;	\
3181991Sheppo 	if (msg->type == LDC_DATA) {                                    \
3191991Sheppo 	    D2((c)->id, "%s: msg%d (/%x/%x/%x/,env[%c%c,sz=%d])",	\
3201991Sheppo 	    (s), mid, msg->type, msg->stype, msg->ctrl,			\
3211991Sheppo 	    (msg->env & LDC_FRAG_START) ? 'B' : ' ',                    \
3221991Sheppo 	    (msg->env & LDC_FRAG_STOP) ? 'E' : ' ',                     \
3231991Sheppo 	    (msg->env & LDC_LEN_MASK));					\
3241991Sheppo 	} else { 							\
3251991Sheppo 	    D2((c)->id, "%s: msg%d (/%x/%x/%x/,env=%x)", (s),		\
3261991Sheppo 	    mid, msg->type, msg->stype, msg->ctrl, msg->env);		\
3271991Sheppo 	} 								\
3281991Sheppo }
3291991Sheppo 
3303560Snarayan #define	LDC_INJECT_RESET(_ldcp)	ldc_inject_error(_ldcp, LDC_ERR_RESET)
3313560Snarayan #define	LDC_INJECT_PKTLOSS(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_PKTLOSS)
3325944Sha137994 #define	LDC_INJECT_DQFULL(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DQFULL)
3336845Sha137994 #define	LDC_INJECT_DRNGCLEAR(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DRNGCLEAR)
3346845Sha137994 extern void i_ldc_mem_inject_dring_clear(ldc_chan_t *ldcp);
3352793Slm66018 
3361991Sheppo #else
3371991Sheppo 
3381991Sheppo #define	DBG_ALL_LDCS -1
3391991Sheppo 
3401991Sheppo #define	D1
3411991Sheppo #define	D2
3421991Sheppo #define	DWARN
3431991Sheppo 
3441991Sheppo #define	DUMP_PAYLOAD(id, addr)
3451991Sheppo #define	DUMP_LDC_PKT(c, s, addr)
3461991Sheppo 
3472793Slm66018 #define	LDC_INJECT_RESET(_ldcp)	(B_FALSE)
3483560Snarayan #define	LDC_INJECT_PKTLOSS(_ldcp) (B_FALSE)
3495944Sha137994 #define	LDC_INJECT_DQFULL(_ldcp) (B_FALSE)
3506845Sha137994 #define	LDC_INJECT_DRNGCLEAR(_ldcp) (B_FALSE)
3512793Slm66018 
3521991Sheppo #endif
3531991Sheppo 
3545944Sha137994 /*
3555944Sha137994  * dtrace SDT probes to ease tracing of the rx data queue and HV queue
3565944Sha137994  * lengths. Just pass the head, tail, and entries values so that the
3575944Sha137994  * length can be calculated in a dtrace script when the probe is enabled.
3585944Sha137994  */
3595944Sha137994 #define	TRACE_RXDQ_LENGTH(ldcp)						\
3605944Sha137994 	DTRACE_PROBE4(rxdq__size,					\
3615944Sha137994 	uint64_t, ldcp->id,						\
3625944Sha137994 	uint64_t, ldcp->rx_dq_head,					\
3635944Sha137994 	uint64_t, ldcp->rx_dq_tail,					\
3645944Sha137994 	uint64_t, ldcp->rx_dq_entries)
3655944Sha137994 
3665944Sha137994 #define	TRACE_RXHVQ_LENGTH(ldcp, head, tail)				\
3675944Sha137994 	DTRACE_PROBE4(rxhvq__size,					\
3685944Sha137994 	uint64_t, ldcp->id,						\
3695944Sha137994 	uint64_t, head,							\
3705944Sha137994 	uint64_t, tail,							\
3715944Sha137994 	uint64_t, ldcp->rx_q_entries)
3725944Sha137994 
3735944Sha137994 /* A dtrace SDT probe to ease tracing of data queue copy operations */
3745944Sha137994 #define	TRACE_RXDQ_COPY(ldcp, bytes)					\
3755944Sha137994 	DTRACE_PROBE2(rxdq__copy, uint64_t, ldcp->id, uint64_t, bytes)	\
3765944Sha137994 
3775944Sha137994 /* The amount of contiguous space at the tail of the queue */
3785944Sha137994 #define	Q_CONTIG_SPACE(head, tail, size)				\
3795944Sha137994 	((head) <= (tail) ? ((size) - (tail)) :				\
3805944Sha137994 	((head) - (tail) - LDC_PACKET_SIZE))
3815944Sha137994 
3821991Sheppo #define	ZERO_PKT(p)			\
3831991Sheppo 	bzero((p), sizeof (ldc_msg_t));
3841991Sheppo 
3851991Sheppo #define	IDX2COOKIE(idx, pg_szc, pg_shift)				\
3861991Sheppo 	(((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift)))
3871991Sheppo 
3881991Sheppo int
_init(void)3891991Sheppo _init(void)
3901991Sheppo {
3911991Sheppo 	int status;
3921991Sheppo 
3931991Sheppo 	status = hsvc_register(&ldc_hsvc, &ldc_sup_minor);
3941991Sheppo 	if (status != 0) {
3954423Sjb145095 		cmn_err(CE_NOTE, "!%s: cannot negotiate hypervisor LDC services"
3961991Sheppo 		    " group: 0x%lx major: %ld minor: %ld errno: %d",
3971991Sheppo 		    ldc_hsvc.hsvc_modname, ldc_hsvc.hsvc_group,
3981991Sheppo 		    ldc_hsvc.hsvc_major, ldc_hsvc.hsvc_minor, status);
3991991Sheppo 		return (-1);
4001991Sheppo 	}
4011991Sheppo 
4026845Sha137994 	/* Initialize shared memory HV API version checking */
4036845Sha137994 	i_ldc_mem_set_hsvc_vers(ldc_hsvc.hsvc_major, ldc_sup_minor);
4046845Sha137994 
4051991Sheppo 	/* allocate soft state structure */
4061991Sheppo 	ldcssp = kmem_zalloc(sizeof (ldc_soft_state_t), KM_SLEEP);
4071991Sheppo 
408*13098SWentao.Yang@Sun.COM 	i_ldc_init_mapin(ldcssp, ldc_hsvc.hsvc_major, ldc_sup_minor);
409*13098SWentao.Yang@Sun.COM 
4101991Sheppo 	/* Link the module into the system */
4111991Sheppo 	status = mod_install(&ml);
4121991Sheppo 	if (status != 0) {
4131991Sheppo 		kmem_free(ldcssp, sizeof (ldc_soft_state_t));
4141991Sheppo 		return (status);
4151991Sheppo 	}
4161991Sheppo 
4171991Sheppo 	/* Initialize the LDC state structure */
4181991Sheppo 	mutex_init(&ldcssp->lock, NULL, MUTEX_DRIVER, NULL);
4191991Sheppo 
4201991Sheppo 	mutex_enter(&ldcssp->lock);
4211991Sheppo 
4222531Snarayan 	/* Create a cache for memory handles */
4232531Snarayan 	ldcssp->memhdl_cache = kmem_cache_create("ldc_memhdl_cache",
4242531Snarayan 	    sizeof (ldc_mhdl_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
4252531Snarayan 	if (ldcssp->memhdl_cache == NULL) {
4262531Snarayan 		DWARN(DBG_ALL_LDCS, "_init: ldc_memhdl cache create failed\n");
4272531Snarayan 		mutex_exit(&ldcssp->lock);
4282531Snarayan 		return (-1);
4292531Snarayan 	}
4302531Snarayan 
4312531Snarayan 	/* Create cache for memory segment structures */
4322531Snarayan 	ldcssp->memseg_cache = kmem_cache_create("ldc_memseg_cache",
4332531Snarayan 	    sizeof (ldc_memseg_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
4342531Snarayan 	if (ldcssp->memseg_cache == NULL) {
4352531Snarayan 		DWARN(DBG_ALL_LDCS, "_init: ldc_memseg cache create failed\n");
4362531Snarayan 		mutex_exit(&ldcssp->lock);
4372531Snarayan 		return (-1);
4382531Snarayan 	}
4392531Snarayan 
4402531Snarayan 
4411991Sheppo 	ldcssp->channel_count = 0;
4421991Sheppo 	ldcssp->channels_open = 0;
4431991Sheppo 	ldcssp->chan_list = NULL;
4441991Sheppo 	ldcssp->dring_list = NULL;
4451991Sheppo 
4468542SHaik.Aftandilian@Sun.COM 	/* Register debug_enter callback */
4478542SHaik.Aftandilian@Sun.COM 	kldc_set_debug_cb(&i_ldc_debug_enter);
4488542SHaik.Aftandilian@Sun.COM 
4491991Sheppo 	mutex_exit(&ldcssp->lock);
4501991Sheppo 
4511991Sheppo 	return (0);
4521991Sheppo }
4531991Sheppo 
4541991Sheppo int
_info(struct modinfo * modinfop)4551991Sheppo _info(struct modinfo *modinfop)
4561991Sheppo {
4571991Sheppo 	/* Report status of the dynamically loadable driver module */
4581991Sheppo 	return (mod_info(&ml, modinfop));
4591991Sheppo }
4601991Sheppo 
4611991Sheppo int
_fini(void)4621991Sheppo _fini(void)
4631991Sheppo {
4641991Sheppo 	int 		rv, status;
4654690Snarayan 	ldc_chan_t 	*tmp_ldcp, *ldcp;
4664690Snarayan 	ldc_dring_t 	*tmp_dringp, *dringp;
4671991Sheppo 	ldc_mem_info_t 	minfo;
4681991Sheppo 
4691991Sheppo 	/* Unlink the driver module from the system */
4701991Sheppo 	status = mod_remove(&ml);
4711991Sheppo 	if (status) {
4721991Sheppo 		DWARN(DBG_ALL_LDCS, "_fini: mod_remove failed\n");
4731991Sheppo 		return (EIO);
4741991Sheppo 	}
4751991Sheppo 
4768542SHaik.Aftandilian@Sun.COM 	/* Unregister debug_enter callback */
4778542SHaik.Aftandilian@Sun.COM 	kldc_set_debug_cb(NULL);
4788542SHaik.Aftandilian@Sun.COM 
4791991Sheppo 	/* Free descriptor rings */
4801991Sheppo 	dringp = ldcssp->dring_list;
4811991Sheppo 	while (dringp != NULL) {
4824690Snarayan 		tmp_dringp = dringp->next;
4831991Sheppo 
4841991Sheppo 		rv = ldc_mem_dring_info((ldc_dring_handle_t)dringp, &minfo);
4851991Sheppo 		if (rv == 0 && minfo.status != LDC_UNBOUND) {
4861991Sheppo 			if (minfo.status == LDC_BOUND) {
4871991Sheppo 				(void) ldc_mem_dring_unbind(
4884690Snarayan 				    (ldc_dring_handle_t)dringp);
4891991Sheppo 			}
4901991Sheppo 			if (minfo.status == LDC_MAPPED) {
4911991Sheppo 				(void) ldc_mem_dring_unmap(
4924690Snarayan 				    (ldc_dring_handle_t)dringp);
4931991Sheppo 			}
4941991Sheppo 		}
4951991Sheppo 
4961991Sheppo 		(void) ldc_mem_dring_destroy((ldc_dring_handle_t)dringp);
4974690Snarayan 		dringp = tmp_dringp;
4981991Sheppo 	}
4991991Sheppo 	ldcssp->dring_list = NULL;
5001991Sheppo 
5014690Snarayan 	/* close and finalize channels */
5024690Snarayan 	ldcp = ldcssp->chan_list;
5034690Snarayan 	while (ldcp != NULL) {
5044690Snarayan 		tmp_ldcp = ldcp->next;
5054690Snarayan 
5064690Snarayan 		(void) ldc_close((ldc_handle_t)ldcp);
5074690Snarayan 		(void) ldc_fini((ldc_handle_t)ldcp);
5084690Snarayan 
5094690Snarayan 		ldcp = tmp_ldcp;
5104690Snarayan 	}
5114690Snarayan 	ldcssp->chan_list = NULL;
5124690Snarayan 
5132531Snarayan 	/* Destroy kmem caches */
5142531Snarayan 	kmem_cache_destroy(ldcssp->memhdl_cache);
5152531Snarayan 	kmem_cache_destroy(ldcssp->memseg_cache);
5162531Snarayan 
5171991Sheppo 	/*
5181991Sheppo 	 * We have successfully "removed" the driver.
5191991Sheppo 	 * Destroying soft states
5201991Sheppo 	 */
5211991Sheppo 	mutex_destroy(&ldcssp->lock);
5221991Sheppo 	kmem_free(ldcssp, sizeof (ldc_soft_state_t));
5231991Sheppo 
5241991Sheppo 	(void) hsvc_unregister(&ldc_hsvc);
5251991Sheppo 
5261991Sheppo 	return (status);
5271991Sheppo }
5281991Sheppo 
5291991Sheppo /* -------------------------------------------------------------------------- */
5301991Sheppo 
5311991Sheppo /*
5322410Slm66018  * LDC Link Layer Internal Functions
5331991Sheppo  */
5341991Sheppo 
5351991Sheppo /*
5361991Sheppo  * Translate HV Errors to sun4v error codes
5371991Sheppo  */
5386408Sha137994 int
i_ldc_h2v_error(int h_error)5391991Sheppo i_ldc_h2v_error(int h_error)
5401991Sheppo {
5411991Sheppo 	switch (h_error) {
5421991Sheppo 
5431991Sheppo 	case	H_EOK:
5441991Sheppo 		return (0);
5451991Sheppo 
5461991Sheppo 	case	H_ENORADDR:
5471991Sheppo 		return (EFAULT);
5481991Sheppo 
5491991Sheppo 	case	H_EBADPGSZ:
5501991Sheppo 	case	H_EINVAL:
5511991Sheppo 		return (EINVAL);
5521991Sheppo 
5531991Sheppo 	case	H_EWOULDBLOCK:
5541991Sheppo 		return (EWOULDBLOCK);
5551991Sheppo 
5561991Sheppo 	case	H_ENOACCESS:
5571991Sheppo 	case	H_ENOMAP:
5581991Sheppo 		return (EACCES);
5591991Sheppo 
5601991Sheppo 	case	H_EIO:
5611991Sheppo 	case	H_ECPUERROR:
5621991Sheppo 		return (EIO);
5631991Sheppo 
5641991Sheppo 	case	H_ENOTSUPPORTED:
5651991Sheppo 		return (ENOTSUP);
5661991Sheppo 
5671991Sheppo 	case 	H_ETOOMANY:
5681991Sheppo 		return (ENOSPC);
5691991Sheppo 
5701991Sheppo 	case	H_ECHANNEL:
5711991Sheppo 		return (ECHRNG);
5721991Sheppo 	default:
5731991Sheppo 		break;
5741991Sheppo 	}
5751991Sheppo 
5761991Sheppo 	return (EIO);
5771991Sheppo }
5781991Sheppo 
5791991Sheppo /*
5801991Sheppo  * Reconfigure the transmit queue
5811991Sheppo  */
5821991Sheppo static int
i_ldc_txq_reconf(ldc_chan_t * ldcp)5831991Sheppo i_ldc_txq_reconf(ldc_chan_t *ldcp)
5841991Sheppo {
5851991Sheppo 	int rv;
5861991Sheppo 
5871991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
5882336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
5892336Snarayan 
5901991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
5911991Sheppo 	if (rv) {
5921991Sheppo 		cmn_err(CE_WARN,
5932793Slm66018 		    "i_ldc_txq_reconf: (0x%lx) cannot set qconf", ldcp->id);
5941991Sheppo 		return (EIO);
5951991Sheppo 	}
5961991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id, &(ldcp->tx_head),
5971991Sheppo 	    &(ldcp->tx_tail), &(ldcp->link_state));
5981991Sheppo 	if (rv) {
5991991Sheppo 		cmn_err(CE_WARN,
6002793Slm66018 		    "i_ldc_txq_reconf: (0x%lx) cannot get qptrs", ldcp->id);
6011991Sheppo 		return (EIO);
6021991Sheppo 	}
6032793Slm66018 	D1(ldcp->id, "i_ldc_txq_reconf: (0x%llx) h=0x%llx,t=0x%llx,"
6041991Sheppo 	    "s=0x%llx\n", ldcp->id, ldcp->tx_head, ldcp->tx_tail,
6051991Sheppo 	    ldcp->link_state);
6061991Sheppo 
6071991Sheppo 	return (0);
6081991Sheppo }
6091991Sheppo 
6101991Sheppo /*
6111991Sheppo  * Reconfigure the receive queue
6121991Sheppo  */
6131991Sheppo static int
i_ldc_rxq_reconf(ldc_chan_t * ldcp,boolean_t force_reset)6142793Slm66018 i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset)
6151991Sheppo {
6161991Sheppo 	int rv;
6171991Sheppo 	uint64_t rx_head, rx_tail;
6181991Sheppo 
6191991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
6201991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
6211991Sheppo 	    &(ldcp->link_state));
6221991Sheppo 	if (rv) {
6231991Sheppo 		cmn_err(CE_WARN,
6242793Slm66018 		    "i_ldc_rxq_reconf: (0x%lx) cannot get state",
6251991Sheppo 		    ldcp->id);
6261991Sheppo 		return (EIO);
6271991Sheppo 	}
6281991Sheppo 
6292793Slm66018 	if (force_reset || (ldcp->tstate & ~TS_IN_RESET) == TS_UP) {
6301991Sheppo 		rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra,
6314690Snarayan 		    ldcp->rx_q_entries);
6321991Sheppo 		if (rv) {
6331991Sheppo 			cmn_err(CE_WARN,
6342793Slm66018 			    "i_ldc_rxq_reconf: (0x%lx) cannot set qconf",
6351991Sheppo 			    ldcp->id);
6361991Sheppo 			return (EIO);
6371991Sheppo 		}
6382793Slm66018 		D1(ldcp->id, "i_ldc_rxq_reconf: (0x%llx) completed q reconf",
6391991Sheppo 		    ldcp->id);
6401991Sheppo 	}
6411991Sheppo 
6421991Sheppo 	return (0);
6431991Sheppo }
6441991Sheppo 
6452841Snarayan 
6462841Snarayan /*
6472841Snarayan  * Drain the contents of the receive queue
6482841Snarayan  */
64910055SKevin.Crowe@Sun.COM static void
i_ldc_rxq_drain(ldc_chan_t * ldcp)6502841Snarayan i_ldc_rxq_drain(ldc_chan_t *ldcp)
6512841Snarayan {
6522841Snarayan 	int rv;
6532841Snarayan 	uint64_t rx_head, rx_tail;
65410055SKevin.Crowe@Sun.COM 	int retries = 0;
6552841Snarayan 
6562841Snarayan 	ASSERT(MUTEX_HELD(&ldcp->lock));
6572841Snarayan 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
6582841Snarayan 	    &(ldcp->link_state));
6592841Snarayan 	if (rv) {
66010055SKevin.Crowe@Sun.COM 		cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot get state, "
66110055SKevin.Crowe@Sun.COM 		    "rv = 0x%x", ldcp->id, rv);
66210055SKevin.Crowe@Sun.COM 		return;
6632841Snarayan 	}
6642841Snarayan 
6659787SZachary.Kissel@Sun.COM 	/* If the queue is already empty just return success. */
6669787SZachary.Kissel@Sun.COM 	if (rx_head == rx_tail)
66710055SKevin.Crowe@Sun.COM 		return;
66810055SKevin.Crowe@Sun.COM 
66910055SKevin.Crowe@Sun.COM 	/*
67010055SKevin.Crowe@Sun.COM 	 * We are draining the queue in order to close the channel.
67110055SKevin.Crowe@Sun.COM 	 * Call hv_ldc_rx_set_qhead directly instead of i_ldc_set_rx_head
67210055SKevin.Crowe@Sun.COM 	 * because we do not need to reset the channel if the set
67310055SKevin.Crowe@Sun.COM 	 * qhead fails.
67410055SKevin.Crowe@Sun.COM 	 */
67510055SKevin.Crowe@Sun.COM 	if ((rv = hv_ldc_rx_set_qhead(ldcp->id, rx_tail)) == 0)
67610055SKevin.Crowe@Sun.COM 		return;
67710055SKevin.Crowe@Sun.COM 
67810055SKevin.Crowe@Sun.COM 	while ((rv == H_EWOULDBLOCK) && (retries++ < ldc_max_retries)) {
67910055SKevin.Crowe@Sun.COM 		drv_usecwait(ldc_delay);
68010055SKevin.Crowe@Sun.COM 		if ((rv = hv_ldc_rx_set_qhead(ldcp->id, rx_tail)) == 0)
68110055SKevin.Crowe@Sun.COM 			return;
68210055SKevin.Crowe@Sun.COM 	}
68310055SKevin.Crowe@Sun.COM 
68410055SKevin.Crowe@Sun.COM 	cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot set qhead 0x%lx, "
68510055SKevin.Crowe@Sun.COM 	    "rv = 0x%x", ldcp->id, rx_tail, rv);
6862841Snarayan }
6872841Snarayan 
6882841Snarayan 
6891991Sheppo /*
6901991Sheppo  * Reset LDC state structure and its contents
6911991Sheppo  */
6921991Sheppo static void
i_ldc_reset_state(ldc_chan_t * ldcp)6931991Sheppo i_ldc_reset_state(ldc_chan_t *ldcp)
6941991Sheppo {
6951991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
6961991Sheppo 	ldcp->last_msg_snt = LDC_INIT_SEQID;
6971991Sheppo 	ldcp->last_ack_rcd = 0;
6981991Sheppo 	ldcp->last_msg_rcd = 0;
6991991Sheppo 	ldcp->tx_ackd_head = ldcp->tx_head;
7005944Sha137994 	ldcp->stream_remains = 0;
7011991Sheppo 	ldcp->next_vidx = 0;
7021991Sheppo 	ldcp->hstate = 0;
7031991Sheppo 	ldcp->tstate = TS_OPEN;
7041991Sheppo 	ldcp->status = LDC_OPEN;
7055944Sha137994 	ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
7065944Sha137994 	ldcp->rx_dq_head = 0;
7075944Sha137994 	ldcp->rx_dq_tail = 0;
7081991Sheppo 
7091991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_UP ||
7101991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
7111991Sheppo 
7121991Sheppo 		if (ldcp->mode == LDC_MODE_RAW) {
7131991Sheppo 			ldcp->status = LDC_UP;
7141991Sheppo 			ldcp->tstate = TS_UP;
7151991Sheppo 		} else {
7161991Sheppo 			ldcp->status = LDC_READY;
7171991Sheppo 			ldcp->tstate |= TS_LINK_READY;
7181991Sheppo 		}
7191991Sheppo 	}
7201991Sheppo }
7211991Sheppo 
7221991Sheppo /*
7231991Sheppo  * Reset a LDC channel
7241991Sheppo  */
7256408Sha137994 void
i_ldc_reset(ldc_chan_t * ldcp,boolean_t force_reset)7262793Slm66018 i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset)
7271991Sheppo {
7283560Snarayan 	DWARN(ldcp->id, "i_ldc_reset: (0x%llx) channel reset\n", ldcp->id);
7291991Sheppo 
7302336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->lock));
7312336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
7322336Snarayan 
7332793Slm66018 	/* reconfig Tx and Rx queues */
7341991Sheppo 	(void) i_ldc_txq_reconf(ldcp);
7352793Slm66018 	(void) i_ldc_rxq_reconf(ldcp, force_reset);
7362793Slm66018 
7372793Slm66018 	/* Clear Tx and Rx interrupts */
7382793Slm66018 	(void) i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
7392793Slm66018 	(void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
7402793Slm66018 
7412793Slm66018 	/* Reset channel state */
7421991Sheppo 	i_ldc_reset_state(ldcp);
7432793Slm66018 
7442793Slm66018 	/* Mark channel in reset */
7452793Slm66018 	ldcp->tstate |= TS_IN_RESET;
7461991Sheppo }
7471991Sheppo 
7488542SHaik.Aftandilian@Sun.COM /*
7498542SHaik.Aftandilian@Sun.COM  * Walk the channel list and reset channels if they are of the right
7508542SHaik.Aftandilian@Sun.COM  * devclass and their Rx queues have been configured. No locks are
7518542SHaik.Aftandilian@Sun.COM  * taken because the function is only invoked by the kernel just before
7528542SHaik.Aftandilian@Sun.COM  * entering the prom or debugger when the system is single-threaded.
7538542SHaik.Aftandilian@Sun.COM  */
7548542SHaik.Aftandilian@Sun.COM static void
i_ldc_debug_enter(void)7558542SHaik.Aftandilian@Sun.COM i_ldc_debug_enter(void)
7568542SHaik.Aftandilian@Sun.COM {
7578542SHaik.Aftandilian@Sun.COM 	ldc_chan_t *ldcp;
7588542SHaik.Aftandilian@Sun.COM 
7598542SHaik.Aftandilian@Sun.COM 	ldcp = ldcssp->chan_list;
7608542SHaik.Aftandilian@Sun.COM 	while (ldcp != NULL) {
7618542SHaik.Aftandilian@Sun.COM 		if (((ldcp->tstate & TS_QCONF_RDY) == TS_QCONF_RDY) &&
7628542SHaik.Aftandilian@Sun.COM 		    (LDC_DEVCLASS_PROM_RESET(ldcp->devclass) != 0)) {
7638542SHaik.Aftandilian@Sun.COM 			(void) hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra,
7648542SHaik.Aftandilian@Sun.COM 			    ldcp->rx_q_entries);
7658542SHaik.Aftandilian@Sun.COM 		}
7668542SHaik.Aftandilian@Sun.COM 		ldcp = ldcp->next;
7678542SHaik.Aftandilian@Sun.COM 	}
7688542SHaik.Aftandilian@Sun.COM }
7692531Snarayan 
7701991Sheppo /*
7711991Sheppo  * Clear pending interrupts
7721991Sheppo  */
7731991Sheppo static void
i_ldc_clear_intr(ldc_chan_t * ldcp,cnex_intrtype_t itype)7741991Sheppo i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype)
7751991Sheppo {
7761991Sheppo 	ldc_cnex_t *cinfo = &ldcssp->cinfo;
7771991Sheppo 
7781991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
7792793Slm66018 	ASSERT(cinfo->dip != NULL);
7802793Slm66018 
7812793Slm66018 	switch (itype) {
7822793Slm66018 	case CNEX_TX_INTR:
7832531Snarayan 		/* check Tx interrupt */
7842793Slm66018 		if (ldcp->tx_intr_state)
7852793Slm66018 			ldcp->tx_intr_state = LDC_INTR_NONE;
7862793Slm66018 		else
7872793Slm66018 			return;
7882793Slm66018 		break;
7892793Slm66018 
7902793Slm66018 	case CNEX_RX_INTR:
7912531Snarayan 		/* check Rx interrupt */
7922793Slm66018 		if (ldcp->rx_intr_state)
7932793Slm66018 			ldcp->rx_intr_state = LDC_INTR_NONE;
7942793Slm66018 		else
7952793Slm66018 			return;
7962793Slm66018 		break;
7972793Slm66018 	}
7982793Slm66018 
7992793Slm66018 	(void) cinfo->clr_intr(cinfo->dip, ldcp->id, itype);
8002793Slm66018 	D2(ldcp->id,
8012793Slm66018 	    "i_ldc_clear_intr: (0x%llx) cleared 0x%x intr\n",
8022793Slm66018 	    ldcp->id, itype);
8031991Sheppo }
8041991Sheppo 
8051991Sheppo /*
8061991Sheppo  * Set the receive queue head
8072032Slm66018  * Resets connection and returns an error if it fails.
8081991Sheppo  */
8091991Sheppo static int
i_ldc_set_rx_head(ldc_chan_t * ldcp,uint64_t head)8101991Sheppo i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head)
8111991Sheppo {
8122032Slm66018 	int 	rv;
8132032Slm66018 	int 	retries;
8141991Sheppo 
8151991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
8162032Slm66018 	for (retries = 0; retries < ldc_max_retries; retries++) {
8172032Slm66018 
8182032Slm66018 		if ((rv = hv_ldc_rx_set_qhead(ldcp->id, head)) == 0)
8192032Slm66018 			return (0);
8202032Slm66018 
8212032Slm66018 		if (rv != H_EWOULDBLOCK)
8222032Slm66018 			break;
8232032Slm66018 
8242032Slm66018 		/* wait for ldc_delay usecs */
8252032Slm66018 		drv_usecwait(ldc_delay);
8262032Slm66018 	}
8272032Slm66018 
82810055SKevin.Crowe@Sun.COM 	cmn_err(CE_WARN, "ldc_set_rx_qhead: (0x%lx) cannot set qhead 0x%lx, "
82910055SKevin.Crowe@Sun.COM 	    "rv = 0x%x", ldcp->id, head, rv);
8302336Snarayan 	mutex_enter(&ldcp->tx_lock);
8312793Slm66018 	i_ldc_reset(ldcp, B_TRUE);
8322336Snarayan 	mutex_exit(&ldcp->tx_lock);
8332032Slm66018 
8342032Slm66018 	return (ECONNRESET);
8351991Sheppo }
8361991Sheppo 
8374690Snarayan /*
8384690Snarayan  * Returns the tx_head to be used for transfer
8394690Snarayan  */
8404690Snarayan static void
i_ldc_get_tx_head(ldc_chan_t * ldcp,uint64_t * head)8414690Snarayan i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head)
8424690Snarayan {
8434690Snarayan 	ldc_msg_t 	*pkt;
8444690Snarayan 
8454690Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
8464690Snarayan 
8474690Snarayan 	/* get current Tx head */
8484690Snarayan 	*head = ldcp->tx_head;
8494690Snarayan 
8504690Snarayan 	/*
8514690Snarayan 	 * Reliable mode will use the ACKd head instead of the regular tx_head.
8524690Snarayan 	 * Also in Reliable mode, advance ackd_head for all non DATA/INFO pkts,
8534690Snarayan 	 * up to the current location of tx_head. This needs to be done
8544690Snarayan 	 * as the peer will only ACK DATA/INFO pkts.
8554690Snarayan 	 */
8566408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
8574690Snarayan 		while (ldcp->tx_ackd_head != ldcp->tx_head) {
8584690Snarayan 			pkt = (ldc_msg_t *)(ldcp->tx_q_va + ldcp->tx_ackd_head);
8594690Snarayan 			if ((pkt->type & LDC_DATA) && (pkt->stype & LDC_INFO)) {
8604690Snarayan 				break;
8614690Snarayan 			}
8624690Snarayan 			/* advance ACKd head */
8634690Snarayan 			ldcp->tx_ackd_head =
8644690Snarayan 			    (ldcp->tx_ackd_head + LDC_PACKET_SIZE) %
8654690Snarayan 			    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
8664690Snarayan 		}
8674690Snarayan 		*head = ldcp->tx_ackd_head;
8684690Snarayan 	}
8694690Snarayan }
8701991Sheppo 
8711991Sheppo /*
8721991Sheppo  * Returns the tx_tail to be used for transfer
8731991Sheppo  * Re-reads the TX queue ptrs if and only if the
8741991Sheppo  * the cached head and tail are equal (queue is full)
8751991Sheppo  */
8761991Sheppo static int
i_ldc_get_tx_tail(ldc_chan_t * ldcp,uint64_t * tail)8771991Sheppo i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail)
8781991Sheppo {
8791991Sheppo 	int 		rv;
8801991Sheppo 	uint64_t 	current_head, new_tail;
8811991Sheppo 
8822336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
8831991Sheppo 	/* Read the head and tail ptrs from HV */
8841991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
8851991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
8861991Sheppo 	if (rv) {
8871991Sheppo 		cmn_err(CE_WARN,
8881991Sheppo 		    "i_ldc_get_tx_tail: (0x%lx) cannot read qptrs\n",
8891991Sheppo 		    ldcp->id);
8901991Sheppo 		return (EIO);
8911991Sheppo 	}
8921991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN) {
8933010Slm66018 		D1(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) channel not ready\n",
8941991Sheppo 		    ldcp->id);
8951991Sheppo 		return (ECONNRESET);
8961991Sheppo 	}
8971991Sheppo 
8984690Snarayan 	i_ldc_get_tx_head(ldcp, &current_head);
8991991Sheppo 
9001991Sheppo 	/* increment the tail */
9011991Sheppo 	new_tail = (ldcp->tx_tail + LDC_PACKET_SIZE) %
9024690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
9031991Sheppo 
9041991Sheppo 	if (new_tail == current_head) {
9051991Sheppo 		DWARN(ldcp->id,
9061991Sheppo 		    "i_ldc_get_tx_tail: (0x%llx) TX queue is full\n",
9071991Sheppo 		    ldcp->id);
9081991Sheppo 		return (EWOULDBLOCK);
9091991Sheppo 	}
9101991Sheppo 
9111991Sheppo 	D2(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) head=0x%llx, tail=0x%llx\n",
9121991Sheppo 	    ldcp->id, ldcp->tx_head, ldcp->tx_tail);
9131991Sheppo 
9141991Sheppo 	*tail = ldcp->tx_tail;
9151991Sheppo 	return (0);
9161991Sheppo }
9171991Sheppo 
9181991Sheppo /*
9191991Sheppo  * Set the tail pointer. If HV returns EWOULDBLOCK, it will back off
9202032Slm66018  * and retry ldc_max_retries times before returning an error.
9211991Sheppo  * Returns 0, EWOULDBLOCK or EIO
9221991Sheppo  */
9231991Sheppo static int
i_ldc_set_tx_tail(ldc_chan_t * ldcp,uint64_t tail)9241991Sheppo i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail)
9251991Sheppo {
9261991Sheppo 	int		rv, retval = EWOULDBLOCK;
9272032Slm66018 	int 		retries;
9281991Sheppo 
9292336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
9302032Slm66018 	for (retries = 0; retries < ldc_max_retries; retries++) {
9311991Sheppo 
9321991Sheppo 		if ((rv = hv_ldc_tx_set_qtail(ldcp->id, tail)) == 0) {
9331991Sheppo 			retval = 0;
9341991Sheppo 			break;
9351991Sheppo 		}
9361991Sheppo 		if (rv != H_EWOULDBLOCK) {
9371991Sheppo 			DWARN(ldcp->id, "i_ldc_set_tx_tail: (0x%llx) set "
9381991Sheppo 			    "qtail=0x%llx failed, rv=%d\n", ldcp->id, tail, rv);
9391991Sheppo 			retval = EIO;
9401991Sheppo 			break;
9411991Sheppo 		}
9421991Sheppo 
9432032Slm66018 		/* wait for ldc_delay usecs */
9442032Slm66018 		drv_usecwait(ldc_delay);
9451991Sheppo 	}
9461991Sheppo 	return (retval);
9471991Sheppo }
9481991Sheppo 
9491991Sheppo /*
9505944Sha137994  * Copy a data packet from the HV receive queue to the data queue.
9515944Sha137994  * Caller must ensure that the data queue is not already full.
9525944Sha137994  *
9535944Sha137994  * The *head argument represents the current head pointer for the HV
9545944Sha137994  * receive queue. After copying a packet from the HV receive queue,
9555944Sha137994  * the *head pointer will be updated. This allows the caller to update
9565944Sha137994  * the head pointer in HV using the returned *head value.
9575944Sha137994  */
9585944Sha137994 void
i_ldc_rxdq_copy(ldc_chan_t * ldcp,uint64_t * head)9595944Sha137994 i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head)
9605944Sha137994 {
9615944Sha137994 	uint64_t	q_size, dq_size;
9625944Sha137994 
9635944Sha137994 	ASSERT(MUTEX_HELD(&ldcp->lock));
9645944Sha137994 
9655944Sha137994 	q_size  = ldcp->rx_q_entries << LDC_PACKET_SHIFT;
9665944Sha137994 	dq_size = ldcp->rx_dq_entries << LDC_PACKET_SHIFT;
9675944Sha137994 
9685944Sha137994 	ASSERT(Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail,
9695944Sha137994 	    dq_size) >= LDC_PACKET_SIZE);
9705944Sha137994 
9715944Sha137994 	bcopy((void *)(ldcp->rx_q_va + *head),
9725944Sha137994 	    (void *)(ldcp->rx_dq_va + ldcp->rx_dq_tail), LDC_PACKET_SIZE);
9735944Sha137994 	TRACE_RXDQ_COPY(ldcp, LDC_PACKET_SIZE);
9745944Sha137994 
9755944Sha137994 	/* Update rx head */
9765944Sha137994 	*head = (*head + LDC_PACKET_SIZE) % q_size;
9775944Sha137994 
9785944Sha137994 	/* Update dq tail */
9795944Sha137994 	ldcp->rx_dq_tail = (ldcp->rx_dq_tail + LDC_PACKET_SIZE) % dq_size;
9805944Sha137994 }
9815944Sha137994 
9825944Sha137994 /*
9835944Sha137994  * Update the Rx data queue head pointer
9845944Sha137994  */
9855944Sha137994 static int
i_ldc_set_rxdq_head(ldc_chan_t * ldcp,uint64_t head)9865944Sha137994 i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head)
9875944Sha137994 {
9885944Sha137994 	ldcp->rx_dq_head = head;
9895944Sha137994 	return (0);
9905944Sha137994 }
9915944Sha137994 
9925944Sha137994 /*
9935944Sha137994  * Get the Rx data queue head and tail pointers
9945944Sha137994  */
9955944Sha137994 static uint64_t
i_ldc_dq_rx_get_state(ldc_chan_t * ldcp,uint64_t * head,uint64_t * tail,uint64_t * link_state)9965944Sha137994 i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail,
9975944Sha137994     uint64_t *link_state)
9985944Sha137994 {
9995944Sha137994 	_NOTE(ARGUNUSED(link_state))
10005944Sha137994 	*head = ldcp->rx_dq_head;
10015944Sha137994 	*tail = ldcp->rx_dq_tail;
10025944Sha137994 	return (0);
10035944Sha137994 }
10045944Sha137994 
10055944Sha137994 /*
10065944Sha137994  * Wrapper for the Rx HV queue set head function. Giving the
10075944Sha137994  * data queue and HV queue set head functions the same type.
10085944Sha137994  */
10095944Sha137994 static uint64_t
i_ldc_hvq_rx_get_state(ldc_chan_t * ldcp,uint64_t * head,uint64_t * tail,uint64_t * link_state)10105944Sha137994 i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail,
10115944Sha137994     uint64_t *link_state)
10125944Sha137994 {
10135944Sha137994 	return (i_ldc_h2v_error(hv_ldc_rx_get_state(ldcp->id, head, tail,
10145944Sha137994 	    link_state)));
10155944Sha137994 }
10165944Sha137994 
10175944Sha137994 /*
10185944Sha137994  * LDC receive interrupt handler
10195944Sha137994  *    triggered for channel with data pending to read
10205944Sha137994  *    i.e. Rx queue content changes
10215944Sha137994  */
10225944Sha137994 static uint_t
i_ldc_rx_hdlr(caddr_t arg1,caddr_t arg2)10235944Sha137994 i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2)
10245944Sha137994 {
10255944Sha137994 	_NOTE(ARGUNUSED(arg2))
10265944Sha137994 
10275944Sha137994 	ldc_chan_t	*ldcp;
10285944Sha137994 	boolean_t	notify;
10295944Sha137994 	uint64_t	event;
10306944Sha137994 	int		rv, status;
10315944Sha137994 
10325944Sha137994 	/* Get the channel for which interrupt was received */
10335944Sha137994 	if (arg1 == NULL) {
10345944Sha137994 		cmn_err(CE_WARN, "i_ldc_rx_hdlr: invalid arg\n");
10355944Sha137994 		return (DDI_INTR_UNCLAIMED);
10365944Sha137994 	}
10375944Sha137994 
10385944Sha137994 	ldcp = (ldc_chan_t *)arg1;
10395944Sha137994 
10405944Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
10415944Sha137994 	    ldcp->id, ldcp);
10425944Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (%llx) USR%lx/TS%lx/HS%lx, LSTATE=%lx\n",
10435944Sha137994 	    ldcp->id, ldcp->status, ldcp->tstate, ldcp->hstate,
10445944Sha137994 	    ldcp->link_state);
10455944Sha137994 
10465944Sha137994 	/* Lock channel */
10475944Sha137994 	mutex_enter(&ldcp->lock);
10485944Sha137994 
10495944Sha137994 	/* Mark the interrupt as being actively handled */
10505944Sha137994 	ldcp->rx_intr_state = LDC_INTR_ACTIVE;
10515944Sha137994 
10526944Sha137994 	status = i_ldc_rx_process_hvq(ldcp, &notify, &event);
10535944Sha137994 
10546408Sha137994 	if (ldcp->mode != LDC_MODE_RELIABLE) {
10555944Sha137994 		/*
10565944Sha137994 		 * If there are no data packets on the queue, clear
10575944Sha137994 		 * the interrupt. Otherwise, the ldc_read will clear
10585944Sha137994 		 * interrupts after draining the queue. To indicate the
10595944Sha137994 		 * interrupt has not yet been cleared, it is marked
10605944Sha137994 		 * as pending.
10615944Sha137994 		 */
10625944Sha137994 		if ((event & LDC_EVT_READ) == 0) {
10635944Sha137994 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
10645944Sha137994 		} else {
10655944Sha137994 			ldcp->rx_intr_state = LDC_INTR_PEND;
10665944Sha137994 		}
10675944Sha137994 	}
10685944Sha137994 
10695944Sha137994 	/* if callbacks are disabled, do not notify */
10705944Sha137994 	if (notify && ldcp->cb_enabled) {
10715944Sha137994 		ldcp->cb_inprogress = B_TRUE;
10725944Sha137994 		mutex_exit(&ldcp->lock);
10735944Sha137994 		rv = ldcp->cb(event, ldcp->cb_arg);
10745944Sha137994 		if (rv) {
10755944Sha137994 			DWARN(ldcp->id,
10765944Sha137994 			    "i_ldc_rx_hdlr: (0x%llx) callback failure",
10775944Sha137994 			    ldcp->id);
10785944Sha137994 		}
10795944Sha137994 		mutex_enter(&ldcp->lock);
10805944Sha137994 		ldcp->cb_inprogress = B_FALSE;
10815944Sha137994 	}
10825944Sha137994 
10836408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
10846944Sha137994 		if (status == ENOSPC) {
10856944Sha137994 			/*
10866944Sha137994 			 * Here, ENOSPC indicates the secondary data
10876944Sha137994 			 * queue is full and the Rx queue is non-empty.
10886944Sha137994 			 * Much like how reliable and raw modes are
10896944Sha137994 			 * handled above, since the Rx queue is non-
10906944Sha137994 			 * empty, we mark the interrupt as pending to
10916944Sha137994 			 * indicate it has not yet been cleared.
10926944Sha137994 			 */
10936944Sha137994 			ldcp->rx_intr_state = LDC_INTR_PEND;
10946944Sha137994 		} else {
10956944Sha137994 			/*
10966944Sha137994 			 * We have processed all CTRL packets and
10976944Sha137994 			 * copied all DATA packets to the secondary
10986944Sha137994 			 * queue. Clear the interrupt.
10996944Sha137994 			 */
11006944Sha137994 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
11016944Sha137994 		}
11025944Sha137994 	}
11035944Sha137994 
11045944Sha137994 	mutex_exit(&ldcp->lock);
11055944Sha137994 
11065944Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) exiting handler", ldcp->id);
11075944Sha137994 
11085944Sha137994 	return (DDI_INTR_CLAIMED);
11095944Sha137994 }
11105944Sha137994 
11115944Sha137994 /*
11125944Sha137994  * Wrapper for the Rx HV queue processing function to be used when
11135944Sha137994  * checking the Rx HV queue for data packets. Unlike the interrupt
11145944Sha137994  * handler code flow, the Rx interrupt is not cleared here and
11155944Sha137994  * callbacks are not made.
11165944Sha137994  */
11175944Sha137994 static uint_t
i_ldc_chkq(ldc_chan_t * ldcp)11185944Sha137994 i_ldc_chkq(ldc_chan_t *ldcp)
11195944Sha137994 {
11205944Sha137994 	boolean_t	notify;
11215944Sha137994 	uint64_t	event;
11225944Sha137994 
11235944Sha137994 	return (i_ldc_rx_process_hvq(ldcp, &notify, &event));
11245944Sha137994 }
11255944Sha137994 
11265944Sha137994 /*
11271991Sheppo  * Send a LDC message
11281991Sheppo  */
11291991Sheppo static int
i_ldc_send_pkt(ldc_chan_t * ldcp,uint8_t pkttype,uint8_t subtype,uint8_t ctrlmsg)11301991Sheppo i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
11311991Sheppo     uint8_t ctrlmsg)
11321991Sheppo {
11331991Sheppo 	int		rv;
11341991Sheppo 	ldc_msg_t 	*pkt;
11351991Sheppo 	uint64_t	tx_tail;
11364690Snarayan 	uint32_t	curr_seqid;
11371991Sheppo 
11382336Snarayan 	/* Obtain Tx lock */
11392336Snarayan 	mutex_enter(&ldcp->tx_lock);
11402336Snarayan 
11414690Snarayan 	curr_seqid = ldcp->last_msg_snt;
11424690Snarayan 
11431991Sheppo 	/* get the current tail for the message */
11441991Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
11451991Sheppo 	if (rv) {
11461991Sheppo 		DWARN(ldcp->id,
11471991Sheppo 		    "i_ldc_send_pkt: (0x%llx) error sending pkt, "
11481991Sheppo 		    "type=0x%x,subtype=0x%x,ctrl=0x%x\n",
11491991Sheppo 		    ldcp->id, pkttype, subtype, ctrlmsg);
11502336Snarayan 		mutex_exit(&ldcp->tx_lock);
11511991Sheppo 		return (rv);
11521991Sheppo 	}
11531991Sheppo 
11541991Sheppo 	pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
11551991Sheppo 	ZERO_PKT(pkt);
11561991Sheppo 
11571991Sheppo 	/* Initialize the packet */
11581991Sheppo 	pkt->type = pkttype;
11591991Sheppo 	pkt->stype = subtype;
11601991Sheppo 	pkt->ctrl = ctrlmsg;
11611991Sheppo 
11621991Sheppo 	/* Store ackid/seqid iff it is RELIABLE mode & not a RTS/RTR message */
11631991Sheppo 	if (((ctrlmsg & LDC_CTRL_MASK) != LDC_RTS) &&
11641991Sheppo 	    ((ctrlmsg & LDC_CTRL_MASK) != LDC_RTR)) {
11651991Sheppo 		curr_seqid++;
11661991Sheppo 		if (ldcp->mode != LDC_MODE_RAW) {
11671991Sheppo 			pkt->seqid = curr_seqid;
11681991Sheppo 			pkt->ackid = ldcp->last_msg_rcd;
11691991Sheppo 		}
11701991Sheppo 	}
11711991Sheppo 	DUMP_LDC_PKT(ldcp, "i_ldc_send_pkt", (uint64_t)pkt);
11721991Sheppo 
11731991Sheppo 	/* initiate the send by calling into HV and set the new tail */
11741991Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
11754690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
11761991Sheppo 
11771991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
11781991Sheppo 	if (rv) {
11791991Sheppo 		DWARN(ldcp->id,
11801991Sheppo 		    "i_ldc_send_pkt:(0x%llx) error sending pkt, "
11811991Sheppo 		    "type=0x%x,stype=0x%x,ctrl=0x%x\n",
11821991Sheppo 		    ldcp->id, pkttype, subtype, ctrlmsg);
11832336Snarayan 		mutex_exit(&ldcp->tx_lock);
11841991Sheppo 		return (EIO);
11851991Sheppo 	}
11861991Sheppo 
11871991Sheppo 	ldcp->last_msg_snt = curr_seqid;
11881991Sheppo 	ldcp->tx_tail = tx_tail;
11891991Sheppo 
11902336Snarayan 	mutex_exit(&ldcp->tx_lock);
11911991Sheppo 	return (0);
11921991Sheppo }
11931991Sheppo 
11941991Sheppo /*
11951991Sheppo  * Checks if packet was received in right order
11962410Slm66018  * in the case of a reliable link.
11971991Sheppo  * Returns 0 if in order, else EIO
11981991Sheppo  */
11991991Sheppo static int
i_ldc_check_seqid(ldc_chan_t * ldcp,ldc_msg_t * msg)12001991Sheppo i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *msg)
12011991Sheppo {
12021991Sheppo 	/* No seqid checking for RAW mode */
12031991Sheppo 	if (ldcp->mode == LDC_MODE_RAW)
12041991Sheppo 		return (0);
12051991Sheppo 
12061991Sheppo 	/* No seqid checking for version, RTS, RTR message */
12071991Sheppo 	if (msg->ctrl == LDC_VER ||
12081991Sheppo 	    msg->ctrl == LDC_RTS ||
12091991Sheppo 	    msg->ctrl == LDC_RTR)
12101991Sheppo 		return (0);
12111991Sheppo 
12121991Sheppo 	/* Initial seqid to use is sent in RTS/RTR and saved in last_msg_rcd */
12131991Sheppo 	if (msg->seqid != (ldcp->last_msg_rcd + 1)) {
12141991Sheppo 		DWARN(ldcp->id,
12151991Sheppo 		    "i_ldc_check_seqid: (0x%llx) out-of-order pkt, got 0x%x, "
12161991Sheppo 		    "expecting 0x%x\n", ldcp->id, msg->seqid,
12171991Sheppo 		    (ldcp->last_msg_rcd + 1));
12181991Sheppo 		return (EIO);
12191991Sheppo 	}
12201991Sheppo 
12213560Snarayan #ifdef DEBUG
12223560Snarayan 	if (LDC_INJECT_PKTLOSS(ldcp)) {
12233560Snarayan 		DWARN(ldcp->id,
12243560Snarayan 		    "i_ldc_check_seqid: (0x%llx) inject pkt loss\n", ldcp->id);
12253560Snarayan 		return (EIO);
12263560Snarayan 	}
12273560Snarayan #endif
12283560Snarayan 
12291991Sheppo 	return (0);
12301991Sheppo }
12311991Sheppo 
12321991Sheppo 
12331991Sheppo /*
12341991Sheppo  * Process an incoming version ctrl message
12351991Sheppo  */
12361991Sheppo static int
i_ldc_process_VER(ldc_chan_t * ldcp,ldc_msg_t * msg)12371991Sheppo i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg)
12381991Sheppo {
12391991Sheppo 	int 		rv = 0, idx = ldcp->next_vidx;
12401991Sheppo 	ldc_msg_t 	*pkt;
12411991Sheppo 	uint64_t	tx_tail;
12421991Sheppo 	ldc_ver_t	*rcvd_ver;
12431991Sheppo 
12441991Sheppo 	/* get the received version */
12451991Sheppo 	rcvd_ver = (ldc_ver_t *)((uint64_t)msg + LDC_PAYLOAD_VER_OFF);
12461991Sheppo 
12471991Sheppo 	D2(ldcp->id, "i_ldc_process_VER: (0x%llx) received VER v%u.%u\n",
12481991Sheppo 	    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
12491991Sheppo 
12502336Snarayan 	/* Obtain Tx lock */
12512336Snarayan 	mutex_enter(&ldcp->tx_lock);
12522336Snarayan 
12531991Sheppo 	switch (msg->stype) {
12541991Sheppo 	case LDC_INFO:
12551991Sheppo 
12562793Slm66018 		if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) {
12572793Slm66018 			(void) i_ldc_txq_reconf(ldcp);
12582793Slm66018 			i_ldc_reset_state(ldcp);
12592793Slm66018 			mutex_exit(&ldcp->tx_lock);
12602793Slm66018 			return (EAGAIN);
12612793Slm66018 		}
12622793Slm66018 
12631991Sheppo 		/* get the current tail and pkt for the response */
12641991Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
12651991Sheppo 		if (rv != 0) {
12661991Sheppo 			DWARN(ldcp->id,
12671991Sheppo 			    "i_ldc_process_VER: (0x%llx) err sending "
12681991Sheppo 			    "version ACK/NACK\n", ldcp->id);
12692793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
12702336Snarayan 			mutex_exit(&ldcp->tx_lock);
12711991Sheppo 			return (ECONNRESET);
12721991Sheppo 		}
12731991Sheppo 
12741991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
12751991Sheppo 		ZERO_PKT(pkt);
12761991Sheppo 
12771991Sheppo 		/* initialize the packet */
12781991Sheppo 		pkt->type = LDC_CTRL;
12791991Sheppo 		pkt->ctrl = LDC_VER;
12801991Sheppo 
12811991Sheppo 		for (;;) {
12821991Sheppo 
12831991Sheppo 			D1(ldcp->id, "i_ldc_process_VER: got %u.%u chk %u.%u\n",
12841991Sheppo 			    rcvd_ver->major, rcvd_ver->minor,
12851991Sheppo 			    ldc_versions[idx].major, ldc_versions[idx].minor);
12861991Sheppo 
12871991Sheppo 			if (rcvd_ver->major == ldc_versions[idx].major) {
12881991Sheppo 				/* major version match - ACK version */
12891991Sheppo 				pkt->stype = LDC_ACK;
12901991Sheppo 
12911991Sheppo 				/*
12921991Sheppo 				 * lower minor version to the one this endpt
12931991Sheppo 				 * supports, if necessary
12941991Sheppo 				 */
12951991Sheppo 				if (rcvd_ver->minor > ldc_versions[idx].minor)
12961991Sheppo 					rcvd_ver->minor =
12974690Snarayan 					    ldc_versions[idx].minor;
12981991Sheppo 				bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver));
12991991Sheppo 
13001991Sheppo 				break;
13011991Sheppo 			}
13021991Sheppo 
13031991Sheppo 			if (rcvd_ver->major > ldc_versions[idx].major) {
13041991Sheppo 
13051991Sheppo 				D1(ldcp->id, "i_ldc_process_VER: using next"
13061991Sheppo 				    " lower idx=%d, v%u.%u\n", idx,
13071991Sheppo 				    ldc_versions[idx].major,
13081991Sheppo 				    ldc_versions[idx].minor);
13091991Sheppo 
13101991Sheppo 				/* nack with next lower version */
13111991Sheppo 				pkt->stype = LDC_NACK;
13121991Sheppo 				bcopy(&ldc_versions[idx], pkt->udata,
13131991Sheppo 				    sizeof (ldc_versions[idx]));
13141991Sheppo 				ldcp->next_vidx = idx;
13151991Sheppo 				break;
13161991Sheppo 			}
13171991Sheppo 
13181991Sheppo 			/* next major version */
13191991Sheppo 			idx++;
13201991Sheppo 
13211991Sheppo 			D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx);
13221991Sheppo 
13231991Sheppo 			if (idx == LDC_NUM_VERS) {
13241991Sheppo 				/* no version match - send NACK */
13251991Sheppo 				pkt->stype = LDC_NACK;
13261991Sheppo 				bzero(pkt->udata, sizeof (ldc_ver_t));
13271991Sheppo 				ldcp->next_vidx = 0;
13281991Sheppo 				break;
13291991Sheppo 			}
13301991Sheppo 		}
13311991Sheppo 
13321991Sheppo 		/* initiate the send by calling into HV and set the new tail */
13331991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
13344690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
13351991Sheppo 
13361991Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
13371991Sheppo 		if (rv == 0) {
13381991Sheppo 			ldcp->tx_tail = tx_tail;
13391991Sheppo 			if (pkt->stype == LDC_ACK) {
13401991Sheppo 				D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent"
13411991Sheppo 				    " version ACK\n", ldcp->id);
13421991Sheppo 				/* Save the ACK'd version */
13431991Sheppo 				ldcp->version.major = rcvd_ver->major;
13441991Sheppo 				ldcp->version.minor = rcvd_ver->minor;
13452032Slm66018 				ldcp->hstate |= TS_RCVD_VER;
13461991Sheppo 				ldcp->tstate |= TS_VER_DONE;
13473560Snarayan 				D1(DBG_ALL_LDCS,
13482793Slm66018 				    "(0x%llx) Sent ACK, "
13492793Slm66018 				    "Agreed on version v%u.%u\n",
13501991Sheppo 				    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
13511991Sheppo 			}
13521991Sheppo 		} else {
13531991Sheppo 			DWARN(ldcp->id,
13541991Sheppo 			    "i_ldc_process_VER: (0x%llx) error sending "
13551991Sheppo 			    "ACK/NACK\n", ldcp->id);
13562793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
13572336Snarayan 			mutex_exit(&ldcp->tx_lock);
13581991Sheppo 			return (ECONNRESET);
13591991Sheppo 		}
13601991Sheppo 
13611991Sheppo 		break;
13621991Sheppo 
13631991Sheppo 	case LDC_ACK:
13642793Slm66018 		if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) {
13652793Slm66018 			if (ldcp->version.major != rcvd_ver->major ||
13664690Snarayan 			    ldcp->version.minor != rcvd_ver->minor) {
13672793Slm66018 
13682793Slm66018 				/* mismatched version - reset connection */
13692793Slm66018 				DWARN(ldcp->id,
13704690Snarayan 				    "i_ldc_process_VER: (0x%llx) recvd"
13714690Snarayan 				    " ACK ver != sent ACK ver\n", ldcp->id);
13722793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
13732793Slm66018 				mutex_exit(&ldcp->tx_lock);
13742793Slm66018 				return (ECONNRESET);
13752793Slm66018 			}
13762793Slm66018 		} else {
13772793Slm66018 			/* SUCCESS - we have agreed on a version */
13782793Slm66018 			ldcp->version.major = rcvd_ver->major;
13792793Slm66018 			ldcp->version.minor = rcvd_ver->minor;
13802793Slm66018 			ldcp->tstate |= TS_VER_DONE;
13812793Slm66018 		}
13822793Slm66018 
13833010Slm66018 		D1(ldcp->id, "(0x%llx) Got ACK, Agreed on version v%u.%u\n",
13841991Sheppo 		    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
13851991Sheppo 
13861991Sheppo 		/* initiate RTS-RTR-RDX handshake */
13871991Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
13881991Sheppo 		if (rv) {
13891991Sheppo 			DWARN(ldcp->id,
13902793Slm66018 		    "i_ldc_process_VER: (0x%llx) cannot send RTS\n",
13911991Sheppo 			    ldcp->id);
13922793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
13932336Snarayan 			mutex_exit(&ldcp->tx_lock);
13941991Sheppo 			return (ECONNRESET);
13951991Sheppo 		}
13961991Sheppo 
13971991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
13981991Sheppo 		ZERO_PKT(pkt);
13991991Sheppo 
14001991Sheppo 		pkt->type = LDC_CTRL;
14011991Sheppo 		pkt->stype = LDC_INFO;
14021991Sheppo 		pkt->ctrl = LDC_RTS;
14031991Sheppo 		pkt->env = ldcp->mode;
14041991Sheppo 		if (ldcp->mode != LDC_MODE_RAW)
14051991Sheppo 			pkt->seqid = LDC_INIT_SEQID;
14061991Sheppo 
14071991Sheppo 		ldcp->last_msg_rcd = LDC_INIT_SEQID;
14081991Sheppo 
14091991Sheppo 		DUMP_LDC_PKT(ldcp, "i_ldc_process_VER snd rts", (uint64_t)pkt);
14101991Sheppo 
14111991Sheppo 		/* initiate the send by calling into HV and set the new tail */
14121991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
14134690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
14141991Sheppo 
14151991Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
14161991Sheppo 		if (rv) {
14171991Sheppo 			D2(ldcp->id,
14181991Sheppo 			    "i_ldc_process_VER: (0x%llx) no listener\n",
14191991Sheppo 			    ldcp->id);
14202793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
14212336Snarayan 			mutex_exit(&ldcp->tx_lock);
14221991Sheppo 			return (ECONNRESET);
14231991Sheppo 		}
14241991Sheppo 
14251991Sheppo 		ldcp->tx_tail = tx_tail;
14261991Sheppo 		ldcp->hstate |= TS_SENT_RTS;
14271991Sheppo 
14281991Sheppo 		break;
14291991Sheppo 
14301991Sheppo 	case LDC_NACK:
14311991Sheppo 		/* check if version in NACK is zero */
14321991Sheppo 		if (rcvd_ver->major == 0 && rcvd_ver->minor == 0) {
14331991Sheppo 			/* version handshake failure */
14341991Sheppo 			DWARN(DBG_ALL_LDCS,
14351991Sheppo 			    "i_ldc_process_VER: (0x%llx) no version match\n",
14361991Sheppo 			    ldcp->id);
14372793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
14382336Snarayan 			mutex_exit(&ldcp->tx_lock);
14391991Sheppo 			return (ECONNRESET);
14401991Sheppo 		}
14411991Sheppo 
14421991Sheppo 		/* get the current tail and pkt for the response */
14431991Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
14441991Sheppo 		if (rv != 0) {
14451991Sheppo 			cmn_err(CE_NOTE,
14461991Sheppo 			    "i_ldc_process_VER: (0x%lx) err sending "
14471991Sheppo 			    "version ACK/NACK\n", ldcp->id);
14482793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
14492336Snarayan 			mutex_exit(&ldcp->tx_lock);
14501991Sheppo 			return (ECONNRESET);
14511991Sheppo 		}
14521991Sheppo 
14531991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
14541991Sheppo 		ZERO_PKT(pkt);
14551991Sheppo 
14561991Sheppo 		/* initialize the packet */
14571991Sheppo 		pkt->type = LDC_CTRL;
14581991Sheppo 		pkt->ctrl = LDC_VER;
14591991Sheppo 		pkt->stype = LDC_INFO;
14601991Sheppo 
14611991Sheppo 		/* check ver in NACK msg has a match */
14621991Sheppo 		for (;;) {
14631991Sheppo 			if (rcvd_ver->major == ldc_versions[idx].major) {
14641991Sheppo 				/*
14651991Sheppo 				 * major version match - resubmit request
14661991Sheppo 				 * if lower minor version to the one this endpt
14671991Sheppo 				 * supports, if necessary
14681991Sheppo 				 */
14691991Sheppo 				if (rcvd_ver->minor > ldc_versions[idx].minor)
14701991Sheppo 					rcvd_ver->minor =
14714690Snarayan 					    ldc_versions[idx].minor;
14721991Sheppo 				bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver));
14731991Sheppo 				break;
14741991Sheppo 			}
14751991Sheppo 
14761991Sheppo 			if (rcvd_ver->major > ldc_versions[idx].major) {
14771991Sheppo 
14781991Sheppo 				D1(ldcp->id, "i_ldc_process_VER: using next"
14791991Sheppo 				    " lower idx=%d, v%u.%u\n", idx,
14801991Sheppo 				    ldc_versions[idx].major,
14811991Sheppo 				    ldc_versions[idx].minor);
14821991Sheppo 
14831991Sheppo 				/* send next lower version */
14841991Sheppo 				bcopy(&ldc_versions[idx], pkt->udata,
14851991Sheppo 				    sizeof (ldc_versions[idx]));
14861991Sheppo 				ldcp->next_vidx = idx;
14871991Sheppo 				break;
14881991Sheppo 			}
14891991Sheppo 
14901991Sheppo 			/* next version */
14911991Sheppo 			idx++;
14921991Sheppo 
14931991Sheppo 			D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx);
14941991Sheppo 
14951991Sheppo 			if (idx == LDC_NUM_VERS) {
14961991Sheppo 				/* no version match - terminate */
14971991Sheppo 				ldcp->next_vidx = 0;
14982336Snarayan 				mutex_exit(&ldcp->tx_lock);
14991991Sheppo 				return (ECONNRESET);
15001991Sheppo 			}
15011991Sheppo 		}
15021991Sheppo 
15031991Sheppo 		/* initiate the send by calling into HV and set the new tail */
15041991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
15054690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
15061991Sheppo 
15071991Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
15081991Sheppo 		if (rv == 0) {
15091991Sheppo 			D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent version"
15101991Sheppo 			    "INFO v%u.%u\n", ldcp->id, ldc_versions[idx].major,
15111991Sheppo 			    ldc_versions[idx].minor);
15121991Sheppo 			ldcp->tx_tail = tx_tail;
15131991Sheppo 		} else {
15141991Sheppo 			cmn_err(CE_NOTE,
15151991Sheppo 			    "i_ldc_process_VER: (0x%lx) error sending version"
15161991Sheppo 			    "INFO\n", ldcp->id);
15172793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
15182336Snarayan 			mutex_exit(&ldcp->tx_lock);
15191991Sheppo 			return (ECONNRESET);
15201991Sheppo 		}
15211991Sheppo 
15221991Sheppo 		break;
15231991Sheppo 	}
15241991Sheppo 
15252336Snarayan 	mutex_exit(&ldcp->tx_lock);
15261991Sheppo 	return (rv);
15271991Sheppo }
15281991Sheppo 
15291991Sheppo 
15301991Sheppo /*
15311991Sheppo  * Process an incoming RTS ctrl message
15321991Sheppo  */
15331991Sheppo static int
i_ldc_process_RTS(ldc_chan_t * ldcp,ldc_msg_t * msg)15341991Sheppo i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg)
15351991Sheppo {
15361991Sheppo 	int 		rv = 0;
15371991Sheppo 	ldc_msg_t 	*pkt;
15381991Sheppo 	uint64_t	tx_tail;
15391991Sheppo 	boolean_t	sent_NACK = B_FALSE;
15401991Sheppo 
15411991Sheppo 	D2(ldcp->id, "i_ldc_process_RTS: (0x%llx) received RTS\n", ldcp->id);
15421991Sheppo 
15431991Sheppo 	switch (msg->stype) {
15441991Sheppo 	case LDC_NACK:
15451991Sheppo 		DWARN(ldcp->id,
15461991Sheppo 		    "i_ldc_process_RTS: (0x%llx) RTS NACK received\n",
15471991Sheppo 		    ldcp->id);
15481991Sheppo 
15491991Sheppo 		/* Reset the channel -- as we cannot continue */
15502336Snarayan 		mutex_enter(&ldcp->tx_lock);
15512793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
15522336Snarayan 		mutex_exit(&ldcp->tx_lock);
15531991Sheppo 		rv = ECONNRESET;
15541991Sheppo 		break;
15551991Sheppo 
15561991Sheppo 	case LDC_INFO:
15571991Sheppo 
15581991Sheppo 		/* check mode */
15591991Sheppo 		if (ldcp->mode != (ldc_mode_t)msg->env) {
15601991Sheppo 			cmn_err(CE_NOTE,
15611991Sheppo 			    "i_ldc_process_RTS: (0x%lx) mode mismatch\n",
15621991Sheppo 			    ldcp->id);
15631991Sheppo 			/*
15641991Sheppo 			 * send NACK in response to MODE message
15651991Sheppo 			 * get the current tail for the response
15661991Sheppo 			 */
15671991Sheppo 			rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTS);
15681991Sheppo 			if (rv) {
15691991Sheppo 				/* if cannot send NACK - reset channel */
15702336Snarayan 				mutex_enter(&ldcp->tx_lock);
15712793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
15722336Snarayan 				mutex_exit(&ldcp->tx_lock);
15731991Sheppo 				rv = ECONNRESET;
15741991Sheppo 				break;
15751991Sheppo 			}
15761991Sheppo 			sent_NACK = B_TRUE;
15771991Sheppo 		}
15781991Sheppo 		break;
15791991Sheppo 	default:
15801991Sheppo 		DWARN(ldcp->id, "i_ldc_process_RTS: (0x%llx) unexp ACK\n",
15811991Sheppo 		    ldcp->id);
15822336Snarayan 		mutex_enter(&ldcp->tx_lock);
15832793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
15842336Snarayan 		mutex_exit(&ldcp->tx_lock);
15851991Sheppo 		rv = ECONNRESET;
15861991Sheppo 		break;
15871991Sheppo 	}
15881991Sheppo 
15891991Sheppo 	/*
15901991Sheppo 	 * If either the connection was reset (when rv != 0) or
15911991Sheppo 	 * a NACK was sent, we return. In the case of a NACK
15921991Sheppo 	 * we dont want to consume the packet that came in but
15931991Sheppo 	 * not record that we received the RTS
15941991Sheppo 	 */
15951991Sheppo 	if (rv || sent_NACK)
15961991Sheppo 		return (rv);
15971991Sheppo 
15981991Sheppo 	/* record RTS received */
15991991Sheppo 	ldcp->hstate |= TS_RCVD_RTS;
16001991Sheppo 
16011991Sheppo 	/* store initial SEQID info */
16021991Sheppo 	ldcp->last_msg_snt = msg->seqid;
16031991Sheppo 
16042336Snarayan 	/* Obtain Tx lock */
16052336Snarayan 	mutex_enter(&ldcp->tx_lock);
16062336Snarayan 
16071991Sheppo 	/* get the current tail for the response */
16081991Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
16091991Sheppo 	if (rv != 0) {
16101991Sheppo 		cmn_err(CE_NOTE,
16111991Sheppo 		    "i_ldc_process_RTS: (0x%lx) err sending RTR\n",
16121991Sheppo 		    ldcp->id);
16132793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
16142336Snarayan 		mutex_exit(&ldcp->tx_lock);
16151991Sheppo 		return (ECONNRESET);
16161991Sheppo 	}
16171991Sheppo 
16181991Sheppo 	pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
16191991Sheppo 	ZERO_PKT(pkt);
16201991Sheppo 
16211991Sheppo 	/* initialize the packet */
16221991Sheppo 	pkt->type = LDC_CTRL;
16231991Sheppo 	pkt->stype = LDC_INFO;
16241991Sheppo 	pkt->ctrl = LDC_RTR;
16251991Sheppo 	pkt->env = ldcp->mode;
16261991Sheppo 	if (ldcp->mode != LDC_MODE_RAW)
16271991Sheppo 		pkt->seqid = LDC_INIT_SEQID;
16281991Sheppo 
16291991Sheppo 	ldcp->last_msg_rcd = msg->seqid;
16301991Sheppo 
16311991Sheppo 	/* initiate the send by calling into HV and set the new tail */
16321991Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
16334690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
16341991Sheppo 
16351991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
16361991Sheppo 	if (rv == 0) {
16371991Sheppo 		D2(ldcp->id,
16381991Sheppo 		    "i_ldc_process_RTS: (0x%llx) sent RTR\n", ldcp->id);
16391991Sheppo 		DUMP_LDC_PKT(ldcp, "i_ldc_process_RTS sent rtr", (uint64_t)pkt);
16401991Sheppo 
16411991Sheppo 		ldcp->tx_tail = tx_tail;
16421991Sheppo 		ldcp->hstate |= TS_SENT_RTR;
16431991Sheppo 
16441991Sheppo 	} else {
16451991Sheppo 		cmn_err(CE_NOTE,
16461991Sheppo 		    "i_ldc_process_RTS: (0x%lx) error sending RTR\n",
16471991Sheppo 		    ldcp->id);
16482793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
16492336Snarayan 		mutex_exit(&ldcp->tx_lock);
16501991Sheppo 		return (ECONNRESET);
16511991Sheppo 	}
16521991Sheppo 
16532336Snarayan 	mutex_exit(&ldcp->tx_lock);
16541991Sheppo 	return (0);
16551991Sheppo }
16561991Sheppo 
16571991Sheppo /*
16581991Sheppo  * Process an incoming RTR ctrl message
16591991Sheppo  */
16601991Sheppo static int
i_ldc_process_RTR(ldc_chan_t * ldcp,ldc_msg_t * msg)16611991Sheppo i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg)
16621991Sheppo {
16631991Sheppo 	int 		rv = 0;
16641991Sheppo 	boolean_t	sent_NACK = B_FALSE;
16651991Sheppo 
16661991Sheppo 	D2(ldcp->id, "i_ldc_process_RTR: (0x%llx) received RTR\n", ldcp->id);
16671991Sheppo 
16681991Sheppo 	switch (msg->stype) {
16691991Sheppo 	case LDC_NACK:
16701991Sheppo 		/* RTR NACK received */
16711991Sheppo 		DWARN(ldcp->id,
16721991Sheppo 		    "i_ldc_process_RTR: (0x%llx) RTR NACK received\n",
16731991Sheppo 		    ldcp->id);
16741991Sheppo 
16751991Sheppo 		/* Reset the channel -- as we cannot continue */
16762336Snarayan 		mutex_enter(&ldcp->tx_lock);
16772793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
16782336Snarayan 		mutex_exit(&ldcp->tx_lock);
16791991Sheppo 		rv = ECONNRESET;
16801991Sheppo 
16811991Sheppo 		break;
16821991Sheppo 
16831991Sheppo 	case LDC_INFO:
16841991Sheppo 
16851991Sheppo 		/* check mode */
16861991Sheppo 		if (ldcp->mode != (ldc_mode_t)msg->env) {
16871991Sheppo 			DWARN(ldcp->id,
16883010Slm66018 			    "i_ldc_process_RTR: (0x%llx) mode mismatch, "
16893010Slm66018 			    "expecting 0x%x, got 0x%x\n",
16903010Slm66018 			    ldcp->id, ldcp->mode, (ldc_mode_t)msg->env);
16911991Sheppo 			/*
16921991Sheppo 			 * send NACK in response to MODE message
16931991Sheppo 			 * get the current tail for the response
16941991Sheppo 			 */
16951991Sheppo 			rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTR);
16961991Sheppo 			if (rv) {
16971991Sheppo 				/* if cannot send NACK - reset channel */
16982336Snarayan 				mutex_enter(&ldcp->tx_lock);
16992793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
17002336Snarayan 				mutex_exit(&ldcp->tx_lock);
17011991Sheppo 				rv = ECONNRESET;
17021991Sheppo 				break;
17031991Sheppo 			}
17041991Sheppo 			sent_NACK = B_TRUE;
17051991Sheppo 		}
17061991Sheppo 		break;
17071991Sheppo 
17081991Sheppo 	default:
17091991Sheppo 		DWARN(ldcp->id, "i_ldc_process_RTR: (0x%llx) unexp ACK\n",
17101991Sheppo 		    ldcp->id);
17111991Sheppo 
17121991Sheppo 		/* Reset the channel -- as we cannot continue */
17132336Snarayan 		mutex_enter(&ldcp->tx_lock);
17142793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
17152336Snarayan 		mutex_exit(&ldcp->tx_lock);
17161991Sheppo 		rv = ECONNRESET;
17171991Sheppo 		break;
17181991Sheppo 	}
17191991Sheppo 
17201991Sheppo 	/*
17211991Sheppo 	 * If either the connection was reset (when rv != 0) or
17221991Sheppo 	 * a NACK was sent, we return. In the case of a NACK
17231991Sheppo 	 * we dont want to consume the packet that came in but
17241991Sheppo 	 * not record that we received the RTR
17251991Sheppo 	 */
17261991Sheppo 	if (rv || sent_NACK)
17271991Sheppo 		return (rv);
17281991Sheppo 
17291991Sheppo 	ldcp->last_msg_snt = msg->seqid;
17301991Sheppo 	ldcp->hstate |= TS_RCVD_RTR;
17311991Sheppo 
17321991Sheppo 	rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_INFO, LDC_RDX);
17331991Sheppo 	if (rv) {
17341991Sheppo 		cmn_err(CE_NOTE,
17351991Sheppo 		    "i_ldc_process_RTR: (0x%lx) cannot send RDX\n",
17361991Sheppo 		    ldcp->id);
17372336Snarayan 		mutex_enter(&ldcp->tx_lock);
17382793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
17392336Snarayan 		mutex_exit(&ldcp->tx_lock);
17401991Sheppo 		return (ECONNRESET);
17411991Sheppo 	}
17421991Sheppo 	D2(ldcp->id,
17431991Sheppo 	    "i_ldc_process_RTR: (0x%llx) sent RDX\n", ldcp->id);
17441991Sheppo 
17451991Sheppo 	ldcp->hstate |= TS_SENT_RDX;
17461991Sheppo 	ldcp->tstate |= TS_HSHAKE_DONE;
17472793Slm66018 	if ((ldcp->tstate & TS_IN_RESET) == 0)
17482793Slm66018 		ldcp->status = LDC_UP;
17491991Sheppo 
17503010Slm66018 	D1(ldcp->id, "(0x%llx) Handshake Complete\n", ldcp->id);
17511991Sheppo 
17521991Sheppo 	return (0);
17531991Sheppo }
17541991Sheppo 
17551991Sheppo 
17561991Sheppo /*
17571991Sheppo  * Process an incoming RDX ctrl message
17581991Sheppo  */
17591991Sheppo static int
i_ldc_process_RDX(ldc_chan_t * ldcp,ldc_msg_t * msg)17601991Sheppo i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg)
17611991Sheppo {
17621991Sheppo 	int	rv = 0;
17631991Sheppo 
17641991Sheppo 	D2(ldcp->id, "i_ldc_process_RDX: (0x%llx) received RDX\n", ldcp->id);
17651991Sheppo 
17661991Sheppo 	switch (msg->stype) {
17671991Sheppo 	case LDC_NACK:
17681991Sheppo 		/* RDX NACK received */
17691991Sheppo 		DWARN(ldcp->id,
17701991Sheppo 		    "i_ldc_process_RDX: (0x%llx) RDX NACK received\n",
17711991Sheppo 		    ldcp->id);
17721991Sheppo 
17731991Sheppo 		/* Reset the channel -- as we cannot continue */
17742336Snarayan 		mutex_enter(&ldcp->tx_lock);
17752793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
17762336Snarayan 		mutex_exit(&ldcp->tx_lock);
17771991Sheppo 		rv = ECONNRESET;
17781991Sheppo 
17791991Sheppo 		break;
17801991Sheppo 
17811991Sheppo 	case LDC_INFO:
17821991Sheppo 
17831991Sheppo 		/*
17841991Sheppo 		 * if channel is UP and a RDX received after data transmission
17851991Sheppo 		 * has commenced it is an error
17861991Sheppo 		 */
17871991Sheppo 		if ((ldcp->tstate == TS_UP) && (ldcp->hstate & TS_RCVD_RDX)) {
17881991Sheppo 			DWARN(DBG_ALL_LDCS,
17891991Sheppo 			    "i_ldc_process_RDX: (0x%llx) unexpected RDX"
17901991Sheppo 			    " - LDC reset\n", ldcp->id);
17912336Snarayan 			mutex_enter(&ldcp->tx_lock);
17922793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
17932336Snarayan 			mutex_exit(&ldcp->tx_lock);
17941991Sheppo 			return (ECONNRESET);
17951991Sheppo 		}
17961991Sheppo 
17971991Sheppo 		ldcp->hstate |= TS_RCVD_RDX;
17981991Sheppo 		ldcp->tstate |= TS_HSHAKE_DONE;
17992793Slm66018 		if ((ldcp->tstate & TS_IN_RESET) == 0)
18002793Slm66018 			ldcp->status = LDC_UP;
18011991Sheppo 
18021991Sheppo 		D1(DBG_ALL_LDCS, "(0x%llx) Handshake Complete\n", ldcp->id);
18031991Sheppo 		break;
18041991Sheppo 
18051991Sheppo 	default:
18061991Sheppo 		DWARN(ldcp->id, "i_ldc_process_RDX: (0x%llx) unexp ACK\n",
18071991Sheppo 		    ldcp->id);
18081991Sheppo 
18091991Sheppo 		/* Reset the channel -- as we cannot continue */
18102336Snarayan 		mutex_enter(&ldcp->tx_lock);
18112793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
18122336Snarayan 		mutex_exit(&ldcp->tx_lock);
18131991Sheppo 		rv = ECONNRESET;
18141991Sheppo 		break;
18151991Sheppo 	}
18161991Sheppo 
18171991Sheppo 	return (rv);
18181991Sheppo }
18191991Sheppo 
18201991Sheppo /*
18211991Sheppo  * Process an incoming ACK for a data packet
18221991Sheppo  */
18231991Sheppo static int
i_ldc_process_data_ACK(ldc_chan_t * ldcp,ldc_msg_t * msg)18241991Sheppo i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg)
18251991Sheppo {
18261991Sheppo 	int		rv;
18271991Sheppo 	uint64_t 	tx_head;
18281991Sheppo 	ldc_msg_t	*pkt;
18291991Sheppo 
18302336Snarayan 	/* Obtain Tx lock */
18312336Snarayan 	mutex_enter(&ldcp->tx_lock);
18322336Snarayan 
18331991Sheppo 	/*
18342336Snarayan 	 * Read the current Tx head and tail
18351991Sheppo 	 */
18361991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
18371991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
18381991Sheppo 	if (rv != 0) {
18391991Sheppo 		cmn_err(CE_WARN,
18401991Sheppo 		    "i_ldc_process_data_ACK: (0x%lx) cannot read qptrs\n",
18411991Sheppo 		    ldcp->id);
18422336Snarayan 
18432336Snarayan 		/* Reset the channel -- as we cannot continue */
18442793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
18452336Snarayan 		mutex_exit(&ldcp->tx_lock);
18462336Snarayan 		return (ECONNRESET);
18471991Sheppo 	}
18481991Sheppo 
18491991Sheppo 	/*
18501991Sheppo 	 * loop from where the previous ACK location was to the
18511991Sheppo 	 * current head location. This is how far the HV has
18521991Sheppo 	 * actually send pkts. Pkts between head and tail are
18531991Sheppo 	 * yet to be sent by HV.
18541991Sheppo 	 */
18551991Sheppo 	tx_head = ldcp->tx_ackd_head;
18561991Sheppo 	for (;;) {
18571991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_head);
18581991Sheppo 		tx_head = (tx_head + LDC_PACKET_SIZE) %
18594690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
18601991Sheppo 
18611991Sheppo 		if (pkt->seqid == msg->ackid) {
18621991Sheppo 			D2(ldcp->id,
18631991Sheppo 			    "i_ldc_process_data_ACK: (0x%llx) found packet\n",
18641991Sheppo 			    ldcp->id);
18651991Sheppo 			ldcp->last_ack_rcd = msg->ackid;
18661991Sheppo 			ldcp->tx_ackd_head = tx_head;
18671991Sheppo 			break;
18681991Sheppo 		}
18691991Sheppo 		if (tx_head == ldcp->tx_head) {
18701991Sheppo 			/* could not find packet */
18711991Sheppo 			DWARN(ldcp->id,
18721991Sheppo 			    "i_ldc_process_data_ACK: (0x%llx) invalid ACKid\n",
18731991Sheppo 			    ldcp->id);
18742336Snarayan 
18752336Snarayan 			/* Reset the channel -- as we cannot continue */
18762793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
18772336Snarayan 			mutex_exit(&ldcp->tx_lock);
18782336Snarayan 			return (ECONNRESET);
18791991Sheppo 		}
18801991Sheppo 	}
18811991Sheppo 
18822336Snarayan 	mutex_exit(&ldcp->tx_lock);
18831991Sheppo 	return (0);
18841991Sheppo }
18851991Sheppo 
18861991Sheppo /*
18871991Sheppo  * Process incoming control message
18881991Sheppo  * Return 0 - session can continue
18891991Sheppo  *        EAGAIN - reprocess packet - state was changed
18901991Sheppo  *	  ECONNRESET - channel was reset
18911991Sheppo  */
18921991Sheppo static int
i_ldc_ctrlmsg(ldc_chan_t * ldcp,ldc_msg_t * msg)18931991Sheppo i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *msg)
18941991Sheppo {
18951991Sheppo 	int 		rv = 0;
18961991Sheppo 
18972793Slm66018 	D1(ldcp->id, "i_ldc_ctrlmsg: (%llx) tstate = %lx, hstate = %lx\n",
18982793Slm66018 	    ldcp->id, ldcp->tstate, ldcp->hstate);
18992793Slm66018 
19002793Slm66018 	switch (ldcp->tstate & ~TS_IN_RESET) {
19011991Sheppo 
19021991Sheppo 	case TS_OPEN:
19031991Sheppo 	case TS_READY:
19041991Sheppo 
19051991Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
19061991Sheppo 		case LDC_VER:
19071991Sheppo 			/* process version message */
19081991Sheppo 			rv = i_ldc_process_VER(ldcp, msg);
19091991Sheppo 			break;
19101991Sheppo 		default:
19111991Sheppo 			DWARN(ldcp->id,
19121991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
19131991Sheppo 			    "tstate=0x%x\n", ldcp->id,
19141991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
19151991Sheppo 			break;
19161991Sheppo 		}
19171991Sheppo 
19181991Sheppo 		break;
19191991Sheppo 
19201991Sheppo 	case TS_VREADY:
19211991Sheppo 
19221991Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
19231991Sheppo 		case LDC_VER:
19242793Slm66018 			/* process version message */
19252793Slm66018 			rv = i_ldc_process_VER(ldcp, msg);
19261991Sheppo 			break;
19271991Sheppo 		case LDC_RTS:
19281991Sheppo 			/* process RTS message */
19291991Sheppo 			rv = i_ldc_process_RTS(ldcp, msg);
19301991Sheppo 			break;
19311991Sheppo 		case LDC_RTR:
19321991Sheppo 			/* process RTR message */
19331991Sheppo 			rv = i_ldc_process_RTR(ldcp, msg);
19341991Sheppo 			break;
19351991Sheppo 		case LDC_RDX:
19361991Sheppo 			/* process RDX message */
19371991Sheppo 			rv = i_ldc_process_RDX(ldcp, msg);
19381991Sheppo 			break;
19391991Sheppo 		default:
19401991Sheppo 			DWARN(ldcp->id,
19411991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
19421991Sheppo 			    "tstate=0x%x\n", ldcp->id,
19431991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
19441991Sheppo 			break;
19451991Sheppo 		}
19461991Sheppo 
19471991Sheppo 		break;
19481991Sheppo 
19491991Sheppo 	case TS_UP:
19501991Sheppo 
19511991Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
19521991Sheppo 		case LDC_VER:
19531991Sheppo 			DWARN(ldcp->id,
19541991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexpected VER "
19551991Sheppo 			    "- LDC reset\n", ldcp->id);
19561991Sheppo 			/* peer is redoing version negotiation */
19572336Snarayan 			mutex_enter(&ldcp->tx_lock);
19581991Sheppo 			(void) i_ldc_txq_reconf(ldcp);
19591991Sheppo 			i_ldc_reset_state(ldcp);
19602336Snarayan 			mutex_exit(&ldcp->tx_lock);
19611991Sheppo 			rv = EAGAIN;
19621991Sheppo 			break;
19631991Sheppo 
19641991Sheppo 		case LDC_RDX:
19651991Sheppo 			/* process RDX message */
19661991Sheppo 			rv = i_ldc_process_RDX(ldcp, msg);
19671991Sheppo 			break;
19681991Sheppo 
19691991Sheppo 		default:
19701991Sheppo 			DWARN(ldcp->id,
19711991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
19721991Sheppo 			    "tstate=0x%x\n", ldcp->id,
19731991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
19741991Sheppo 			break;
19751991Sheppo 		}
19761991Sheppo 	}
19771991Sheppo 
19781991Sheppo 	return (rv);
19791991Sheppo }
19801991Sheppo 
19811991Sheppo /*
19821991Sheppo  * Register channel with the channel nexus
19831991Sheppo  */
19841991Sheppo static int
i_ldc_register_channel(ldc_chan_t * ldcp)19851991Sheppo i_ldc_register_channel(ldc_chan_t *ldcp)
19861991Sheppo {
19871991Sheppo 	int		rv = 0;
19881991Sheppo 	ldc_cnex_t	*cinfo = &ldcssp->cinfo;
19891991Sheppo 
19901991Sheppo 	if (cinfo->dip == NULL) {
19911991Sheppo 		DWARN(ldcp->id,
19921991Sheppo 		    "i_ldc_register_channel: cnex has not registered\n");
19931991Sheppo 		return (EAGAIN);
19941991Sheppo 	}
19951991Sheppo 
19961991Sheppo 	rv = cinfo->reg_chan(cinfo->dip, ldcp->id, ldcp->devclass);
19971991Sheppo 	if (rv) {
19981991Sheppo 		DWARN(ldcp->id,
19991991Sheppo 		    "i_ldc_register_channel: cannot register channel\n");
20001991Sheppo 		return (rv);
20011991Sheppo 	}
20021991Sheppo 
20031991Sheppo 	rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR,
20041991Sheppo 	    i_ldc_tx_hdlr, ldcp, NULL);
20051991Sheppo 	if (rv) {
20061991Sheppo 		DWARN(ldcp->id,
20071991Sheppo 		    "i_ldc_register_channel: cannot add Tx interrupt\n");
20081991Sheppo 		(void) cinfo->unreg_chan(cinfo->dip, ldcp->id);
20091991Sheppo 		return (rv);
20101991Sheppo 	}
20111991Sheppo 
20121991Sheppo 	rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR,
20131991Sheppo 	    i_ldc_rx_hdlr, ldcp, NULL);
20141991Sheppo 	if (rv) {
20151991Sheppo 		DWARN(ldcp->id,
20161991Sheppo 		    "i_ldc_register_channel: cannot add Rx interrupt\n");
20171991Sheppo 		(void) cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
20181991Sheppo 		(void) cinfo->unreg_chan(cinfo->dip, ldcp->id);
20191991Sheppo 		return (rv);
20201991Sheppo 	}
20211991Sheppo 
20221991Sheppo 	ldcp->tstate |= TS_CNEX_RDY;
20231991Sheppo 
20241991Sheppo 	return (0);
20251991Sheppo }
20261991Sheppo 
20271991Sheppo /*
20281991Sheppo  * Unregister a channel with the channel nexus
20291991Sheppo  */
20301991Sheppo static int
i_ldc_unregister_channel(ldc_chan_t * ldcp)20311991Sheppo i_ldc_unregister_channel(ldc_chan_t *ldcp)
20321991Sheppo {
20331991Sheppo 	int		rv = 0;
20341991Sheppo 	ldc_cnex_t	*cinfo = &ldcssp->cinfo;
20351991Sheppo 
20361991Sheppo 	if (cinfo->dip == NULL) {
20371991Sheppo 		DWARN(ldcp->id,
20381991Sheppo 		    "i_ldc_unregister_channel: cnex has not registered\n");
20391991Sheppo 		return (EAGAIN);
20401991Sheppo 	}
20411991Sheppo 
20421991Sheppo 	if (ldcp->tstate & TS_CNEX_RDY) {
20431991Sheppo 
20442336Snarayan 		/* Remove the Rx interrupt */
20451991Sheppo 		rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR);
20461991Sheppo 		if (rv) {
20472793Slm66018 			if (rv != EAGAIN) {
20482793Slm66018 				DWARN(ldcp->id,
20492793Slm66018 				    "i_ldc_unregister_channel: err removing "
20502793Slm66018 				    "Rx intr\n");
20512793Slm66018 				return (rv);
20522793Slm66018 			}
20532793Slm66018 
20542793Slm66018 			/*
20552793Slm66018 			 * If interrupts are pending and handler has
20562793Slm66018 			 * finished running, clear interrupt and try
20572793Slm66018 			 * again
20582793Slm66018 			 */
20592793Slm66018 			if (ldcp->rx_intr_state != LDC_INTR_PEND)
20602793Slm66018 				return (rv);
20612793Slm66018 
20622793Slm66018 			(void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
20632793Slm66018 			rv = cinfo->rem_intr(cinfo->dip, ldcp->id,
20642793Slm66018 			    CNEX_RX_INTR);
20652793Slm66018 			if (rv) {
20662793Slm66018 				DWARN(ldcp->id, "i_ldc_unregister_channel: "
20672793Slm66018 				    "err removing Rx interrupt\n");
20682793Slm66018 				return (rv);
20692793Slm66018 			}
20701991Sheppo 		}
20712336Snarayan 
20722336Snarayan 		/* Remove the Tx interrupt */
20731991Sheppo 		rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
20741991Sheppo 		if (rv) {
20751991Sheppo 			DWARN(ldcp->id,
20761991Sheppo 			    "i_ldc_unregister_channel: err removing Tx intr\n");
20772336Snarayan 			return (rv);
20781991Sheppo 		}
20792336Snarayan 
20802336Snarayan 		/* Unregister the channel */
20811991Sheppo 		rv = cinfo->unreg_chan(ldcssp->cinfo.dip, ldcp->id);
20821991Sheppo 		if (rv) {
20831991Sheppo 			DWARN(ldcp->id,
20841991Sheppo 			    "i_ldc_unregister_channel: cannot unreg channel\n");
20852336Snarayan 			return (rv);
20861991Sheppo 		}
20871991Sheppo 
20881991Sheppo 		ldcp->tstate &= ~TS_CNEX_RDY;
20891991Sheppo 	}
20901991Sheppo 
20911991Sheppo 	return (0);
20921991Sheppo }
20931991Sheppo 
20941991Sheppo 
20951991Sheppo /*
20961991Sheppo  * LDC transmit interrupt handler
20971991Sheppo  *    triggered for chanel up/down/reset events
20981991Sheppo  *    and Tx queue content changes
20991991Sheppo  */
21001991Sheppo static uint_t
i_ldc_tx_hdlr(caddr_t arg1,caddr_t arg2)21011991Sheppo i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2)
21021991Sheppo {
21031991Sheppo 	_NOTE(ARGUNUSED(arg2))
21041991Sheppo 
21051991Sheppo 	int 		rv;
21061991Sheppo 	ldc_chan_t 	*ldcp;
21071991Sheppo 	boolean_t 	notify_client = B_FALSE;
21082793Slm66018 	uint64_t	notify_event = 0, link_state;
21091991Sheppo 
21101991Sheppo 	/* Get the channel for which interrupt was received */
21111991Sheppo 	ASSERT(arg1 != NULL);
21121991Sheppo 	ldcp = (ldc_chan_t *)arg1;
21131991Sheppo 
21141991Sheppo 	D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
21151991Sheppo 	    ldcp->id, ldcp);
21161991Sheppo 
21171991Sheppo 	/* Lock channel */
21181991Sheppo 	mutex_enter(&ldcp->lock);
21191991Sheppo 
21202336Snarayan 	/* Obtain Tx lock */
21212336Snarayan 	mutex_enter(&ldcp->tx_lock);
21222336Snarayan 
21232531Snarayan 	/* mark interrupt as pending */
21242793Slm66018 	ldcp->tx_intr_state = LDC_INTR_ACTIVE;
21252793Slm66018 
21262793Slm66018 	/* save current link state */
21272793Slm66018 	link_state = ldcp->link_state;
21282531Snarayan 
21291991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id, &ldcp->tx_head, &ldcp->tx_tail,
21301991Sheppo 	    &ldcp->link_state);
21311991Sheppo 	if (rv) {
21321991Sheppo 		cmn_err(CE_WARN,
21331991Sheppo 		    "i_ldc_tx_hdlr: (0x%lx) cannot read queue ptrs rv=0x%d\n",
21341991Sheppo 		    ldcp->id, rv);
21352531Snarayan 		i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
21362336Snarayan 		mutex_exit(&ldcp->tx_lock);
21371991Sheppo 		mutex_exit(&ldcp->lock);
21381991Sheppo 		return (DDI_INTR_CLAIMED);
21391991Sheppo 	}
21401991Sheppo 
21411991Sheppo 	/*
21421991Sheppo 	 * reset the channel state if the channel went down
21431991Sheppo 	 * (other side unconfigured queue) or channel was reset
21441991Sheppo 	 * (other side reconfigured its queue)
21451991Sheppo 	 */
21462793Slm66018 	if (link_state != ldcp->link_state &&
21472793Slm66018 	    ldcp->link_state == LDC_CHANNEL_DOWN) {
21481991Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link down\n", ldcp->id);
21492793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
21501991Sheppo 		notify_client = B_TRUE;
21511991Sheppo 		notify_event = LDC_EVT_DOWN;
21521991Sheppo 	}
21531991Sheppo 
21542793Slm66018 	if (link_state != ldcp->link_state &&
21552793Slm66018 	    ldcp->link_state == LDC_CHANNEL_RESET) {
21561991Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link reset\n", ldcp->id);
21572793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
21581991Sheppo 		notify_client = B_TRUE;
21591991Sheppo 		notify_event = LDC_EVT_RESET;
21601991Sheppo 	}
21611991Sheppo 
21622793Slm66018 	if (link_state != ldcp->link_state &&
21632793Slm66018 	    (ldcp->tstate & ~TS_IN_RESET) == TS_OPEN &&
21642793Slm66018 	    ldcp->link_state == LDC_CHANNEL_UP) {
21651991Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link up\n", ldcp->id);
21661991Sheppo 		notify_client = B_TRUE;
21671991Sheppo 		notify_event = LDC_EVT_RESET;
21681991Sheppo 		ldcp->tstate |= TS_LINK_READY;
21691991Sheppo 		ldcp->status = LDC_READY;
21701991Sheppo 	}
21711991Sheppo 
21721991Sheppo 	/* if callbacks are disabled, do not notify */
21731991Sheppo 	if (!ldcp->cb_enabled)
21741991Sheppo 		notify_client = B_FALSE;
21751991Sheppo 
21763151Ssg70180 	i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
21774690Snarayan 	mutex_exit(&ldcp->tx_lock);
21781991Sheppo 
21791991Sheppo 	if (notify_client) {
21802793Slm66018 		ldcp->cb_inprogress = B_TRUE;
21812793Slm66018 		mutex_exit(&ldcp->lock);
21821991Sheppo 		rv = ldcp->cb(notify_event, ldcp->cb_arg);
21831991Sheppo 		if (rv) {
21841991Sheppo 			DWARN(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) callback "
21851991Sheppo 			    "failure", ldcp->id);
21861991Sheppo 		}
21871991Sheppo 		mutex_enter(&ldcp->lock);
21881991Sheppo 		ldcp->cb_inprogress = B_FALSE;
21892793Slm66018 	}
21902793Slm66018 
21911991Sheppo 	mutex_exit(&ldcp->lock);
21921991Sheppo 
21931991Sheppo 	D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) exiting handler", ldcp->id);
21941991Sheppo 
21951991Sheppo 	return (DDI_INTR_CLAIMED);
21961991Sheppo }
21971991Sheppo 
21981991Sheppo /*
21995944Sha137994  * Process the Rx HV queue.
22005944Sha137994  *
22015944Sha137994  * Returns 0 if data packets were found and no errors were encountered,
22025944Sha137994  * otherwise returns an error. In either case, the *notify argument is
22035944Sha137994  * set to indicate whether or not the client callback function should
22045944Sha137994  * be invoked. The *event argument is set to contain the callback event.
22055944Sha137994  *
22065944Sha137994  * Depending on the channel mode, packets are handled differently:
22075944Sha137994  *
22085944Sha137994  * RAW MODE
22095944Sha137994  * For raw mode channels, when a data packet is encountered,
22105944Sha137994  * processing stops and all packets are left on the queue to be removed
22115944Sha137994  * and processed by the ldc_read code path.
22125944Sha137994  *
22135944Sha137994  * UNRELIABLE MODE
22145944Sha137994  * For unreliable mode, when a data packet is encountered, processing
22155944Sha137994  * stops, and all packets are left on the queue to be removed and
22165944Sha137994  * processed by the ldc_read code path. Control packets are processed
22175944Sha137994  * inline if they are encountered before any data packets.
22185944Sha137994  *
22196408Sha137994  * RELIABLE MODE
22206408Sha137994  * For reliable mode channels, all packets on the receive queue
22215944Sha137994  * are processed: data packets are copied to the data queue and
22225944Sha137994  * control packets are processed inline. Packets are only left on
22235944Sha137994  * the receive queue when the data queue is full.
22241991Sheppo  */
22251991Sheppo static uint_t
i_ldc_rx_process_hvq(ldc_chan_t * ldcp,boolean_t * notify_client,uint64_t * notify_event)22265944Sha137994 i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client,
22275944Sha137994     uint64_t *notify_event)
22281991Sheppo {
22291991Sheppo 	int		rv;
22301991Sheppo 	uint64_t 	rx_head, rx_tail;
22311991Sheppo 	ldc_msg_t 	*msg;
22322793Slm66018 	uint64_t	link_state, first_fragment = 0;
22335944Sha137994 	boolean_t	trace_length = B_TRUE;
22345944Sha137994 
22355944Sha137994 	ASSERT(MUTEX_HELD(&ldcp->lock));
22365944Sha137994 	*notify_client = B_FALSE;
22375944Sha137994 	*notify_event = 0;
22381991Sheppo 
22391991Sheppo 	/*
22401991Sheppo 	 * Read packet(s) from the queue
22411991Sheppo 	 */
22421991Sheppo 	for (;;) {
22431991Sheppo 
22442793Slm66018 		link_state = ldcp->link_state;
22451991Sheppo 		rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
22461991Sheppo 		    &ldcp->link_state);
22471991Sheppo 		if (rv) {
22481991Sheppo 			cmn_err(CE_WARN,
22495944Sha137994 			    "i_ldc_rx_process_hvq: (0x%lx) cannot read "
22501991Sheppo 			    "queue ptrs, rv=0x%d\n", ldcp->id, rv);
22511991Sheppo 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
22525944Sha137994 			return (EIO);
22531991Sheppo 		}
22541991Sheppo 
22551991Sheppo 		/*
22561991Sheppo 		 * reset the channel state if the channel went down
22571991Sheppo 		 * (other side unconfigured queue) or channel was reset
22582793Slm66018 		 * (other side reconfigured its queue)
22591991Sheppo 		 */
22602793Slm66018 
22612793Slm66018 		if (link_state != ldcp->link_state) {
22623010Slm66018 
22632793Slm66018 			switch (ldcp->link_state) {
22642793Slm66018 			case LDC_CHANNEL_DOWN:
22655944Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: channel "
22662793Slm66018 				    "link down\n", ldcp->id);
22672793Slm66018 				mutex_enter(&ldcp->tx_lock);
22682793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
22692793Slm66018 				mutex_exit(&ldcp->tx_lock);
22705944Sha137994 				*notify_client = B_TRUE;
22715944Sha137994 				*notify_event = LDC_EVT_DOWN;
22722793Slm66018 				goto loop_exit;
22732793Slm66018 
22742793Slm66018 			case LDC_CHANNEL_UP:
22755944Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: "
22762793Slm66018 				    "channel link up\n", ldcp->id);
22772793Slm66018 
22782793Slm66018 				if ((ldcp->tstate & ~TS_IN_RESET) == TS_OPEN) {
22795944Sha137994 					*notify_client = B_TRUE;
22805944Sha137994 					*notify_event = LDC_EVT_RESET;
22812793Slm66018 					ldcp->tstate |= TS_LINK_READY;
22822793Slm66018 					ldcp->status = LDC_READY;
22832793Slm66018 				}
22842793Slm66018 				break;
22852793Slm66018 
22862793Slm66018 			case LDC_CHANNEL_RESET:
22872793Slm66018 			default:
22882793Slm66018 #ifdef DEBUG
22892793Slm66018 force_reset:
22902793Slm66018 #endif
22915944Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: channel "
22922793Slm66018 				    "link reset\n", ldcp->id);
22932793Slm66018 				mutex_enter(&ldcp->tx_lock);
22942793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
22952793Slm66018 				mutex_exit(&ldcp->tx_lock);
22965944Sha137994 				*notify_client = B_TRUE;
22975944Sha137994 				*notify_event = LDC_EVT_RESET;
22982793Slm66018 				break;
22992793Slm66018 			}
23001991Sheppo 		}
23012793Slm66018 
23022793Slm66018 #ifdef DEBUG
23032793Slm66018 		if (LDC_INJECT_RESET(ldcp))
23042793Slm66018 			goto force_reset;
23056845Sha137994 		if (LDC_INJECT_DRNGCLEAR(ldcp))
23066845Sha137994 			i_ldc_mem_inject_dring_clear(ldcp);
23072793Slm66018 #endif
23085944Sha137994 		if (trace_length) {
23095944Sha137994 			TRACE_RXHVQ_LENGTH(ldcp, rx_head, rx_tail);
23105944Sha137994 			trace_length = B_FALSE;
23115944Sha137994 		}
23121991Sheppo 
23131991Sheppo 		if (rx_head == rx_tail) {
23145944Sha137994 			D2(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) "
23155944Sha137994 			    "No packets\n", ldcp->id);
23161991Sheppo 			break;
23171991Sheppo 		}
23182793Slm66018 
23195944Sha137994 		D2(ldcp->id, "i_ldc_rx_process_hvq: head=0x%llx, "
23205944Sha137994 		    "tail=0x%llx\n", rx_head, rx_tail);
23215944Sha137994 		DUMP_LDC_PKT(ldcp, "i_ldc_rx_process_hvq rcd",
23221991Sheppo 		    ldcp->rx_q_va + rx_head);
23231991Sheppo 
23241991Sheppo 		/* get the message */
23251991Sheppo 		msg = (ldc_msg_t *)(ldcp->rx_q_va + rx_head);
23261991Sheppo 
23271991Sheppo 		/* if channel is in RAW mode or data pkt, notify and return */
23281991Sheppo 		if (ldcp->mode == LDC_MODE_RAW) {
23295944Sha137994 			*notify_client = B_TRUE;
23305944Sha137994 			*notify_event |= LDC_EVT_READ;
23311991Sheppo 			break;
23321991Sheppo 		}
23331991Sheppo 
23341991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
23351991Sheppo 
23361991Sheppo 			/* discard packet if channel is not up */
23372793Slm66018 			if ((ldcp->tstate & ~TS_IN_RESET) != TS_UP) {
23381991Sheppo 
23391991Sheppo 				/* move the head one position */
23401991Sheppo 				rx_head = (rx_head + LDC_PACKET_SIZE) %
23414690Snarayan 				    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
23421991Sheppo 
23431991Sheppo 				if (rv = i_ldc_set_rx_head(ldcp, rx_head))
23441991Sheppo 					break;
23451991Sheppo 
23461991Sheppo 				continue;
23471991Sheppo 			} else {
23485944Sha137994 				uint64_t dq_head, dq_tail;
23495944Sha137994 
23506408Sha137994 				/* process only RELIABLE mode data packets */
23516408Sha137994 				if (ldcp->mode != LDC_MODE_RELIABLE) {
23525944Sha137994 					if ((ldcp->tstate & TS_IN_RESET) == 0)
23535944Sha137994 						*notify_client = B_TRUE;
23545944Sha137994 					*notify_event |= LDC_EVT_READ;
23555944Sha137994 					break;
23565944Sha137994 				}
23575944Sha137994 
23585944Sha137994 				/* don't process packet if queue full */
23595944Sha137994 				(void) i_ldc_dq_rx_get_state(ldcp, &dq_head,
23605944Sha137994 				    &dq_tail, NULL);
23615944Sha137994 				dq_tail = (dq_tail + LDC_PACKET_SIZE) %
23625944Sha137994 				    (ldcp->rx_dq_entries << LDC_PACKET_SHIFT);
23635944Sha137994 				if (dq_tail == dq_head ||
23645944Sha137994 				    LDC_INJECT_DQFULL(ldcp)) {
23655944Sha137994 					rv = ENOSPC;
23665944Sha137994 					break;
23675944Sha137994 				}
23681991Sheppo 			}
23691991Sheppo 		}
23701991Sheppo 
23711991Sheppo 		/* Check the sequence ID for the message received */
23722793Slm66018 		rv = i_ldc_check_seqid(ldcp, msg);
23732793Slm66018 		if (rv != 0) {
23741991Sheppo 
23755944Sha137994 			DWARN(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) "
23765944Sha137994 			    "seqid error, q_ptrs=0x%lx,0x%lx", ldcp->id,
23775944Sha137994 			    rx_head, rx_tail);
23781991Sheppo 
23791991Sheppo 			/* Reset last_msg_rcd to start of message */
23802336Snarayan 			if (first_fragment != 0) {
23812336Snarayan 				ldcp->last_msg_rcd = first_fragment - 1;
23822336Snarayan 				first_fragment = 0;
23831991Sheppo 			}
23842336Snarayan 
23851991Sheppo 			/*
23861991Sheppo 			 * Send a NACK due to seqid mismatch
23871991Sheppo 			 */
23884690Snarayan 			rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK,
23891991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK));
23901991Sheppo 
23911991Sheppo 			if (rv) {
23925944Sha137994 				cmn_err(CE_NOTE, "i_ldc_rx_process_hvq: "
23935944Sha137994 				    "(0x%lx) err sending CTRL/DATA NACK msg\n",
23945944Sha137994 				    ldcp->id);
23952336Snarayan 
23962336Snarayan 				/* if cannot send NACK - reset channel */
23972336Snarayan 				mutex_enter(&ldcp->tx_lock);
23982793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
23992336Snarayan 				mutex_exit(&ldcp->tx_lock);
24003560Snarayan 
24015944Sha137994 				*notify_client = B_TRUE;
24025944Sha137994 				*notify_event = LDC_EVT_RESET;
24032336Snarayan 				break;
24041991Sheppo 			}
24051991Sheppo 
24061991Sheppo 			/* purge receive queue */
24071991Sheppo 			(void) i_ldc_set_rx_head(ldcp, rx_tail);
24081991Sheppo 			break;
24091991Sheppo 		}
24101991Sheppo 
24111991Sheppo 		/* record the message ID */
24121991Sheppo 		ldcp->last_msg_rcd = msg->seqid;
24131991Sheppo 
24141991Sheppo 		/* process control messages */
24151991Sheppo 		if (msg->type & LDC_CTRL) {
24161991Sheppo 			/* save current internal state */
24171991Sheppo 			uint64_t tstate = ldcp->tstate;
24181991Sheppo 
24191991Sheppo 			rv = i_ldc_ctrlmsg(ldcp, msg);
24201991Sheppo 			if (rv == EAGAIN) {
24211991Sheppo 				/* re-process pkt - state was adjusted */
24221991Sheppo 				continue;
24231991Sheppo 			}
24241991Sheppo 			if (rv == ECONNRESET) {
24255944Sha137994 				*notify_client = B_TRUE;
24265944Sha137994 				*notify_event = LDC_EVT_RESET;
24271991Sheppo 				break;
24281991Sheppo 			}
24291991Sheppo 
24301991Sheppo 			/*
24311991Sheppo 			 * control message processing was successful
24321991Sheppo 			 * channel transitioned to ready for communication
24331991Sheppo 			 */
24341991Sheppo 			if (rv == 0 && ldcp->tstate == TS_UP &&
24352793Slm66018 			    (tstate & ~TS_IN_RESET) !=
24362793Slm66018 			    (ldcp->tstate & ~TS_IN_RESET)) {
24375944Sha137994 				*notify_client = B_TRUE;
24385944Sha137994 				*notify_event = LDC_EVT_UP;
24391991Sheppo 			}
24401991Sheppo 		}
24411991Sheppo 
24423560Snarayan 		/* process data NACKs */
24433560Snarayan 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) {
24443560Snarayan 			DWARN(ldcp->id,
24455944Sha137994 			    "i_ldc_rx_process_hvq: (0x%llx) received DATA/NACK",
24463560Snarayan 			    ldcp->id);
24473560Snarayan 			mutex_enter(&ldcp->tx_lock);
24483560Snarayan 			i_ldc_reset(ldcp, B_TRUE);
24493560Snarayan 			mutex_exit(&ldcp->tx_lock);
24505944Sha137994 			*notify_client = B_TRUE;
24515944Sha137994 			*notify_event = LDC_EVT_RESET;
24523560Snarayan 			break;
24533560Snarayan 		}
24543560Snarayan 
24551991Sheppo 		/* process data ACKs */
24561991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
24572336Snarayan 			if (rv = i_ldc_process_data_ACK(ldcp, msg)) {
24585944Sha137994 				*notify_client = B_TRUE;
24595944Sha137994 				*notify_event = LDC_EVT_RESET;
24602336Snarayan 				break;
24612336Snarayan 			}
24621991Sheppo 		}
24631991Sheppo 
24645944Sha137994 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
24656408Sha137994 			ASSERT(ldcp->mode == LDC_MODE_RELIABLE);
24665944Sha137994 
24675944Sha137994 			/*
24685944Sha137994 			 * Copy the data packet to the data queue. Note
24695944Sha137994 			 * that the copy routine updates the rx_head pointer.
24705944Sha137994 			 */
24715944Sha137994 			i_ldc_rxdq_copy(ldcp, &rx_head);
24725944Sha137994 
24735944Sha137994 			if ((ldcp->tstate & TS_IN_RESET) == 0)
24745944Sha137994 				*notify_client = B_TRUE;
24755944Sha137994 			*notify_event |= LDC_EVT_READ;
24765944Sha137994 		} else {
24775944Sha137994 			rx_head = (rx_head + LDC_PACKET_SIZE) %
24785944Sha137994 			    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
24795944Sha137994 		}
24805944Sha137994 
24811991Sheppo 		/* move the head one position */
24822032Slm66018 		if (rv = i_ldc_set_rx_head(ldcp, rx_head)) {
24835944Sha137994 			*notify_client = B_TRUE;
24845944Sha137994 			*notify_event = LDC_EVT_RESET;
24851991Sheppo 			break;
24862032Slm66018 		}
24871991Sheppo 
24881991Sheppo 	} /* for */
24891991Sheppo 
24902793Slm66018 loop_exit:
24912793Slm66018 
24926408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
24935944Sha137994 		/* ACK data packets */
24945944Sha137994 		if ((*notify_event &
24955944Sha137994 		    (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) {
24965944Sha137994 			int ack_rv;
24975944Sha137994 			ack_rv = i_ldc_send_pkt(ldcp, LDC_DATA, LDC_ACK, 0);
24985944Sha137994 			if (ack_rv && ack_rv != EWOULDBLOCK) {
24995944Sha137994 				cmn_err(CE_NOTE,
25005944Sha137994 				    "i_ldc_rx_process_hvq: (0x%lx) cannot "
25015944Sha137994 				    "send ACK\n", ldcp->id);
25025944Sha137994 
25035944Sha137994 				mutex_enter(&ldcp->tx_lock);
25045944Sha137994 				i_ldc_reset(ldcp, B_FALSE);
25055944Sha137994 				mutex_exit(&ldcp->tx_lock);
25065944Sha137994 
25075944Sha137994 				*notify_client = B_TRUE;
25085944Sha137994 				*notify_event = LDC_EVT_RESET;
25095944Sha137994 				goto skip_ackpeek;
25105944Sha137994 			}
25115944Sha137994 		}
25125944Sha137994 
25135944Sha137994 		/*
25145944Sha137994 		 * If we have no more space on the data queue, make sure
25155944Sha137994 		 * there are no ACKs on the rx queue waiting to be processed.
25165944Sha137994 		 */
25175944Sha137994 		if (rv == ENOSPC) {
25185944Sha137994 			if (i_ldc_rx_ackpeek(ldcp, rx_head, rx_tail) != 0) {
25195944Sha137994 				ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
25205944Sha137994 				*notify_client = B_TRUE;
25215944Sha137994 				*notify_event = LDC_EVT_RESET;
25225944Sha137994 			}
25236944Sha137994 			return (rv);
25245944Sha137994 		} else {
25255944Sha137994 			ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
25261991Sheppo 		}
25275944Sha137994 	}
25285944Sha137994 
25295944Sha137994 skip_ackpeek:
25305944Sha137994 
25315944Sha137994 	/* Return, indicating whether or not data packets were found */
25325944Sha137994 	if ((*notify_event & (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ)
25335944Sha137994 		return (0);
25345944Sha137994 
25355944Sha137994 	return (ENOMSG);
25361991Sheppo }
25371991Sheppo 
25385944Sha137994 /*
25395944Sha137994  * Process any ACK packets on the HV receive queue.
25405944Sha137994  *
25416408Sha137994  * This function is only used by RELIABLE mode channels when the
25425944Sha137994  * secondary data queue fills up and there are packets remaining on
25435944Sha137994  * the HV receive queue.
25445944Sha137994  */
25455944Sha137994 int
i_ldc_rx_ackpeek(ldc_chan_t * ldcp,uint64_t rx_head,uint64_t rx_tail)25465944Sha137994 i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, uint64_t rx_tail)
25475944Sha137994 {
25485944Sha137994 	int		rv = 0;
25495944Sha137994 	ldc_msg_t	*msg;
25505944Sha137994 
25515944Sha137994 	if (ldcp->rx_ack_head == ACKPEEK_HEAD_INVALID)
25525944Sha137994 		ldcp->rx_ack_head = rx_head;
25535944Sha137994 
25545944Sha137994 	while (ldcp->rx_ack_head != rx_tail) {
25555944Sha137994 		msg = (ldc_msg_t *)(ldcp->rx_q_va + ldcp->rx_ack_head);
25565944Sha137994 
25575944Sha137994 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
25585944Sha137994 			if (rv = i_ldc_process_data_ACK(ldcp, msg))
25595944Sha137994 				break;
25605944Sha137994 			msg->stype &= ~LDC_ACK;
25615944Sha137994 		}
25625944Sha137994 
25635944Sha137994 		ldcp->rx_ack_head =
25645944Sha137994 		    (ldcp->rx_ack_head + LDC_PACKET_SIZE) %
25655944Sha137994 		    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
25665944Sha137994 	}
25675944Sha137994 	return (rv);
25685944Sha137994 }
25691991Sheppo 
25701991Sheppo /* -------------------------------------------------------------------------- */
25711991Sheppo 
25721991Sheppo /*
25731991Sheppo  * LDC API functions
25741991Sheppo  */
25751991Sheppo 
25761991Sheppo /*
25771991Sheppo  * Initialize the channel. Allocate internal structure and memory for
25781991Sheppo  * TX/RX queues, and initialize locks.
25791991Sheppo  */
25801991Sheppo int
ldc_init(uint64_t id,ldc_attr_t * attr,ldc_handle_t * handle)25811991Sheppo ldc_init(uint64_t id, ldc_attr_t *attr, ldc_handle_t *handle)
25821991Sheppo {
25831991Sheppo 	ldc_chan_t 	*ldcp;
25841991Sheppo 	int		rv, exit_val;
25851991Sheppo 	uint64_t	ra_base, nentries;
25862410Slm66018 	uint64_t	qlen;
25871991Sheppo 
25881991Sheppo 	exit_val = EINVAL;	/* guarantee an error if exit on failure */
25891991Sheppo 
25901991Sheppo 	if (attr == NULL) {
25911991Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid attr\n", id);
25921991Sheppo 		return (EINVAL);
25931991Sheppo 	}
25941991Sheppo 	if (handle == NULL) {
25951991Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid handle\n", id);
25961991Sheppo 		return (EINVAL);
25971991Sheppo 	}
25981991Sheppo 
25991991Sheppo 	/* check if channel is valid */
26001991Sheppo 	rv = hv_ldc_tx_qinfo(id, &ra_base, &nentries);
26011991Sheppo 	if (rv == H_ECHANNEL) {
26021991Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid channel id\n", id);
26031991Sheppo 		return (EINVAL);
26041991Sheppo 	}
26051991Sheppo 
26061991Sheppo 	/* check if the channel has already been initialized */
26071991Sheppo 	mutex_enter(&ldcssp->lock);
26081991Sheppo 	ldcp = ldcssp->chan_list;
26091991Sheppo 	while (ldcp != NULL) {
26101991Sheppo 		if (ldcp->id == id) {
26111991Sheppo 			DWARN(id, "ldc_init: (0x%llx) already initialized\n",
26121991Sheppo 			    id);
26131991Sheppo 			mutex_exit(&ldcssp->lock);
26141991Sheppo 			return (EADDRINUSE);
26151991Sheppo 		}
26161991Sheppo 		ldcp = ldcp->next;
26171991Sheppo 	}
26181991Sheppo 	mutex_exit(&ldcssp->lock);
26191991Sheppo 
26201991Sheppo 	ASSERT(ldcp == NULL);
26211991Sheppo 
26221991Sheppo 	*handle = 0;
26231991Sheppo 
26241991Sheppo 	/* Allocate an ldcp structure */
26251991Sheppo 	ldcp = kmem_zalloc(sizeof (ldc_chan_t), KM_SLEEP);
26261991Sheppo 
26272336Snarayan 	/*
26282336Snarayan 	 * Initialize the channel and Tx lock
26292336Snarayan 	 *
26302336Snarayan 	 * The channel 'lock' protects the entire channel and
26312336Snarayan 	 * should be acquired before initializing, resetting,
26322336Snarayan 	 * destroying or reading from a channel.
26332336Snarayan 	 *
26342336Snarayan 	 * The 'tx_lock' should be acquired prior to transmitting
26352336Snarayan 	 * data over the channel. The lock should also be acquired
26362336Snarayan 	 * prior to channel reconfiguration (in order to prevent
26372336Snarayan 	 * concurrent writes).
26382336Snarayan 	 *
26392336Snarayan 	 * ORDERING: When both locks are being acquired, to prevent
26402336Snarayan 	 * deadlocks, the channel lock should be always acquired prior
26412336Snarayan 	 * to the tx_lock.
26422336Snarayan 	 */
26431991Sheppo 	mutex_init(&ldcp->lock, NULL, MUTEX_DRIVER, NULL);
26442336Snarayan 	mutex_init(&ldcp->tx_lock, NULL, MUTEX_DRIVER, NULL);
26451991Sheppo 
26461991Sheppo 	/* Initialize the channel */
26471991Sheppo 	ldcp->id = id;
26481991Sheppo 	ldcp->cb = NULL;
26491991Sheppo 	ldcp->cb_arg = NULL;
26501991Sheppo 	ldcp->cb_inprogress = B_FALSE;
26511991Sheppo 	ldcp->cb_enabled = B_FALSE;
26521991Sheppo 	ldcp->next = NULL;
26531991Sheppo 
26541991Sheppo 	/* Read attributes */
26551991Sheppo 	ldcp->mode = attr->mode;
26561991Sheppo 	ldcp->devclass = attr->devclass;
26571991Sheppo 	ldcp->devinst = attr->instance;
26582410Slm66018 	ldcp->mtu = (attr->mtu > 0) ? attr->mtu : LDC_DEFAULT_MTU;
26591991Sheppo 
26601991Sheppo 	D1(ldcp->id,
26611991Sheppo 	    "ldc_init: (0x%llx) channel attributes, class=0x%x, "
26622410Slm66018 	    "instance=0x%llx, mode=%d, mtu=%d\n",
26632410Slm66018 	    ldcp->id, ldcp->devclass, ldcp->devinst, ldcp->mode, ldcp->mtu);
26641991Sheppo 
26651991Sheppo 	ldcp->next_vidx = 0;
26662793Slm66018 	ldcp->tstate = TS_IN_RESET;
26671991Sheppo 	ldcp->hstate = 0;
26681991Sheppo 	ldcp->last_msg_snt = LDC_INIT_SEQID;
26691991Sheppo 	ldcp->last_ack_rcd = 0;
26701991Sheppo 	ldcp->last_msg_rcd = 0;
26715944Sha137994 	ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
26721991Sheppo 
26731991Sheppo 	ldcp->stream_bufferp = NULL;
26741991Sheppo 	ldcp->exp_dring_list = NULL;
26751991Sheppo 	ldcp->imp_dring_list = NULL;
26761991Sheppo 	ldcp->mhdl_list = NULL;
26771991Sheppo 
26782793Slm66018 	ldcp->tx_intr_state = LDC_INTR_NONE;
26792793Slm66018 	ldcp->rx_intr_state = LDC_INTR_NONE;
26802793Slm66018 
26811991Sheppo 	/* Initialize payload size depending on whether channel is reliable */
26821991Sheppo 	switch (ldcp->mode) {
26831991Sheppo 	case LDC_MODE_RAW:
26841991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RAW;
26851991Sheppo 		ldcp->read_p = i_ldc_read_raw;
26861991Sheppo 		ldcp->write_p = i_ldc_write_raw;
26871991Sheppo 		break;
26881991Sheppo 	case LDC_MODE_UNRELIABLE:
26891991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_UNRELIABLE;
26901991Sheppo 		ldcp->read_p = i_ldc_read_packet;
26911991Sheppo 		ldcp->write_p = i_ldc_write_packet;
26921991Sheppo 		break;
26931991Sheppo 	case LDC_MODE_RELIABLE:
26941991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE;
26951991Sheppo 
26961991Sheppo 		ldcp->stream_remains = 0;
26971991Sheppo 		ldcp->stream_offset = 0;
26981991Sheppo 		ldcp->stream_bufferp = kmem_alloc(ldcp->mtu, KM_SLEEP);
26991991Sheppo 		ldcp->read_p = i_ldc_read_stream;
27001991Sheppo 		ldcp->write_p = i_ldc_write_stream;
27011991Sheppo 		break;
27021991Sheppo 	default:
27031991Sheppo 		exit_val = EINVAL;
27041991Sheppo 		goto cleanup_on_exit;
27051991Sheppo 	}
27061991Sheppo 
27072410Slm66018 	/*
27082410Slm66018 	 * qlen is (mtu * ldc_mtu_msgs) / pkt_payload. If this
27092410Slm66018 	 * value is smaller than default length of ldc_queue_entries,
27104690Snarayan 	 * qlen is set to ldc_queue_entries. Ensure that computed
27114690Snarayan 	 * length is a power-of-two value.
27122410Slm66018 	 */
27132410Slm66018 	qlen = (ldcp->mtu * ldc_mtu_msgs) / ldcp->pkt_payload;
27144690Snarayan 	if (!ISP2(qlen)) {
27154690Snarayan 		uint64_t	tmp = 1;
27164690Snarayan 		while (qlen) {
27174690Snarayan 			qlen >>= 1; tmp <<= 1;
27184690Snarayan 		}
27194690Snarayan 		qlen = tmp;
27204690Snarayan 	}
27214690Snarayan 
27222410Slm66018 	ldcp->rx_q_entries =
27234690Snarayan 	    (qlen < ldc_queue_entries) ? ldc_queue_entries : qlen;
27242410Slm66018 	ldcp->tx_q_entries = ldcp->rx_q_entries;
27252410Slm66018 
27264690Snarayan 	D1(ldcp->id, "ldc_init: queue length = 0x%llx\n", ldcp->rx_q_entries);
27272410Slm66018 
27281991Sheppo 	/* Create a transmit queue */
27291991Sheppo 	ldcp->tx_q_va = (uint64_t)
27304690Snarayan 	    contig_mem_alloc(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
27311991Sheppo 	if (ldcp->tx_q_va == NULL) {
27321991Sheppo 		cmn_err(CE_WARN,
27331991Sheppo 		    "ldc_init: (0x%lx) TX queue allocation failed\n",
27341991Sheppo 		    ldcp->id);
27351991Sheppo 		exit_val = ENOMEM;
27361991Sheppo 		goto cleanup_on_exit;
27371991Sheppo 	}
27381991Sheppo 	ldcp->tx_q_ra = va_to_pa((caddr_t)ldcp->tx_q_va);
27391991Sheppo 
27401991Sheppo 	D2(ldcp->id, "ldc_init: txq_va=0x%llx, txq_ra=0x%llx, entries=0x%llx\n",
27411991Sheppo 	    ldcp->tx_q_va, ldcp->tx_q_ra, ldcp->tx_q_entries);
27421991Sheppo 
27431991Sheppo 	ldcp->tstate |= TS_TXQ_RDY;
27441991Sheppo 
27451991Sheppo 	/* Create a receive queue */
27461991Sheppo 	ldcp->rx_q_va = (uint64_t)
27474690Snarayan 	    contig_mem_alloc(ldcp->rx_q_entries << LDC_PACKET_SHIFT);
27481991Sheppo 	if (ldcp->rx_q_va == NULL) {
27491991Sheppo 		cmn_err(CE_WARN,
27501991Sheppo 		    "ldc_init: (0x%lx) RX queue allocation failed\n",
27511991Sheppo 		    ldcp->id);
27521991Sheppo 		exit_val = ENOMEM;
27531991Sheppo 		goto cleanup_on_exit;
27541991Sheppo 	}
27551991Sheppo 	ldcp->rx_q_ra = va_to_pa((caddr_t)ldcp->rx_q_va);
27561991Sheppo 
27571991Sheppo 	D2(ldcp->id, "ldc_init: rxq_va=0x%llx, rxq_ra=0x%llx, entries=0x%llx\n",
27581991Sheppo 	    ldcp->rx_q_va, ldcp->rx_q_ra, ldcp->rx_q_entries);
27591991Sheppo 
27601991Sheppo 	ldcp->tstate |= TS_RXQ_RDY;
27611991Sheppo 
27625944Sha137994 	/* Setup a separate read data queue */
27636408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
27645944Sha137994 		ldcp->readq_get_state = i_ldc_dq_rx_get_state;
27655944Sha137994 		ldcp->readq_set_head  = i_ldc_set_rxdq_head;
27665944Sha137994 
27675944Sha137994 		/* Make sure the data queue multiplier is a power of 2 */
27685944Sha137994 		if (!ISP2(ldc_rxdq_multiplier)) {
27695944Sha137994 			D1(ldcp->id, "ldc_init: (0x%llx) ldc_rxdq_multiplier "
27705944Sha137994 			    "not a power of 2, resetting", ldcp->id);
27715944Sha137994 			ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER;
27725944Sha137994 		}
27735944Sha137994 
27745944Sha137994 		ldcp->rx_dq_entries = ldc_rxdq_multiplier * ldcp->rx_q_entries;
27755944Sha137994 		ldcp->rx_dq_va = (uint64_t)
27765944Sha137994 		    kmem_alloc(ldcp->rx_dq_entries << LDC_PACKET_SHIFT,
27775944Sha137994 		    KM_SLEEP);
27785944Sha137994 		if (ldcp->rx_dq_va == NULL) {
27795944Sha137994 			cmn_err(CE_WARN,
27805944Sha137994 			    "ldc_init: (0x%lx) RX data queue "
27815944Sha137994 			    "allocation failed\n", ldcp->id);
27825944Sha137994 			exit_val = ENOMEM;
27835944Sha137994 			goto cleanup_on_exit;
27845944Sha137994 		}
27855944Sha137994 
27865944Sha137994 		ldcp->rx_dq_head = ldcp->rx_dq_tail = 0;
27875944Sha137994 
27885944Sha137994 		D2(ldcp->id, "ldc_init: rx_dq_va=0x%llx, "
27895944Sha137994 		    "rx_dq_entries=0x%llx\n", ldcp->rx_dq_va,
27905944Sha137994 		    ldcp->rx_dq_entries);
27915944Sha137994 	} else {
27925944Sha137994 		ldcp->readq_get_state = i_ldc_hvq_rx_get_state;
27935944Sha137994 		ldcp->readq_set_head  = i_ldc_set_rx_head;
27945944Sha137994 	}
27955944Sha137994 
27961991Sheppo 	/* Init descriptor ring and memory handle list lock */
27971991Sheppo 	mutex_init(&ldcp->exp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
27981991Sheppo 	mutex_init(&ldcp->imp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
27991991Sheppo 	mutex_init(&ldcp->mlist_lock, NULL, MUTEX_DRIVER, NULL);
28001991Sheppo 
28011991Sheppo 	/* mark status as INITialized */
28021991Sheppo 	ldcp->status = LDC_INIT;
28031991Sheppo 
28041991Sheppo 	/* Add to channel list */
28051991Sheppo 	mutex_enter(&ldcssp->lock);
28061991Sheppo 	ldcp->next = ldcssp->chan_list;
28071991Sheppo 	ldcssp->chan_list = ldcp;
28081991Sheppo 	ldcssp->channel_count++;
28091991Sheppo 	mutex_exit(&ldcssp->lock);
28101991Sheppo 
28111991Sheppo 	/* set the handle */
28121991Sheppo 	*handle = (ldc_handle_t)ldcp;
28131991Sheppo 
28141991Sheppo 	D1(ldcp->id, "ldc_init: (0x%llx) channel initialized\n", ldcp->id);
28151991Sheppo 
28161991Sheppo 	return (0);
28171991Sheppo 
28181991Sheppo cleanup_on_exit:
28191991Sheppo 
28206408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp)
28211991Sheppo 		kmem_free(ldcp->stream_bufferp, ldcp->mtu);
28221991Sheppo 
28231991Sheppo 	if (ldcp->tstate & TS_TXQ_RDY)
28241991Sheppo 		contig_mem_free((caddr_t)ldcp->tx_q_va,
28251991Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
28261991Sheppo 
28271991Sheppo 	if (ldcp->tstate & TS_RXQ_RDY)
28281991Sheppo 		contig_mem_free((caddr_t)ldcp->rx_q_va,
28291991Sheppo 		    (ldcp->rx_q_entries << LDC_PACKET_SHIFT));
28301991Sheppo 
28312336Snarayan 	mutex_destroy(&ldcp->tx_lock);
28321991Sheppo 	mutex_destroy(&ldcp->lock);
28331991Sheppo 
28341991Sheppo 	if (ldcp)
28351991Sheppo 		kmem_free(ldcp, sizeof (ldc_chan_t));
28361991Sheppo 
28371991Sheppo 	return (exit_val);
28381991Sheppo }
28391991Sheppo 
28401991Sheppo /*
28411991Sheppo  * Finalizes the LDC connection. It will return EBUSY if the
28421991Sheppo  * channel is open. A ldc_close() has to be done prior to
28431991Sheppo  * a ldc_fini operation. It frees TX/RX queues, associated
28441991Sheppo  * with the channel
28451991Sheppo  */
28461991Sheppo int
ldc_fini(ldc_handle_t handle)28471991Sheppo ldc_fini(ldc_handle_t handle)
28481991Sheppo {
28491991Sheppo 	ldc_chan_t 	*ldcp;
28501991Sheppo 	ldc_chan_t 	*tmp_ldcp;
28511991Sheppo 	uint64_t 	id;
28521991Sheppo 
28531991Sheppo 	if (handle == NULL) {
28541991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel handle\n");
28551991Sheppo 		return (EINVAL);
28561991Sheppo 	}
28571991Sheppo 	ldcp = (ldc_chan_t *)handle;
28581991Sheppo 	id = ldcp->id;
28591991Sheppo 
28601991Sheppo 	mutex_enter(&ldcp->lock);
28611991Sheppo 
28622793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) > TS_INIT) {
28631991Sheppo 		DWARN(ldcp->id, "ldc_fini: (0x%llx) channel is open\n",
28641991Sheppo 		    ldcp->id);
28651991Sheppo 		mutex_exit(&ldcp->lock);
28661991Sheppo 		return (EBUSY);
28671991Sheppo 	}
28681991Sheppo 
28691991Sheppo 	/* Remove from the channel list */
28701991Sheppo 	mutex_enter(&ldcssp->lock);
28711991Sheppo 	tmp_ldcp = ldcssp->chan_list;
28721991Sheppo 	if (tmp_ldcp == ldcp) {
28731991Sheppo 		ldcssp->chan_list = ldcp->next;
28741991Sheppo 		ldcp->next = NULL;
28751991Sheppo 	} else {
28761991Sheppo 		while (tmp_ldcp != NULL) {
28771991Sheppo 			if (tmp_ldcp->next == ldcp) {
28781991Sheppo 				tmp_ldcp->next = ldcp->next;
28791991Sheppo 				ldcp->next = NULL;
28801991Sheppo 				break;
28811991Sheppo 			}
28821991Sheppo 			tmp_ldcp = tmp_ldcp->next;
28831991Sheppo 		}
28841991Sheppo 		if (tmp_ldcp == NULL) {
28851991Sheppo 			DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel hdl\n");
28861991Sheppo 			mutex_exit(&ldcssp->lock);
28871991Sheppo 			mutex_exit(&ldcp->lock);
28881991Sheppo 			return (EINVAL);
28891991Sheppo 		}
28901991Sheppo 	}
28911991Sheppo 
28921991Sheppo 	ldcssp->channel_count--;
28931991Sheppo 
28941991Sheppo 	mutex_exit(&ldcssp->lock);
28951991Sheppo 
28961991Sheppo 	/* Free the map table for this channel */
28971991Sheppo 	if (ldcp->mtbl) {
28981991Sheppo 		(void) hv_ldc_set_map_table(ldcp->id, NULL, NULL);
28992793Slm66018 		if (ldcp->mtbl->contigmem)
29002793Slm66018 			contig_mem_free(ldcp->mtbl->table, ldcp->mtbl->size);
29012793Slm66018 		else
29022793Slm66018 			kmem_free(ldcp->mtbl->table, ldcp->mtbl->size);
29031991Sheppo 		mutex_destroy(&ldcp->mtbl->lock);
29041991Sheppo 		kmem_free(ldcp->mtbl, sizeof (ldc_mtbl_t));
29051991Sheppo 	}
29061991Sheppo 
29071991Sheppo 	/* Destroy descriptor ring and memory handle list lock */
29081991Sheppo 	mutex_destroy(&ldcp->exp_dlist_lock);
29091991Sheppo 	mutex_destroy(&ldcp->imp_dlist_lock);
29101991Sheppo 	mutex_destroy(&ldcp->mlist_lock);
29111991Sheppo 
29126408Sha137994 	/* Free the stream buffer for RELIABLE_MODE */
29136408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp)
29141991Sheppo 		kmem_free(ldcp->stream_bufferp, ldcp->mtu);
29151991Sheppo 
29161991Sheppo 	/* Free the RX queue */
29171991Sheppo 	contig_mem_free((caddr_t)ldcp->rx_q_va,
29181991Sheppo 	    (ldcp->rx_q_entries << LDC_PACKET_SHIFT));
29191991Sheppo 	ldcp->tstate &= ~TS_RXQ_RDY;
29201991Sheppo 
29215944Sha137994 	/* Free the RX data queue */
29226408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
29235944Sha137994 		kmem_free((caddr_t)ldcp->rx_dq_va,
29245944Sha137994 		    (ldcp->rx_dq_entries << LDC_PACKET_SHIFT));
29255944Sha137994 	}
29265944Sha137994 
29271991Sheppo 	/* Free the TX queue */
29281991Sheppo 	contig_mem_free((caddr_t)ldcp->tx_q_va,
29291991Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
29301991Sheppo 	ldcp->tstate &= ~TS_TXQ_RDY;
29311991Sheppo 
29321991Sheppo 	mutex_exit(&ldcp->lock);
29331991Sheppo 
29341991Sheppo 	/* Destroy mutex */
29352336Snarayan 	mutex_destroy(&ldcp->tx_lock);
29361991Sheppo 	mutex_destroy(&ldcp->lock);
29371991Sheppo 
29381991Sheppo 	/* free channel structure */
29391991Sheppo 	kmem_free(ldcp, sizeof (ldc_chan_t));
29401991Sheppo 
29411991Sheppo 	D1(id, "ldc_fini: (0x%llx) channel finalized\n", id);
29421991Sheppo 
29431991Sheppo 	return (0);
29441991Sheppo }
29451991Sheppo 
29461991Sheppo /*
29471991Sheppo  * Open the LDC channel for use. It registers the TX/RX queues
29481991Sheppo  * with the Hypervisor. It also specifies the interrupt number
29491991Sheppo  * and target CPU for this channel
29501991Sheppo  */
29511991Sheppo int
ldc_open(ldc_handle_t handle)29521991Sheppo ldc_open(ldc_handle_t handle)
29531991Sheppo {
29541991Sheppo 	ldc_chan_t 	*ldcp;
29551991Sheppo 	int 		rv;
29561991Sheppo 
29571991Sheppo 	if (handle == NULL) {
29581991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_open: invalid channel handle\n");
29591991Sheppo 		return (EINVAL);
29601991Sheppo 	}
29611991Sheppo 
29621991Sheppo 	ldcp = (ldc_chan_t *)handle;
29631991Sheppo 
29641991Sheppo 	mutex_enter(&ldcp->lock);
29651991Sheppo 
29661991Sheppo 	if (ldcp->tstate < TS_INIT) {
29671991Sheppo 		DWARN(ldcp->id,
29681991Sheppo 		    "ldc_open: (0x%llx) channel not initialized\n", ldcp->id);
29691991Sheppo 		mutex_exit(&ldcp->lock);
29701991Sheppo 		return (EFAULT);
29711991Sheppo 	}
29722793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) >= TS_OPEN) {
29731991Sheppo 		DWARN(ldcp->id,
29741991Sheppo 		    "ldc_open: (0x%llx) channel is already open\n", ldcp->id);
29751991Sheppo 		mutex_exit(&ldcp->lock);
29761991Sheppo 		return (EFAULT);
29771991Sheppo 	}
29781991Sheppo 
29791991Sheppo 	/*
29801991Sheppo 	 * Unregister/Register the tx queue with the hypervisor
29811991Sheppo 	 */
29821991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
29831991Sheppo 	if (rv) {
29841991Sheppo 		cmn_err(CE_WARN,
29851991Sheppo 		    "ldc_open: (0x%lx) channel tx queue unconf failed\n",
29861991Sheppo 		    ldcp->id);
29871991Sheppo 		mutex_exit(&ldcp->lock);
29881991Sheppo 		return (EIO);
29891991Sheppo 	}
29901991Sheppo 
29911991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
29921991Sheppo 	if (rv) {
29931991Sheppo 		cmn_err(CE_WARN,
29941991Sheppo 		    "ldc_open: (0x%lx) channel tx queue conf failed\n",
29951991Sheppo 		    ldcp->id);
29961991Sheppo 		mutex_exit(&ldcp->lock);
29971991Sheppo 		return (EIO);
29981991Sheppo 	}
29991991Sheppo 
30001991Sheppo 	D2(ldcp->id, "ldc_open: (0x%llx) registered tx queue with LDC\n",
30011991Sheppo 	    ldcp->id);
30021991Sheppo 
30031991Sheppo 	/*
30041991Sheppo 	 * Unregister/Register the rx queue with the hypervisor
30051991Sheppo 	 */
30061991Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
30071991Sheppo 	if (rv) {
30081991Sheppo 		cmn_err(CE_WARN,
30091991Sheppo 		    "ldc_open: (0x%lx) channel rx queue unconf failed\n",
30101991Sheppo 		    ldcp->id);
30111991Sheppo 		mutex_exit(&ldcp->lock);
30121991Sheppo 		return (EIO);
30131991Sheppo 	}
30141991Sheppo 
30151991Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, ldcp->rx_q_entries);
30161991Sheppo 	if (rv) {
30171991Sheppo 		cmn_err(CE_WARN,
30181991Sheppo 		    "ldc_open: (0x%lx) channel rx queue conf failed\n",
30191991Sheppo 		    ldcp->id);
30201991Sheppo 		mutex_exit(&ldcp->lock);
30211991Sheppo 		return (EIO);
30221991Sheppo 	}
30231991Sheppo 
30241991Sheppo 	D2(ldcp->id, "ldc_open: (0x%llx) registered rx queue with LDC\n",
30251991Sheppo 	    ldcp->id);
30261991Sheppo 
30271991Sheppo 	ldcp->tstate |= TS_QCONF_RDY;
30281991Sheppo 
30291991Sheppo 	/* Register the channel with the channel nexus */
30301991Sheppo 	rv = i_ldc_register_channel(ldcp);
30311991Sheppo 	if (rv && rv != EAGAIN) {
30321991Sheppo 		cmn_err(CE_WARN,
30331991Sheppo 		    "ldc_open: (0x%lx) channel register failed\n", ldcp->id);
30348542SHaik.Aftandilian@Sun.COM 		ldcp->tstate &= ~TS_QCONF_RDY;
30351991Sheppo 		(void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
30361991Sheppo 		(void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
30371991Sheppo 		mutex_exit(&ldcp->lock);
30381991Sheppo 		return (EIO);
30391991Sheppo 	}
30401991Sheppo 
30411991Sheppo 	/* mark channel in OPEN state */
30421991Sheppo 	ldcp->status = LDC_OPEN;
30431991Sheppo 
30441991Sheppo 	/* Read channel state */
30451991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
30461991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
30471991Sheppo 	if (rv) {
30481991Sheppo 		cmn_err(CE_WARN,
30491991Sheppo 		    "ldc_open: (0x%lx) cannot read channel state\n",
30501991Sheppo 		    ldcp->id);
30511991Sheppo 		(void) i_ldc_unregister_channel(ldcp);
30528542SHaik.Aftandilian@Sun.COM 		ldcp->tstate &= ~TS_QCONF_RDY;
30531991Sheppo 		(void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
30541991Sheppo 		(void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
30551991Sheppo 		mutex_exit(&ldcp->lock);
30561991Sheppo 		return (EIO);
30571991Sheppo 	}
30581991Sheppo 
30591991Sheppo 	/*
30606408Sha137994 	 * set the ACKd head to current head location for reliable
30611991Sheppo 	 */
30621991Sheppo 	ldcp->tx_ackd_head = ldcp->tx_head;
30631991Sheppo 
30641991Sheppo 	/* mark channel ready if HV report link is UP (peer alloc'd Rx queue) */
30651991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_UP ||
30661991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
30671991Sheppo 		ldcp->tstate |= TS_LINK_READY;
30681991Sheppo 		ldcp->status = LDC_READY;
30691991Sheppo 	}
30701991Sheppo 
30711991Sheppo 	/*
30721991Sheppo 	 * if channel is being opened in RAW mode - no handshake is needed
30731991Sheppo 	 * switch the channel READY and UP state
30741991Sheppo 	 */
30751991Sheppo 	if (ldcp->mode == LDC_MODE_RAW) {
30761991Sheppo 		ldcp->tstate = TS_UP;	/* set bits associated with LDC UP */
30771991Sheppo 		ldcp->status = LDC_UP;
30781991Sheppo 	}
30791991Sheppo 
30801991Sheppo 	mutex_exit(&ldcp->lock);
30811991Sheppo 
30821991Sheppo 	/*
30831991Sheppo 	 * Increment number of open channels
30841991Sheppo 	 */
30851991Sheppo 	mutex_enter(&ldcssp->lock);
30861991Sheppo 	ldcssp->channels_open++;
30871991Sheppo 	mutex_exit(&ldcssp->lock);
30881991Sheppo 
30893010Slm66018 	D1(ldcp->id,
30902793Slm66018 	    "ldc_open: (0x%llx) channel (0x%p) open for use "
30912793Slm66018 	    "(tstate=0x%x, status=0x%x)\n",
30922793Slm66018 	    ldcp->id, ldcp, ldcp->tstate, ldcp->status);
30931991Sheppo 
30941991Sheppo 	return (0);
30951991Sheppo }
30961991Sheppo 
30971991Sheppo /*
30981991Sheppo  * Close the LDC connection. It will return EBUSY if there
30991991Sheppo  * are memory segments or descriptor rings either bound to or
31001991Sheppo  * mapped over the channel
31011991Sheppo  */
31021991Sheppo int
ldc_close(ldc_handle_t handle)31031991Sheppo ldc_close(ldc_handle_t handle)
31041991Sheppo {
31051991Sheppo 	ldc_chan_t 	*ldcp;
31062336Snarayan 	int		rv = 0, retries = 0;
31071991Sheppo 	boolean_t	chk_done = B_FALSE;
31081991Sheppo 
31091991Sheppo 	if (handle == NULL) {
31101991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_close: invalid channel handle\n");
31111991Sheppo 		return (EINVAL);
31121991Sheppo 	}
31131991Sheppo 	ldcp = (ldc_chan_t *)handle;
31141991Sheppo 
31151991Sheppo 	mutex_enter(&ldcp->lock);
31161991Sheppo 
31171991Sheppo 	/* return error if channel is not open */
31182793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) < TS_OPEN) {
31191991Sheppo 		DWARN(ldcp->id,
31201991Sheppo 		    "ldc_close: (0x%llx) channel is not open\n", ldcp->id);
31211991Sheppo 		mutex_exit(&ldcp->lock);
31221991Sheppo 		return (EFAULT);
31231991Sheppo 	}
31241991Sheppo 
31251991Sheppo 	/* if any memory handles, drings, are bound or mapped cannot close */
31261991Sheppo 	if (ldcp->mhdl_list != NULL) {
31271991Sheppo 		DWARN(ldcp->id,
31281991Sheppo 		    "ldc_close: (0x%llx) channel has bound memory handles\n",
31291991Sheppo 		    ldcp->id);
31301991Sheppo 		mutex_exit(&ldcp->lock);
31311991Sheppo 		return (EBUSY);
31321991Sheppo 	}
31331991Sheppo 	if (ldcp->exp_dring_list != NULL) {
31341991Sheppo 		DWARN(ldcp->id,
31351991Sheppo 		    "ldc_close: (0x%llx) channel has bound descriptor rings\n",
31361991Sheppo 		    ldcp->id);
31371991Sheppo 		mutex_exit(&ldcp->lock);
31381991Sheppo 		return (EBUSY);
31391991Sheppo 	}
31401991Sheppo 	if (ldcp->imp_dring_list != NULL) {
31411991Sheppo 		DWARN(ldcp->id,
31421991Sheppo 		    "ldc_close: (0x%llx) channel has mapped descriptor rings\n",
31431991Sheppo 		    ldcp->id);
31441991Sheppo 		mutex_exit(&ldcp->lock);
31451991Sheppo 		return (EBUSY);
31461991Sheppo 	}
31471991Sheppo 
31483151Ssg70180 	if (ldcp->cb_inprogress) {
31493151Ssg70180 		DWARN(ldcp->id, "ldc_close: (0x%llx) callback active\n",
31503151Ssg70180 		    ldcp->id);
31513151Ssg70180 		mutex_exit(&ldcp->lock);
31523151Ssg70180 		return (EWOULDBLOCK);
31533151Ssg70180 	}
31543151Ssg70180 
31552336Snarayan 	/* Obtain Tx lock */
31562336Snarayan 	mutex_enter(&ldcp->tx_lock);
31572336Snarayan 
31581991Sheppo 	/*
31591991Sheppo 	 * Wait for pending transmits to complete i.e Tx queue to drain
31601991Sheppo 	 * if there are pending pkts - wait 1 ms and retry again
31611991Sheppo 	 */
31621991Sheppo 	for (;;) {
31631991Sheppo 
31641991Sheppo 		rv = hv_ldc_tx_get_state(ldcp->id,
31651991Sheppo 		    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
31661991Sheppo 		if (rv) {
31671991Sheppo 			cmn_err(CE_WARN,
31681991Sheppo 			    "ldc_close: (0x%lx) cannot read qptrs\n", ldcp->id);
31692336Snarayan 			mutex_exit(&ldcp->tx_lock);
31701991Sheppo 			mutex_exit(&ldcp->lock);
31711991Sheppo 			return (EIO);
31721991Sheppo 		}
31731991Sheppo 
31741991Sheppo 		if (ldcp->tx_head == ldcp->tx_tail ||
31751991Sheppo 		    ldcp->link_state != LDC_CHANNEL_UP) {
31761991Sheppo 			break;
31771991Sheppo 		}
31781991Sheppo 
31791991Sheppo 		if (chk_done) {
31801991Sheppo 			DWARN(ldcp->id,
31811991Sheppo 			    "ldc_close: (0x%llx) Tx queue drain timeout\n",
31821991Sheppo 			    ldcp->id);
31831991Sheppo 			break;
31841991Sheppo 		}
31851991Sheppo 
31861991Sheppo 		/* wait for one ms and try again */
31871991Sheppo 		delay(drv_usectohz(1000));
31881991Sheppo 		chk_done = B_TRUE;
31891991Sheppo 	}
31901991Sheppo 
31911991Sheppo 	/*
31922841Snarayan 	 * Drain the Tx and Rx queues as we are closing the
31932841Snarayan 	 * channel. We dont care about any pending packets.
31942841Snarayan 	 * We have to also drain the queue prior to clearing
31952841Snarayan 	 * pending interrupts, otherwise the HV will trigger
31962841Snarayan 	 * an interrupt the moment the interrupt state is
31972841Snarayan 	 * cleared.
31982793Slm66018 	 */
31992793Slm66018 	(void) i_ldc_txq_reconf(ldcp);
320010055SKevin.Crowe@Sun.COM 	i_ldc_rxq_drain(ldcp);
32012793Slm66018 
32022793Slm66018 	/*
32031991Sheppo 	 * Unregister the channel with the nexus
32041991Sheppo 	 */
32052336Snarayan 	while ((rv = i_ldc_unregister_channel(ldcp)) != 0) {
32062336Snarayan 
32072336Snarayan 		mutex_exit(&ldcp->tx_lock);
32081991Sheppo 		mutex_exit(&ldcp->lock);
32092336Snarayan 
32102336Snarayan 		/* if any error other than EAGAIN return back */
32112841Snarayan 		if (rv != EAGAIN || retries >= ldc_max_retries) {
32122336Snarayan 			cmn_err(CE_WARN,
32132336Snarayan 			    "ldc_close: (0x%lx) unregister failed, %d\n",
32142336Snarayan 			    ldcp->id, rv);
32152336Snarayan 			return (rv);
32162336Snarayan 		}
32172336Snarayan 
32182336Snarayan 		/*
32192336Snarayan 		 * As there could be pending interrupts we need
32202336Snarayan 		 * to wait and try again
32212336Snarayan 		 */
32223151Ssg70180 		drv_usecwait(ldc_close_delay);
32232336Snarayan 		mutex_enter(&ldcp->lock);
32242336Snarayan 		mutex_enter(&ldcp->tx_lock);
32252336Snarayan 		retries++;
32261991Sheppo 	}
32271991Sheppo 
32288542SHaik.Aftandilian@Sun.COM 	ldcp->tstate &= ~TS_QCONF_RDY;
32298542SHaik.Aftandilian@Sun.COM 
32301991Sheppo 	/*
32311991Sheppo 	 * Unregister queues
32321991Sheppo 	 */
32331991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
32341991Sheppo 	if (rv) {
32351991Sheppo 		cmn_err(CE_WARN,
32361991Sheppo 		    "ldc_close: (0x%lx) channel TX queue unconf failed\n",
32371991Sheppo 		    ldcp->id);
32382336Snarayan 		mutex_exit(&ldcp->tx_lock);
32391991Sheppo 		mutex_exit(&ldcp->lock);
32401991Sheppo 		return (EIO);
32411991Sheppo 	}
32421991Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
32431991Sheppo 	if (rv) {
32441991Sheppo 		cmn_err(CE_WARN,
32451991Sheppo 		    "ldc_close: (0x%lx) channel RX queue unconf failed\n",
32461991Sheppo 		    ldcp->id);
32472336Snarayan 		mutex_exit(&ldcp->tx_lock);
32481991Sheppo 		mutex_exit(&ldcp->lock);
32491991Sheppo 		return (EIO);
32501991Sheppo 	}
32511991Sheppo 
32521991Sheppo 	/* Reset channel state information */
32531991Sheppo 	i_ldc_reset_state(ldcp);
32541991Sheppo 
32551991Sheppo 	/* Mark channel as down and in initialized state */
32561991Sheppo 	ldcp->tx_ackd_head = 0;
32571991Sheppo 	ldcp->tx_head = 0;
32582793Slm66018 	ldcp->tstate = TS_IN_RESET|TS_INIT;
32591991Sheppo 	ldcp->status = LDC_INIT;
32601991Sheppo 
32612336Snarayan 	mutex_exit(&ldcp->tx_lock);
32621991Sheppo 	mutex_exit(&ldcp->lock);
32631991Sheppo 
32641991Sheppo 	/* Decrement number of open channels */
32651991Sheppo 	mutex_enter(&ldcssp->lock);
32661991Sheppo 	ldcssp->channels_open--;
32671991Sheppo 	mutex_exit(&ldcssp->lock);
32681991Sheppo 
32691991Sheppo 	D1(ldcp->id, "ldc_close: (0x%llx) channel closed\n", ldcp->id);
32701991Sheppo 
32711991Sheppo 	return (0);
32721991Sheppo }
32731991Sheppo 
32741991Sheppo /*
32751991Sheppo  * Register channel callback
32761991Sheppo  */
32771991Sheppo int
ldc_reg_callback(ldc_handle_t handle,uint_t (* cb)(uint64_t event,caddr_t arg),caddr_t arg)32781991Sheppo ldc_reg_callback(ldc_handle_t handle,
32791991Sheppo     uint_t(*cb)(uint64_t event, caddr_t arg), caddr_t arg)
32801991Sheppo {
32811991Sheppo 	ldc_chan_t *ldcp;
32821991Sheppo 
32831991Sheppo 	if (handle == NULL) {
32841991Sheppo 		DWARN(DBG_ALL_LDCS,
32851991Sheppo 		    "ldc_reg_callback: invalid channel handle\n");
32861991Sheppo 		return (EINVAL);
32871991Sheppo 	}
32881991Sheppo 	if (((uint64_t)cb) < KERNELBASE) {
32891991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_reg_callback: invalid callback\n");
32901991Sheppo 		return (EINVAL);
32911991Sheppo 	}
32921991Sheppo 	ldcp = (ldc_chan_t *)handle;
32931991Sheppo 
32941991Sheppo 	mutex_enter(&ldcp->lock);
32951991Sheppo 
32961991Sheppo 	if (ldcp->cb) {
32971991Sheppo 		DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback exists\n",
32981991Sheppo 		    ldcp->id);
32991991Sheppo 		mutex_exit(&ldcp->lock);
33001991Sheppo 		return (EIO);
33011991Sheppo 	}
33021991Sheppo 	if (ldcp->cb_inprogress) {
33031991Sheppo 		DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback active\n",
33041991Sheppo 		    ldcp->id);
33051991Sheppo 		mutex_exit(&ldcp->lock);
33061991Sheppo 		return (EWOULDBLOCK);
33071991Sheppo 	}
33081991Sheppo 
33091991Sheppo 	ldcp->cb = cb;
33101991Sheppo 	ldcp->cb_arg = arg;
33111991Sheppo 	ldcp->cb_enabled = B_TRUE;
33121991Sheppo 
33131991Sheppo 	D1(ldcp->id,
33141991Sheppo 	    "ldc_reg_callback: (0x%llx) registered callback for channel\n",
33151991Sheppo 	    ldcp->id);
33161991Sheppo 
33171991Sheppo 	mutex_exit(&ldcp->lock);
33181991Sheppo 
33191991Sheppo 	return (0);
33201991Sheppo }
33211991Sheppo 
33221991Sheppo /*
33231991Sheppo  * Unregister channel callback
33241991Sheppo  */
33251991Sheppo int
ldc_unreg_callback(ldc_handle_t handle)33261991Sheppo ldc_unreg_callback(ldc_handle_t handle)
33271991Sheppo {
33281991Sheppo 	ldc_chan_t *ldcp;
33291991Sheppo 
33301991Sheppo 	if (handle == NULL) {
33311991Sheppo 		DWARN(DBG_ALL_LDCS,
33321991Sheppo 		    "ldc_unreg_callback: invalid channel handle\n");
33331991Sheppo 		return (EINVAL);
33341991Sheppo 	}
33351991Sheppo 	ldcp = (ldc_chan_t *)handle;
33361991Sheppo 
33371991Sheppo 	mutex_enter(&ldcp->lock);
33381991Sheppo 
33391991Sheppo 	if (ldcp->cb == NULL) {
33401991Sheppo 		DWARN(ldcp->id,
33411991Sheppo 		    "ldc_unreg_callback: (0x%llx) no callback exists\n",
33421991Sheppo 		    ldcp->id);
33431991Sheppo 		mutex_exit(&ldcp->lock);
33441991Sheppo 		return (EIO);
33451991Sheppo 	}
33461991Sheppo 	if (ldcp->cb_inprogress) {
33471991Sheppo 		DWARN(ldcp->id,
33481991Sheppo 		    "ldc_unreg_callback: (0x%llx) callback active\n",
33491991Sheppo 		    ldcp->id);
33501991Sheppo 		mutex_exit(&ldcp->lock);
33511991Sheppo 		return (EWOULDBLOCK);
33521991Sheppo 	}
33531991Sheppo 
33541991Sheppo 	ldcp->cb = NULL;
33551991Sheppo 	ldcp->cb_arg = NULL;
33561991Sheppo 	ldcp->cb_enabled = B_FALSE;
33571991Sheppo 
33581991Sheppo 	D1(ldcp->id,
33591991Sheppo 	    "ldc_unreg_callback: (0x%llx) unregistered callback for channel\n",
33601991Sheppo 	    ldcp->id);
33611991Sheppo 
33621991Sheppo 	mutex_exit(&ldcp->lock);
33631991Sheppo 
33641991Sheppo 	return (0);
33651991Sheppo }
33661991Sheppo 
33671991Sheppo 
33681991Sheppo /*
33691991Sheppo  * Bring a channel up by initiating a handshake with the peer
33701991Sheppo  * This call is asynchronous. It will complete at a later point
33711991Sheppo  * in time when the peer responds back with an RTR.
33721991Sheppo  */
33731991Sheppo int
ldc_up(ldc_handle_t handle)33741991Sheppo ldc_up(ldc_handle_t handle)
33751991Sheppo {
33761991Sheppo 	int 		rv;
33771991Sheppo 	ldc_chan_t 	*ldcp;
33781991Sheppo 	ldc_msg_t 	*ldcmsg;
33793808Ssb155480 	uint64_t 	tx_tail, tstate, link_state;
33801991Sheppo 
33811991Sheppo 	if (handle == NULL) {
33821991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_up: invalid channel handle\n");
33831991Sheppo 		return (EINVAL);
33841991Sheppo 	}
33851991Sheppo 	ldcp = (ldc_chan_t *)handle;
33861991Sheppo 
33871991Sheppo 	mutex_enter(&ldcp->lock);
33881991Sheppo 
33892793Slm66018 	D1(ldcp->id, "ldc_up: (0x%llx) doing channel UP\n", ldcp->id);
33902793Slm66018 
33912793Slm66018 	/* clear the reset state */
33922793Slm66018 	tstate = ldcp->tstate;
33932793Slm66018 	ldcp->tstate &= ~TS_IN_RESET;
33942793Slm66018 
33951991Sheppo 	if (ldcp->tstate == TS_UP) {
33962793Slm66018 		DWARN(ldcp->id,
33971991Sheppo 		    "ldc_up: (0x%llx) channel is already in UP state\n",
33981991Sheppo 		    ldcp->id);
33992793Slm66018 
34002793Slm66018 		/* mark channel as up */
34012793Slm66018 		ldcp->status = LDC_UP;
34022793Slm66018 
34032793Slm66018 		/*
34042793Slm66018 		 * if channel was in reset state and there was
34052793Slm66018 		 * pending data clear interrupt state. this will
34062793Slm66018 		 * trigger an interrupt, causing the RX handler to
34072793Slm66018 		 * to invoke the client's callback
34082793Slm66018 		 */
34092793Slm66018 		if ((tstate & TS_IN_RESET) &&
34102793Slm66018 		    ldcp->rx_intr_state == LDC_INTR_PEND) {
34113010Slm66018 			D1(ldcp->id,
34122793Slm66018 			    "ldc_up: (0x%llx) channel has pending data, "
34132793Slm66018 			    "clearing interrupt\n", ldcp->id);
34142793Slm66018 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
34152793Slm66018 		}
34162793Slm66018 
34171991Sheppo 		mutex_exit(&ldcp->lock);
34181991Sheppo 		return (0);
34191991Sheppo 	}
34201991Sheppo 
34211991Sheppo 	/* if the channel is in RAW mode - mark it as UP, if READY */
34221991Sheppo 	if (ldcp->mode == LDC_MODE_RAW && ldcp->tstate >= TS_READY) {
34231991Sheppo 		ldcp->tstate = TS_UP;
34241991Sheppo 		mutex_exit(&ldcp->lock);
34251991Sheppo 		return (0);
34261991Sheppo 	}
34271991Sheppo 
34281991Sheppo 	/* Don't start another handshake if there is one in progress */
34291991Sheppo 	if (ldcp->hstate) {
34302793Slm66018 		D1(ldcp->id,
34311991Sheppo 		    "ldc_up: (0x%llx) channel handshake in progress\n",
34321991Sheppo 		    ldcp->id);
34331991Sheppo 		mutex_exit(&ldcp->lock);
34341991Sheppo 		return (0);
34351991Sheppo 	}
34361991Sheppo 
34372336Snarayan 	mutex_enter(&ldcp->tx_lock);
34382336Snarayan 
34393808Ssb155480 	/* save current link state */
34403808Ssb155480 	link_state = ldcp->link_state;
34413808Ssb155480 
34421991Sheppo 	/* get the current tail for the LDC msg */
34431991Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
34441991Sheppo 	if (rv) {
34453010Slm66018 		D1(ldcp->id, "ldc_up: (0x%llx) cannot initiate handshake\n",
34461991Sheppo 		    ldcp->id);
34472336Snarayan 		mutex_exit(&ldcp->tx_lock);
34481991Sheppo 		mutex_exit(&ldcp->lock);
34491991Sheppo 		return (ECONNREFUSED);
34501991Sheppo 	}
34511991Sheppo 
34523808Ssb155480 	/*
34533808Ssb155480 	 * If i_ldc_get_tx_tail() changed link_state to either RESET or UP,
34543808Ssb155480 	 * from a previous state of DOWN, then mark the channel as
34553808Ssb155480 	 * being ready for handshake.
34563808Ssb155480 	 */
34573808Ssb155480 	if ((link_state == LDC_CHANNEL_DOWN) &&
34583808Ssb155480 	    (link_state != ldcp->link_state)) {
34593808Ssb155480 
34603808Ssb155480 		ASSERT((ldcp->link_state == LDC_CHANNEL_RESET) ||
34613808Ssb155480 		    (ldcp->link_state == LDC_CHANNEL_UP));
34623808Ssb155480 
34633808Ssb155480 		if (ldcp->mode == LDC_MODE_RAW) {
34643808Ssb155480 			ldcp->status = LDC_UP;
34653808Ssb155480 			ldcp->tstate = TS_UP;
34663808Ssb155480 			mutex_exit(&ldcp->tx_lock);
34673808Ssb155480 			mutex_exit(&ldcp->lock);
34683808Ssb155480 			return (0);
34693808Ssb155480 		} else {
34703808Ssb155480 			ldcp->status = LDC_READY;
34713808Ssb155480 			ldcp->tstate |= TS_LINK_READY;
34723808Ssb155480 		}
34733808Ssb155480 
34743808Ssb155480 	}
34753808Ssb155480 
34761991Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
34771991Sheppo 	ZERO_PKT(ldcmsg);
34781991Sheppo 
34791991Sheppo 	ldcmsg->type = LDC_CTRL;
34801991Sheppo 	ldcmsg->stype = LDC_INFO;
34811991Sheppo 	ldcmsg->ctrl = LDC_VER;
34821991Sheppo 	ldcp->next_vidx = 0;
34831991Sheppo 	bcopy(&ldc_versions[0], ldcmsg->udata, sizeof (ldc_versions[0]));
34841991Sheppo 
34851991Sheppo 	DUMP_LDC_PKT(ldcp, "ldc_up snd ver", (uint64_t)ldcmsg);
34861991Sheppo 
34871991Sheppo 	/* initiate the send by calling into HV and set the new tail */
34881991Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
34894690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
34901991Sheppo 
34911991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
34921991Sheppo 	if (rv) {
34931991Sheppo 		DWARN(ldcp->id,
34941991Sheppo 		    "ldc_up: (0x%llx) cannot initiate handshake rv=%d\n",
34951991Sheppo 		    ldcp->id, rv);
34962336Snarayan 		mutex_exit(&ldcp->tx_lock);
34971991Sheppo 		mutex_exit(&ldcp->lock);
34981991Sheppo 		return (rv);
34991991Sheppo 	}
35001991Sheppo 
35012032Slm66018 	ldcp->hstate |= TS_SENT_VER;
35021991Sheppo 	ldcp->tx_tail = tx_tail;
35031991Sheppo 	D1(ldcp->id, "ldc_up: (0x%llx) channel up initiated\n", ldcp->id);
35041991Sheppo 
35052336Snarayan 	mutex_exit(&ldcp->tx_lock);
35061991Sheppo 	mutex_exit(&ldcp->lock);
35071991Sheppo 
35081991Sheppo 	return (rv);
35091991Sheppo }
35101991Sheppo 
35111991Sheppo 
35121991Sheppo /*
35132410Slm66018  * Bring a channel down by resetting its state and queues
35141991Sheppo  */
35151991Sheppo int
ldc_down(ldc_handle_t handle)35162410Slm66018 ldc_down(ldc_handle_t handle)
35171991Sheppo {
35181991Sheppo 	ldc_chan_t 	*ldcp;
35191991Sheppo 
35201991Sheppo 	if (handle == NULL) {
35212410Slm66018 		DWARN(DBG_ALL_LDCS, "ldc_down: invalid channel handle\n");
35221991Sheppo 		return (EINVAL);
35231991Sheppo 	}
35241991Sheppo 	ldcp = (ldc_chan_t *)handle;
35251991Sheppo 	mutex_enter(&ldcp->lock);
35262336Snarayan 	mutex_enter(&ldcp->tx_lock);
35272793Slm66018 	i_ldc_reset(ldcp, B_TRUE);
35282336Snarayan 	mutex_exit(&ldcp->tx_lock);
35291991Sheppo 	mutex_exit(&ldcp->lock);
35301991Sheppo 
35311991Sheppo 	return (0);
35321991Sheppo }
35331991Sheppo 
35341991Sheppo /*
35351991Sheppo  * Get the current channel status
35361991Sheppo  */
35371991Sheppo int
ldc_status(ldc_handle_t handle,ldc_status_t * status)35381991Sheppo ldc_status(ldc_handle_t handle, ldc_status_t *status)
35391991Sheppo {
35401991Sheppo 	ldc_chan_t *ldcp;
35411991Sheppo 
35421991Sheppo 	if (handle == NULL || status == NULL) {
35431991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_status: invalid argument\n");
35441991Sheppo 		return (EINVAL);
35451991Sheppo 	}
35461991Sheppo 	ldcp = (ldc_chan_t *)handle;
35471991Sheppo 
35481991Sheppo 	*status = ((ldc_chan_t *)handle)->status;
35491991Sheppo 
35503010Slm66018 	D1(ldcp->id,
35511991Sheppo 	    "ldc_status: (0x%llx) returned status %d\n", ldcp->id, *status);
35521991Sheppo 	return (0);
35531991Sheppo }
35541991Sheppo 
35551991Sheppo 
35561991Sheppo /*
35571991Sheppo  * Set the channel's callback mode - enable/disable callbacks
35581991Sheppo  */
35591991Sheppo int
ldc_set_cb_mode(ldc_handle_t handle,ldc_cb_mode_t cmode)35601991Sheppo ldc_set_cb_mode(ldc_handle_t handle, ldc_cb_mode_t cmode)
35611991Sheppo {
35621991Sheppo 	ldc_chan_t 	*ldcp;
35631991Sheppo 
35641991Sheppo 	if (handle == NULL) {
35651991Sheppo 		DWARN(DBG_ALL_LDCS,
35661991Sheppo 		    "ldc_set_intr_mode: invalid channel handle\n");
35671991Sheppo 		return (EINVAL);
35681991Sheppo 	}
35691991Sheppo 	ldcp = (ldc_chan_t *)handle;
35701991Sheppo 
35711991Sheppo 	/*
35721991Sheppo 	 * Record no callbacks should be invoked
35731991Sheppo 	 */
35741991Sheppo 	mutex_enter(&ldcp->lock);
35751991Sheppo 
35761991Sheppo 	switch (cmode) {
35771991Sheppo 	case LDC_CB_DISABLE:
35781991Sheppo 		if (!ldcp->cb_enabled) {
35791991Sheppo 			DWARN(ldcp->id,
35801991Sheppo 			    "ldc_set_cb_mode: (0x%llx) callbacks disabled\n",
35811991Sheppo 			    ldcp->id);
35821991Sheppo 			break;
35831991Sheppo 		}
35841991Sheppo 		ldcp->cb_enabled = B_FALSE;
35851991Sheppo 
35861991Sheppo 		D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) disabled callbacks\n",
35871991Sheppo 		    ldcp->id);
35881991Sheppo 		break;
35891991Sheppo 
35901991Sheppo 	case LDC_CB_ENABLE:
35911991Sheppo 		if (ldcp->cb_enabled) {
35921991Sheppo 			DWARN(ldcp->id,
35931991Sheppo 			    "ldc_set_cb_mode: (0x%llx) callbacks enabled\n",
35941991Sheppo 			    ldcp->id);
35951991Sheppo 			break;
35961991Sheppo 		}
35971991Sheppo 		ldcp->cb_enabled = B_TRUE;
35981991Sheppo 
35991991Sheppo 		D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) enabled callbacks\n",
36001991Sheppo 		    ldcp->id);
36011991Sheppo 		break;
36021991Sheppo 	}
36031991Sheppo 
36041991Sheppo 	mutex_exit(&ldcp->lock);
36051991Sheppo 
36061991Sheppo 	return (0);
36071991Sheppo }
36081991Sheppo 
36091991Sheppo /*
36101991Sheppo  * Check to see if there are packets on the incoming queue
36112410Slm66018  * Will return hasdata = B_FALSE if there are no packets
36121991Sheppo  */
36131991Sheppo int
ldc_chkq(ldc_handle_t handle,boolean_t * hasdata)36142410Slm66018 ldc_chkq(ldc_handle_t handle, boolean_t *hasdata)
36151991Sheppo {
36161991Sheppo 	int 		rv;
36171991Sheppo 	uint64_t 	rx_head, rx_tail;
36181991Sheppo 	ldc_chan_t 	*ldcp;
36191991Sheppo 
36201991Sheppo 	if (handle == NULL) {
36211991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_chkq: invalid channel handle\n");
36221991Sheppo 		return (EINVAL);
36231991Sheppo 	}
36241991Sheppo 	ldcp = (ldc_chan_t *)handle;
36251991Sheppo 
36262410Slm66018 	*hasdata = B_FALSE;
36271991Sheppo 
36281991Sheppo 	mutex_enter(&ldcp->lock);
36291991Sheppo 
36301991Sheppo 	if (ldcp->tstate != TS_UP) {
36311991Sheppo 		D1(ldcp->id,
36321991Sheppo 		    "ldc_chkq: (0x%llx) channel is not up\n", ldcp->id);
36331991Sheppo 		mutex_exit(&ldcp->lock);
36341991Sheppo 		return (ECONNRESET);
36351991Sheppo 	}
36361991Sheppo 
36371991Sheppo 	/* Read packet(s) from the queue */
36381991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
36391991Sheppo 	    &ldcp->link_state);
36401991Sheppo 	if (rv != 0) {
36411991Sheppo 		cmn_err(CE_WARN,
36421991Sheppo 		    "ldc_chkq: (0x%lx) unable to read queue ptrs", ldcp->id);
36431991Sheppo 		mutex_exit(&ldcp->lock);
36441991Sheppo 		return (EIO);
36451991Sheppo 	}
36465944Sha137994 
36471991Sheppo 	/* reset the channel state if the channel went down */
36481991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
36491991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
36502336Snarayan 		mutex_enter(&ldcp->tx_lock);
36512793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
36522336Snarayan 		mutex_exit(&ldcp->tx_lock);
36531991Sheppo 		mutex_exit(&ldcp->lock);
36541991Sheppo 		return (ECONNRESET);
36551991Sheppo 	}
36561991Sheppo 
36575944Sha137994 	switch (ldcp->mode) {
36585944Sha137994 	case LDC_MODE_RAW:
36595944Sha137994 		/*
36605944Sha137994 		 * In raw mode, there are no ctrl packets, so checking
36615944Sha137994 		 * if the queue is non-empty is sufficient.
36625944Sha137994 		 */
36635944Sha137994 		*hasdata = (rx_head != rx_tail);
36645944Sha137994 		break;
36655944Sha137994 
36665944Sha137994 	case LDC_MODE_UNRELIABLE:
36675944Sha137994 		/*
36685944Sha137994 		 * In unreliable mode, if the queue is non-empty, we need
36695944Sha137994 		 * to check if it actually contains unread data packets.
36705944Sha137994 		 * The queue may just contain ctrl packets.
36715944Sha137994 		 */
36726446Sha137994 		if (rx_head != rx_tail) {
36735944Sha137994 			*hasdata = (i_ldc_chkq(ldcp) == 0);
36746446Sha137994 			/*
36756446Sha137994 			 * If no data packets were found on the queue,
36766446Sha137994 			 * all packets must have been control packets
36776446Sha137994 			 * which will now have been processed, leaving
36786446Sha137994 			 * the queue empty. If the interrupt state
36796446Sha137994 			 * is pending, we need to clear the interrupt
36806446Sha137994 			 * here.
36816446Sha137994 			 */
36826446Sha137994 			if (*hasdata == B_FALSE &&
36836446Sha137994 			    ldcp->rx_intr_state == LDC_INTR_PEND) {
36846446Sha137994 				i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
36856446Sha137994 			}
36866446Sha137994 		}
36875944Sha137994 		break;
36885944Sha137994 
36896408Sha137994 	case LDC_MODE_RELIABLE:
36905944Sha137994 		/*
36916408Sha137994 		 * In reliable mode, first check for 'stream_remains' > 0.
36925944Sha137994 		 * Otherwise, if the data queue head and tail pointers
36935944Sha137994 		 * differ, there must be data to read.
36945944Sha137994 		 */
36955944Sha137994 		if (ldcp->stream_remains > 0)
36965944Sha137994 			*hasdata = B_TRUE;
36975944Sha137994 		else
36985944Sha137994 			*hasdata = (ldcp->rx_dq_head != ldcp->rx_dq_tail);
36995944Sha137994 		break;
37005944Sha137994 
37015944Sha137994 	default:
37025944Sha137994 		cmn_err(CE_WARN, "ldc_chkq: (0x%lx) unexpected channel mode "
37035944Sha137994 		    "(0x%x)", ldcp->id, ldcp->mode);
37045944Sha137994 		mutex_exit(&ldcp->lock);
37055944Sha137994 		return (EIO);
37061991Sheppo 	}
37071991Sheppo 
37081991Sheppo 	mutex_exit(&ldcp->lock);
37091991Sheppo 
37101991Sheppo 	return (0);
37111991Sheppo }
37121991Sheppo 
37131991Sheppo 
37141991Sheppo /*
37151991Sheppo  * Read 'size' amount of bytes or less. If incoming buffer
37161991Sheppo  * is more than 'size', ENOBUFS is returned.
37171991Sheppo  *
37181991Sheppo  * On return, size contains the number of bytes read.
37191991Sheppo  */
37201991Sheppo int
ldc_read(ldc_handle_t handle,caddr_t bufp,size_t * sizep)37211991Sheppo ldc_read(ldc_handle_t handle, caddr_t bufp, size_t *sizep)
37221991Sheppo {
37231991Sheppo 	ldc_chan_t 	*ldcp;
37241991Sheppo 	uint64_t 	rx_head = 0, rx_tail = 0;
37251991Sheppo 	int		rv = 0, exit_val;
37261991Sheppo 
37271991Sheppo 	if (handle == NULL) {
37281991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_read: invalid channel handle\n");
37291991Sheppo 		return (EINVAL);
37301991Sheppo 	}
37311991Sheppo 
37321991Sheppo 	ldcp = (ldc_chan_t *)handle;
37331991Sheppo 
37341991Sheppo 	/* channel lock */
37351991Sheppo 	mutex_enter(&ldcp->lock);
37361991Sheppo 
37371991Sheppo 	if (ldcp->tstate != TS_UP) {
37381991Sheppo 		DWARN(ldcp->id,
37391991Sheppo 		    "ldc_read: (0x%llx) channel is not in UP state\n",
37401991Sheppo 		    ldcp->id);
37411991Sheppo 		exit_val = ECONNRESET;
37426408Sha137994 	} else if (ldcp->mode == LDC_MODE_RELIABLE) {
37435944Sha137994 		TRACE_RXDQ_LENGTH(ldcp);
37445944Sha137994 		exit_val = ldcp->read_p(ldcp, bufp, sizep);
37456944Sha137994 
37466944Sha137994 		/*
37476944Sha137994 		 * For reliable mode channels, the interrupt
37486944Sha137994 		 * state is only set to pending during
37496944Sha137994 		 * interrupt handling when the secondary data
37506944Sha137994 		 * queue became full, leaving unprocessed
37516944Sha137994 		 * packets on the Rx queue. If the interrupt
37526944Sha137994 		 * state is pending and space is now available
37536944Sha137994 		 * on the data queue, clear the interrupt.
37546944Sha137994 		 */
37556944Sha137994 		if (ldcp->rx_intr_state == LDC_INTR_PEND &&
37566944Sha137994 		    Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail,
37576944Sha137994 		    ldcp->rx_dq_entries << LDC_PACKET_SHIFT) >=
37586944Sha137994 		    LDC_PACKET_SIZE) {
37596944Sha137994 			/* data queue is not full */
37606944Sha137994 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
37616944Sha137994 		}
37626944Sha137994 
37635944Sha137994 		mutex_exit(&ldcp->lock);
37645944Sha137994 		return (exit_val);
37651991Sheppo 	} else {
37661991Sheppo 		exit_val = ldcp->read_p(ldcp, bufp, sizep);
37671991Sheppo 	}
37681991Sheppo 
37691991Sheppo 	/*
37701991Sheppo 	 * if queue has been drained - clear interrupt
37711991Sheppo 	 */
37721991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
37731991Sheppo 	    &ldcp->link_state);
37743010Slm66018 	if (rv != 0) {
37753010Slm66018 		cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
37763010Slm66018 		    ldcp->id);
37773010Slm66018 		mutex_enter(&ldcp->tx_lock);
37783010Slm66018 		i_ldc_reset(ldcp, B_TRUE);
37793010Slm66018 		mutex_exit(&ldcp->tx_lock);
37803653Snarayan 		mutex_exit(&ldcp->lock);
37813010Slm66018 		return (ECONNRESET);
37823010Slm66018 	}
37832793Slm66018 
37842793Slm66018 	if (exit_val == 0) {
37852793Slm66018 		if (ldcp->link_state == LDC_CHANNEL_DOWN ||
37862793Slm66018 		    ldcp->link_state == LDC_CHANNEL_RESET) {
37872793Slm66018 			mutex_enter(&ldcp->tx_lock);
37882793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
37892793Slm66018 			exit_val = ECONNRESET;
37902793Slm66018 			mutex_exit(&ldcp->tx_lock);
37912793Slm66018 		}
37922793Slm66018 		if ((rv == 0) &&
37932793Slm66018 		    (ldcp->rx_intr_state == LDC_INTR_PEND) &&
37942793Slm66018 		    (rx_head == rx_tail)) {
37952793Slm66018 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
37962793Slm66018 		}
37971991Sheppo 	}
37981991Sheppo 
37991991Sheppo 	mutex_exit(&ldcp->lock);
38001991Sheppo 	return (exit_val);
38011991Sheppo }
38021991Sheppo 
38031991Sheppo /*
38041991Sheppo  * Basic raw mondo read -
38051991Sheppo  * no interpretation of mondo contents at all.
38061991Sheppo  *
38071991Sheppo  * Enter and exit with ldcp->lock held by caller
38081991Sheppo  */
38091991Sheppo static int
i_ldc_read_raw(ldc_chan_t * ldcp,caddr_t target_bufp,size_t * sizep)38101991Sheppo i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
38111991Sheppo {
38121991Sheppo 	uint64_t 	q_size_mask;
38131991Sheppo 	ldc_msg_t 	*msgp;
38141991Sheppo 	uint8_t		*msgbufp;
38151991Sheppo 	int		rv = 0, space;
38161991Sheppo 	uint64_t 	rx_head, rx_tail;
38171991Sheppo 
38181991Sheppo 	space = *sizep;
38191991Sheppo 
38201991Sheppo 	if (space < LDC_PAYLOAD_SIZE_RAW)
38211991Sheppo 		return (ENOBUFS);
38221991Sheppo 
38231991Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
38241991Sheppo 
38251991Sheppo 	/* compute mask for increment */
38261991Sheppo 	q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
38271991Sheppo 
38281991Sheppo 	/*
38291991Sheppo 	 * Read packet(s) from the queue
38301991Sheppo 	 */
38311991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
38321991Sheppo 	    &ldcp->link_state);
38331991Sheppo 	if (rv != 0) {
38341991Sheppo 		cmn_err(CE_WARN,
38351991Sheppo 		    "ldc_read_raw: (0x%lx) unable to read queue ptrs",
38361991Sheppo 		    ldcp->id);
38371991Sheppo 		return (EIO);
38381991Sheppo 	}
38391991Sheppo 	D1(ldcp->id, "ldc_read_raw: (0x%llx) rxh=0x%llx,"
38404690Snarayan 	    " rxt=0x%llx, st=0x%llx\n",
38414690Snarayan 	    ldcp->id, rx_head, rx_tail, ldcp->link_state);
38421991Sheppo 
38431991Sheppo 	/* reset the channel state if the channel went down */
38442793Slm66018 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
38452793Slm66018 	    ldcp->link_state == LDC_CHANNEL_RESET) {
38462336Snarayan 		mutex_enter(&ldcp->tx_lock);
38472793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
38482336Snarayan 		mutex_exit(&ldcp->tx_lock);
38491991Sheppo 		return (ECONNRESET);
38501991Sheppo 	}
38511991Sheppo 
38521991Sheppo 	/*
38531991Sheppo 	 * Check for empty queue
38541991Sheppo 	 */
38551991Sheppo 	if (rx_head == rx_tail) {
38561991Sheppo 		*sizep = 0;
38571991Sheppo 		return (0);
38581991Sheppo 	}
38591991Sheppo 
38601991Sheppo 	/* get the message */
38611991Sheppo 	msgp = (ldc_msg_t *)(ldcp->rx_q_va + rx_head);
38621991Sheppo 
38631991Sheppo 	/* if channel is in RAW mode, copy data and return */
38641991Sheppo 	msgbufp = (uint8_t *)&(msgp->raw[0]);
38651991Sheppo 
38661991Sheppo 	bcopy(msgbufp, target_bufp, LDC_PAYLOAD_SIZE_RAW);
38671991Sheppo 
38681991Sheppo 	DUMP_PAYLOAD(ldcp->id, msgbufp);
38691991Sheppo 
38701991Sheppo 	*sizep = LDC_PAYLOAD_SIZE_RAW;
38711991Sheppo 
38721991Sheppo 	rx_head = (rx_head + LDC_PACKET_SIZE) & q_size_mask;
38732032Slm66018 	rv = i_ldc_set_rx_head(ldcp, rx_head);
38741991Sheppo 
38751991Sheppo 	return (rv);
38761991Sheppo }
38771991Sheppo 
38781991Sheppo /*
38791991Sheppo  * Process LDC mondos to build larger packets
38801991Sheppo  * with either un-reliable or reliable delivery.
38811991Sheppo  *
38821991Sheppo  * Enter and exit with ldcp->lock held by caller
38831991Sheppo  */
38841991Sheppo static int
i_ldc_read_packet(ldc_chan_t * ldcp,caddr_t target_bufp,size_t * sizep)38851991Sheppo i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
38861991Sheppo {
38871991Sheppo 	int		rv = 0;
38881991Sheppo 	uint64_t 	rx_head = 0, rx_tail = 0;
38891991Sheppo 	uint64_t 	curr_head = 0;
38901991Sheppo 	ldc_msg_t 	*msg;
38911991Sheppo 	caddr_t 	target;
38921991Sheppo 	size_t 		len = 0, bytes_read = 0;
38932032Slm66018 	int 		retries = 0;
38945944Sha137994 	uint64_t 	q_va, q_size_mask;
38952336Snarayan 	uint64_t	first_fragment = 0;
38961991Sheppo 
38971991Sheppo 	target = target_bufp;
38981991Sheppo 
38991991Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
39001991Sheppo 
39012793Slm66018 	/* check if the buffer and size are valid */
39022793Slm66018 	if (target_bufp == NULL || *sizep == 0) {
39032793Slm66018 		DWARN(ldcp->id, "ldc_read: (0x%llx) invalid buffer/size\n",
39042793Slm66018 		    ldcp->id);
39052793Slm66018 		return (EINVAL);
39062793Slm66018 	}
39072793Slm66018 
39085944Sha137994 	/* Set q_va and compute increment mask for the appropriate queue */
39096408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
39105944Sha137994 		q_va	    = ldcp->rx_dq_va;
39115944Sha137994 		q_size_mask = (ldcp->rx_dq_entries-1)<<LDC_PACKET_SHIFT;
39125944Sha137994 	} else {
39135944Sha137994 		q_va	    = ldcp->rx_q_va;
39145944Sha137994 		q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
39155944Sha137994 	}
39161991Sheppo 
39171991Sheppo 	/*
39181991Sheppo 	 * Read packet(s) from the queue
39191991Sheppo 	 */
39205944Sha137994 	rv = ldcp->readq_get_state(ldcp, &curr_head, &rx_tail,
39211991Sheppo 	    &ldcp->link_state);
39221991Sheppo 	if (rv != 0) {
39232793Slm66018 		cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
39241991Sheppo 		    ldcp->id);
39252793Slm66018 		mutex_enter(&ldcp->tx_lock);
39262793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
39272793Slm66018 		mutex_exit(&ldcp->tx_lock);
39282793Slm66018 		return (ECONNRESET);
39291991Sheppo 	}
39301991Sheppo 	D1(ldcp->id, "ldc_read: (0x%llx) chd=0x%llx, tl=0x%llx, st=0x%llx\n",
39311991Sheppo 	    ldcp->id, curr_head, rx_tail, ldcp->link_state);
39321991Sheppo 
39331991Sheppo 	/* reset the channel state if the channel went down */
39342793Slm66018 	if (ldcp->link_state != LDC_CHANNEL_UP)
39352793Slm66018 		goto channel_is_reset;
39361991Sheppo 
39371991Sheppo 	for (;;) {
39381991Sheppo 
39391991Sheppo 		if (curr_head == rx_tail) {
39405944Sha137994 			/*
39415944Sha137994 			 * If a data queue is being used, check the Rx HV
39425944Sha137994 			 * queue. This will copy over any new data packets
39435944Sha137994 			 * that have arrived.
39445944Sha137994 			 */
39456408Sha137994 			if (ldcp->mode == LDC_MODE_RELIABLE)
39465944Sha137994 				(void) i_ldc_chkq(ldcp);
39475944Sha137994 
39485944Sha137994 			rv = ldcp->readq_get_state(ldcp,
39491991Sheppo 			    &rx_head, &rx_tail, &ldcp->link_state);
39501991Sheppo 			if (rv != 0) {
39511991Sheppo 				cmn_err(CE_WARN,
39521991Sheppo 				    "ldc_read: (0x%lx) cannot read queue ptrs",
39531991Sheppo 				    ldcp->id);
39542336Snarayan 				mutex_enter(&ldcp->tx_lock);
39552793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
39562336Snarayan 				mutex_exit(&ldcp->tx_lock);
39571991Sheppo 				return (ECONNRESET);
39581991Sheppo 			}
39595944Sha137994 
39602793Slm66018 			if (ldcp->link_state != LDC_CHANNEL_UP)
39612793Slm66018 				goto channel_is_reset;
39622793Slm66018 
39632793Slm66018 			if (curr_head == rx_tail) {
39642793Slm66018 
39652793Slm66018 				/* If in the middle of a fragmented xfer */
39662793Slm66018 				if (first_fragment != 0) {
39672793Slm66018 
39682793Slm66018 					/* wait for ldc_delay usecs */
39692793Slm66018 					drv_usecwait(ldc_delay);
39702793Slm66018 
39712793Slm66018 					if (++retries < ldc_max_retries)
39722793Slm66018 						continue;
39732793Slm66018 
39742793Slm66018 					*sizep = 0;
39756408Sha137994 					if (ldcp->mode != LDC_MODE_RELIABLE)
39765944Sha137994 						ldcp->last_msg_rcd =
39775944Sha137994 						    first_fragment - 1;
39782793Slm66018 					DWARN(DBG_ALL_LDCS, "ldc_read: "
39794690Snarayan 					    "(0x%llx) read timeout", ldcp->id);
39802793Slm66018 					return (EAGAIN);
39812793Slm66018 				}
39822032Slm66018 				*sizep = 0;
39832793Slm66018 				break;
39841991Sheppo 			}
39851991Sheppo 		}
39862032Slm66018 		retries = 0;
39871991Sheppo 
39881991Sheppo 		D2(ldcp->id,
39891991Sheppo 		    "ldc_read: (0x%llx) chd=0x%llx, rxhd=0x%llx, rxtl=0x%llx\n",
39901991Sheppo 		    ldcp->id, curr_head, rx_head, rx_tail);
39911991Sheppo 
39921991Sheppo 		/* get the message */
39935944Sha137994 		msg = (ldc_msg_t *)(q_va + curr_head);
39941991Sheppo 
39951991Sheppo 		DUMP_LDC_PKT(ldcp, "ldc_read received pkt",
39961991Sheppo 		    ldcp->rx_q_va + curr_head);
39971991Sheppo 
39981991Sheppo 		/* Check the message ID for the message received */
39996408Sha137994 		if (ldcp->mode != LDC_MODE_RELIABLE) {
40005944Sha137994 			if ((rv = i_ldc_check_seqid(ldcp, msg)) != 0) {
40015944Sha137994 
40025944Sha137994 				DWARN(ldcp->id, "ldc_read: (0x%llx) seqid "
40035944Sha137994 				    "error, q_ptrs=0x%lx,0x%lx",
40045944Sha137994 				    ldcp->id, rx_head, rx_tail);
40055944Sha137994 
40065944Sha137994 				/* throw away data */
40075944Sha137994 				bytes_read = 0;
40085944Sha137994 
40095944Sha137994 				/* Reset last_msg_rcd to start of message */
40105944Sha137994 				if (first_fragment != 0) {
40115944Sha137994 					ldcp->last_msg_rcd = first_fragment - 1;
40125944Sha137994 					first_fragment = 0;
40135944Sha137994 				}
40145944Sha137994 				/*
40155944Sha137994 				 * Send a NACK -- invalid seqid
40165944Sha137994 				 * get the current tail for the response
40175944Sha137994 				 */
40185944Sha137994 				rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK,
40195944Sha137994 				    (msg->ctrl & LDC_CTRL_MASK));
40205944Sha137994 				if (rv) {
40215944Sha137994 					cmn_err(CE_NOTE,
40225944Sha137994 					    "ldc_read: (0x%lx) err sending "
40235944Sha137994 					    "NACK msg\n", ldcp->id);
40245944Sha137994 
40255944Sha137994 					/* if cannot send NACK - reset chan */
40265944Sha137994 					mutex_enter(&ldcp->tx_lock);
40275944Sha137994 					i_ldc_reset(ldcp, B_FALSE);
40285944Sha137994 					mutex_exit(&ldcp->tx_lock);
40295944Sha137994 					rv = ECONNRESET;
40305944Sha137994 					break;
40315944Sha137994 				}
40325944Sha137994 
40335944Sha137994 				/* purge receive queue */
40345944Sha137994 				rv = i_ldc_set_rx_head(ldcp, rx_tail);
40355944Sha137994 
40362336Snarayan 				break;
40371991Sheppo 			}
40381991Sheppo 
40395944Sha137994 			/*
40405944Sha137994 			 * Process any messages of type CTRL messages
40415944Sha137994 			 * Future implementations should try to pass these
40425944Sha137994 			 * to LDC link by resetting the intr state.
40435944Sha137994 			 *
40445944Sha137994 			 * NOTE: not done as a switch() as type can be
40455944Sha137994 			 * both ctrl+data
40465944Sha137994 			 */
40475944Sha137994 			if (msg->type & LDC_CTRL) {
40485944Sha137994 				if (rv = i_ldc_ctrlmsg(ldcp, msg)) {
40495944Sha137994 					if (rv == EAGAIN)
40505944Sha137994 						continue;
40515944Sha137994 					rv = i_ldc_set_rx_head(ldcp, rx_tail);
40525944Sha137994 					*sizep = 0;
40535944Sha137994 					bytes_read = 0;
40545944Sha137994 					break;
40555944Sha137994 				}
40561991Sheppo 			}
40575944Sha137994 
40585944Sha137994 			/* process data ACKs */
40595944Sha137994 			if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
40605944Sha137994 				if (rv = i_ldc_process_data_ACK(ldcp, msg)) {
40615944Sha137994 					*sizep = 0;
40625944Sha137994 					bytes_read = 0;
40635944Sha137994 					break;
40645944Sha137994 				}
40652336Snarayan 			}
40665944Sha137994 
40675944Sha137994 			/* process data NACKs */
40685944Sha137994 			if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) {
40695944Sha137994 				DWARN(ldcp->id,
40705944Sha137994 				    "ldc_read: (0x%llx) received DATA/NACK",
40715944Sha137994 				    ldcp->id);
40725944Sha137994 				mutex_enter(&ldcp->tx_lock);
40735944Sha137994 				i_ldc_reset(ldcp, B_TRUE);
40745944Sha137994 				mutex_exit(&ldcp->tx_lock);
40755944Sha137994 				return (ECONNRESET);
40765944Sha137994 			}
40773560Snarayan 		}
40783560Snarayan 
40791991Sheppo 		/* process data messages */
40801991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
40811991Sheppo 
40821991Sheppo 			uint8_t *msgbuf = (uint8_t *)(
40836408Sha137994 			    (ldcp->mode == LDC_MODE_RELIABLE) ?
40844690Snarayan 			    msg->rdata : msg->udata);
40851991Sheppo 
40861991Sheppo 			D2(ldcp->id,
40871991Sheppo 			    "ldc_read: (0x%llx) received data msg\n", ldcp->id);
40881991Sheppo 
40891991Sheppo 			/* get the packet length */
40901991Sheppo 			len = (msg->env & LDC_LEN_MASK);
40911991Sheppo 
40921991Sheppo 				/*
40931991Sheppo 				 * FUTURE OPTIMIZATION:
40941991Sheppo 				 * dont need to set q head for every
40951991Sheppo 				 * packet we read just need to do this when
40961991Sheppo 				 * we are done or need to wait for more
40971991Sheppo 				 * mondos to make a full packet - this is
40981991Sheppo 				 * currently expensive.
40991991Sheppo 				 */
41001991Sheppo 
41012336Snarayan 			if (first_fragment == 0) {
41021991Sheppo 
41031991Sheppo 				/*
41041991Sheppo 				 * first packets should always have the start
41051991Sheppo 				 * bit set (even for a single packet). If not
41061991Sheppo 				 * throw away the packet
41071991Sheppo 				 */
41081991Sheppo 				if (!(msg->env & LDC_FRAG_START)) {
41091991Sheppo 
41101991Sheppo 					DWARN(DBG_ALL_LDCS,
41111991Sheppo 					    "ldc_read: (0x%llx) not start - "
41121991Sheppo 					    "frag=%x\n", ldcp->id,
41131991Sheppo 					    (msg->env) & LDC_FRAG_MASK);
41141991Sheppo 
41151991Sheppo 					/* toss pkt, inc head, cont reading */
41161991Sheppo 					bytes_read = 0;
41171991Sheppo 					target = target_bufp;
41181991Sheppo 					curr_head =
41194690Snarayan 					    (curr_head + LDC_PACKET_SIZE)
41204690Snarayan 					    & q_size_mask;
41215944Sha137994 					if (rv = ldcp->readq_set_head(ldcp,
41224690Snarayan 					    curr_head))
41231991Sheppo 						break;
41241991Sheppo 
41251991Sheppo 					continue;
41261991Sheppo 				}
41271991Sheppo 
41282336Snarayan 				first_fragment = msg->seqid;
41291991Sheppo 			} else {
41301991Sheppo 				/* check to see if this is a pkt w/ START bit */
41311991Sheppo 				if (msg->env & LDC_FRAG_START) {
41321991Sheppo 					DWARN(DBG_ALL_LDCS,
41331991Sheppo 					    "ldc_read:(0x%llx) unexpected pkt"
41341991Sheppo 					    " env=0x%x discarding %d bytes,"
41351991Sheppo 					    " lastmsg=%d, currentmsg=%d\n",
41361991Sheppo 					    ldcp->id, msg->env&LDC_FRAG_MASK,
41371991Sheppo 					    bytes_read, ldcp->last_msg_rcd,
41381991Sheppo 					    msg->seqid);
41391991Sheppo 
41401991Sheppo 					/* throw data we have read so far */
41411991Sheppo 					bytes_read = 0;
41421991Sheppo 					target = target_bufp;
41432336Snarayan 					first_fragment = msg->seqid;
41441991Sheppo 
41455944Sha137994 					if (rv = ldcp->readq_set_head(ldcp,
41464690Snarayan 					    curr_head))
41471991Sheppo 						break;
41481991Sheppo 				}
41491991Sheppo 			}
41501991Sheppo 
41511991Sheppo 			/* copy (next) pkt into buffer */
41521991Sheppo 			if (len <= (*sizep - bytes_read)) {
41531991Sheppo 				bcopy(msgbuf, target, len);
41541991Sheppo 				target += len;
41551991Sheppo 				bytes_read += len;
41561991Sheppo 			} else {
41571991Sheppo 				/*
41581991Sheppo 				 * there is not enough space in the buffer to
41591991Sheppo 				 * read this pkt. throw message away & continue
41601991Sheppo 				 * reading data from queue
41611991Sheppo 				 */
41621991Sheppo 				DWARN(DBG_ALL_LDCS,
41631991Sheppo 				    "ldc_read: (0x%llx) buffer too small, "
41641991Sheppo 				    "head=0x%lx, expect=%d, got=%d\n", ldcp->id,
41651991Sheppo 				    curr_head, *sizep, bytes_read+len);
41661991Sheppo 
41672336Snarayan 				first_fragment = 0;
41681991Sheppo 				target = target_bufp;
41691991Sheppo 				bytes_read = 0;
41701991Sheppo 
41711991Sheppo 				/* throw away everything received so far */
41725944Sha137994 				if (rv = ldcp->readq_set_head(ldcp, curr_head))
41731991Sheppo 					break;
41741991Sheppo 
41751991Sheppo 				/* continue reading remaining pkts */
41761991Sheppo 				continue;
41771991Sheppo 			}
41781991Sheppo 		}
41791991Sheppo 
41801991Sheppo 		/* set the message id */
41816408Sha137994 		if (ldcp->mode != LDC_MODE_RELIABLE)
41825944Sha137994 			ldcp->last_msg_rcd = msg->seqid;
41831991Sheppo 
41841991Sheppo 		/* move the head one position */
41851991Sheppo 		curr_head = (curr_head + LDC_PACKET_SIZE) & q_size_mask;
41861991Sheppo 
41871991Sheppo 		if (msg->env & LDC_FRAG_STOP) {
41881991Sheppo 
41891991Sheppo 			/*
41901991Sheppo 			 * All pkts that are part of this fragmented transfer
41911991Sheppo 			 * have been read or this was a single pkt read
41921991Sheppo 			 * or there was an error
41931991Sheppo 			 */
41941991Sheppo 
41951991Sheppo 			/* set the queue head */
41965944Sha137994 			if (rv = ldcp->readq_set_head(ldcp, curr_head))
41971991Sheppo 				bytes_read = 0;
41981991Sheppo 
41991991Sheppo 			*sizep = bytes_read;
42001991Sheppo 
42011991Sheppo 			break;
42021991Sheppo 		}
42031991Sheppo 
42044890Snarayan 		/* advance head if it is a CTRL packet or a DATA ACK packet */
42054890Snarayan 		if ((msg->type & LDC_CTRL) ||
42064890Snarayan 		    ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK))) {
42071991Sheppo 
42081991Sheppo 			/* set the queue head */
42095944Sha137994 			if (rv = ldcp->readq_set_head(ldcp, curr_head)) {
42101991Sheppo 				bytes_read = 0;
42111991Sheppo 				break;
42121991Sheppo 			}
42131991Sheppo 
42141991Sheppo 			D2(ldcp->id, "ldc_read: (0x%llx) set ACK qhead 0x%llx",
42151991Sheppo 			    ldcp->id, curr_head);
42161991Sheppo 		}
42171991Sheppo 
42181991Sheppo 	} /* for (;;) */
42191991Sheppo 
42201991Sheppo 	D2(ldcp->id, "ldc_read: (0x%llx) end size=%d", ldcp->id, *sizep);
42211991Sheppo 
42221991Sheppo 	return (rv);
42232793Slm66018 
42242793Slm66018 channel_is_reset:
42252793Slm66018 	mutex_enter(&ldcp->tx_lock);
42262793Slm66018 	i_ldc_reset(ldcp, B_FALSE);
42272793Slm66018 	mutex_exit(&ldcp->tx_lock);
42282793Slm66018 	return (ECONNRESET);
42291991Sheppo }
42301991Sheppo 
42311991Sheppo /*
42326408Sha137994  * Fetch and buffer incoming packets so we can hand them back as
42331991Sheppo  * a basic byte stream.
42341991Sheppo  *
42351991Sheppo  * Enter and exit with ldcp->lock held by caller
42361991Sheppo  */
42371991Sheppo static int
i_ldc_read_stream(ldc_chan_t * ldcp,caddr_t target_bufp,size_t * sizep)42381991Sheppo i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
42391991Sheppo {
42401991Sheppo 	int	rv;
42411991Sheppo 	size_t	size;
42421991Sheppo 
42431991Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
42441991Sheppo 
42451991Sheppo 	D2(ldcp->id, "i_ldc_read_stream: (0x%llx) buffer size=%d",
42464690Snarayan 	    ldcp->id, *sizep);
42471991Sheppo 
42481991Sheppo 	if (ldcp->stream_remains == 0) {
42491991Sheppo 		size = ldcp->mtu;
42501991Sheppo 		rv = i_ldc_read_packet(ldcp,
42514690Snarayan 		    (caddr_t)ldcp->stream_bufferp, &size);
42521991Sheppo 		D2(ldcp->id, "i_ldc_read_stream: read packet (0x%llx) size=%d",
42534690Snarayan 		    ldcp->id, size);
42541991Sheppo 
42551991Sheppo 		if (rv != 0)
42561991Sheppo 			return (rv);
42571991Sheppo 
42581991Sheppo 		ldcp->stream_remains = size;
42591991Sheppo 		ldcp->stream_offset = 0;
42601991Sheppo 	}
42611991Sheppo 
42621991Sheppo 	size = MIN(ldcp->stream_remains, *sizep);
42631991Sheppo 
42641991Sheppo 	bcopy(ldcp->stream_bufferp + ldcp->stream_offset, target_bufp, size);
42651991Sheppo 	ldcp->stream_offset += size;
42661991Sheppo 	ldcp->stream_remains -= size;
42671991Sheppo 
42681991Sheppo 	D2(ldcp->id, "i_ldc_read_stream: (0x%llx) fill from buffer size=%d",
42694690Snarayan 	    ldcp->id, size);
42701991Sheppo 
42711991Sheppo 	*sizep = size;
42721991Sheppo 	return (0);
42731991Sheppo }
42741991Sheppo 
42751991Sheppo /*
42761991Sheppo  * Write specified amount of bytes to the channel
42771991Sheppo  * in multiple pkts of pkt_payload size. Each
42781991Sheppo  * packet is tagged with an unique packet ID in
42792410Slm66018  * the case of a reliable link.
42801991Sheppo  *
42811991Sheppo  * On return, size contains the number of bytes written.
42821991Sheppo  */
42831991Sheppo int
ldc_write(ldc_handle_t handle,caddr_t buf,size_t * sizep)42841991Sheppo ldc_write(ldc_handle_t handle, caddr_t buf, size_t *sizep)
42851991Sheppo {
42861991Sheppo 	ldc_chan_t	*ldcp;
42871991Sheppo 	int		rv = 0;
42881991Sheppo 
42891991Sheppo 	if (handle == NULL) {
42901991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_write: invalid channel handle\n");
42911991Sheppo 		return (EINVAL);
42921991Sheppo 	}
42931991Sheppo 	ldcp = (ldc_chan_t *)handle;
42941991Sheppo 
429512011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->tx_lock);
42961991Sheppo 
42971991Sheppo 	/* check if non-zero data to write */
42981991Sheppo 	if (buf == NULL || sizep == NULL) {
42991991Sheppo 		DWARN(ldcp->id, "ldc_write: (0x%llx) invalid data write\n",
43001991Sheppo 		    ldcp->id);
43012336Snarayan 		mutex_exit(&ldcp->tx_lock);
43021991Sheppo 		return (EINVAL);
43031991Sheppo 	}
43041991Sheppo 
43051991Sheppo 	if (*sizep == 0) {
43061991Sheppo 		DWARN(ldcp->id, "ldc_write: (0x%llx) write size of zero\n",
43071991Sheppo 		    ldcp->id);
43082336Snarayan 		mutex_exit(&ldcp->tx_lock);
43091991Sheppo 		return (0);
43101991Sheppo 	}
43111991Sheppo 
43121991Sheppo 	/* Check if channel is UP for data exchange */
43131991Sheppo 	if (ldcp->tstate != TS_UP) {
43141991Sheppo 		DWARN(ldcp->id,
43151991Sheppo 		    "ldc_write: (0x%llx) channel is not in UP state\n",
43161991Sheppo 		    ldcp->id);
43171991Sheppo 		*sizep = 0;
43181991Sheppo 		rv = ECONNRESET;
43191991Sheppo 	} else {
43201991Sheppo 		rv = ldcp->write_p(ldcp, buf, sizep);
43211991Sheppo 	}
43221991Sheppo 
43232336Snarayan 	mutex_exit(&ldcp->tx_lock);
43241991Sheppo 
43251991Sheppo 	return (rv);
43261991Sheppo }
43271991Sheppo 
43281991Sheppo /*
43291991Sheppo  * Write a raw packet to the channel
43301991Sheppo  * On return, size contains the number of bytes written.
43311991Sheppo  */
43321991Sheppo static int
i_ldc_write_raw(ldc_chan_t * ldcp,caddr_t buf,size_t * sizep)43331991Sheppo i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
43341991Sheppo {
43351991Sheppo 	ldc_msg_t 	*ldcmsg;
43361991Sheppo 	uint64_t 	tx_head, tx_tail, new_tail;
43371991Sheppo 	int		rv = 0;
43381991Sheppo 	size_t		size;
43391991Sheppo 
43402336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
43411991Sheppo 	ASSERT(ldcp->mode == LDC_MODE_RAW);
43421991Sheppo 
43431991Sheppo 	size = *sizep;
43441991Sheppo 
43451991Sheppo 	/*
43461991Sheppo 	 * Check to see if the packet size is less than or
43471991Sheppo 	 * equal to packet size support in raw mode
43481991Sheppo 	 */
43491991Sheppo 	if (size > ldcp->pkt_payload) {
43501991Sheppo 		DWARN(ldcp->id,
43511991Sheppo 		    "ldc_write: (0x%llx) invalid size (0x%llx) for RAW mode\n",
43521991Sheppo 		    ldcp->id, *sizep);
43531991Sheppo 		*sizep = 0;
43541991Sheppo 		return (EMSGSIZE);
43551991Sheppo 	}
43561991Sheppo 
43571991Sheppo 	/* get the qptrs for the tx queue */
43581991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
43591991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
43601991Sheppo 	if (rv != 0) {
43611991Sheppo 		cmn_err(CE_WARN,
43621991Sheppo 		    "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
43631991Sheppo 		*sizep = 0;
43641991Sheppo 		return (EIO);
43651991Sheppo 	}
43661991Sheppo 
43671991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
43681991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
43691991Sheppo 		DWARN(ldcp->id,
43701991Sheppo 		    "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
43712336Snarayan 
43721991Sheppo 		*sizep = 0;
43732336Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
43742793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
43752336Snarayan 			mutex_exit(&ldcp->lock);
43762336Snarayan 		} else {
43772336Snarayan 			/*
43782336Snarayan 			 * Release Tx lock, and then reacquire channel
43792336Snarayan 			 * and Tx lock in correct order
43802336Snarayan 			 */
43812336Snarayan 			mutex_exit(&ldcp->tx_lock);
43822336Snarayan 			mutex_enter(&ldcp->lock);
43832336Snarayan 			mutex_enter(&ldcp->tx_lock);
43842793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
43852336Snarayan 			mutex_exit(&ldcp->lock);
43862336Snarayan 		}
43871991Sheppo 		return (ECONNRESET);
43881991Sheppo 	}
43891991Sheppo 
43901991Sheppo 	tx_tail = ldcp->tx_tail;
43911991Sheppo 	tx_head = ldcp->tx_head;
43921991Sheppo 	new_tail = (tx_tail + LDC_PACKET_SIZE) &
43934690Snarayan 	    ((ldcp->tx_q_entries-1) << LDC_PACKET_SHIFT);
43941991Sheppo 
43951991Sheppo 	if (new_tail == tx_head) {
43961991Sheppo 		DWARN(DBG_ALL_LDCS,
43971991Sheppo 		    "ldc_write: (0x%llx) TX queue is full\n", ldcp->id);
43981991Sheppo 		*sizep = 0;
43991991Sheppo 		return (EWOULDBLOCK);
44001991Sheppo 	}
44011991Sheppo 
44021991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
44031991Sheppo 	    ldcp->id, size);
44041991Sheppo 
44051991Sheppo 	/* Send the data now */
44061991Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
44071991Sheppo 
44082336Snarayan 	/* copy the data into pkt */
44091991Sheppo 	bcopy((uint8_t *)buf, ldcmsg, size);
44101991Sheppo 
44112336Snarayan 	/* increment tail */
44121991Sheppo 	tx_tail = new_tail;
44131991Sheppo 
44141991Sheppo 	/*
44151991Sheppo 	 * All packets have been copied into the TX queue
44161991Sheppo 	 * update the tail ptr in the HV
44171991Sheppo 	 */
44181991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
44191991Sheppo 	if (rv) {
44201991Sheppo 		if (rv == EWOULDBLOCK) {
44211991Sheppo 			DWARN(ldcp->id, "ldc_write: (0x%llx) write timed out\n",
44221991Sheppo 			    ldcp->id);
44231991Sheppo 			*sizep = 0;
44241991Sheppo 			return (EWOULDBLOCK);
44251991Sheppo 		}
44261991Sheppo 
44271991Sheppo 		*sizep = 0;
44282336Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
44292793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
44302336Snarayan 			mutex_exit(&ldcp->lock);
44312336Snarayan 		} else {
44322336Snarayan 			/*
44332336Snarayan 			 * Release Tx lock, and then reacquire channel
44342336Snarayan 			 * and Tx lock in correct order
44352336Snarayan 			 */
44362336Snarayan 			mutex_exit(&ldcp->tx_lock);
44372336Snarayan 			mutex_enter(&ldcp->lock);
44382336Snarayan 			mutex_enter(&ldcp->tx_lock);
44392793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
44402336Snarayan 			mutex_exit(&ldcp->lock);
44412336Snarayan 		}
44421991Sheppo 		return (ECONNRESET);
44431991Sheppo 	}
44441991Sheppo 
44451991Sheppo 	ldcp->tx_tail = tx_tail;
44461991Sheppo 	*sizep = size;
44471991Sheppo 
44481991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, size);
44491991Sheppo 
44501991Sheppo 	return (rv);
44511991Sheppo }
44521991Sheppo 
44531991Sheppo 
44541991Sheppo /*
44551991Sheppo  * Write specified amount of bytes to the channel
44561991Sheppo  * in multiple pkts of pkt_payload size. Each
44571991Sheppo  * packet is tagged with an unique packet ID in
44582410Slm66018  * the case of a reliable link.
44591991Sheppo  *
44601991Sheppo  * On return, size contains the number of bytes written.
44611991Sheppo  * This function needs to ensure that the write size is < MTU size
44621991Sheppo  */
44631991Sheppo static int
i_ldc_write_packet(ldc_chan_t * ldcp,caddr_t buf,size_t * size)44641991Sheppo i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t buf, size_t *size)
44651991Sheppo {
44661991Sheppo 	ldc_msg_t 	*ldcmsg;
44671991Sheppo 	uint64_t 	tx_head, tx_tail, new_tail, start;
44681991Sheppo 	uint64_t	txq_size_mask, numavail;
44691991Sheppo 	uint8_t 	*msgbuf, *source = (uint8_t *)buf;
44701991Sheppo 	size_t 		len, bytes_written = 0, remaining;
44711991Sheppo 	int		rv;
44721991Sheppo 	uint32_t	curr_seqid;
44731991Sheppo 
44742336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
44751991Sheppo 
44761991Sheppo 	ASSERT(ldcp->mode == LDC_MODE_RELIABLE ||
44776408Sha137994 	    ldcp->mode == LDC_MODE_UNRELIABLE);
44781991Sheppo 
44791991Sheppo 	/* compute mask for increment */
44801991Sheppo 	txq_size_mask = (ldcp->tx_q_entries - 1) << LDC_PACKET_SHIFT;
44811991Sheppo 
44821991Sheppo 	/* get the qptrs for the tx queue */
44831991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
44841991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
44851991Sheppo 	if (rv != 0) {
44861991Sheppo 		cmn_err(CE_WARN,
44871991Sheppo 		    "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
44881991Sheppo 		*size = 0;
44891991Sheppo 		return (EIO);
44901991Sheppo 	}
44911991Sheppo 
44921991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
44931991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
44941991Sheppo 		DWARN(ldcp->id,
44951991Sheppo 		    "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
44961991Sheppo 		*size = 0;
44972336Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
44982793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
44992336Snarayan 			mutex_exit(&ldcp->lock);
45002336Snarayan 		} else {
45012336Snarayan 			/*
45022336Snarayan 			 * Release Tx lock, and then reacquire channel
45032336Snarayan 			 * and Tx lock in correct order
45042336Snarayan 			 */
45052336Snarayan 			mutex_exit(&ldcp->tx_lock);
45062336Snarayan 			mutex_enter(&ldcp->lock);
45072336Snarayan 			mutex_enter(&ldcp->tx_lock);
45082793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
45092336Snarayan 			mutex_exit(&ldcp->lock);
45102336Snarayan 		}
45111991Sheppo 		return (ECONNRESET);
45121991Sheppo 	}
45131991Sheppo 
45141991Sheppo 	tx_tail = ldcp->tx_tail;
45151991Sheppo 	new_tail = (tx_tail + LDC_PACKET_SIZE) %
45164690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
45171991Sheppo 
45181991Sheppo 	/*
45194690Snarayan 	 * Check to see if the queue is full. The check is done using
45204690Snarayan 	 * the appropriate head based on the link mode.
45211991Sheppo 	 */
45224690Snarayan 	i_ldc_get_tx_head(ldcp, &tx_head);
45234690Snarayan 
45241991Sheppo 	if (new_tail == tx_head) {
45251991Sheppo 		DWARN(DBG_ALL_LDCS,
45261991Sheppo 		    "ldc_write: (0x%llx) TX queue is full\n", ldcp->id);
45271991Sheppo 		*size = 0;
45281991Sheppo 		return (EWOULDBLOCK);
45291991Sheppo 	}
45301991Sheppo 
45311991Sheppo 	/*
45321991Sheppo 	 * Make sure that the LDC Tx queue has enough space
45331991Sheppo 	 */
45341991Sheppo 	numavail = (tx_head >> LDC_PACKET_SHIFT) - (tx_tail >> LDC_PACKET_SHIFT)
45354690Snarayan 	    + ldcp->tx_q_entries - 1;
45361991Sheppo 	numavail %= ldcp->tx_q_entries;
45371991Sheppo 
45381991Sheppo 	if (*size > (numavail * ldcp->pkt_payload)) {
45391991Sheppo 		DWARN(DBG_ALL_LDCS,
45401991Sheppo 		    "ldc_write: (0x%llx) TX queue has no space\n", ldcp->id);
45411991Sheppo 		return (EWOULDBLOCK);
45421991Sheppo 	}
45431991Sheppo 
45441991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
45451991Sheppo 	    ldcp->id, *size);
45461991Sheppo 
45471991Sheppo 	/* Send the data now */
45481991Sheppo 	bytes_written = 0;
45491991Sheppo 	curr_seqid = ldcp->last_msg_snt;
45501991Sheppo 	start = tx_tail;
45511991Sheppo 
45521991Sheppo 	while (*size > bytes_written) {
45531991Sheppo 
45541991Sheppo 		ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
45551991Sheppo 
45566408Sha137994 		msgbuf = (uint8_t *)((ldcp->mode == LDC_MODE_RELIABLE) ?
45574690Snarayan 		    ldcmsg->rdata : ldcmsg->udata);
45581991Sheppo 
45591991Sheppo 		ldcmsg->type = LDC_DATA;
45601991Sheppo 		ldcmsg->stype = LDC_INFO;
45611991Sheppo 		ldcmsg->ctrl = 0;
45621991Sheppo 
45631991Sheppo 		remaining = *size - bytes_written;
45641991Sheppo 		len = min(ldcp->pkt_payload, remaining);
45651991Sheppo 		ldcmsg->env = (uint8_t)len;
45661991Sheppo 
45671991Sheppo 		curr_seqid++;
45681991Sheppo 		ldcmsg->seqid = curr_seqid;
45691991Sheppo 
45701991Sheppo 		/* copy the data into pkt */
45711991Sheppo 		bcopy(source, msgbuf, len);
45721991Sheppo 
45731991Sheppo 		source += len;
45741991Sheppo 		bytes_written += len;
45751991Sheppo 
45761991Sheppo 		/* increment tail */
45771991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) & txq_size_mask;
45781991Sheppo 
45791991Sheppo 		ASSERT(tx_tail != tx_head);
45801991Sheppo 	}
45811991Sheppo 
45821991Sheppo 	/* Set the start and stop bits */
45831991Sheppo 	ldcmsg->env |= LDC_FRAG_STOP;
45841991Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + start);
45851991Sheppo 	ldcmsg->env |= LDC_FRAG_START;
45861991Sheppo 
45871991Sheppo 	/*
45881991Sheppo 	 * All packets have been copied into the TX queue
45891991Sheppo 	 * update the tail ptr in the HV
45901991Sheppo 	 */
45911991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
45921991Sheppo 	if (rv == 0) {
45931991Sheppo 		ldcp->tx_tail = tx_tail;
45941991Sheppo 		ldcp->last_msg_snt = curr_seqid;
45951991Sheppo 		*size = bytes_written;
45961991Sheppo 	} else {
45971991Sheppo 		int rv2;
45981991Sheppo 
45991991Sheppo 		if (rv != EWOULDBLOCK) {
46001991Sheppo 			*size = 0;
46012336Snarayan 			if (mutex_tryenter(&ldcp->lock)) {
46022793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
46032336Snarayan 				mutex_exit(&ldcp->lock);
46042336Snarayan 			} else {
46052336Snarayan 				/*
46062336Snarayan 				 * Release Tx lock, and then reacquire channel
46072336Snarayan 				 * and Tx lock in correct order
46082336Snarayan 				 */
46092336Snarayan 				mutex_exit(&ldcp->tx_lock);
46102336Snarayan 				mutex_enter(&ldcp->lock);
46112336Snarayan 				mutex_enter(&ldcp->tx_lock);
46122793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
46132336Snarayan 				mutex_exit(&ldcp->lock);
46142336Snarayan 			}
46151991Sheppo 			return (ECONNRESET);
46161991Sheppo 		}
46171991Sheppo 
46183010Slm66018 		D1(ldcp->id, "hv_tx_set_tail returns 0x%x (head 0x%x, "
46194690Snarayan 		    "old tail 0x%x, new tail 0x%x, qsize=0x%x)\n",
46204690Snarayan 		    rv, ldcp->tx_head, ldcp->tx_tail, tx_tail,
46214690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
46221991Sheppo 
46231991Sheppo 		rv2 = hv_ldc_tx_get_state(ldcp->id,
46241991Sheppo 		    &tx_head, &tx_tail, &ldcp->link_state);
46251991Sheppo 
46263010Slm66018 		D1(ldcp->id, "hv_ldc_tx_get_state returns 0x%x "
46274690Snarayan 		    "(head 0x%x, tail 0x%x state 0x%x)\n",
46284690Snarayan 		    rv2, tx_head, tx_tail, ldcp->link_state);
46291991Sheppo 
46301991Sheppo 		*size = 0;
46311991Sheppo 	}
46321991Sheppo 
46331991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, *size);
46341991Sheppo 
46351991Sheppo 	return (rv);
46361991Sheppo }
46371991Sheppo 
46381991Sheppo /*
46391991Sheppo  * Write specified amount of bytes to the channel
46401991Sheppo  * in multiple pkts of pkt_payload size. Each
46411991Sheppo  * packet is tagged with an unique packet ID in
46422410Slm66018  * the case of a reliable link.
46431991Sheppo  *
46441991Sheppo  * On return, size contains the number of bytes written.
46451991Sheppo  * This function needs to ensure that the write size is < MTU size
46461991Sheppo  */
46471991Sheppo static int
i_ldc_write_stream(ldc_chan_t * ldcp,caddr_t buf,size_t * sizep)46481991Sheppo i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
46491991Sheppo {
46502336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
46516408Sha137994 	ASSERT(ldcp->mode == LDC_MODE_RELIABLE);
46521991Sheppo 
46531991Sheppo 	/* Truncate packet to max of MTU size */
46541991Sheppo 	if (*sizep > ldcp->mtu) *sizep = ldcp->mtu;
46551991Sheppo 	return (i_ldc_write_packet(ldcp, buf, sizep));
46561991Sheppo }
46571991Sheppo 
46581991Sheppo 
46591991Sheppo /*
46601991Sheppo  * Interfaces for channel nexus to register/unregister with LDC module
46611991Sheppo  * The nexus will register functions to be used to register individual
46621991Sheppo  * channels with the nexus and enable interrupts for the channels
46631991Sheppo  */
46641991Sheppo int
ldc_register(ldc_cnex_t * cinfo)46651991Sheppo ldc_register(ldc_cnex_t *cinfo)
46661991Sheppo {
46671991Sheppo 	ldc_chan_t	*ldcp;
46681991Sheppo 
46691991Sheppo 	if (cinfo == NULL || cinfo->dip == NULL ||
46701991Sheppo 	    cinfo->reg_chan == NULL || cinfo->unreg_chan == NULL ||
46711991Sheppo 	    cinfo->add_intr == NULL || cinfo->rem_intr == NULL ||
46721991Sheppo 	    cinfo->clr_intr == NULL) {
46731991Sheppo 
46741991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_register: invalid nexus info\n");
46751991Sheppo 		return (EINVAL);
46761991Sheppo 	}
46771991Sheppo 
46781991Sheppo 	mutex_enter(&ldcssp->lock);
46791991Sheppo 
46801991Sheppo 	/* nexus registration */
46811991Sheppo 	ldcssp->cinfo.dip = cinfo->dip;
46821991Sheppo 	ldcssp->cinfo.reg_chan = cinfo->reg_chan;
46831991Sheppo 	ldcssp->cinfo.unreg_chan = cinfo->unreg_chan;
46841991Sheppo 	ldcssp->cinfo.add_intr = cinfo->add_intr;
46851991Sheppo 	ldcssp->cinfo.rem_intr = cinfo->rem_intr;
46861991Sheppo 	ldcssp->cinfo.clr_intr = cinfo->clr_intr;
46871991Sheppo 
46881991Sheppo 	/* register any channels that might have been previously initialized */
46891991Sheppo 	ldcp = ldcssp->chan_list;
46901991Sheppo 	while (ldcp) {
46911991Sheppo 		if ((ldcp->tstate & TS_QCONF_RDY) &&
46921991Sheppo 		    (ldcp->tstate & TS_CNEX_RDY) == 0)
46931991Sheppo 			(void) i_ldc_register_channel(ldcp);
46941991Sheppo 
46951991Sheppo 		ldcp = ldcp->next;
46961991Sheppo 	}
46971991Sheppo 
46981991Sheppo 	mutex_exit(&ldcssp->lock);
46991991Sheppo 
47001991Sheppo 	return (0);
47011991Sheppo }
47021991Sheppo 
47031991Sheppo int
ldc_unregister(ldc_cnex_t * cinfo)47041991Sheppo ldc_unregister(ldc_cnex_t *cinfo)
47051991Sheppo {
47061991Sheppo 	if (cinfo == NULL || cinfo->dip == NULL) {
47071991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid nexus info\n");
47081991Sheppo 		return (EINVAL);
47091991Sheppo 	}
47101991Sheppo 
47111991Sheppo 	mutex_enter(&ldcssp->lock);
47121991Sheppo 
47131991Sheppo 	if (cinfo->dip != ldcssp->cinfo.dip) {
47141991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid dip\n");
47151991Sheppo 		mutex_exit(&ldcssp->lock);
47161991Sheppo 		return (EINVAL);
47171991Sheppo 	}
47181991Sheppo 
47191991Sheppo 	/* nexus unregister */
47201991Sheppo 	ldcssp->cinfo.dip = NULL;
47211991Sheppo 	ldcssp->cinfo.reg_chan = NULL;
47221991Sheppo 	ldcssp->cinfo.unreg_chan = NULL;
47231991Sheppo 	ldcssp->cinfo.add_intr = NULL;
47241991Sheppo 	ldcssp->cinfo.rem_intr = NULL;
47251991Sheppo 	ldcssp->cinfo.clr_intr = NULL;
47261991Sheppo 
47271991Sheppo 	mutex_exit(&ldcssp->lock);
47281991Sheppo 
47291991Sheppo 	return (0);
47301991Sheppo }
4731*13098SWentao.Yang@Sun.COM 
4732*13098SWentao.Yang@Sun.COM int
ldc_info(ldc_handle_t handle,ldc_info_t * info)4733*13098SWentao.Yang@Sun.COM ldc_info(ldc_handle_t handle, ldc_info_t *info)
4734*13098SWentao.Yang@Sun.COM {
4735*13098SWentao.Yang@Sun.COM 	ldc_chan_t	*ldcp;
4736*13098SWentao.Yang@Sun.COM 	uint64_t	avail;
4737*13098SWentao.Yang@Sun.COM 
4738*13098SWentao.Yang@Sun.COM 	if (handle == NULL || info == NULL) {
4739*13098SWentao.Yang@Sun.COM 		DWARN(DBG_ALL_LDCS, "ldc_get_info: invalid args\n");
4740*13098SWentao.Yang@Sun.COM 		return (EINVAL);
4741*13098SWentao.Yang@Sun.COM 	}
4742*13098SWentao.Yang@Sun.COM 
4743*13098SWentao.Yang@Sun.COM 	ldcp = (ldc_chan_t *)handle;
4744*13098SWentao.Yang@Sun.COM 
4745*13098SWentao.Yang@Sun.COM 	mutex_enter(&ldcp->lock);
4746*13098SWentao.Yang@Sun.COM 
4747*13098SWentao.Yang@Sun.COM 	/* check to see if channel is initalized */
4748*13098SWentao.Yang@Sun.COM 	if ((ldcp->tstate & ~TS_IN_RESET) < TS_INIT) {
4749*13098SWentao.Yang@Sun.COM 		DWARN(ldcp->id,
4750*13098SWentao.Yang@Sun.COM 		    "ldc_get_info: (0x%llx) channel not initialized\n",
4751*13098SWentao.Yang@Sun.COM 		    ldcp->id);
4752*13098SWentao.Yang@Sun.COM 		mutex_exit(&ldcp->lock);
4753*13098SWentao.Yang@Sun.COM 		return (EINVAL);
4754*13098SWentao.Yang@Sun.COM 	}
4755*13098SWentao.Yang@Sun.COM 
4756*13098SWentao.Yang@Sun.COM 	mutex_exit(&ldcp->lock);
4757*13098SWentao.Yang@Sun.COM 
4758*13098SWentao.Yang@Sun.COM 	/*
4759*13098SWentao.Yang@Sun.COM 	 * ldcssp->mapin_size is the max amount of shared memory supported by
4760*13098SWentao.Yang@Sun.COM 	 * the Hypervisor per guest. e.g, legacy HV supports 64MB; latest HV
4761*13098SWentao.Yang@Sun.COM 	 * support 1GB. This size is read during ldc module initialization.
4762*13098SWentao.Yang@Sun.COM 	 *
4763*13098SWentao.Yang@Sun.COM 	 * ldc_dring_direct_map_rsvd is the amount of memory reserved for
4764*13098SWentao.Yang@Sun.COM 	 * mapping in descriptor rings. In the initial implementation, we use a
4765*13098SWentao.Yang@Sun.COM 	 * simple approach to determine the amount of mapin space available per
4766*13098SWentao.Yang@Sun.COM 	 * channel. In future, we may implement strict accounting of the actual
4767*13098SWentao.Yang@Sun.COM 	 * memory consumed to determine the exact amount available per channel.
4768*13098SWentao.Yang@Sun.COM 	 */
4769*13098SWentao.Yang@Sun.COM 	if (ldcssp->mapin_size <= ldc_dring_direct_map_rsvd) {
4770*13098SWentao.Yang@Sun.COM 		info->direct_map_size_max = 0;
4771*13098SWentao.Yang@Sun.COM 		return (0);
4772*13098SWentao.Yang@Sun.COM 	}
4773*13098SWentao.Yang@Sun.COM 
4774*13098SWentao.Yang@Sun.COM 	avail = ldcssp->mapin_size - ldc_dring_direct_map_rsvd;
4775*13098SWentao.Yang@Sun.COM 	if (avail >= ldc_direct_map_size_max) {
4776*13098SWentao.Yang@Sun.COM 		info->direct_map_size_max = ldc_direct_map_size_max;
4777*13098SWentao.Yang@Sun.COM 	} else {
4778*13098SWentao.Yang@Sun.COM 		info->direct_map_size_max = 0;
4779*13098SWentao.Yang@Sun.COM 	}
4780*13098SWentao.Yang@Sun.COM 
4781*13098SWentao.Yang@Sun.COM 	return (0);
4782*13098SWentao.Yang@Sun.COM }
4783