xref: /onnv-gate/usr/src/uts/sun4v/io/ldc.c (revision 10055:c14dc8a84103)
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 /*
238542SHaik.Aftandilian@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
241991Sheppo  * Use is subject to license terms.
251991Sheppo  */
261991Sheppo 
271991Sheppo /*
282410Slm66018  * sun4v LDC Link Layer
291991Sheppo  */
301991Sheppo #include <sys/types.h>
311991Sheppo #include <sys/file.h>
321991Sheppo #include <sys/errno.h>
331991Sheppo #include <sys/open.h>
341991Sheppo #include <sys/cred.h>
351991Sheppo #include <sys/kmem.h>
361991Sheppo #include <sys/conf.h>
371991Sheppo #include <sys/cmn_err.h>
381991Sheppo #include <sys/ksynch.h>
391991Sheppo #include <sys/modctl.h>
401991Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */
411991Sheppo #include <sys/debug.h>
421991Sheppo #include <sys/cred.h>
431991Sheppo #include <sys/promif.h>
441991Sheppo #include <sys/ddi.h>
451991Sheppo #include <sys/sunddi.h>
461991Sheppo #include <sys/cyclic.h>
471991Sheppo #include <sys/machsystm.h>
481991Sheppo #include <sys/vm.h>
491991Sheppo #include <sys/cpu.h>
501991Sheppo #include <sys/intreg.h>
511991Sheppo #include <sys/machcpuvar.h>
522531Snarayan #include <sys/mmu.h>
532531Snarayan #include <sys/pte.h>
542531Snarayan #include <vm/hat.h>
552531Snarayan #include <vm/as.h>
562531Snarayan #include <vm/hat_sfmmu.h>
572531Snarayan #include <sys/vm_machparam.h>
582531Snarayan #include <vm/seg_kmem.h>
592531Snarayan #include <vm/seg_kpm.h>
601991Sheppo #include <sys/note.h>
611991Sheppo #include <sys/ivintr.h>
621991Sheppo #include <sys/hypervisor_api.h>
631991Sheppo #include <sys/ldc.h>
641991Sheppo #include <sys/ldc_impl.h>
651991Sheppo #include <sys/cnex.h>
661991Sheppo #include <sys/hsvc.h>
675944Sha137994 #include <sys/sdt.h>
688542SHaik.Aftandilian@Sun.COM #include <sys/kldc.h>
691991Sheppo 
701991Sheppo /* Core internal functions */
716408Sha137994 int i_ldc_h2v_error(int h_error);
726408Sha137994 void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset);
736408Sha137994 
741991Sheppo static int i_ldc_txq_reconf(ldc_chan_t *ldcp);
752793Slm66018 static int i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset);
76*10055SKevin.Crowe@Sun.COM static void i_ldc_rxq_drain(ldc_chan_t *ldcp);
771991Sheppo static void i_ldc_reset_state(ldc_chan_t *ldcp);
788542SHaik.Aftandilian@Sun.COM static void i_ldc_debug_enter(void);
791991Sheppo 
801991Sheppo static int i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail);
814690Snarayan static void i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head);
821991Sheppo static int i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail);
831991Sheppo static int i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head);
841991Sheppo static int i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
851991Sheppo     uint8_t ctrlmsg);
861991Sheppo 
875944Sha137994 static int  i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head);
885944Sha137994 static void i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head);
895944Sha137994 static uint64_t i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head,
905944Sha137994     uint64_t *tail, uint64_t *link_state);
915944Sha137994 static uint64_t i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head,
925944Sha137994     uint64_t *tail, uint64_t *link_state);
935944Sha137994 static int i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head,
945944Sha137994     uint64_t rx_tail);
955944Sha137994 static uint_t i_ldc_chkq(ldc_chan_t *ldcp);
965944Sha137994 
971991Sheppo /* Interrupt handling functions */
981991Sheppo static uint_t i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2);
991991Sheppo static uint_t i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2);
1005944Sha137994 static uint_t i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client,
1015944Sha137994     uint64_t *notify_event);
1021991Sheppo static void i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype);
1031991Sheppo 
1041991Sheppo /* Read method functions */
1051991Sheppo static int i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep);
1061991Sheppo static int i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp,
1071991Sheppo 	size_t *sizep);
1081991Sheppo static int i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp,
1091991Sheppo 	size_t *sizep);
1101991Sheppo 
1111991Sheppo /* Write method functions */
1121991Sheppo static int i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t target_bufp,
1131991Sheppo 	size_t *sizep);
1141991Sheppo static int i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t target_bufp,
1151991Sheppo 	size_t *sizep);
1161991Sheppo static int i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t target_bufp,
1171991Sheppo 	size_t *sizep);
1181991Sheppo 
1191991Sheppo /* Pkt processing internal functions */
1201991Sheppo static int i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg);
1211991Sheppo static int i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg);
1221991Sheppo static int i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg);
1231991Sheppo static int i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg);
1241991Sheppo static int i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg);
1251991Sheppo static int i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg);
1261991Sheppo static int i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg);
1271991Sheppo 
1281991Sheppo /* LDC Version */
1291991Sheppo static ldc_ver_t ldc_versions[] = { {1, 0} };
1301991Sheppo 
1311991Sheppo /* number of supported versions */
1321991Sheppo #define	LDC_NUM_VERS	(sizeof (ldc_versions) / sizeof (ldc_versions[0]))
1331991Sheppo 
1345944Sha137994 /* Invalid value for the ldc_chan_t rx_ack_head field */
1355944Sha137994 #define	ACKPEEK_HEAD_INVALID	((uint64_t)-1)
1365944Sha137994 
1375944Sha137994 
1381991Sheppo /* Module State Pointer */
1396408Sha137994 ldc_soft_state_t *ldcssp;
1401991Sheppo 
1411991Sheppo static struct modldrv md = {
1421991Sheppo 	&mod_miscops,			/* This is a misc module */
1437799SRichard.Bean@Sun.COM 	"sun4v LDC module",		/* Name of the module */
1441991Sheppo };
1451991Sheppo 
1461991Sheppo static struct modlinkage ml = {
1471991Sheppo 	MODREV_1,
1481991Sheppo 	&md,
1491991Sheppo 	NULL
1501991Sheppo };
1511991Sheppo 
1521991Sheppo static uint64_t ldc_sup_minor;		/* Supported minor number */
1531991Sheppo static hsvc_info_t ldc_hsvc = {
1546845Sha137994 	HSVC_REV_1, NULL, HSVC_GROUP_LDC, 1, 1, "ldc"
1551991Sheppo };
1561991Sheppo 
1572531Snarayan /*
1582410Slm66018  * The no. of MTU size messages that can be stored in
1592410Slm66018  * the LDC Tx queue. The number of Tx queue entries is
1602410Slm66018  * then computed as (mtu * mtu_msgs)/sizeof(queue_entry)
1612410Slm66018  */
1622410Slm66018 uint64_t ldc_mtu_msgs = LDC_MTU_MSGS;
1632410Slm66018 
1642410Slm66018 /*
1652410Slm66018  * The minimum queue length. This is the size of the smallest
1662410Slm66018  * LDC queue. If the computed value is less than this default,
1672410Slm66018  * the queue length is rounded up to 'ldc_queue_entries'.
1682410Slm66018  */
1692410Slm66018 uint64_t ldc_queue_entries = LDC_QUEUE_ENTRIES;
1702410Slm66018 
1712410Slm66018 /*
1725944Sha137994  * The length of the reliable-mode data queue in terms of the LDC
1735944Sha137994  * receive queue length. i.e., the number of times larger than the
1745944Sha137994  * LDC receive queue that the data queue should be. The HV receive
1755944Sha137994  * queue is required to be a power of 2 and this implementation
1765944Sha137994  * assumes the data queue will also be a power of 2. By making the
1775944Sha137994  * multiplier a power of 2, we ensure the data queue will be a
1785944Sha137994  * power of 2. We use a multiplier because the receive queue is
1795944Sha137994  * sized to be sane relative to the MTU and the same is needed for
1805944Sha137994  * the data queue.
1815944Sha137994  */
1825944Sha137994 uint64_t ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER;
1835944Sha137994 
1845944Sha137994 /*
1852410Slm66018  * LDC retry count and delay - when the HV returns EWOULDBLOCK
1862410Slm66018  * the operation is retried 'ldc_max_retries' times with a
1872410Slm66018  * wait of 'ldc_delay' usecs between each retry.
1882032Slm66018  */
1892032Slm66018 int ldc_max_retries = LDC_MAX_RETRIES;
1902032Slm66018 clock_t ldc_delay = LDC_DELAY;
1912032Slm66018 
1923151Ssg70180 /*
1938542SHaik.Aftandilian@Sun.COM  * Channels which have a devclass satisfying the following
1948542SHaik.Aftandilian@Sun.COM  * will be reset when entering the prom or kmdb.
1958542SHaik.Aftandilian@Sun.COM  *
1968542SHaik.Aftandilian@Sun.COM  *   LDC_DEVCLASS_PROM_RESET(devclass) != 0
1978542SHaik.Aftandilian@Sun.COM  *
1988542SHaik.Aftandilian@Sun.COM  * By default, only block device service channels are reset.
1998542SHaik.Aftandilian@Sun.COM  */
2008542SHaik.Aftandilian@Sun.COM #define	LDC_DEVCLASS_BIT(dc)		(0x1 << (dc))
2018542SHaik.Aftandilian@Sun.COM #define	LDC_DEVCLASS_PROM_RESET(dc)	\
2028542SHaik.Aftandilian@Sun.COM 	(LDC_DEVCLASS_BIT(dc) & ldc_debug_reset_mask)
2038542SHaik.Aftandilian@Sun.COM static uint64_t ldc_debug_reset_mask = LDC_DEVCLASS_BIT(LDC_DEV_BLK_SVC);
2048542SHaik.Aftandilian@Sun.COM 
2058542SHaik.Aftandilian@Sun.COM /*
2063151Ssg70180  * delay between each retry of channel unregistration in
2073151Ssg70180  * ldc_close(), to wait for pending interrupts to complete.
2083151Ssg70180  */
2093151Ssg70180 clock_t ldc_close_delay = LDC_CLOSE_DELAY;
2103151Ssg70180 
2111991Sheppo #ifdef DEBUG
2121991Sheppo 
2131991Sheppo /*
2141991Sheppo  * Print debug messages
2151991Sheppo  *
2161991Sheppo  * set ldcdbg to 0x7 for enabling all msgs
2171991Sheppo  * 0x4 - Warnings
2181991Sheppo  * 0x2 - All debug messages
2191991Sheppo  * 0x1 - Minimal debug messages
2201991Sheppo  *
2211991Sheppo  * set ldcdbgchan to the channel number you want to debug
2221991Sheppo  * setting it to -1 prints debug messages for all channels
2231991Sheppo  * NOTE: ldcdbgchan has no effect on error messages
2241991Sheppo  */
2251991Sheppo 
2261991Sheppo int ldcdbg = 0x0;
2271991Sheppo int64_t ldcdbgchan = DBG_ALL_LDCS;
2283560Snarayan uint64_t ldc_inject_err_flag = 0;
2291991Sheppo 
2306408Sha137994 void
2311991Sheppo ldcdebug(int64_t id, const char *fmt, ...)
2321991Sheppo {
2331991Sheppo 	char buf[512];
2341991Sheppo 	va_list ap;
2351991Sheppo 
2361991Sheppo 	/*
2371991Sheppo 	 * Do not return if,
2381991Sheppo 	 * caller wants to print it anyway - (id == DBG_ALL_LDCS)
2391991Sheppo 	 * debug channel is set to all LDCs - (ldcdbgchan == DBG_ALL_LDCS)
2401991Sheppo 	 * debug channel = caller specified channel
2411991Sheppo 	 */
2421991Sheppo 	if ((id != DBG_ALL_LDCS) &&
2431991Sheppo 	    (ldcdbgchan != DBG_ALL_LDCS) &&
2441991Sheppo 	    (ldcdbgchan != id)) {
2451991Sheppo 		return;
2461991Sheppo 	}
2471991Sheppo 
2481991Sheppo 	va_start(ap, fmt);
2491991Sheppo 	(void) vsprintf(buf, fmt, ap);
2501991Sheppo 	va_end(ap);
2511991Sheppo 
2522793Slm66018 	cmn_err(CE_CONT, "?%s", buf);
2532793Slm66018 }
2542793Slm66018 
2556845Sha137994 #define	LDC_ERR_RESET		0x1
2566845Sha137994 #define	LDC_ERR_PKTLOSS		0x2
2576845Sha137994 #define	LDC_ERR_DQFULL		0x4
2586845Sha137994 #define	LDC_ERR_DRNGCLEAR	0x8
2593560Snarayan 
2602793Slm66018 static boolean_t
2613560Snarayan ldc_inject_error(ldc_chan_t *ldcp, uint64_t error)
2622793Slm66018 {
2632793Slm66018 	if ((ldcdbgchan != DBG_ALL_LDCS) && (ldcdbgchan != ldcp->id))
2642793Slm66018 		return (B_FALSE);
2652793Slm66018 
2663560Snarayan 	if ((ldc_inject_err_flag & error) == 0)
2672793Slm66018 		return (B_FALSE);
2682793Slm66018 
2692793Slm66018 	/* clear the injection state */
2703560Snarayan 	ldc_inject_err_flag &= ~error;
2712793Slm66018 
2722793Slm66018 	return (B_TRUE);
2731991Sheppo }
2741991Sheppo 
2751991Sheppo #define	D1		\
2761991Sheppo if (ldcdbg & 0x01)	\
2771991Sheppo 	ldcdebug
2781991Sheppo 
2791991Sheppo #define	D2		\
2801991Sheppo if (ldcdbg & 0x02)	\
2811991Sheppo 	ldcdebug
2821991Sheppo 
2831991Sheppo #define	DWARN		\
2841991Sheppo if (ldcdbg & 0x04)	\
2851991Sheppo 	ldcdebug
2861991Sheppo 
2871991Sheppo #define	DUMP_PAYLOAD(id, addr)						\
2881991Sheppo {									\
2891991Sheppo 	char buf[65*3];							\
2901991Sheppo 	int i;								\
2911991Sheppo 	uint8_t *src = (uint8_t *)addr;					\
2921991Sheppo 	for (i = 0; i < 64; i++, src++)					\
2931991Sheppo 		(void) sprintf(&buf[i * 3], "|%02x", *src);		\
2941991Sheppo 	(void) sprintf(&buf[i * 3], "|\n");				\
2951991Sheppo 	D2((id), "payload: %s", buf);					\
2961991Sheppo }
2971991Sheppo 
2981991Sheppo #define	DUMP_LDC_PKT(c, s, addr)					\
2991991Sheppo {									\
3001991Sheppo 	ldc_msg_t *msg = (ldc_msg_t *)(addr);				\
3011991Sheppo 	uint32_t mid = ((c)->mode != LDC_MODE_RAW) ? msg->seqid : 0;	\
3021991Sheppo 	if (msg->type == LDC_DATA) {                                    \
3031991Sheppo 	    D2((c)->id, "%s: msg%d (/%x/%x/%x/,env[%c%c,sz=%d])",	\
3041991Sheppo 	    (s), mid, msg->type, msg->stype, msg->ctrl,			\
3051991Sheppo 	    (msg->env & LDC_FRAG_START) ? 'B' : ' ',                    \
3061991Sheppo 	    (msg->env & LDC_FRAG_STOP) ? 'E' : ' ',                     \
3071991Sheppo 	    (msg->env & LDC_LEN_MASK));					\
3081991Sheppo 	} else { 							\
3091991Sheppo 	    D2((c)->id, "%s: msg%d (/%x/%x/%x/,env=%x)", (s),		\
3101991Sheppo 	    mid, msg->type, msg->stype, msg->ctrl, msg->env);		\
3111991Sheppo 	} 								\
3121991Sheppo }
3131991Sheppo 
3143560Snarayan #define	LDC_INJECT_RESET(_ldcp)	ldc_inject_error(_ldcp, LDC_ERR_RESET)
3153560Snarayan #define	LDC_INJECT_PKTLOSS(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_PKTLOSS)
3165944Sha137994 #define	LDC_INJECT_DQFULL(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DQFULL)
3176845Sha137994 #define	LDC_INJECT_DRNGCLEAR(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DRNGCLEAR)
3186845Sha137994 extern void i_ldc_mem_inject_dring_clear(ldc_chan_t *ldcp);
3192793Slm66018 
3201991Sheppo #else
3211991Sheppo 
3221991Sheppo #define	DBG_ALL_LDCS -1
3231991Sheppo 
3241991Sheppo #define	D1
3251991Sheppo #define	D2
3261991Sheppo #define	DWARN
3271991Sheppo 
3281991Sheppo #define	DUMP_PAYLOAD(id, addr)
3291991Sheppo #define	DUMP_LDC_PKT(c, s, addr)
3301991Sheppo 
3312793Slm66018 #define	LDC_INJECT_RESET(_ldcp)	(B_FALSE)
3323560Snarayan #define	LDC_INJECT_PKTLOSS(_ldcp) (B_FALSE)
3335944Sha137994 #define	LDC_INJECT_DQFULL(_ldcp) (B_FALSE)
3346845Sha137994 #define	LDC_INJECT_DRNGCLEAR(_ldcp) (B_FALSE)
3352793Slm66018 
3361991Sheppo #endif
3371991Sheppo 
3385944Sha137994 /*
3395944Sha137994  * dtrace SDT probes to ease tracing of the rx data queue and HV queue
3405944Sha137994  * lengths. Just pass the head, tail, and entries values so that the
3415944Sha137994  * length can be calculated in a dtrace script when the probe is enabled.
3425944Sha137994  */
3435944Sha137994 #define	TRACE_RXDQ_LENGTH(ldcp)						\
3445944Sha137994 	DTRACE_PROBE4(rxdq__size,					\
3455944Sha137994 	uint64_t, ldcp->id,						\
3465944Sha137994 	uint64_t, ldcp->rx_dq_head,					\
3475944Sha137994 	uint64_t, ldcp->rx_dq_tail,					\
3485944Sha137994 	uint64_t, ldcp->rx_dq_entries)
3495944Sha137994 
3505944Sha137994 #define	TRACE_RXHVQ_LENGTH(ldcp, head, tail)				\
3515944Sha137994 	DTRACE_PROBE4(rxhvq__size,					\
3525944Sha137994 	uint64_t, ldcp->id,						\
3535944Sha137994 	uint64_t, head,							\
3545944Sha137994 	uint64_t, tail,							\
3555944Sha137994 	uint64_t, ldcp->rx_q_entries)
3565944Sha137994 
3575944Sha137994 /* A dtrace SDT probe to ease tracing of data queue copy operations */
3585944Sha137994 #define	TRACE_RXDQ_COPY(ldcp, bytes)					\
3595944Sha137994 	DTRACE_PROBE2(rxdq__copy, uint64_t, ldcp->id, uint64_t, bytes)	\
3605944Sha137994 
3615944Sha137994 /* The amount of contiguous space at the tail of the queue */
3625944Sha137994 #define	Q_CONTIG_SPACE(head, tail, size)				\
3635944Sha137994 	((head) <= (tail) ? ((size) - (tail)) :				\
3645944Sha137994 	((head) - (tail) - LDC_PACKET_SIZE))
3655944Sha137994 
3661991Sheppo #define	ZERO_PKT(p)			\
3671991Sheppo 	bzero((p), sizeof (ldc_msg_t));
3681991Sheppo 
3691991Sheppo #define	IDX2COOKIE(idx, pg_szc, pg_shift)				\
3701991Sheppo 	(((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift)))
3711991Sheppo 
3721991Sheppo int
3731991Sheppo _init(void)
3741991Sheppo {
3751991Sheppo 	int status;
3766845Sha137994 	extern void i_ldc_mem_set_hsvc_vers(uint64_t major, uint64_t minor);
3771991Sheppo 
3781991Sheppo 	status = hsvc_register(&ldc_hsvc, &ldc_sup_minor);
3791991Sheppo 	if (status != 0) {
3804423Sjb145095 		cmn_err(CE_NOTE, "!%s: cannot negotiate hypervisor LDC services"
3811991Sheppo 		    " group: 0x%lx major: %ld minor: %ld errno: %d",
3821991Sheppo 		    ldc_hsvc.hsvc_modname, ldc_hsvc.hsvc_group,
3831991Sheppo 		    ldc_hsvc.hsvc_major, ldc_hsvc.hsvc_minor, status);
3841991Sheppo 		return (-1);
3851991Sheppo 	}
3861991Sheppo 
3876845Sha137994 	/* Initialize shared memory HV API version checking */
3886845Sha137994 	i_ldc_mem_set_hsvc_vers(ldc_hsvc.hsvc_major, ldc_sup_minor);
3896845Sha137994 
3901991Sheppo 	/* allocate soft state structure */
3911991Sheppo 	ldcssp = kmem_zalloc(sizeof (ldc_soft_state_t), KM_SLEEP);
3921991Sheppo 
3931991Sheppo 	/* Link the module into the system */
3941991Sheppo 	status = mod_install(&ml);
3951991Sheppo 	if (status != 0) {
3961991Sheppo 		kmem_free(ldcssp, sizeof (ldc_soft_state_t));
3971991Sheppo 		return (status);
3981991Sheppo 	}
3991991Sheppo 
4001991Sheppo 	/* Initialize the LDC state structure */
4011991Sheppo 	mutex_init(&ldcssp->lock, NULL, MUTEX_DRIVER, NULL);
4021991Sheppo 
4031991Sheppo 	mutex_enter(&ldcssp->lock);
4041991Sheppo 
4052531Snarayan 	/* Create a cache for memory handles */
4062531Snarayan 	ldcssp->memhdl_cache = kmem_cache_create("ldc_memhdl_cache",
4072531Snarayan 	    sizeof (ldc_mhdl_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
4082531Snarayan 	if (ldcssp->memhdl_cache == NULL) {
4092531Snarayan 		DWARN(DBG_ALL_LDCS, "_init: ldc_memhdl cache create failed\n");
4102531Snarayan 		mutex_exit(&ldcssp->lock);
4112531Snarayan 		return (-1);
4122531Snarayan 	}
4132531Snarayan 
4142531Snarayan 	/* Create cache for memory segment structures */
4152531Snarayan 	ldcssp->memseg_cache = kmem_cache_create("ldc_memseg_cache",
4162531Snarayan 	    sizeof (ldc_memseg_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
4172531Snarayan 	if (ldcssp->memseg_cache == NULL) {
4182531Snarayan 		DWARN(DBG_ALL_LDCS, "_init: ldc_memseg cache create failed\n");
4192531Snarayan 		mutex_exit(&ldcssp->lock);
4202531Snarayan 		return (-1);
4212531Snarayan 	}
4222531Snarayan 
4232531Snarayan 
4241991Sheppo 	ldcssp->channel_count = 0;
4251991Sheppo 	ldcssp->channels_open = 0;
4261991Sheppo 	ldcssp->chan_list = NULL;
4271991Sheppo 	ldcssp->dring_list = NULL;
4281991Sheppo 
4298542SHaik.Aftandilian@Sun.COM 	/* Register debug_enter callback */
4308542SHaik.Aftandilian@Sun.COM 	kldc_set_debug_cb(&i_ldc_debug_enter);
4318542SHaik.Aftandilian@Sun.COM 
4321991Sheppo 	mutex_exit(&ldcssp->lock);
4331991Sheppo 
4341991Sheppo 	return (0);
4351991Sheppo }
4361991Sheppo 
4371991Sheppo int
4381991Sheppo _info(struct modinfo *modinfop)
4391991Sheppo {
4401991Sheppo 	/* Report status of the dynamically loadable driver module */
4411991Sheppo 	return (mod_info(&ml, modinfop));
4421991Sheppo }
4431991Sheppo 
4441991Sheppo int
4451991Sheppo _fini(void)
4461991Sheppo {
4471991Sheppo 	int 		rv, status;
4484690Snarayan 	ldc_chan_t 	*tmp_ldcp, *ldcp;
4494690Snarayan 	ldc_dring_t 	*tmp_dringp, *dringp;
4501991Sheppo 	ldc_mem_info_t 	minfo;
4511991Sheppo 
4521991Sheppo 	/* Unlink the driver module from the system */
4531991Sheppo 	status = mod_remove(&ml);
4541991Sheppo 	if (status) {
4551991Sheppo 		DWARN(DBG_ALL_LDCS, "_fini: mod_remove failed\n");
4561991Sheppo 		return (EIO);
4571991Sheppo 	}
4581991Sheppo 
4598542SHaik.Aftandilian@Sun.COM 	/* Unregister debug_enter callback */
4608542SHaik.Aftandilian@Sun.COM 	kldc_set_debug_cb(NULL);
4618542SHaik.Aftandilian@Sun.COM 
4621991Sheppo 	/* Free descriptor rings */
4631991Sheppo 	dringp = ldcssp->dring_list;
4641991Sheppo 	while (dringp != NULL) {
4654690Snarayan 		tmp_dringp = dringp->next;
4661991Sheppo 
4671991Sheppo 		rv = ldc_mem_dring_info((ldc_dring_handle_t)dringp, &minfo);
4681991Sheppo 		if (rv == 0 && minfo.status != LDC_UNBOUND) {
4691991Sheppo 			if (minfo.status == LDC_BOUND) {
4701991Sheppo 				(void) ldc_mem_dring_unbind(
4714690Snarayan 				    (ldc_dring_handle_t)dringp);
4721991Sheppo 			}
4731991Sheppo 			if (minfo.status == LDC_MAPPED) {
4741991Sheppo 				(void) ldc_mem_dring_unmap(
4754690Snarayan 				    (ldc_dring_handle_t)dringp);
4761991Sheppo 			}
4771991Sheppo 		}
4781991Sheppo 
4791991Sheppo 		(void) ldc_mem_dring_destroy((ldc_dring_handle_t)dringp);
4804690Snarayan 		dringp = tmp_dringp;
4811991Sheppo 	}
4821991Sheppo 	ldcssp->dring_list = NULL;
4831991Sheppo 
4844690Snarayan 	/* close and finalize channels */
4854690Snarayan 	ldcp = ldcssp->chan_list;
4864690Snarayan 	while (ldcp != NULL) {
4874690Snarayan 		tmp_ldcp = ldcp->next;
4884690Snarayan 
4894690Snarayan 		(void) ldc_close((ldc_handle_t)ldcp);
4904690Snarayan 		(void) ldc_fini((ldc_handle_t)ldcp);
4914690Snarayan 
4924690Snarayan 		ldcp = tmp_ldcp;
4934690Snarayan 	}
4944690Snarayan 	ldcssp->chan_list = NULL;
4954690Snarayan 
4962531Snarayan 	/* Destroy kmem caches */
4972531Snarayan 	kmem_cache_destroy(ldcssp->memhdl_cache);
4982531Snarayan 	kmem_cache_destroy(ldcssp->memseg_cache);
4992531Snarayan 
5001991Sheppo 	/*
5011991Sheppo 	 * We have successfully "removed" the driver.
5021991Sheppo 	 * Destroying soft states
5031991Sheppo 	 */
5041991Sheppo 	mutex_destroy(&ldcssp->lock);
5051991Sheppo 	kmem_free(ldcssp, sizeof (ldc_soft_state_t));
5061991Sheppo 
5071991Sheppo 	(void) hsvc_unregister(&ldc_hsvc);
5081991Sheppo 
5091991Sheppo 	return (status);
5101991Sheppo }
5111991Sheppo 
5121991Sheppo /* -------------------------------------------------------------------------- */
5131991Sheppo 
5141991Sheppo /*
5152410Slm66018  * LDC Link Layer Internal Functions
5161991Sheppo  */
5171991Sheppo 
5181991Sheppo /*
5191991Sheppo  * Translate HV Errors to sun4v error codes
5201991Sheppo  */
5216408Sha137994 int
5221991Sheppo i_ldc_h2v_error(int h_error)
5231991Sheppo {
5241991Sheppo 	switch (h_error) {
5251991Sheppo 
5261991Sheppo 	case	H_EOK:
5271991Sheppo 		return (0);
5281991Sheppo 
5291991Sheppo 	case	H_ENORADDR:
5301991Sheppo 		return (EFAULT);
5311991Sheppo 
5321991Sheppo 	case	H_EBADPGSZ:
5331991Sheppo 	case	H_EINVAL:
5341991Sheppo 		return (EINVAL);
5351991Sheppo 
5361991Sheppo 	case	H_EWOULDBLOCK:
5371991Sheppo 		return (EWOULDBLOCK);
5381991Sheppo 
5391991Sheppo 	case	H_ENOACCESS:
5401991Sheppo 	case	H_ENOMAP:
5411991Sheppo 		return (EACCES);
5421991Sheppo 
5431991Sheppo 	case	H_EIO:
5441991Sheppo 	case	H_ECPUERROR:
5451991Sheppo 		return (EIO);
5461991Sheppo 
5471991Sheppo 	case	H_ENOTSUPPORTED:
5481991Sheppo 		return (ENOTSUP);
5491991Sheppo 
5501991Sheppo 	case 	H_ETOOMANY:
5511991Sheppo 		return (ENOSPC);
5521991Sheppo 
5531991Sheppo 	case	H_ECHANNEL:
5541991Sheppo 		return (ECHRNG);
5551991Sheppo 	default:
5561991Sheppo 		break;
5571991Sheppo 	}
5581991Sheppo 
5591991Sheppo 	return (EIO);
5601991Sheppo }
5611991Sheppo 
5621991Sheppo /*
5631991Sheppo  * Reconfigure the transmit queue
5641991Sheppo  */
5651991Sheppo static int
5661991Sheppo i_ldc_txq_reconf(ldc_chan_t *ldcp)
5671991Sheppo {
5681991Sheppo 	int rv;
5691991Sheppo 
5701991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
5712336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
5722336Snarayan 
5731991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
5741991Sheppo 	if (rv) {
5751991Sheppo 		cmn_err(CE_WARN,
5762793Slm66018 		    "i_ldc_txq_reconf: (0x%lx) cannot set qconf", ldcp->id);
5771991Sheppo 		return (EIO);
5781991Sheppo 	}
5791991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id, &(ldcp->tx_head),
5801991Sheppo 	    &(ldcp->tx_tail), &(ldcp->link_state));
5811991Sheppo 	if (rv) {
5821991Sheppo 		cmn_err(CE_WARN,
5832793Slm66018 		    "i_ldc_txq_reconf: (0x%lx) cannot get qptrs", ldcp->id);
5841991Sheppo 		return (EIO);
5851991Sheppo 	}
5862793Slm66018 	D1(ldcp->id, "i_ldc_txq_reconf: (0x%llx) h=0x%llx,t=0x%llx,"
5871991Sheppo 	    "s=0x%llx\n", ldcp->id, ldcp->tx_head, ldcp->tx_tail,
5881991Sheppo 	    ldcp->link_state);
5891991Sheppo 
5901991Sheppo 	return (0);
5911991Sheppo }
5921991Sheppo 
5931991Sheppo /*
5941991Sheppo  * Reconfigure the receive queue
5951991Sheppo  */
5961991Sheppo static int
5972793Slm66018 i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset)
5981991Sheppo {
5991991Sheppo 	int rv;
6001991Sheppo 	uint64_t rx_head, rx_tail;
6011991Sheppo 
6021991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
6031991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
6041991Sheppo 	    &(ldcp->link_state));
6051991Sheppo 	if (rv) {
6061991Sheppo 		cmn_err(CE_WARN,
6072793Slm66018 		    "i_ldc_rxq_reconf: (0x%lx) cannot get state",
6081991Sheppo 		    ldcp->id);
6091991Sheppo 		return (EIO);
6101991Sheppo 	}
6111991Sheppo 
6122793Slm66018 	if (force_reset || (ldcp->tstate & ~TS_IN_RESET) == TS_UP) {
6131991Sheppo 		rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra,
6144690Snarayan 		    ldcp->rx_q_entries);
6151991Sheppo 		if (rv) {
6161991Sheppo 			cmn_err(CE_WARN,
6172793Slm66018 			    "i_ldc_rxq_reconf: (0x%lx) cannot set qconf",
6181991Sheppo 			    ldcp->id);
6191991Sheppo 			return (EIO);
6201991Sheppo 		}
6212793Slm66018 		D1(ldcp->id, "i_ldc_rxq_reconf: (0x%llx) completed q reconf",
6221991Sheppo 		    ldcp->id);
6231991Sheppo 	}
6241991Sheppo 
6251991Sheppo 	return (0);
6261991Sheppo }
6271991Sheppo 
6282841Snarayan 
6292841Snarayan /*
6302841Snarayan  * Drain the contents of the receive queue
6312841Snarayan  */
632*10055SKevin.Crowe@Sun.COM static void
6332841Snarayan i_ldc_rxq_drain(ldc_chan_t *ldcp)
6342841Snarayan {
6352841Snarayan 	int rv;
6362841Snarayan 	uint64_t rx_head, rx_tail;
637*10055SKevin.Crowe@Sun.COM 	int retries = 0;
6382841Snarayan 
6392841Snarayan 	ASSERT(MUTEX_HELD(&ldcp->lock));
6402841Snarayan 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
6412841Snarayan 	    &(ldcp->link_state));
6422841Snarayan 	if (rv) {
643*10055SKevin.Crowe@Sun.COM 		cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot get state, "
644*10055SKevin.Crowe@Sun.COM 		    "rv = 0x%x", ldcp->id, rv);
645*10055SKevin.Crowe@Sun.COM 		return;
6462841Snarayan 	}
6472841Snarayan 
6489787SZachary.Kissel@Sun.COM 	/* If the queue is already empty just return success. */
6499787SZachary.Kissel@Sun.COM 	if (rx_head == rx_tail)
650*10055SKevin.Crowe@Sun.COM 		return;
651*10055SKevin.Crowe@Sun.COM 
652*10055SKevin.Crowe@Sun.COM 	/*
653*10055SKevin.Crowe@Sun.COM 	 * We are draining the queue in order to close the channel.
654*10055SKevin.Crowe@Sun.COM 	 * Call hv_ldc_rx_set_qhead directly instead of i_ldc_set_rx_head
655*10055SKevin.Crowe@Sun.COM 	 * because we do not need to reset the channel if the set
656*10055SKevin.Crowe@Sun.COM 	 * qhead fails.
657*10055SKevin.Crowe@Sun.COM 	 */
658*10055SKevin.Crowe@Sun.COM 	if ((rv = hv_ldc_rx_set_qhead(ldcp->id, rx_tail)) == 0)
659*10055SKevin.Crowe@Sun.COM 		return;
660*10055SKevin.Crowe@Sun.COM 
661*10055SKevin.Crowe@Sun.COM 	while ((rv == H_EWOULDBLOCK) && (retries++ < ldc_max_retries)) {
662*10055SKevin.Crowe@Sun.COM 		drv_usecwait(ldc_delay);
663*10055SKevin.Crowe@Sun.COM 		if ((rv = hv_ldc_rx_set_qhead(ldcp->id, rx_tail)) == 0)
664*10055SKevin.Crowe@Sun.COM 			return;
665*10055SKevin.Crowe@Sun.COM 	}
666*10055SKevin.Crowe@Sun.COM 
667*10055SKevin.Crowe@Sun.COM 	cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot set qhead 0x%lx, "
668*10055SKevin.Crowe@Sun.COM 	    "rv = 0x%x", ldcp->id, rx_tail, rv);
6692841Snarayan }
6702841Snarayan 
6712841Snarayan 
6721991Sheppo /*
6731991Sheppo  * Reset LDC state structure and its contents
6741991Sheppo  */
6751991Sheppo static void
6761991Sheppo i_ldc_reset_state(ldc_chan_t *ldcp)
6771991Sheppo {
6781991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
6791991Sheppo 	ldcp->last_msg_snt = LDC_INIT_SEQID;
6801991Sheppo 	ldcp->last_ack_rcd = 0;
6811991Sheppo 	ldcp->last_msg_rcd = 0;
6821991Sheppo 	ldcp->tx_ackd_head = ldcp->tx_head;
6835944Sha137994 	ldcp->stream_remains = 0;
6841991Sheppo 	ldcp->next_vidx = 0;
6851991Sheppo 	ldcp->hstate = 0;
6861991Sheppo 	ldcp->tstate = TS_OPEN;
6871991Sheppo 	ldcp->status = LDC_OPEN;
6885944Sha137994 	ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
6895944Sha137994 	ldcp->rx_dq_head = 0;
6905944Sha137994 	ldcp->rx_dq_tail = 0;
6911991Sheppo 
6921991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_UP ||
6931991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
6941991Sheppo 
6951991Sheppo 		if (ldcp->mode == LDC_MODE_RAW) {
6961991Sheppo 			ldcp->status = LDC_UP;
6971991Sheppo 			ldcp->tstate = TS_UP;
6981991Sheppo 		} else {
6991991Sheppo 			ldcp->status = LDC_READY;
7001991Sheppo 			ldcp->tstate |= TS_LINK_READY;
7011991Sheppo 		}
7021991Sheppo 	}
7031991Sheppo }
7041991Sheppo 
7051991Sheppo /*
7061991Sheppo  * Reset a LDC channel
7071991Sheppo  */
7086408Sha137994 void
7092793Slm66018 i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset)
7101991Sheppo {
7113560Snarayan 	DWARN(ldcp->id, "i_ldc_reset: (0x%llx) channel reset\n", ldcp->id);
7121991Sheppo 
7132336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->lock));
7142336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
7152336Snarayan 
7162793Slm66018 	/* reconfig Tx and Rx queues */
7171991Sheppo 	(void) i_ldc_txq_reconf(ldcp);
7182793Slm66018 	(void) i_ldc_rxq_reconf(ldcp, force_reset);
7192793Slm66018 
7202793Slm66018 	/* Clear Tx and Rx interrupts */
7212793Slm66018 	(void) i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
7222793Slm66018 	(void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
7232793Slm66018 
7242793Slm66018 	/* Reset channel state */
7251991Sheppo 	i_ldc_reset_state(ldcp);
7262793Slm66018 
7272793Slm66018 	/* Mark channel in reset */
7282793Slm66018 	ldcp->tstate |= TS_IN_RESET;
7291991Sheppo }
7301991Sheppo 
7318542SHaik.Aftandilian@Sun.COM /*
7328542SHaik.Aftandilian@Sun.COM  * Walk the channel list and reset channels if they are of the right
7338542SHaik.Aftandilian@Sun.COM  * devclass and their Rx queues have been configured. No locks are
7348542SHaik.Aftandilian@Sun.COM  * taken because the function is only invoked by the kernel just before
7358542SHaik.Aftandilian@Sun.COM  * entering the prom or debugger when the system is single-threaded.
7368542SHaik.Aftandilian@Sun.COM  */
7378542SHaik.Aftandilian@Sun.COM static void
7388542SHaik.Aftandilian@Sun.COM i_ldc_debug_enter(void)
7398542SHaik.Aftandilian@Sun.COM {
7408542SHaik.Aftandilian@Sun.COM 	ldc_chan_t *ldcp;
7418542SHaik.Aftandilian@Sun.COM 
7428542SHaik.Aftandilian@Sun.COM 	ldcp = ldcssp->chan_list;
7438542SHaik.Aftandilian@Sun.COM 	while (ldcp != NULL) {
7448542SHaik.Aftandilian@Sun.COM 		if (((ldcp->tstate & TS_QCONF_RDY) == TS_QCONF_RDY) &&
7458542SHaik.Aftandilian@Sun.COM 		    (LDC_DEVCLASS_PROM_RESET(ldcp->devclass) != 0)) {
7468542SHaik.Aftandilian@Sun.COM 			(void) hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra,
7478542SHaik.Aftandilian@Sun.COM 			    ldcp->rx_q_entries);
7488542SHaik.Aftandilian@Sun.COM 		}
7498542SHaik.Aftandilian@Sun.COM 		ldcp = ldcp->next;
7508542SHaik.Aftandilian@Sun.COM 	}
7518542SHaik.Aftandilian@Sun.COM }
7522531Snarayan 
7531991Sheppo /*
7541991Sheppo  * Clear pending interrupts
7551991Sheppo  */
7561991Sheppo static void
7571991Sheppo i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype)
7581991Sheppo {
7591991Sheppo 	ldc_cnex_t *cinfo = &ldcssp->cinfo;
7601991Sheppo 
7611991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
7622793Slm66018 	ASSERT(cinfo->dip != NULL);
7632793Slm66018 
7642793Slm66018 	switch (itype) {
7652793Slm66018 	case CNEX_TX_INTR:
7662531Snarayan 		/* check Tx interrupt */
7672793Slm66018 		if (ldcp->tx_intr_state)
7682793Slm66018 			ldcp->tx_intr_state = LDC_INTR_NONE;
7692793Slm66018 		else
7702793Slm66018 			return;
7712793Slm66018 		break;
7722793Slm66018 
7732793Slm66018 	case CNEX_RX_INTR:
7742531Snarayan 		/* check Rx interrupt */
7752793Slm66018 		if (ldcp->rx_intr_state)
7762793Slm66018 			ldcp->rx_intr_state = LDC_INTR_NONE;
7772793Slm66018 		else
7782793Slm66018 			return;
7792793Slm66018 		break;
7802793Slm66018 	}
7812793Slm66018 
7822793Slm66018 	(void) cinfo->clr_intr(cinfo->dip, ldcp->id, itype);
7832793Slm66018 	D2(ldcp->id,
7842793Slm66018 	    "i_ldc_clear_intr: (0x%llx) cleared 0x%x intr\n",
7852793Slm66018 	    ldcp->id, itype);
7861991Sheppo }
7871991Sheppo 
7881991Sheppo /*
7891991Sheppo  * Set the receive queue head
7902032Slm66018  * Resets connection and returns an error if it fails.
7911991Sheppo  */
7921991Sheppo static int
7931991Sheppo i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head)
7941991Sheppo {
7952032Slm66018 	int 	rv;
7962032Slm66018 	int 	retries;
7971991Sheppo 
7981991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
7992032Slm66018 	for (retries = 0; retries < ldc_max_retries; retries++) {
8002032Slm66018 
8012032Slm66018 		if ((rv = hv_ldc_rx_set_qhead(ldcp->id, head)) == 0)
8022032Slm66018 			return (0);
8032032Slm66018 
8042032Slm66018 		if (rv != H_EWOULDBLOCK)
8052032Slm66018 			break;
8062032Slm66018 
8072032Slm66018 		/* wait for ldc_delay usecs */
8082032Slm66018 		drv_usecwait(ldc_delay);
8092032Slm66018 	}
8102032Slm66018 
811*10055SKevin.Crowe@Sun.COM 	cmn_err(CE_WARN, "ldc_set_rx_qhead: (0x%lx) cannot set qhead 0x%lx, "
812*10055SKevin.Crowe@Sun.COM 	    "rv = 0x%x", ldcp->id, head, rv);
8132336Snarayan 	mutex_enter(&ldcp->tx_lock);
8142793Slm66018 	i_ldc_reset(ldcp, B_TRUE);
8152336Snarayan 	mutex_exit(&ldcp->tx_lock);
8162032Slm66018 
8172032Slm66018 	return (ECONNRESET);
8181991Sheppo }
8191991Sheppo 
8204690Snarayan /*
8214690Snarayan  * Returns the tx_head to be used for transfer
8224690Snarayan  */
8234690Snarayan static void
8244690Snarayan i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head)
8254690Snarayan {
8264690Snarayan 	ldc_msg_t 	*pkt;
8274690Snarayan 
8284690Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
8294690Snarayan 
8304690Snarayan 	/* get current Tx head */
8314690Snarayan 	*head = ldcp->tx_head;
8324690Snarayan 
8334690Snarayan 	/*
8344690Snarayan 	 * Reliable mode will use the ACKd head instead of the regular tx_head.
8354690Snarayan 	 * Also in Reliable mode, advance ackd_head for all non DATA/INFO pkts,
8364690Snarayan 	 * up to the current location of tx_head. This needs to be done
8374690Snarayan 	 * as the peer will only ACK DATA/INFO pkts.
8384690Snarayan 	 */
8396408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
8404690Snarayan 		while (ldcp->tx_ackd_head != ldcp->tx_head) {
8414690Snarayan 			pkt = (ldc_msg_t *)(ldcp->tx_q_va + ldcp->tx_ackd_head);
8424690Snarayan 			if ((pkt->type & LDC_DATA) && (pkt->stype & LDC_INFO)) {
8434690Snarayan 				break;
8444690Snarayan 			}
8454690Snarayan 			/* advance ACKd head */
8464690Snarayan 			ldcp->tx_ackd_head =
8474690Snarayan 			    (ldcp->tx_ackd_head + LDC_PACKET_SIZE) %
8484690Snarayan 			    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
8494690Snarayan 		}
8504690Snarayan 		*head = ldcp->tx_ackd_head;
8514690Snarayan 	}
8524690Snarayan }
8531991Sheppo 
8541991Sheppo /*
8551991Sheppo  * Returns the tx_tail to be used for transfer
8561991Sheppo  * Re-reads the TX queue ptrs if and only if the
8571991Sheppo  * the cached head and tail are equal (queue is full)
8581991Sheppo  */
8591991Sheppo static int
8601991Sheppo i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail)
8611991Sheppo {
8621991Sheppo 	int 		rv;
8631991Sheppo 	uint64_t 	current_head, new_tail;
8641991Sheppo 
8652336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
8661991Sheppo 	/* Read the head and tail ptrs from HV */
8671991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
8681991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
8691991Sheppo 	if (rv) {
8701991Sheppo 		cmn_err(CE_WARN,
8711991Sheppo 		    "i_ldc_get_tx_tail: (0x%lx) cannot read qptrs\n",
8721991Sheppo 		    ldcp->id);
8731991Sheppo 		return (EIO);
8741991Sheppo 	}
8751991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN) {
8763010Slm66018 		D1(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) channel not ready\n",
8771991Sheppo 		    ldcp->id);
8781991Sheppo 		return (ECONNRESET);
8791991Sheppo 	}
8801991Sheppo 
8814690Snarayan 	i_ldc_get_tx_head(ldcp, &current_head);
8821991Sheppo 
8831991Sheppo 	/* increment the tail */
8841991Sheppo 	new_tail = (ldcp->tx_tail + LDC_PACKET_SIZE) %
8854690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
8861991Sheppo 
8871991Sheppo 	if (new_tail == current_head) {
8881991Sheppo 		DWARN(ldcp->id,
8891991Sheppo 		    "i_ldc_get_tx_tail: (0x%llx) TX queue is full\n",
8901991Sheppo 		    ldcp->id);
8911991Sheppo 		return (EWOULDBLOCK);
8921991Sheppo 	}
8931991Sheppo 
8941991Sheppo 	D2(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) head=0x%llx, tail=0x%llx\n",
8951991Sheppo 	    ldcp->id, ldcp->tx_head, ldcp->tx_tail);
8961991Sheppo 
8971991Sheppo 	*tail = ldcp->tx_tail;
8981991Sheppo 	return (0);
8991991Sheppo }
9001991Sheppo 
9011991Sheppo /*
9021991Sheppo  * Set the tail pointer. If HV returns EWOULDBLOCK, it will back off
9032032Slm66018  * and retry ldc_max_retries times before returning an error.
9041991Sheppo  * Returns 0, EWOULDBLOCK or EIO
9051991Sheppo  */
9061991Sheppo static int
9071991Sheppo i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail)
9081991Sheppo {
9091991Sheppo 	int		rv, retval = EWOULDBLOCK;
9102032Slm66018 	int 		retries;
9111991Sheppo 
9122336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
9132032Slm66018 	for (retries = 0; retries < ldc_max_retries; retries++) {
9141991Sheppo 
9151991Sheppo 		if ((rv = hv_ldc_tx_set_qtail(ldcp->id, tail)) == 0) {
9161991Sheppo 			retval = 0;
9171991Sheppo 			break;
9181991Sheppo 		}
9191991Sheppo 		if (rv != H_EWOULDBLOCK) {
9201991Sheppo 			DWARN(ldcp->id, "i_ldc_set_tx_tail: (0x%llx) set "
9211991Sheppo 			    "qtail=0x%llx failed, rv=%d\n", ldcp->id, tail, rv);
9221991Sheppo 			retval = EIO;
9231991Sheppo 			break;
9241991Sheppo 		}
9251991Sheppo 
9262032Slm66018 		/* wait for ldc_delay usecs */
9272032Slm66018 		drv_usecwait(ldc_delay);
9281991Sheppo 	}
9291991Sheppo 	return (retval);
9301991Sheppo }
9311991Sheppo 
9321991Sheppo /*
9335944Sha137994  * Copy a data packet from the HV receive queue to the data queue.
9345944Sha137994  * Caller must ensure that the data queue is not already full.
9355944Sha137994  *
9365944Sha137994  * The *head argument represents the current head pointer for the HV
9375944Sha137994  * receive queue. After copying a packet from the HV receive queue,
9385944Sha137994  * the *head pointer will be updated. This allows the caller to update
9395944Sha137994  * the head pointer in HV using the returned *head value.
9405944Sha137994  */
9415944Sha137994 void
9425944Sha137994 i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head)
9435944Sha137994 {
9445944Sha137994 	uint64_t	q_size, dq_size;
9455944Sha137994 
9465944Sha137994 	ASSERT(MUTEX_HELD(&ldcp->lock));
9475944Sha137994 
9485944Sha137994 	q_size  = ldcp->rx_q_entries << LDC_PACKET_SHIFT;
9495944Sha137994 	dq_size = ldcp->rx_dq_entries << LDC_PACKET_SHIFT;
9505944Sha137994 
9515944Sha137994 	ASSERT(Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail,
9525944Sha137994 	    dq_size) >= LDC_PACKET_SIZE);
9535944Sha137994 
9545944Sha137994 	bcopy((void *)(ldcp->rx_q_va + *head),
9555944Sha137994 	    (void *)(ldcp->rx_dq_va + ldcp->rx_dq_tail), LDC_PACKET_SIZE);
9565944Sha137994 	TRACE_RXDQ_COPY(ldcp, LDC_PACKET_SIZE);
9575944Sha137994 
9585944Sha137994 	/* Update rx head */
9595944Sha137994 	*head = (*head + LDC_PACKET_SIZE) % q_size;
9605944Sha137994 
9615944Sha137994 	/* Update dq tail */
9625944Sha137994 	ldcp->rx_dq_tail = (ldcp->rx_dq_tail + LDC_PACKET_SIZE) % dq_size;
9635944Sha137994 }
9645944Sha137994 
9655944Sha137994 /*
9665944Sha137994  * Update the Rx data queue head pointer
9675944Sha137994  */
9685944Sha137994 static int
9695944Sha137994 i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head)
9705944Sha137994 {
9715944Sha137994 	ldcp->rx_dq_head = head;
9725944Sha137994 	return (0);
9735944Sha137994 }
9745944Sha137994 
9755944Sha137994 /*
9765944Sha137994  * Get the Rx data queue head and tail pointers
9775944Sha137994  */
9785944Sha137994 static uint64_t
9795944Sha137994 i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail,
9805944Sha137994     uint64_t *link_state)
9815944Sha137994 {
9825944Sha137994 	_NOTE(ARGUNUSED(link_state))
9835944Sha137994 	*head = ldcp->rx_dq_head;
9845944Sha137994 	*tail = ldcp->rx_dq_tail;
9855944Sha137994 	return (0);
9865944Sha137994 }
9875944Sha137994 
9885944Sha137994 /*
9895944Sha137994  * Wrapper for the Rx HV queue set head function. Giving the
9905944Sha137994  * data queue and HV queue set head functions the same type.
9915944Sha137994  */
9925944Sha137994 static uint64_t
9935944Sha137994 i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail,
9945944Sha137994     uint64_t *link_state)
9955944Sha137994 {
9965944Sha137994 	return (i_ldc_h2v_error(hv_ldc_rx_get_state(ldcp->id, head, tail,
9975944Sha137994 	    link_state)));
9985944Sha137994 }
9995944Sha137994 
10005944Sha137994 /*
10015944Sha137994  * LDC receive interrupt handler
10025944Sha137994  *    triggered for channel with data pending to read
10035944Sha137994  *    i.e. Rx queue content changes
10045944Sha137994  */
10055944Sha137994 static uint_t
10065944Sha137994 i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2)
10075944Sha137994 {
10085944Sha137994 	_NOTE(ARGUNUSED(arg2))
10095944Sha137994 
10105944Sha137994 	ldc_chan_t	*ldcp;
10115944Sha137994 	boolean_t	notify;
10125944Sha137994 	uint64_t	event;
10136944Sha137994 	int		rv, status;
10145944Sha137994 
10155944Sha137994 	/* Get the channel for which interrupt was received */
10165944Sha137994 	if (arg1 == NULL) {
10175944Sha137994 		cmn_err(CE_WARN, "i_ldc_rx_hdlr: invalid arg\n");
10185944Sha137994 		return (DDI_INTR_UNCLAIMED);
10195944Sha137994 	}
10205944Sha137994 
10215944Sha137994 	ldcp = (ldc_chan_t *)arg1;
10225944Sha137994 
10235944Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
10245944Sha137994 	    ldcp->id, ldcp);
10255944Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (%llx) USR%lx/TS%lx/HS%lx, LSTATE=%lx\n",
10265944Sha137994 	    ldcp->id, ldcp->status, ldcp->tstate, ldcp->hstate,
10275944Sha137994 	    ldcp->link_state);
10285944Sha137994 
10295944Sha137994 	/* Lock channel */
10305944Sha137994 	mutex_enter(&ldcp->lock);
10315944Sha137994 
10325944Sha137994 	/* Mark the interrupt as being actively handled */
10335944Sha137994 	ldcp->rx_intr_state = LDC_INTR_ACTIVE;
10345944Sha137994 
10356944Sha137994 	status = i_ldc_rx_process_hvq(ldcp, &notify, &event);
10365944Sha137994 
10376408Sha137994 	if (ldcp->mode != LDC_MODE_RELIABLE) {
10385944Sha137994 		/*
10395944Sha137994 		 * If there are no data packets on the queue, clear
10405944Sha137994 		 * the interrupt. Otherwise, the ldc_read will clear
10415944Sha137994 		 * interrupts after draining the queue. To indicate the
10425944Sha137994 		 * interrupt has not yet been cleared, it is marked
10435944Sha137994 		 * as pending.
10445944Sha137994 		 */
10455944Sha137994 		if ((event & LDC_EVT_READ) == 0) {
10465944Sha137994 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
10475944Sha137994 		} else {
10485944Sha137994 			ldcp->rx_intr_state = LDC_INTR_PEND;
10495944Sha137994 		}
10505944Sha137994 	}
10515944Sha137994 
10525944Sha137994 	/* if callbacks are disabled, do not notify */
10535944Sha137994 	if (notify && ldcp->cb_enabled) {
10545944Sha137994 		ldcp->cb_inprogress = B_TRUE;
10555944Sha137994 		mutex_exit(&ldcp->lock);
10565944Sha137994 		rv = ldcp->cb(event, ldcp->cb_arg);
10575944Sha137994 		if (rv) {
10585944Sha137994 			DWARN(ldcp->id,
10595944Sha137994 			    "i_ldc_rx_hdlr: (0x%llx) callback failure",
10605944Sha137994 			    ldcp->id);
10615944Sha137994 		}
10625944Sha137994 		mutex_enter(&ldcp->lock);
10635944Sha137994 		ldcp->cb_inprogress = B_FALSE;
10645944Sha137994 	}
10655944Sha137994 
10666408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
10676944Sha137994 		if (status == ENOSPC) {
10686944Sha137994 			/*
10696944Sha137994 			 * Here, ENOSPC indicates the secondary data
10706944Sha137994 			 * queue is full and the Rx queue is non-empty.
10716944Sha137994 			 * Much like how reliable and raw modes are
10726944Sha137994 			 * handled above, since the Rx queue is non-
10736944Sha137994 			 * empty, we mark the interrupt as pending to
10746944Sha137994 			 * indicate it has not yet been cleared.
10756944Sha137994 			 */
10766944Sha137994 			ldcp->rx_intr_state = LDC_INTR_PEND;
10776944Sha137994 		} else {
10786944Sha137994 			/*
10796944Sha137994 			 * We have processed all CTRL packets and
10806944Sha137994 			 * copied all DATA packets to the secondary
10816944Sha137994 			 * queue. Clear the interrupt.
10826944Sha137994 			 */
10836944Sha137994 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
10846944Sha137994 		}
10855944Sha137994 	}
10865944Sha137994 
10875944Sha137994 	mutex_exit(&ldcp->lock);
10885944Sha137994 
10895944Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) exiting handler", ldcp->id);
10905944Sha137994 
10915944Sha137994 	return (DDI_INTR_CLAIMED);
10925944Sha137994 }
10935944Sha137994 
10945944Sha137994 /*
10955944Sha137994  * Wrapper for the Rx HV queue processing function to be used when
10965944Sha137994  * checking the Rx HV queue for data packets. Unlike the interrupt
10975944Sha137994  * handler code flow, the Rx interrupt is not cleared here and
10985944Sha137994  * callbacks are not made.
10995944Sha137994  */
11005944Sha137994 static uint_t
11015944Sha137994 i_ldc_chkq(ldc_chan_t *ldcp)
11025944Sha137994 {
11035944Sha137994 	boolean_t	notify;
11045944Sha137994 	uint64_t	event;
11055944Sha137994 
11065944Sha137994 	return (i_ldc_rx_process_hvq(ldcp, &notify, &event));
11075944Sha137994 }
11085944Sha137994 
11095944Sha137994 /*
11101991Sheppo  * Send a LDC message
11111991Sheppo  */
11121991Sheppo static int
11131991Sheppo i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
11141991Sheppo     uint8_t ctrlmsg)
11151991Sheppo {
11161991Sheppo 	int		rv;
11171991Sheppo 	ldc_msg_t 	*pkt;
11181991Sheppo 	uint64_t	tx_tail;
11194690Snarayan 	uint32_t	curr_seqid;
11201991Sheppo 
11212336Snarayan 	/* Obtain Tx lock */
11222336Snarayan 	mutex_enter(&ldcp->tx_lock);
11232336Snarayan 
11244690Snarayan 	curr_seqid = ldcp->last_msg_snt;
11254690Snarayan 
11261991Sheppo 	/* get the current tail for the message */
11271991Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
11281991Sheppo 	if (rv) {
11291991Sheppo 		DWARN(ldcp->id,
11301991Sheppo 		    "i_ldc_send_pkt: (0x%llx) error sending pkt, "
11311991Sheppo 		    "type=0x%x,subtype=0x%x,ctrl=0x%x\n",
11321991Sheppo 		    ldcp->id, pkttype, subtype, ctrlmsg);
11332336Snarayan 		mutex_exit(&ldcp->tx_lock);
11341991Sheppo 		return (rv);
11351991Sheppo 	}
11361991Sheppo 
11371991Sheppo 	pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
11381991Sheppo 	ZERO_PKT(pkt);
11391991Sheppo 
11401991Sheppo 	/* Initialize the packet */
11411991Sheppo 	pkt->type = pkttype;
11421991Sheppo 	pkt->stype = subtype;
11431991Sheppo 	pkt->ctrl = ctrlmsg;
11441991Sheppo 
11451991Sheppo 	/* Store ackid/seqid iff it is RELIABLE mode & not a RTS/RTR message */
11461991Sheppo 	if (((ctrlmsg & LDC_CTRL_MASK) != LDC_RTS) &&
11471991Sheppo 	    ((ctrlmsg & LDC_CTRL_MASK) != LDC_RTR)) {
11481991Sheppo 		curr_seqid++;
11491991Sheppo 		if (ldcp->mode != LDC_MODE_RAW) {
11501991Sheppo 			pkt->seqid = curr_seqid;
11511991Sheppo 			pkt->ackid = ldcp->last_msg_rcd;
11521991Sheppo 		}
11531991Sheppo 	}
11541991Sheppo 	DUMP_LDC_PKT(ldcp, "i_ldc_send_pkt", (uint64_t)pkt);
11551991Sheppo 
11561991Sheppo 	/* initiate the send by calling into HV and set the new tail */
11571991Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
11584690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
11591991Sheppo 
11601991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
11611991Sheppo 	if (rv) {
11621991Sheppo 		DWARN(ldcp->id,
11631991Sheppo 		    "i_ldc_send_pkt:(0x%llx) error sending pkt, "
11641991Sheppo 		    "type=0x%x,stype=0x%x,ctrl=0x%x\n",
11651991Sheppo 		    ldcp->id, pkttype, subtype, ctrlmsg);
11662336Snarayan 		mutex_exit(&ldcp->tx_lock);
11671991Sheppo 		return (EIO);
11681991Sheppo 	}
11691991Sheppo 
11701991Sheppo 	ldcp->last_msg_snt = curr_seqid;
11711991Sheppo 	ldcp->tx_tail = tx_tail;
11721991Sheppo 
11732336Snarayan 	mutex_exit(&ldcp->tx_lock);
11741991Sheppo 	return (0);
11751991Sheppo }
11761991Sheppo 
11771991Sheppo /*
11781991Sheppo  * Checks if packet was received in right order
11792410Slm66018  * in the case of a reliable link.
11801991Sheppo  * Returns 0 if in order, else EIO
11811991Sheppo  */
11821991Sheppo static int
11831991Sheppo i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *msg)
11841991Sheppo {
11851991Sheppo 	/* No seqid checking for RAW mode */
11861991Sheppo 	if (ldcp->mode == LDC_MODE_RAW)
11871991Sheppo 		return (0);
11881991Sheppo 
11891991Sheppo 	/* No seqid checking for version, RTS, RTR message */
11901991Sheppo 	if (msg->ctrl == LDC_VER ||
11911991Sheppo 	    msg->ctrl == LDC_RTS ||
11921991Sheppo 	    msg->ctrl == LDC_RTR)
11931991Sheppo 		return (0);
11941991Sheppo 
11951991Sheppo 	/* Initial seqid to use is sent in RTS/RTR and saved in last_msg_rcd */
11961991Sheppo 	if (msg->seqid != (ldcp->last_msg_rcd + 1)) {
11971991Sheppo 		DWARN(ldcp->id,
11981991Sheppo 		    "i_ldc_check_seqid: (0x%llx) out-of-order pkt, got 0x%x, "
11991991Sheppo 		    "expecting 0x%x\n", ldcp->id, msg->seqid,
12001991Sheppo 		    (ldcp->last_msg_rcd + 1));
12011991Sheppo 		return (EIO);
12021991Sheppo 	}
12031991Sheppo 
12043560Snarayan #ifdef DEBUG
12053560Snarayan 	if (LDC_INJECT_PKTLOSS(ldcp)) {
12063560Snarayan 		DWARN(ldcp->id,
12073560Snarayan 		    "i_ldc_check_seqid: (0x%llx) inject pkt loss\n", ldcp->id);
12083560Snarayan 		return (EIO);
12093560Snarayan 	}
12103560Snarayan #endif
12113560Snarayan 
12121991Sheppo 	return (0);
12131991Sheppo }
12141991Sheppo 
12151991Sheppo 
12161991Sheppo /*
12171991Sheppo  * Process an incoming version ctrl message
12181991Sheppo  */
12191991Sheppo static int
12201991Sheppo i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg)
12211991Sheppo {
12221991Sheppo 	int 		rv = 0, idx = ldcp->next_vidx;
12231991Sheppo 	ldc_msg_t 	*pkt;
12241991Sheppo 	uint64_t	tx_tail;
12251991Sheppo 	ldc_ver_t	*rcvd_ver;
12261991Sheppo 
12271991Sheppo 	/* get the received version */
12281991Sheppo 	rcvd_ver = (ldc_ver_t *)((uint64_t)msg + LDC_PAYLOAD_VER_OFF);
12291991Sheppo 
12301991Sheppo 	D2(ldcp->id, "i_ldc_process_VER: (0x%llx) received VER v%u.%u\n",
12311991Sheppo 	    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
12321991Sheppo 
12332336Snarayan 	/* Obtain Tx lock */
12342336Snarayan 	mutex_enter(&ldcp->tx_lock);
12352336Snarayan 
12361991Sheppo 	switch (msg->stype) {
12371991Sheppo 	case LDC_INFO:
12381991Sheppo 
12392793Slm66018 		if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) {
12402793Slm66018 			(void) i_ldc_txq_reconf(ldcp);
12412793Slm66018 			i_ldc_reset_state(ldcp);
12422793Slm66018 			mutex_exit(&ldcp->tx_lock);
12432793Slm66018 			return (EAGAIN);
12442793Slm66018 		}
12452793Slm66018 
12461991Sheppo 		/* get the current tail and pkt for the response */
12471991Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
12481991Sheppo 		if (rv != 0) {
12491991Sheppo 			DWARN(ldcp->id,
12501991Sheppo 			    "i_ldc_process_VER: (0x%llx) err sending "
12511991Sheppo 			    "version ACK/NACK\n", ldcp->id);
12522793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
12532336Snarayan 			mutex_exit(&ldcp->tx_lock);
12541991Sheppo 			return (ECONNRESET);
12551991Sheppo 		}
12561991Sheppo 
12571991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
12581991Sheppo 		ZERO_PKT(pkt);
12591991Sheppo 
12601991Sheppo 		/* initialize the packet */
12611991Sheppo 		pkt->type = LDC_CTRL;
12621991Sheppo 		pkt->ctrl = LDC_VER;
12631991Sheppo 
12641991Sheppo 		for (;;) {
12651991Sheppo 
12661991Sheppo 			D1(ldcp->id, "i_ldc_process_VER: got %u.%u chk %u.%u\n",
12671991Sheppo 			    rcvd_ver->major, rcvd_ver->minor,
12681991Sheppo 			    ldc_versions[idx].major, ldc_versions[idx].minor);
12691991Sheppo 
12701991Sheppo 			if (rcvd_ver->major == ldc_versions[idx].major) {
12711991Sheppo 				/* major version match - ACK version */
12721991Sheppo 				pkt->stype = LDC_ACK;
12731991Sheppo 
12741991Sheppo 				/*
12751991Sheppo 				 * lower minor version to the one this endpt
12761991Sheppo 				 * supports, if necessary
12771991Sheppo 				 */
12781991Sheppo 				if (rcvd_ver->minor > ldc_versions[idx].minor)
12791991Sheppo 					rcvd_ver->minor =
12804690Snarayan 					    ldc_versions[idx].minor;
12811991Sheppo 				bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver));
12821991Sheppo 
12831991Sheppo 				break;
12841991Sheppo 			}
12851991Sheppo 
12861991Sheppo 			if (rcvd_ver->major > ldc_versions[idx].major) {
12871991Sheppo 
12881991Sheppo 				D1(ldcp->id, "i_ldc_process_VER: using next"
12891991Sheppo 				    " lower idx=%d, v%u.%u\n", idx,
12901991Sheppo 				    ldc_versions[idx].major,
12911991Sheppo 				    ldc_versions[idx].minor);
12921991Sheppo 
12931991Sheppo 				/* nack with next lower version */
12941991Sheppo 				pkt->stype = LDC_NACK;
12951991Sheppo 				bcopy(&ldc_versions[idx], pkt->udata,
12961991Sheppo 				    sizeof (ldc_versions[idx]));
12971991Sheppo 				ldcp->next_vidx = idx;
12981991Sheppo 				break;
12991991Sheppo 			}
13001991Sheppo 
13011991Sheppo 			/* next major version */
13021991Sheppo 			idx++;
13031991Sheppo 
13041991Sheppo 			D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx);
13051991Sheppo 
13061991Sheppo 			if (idx == LDC_NUM_VERS) {
13071991Sheppo 				/* no version match - send NACK */
13081991Sheppo 				pkt->stype = LDC_NACK;
13091991Sheppo 				bzero(pkt->udata, sizeof (ldc_ver_t));
13101991Sheppo 				ldcp->next_vidx = 0;
13111991Sheppo 				break;
13121991Sheppo 			}
13131991Sheppo 		}
13141991Sheppo 
13151991Sheppo 		/* initiate the send by calling into HV and set the new tail */
13161991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
13174690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
13181991Sheppo 
13191991Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
13201991Sheppo 		if (rv == 0) {
13211991Sheppo 			ldcp->tx_tail = tx_tail;
13221991Sheppo 			if (pkt->stype == LDC_ACK) {
13231991Sheppo 				D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent"
13241991Sheppo 				    " version ACK\n", ldcp->id);
13251991Sheppo 				/* Save the ACK'd version */
13261991Sheppo 				ldcp->version.major = rcvd_ver->major;
13271991Sheppo 				ldcp->version.minor = rcvd_ver->minor;
13282032Slm66018 				ldcp->hstate |= TS_RCVD_VER;
13291991Sheppo 				ldcp->tstate |= TS_VER_DONE;
13303560Snarayan 				D1(DBG_ALL_LDCS,
13312793Slm66018 				    "(0x%llx) Sent ACK, "
13322793Slm66018 				    "Agreed on version v%u.%u\n",
13331991Sheppo 				    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
13341991Sheppo 			}
13351991Sheppo 		} else {
13361991Sheppo 			DWARN(ldcp->id,
13371991Sheppo 			    "i_ldc_process_VER: (0x%llx) error sending "
13381991Sheppo 			    "ACK/NACK\n", ldcp->id);
13392793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
13402336Snarayan 			mutex_exit(&ldcp->tx_lock);
13411991Sheppo 			return (ECONNRESET);
13421991Sheppo 		}
13431991Sheppo 
13441991Sheppo 		break;
13451991Sheppo 
13461991Sheppo 	case LDC_ACK:
13472793Slm66018 		if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) {
13482793Slm66018 			if (ldcp->version.major != rcvd_ver->major ||
13494690Snarayan 			    ldcp->version.minor != rcvd_ver->minor) {
13502793Slm66018 
13512793Slm66018 				/* mismatched version - reset connection */
13522793Slm66018 				DWARN(ldcp->id,
13534690Snarayan 				    "i_ldc_process_VER: (0x%llx) recvd"
13544690Snarayan 				    " ACK ver != sent ACK ver\n", ldcp->id);
13552793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
13562793Slm66018 				mutex_exit(&ldcp->tx_lock);
13572793Slm66018 				return (ECONNRESET);
13582793Slm66018 			}
13592793Slm66018 		} else {
13602793Slm66018 			/* SUCCESS - we have agreed on a version */
13612793Slm66018 			ldcp->version.major = rcvd_ver->major;
13622793Slm66018 			ldcp->version.minor = rcvd_ver->minor;
13632793Slm66018 			ldcp->tstate |= TS_VER_DONE;
13642793Slm66018 		}
13652793Slm66018 
13663010Slm66018 		D1(ldcp->id, "(0x%llx) Got ACK, Agreed on version v%u.%u\n",
13671991Sheppo 		    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
13681991Sheppo 
13691991Sheppo 		/* initiate RTS-RTR-RDX handshake */
13701991Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
13711991Sheppo 		if (rv) {
13721991Sheppo 			DWARN(ldcp->id,
13732793Slm66018 		    "i_ldc_process_VER: (0x%llx) cannot send RTS\n",
13741991Sheppo 			    ldcp->id);
13752793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
13762336Snarayan 			mutex_exit(&ldcp->tx_lock);
13771991Sheppo 			return (ECONNRESET);
13781991Sheppo 		}
13791991Sheppo 
13801991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
13811991Sheppo 		ZERO_PKT(pkt);
13821991Sheppo 
13831991Sheppo 		pkt->type = LDC_CTRL;
13841991Sheppo 		pkt->stype = LDC_INFO;
13851991Sheppo 		pkt->ctrl = LDC_RTS;
13861991Sheppo 		pkt->env = ldcp->mode;
13871991Sheppo 		if (ldcp->mode != LDC_MODE_RAW)
13881991Sheppo 			pkt->seqid = LDC_INIT_SEQID;
13891991Sheppo 
13901991Sheppo 		ldcp->last_msg_rcd = LDC_INIT_SEQID;
13911991Sheppo 
13921991Sheppo 		DUMP_LDC_PKT(ldcp, "i_ldc_process_VER snd rts", (uint64_t)pkt);
13931991Sheppo 
13941991Sheppo 		/* initiate the send by calling into HV and set the new tail */
13951991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
13964690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
13971991Sheppo 
13981991Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
13991991Sheppo 		if (rv) {
14001991Sheppo 			D2(ldcp->id,
14011991Sheppo 			    "i_ldc_process_VER: (0x%llx) no listener\n",
14021991Sheppo 			    ldcp->id);
14032793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
14042336Snarayan 			mutex_exit(&ldcp->tx_lock);
14051991Sheppo 			return (ECONNRESET);
14061991Sheppo 		}
14071991Sheppo 
14081991Sheppo 		ldcp->tx_tail = tx_tail;
14091991Sheppo 		ldcp->hstate |= TS_SENT_RTS;
14101991Sheppo 
14111991Sheppo 		break;
14121991Sheppo 
14131991Sheppo 	case LDC_NACK:
14141991Sheppo 		/* check if version in NACK is zero */
14151991Sheppo 		if (rcvd_ver->major == 0 && rcvd_ver->minor == 0) {
14161991Sheppo 			/* version handshake failure */
14171991Sheppo 			DWARN(DBG_ALL_LDCS,
14181991Sheppo 			    "i_ldc_process_VER: (0x%llx) no version match\n",
14191991Sheppo 			    ldcp->id);
14202793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
14212336Snarayan 			mutex_exit(&ldcp->tx_lock);
14221991Sheppo 			return (ECONNRESET);
14231991Sheppo 		}
14241991Sheppo 
14251991Sheppo 		/* get the current tail and pkt for the response */
14261991Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
14271991Sheppo 		if (rv != 0) {
14281991Sheppo 			cmn_err(CE_NOTE,
14291991Sheppo 			    "i_ldc_process_VER: (0x%lx) err sending "
14301991Sheppo 			    "version ACK/NACK\n", ldcp->id);
14312793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
14322336Snarayan 			mutex_exit(&ldcp->tx_lock);
14331991Sheppo 			return (ECONNRESET);
14341991Sheppo 		}
14351991Sheppo 
14361991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
14371991Sheppo 		ZERO_PKT(pkt);
14381991Sheppo 
14391991Sheppo 		/* initialize the packet */
14401991Sheppo 		pkt->type = LDC_CTRL;
14411991Sheppo 		pkt->ctrl = LDC_VER;
14421991Sheppo 		pkt->stype = LDC_INFO;
14431991Sheppo 
14441991Sheppo 		/* check ver in NACK msg has a match */
14451991Sheppo 		for (;;) {
14461991Sheppo 			if (rcvd_ver->major == ldc_versions[idx].major) {
14471991Sheppo 				/*
14481991Sheppo 				 * major version match - resubmit request
14491991Sheppo 				 * if lower minor version to the one this endpt
14501991Sheppo 				 * supports, if necessary
14511991Sheppo 				 */
14521991Sheppo 				if (rcvd_ver->minor > ldc_versions[idx].minor)
14531991Sheppo 					rcvd_ver->minor =
14544690Snarayan 					    ldc_versions[idx].minor;
14551991Sheppo 				bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver));
14561991Sheppo 				break;
14571991Sheppo 			}
14581991Sheppo 
14591991Sheppo 			if (rcvd_ver->major > ldc_versions[idx].major) {
14601991Sheppo 
14611991Sheppo 				D1(ldcp->id, "i_ldc_process_VER: using next"
14621991Sheppo 				    " lower idx=%d, v%u.%u\n", idx,
14631991Sheppo 				    ldc_versions[idx].major,
14641991Sheppo 				    ldc_versions[idx].minor);
14651991Sheppo 
14661991Sheppo 				/* send next lower version */
14671991Sheppo 				bcopy(&ldc_versions[idx], pkt->udata,
14681991Sheppo 				    sizeof (ldc_versions[idx]));
14691991Sheppo 				ldcp->next_vidx = idx;
14701991Sheppo 				break;
14711991Sheppo 			}
14721991Sheppo 
14731991Sheppo 			/* next version */
14741991Sheppo 			idx++;
14751991Sheppo 
14761991Sheppo 			D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx);
14771991Sheppo 
14781991Sheppo 			if (idx == LDC_NUM_VERS) {
14791991Sheppo 				/* no version match - terminate */
14801991Sheppo 				ldcp->next_vidx = 0;
14812336Snarayan 				mutex_exit(&ldcp->tx_lock);
14821991Sheppo 				return (ECONNRESET);
14831991Sheppo 			}
14841991Sheppo 		}
14851991Sheppo 
14861991Sheppo 		/* initiate the send by calling into HV and set the new tail */
14871991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
14884690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
14891991Sheppo 
14901991Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
14911991Sheppo 		if (rv == 0) {
14921991Sheppo 			D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent version"
14931991Sheppo 			    "INFO v%u.%u\n", ldcp->id, ldc_versions[idx].major,
14941991Sheppo 			    ldc_versions[idx].minor);
14951991Sheppo 			ldcp->tx_tail = tx_tail;
14961991Sheppo 		} else {
14971991Sheppo 			cmn_err(CE_NOTE,
14981991Sheppo 			    "i_ldc_process_VER: (0x%lx) error sending version"
14991991Sheppo 			    "INFO\n", ldcp->id);
15002793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
15012336Snarayan 			mutex_exit(&ldcp->tx_lock);
15021991Sheppo 			return (ECONNRESET);
15031991Sheppo 		}
15041991Sheppo 
15051991Sheppo 		break;
15061991Sheppo 	}
15071991Sheppo 
15082336Snarayan 	mutex_exit(&ldcp->tx_lock);
15091991Sheppo 	return (rv);
15101991Sheppo }
15111991Sheppo 
15121991Sheppo 
15131991Sheppo /*
15141991Sheppo  * Process an incoming RTS ctrl message
15151991Sheppo  */
15161991Sheppo static int
15171991Sheppo i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg)
15181991Sheppo {
15191991Sheppo 	int 		rv = 0;
15201991Sheppo 	ldc_msg_t 	*pkt;
15211991Sheppo 	uint64_t	tx_tail;
15221991Sheppo 	boolean_t	sent_NACK = B_FALSE;
15231991Sheppo 
15241991Sheppo 	D2(ldcp->id, "i_ldc_process_RTS: (0x%llx) received RTS\n", ldcp->id);
15251991Sheppo 
15261991Sheppo 	switch (msg->stype) {
15271991Sheppo 	case LDC_NACK:
15281991Sheppo 		DWARN(ldcp->id,
15291991Sheppo 		    "i_ldc_process_RTS: (0x%llx) RTS NACK received\n",
15301991Sheppo 		    ldcp->id);
15311991Sheppo 
15321991Sheppo 		/* Reset the channel -- as we cannot continue */
15332336Snarayan 		mutex_enter(&ldcp->tx_lock);
15342793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
15352336Snarayan 		mutex_exit(&ldcp->tx_lock);
15361991Sheppo 		rv = ECONNRESET;
15371991Sheppo 		break;
15381991Sheppo 
15391991Sheppo 	case LDC_INFO:
15401991Sheppo 
15411991Sheppo 		/* check mode */
15421991Sheppo 		if (ldcp->mode != (ldc_mode_t)msg->env) {
15431991Sheppo 			cmn_err(CE_NOTE,
15441991Sheppo 			    "i_ldc_process_RTS: (0x%lx) mode mismatch\n",
15451991Sheppo 			    ldcp->id);
15461991Sheppo 			/*
15471991Sheppo 			 * send NACK in response to MODE message
15481991Sheppo 			 * get the current tail for the response
15491991Sheppo 			 */
15501991Sheppo 			rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTS);
15511991Sheppo 			if (rv) {
15521991Sheppo 				/* if cannot send NACK - reset channel */
15532336Snarayan 				mutex_enter(&ldcp->tx_lock);
15542793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
15552336Snarayan 				mutex_exit(&ldcp->tx_lock);
15561991Sheppo 				rv = ECONNRESET;
15571991Sheppo 				break;
15581991Sheppo 			}
15591991Sheppo 			sent_NACK = B_TRUE;
15601991Sheppo 		}
15611991Sheppo 		break;
15621991Sheppo 	default:
15631991Sheppo 		DWARN(ldcp->id, "i_ldc_process_RTS: (0x%llx) unexp ACK\n",
15641991Sheppo 		    ldcp->id);
15652336Snarayan 		mutex_enter(&ldcp->tx_lock);
15662793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
15672336Snarayan 		mutex_exit(&ldcp->tx_lock);
15681991Sheppo 		rv = ECONNRESET;
15691991Sheppo 		break;
15701991Sheppo 	}
15711991Sheppo 
15721991Sheppo 	/*
15731991Sheppo 	 * If either the connection was reset (when rv != 0) or
15741991Sheppo 	 * a NACK was sent, we return. In the case of a NACK
15751991Sheppo 	 * we dont want to consume the packet that came in but
15761991Sheppo 	 * not record that we received the RTS
15771991Sheppo 	 */
15781991Sheppo 	if (rv || sent_NACK)
15791991Sheppo 		return (rv);
15801991Sheppo 
15811991Sheppo 	/* record RTS received */
15821991Sheppo 	ldcp->hstate |= TS_RCVD_RTS;
15831991Sheppo 
15841991Sheppo 	/* store initial SEQID info */
15851991Sheppo 	ldcp->last_msg_snt = msg->seqid;
15861991Sheppo 
15872336Snarayan 	/* Obtain Tx lock */
15882336Snarayan 	mutex_enter(&ldcp->tx_lock);
15892336Snarayan 
15901991Sheppo 	/* get the current tail for the response */
15911991Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
15921991Sheppo 	if (rv != 0) {
15931991Sheppo 		cmn_err(CE_NOTE,
15941991Sheppo 		    "i_ldc_process_RTS: (0x%lx) err sending RTR\n",
15951991Sheppo 		    ldcp->id);
15962793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
15972336Snarayan 		mutex_exit(&ldcp->tx_lock);
15981991Sheppo 		return (ECONNRESET);
15991991Sheppo 	}
16001991Sheppo 
16011991Sheppo 	pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
16021991Sheppo 	ZERO_PKT(pkt);
16031991Sheppo 
16041991Sheppo 	/* initialize the packet */
16051991Sheppo 	pkt->type = LDC_CTRL;
16061991Sheppo 	pkt->stype = LDC_INFO;
16071991Sheppo 	pkt->ctrl = LDC_RTR;
16081991Sheppo 	pkt->env = ldcp->mode;
16091991Sheppo 	if (ldcp->mode != LDC_MODE_RAW)
16101991Sheppo 		pkt->seqid = LDC_INIT_SEQID;
16111991Sheppo 
16121991Sheppo 	ldcp->last_msg_rcd = msg->seqid;
16131991Sheppo 
16141991Sheppo 	/* initiate the send by calling into HV and set the new tail */
16151991Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
16164690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
16171991Sheppo 
16181991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
16191991Sheppo 	if (rv == 0) {
16201991Sheppo 		D2(ldcp->id,
16211991Sheppo 		    "i_ldc_process_RTS: (0x%llx) sent RTR\n", ldcp->id);
16221991Sheppo 		DUMP_LDC_PKT(ldcp, "i_ldc_process_RTS sent rtr", (uint64_t)pkt);
16231991Sheppo 
16241991Sheppo 		ldcp->tx_tail = tx_tail;
16251991Sheppo 		ldcp->hstate |= TS_SENT_RTR;
16261991Sheppo 
16271991Sheppo 	} else {
16281991Sheppo 		cmn_err(CE_NOTE,
16291991Sheppo 		    "i_ldc_process_RTS: (0x%lx) error sending RTR\n",
16301991Sheppo 		    ldcp->id);
16312793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
16322336Snarayan 		mutex_exit(&ldcp->tx_lock);
16331991Sheppo 		return (ECONNRESET);
16341991Sheppo 	}
16351991Sheppo 
16362336Snarayan 	mutex_exit(&ldcp->tx_lock);
16371991Sheppo 	return (0);
16381991Sheppo }
16391991Sheppo 
16401991Sheppo /*
16411991Sheppo  * Process an incoming RTR ctrl message
16421991Sheppo  */
16431991Sheppo static int
16441991Sheppo i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg)
16451991Sheppo {
16461991Sheppo 	int 		rv = 0;
16471991Sheppo 	boolean_t	sent_NACK = B_FALSE;
16481991Sheppo 
16491991Sheppo 	D2(ldcp->id, "i_ldc_process_RTR: (0x%llx) received RTR\n", ldcp->id);
16501991Sheppo 
16511991Sheppo 	switch (msg->stype) {
16521991Sheppo 	case LDC_NACK:
16531991Sheppo 		/* RTR NACK received */
16541991Sheppo 		DWARN(ldcp->id,
16551991Sheppo 		    "i_ldc_process_RTR: (0x%llx) RTR NACK received\n",
16561991Sheppo 		    ldcp->id);
16571991Sheppo 
16581991Sheppo 		/* Reset the channel -- as we cannot continue */
16592336Snarayan 		mutex_enter(&ldcp->tx_lock);
16602793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
16612336Snarayan 		mutex_exit(&ldcp->tx_lock);
16621991Sheppo 		rv = ECONNRESET;
16631991Sheppo 
16641991Sheppo 		break;
16651991Sheppo 
16661991Sheppo 	case LDC_INFO:
16671991Sheppo 
16681991Sheppo 		/* check mode */
16691991Sheppo 		if (ldcp->mode != (ldc_mode_t)msg->env) {
16701991Sheppo 			DWARN(ldcp->id,
16713010Slm66018 			    "i_ldc_process_RTR: (0x%llx) mode mismatch, "
16723010Slm66018 			    "expecting 0x%x, got 0x%x\n",
16733010Slm66018 			    ldcp->id, ldcp->mode, (ldc_mode_t)msg->env);
16741991Sheppo 			/*
16751991Sheppo 			 * send NACK in response to MODE message
16761991Sheppo 			 * get the current tail for the response
16771991Sheppo 			 */
16781991Sheppo 			rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTR);
16791991Sheppo 			if (rv) {
16801991Sheppo 				/* if cannot send NACK - reset channel */
16812336Snarayan 				mutex_enter(&ldcp->tx_lock);
16822793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
16832336Snarayan 				mutex_exit(&ldcp->tx_lock);
16841991Sheppo 				rv = ECONNRESET;
16851991Sheppo 				break;
16861991Sheppo 			}
16871991Sheppo 			sent_NACK = B_TRUE;
16881991Sheppo 		}
16891991Sheppo 		break;
16901991Sheppo 
16911991Sheppo 	default:
16921991Sheppo 		DWARN(ldcp->id, "i_ldc_process_RTR: (0x%llx) unexp ACK\n",
16931991Sheppo 		    ldcp->id);
16941991Sheppo 
16951991Sheppo 		/* Reset the channel -- as we cannot continue */
16962336Snarayan 		mutex_enter(&ldcp->tx_lock);
16972793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
16982336Snarayan 		mutex_exit(&ldcp->tx_lock);
16991991Sheppo 		rv = ECONNRESET;
17001991Sheppo 		break;
17011991Sheppo 	}
17021991Sheppo 
17031991Sheppo 	/*
17041991Sheppo 	 * If either the connection was reset (when rv != 0) or
17051991Sheppo 	 * a NACK was sent, we return. In the case of a NACK
17061991Sheppo 	 * we dont want to consume the packet that came in but
17071991Sheppo 	 * not record that we received the RTR
17081991Sheppo 	 */
17091991Sheppo 	if (rv || sent_NACK)
17101991Sheppo 		return (rv);
17111991Sheppo 
17121991Sheppo 	ldcp->last_msg_snt = msg->seqid;
17131991Sheppo 	ldcp->hstate |= TS_RCVD_RTR;
17141991Sheppo 
17151991Sheppo 	rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_INFO, LDC_RDX);
17161991Sheppo 	if (rv) {
17171991Sheppo 		cmn_err(CE_NOTE,
17181991Sheppo 		    "i_ldc_process_RTR: (0x%lx) cannot send RDX\n",
17191991Sheppo 		    ldcp->id);
17202336Snarayan 		mutex_enter(&ldcp->tx_lock);
17212793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
17222336Snarayan 		mutex_exit(&ldcp->tx_lock);
17231991Sheppo 		return (ECONNRESET);
17241991Sheppo 	}
17251991Sheppo 	D2(ldcp->id,
17261991Sheppo 	    "i_ldc_process_RTR: (0x%llx) sent RDX\n", ldcp->id);
17271991Sheppo 
17281991Sheppo 	ldcp->hstate |= TS_SENT_RDX;
17291991Sheppo 	ldcp->tstate |= TS_HSHAKE_DONE;
17302793Slm66018 	if ((ldcp->tstate & TS_IN_RESET) == 0)
17312793Slm66018 		ldcp->status = LDC_UP;
17321991Sheppo 
17333010Slm66018 	D1(ldcp->id, "(0x%llx) Handshake Complete\n", ldcp->id);
17341991Sheppo 
17351991Sheppo 	return (0);
17361991Sheppo }
17371991Sheppo 
17381991Sheppo 
17391991Sheppo /*
17401991Sheppo  * Process an incoming RDX ctrl message
17411991Sheppo  */
17421991Sheppo static int
17431991Sheppo i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg)
17441991Sheppo {
17451991Sheppo 	int	rv = 0;
17461991Sheppo 
17471991Sheppo 	D2(ldcp->id, "i_ldc_process_RDX: (0x%llx) received RDX\n", ldcp->id);
17481991Sheppo 
17491991Sheppo 	switch (msg->stype) {
17501991Sheppo 	case LDC_NACK:
17511991Sheppo 		/* RDX NACK received */
17521991Sheppo 		DWARN(ldcp->id,
17531991Sheppo 		    "i_ldc_process_RDX: (0x%llx) RDX NACK received\n",
17541991Sheppo 		    ldcp->id);
17551991Sheppo 
17561991Sheppo 		/* Reset the channel -- as we cannot continue */
17572336Snarayan 		mutex_enter(&ldcp->tx_lock);
17582793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
17592336Snarayan 		mutex_exit(&ldcp->tx_lock);
17601991Sheppo 		rv = ECONNRESET;
17611991Sheppo 
17621991Sheppo 		break;
17631991Sheppo 
17641991Sheppo 	case LDC_INFO:
17651991Sheppo 
17661991Sheppo 		/*
17671991Sheppo 		 * if channel is UP and a RDX received after data transmission
17681991Sheppo 		 * has commenced it is an error
17691991Sheppo 		 */
17701991Sheppo 		if ((ldcp->tstate == TS_UP) && (ldcp->hstate & TS_RCVD_RDX)) {
17711991Sheppo 			DWARN(DBG_ALL_LDCS,
17721991Sheppo 			    "i_ldc_process_RDX: (0x%llx) unexpected RDX"
17731991Sheppo 			    " - LDC reset\n", ldcp->id);
17742336Snarayan 			mutex_enter(&ldcp->tx_lock);
17752793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
17762336Snarayan 			mutex_exit(&ldcp->tx_lock);
17771991Sheppo 			return (ECONNRESET);
17781991Sheppo 		}
17791991Sheppo 
17801991Sheppo 		ldcp->hstate |= TS_RCVD_RDX;
17811991Sheppo 		ldcp->tstate |= TS_HSHAKE_DONE;
17822793Slm66018 		if ((ldcp->tstate & TS_IN_RESET) == 0)
17832793Slm66018 			ldcp->status = LDC_UP;
17841991Sheppo 
17851991Sheppo 		D1(DBG_ALL_LDCS, "(0x%llx) Handshake Complete\n", ldcp->id);
17861991Sheppo 		break;
17871991Sheppo 
17881991Sheppo 	default:
17891991Sheppo 		DWARN(ldcp->id, "i_ldc_process_RDX: (0x%llx) unexp ACK\n",
17901991Sheppo 		    ldcp->id);
17911991Sheppo 
17921991Sheppo 		/* Reset the channel -- as we cannot continue */
17932336Snarayan 		mutex_enter(&ldcp->tx_lock);
17942793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
17952336Snarayan 		mutex_exit(&ldcp->tx_lock);
17961991Sheppo 		rv = ECONNRESET;
17971991Sheppo 		break;
17981991Sheppo 	}
17991991Sheppo 
18001991Sheppo 	return (rv);
18011991Sheppo }
18021991Sheppo 
18031991Sheppo /*
18041991Sheppo  * Process an incoming ACK for a data packet
18051991Sheppo  */
18061991Sheppo static int
18071991Sheppo i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg)
18081991Sheppo {
18091991Sheppo 	int		rv;
18101991Sheppo 	uint64_t 	tx_head;
18111991Sheppo 	ldc_msg_t	*pkt;
18121991Sheppo 
18132336Snarayan 	/* Obtain Tx lock */
18142336Snarayan 	mutex_enter(&ldcp->tx_lock);
18152336Snarayan 
18161991Sheppo 	/*
18172336Snarayan 	 * Read the current Tx head and tail
18181991Sheppo 	 */
18191991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
18201991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
18211991Sheppo 	if (rv != 0) {
18221991Sheppo 		cmn_err(CE_WARN,
18231991Sheppo 		    "i_ldc_process_data_ACK: (0x%lx) cannot read qptrs\n",
18241991Sheppo 		    ldcp->id);
18252336Snarayan 
18262336Snarayan 		/* Reset the channel -- as we cannot continue */
18272793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
18282336Snarayan 		mutex_exit(&ldcp->tx_lock);
18292336Snarayan 		return (ECONNRESET);
18301991Sheppo 	}
18311991Sheppo 
18321991Sheppo 	/*
18331991Sheppo 	 * loop from where the previous ACK location was to the
18341991Sheppo 	 * current head location. This is how far the HV has
18351991Sheppo 	 * actually send pkts. Pkts between head and tail are
18361991Sheppo 	 * yet to be sent by HV.
18371991Sheppo 	 */
18381991Sheppo 	tx_head = ldcp->tx_ackd_head;
18391991Sheppo 	for (;;) {
18401991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_head);
18411991Sheppo 		tx_head = (tx_head + LDC_PACKET_SIZE) %
18424690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
18431991Sheppo 
18441991Sheppo 		if (pkt->seqid == msg->ackid) {
18451991Sheppo 			D2(ldcp->id,
18461991Sheppo 			    "i_ldc_process_data_ACK: (0x%llx) found packet\n",
18471991Sheppo 			    ldcp->id);
18481991Sheppo 			ldcp->last_ack_rcd = msg->ackid;
18491991Sheppo 			ldcp->tx_ackd_head = tx_head;
18501991Sheppo 			break;
18511991Sheppo 		}
18521991Sheppo 		if (tx_head == ldcp->tx_head) {
18531991Sheppo 			/* could not find packet */
18541991Sheppo 			DWARN(ldcp->id,
18551991Sheppo 			    "i_ldc_process_data_ACK: (0x%llx) invalid ACKid\n",
18561991Sheppo 			    ldcp->id);
18572336Snarayan 
18582336Snarayan 			/* Reset the channel -- as we cannot continue */
18592793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
18602336Snarayan 			mutex_exit(&ldcp->tx_lock);
18612336Snarayan 			return (ECONNRESET);
18621991Sheppo 		}
18631991Sheppo 	}
18641991Sheppo 
18652336Snarayan 	mutex_exit(&ldcp->tx_lock);
18661991Sheppo 	return (0);
18671991Sheppo }
18681991Sheppo 
18691991Sheppo /*
18701991Sheppo  * Process incoming control message
18711991Sheppo  * Return 0 - session can continue
18721991Sheppo  *        EAGAIN - reprocess packet - state was changed
18731991Sheppo  *	  ECONNRESET - channel was reset
18741991Sheppo  */
18751991Sheppo static int
18761991Sheppo i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *msg)
18771991Sheppo {
18781991Sheppo 	int 		rv = 0;
18791991Sheppo 
18802793Slm66018 	D1(ldcp->id, "i_ldc_ctrlmsg: (%llx) tstate = %lx, hstate = %lx\n",
18812793Slm66018 	    ldcp->id, ldcp->tstate, ldcp->hstate);
18822793Slm66018 
18832793Slm66018 	switch (ldcp->tstate & ~TS_IN_RESET) {
18841991Sheppo 
18851991Sheppo 	case TS_OPEN:
18861991Sheppo 	case TS_READY:
18871991Sheppo 
18881991Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
18891991Sheppo 		case LDC_VER:
18901991Sheppo 			/* process version message */
18911991Sheppo 			rv = i_ldc_process_VER(ldcp, msg);
18921991Sheppo 			break;
18931991Sheppo 		default:
18941991Sheppo 			DWARN(ldcp->id,
18951991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
18961991Sheppo 			    "tstate=0x%x\n", ldcp->id,
18971991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
18981991Sheppo 			break;
18991991Sheppo 		}
19001991Sheppo 
19011991Sheppo 		break;
19021991Sheppo 
19031991Sheppo 	case TS_VREADY:
19041991Sheppo 
19051991Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
19061991Sheppo 		case LDC_VER:
19072793Slm66018 			/* process version message */
19082793Slm66018 			rv = i_ldc_process_VER(ldcp, msg);
19091991Sheppo 			break;
19101991Sheppo 		case LDC_RTS:
19111991Sheppo 			/* process RTS message */
19121991Sheppo 			rv = i_ldc_process_RTS(ldcp, msg);
19131991Sheppo 			break;
19141991Sheppo 		case LDC_RTR:
19151991Sheppo 			/* process RTR message */
19161991Sheppo 			rv = i_ldc_process_RTR(ldcp, msg);
19171991Sheppo 			break;
19181991Sheppo 		case LDC_RDX:
19191991Sheppo 			/* process RDX message */
19201991Sheppo 			rv = i_ldc_process_RDX(ldcp, msg);
19211991Sheppo 			break;
19221991Sheppo 		default:
19231991Sheppo 			DWARN(ldcp->id,
19241991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
19251991Sheppo 			    "tstate=0x%x\n", ldcp->id,
19261991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
19271991Sheppo 			break;
19281991Sheppo 		}
19291991Sheppo 
19301991Sheppo 		break;
19311991Sheppo 
19321991Sheppo 	case TS_UP:
19331991Sheppo 
19341991Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
19351991Sheppo 		case LDC_VER:
19361991Sheppo 			DWARN(ldcp->id,
19371991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexpected VER "
19381991Sheppo 			    "- LDC reset\n", ldcp->id);
19391991Sheppo 			/* peer is redoing version negotiation */
19402336Snarayan 			mutex_enter(&ldcp->tx_lock);
19411991Sheppo 			(void) i_ldc_txq_reconf(ldcp);
19421991Sheppo 			i_ldc_reset_state(ldcp);
19432336Snarayan 			mutex_exit(&ldcp->tx_lock);
19441991Sheppo 			rv = EAGAIN;
19451991Sheppo 			break;
19461991Sheppo 
19471991Sheppo 		case LDC_RDX:
19481991Sheppo 			/* process RDX message */
19491991Sheppo 			rv = i_ldc_process_RDX(ldcp, msg);
19501991Sheppo 			break;
19511991Sheppo 
19521991Sheppo 		default:
19531991Sheppo 			DWARN(ldcp->id,
19541991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
19551991Sheppo 			    "tstate=0x%x\n", ldcp->id,
19561991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
19571991Sheppo 			break;
19581991Sheppo 		}
19591991Sheppo 	}
19601991Sheppo 
19611991Sheppo 	return (rv);
19621991Sheppo }
19631991Sheppo 
19641991Sheppo /*
19651991Sheppo  * Register channel with the channel nexus
19661991Sheppo  */
19671991Sheppo static int
19681991Sheppo i_ldc_register_channel(ldc_chan_t *ldcp)
19691991Sheppo {
19701991Sheppo 	int		rv = 0;
19711991Sheppo 	ldc_cnex_t	*cinfo = &ldcssp->cinfo;
19721991Sheppo 
19731991Sheppo 	if (cinfo->dip == NULL) {
19741991Sheppo 		DWARN(ldcp->id,
19751991Sheppo 		    "i_ldc_register_channel: cnex has not registered\n");
19761991Sheppo 		return (EAGAIN);
19771991Sheppo 	}
19781991Sheppo 
19791991Sheppo 	rv = cinfo->reg_chan(cinfo->dip, ldcp->id, ldcp->devclass);
19801991Sheppo 	if (rv) {
19811991Sheppo 		DWARN(ldcp->id,
19821991Sheppo 		    "i_ldc_register_channel: cannot register channel\n");
19831991Sheppo 		return (rv);
19841991Sheppo 	}
19851991Sheppo 
19861991Sheppo 	rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR,
19871991Sheppo 	    i_ldc_tx_hdlr, ldcp, NULL);
19881991Sheppo 	if (rv) {
19891991Sheppo 		DWARN(ldcp->id,
19901991Sheppo 		    "i_ldc_register_channel: cannot add Tx interrupt\n");
19911991Sheppo 		(void) cinfo->unreg_chan(cinfo->dip, ldcp->id);
19921991Sheppo 		return (rv);
19931991Sheppo 	}
19941991Sheppo 
19951991Sheppo 	rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR,
19961991Sheppo 	    i_ldc_rx_hdlr, ldcp, NULL);
19971991Sheppo 	if (rv) {
19981991Sheppo 		DWARN(ldcp->id,
19991991Sheppo 		    "i_ldc_register_channel: cannot add Rx interrupt\n");
20001991Sheppo 		(void) cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
20011991Sheppo 		(void) cinfo->unreg_chan(cinfo->dip, ldcp->id);
20021991Sheppo 		return (rv);
20031991Sheppo 	}
20041991Sheppo 
20051991Sheppo 	ldcp->tstate |= TS_CNEX_RDY;
20061991Sheppo 
20071991Sheppo 	return (0);
20081991Sheppo }
20091991Sheppo 
20101991Sheppo /*
20111991Sheppo  * Unregister a channel with the channel nexus
20121991Sheppo  */
20131991Sheppo static int
20141991Sheppo i_ldc_unregister_channel(ldc_chan_t *ldcp)
20151991Sheppo {
20161991Sheppo 	int		rv = 0;
20171991Sheppo 	ldc_cnex_t	*cinfo = &ldcssp->cinfo;
20181991Sheppo 
20191991Sheppo 	if (cinfo->dip == NULL) {
20201991Sheppo 		DWARN(ldcp->id,
20211991Sheppo 		    "i_ldc_unregister_channel: cnex has not registered\n");
20221991Sheppo 		return (EAGAIN);
20231991Sheppo 	}
20241991Sheppo 
20251991Sheppo 	if (ldcp->tstate & TS_CNEX_RDY) {
20261991Sheppo 
20272336Snarayan 		/* Remove the Rx interrupt */
20281991Sheppo 		rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR);
20291991Sheppo 		if (rv) {
20302793Slm66018 			if (rv != EAGAIN) {
20312793Slm66018 				DWARN(ldcp->id,
20322793Slm66018 				    "i_ldc_unregister_channel: err removing "
20332793Slm66018 				    "Rx intr\n");
20342793Slm66018 				return (rv);
20352793Slm66018 			}
20362793Slm66018 
20372793Slm66018 			/*
20382793Slm66018 			 * If interrupts are pending and handler has
20392793Slm66018 			 * finished running, clear interrupt and try
20402793Slm66018 			 * again
20412793Slm66018 			 */
20422793Slm66018 			if (ldcp->rx_intr_state != LDC_INTR_PEND)
20432793Slm66018 				return (rv);
20442793Slm66018 
20452793Slm66018 			(void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
20462793Slm66018 			rv = cinfo->rem_intr(cinfo->dip, ldcp->id,
20472793Slm66018 			    CNEX_RX_INTR);
20482793Slm66018 			if (rv) {
20492793Slm66018 				DWARN(ldcp->id, "i_ldc_unregister_channel: "
20502793Slm66018 				    "err removing Rx interrupt\n");
20512793Slm66018 				return (rv);
20522793Slm66018 			}
20531991Sheppo 		}
20542336Snarayan 
20552336Snarayan 		/* Remove the Tx interrupt */
20561991Sheppo 		rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
20571991Sheppo 		if (rv) {
20581991Sheppo 			DWARN(ldcp->id,
20591991Sheppo 			    "i_ldc_unregister_channel: err removing Tx intr\n");
20602336Snarayan 			return (rv);
20611991Sheppo 		}
20622336Snarayan 
20632336Snarayan 		/* Unregister the channel */
20641991Sheppo 		rv = cinfo->unreg_chan(ldcssp->cinfo.dip, ldcp->id);
20651991Sheppo 		if (rv) {
20661991Sheppo 			DWARN(ldcp->id,
20671991Sheppo 			    "i_ldc_unregister_channel: cannot unreg channel\n");
20682336Snarayan 			return (rv);
20691991Sheppo 		}
20701991Sheppo 
20711991Sheppo 		ldcp->tstate &= ~TS_CNEX_RDY;
20721991Sheppo 	}
20731991Sheppo 
20741991Sheppo 	return (0);
20751991Sheppo }
20761991Sheppo 
20771991Sheppo 
20781991Sheppo /*
20791991Sheppo  * LDC transmit interrupt handler
20801991Sheppo  *    triggered for chanel up/down/reset events
20811991Sheppo  *    and Tx queue content changes
20821991Sheppo  */
20831991Sheppo static uint_t
20841991Sheppo i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2)
20851991Sheppo {
20861991Sheppo 	_NOTE(ARGUNUSED(arg2))
20871991Sheppo 
20881991Sheppo 	int 		rv;
20891991Sheppo 	ldc_chan_t 	*ldcp;
20901991Sheppo 	boolean_t 	notify_client = B_FALSE;
20912793Slm66018 	uint64_t	notify_event = 0, link_state;
20921991Sheppo 
20931991Sheppo 	/* Get the channel for which interrupt was received */
20941991Sheppo 	ASSERT(arg1 != NULL);
20951991Sheppo 	ldcp = (ldc_chan_t *)arg1;
20961991Sheppo 
20971991Sheppo 	D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
20981991Sheppo 	    ldcp->id, ldcp);
20991991Sheppo 
21001991Sheppo 	/* Lock channel */
21011991Sheppo 	mutex_enter(&ldcp->lock);
21021991Sheppo 
21032336Snarayan 	/* Obtain Tx lock */
21042336Snarayan 	mutex_enter(&ldcp->tx_lock);
21052336Snarayan 
21062531Snarayan 	/* mark interrupt as pending */
21072793Slm66018 	ldcp->tx_intr_state = LDC_INTR_ACTIVE;
21082793Slm66018 
21092793Slm66018 	/* save current link state */
21102793Slm66018 	link_state = ldcp->link_state;
21112531Snarayan 
21121991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id, &ldcp->tx_head, &ldcp->tx_tail,
21131991Sheppo 	    &ldcp->link_state);
21141991Sheppo 	if (rv) {
21151991Sheppo 		cmn_err(CE_WARN,
21161991Sheppo 		    "i_ldc_tx_hdlr: (0x%lx) cannot read queue ptrs rv=0x%d\n",
21171991Sheppo 		    ldcp->id, rv);
21182531Snarayan 		i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
21192336Snarayan 		mutex_exit(&ldcp->tx_lock);
21201991Sheppo 		mutex_exit(&ldcp->lock);
21211991Sheppo 		return (DDI_INTR_CLAIMED);
21221991Sheppo 	}
21231991Sheppo 
21241991Sheppo 	/*
21251991Sheppo 	 * reset the channel state if the channel went down
21261991Sheppo 	 * (other side unconfigured queue) or channel was reset
21271991Sheppo 	 * (other side reconfigured its queue)
21281991Sheppo 	 */
21292793Slm66018 	if (link_state != ldcp->link_state &&
21302793Slm66018 	    ldcp->link_state == LDC_CHANNEL_DOWN) {
21311991Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link down\n", ldcp->id);
21322793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
21331991Sheppo 		notify_client = B_TRUE;
21341991Sheppo 		notify_event = LDC_EVT_DOWN;
21351991Sheppo 	}
21361991Sheppo 
21372793Slm66018 	if (link_state != ldcp->link_state &&
21382793Slm66018 	    ldcp->link_state == LDC_CHANNEL_RESET) {
21391991Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link reset\n", ldcp->id);
21402793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
21411991Sheppo 		notify_client = B_TRUE;
21421991Sheppo 		notify_event = LDC_EVT_RESET;
21431991Sheppo 	}
21441991Sheppo 
21452793Slm66018 	if (link_state != ldcp->link_state &&
21462793Slm66018 	    (ldcp->tstate & ~TS_IN_RESET) == TS_OPEN &&
21472793Slm66018 	    ldcp->link_state == LDC_CHANNEL_UP) {
21481991Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link up\n", ldcp->id);
21491991Sheppo 		notify_client = B_TRUE;
21501991Sheppo 		notify_event = LDC_EVT_RESET;
21511991Sheppo 		ldcp->tstate |= TS_LINK_READY;
21521991Sheppo 		ldcp->status = LDC_READY;
21531991Sheppo 	}
21541991Sheppo 
21551991Sheppo 	/* if callbacks are disabled, do not notify */
21561991Sheppo 	if (!ldcp->cb_enabled)
21571991Sheppo 		notify_client = B_FALSE;
21581991Sheppo 
21593151Ssg70180 	i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
21604690Snarayan 	mutex_exit(&ldcp->tx_lock);
21611991Sheppo 
21621991Sheppo 	if (notify_client) {
21632793Slm66018 		ldcp->cb_inprogress = B_TRUE;
21642793Slm66018 		mutex_exit(&ldcp->lock);
21651991Sheppo 		rv = ldcp->cb(notify_event, ldcp->cb_arg);
21661991Sheppo 		if (rv) {
21671991Sheppo 			DWARN(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) callback "
21681991Sheppo 			    "failure", ldcp->id);
21691991Sheppo 		}
21701991Sheppo 		mutex_enter(&ldcp->lock);
21711991Sheppo 		ldcp->cb_inprogress = B_FALSE;
21722793Slm66018 	}
21732793Slm66018 
21741991Sheppo 	mutex_exit(&ldcp->lock);
21751991Sheppo 
21761991Sheppo 	D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) exiting handler", ldcp->id);
21771991Sheppo 
21781991Sheppo 	return (DDI_INTR_CLAIMED);
21791991Sheppo }
21801991Sheppo 
21811991Sheppo /*
21825944Sha137994  * Process the Rx HV queue.
21835944Sha137994  *
21845944Sha137994  * Returns 0 if data packets were found and no errors were encountered,
21855944Sha137994  * otherwise returns an error. In either case, the *notify argument is
21865944Sha137994  * set to indicate whether or not the client callback function should
21875944Sha137994  * be invoked. The *event argument is set to contain the callback event.
21885944Sha137994  *
21895944Sha137994  * Depending on the channel mode, packets are handled differently:
21905944Sha137994  *
21915944Sha137994  * RAW MODE
21925944Sha137994  * For raw mode channels, when a data packet is encountered,
21935944Sha137994  * processing stops and all packets are left on the queue to be removed
21945944Sha137994  * and processed by the ldc_read code path.
21955944Sha137994  *
21965944Sha137994  * UNRELIABLE MODE
21975944Sha137994  * For unreliable mode, when a data packet is encountered, processing
21985944Sha137994  * stops, and all packets are left on the queue to be removed and
21995944Sha137994  * processed by the ldc_read code path. Control packets are processed
22005944Sha137994  * inline if they are encountered before any data packets.
22015944Sha137994  *
22026408Sha137994  * RELIABLE MODE
22036408Sha137994  * For reliable mode channels, all packets on the receive queue
22045944Sha137994  * are processed: data packets are copied to the data queue and
22055944Sha137994  * control packets are processed inline. Packets are only left on
22065944Sha137994  * the receive queue when the data queue is full.
22071991Sheppo  */
22081991Sheppo static uint_t
22095944Sha137994 i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client,
22105944Sha137994     uint64_t *notify_event)
22111991Sheppo {
22121991Sheppo 	int		rv;
22131991Sheppo 	uint64_t 	rx_head, rx_tail;
22141991Sheppo 	ldc_msg_t 	*msg;
22152793Slm66018 	uint64_t	link_state, first_fragment = 0;
22165944Sha137994 	boolean_t	trace_length = B_TRUE;
22175944Sha137994 
22185944Sha137994 	ASSERT(MUTEX_HELD(&ldcp->lock));
22195944Sha137994 	*notify_client = B_FALSE;
22205944Sha137994 	*notify_event = 0;
22211991Sheppo 
22221991Sheppo 	/*
22231991Sheppo 	 * Read packet(s) from the queue
22241991Sheppo 	 */
22251991Sheppo 	for (;;) {
22261991Sheppo 
22272793Slm66018 		link_state = ldcp->link_state;
22281991Sheppo 		rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
22291991Sheppo 		    &ldcp->link_state);
22301991Sheppo 		if (rv) {
22311991Sheppo 			cmn_err(CE_WARN,
22325944Sha137994 			    "i_ldc_rx_process_hvq: (0x%lx) cannot read "
22331991Sheppo 			    "queue ptrs, rv=0x%d\n", ldcp->id, rv);
22341991Sheppo 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
22355944Sha137994 			return (EIO);
22361991Sheppo 		}
22371991Sheppo 
22381991Sheppo 		/*
22391991Sheppo 		 * reset the channel state if the channel went down
22401991Sheppo 		 * (other side unconfigured queue) or channel was reset
22412793Slm66018 		 * (other side reconfigured its queue)
22421991Sheppo 		 */
22432793Slm66018 
22442793Slm66018 		if (link_state != ldcp->link_state) {
22453010Slm66018 
22462793Slm66018 			switch (ldcp->link_state) {
22472793Slm66018 			case LDC_CHANNEL_DOWN:
22485944Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: channel "
22492793Slm66018 				    "link down\n", ldcp->id);
22502793Slm66018 				mutex_enter(&ldcp->tx_lock);
22512793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
22522793Slm66018 				mutex_exit(&ldcp->tx_lock);
22535944Sha137994 				*notify_client = B_TRUE;
22545944Sha137994 				*notify_event = LDC_EVT_DOWN;
22552793Slm66018 				goto loop_exit;
22562793Slm66018 
22572793Slm66018 			case LDC_CHANNEL_UP:
22585944Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: "
22592793Slm66018 				    "channel link up\n", ldcp->id);
22602793Slm66018 
22612793Slm66018 				if ((ldcp->tstate & ~TS_IN_RESET) == TS_OPEN) {
22625944Sha137994 					*notify_client = B_TRUE;
22635944Sha137994 					*notify_event = LDC_EVT_RESET;
22642793Slm66018 					ldcp->tstate |= TS_LINK_READY;
22652793Slm66018 					ldcp->status = LDC_READY;
22662793Slm66018 				}
22672793Slm66018 				break;
22682793Slm66018 
22692793Slm66018 			case LDC_CHANNEL_RESET:
22702793Slm66018 			default:
22712793Slm66018 #ifdef DEBUG
22722793Slm66018 force_reset:
22732793Slm66018 #endif
22745944Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: channel "
22752793Slm66018 				    "link reset\n", ldcp->id);
22762793Slm66018 				mutex_enter(&ldcp->tx_lock);
22772793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
22782793Slm66018 				mutex_exit(&ldcp->tx_lock);
22795944Sha137994 				*notify_client = B_TRUE;
22805944Sha137994 				*notify_event = LDC_EVT_RESET;
22812793Slm66018 				break;
22822793Slm66018 			}
22831991Sheppo 		}
22842793Slm66018 
22852793Slm66018 #ifdef DEBUG
22862793Slm66018 		if (LDC_INJECT_RESET(ldcp))
22872793Slm66018 			goto force_reset;
22886845Sha137994 		if (LDC_INJECT_DRNGCLEAR(ldcp))
22896845Sha137994 			i_ldc_mem_inject_dring_clear(ldcp);
22902793Slm66018 #endif
22915944Sha137994 		if (trace_length) {
22925944Sha137994 			TRACE_RXHVQ_LENGTH(ldcp, rx_head, rx_tail);
22935944Sha137994 			trace_length = B_FALSE;
22945944Sha137994 		}
22951991Sheppo 
22961991Sheppo 		if (rx_head == rx_tail) {
22975944Sha137994 			D2(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) "
22985944Sha137994 			    "No packets\n", ldcp->id);
22991991Sheppo 			break;
23001991Sheppo 		}
23012793Slm66018 
23025944Sha137994 		D2(ldcp->id, "i_ldc_rx_process_hvq: head=0x%llx, "
23035944Sha137994 		    "tail=0x%llx\n", rx_head, rx_tail);
23045944Sha137994 		DUMP_LDC_PKT(ldcp, "i_ldc_rx_process_hvq rcd",
23051991Sheppo 		    ldcp->rx_q_va + rx_head);
23061991Sheppo 
23071991Sheppo 		/* get the message */
23081991Sheppo 		msg = (ldc_msg_t *)(ldcp->rx_q_va + rx_head);
23091991Sheppo 
23101991Sheppo 		/* if channel is in RAW mode or data pkt, notify and return */
23111991Sheppo 		if (ldcp->mode == LDC_MODE_RAW) {
23125944Sha137994 			*notify_client = B_TRUE;
23135944Sha137994 			*notify_event |= LDC_EVT_READ;
23141991Sheppo 			break;
23151991Sheppo 		}
23161991Sheppo 
23171991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
23181991Sheppo 
23191991Sheppo 			/* discard packet if channel is not up */
23202793Slm66018 			if ((ldcp->tstate & ~TS_IN_RESET) != TS_UP) {
23211991Sheppo 
23221991Sheppo 				/* move the head one position */
23231991Sheppo 				rx_head = (rx_head + LDC_PACKET_SIZE) %
23244690Snarayan 				    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
23251991Sheppo 
23261991Sheppo 				if (rv = i_ldc_set_rx_head(ldcp, rx_head))
23271991Sheppo 					break;
23281991Sheppo 
23291991Sheppo 				continue;
23301991Sheppo 			} else {
23315944Sha137994 				uint64_t dq_head, dq_tail;
23325944Sha137994 
23336408Sha137994 				/* process only RELIABLE mode data packets */
23346408Sha137994 				if (ldcp->mode != LDC_MODE_RELIABLE) {
23355944Sha137994 					if ((ldcp->tstate & TS_IN_RESET) == 0)
23365944Sha137994 						*notify_client = B_TRUE;
23375944Sha137994 					*notify_event |= LDC_EVT_READ;
23385944Sha137994 					break;
23395944Sha137994 				}
23405944Sha137994 
23415944Sha137994 				/* don't process packet if queue full */
23425944Sha137994 				(void) i_ldc_dq_rx_get_state(ldcp, &dq_head,
23435944Sha137994 				    &dq_tail, NULL);
23445944Sha137994 				dq_tail = (dq_tail + LDC_PACKET_SIZE) %
23455944Sha137994 				    (ldcp->rx_dq_entries << LDC_PACKET_SHIFT);
23465944Sha137994 				if (dq_tail == dq_head ||
23475944Sha137994 				    LDC_INJECT_DQFULL(ldcp)) {
23485944Sha137994 					rv = ENOSPC;
23495944Sha137994 					break;
23505944Sha137994 				}
23511991Sheppo 			}
23521991Sheppo 		}
23531991Sheppo 
23541991Sheppo 		/* Check the sequence ID for the message received */
23552793Slm66018 		rv = i_ldc_check_seqid(ldcp, msg);
23562793Slm66018 		if (rv != 0) {
23571991Sheppo 
23585944Sha137994 			DWARN(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) "
23595944Sha137994 			    "seqid error, q_ptrs=0x%lx,0x%lx", ldcp->id,
23605944Sha137994 			    rx_head, rx_tail);
23611991Sheppo 
23621991Sheppo 			/* Reset last_msg_rcd to start of message */
23632336Snarayan 			if (first_fragment != 0) {
23642336Snarayan 				ldcp->last_msg_rcd = first_fragment - 1;
23652336Snarayan 				first_fragment = 0;
23661991Sheppo 			}
23672336Snarayan 
23681991Sheppo 			/*
23691991Sheppo 			 * Send a NACK due to seqid mismatch
23701991Sheppo 			 */
23714690Snarayan 			rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK,
23721991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK));
23731991Sheppo 
23741991Sheppo 			if (rv) {
23755944Sha137994 				cmn_err(CE_NOTE, "i_ldc_rx_process_hvq: "
23765944Sha137994 				    "(0x%lx) err sending CTRL/DATA NACK msg\n",
23775944Sha137994 				    ldcp->id);
23782336Snarayan 
23792336Snarayan 				/* if cannot send NACK - reset channel */
23802336Snarayan 				mutex_enter(&ldcp->tx_lock);
23812793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
23822336Snarayan 				mutex_exit(&ldcp->tx_lock);
23833560Snarayan 
23845944Sha137994 				*notify_client = B_TRUE;
23855944Sha137994 				*notify_event = LDC_EVT_RESET;
23862336Snarayan 				break;
23871991Sheppo 			}
23881991Sheppo 
23891991Sheppo 			/* purge receive queue */
23901991Sheppo 			(void) i_ldc_set_rx_head(ldcp, rx_tail);
23911991Sheppo 			break;
23921991Sheppo 		}
23931991Sheppo 
23941991Sheppo 		/* record the message ID */
23951991Sheppo 		ldcp->last_msg_rcd = msg->seqid;
23961991Sheppo 
23971991Sheppo 		/* process control messages */
23981991Sheppo 		if (msg->type & LDC_CTRL) {
23991991Sheppo 			/* save current internal state */
24001991Sheppo 			uint64_t tstate = ldcp->tstate;
24011991Sheppo 
24021991Sheppo 			rv = i_ldc_ctrlmsg(ldcp, msg);
24031991Sheppo 			if (rv == EAGAIN) {
24041991Sheppo 				/* re-process pkt - state was adjusted */
24051991Sheppo 				continue;
24061991Sheppo 			}
24071991Sheppo 			if (rv == ECONNRESET) {
24085944Sha137994 				*notify_client = B_TRUE;
24095944Sha137994 				*notify_event = LDC_EVT_RESET;
24101991Sheppo 				break;
24111991Sheppo 			}
24121991Sheppo 
24131991Sheppo 			/*
24141991Sheppo 			 * control message processing was successful
24151991Sheppo 			 * channel transitioned to ready for communication
24161991Sheppo 			 */
24171991Sheppo 			if (rv == 0 && ldcp->tstate == TS_UP &&
24182793Slm66018 			    (tstate & ~TS_IN_RESET) !=
24192793Slm66018 			    (ldcp->tstate & ~TS_IN_RESET)) {
24205944Sha137994 				*notify_client = B_TRUE;
24215944Sha137994 				*notify_event = LDC_EVT_UP;
24221991Sheppo 			}
24231991Sheppo 		}
24241991Sheppo 
24253560Snarayan 		/* process data NACKs */
24263560Snarayan 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) {
24273560Snarayan 			DWARN(ldcp->id,
24285944Sha137994 			    "i_ldc_rx_process_hvq: (0x%llx) received DATA/NACK",
24293560Snarayan 			    ldcp->id);
24303560Snarayan 			mutex_enter(&ldcp->tx_lock);
24313560Snarayan 			i_ldc_reset(ldcp, B_TRUE);
24323560Snarayan 			mutex_exit(&ldcp->tx_lock);
24335944Sha137994 			*notify_client = B_TRUE;
24345944Sha137994 			*notify_event = LDC_EVT_RESET;
24353560Snarayan 			break;
24363560Snarayan 		}
24373560Snarayan 
24381991Sheppo 		/* process data ACKs */
24391991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
24402336Snarayan 			if (rv = i_ldc_process_data_ACK(ldcp, msg)) {
24415944Sha137994 				*notify_client = B_TRUE;
24425944Sha137994 				*notify_event = LDC_EVT_RESET;
24432336Snarayan 				break;
24442336Snarayan 			}
24451991Sheppo 		}
24461991Sheppo 
24475944Sha137994 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
24486408Sha137994 			ASSERT(ldcp->mode == LDC_MODE_RELIABLE);
24495944Sha137994 
24505944Sha137994 			/*
24515944Sha137994 			 * Copy the data packet to the data queue. Note
24525944Sha137994 			 * that the copy routine updates the rx_head pointer.
24535944Sha137994 			 */
24545944Sha137994 			i_ldc_rxdq_copy(ldcp, &rx_head);
24555944Sha137994 
24565944Sha137994 			if ((ldcp->tstate & TS_IN_RESET) == 0)
24575944Sha137994 				*notify_client = B_TRUE;
24585944Sha137994 			*notify_event |= LDC_EVT_READ;
24595944Sha137994 		} else {
24605944Sha137994 			rx_head = (rx_head + LDC_PACKET_SIZE) %
24615944Sha137994 			    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
24625944Sha137994 		}
24635944Sha137994 
24641991Sheppo 		/* move the head one position */
24652032Slm66018 		if (rv = i_ldc_set_rx_head(ldcp, rx_head)) {
24665944Sha137994 			*notify_client = B_TRUE;
24675944Sha137994 			*notify_event = LDC_EVT_RESET;
24681991Sheppo 			break;
24692032Slm66018 		}
24701991Sheppo 
24711991Sheppo 	} /* for */
24721991Sheppo 
24732793Slm66018 loop_exit:
24742793Slm66018 
24756408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
24765944Sha137994 		/* ACK data packets */
24775944Sha137994 		if ((*notify_event &
24785944Sha137994 		    (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) {
24795944Sha137994 			int ack_rv;
24805944Sha137994 			ack_rv = i_ldc_send_pkt(ldcp, LDC_DATA, LDC_ACK, 0);
24815944Sha137994 			if (ack_rv && ack_rv != EWOULDBLOCK) {
24825944Sha137994 				cmn_err(CE_NOTE,
24835944Sha137994 				    "i_ldc_rx_process_hvq: (0x%lx) cannot "
24845944Sha137994 				    "send ACK\n", ldcp->id);
24855944Sha137994 
24865944Sha137994 				mutex_enter(&ldcp->tx_lock);
24875944Sha137994 				i_ldc_reset(ldcp, B_FALSE);
24885944Sha137994 				mutex_exit(&ldcp->tx_lock);
24895944Sha137994 
24905944Sha137994 				*notify_client = B_TRUE;
24915944Sha137994 				*notify_event = LDC_EVT_RESET;
24925944Sha137994 				goto skip_ackpeek;
24935944Sha137994 			}
24945944Sha137994 		}
24955944Sha137994 
24965944Sha137994 		/*
24975944Sha137994 		 * If we have no more space on the data queue, make sure
24985944Sha137994 		 * there are no ACKs on the rx queue waiting to be processed.
24995944Sha137994 		 */
25005944Sha137994 		if (rv == ENOSPC) {
25015944Sha137994 			if (i_ldc_rx_ackpeek(ldcp, rx_head, rx_tail) != 0) {
25025944Sha137994 				ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
25035944Sha137994 				*notify_client = B_TRUE;
25045944Sha137994 				*notify_event = LDC_EVT_RESET;
25055944Sha137994 			}
25066944Sha137994 			return (rv);
25075944Sha137994 		} else {
25085944Sha137994 			ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
25091991Sheppo 		}
25105944Sha137994 	}
25115944Sha137994 
25125944Sha137994 skip_ackpeek:
25135944Sha137994 
25145944Sha137994 	/* Return, indicating whether or not data packets were found */
25155944Sha137994 	if ((*notify_event & (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ)
25165944Sha137994 		return (0);
25175944Sha137994 
25185944Sha137994 	return (ENOMSG);
25191991Sheppo }
25201991Sheppo 
25215944Sha137994 /*
25225944Sha137994  * Process any ACK packets on the HV receive queue.
25235944Sha137994  *
25246408Sha137994  * This function is only used by RELIABLE mode channels when the
25255944Sha137994  * secondary data queue fills up and there are packets remaining on
25265944Sha137994  * the HV receive queue.
25275944Sha137994  */
25285944Sha137994 int
25295944Sha137994 i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, uint64_t rx_tail)
25305944Sha137994 {
25315944Sha137994 	int		rv = 0;
25325944Sha137994 	ldc_msg_t	*msg;
25335944Sha137994 
25345944Sha137994 	if (ldcp->rx_ack_head == ACKPEEK_HEAD_INVALID)
25355944Sha137994 		ldcp->rx_ack_head = rx_head;
25365944Sha137994 
25375944Sha137994 	while (ldcp->rx_ack_head != rx_tail) {
25385944Sha137994 		msg = (ldc_msg_t *)(ldcp->rx_q_va + ldcp->rx_ack_head);
25395944Sha137994 
25405944Sha137994 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
25415944Sha137994 			if (rv = i_ldc_process_data_ACK(ldcp, msg))
25425944Sha137994 				break;
25435944Sha137994 			msg->stype &= ~LDC_ACK;
25445944Sha137994 		}
25455944Sha137994 
25465944Sha137994 		ldcp->rx_ack_head =
25475944Sha137994 		    (ldcp->rx_ack_head + LDC_PACKET_SIZE) %
25485944Sha137994 		    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
25495944Sha137994 	}
25505944Sha137994 	return (rv);
25515944Sha137994 }
25521991Sheppo 
25531991Sheppo /* -------------------------------------------------------------------------- */
25541991Sheppo 
25551991Sheppo /*
25561991Sheppo  * LDC API functions
25571991Sheppo  */
25581991Sheppo 
25591991Sheppo /*
25601991Sheppo  * Initialize the channel. Allocate internal structure and memory for
25611991Sheppo  * TX/RX queues, and initialize locks.
25621991Sheppo  */
25631991Sheppo int
25641991Sheppo ldc_init(uint64_t id, ldc_attr_t *attr, ldc_handle_t *handle)
25651991Sheppo {
25661991Sheppo 	ldc_chan_t 	*ldcp;
25671991Sheppo 	int		rv, exit_val;
25681991Sheppo 	uint64_t	ra_base, nentries;
25692410Slm66018 	uint64_t	qlen;
25701991Sheppo 
25711991Sheppo 	exit_val = EINVAL;	/* guarantee an error if exit on failure */
25721991Sheppo 
25731991Sheppo 	if (attr == NULL) {
25741991Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid attr\n", id);
25751991Sheppo 		return (EINVAL);
25761991Sheppo 	}
25771991Sheppo 	if (handle == NULL) {
25781991Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid handle\n", id);
25791991Sheppo 		return (EINVAL);
25801991Sheppo 	}
25811991Sheppo 
25821991Sheppo 	/* check if channel is valid */
25831991Sheppo 	rv = hv_ldc_tx_qinfo(id, &ra_base, &nentries);
25841991Sheppo 	if (rv == H_ECHANNEL) {
25851991Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid channel id\n", id);
25861991Sheppo 		return (EINVAL);
25871991Sheppo 	}
25881991Sheppo 
25891991Sheppo 	/* check if the channel has already been initialized */
25901991Sheppo 	mutex_enter(&ldcssp->lock);
25911991Sheppo 	ldcp = ldcssp->chan_list;
25921991Sheppo 	while (ldcp != NULL) {
25931991Sheppo 		if (ldcp->id == id) {
25941991Sheppo 			DWARN(id, "ldc_init: (0x%llx) already initialized\n",
25951991Sheppo 			    id);
25961991Sheppo 			mutex_exit(&ldcssp->lock);
25971991Sheppo 			return (EADDRINUSE);
25981991Sheppo 		}
25991991Sheppo 		ldcp = ldcp->next;
26001991Sheppo 	}
26011991Sheppo 	mutex_exit(&ldcssp->lock);
26021991Sheppo 
26031991Sheppo 	ASSERT(ldcp == NULL);
26041991Sheppo 
26051991Sheppo 	*handle = 0;
26061991Sheppo 
26071991Sheppo 	/* Allocate an ldcp structure */
26081991Sheppo 	ldcp = kmem_zalloc(sizeof (ldc_chan_t), KM_SLEEP);
26091991Sheppo 
26102336Snarayan 	/*
26112336Snarayan 	 * Initialize the channel and Tx lock
26122336Snarayan 	 *
26132336Snarayan 	 * The channel 'lock' protects the entire channel and
26142336Snarayan 	 * should be acquired before initializing, resetting,
26152336Snarayan 	 * destroying or reading from a channel.
26162336Snarayan 	 *
26172336Snarayan 	 * The 'tx_lock' should be acquired prior to transmitting
26182336Snarayan 	 * data over the channel. The lock should also be acquired
26192336Snarayan 	 * prior to channel reconfiguration (in order to prevent
26202336Snarayan 	 * concurrent writes).
26212336Snarayan 	 *
26222336Snarayan 	 * ORDERING: When both locks are being acquired, to prevent
26232336Snarayan 	 * deadlocks, the channel lock should be always acquired prior
26242336Snarayan 	 * to the tx_lock.
26252336Snarayan 	 */
26261991Sheppo 	mutex_init(&ldcp->lock, NULL, MUTEX_DRIVER, NULL);
26272336Snarayan 	mutex_init(&ldcp->tx_lock, NULL, MUTEX_DRIVER, NULL);
26281991Sheppo 
26291991Sheppo 	/* Initialize the channel */
26301991Sheppo 	ldcp->id = id;
26311991Sheppo 	ldcp->cb = NULL;
26321991Sheppo 	ldcp->cb_arg = NULL;
26331991Sheppo 	ldcp->cb_inprogress = B_FALSE;
26341991Sheppo 	ldcp->cb_enabled = B_FALSE;
26351991Sheppo 	ldcp->next = NULL;
26361991Sheppo 
26371991Sheppo 	/* Read attributes */
26381991Sheppo 	ldcp->mode = attr->mode;
26391991Sheppo 	ldcp->devclass = attr->devclass;
26401991Sheppo 	ldcp->devinst = attr->instance;
26412410Slm66018 	ldcp->mtu = (attr->mtu > 0) ? attr->mtu : LDC_DEFAULT_MTU;
26421991Sheppo 
26431991Sheppo 	D1(ldcp->id,
26441991Sheppo 	    "ldc_init: (0x%llx) channel attributes, class=0x%x, "
26452410Slm66018 	    "instance=0x%llx, mode=%d, mtu=%d\n",
26462410Slm66018 	    ldcp->id, ldcp->devclass, ldcp->devinst, ldcp->mode, ldcp->mtu);
26471991Sheppo 
26481991Sheppo 	ldcp->next_vidx = 0;
26492793Slm66018 	ldcp->tstate = TS_IN_RESET;
26501991Sheppo 	ldcp->hstate = 0;
26511991Sheppo 	ldcp->last_msg_snt = LDC_INIT_SEQID;
26521991Sheppo 	ldcp->last_ack_rcd = 0;
26531991Sheppo 	ldcp->last_msg_rcd = 0;
26545944Sha137994 	ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
26551991Sheppo 
26561991Sheppo 	ldcp->stream_bufferp = NULL;
26571991Sheppo 	ldcp->exp_dring_list = NULL;
26581991Sheppo 	ldcp->imp_dring_list = NULL;
26591991Sheppo 	ldcp->mhdl_list = NULL;
26601991Sheppo 
26612793Slm66018 	ldcp->tx_intr_state = LDC_INTR_NONE;
26622793Slm66018 	ldcp->rx_intr_state = LDC_INTR_NONE;
26632793Slm66018 
26641991Sheppo 	/* Initialize payload size depending on whether channel is reliable */
26651991Sheppo 	switch (ldcp->mode) {
26661991Sheppo 	case LDC_MODE_RAW:
26671991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RAW;
26681991Sheppo 		ldcp->read_p = i_ldc_read_raw;
26691991Sheppo 		ldcp->write_p = i_ldc_write_raw;
26701991Sheppo 		break;
26711991Sheppo 	case LDC_MODE_UNRELIABLE:
26721991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_UNRELIABLE;
26731991Sheppo 		ldcp->read_p = i_ldc_read_packet;
26741991Sheppo 		ldcp->write_p = i_ldc_write_packet;
26751991Sheppo 		break;
26761991Sheppo 	case LDC_MODE_RELIABLE:
26771991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE;
26781991Sheppo 
26791991Sheppo 		ldcp->stream_remains = 0;
26801991Sheppo 		ldcp->stream_offset = 0;
26811991Sheppo 		ldcp->stream_bufferp = kmem_alloc(ldcp->mtu, KM_SLEEP);
26821991Sheppo 		ldcp->read_p = i_ldc_read_stream;
26831991Sheppo 		ldcp->write_p = i_ldc_write_stream;
26841991Sheppo 		break;
26851991Sheppo 	default:
26861991Sheppo 		exit_val = EINVAL;
26871991Sheppo 		goto cleanup_on_exit;
26881991Sheppo 	}
26891991Sheppo 
26902410Slm66018 	/*
26912410Slm66018 	 * qlen is (mtu * ldc_mtu_msgs) / pkt_payload. If this
26922410Slm66018 	 * value is smaller than default length of ldc_queue_entries,
26934690Snarayan 	 * qlen is set to ldc_queue_entries. Ensure that computed
26944690Snarayan 	 * length is a power-of-two value.
26952410Slm66018 	 */
26962410Slm66018 	qlen = (ldcp->mtu * ldc_mtu_msgs) / ldcp->pkt_payload;
26974690Snarayan 	if (!ISP2(qlen)) {
26984690Snarayan 		uint64_t	tmp = 1;
26994690Snarayan 		while (qlen) {
27004690Snarayan 			qlen >>= 1; tmp <<= 1;
27014690Snarayan 		}
27024690Snarayan 		qlen = tmp;
27034690Snarayan 	}
27044690Snarayan 
27052410Slm66018 	ldcp->rx_q_entries =
27064690Snarayan 	    (qlen < ldc_queue_entries) ? ldc_queue_entries : qlen;
27072410Slm66018 	ldcp->tx_q_entries = ldcp->rx_q_entries;
27082410Slm66018 
27094690Snarayan 	D1(ldcp->id, "ldc_init: queue length = 0x%llx\n", ldcp->rx_q_entries);
27102410Slm66018 
27111991Sheppo 	/* Create a transmit queue */
27121991Sheppo 	ldcp->tx_q_va = (uint64_t)
27134690Snarayan 	    contig_mem_alloc(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
27141991Sheppo 	if (ldcp->tx_q_va == NULL) {
27151991Sheppo 		cmn_err(CE_WARN,
27161991Sheppo 		    "ldc_init: (0x%lx) TX queue allocation failed\n",
27171991Sheppo 		    ldcp->id);
27181991Sheppo 		exit_val = ENOMEM;
27191991Sheppo 		goto cleanup_on_exit;
27201991Sheppo 	}
27211991Sheppo 	ldcp->tx_q_ra = va_to_pa((caddr_t)ldcp->tx_q_va);
27221991Sheppo 
27231991Sheppo 	D2(ldcp->id, "ldc_init: txq_va=0x%llx, txq_ra=0x%llx, entries=0x%llx\n",
27241991Sheppo 	    ldcp->tx_q_va, ldcp->tx_q_ra, ldcp->tx_q_entries);
27251991Sheppo 
27261991Sheppo 	ldcp->tstate |= TS_TXQ_RDY;
27271991Sheppo 
27281991Sheppo 	/* Create a receive queue */
27291991Sheppo 	ldcp->rx_q_va = (uint64_t)
27304690Snarayan 	    contig_mem_alloc(ldcp->rx_q_entries << LDC_PACKET_SHIFT);
27311991Sheppo 	if (ldcp->rx_q_va == NULL) {
27321991Sheppo 		cmn_err(CE_WARN,
27331991Sheppo 		    "ldc_init: (0x%lx) RX queue allocation failed\n",
27341991Sheppo 		    ldcp->id);
27351991Sheppo 		exit_val = ENOMEM;
27361991Sheppo 		goto cleanup_on_exit;
27371991Sheppo 	}
27381991Sheppo 	ldcp->rx_q_ra = va_to_pa((caddr_t)ldcp->rx_q_va);
27391991Sheppo 
27401991Sheppo 	D2(ldcp->id, "ldc_init: rxq_va=0x%llx, rxq_ra=0x%llx, entries=0x%llx\n",
27411991Sheppo 	    ldcp->rx_q_va, ldcp->rx_q_ra, ldcp->rx_q_entries);
27421991Sheppo 
27431991Sheppo 	ldcp->tstate |= TS_RXQ_RDY;
27441991Sheppo 
27455944Sha137994 	/* Setup a separate read data queue */
27466408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
27475944Sha137994 		ldcp->readq_get_state = i_ldc_dq_rx_get_state;
27485944Sha137994 		ldcp->readq_set_head  = i_ldc_set_rxdq_head;
27495944Sha137994 
27505944Sha137994 		/* Make sure the data queue multiplier is a power of 2 */
27515944Sha137994 		if (!ISP2(ldc_rxdq_multiplier)) {
27525944Sha137994 			D1(ldcp->id, "ldc_init: (0x%llx) ldc_rxdq_multiplier "
27535944Sha137994 			    "not a power of 2, resetting", ldcp->id);
27545944Sha137994 			ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER;
27555944Sha137994 		}
27565944Sha137994 
27575944Sha137994 		ldcp->rx_dq_entries = ldc_rxdq_multiplier * ldcp->rx_q_entries;
27585944Sha137994 		ldcp->rx_dq_va = (uint64_t)
27595944Sha137994 		    kmem_alloc(ldcp->rx_dq_entries << LDC_PACKET_SHIFT,
27605944Sha137994 		    KM_SLEEP);
27615944Sha137994 		if (ldcp->rx_dq_va == NULL) {
27625944Sha137994 			cmn_err(CE_WARN,
27635944Sha137994 			    "ldc_init: (0x%lx) RX data queue "
27645944Sha137994 			    "allocation failed\n", ldcp->id);
27655944Sha137994 			exit_val = ENOMEM;
27665944Sha137994 			goto cleanup_on_exit;
27675944Sha137994 		}
27685944Sha137994 
27695944Sha137994 		ldcp->rx_dq_head = ldcp->rx_dq_tail = 0;
27705944Sha137994 
27715944Sha137994 		D2(ldcp->id, "ldc_init: rx_dq_va=0x%llx, "
27725944Sha137994 		    "rx_dq_entries=0x%llx\n", ldcp->rx_dq_va,
27735944Sha137994 		    ldcp->rx_dq_entries);
27745944Sha137994 	} else {
27755944Sha137994 		ldcp->readq_get_state = i_ldc_hvq_rx_get_state;
27765944Sha137994 		ldcp->readq_set_head  = i_ldc_set_rx_head;
27775944Sha137994 	}
27785944Sha137994 
27791991Sheppo 	/* Init descriptor ring and memory handle list lock */
27801991Sheppo 	mutex_init(&ldcp->exp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
27811991Sheppo 	mutex_init(&ldcp->imp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
27821991Sheppo 	mutex_init(&ldcp->mlist_lock, NULL, MUTEX_DRIVER, NULL);
27831991Sheppo 
27841991Sheppo 	/* mark status as INITialized */
27851991Sheppo 	ldcp->status = LDC_INIT;
27861991Sheppo 
27871991Sheppo 	/* Add to channel list */
27881991Sheppo 	mutex_enter(&ldcssp->lock);
27891991Sheppo 	ldcp->next = ldcssp->chan_list;
27901991Sheppo 	ldcssp->chan_list = ldcp;
27911991Sheppo 	ldcssp->channel_count++;
27921991Sheppo 	mutex_exit(&ldcssp->lock);
27931991Sheppo 
27941991Sheppo 	/* set the handle */
27951991Sheppo 	*handle = (ldc_handle_t)ldcp;
27961991Sheppo 
27971991Sheppo 	D1(ldcp->id, "ldc_init: (0x%llx) channel initialized\n", ldcp->id);
27981991Sheppo 
27991991Sheppo 	return (0);
28001991Sheppo 
28011991Sheppo cleanup_on_exit:
28021991Sheppo 
28036408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp)
28041991Sheppo 		kmem_free(ldcp->stream_bufferp, ldcp->mtu);
28051991Sheppo 
28061991Sheppo 	if (ldcp->tstate & TS_TXQ_RDY)
28071991Sheppo 		contig_mem_free((caddr_t)ldcp->tx_q_va,
28081991Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
28091991Sheppo 
28101991Sheppo 	if (ldcp->tstate & TS_RXQ_RDY)
28111991Sheppo 		contig_mem_free((caddr_t)ldcp->rx_q_va,
28121991Sheppo 		    (ldcp->rx_q_entries << LDC_PACKET_SHIFT));
28131991Sheppo 
28142336Snarayan 	mutex_destroy(&ldcp->tx_lock);
28151991Sheppo 	mutex_destroy(&ldcp->lock);
28161991Sheppo 
28171991Sheppo 	if (ldcp)
28181991Sheppo 		kmem_free(ldcp, sizeof (ldc_chan_t));
28191991Sheppo 
28201991Sheppo 	return (exit_val);
28211991Sheppo }
28221991Sheppo 
28231991Sheppo /*
28241991Sheppo  * Finalizes the LDC connection. It will return EBUSY if the
28251991Sheppo  * channel is open. A ldc_close() has to be done prior to
28261991Sheppo  * a ldc_fini operation. It frees TX/RX queues, associated
28271991Sheppo  * with the channel
28281991Sheppo  */
28291991Sheppo int
28301991Sheppo ldc_fini(ldc_handle_t handle)
28311991Sheppo {
28321991Sheppo 	ldc_chan_t 	*ldcp;
28331991Sheppo 	ldc_chan_t 	*tmp_ldcp;
28341991Sheppo 	uint64_t 	id;
28351991Sheppo 
28361991Sheppo 	if (handle == NULL) {
28371991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel handle\n");
28381991Sheppo 		return (EINVAL);
28391991Sheppo 	}
28401991Sheppo 	ldcp = (ldc_chan_t *)handle;
28411991Sheppo 	id = ldcp->id;
28421991Sheppo 
28431991Sheppo 	mutex_enter(&ldcp->lock);
28441991Sheppo 
28452793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) > TS_INIT) {
28461991Sheppo 		DWARN(ldcp->id, "ldc_fini: (0x%llx) channel is open\n",
28471991Sheppo 		    ldcp->id);
28481991Sheppo 		mutex_exit(&ldcp->lock);
28491991Sheppo 		return (EBUSY);
28501991Sheppo 	}
28511991Sheppo 
28521991Sheppo 	/* Remove from the channel list */
28531991Sheppo 	mutex_enter(&ldcssp->lock);
28541991Sheppo 	tmp_ldcp = ldcssp->chan_list;
28551991Sheppo 	if (tmp_ldcp == ldcp) {
28561991Sheppo 		ldcssp->chan_list = ldcp->next;
28571991Sheppo 		ldcp->next = NULL;
28581991Sheppo 	} else {
28591991Sheppo 		while (tmp_ldcp != NULL) {
28601991Sheppo 			if (tmp_ldcp->next == ldcp) {
28611991Sheppo 				tmp_ldcp->next = ldcp->next;
28621991Sheppo 				ldcp->next = NULL;
28631991Sheppo 				break;
28641991Sheppo 			}
28651991Sheppo 			tmp_ldcp = tmp_ldcp->next;
28661991Sheppo 		}
28671991Sheppo 		if (tmp_ldcp == NULL) {
28681991Sheppo 			DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel hdl\n");
28691991Sheppo 			mutex_exit(&ldcssp->lock);
28701991Sheppo 			mutex_exit(&ldcp->lock);
28711991Sheppo 			return (EINVAL);
28721991Sheppo 		}
28731991Sheppo 	}
28741991Sheppo 
28751991Sheppo 	ldcssp->channel_count--;
28761991Sheppo 
28771991Sheppo 	mutex_exit(&ldcssp->lock);
28781991Sheppo 
28791991Sheppo 	/* Free the map table for this channel */
28801991Sheppo 	if (ldcp->mtbl) {
28811991Sheppo 		(void) hv_ldc_set_map_table(ldcp->id, NULL, NULL);
28822793Slm66018 		if (ldcp->mtbl->contigmem)
28832793Slm66018 			contig_mem_free(ldcp->mtbl->table, ldcp->mtbl->size);
28842793Slm66018 		else
28852793Slm66018 			kmem_free(ldcp->mtbl->table, ldcp->mtbl->size);
28861991Sheppo 		mutex_destroy(&ldcp->mtbl->lock);
28871991Sheppo 		kmem_free(ldcp->mtbl, sizeof (ldc_mtbl_t));
28881991Sheppo 	}
28891991Sheppo 
28901991Sheppo 	/* Destroy descriptor ring and memory handle list lock */
28911991Sheppo 	mutex_destroy(&ldcp->exp_dlist_lock);
28921991Sheppo 	mutex_destroy(&ldcp->imp_dlist_lock);
28931991Sheppo 	mutex_destroy(&ldcp->mlist_lock);
28941991Sheppo 
28956408Sha137994 	/* Free the stream buffer for RELIABLE_MODE */
28966408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp)
28971991Sheppo 		kmem_free(ldcp->stream_bufferp, ldcp->mtu);
28981991Sheppo 
28991991Sheppo 	/* Free the RX queue */
29001991Sheppo 	contig_mem_free((caddr_t)ldcp->rx_q_va,
29011991Sheppo 	    (ldcp->rx_q_entries << LDC_PACKET_SHIFT));
29021991Sheppo 	ldcp->tstate &= ~TS_RXQ_RDY;
29031991Sheppo 
29045944Sha137994 	/* Free the RX data queue */
29056408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
29065944Sha137994 		kmem_free((caddr_t)ldcp->rx_dq_va,
29075944Sha137994 		    (ldcp->rx_dq_entries << LDC_PACKET_SHIFT));
29085944Sha137994 	}
29095944Sha137994 
29101991Sheppo 	/* Free the TX queue */
29111991Sheppo 	contig_mem_free((caddr_t)ldcp->tx_q_va,
29121991Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
29131991Sheppo 	ldcp->tstate &= ~TS_TXQ_RDY;
29141991Sheppo 
29151991Sheppo 	mutex_exit(&ldcp->lock);
29161991Sheppo 
29171991Sheppo 	/* Destroy mutex */
29182336Snarayan 	mutex_destroy(&ldcp->tx_lock);
29191991Sheppo 	mutex_destroy(&ldcp->lock);
29201991Sheppo 
29211991Sheppo 	/* free channel structure */
29221991Sheppo 	kmem_free(ldcp, sizeof (ldc_chan_t));
29231991Sheppo 
29241991Sheppo 	D1(id, "ldc_fini: (0x%llx) channel finalized\n", id);
29251991Sheppo 
29261991Sheppo 	return (0);
29271991Sheppo }
29281991Sheppo 
29291991Sheppo /*
29301991Sheppo  * Open the LDC channel for use. It registers the TX/RX queues
29311991Sheppo  * with the Hypervisor. It also specifies the interrupt number
29321991Sheppo  * and target CPU for this channel
29331991Sheppo  */
29341991Sheppo int
29351991Sheppo ldc_open(ldc_handle_t handle)
29361991Sheppo {
29371991Sheppo 	ldc_chan_t 	*ldcp;
29381991Sheppo 	int 		rv;
29391991Sheppo 
29401991Sheppo 	if (handle == NULL) {
29411991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_open: invalid channel handle\n");
29421991Sheppo 		return (EINVAL);
29431991Sheppo 	}
29441991Sheppo 
29451991Sheppo 	ldcp = (ldc_chan_t *)handle;
29461991Sheppo 
29471991Sheppo 	mutex_enter(&ldcp->lock);
29481991Sheppo 
29491991Sheppo 	if (ldcp->tstate < TS_INIT) {
29501991Sheppo 		DWARN(ldcp->id,
29511991Sheppo 		    "ldc_open: (0x%llx) channel not initialized\n", ldcp->id);
29521991Sheppo 		mutex_exit(&ldcp->lock);
29531991Sheppo 		return (EFAULT);
29541991Sheppo 	}
29552793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) >= TS_OPEN) {
29561991Sheppo 		DWARN(ldcp->id,
29571991Sheppo 		    "ldc_open: (0x%llx) channel is already open\n", ldcp->id);
29581991Sheppo 		mutex_exit(&ldcp->lock);
29591991Sheppo 		return (EFAULT);
29601991Sheppo 	}
29611991Sheppo 
29621991Sheppo 	/*
29631991Sheppo 	 * Unregister/Register the tx queue with the hypervisor
29641991Sheppo 	 */
29651991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
29661991Sheppo 	if (rv) {
29671991Sheppo 		cmn_err(CE_WARN,
29681991Sheppo 		    "ldc_open: (0x%lx) channel tx queue unconf failed\n",
29691991Sheppo 		    ldcp->id);
29701991Sheppo 		mutex_exit(&ldcp->lock);
29711991Sheppo 		return (EIO);
29721991Sheppo 	}
29731991Sheppo 
29741991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
29751991Sheppo 	if (rv) {
29761991Sheppo 		cmn_err(CE_WARN,
29771991Sheppo 		    "ldc_open: (0x%lx) channel tx queue conf failed\n",
29781991Sheppo 		    ldcp->id);
29791991Sheppo 		mutex_exit(&ldcp->lock);
29801991Sheppo 		return (EIO);
29811991Sheppo 	}
29821991Sheppo 
29831991Sheppo 	D2(ldcp->id, "ldc_open: (0x%llx) registered tx queue with LDC\n",
29841991Sheppo 	    ldcp->id);
29851991Sheppo 
29861991Sheppo 	/*
29871991Sheppo 	 * Unregister/Register the rx queue with the hypervisor
29881991Sheppo 	 */
29891991Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
29901991Sheppo 	if (rv) {
29911991Sheppo 		cmn_err(CE_WARN,
29921991Sheppo 		    "ldc_open: (0x%lx) channel rx queue unconf failed\n",
29931991Sheppo 		    ldcp->id);
29941991Sheppo 		mutex_exit(&ldcp->lock);
29951991Sheppo 		return (EIO);
29961991Sheppo 	}
29971991Sheppo 
29981991Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, ldcp->rx_q_entries);
29991991Sheppo 	if (rv) {
30001991Sheppo 		cmn_err(CE_WARN,
30011991Sheppo 		    "ldc_open: (0x%lx) channel rx queue conf failed\n",
30021991Sheppo 		    ldcp->id);
30031991Sheppo 		mutex_exit(&ldcp->lock);
30041991Sheppo 		return (EIO);
30051991Sheppo 	}
30061991Sheppo 
30071991Sheppo 	D2(ldcp->id, "ldc_open: (0x%llx) registered rx queue with LDC\n",
30081991Sheppo 	    ldcp->id);
30091991Sheppo 
30101991Sheppo 	ldcp->tstate |= TS_QCONF_RDY;
30111991Sheppo 
30121991Sheppo 	/* Register the channel with the channel nexus */
30131991Sheppo 	rv = i_ldc_register_channel(ldcp);
30141991Sheppo 	if (rv && rv != EAGAIN) {
30151991Sheppo 		cmn_err(CE_WARN,
30161991Sheppo 		    "ldc_open: (0x%lx) channel register failed\n", ldcp->id);
30178542SHaik.Aftandilian@Sun.COM 		ldcp->tstate &= ~TS_QCONF_RDY;
30181991Sheppo 		(void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
30191991Sheppo 		(void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
30201991Sheppo 		mutex_exit(&ldcp->lock);
30211991Sheppo 		return (EIO);
30221991Sheppo 	}
30231991Sheppo 
30241991Sheppo 	/* mark channel in OPEN state */
30251991Sheppo 	ldcp->status = LDC_OPEN;
30261991Sheppo 
30271991Sheppo 	/* Read channel state */
30281991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
30291991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
30301991Sheppo 	if (rv) {
30311991Sheppo 		cmn_err(CE_WARN,
30321991Sheppo 		    "ldc_open: (0x%lx) cannot read channel state\n",
30331991Sheppo 		    ldcp->id);
30341991Sheppo 		(void) i_ldc_unregister_channel(ldcp);
30358542SHaik.Aftandilian@Sun.COM 		ldcp->tstate &= ~TS_QCONF_RDY;
30361991Sheppo 		(void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
30371991Sheppo 		(void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
30381991Sheppo 		mutex_exit(&ldcp->lock);
30391991Sheppo 		return (EIO);
30401991Sheppo 	}
30411991Sheppo 
30421991Sheppo 	/*
30436408Sha137994 	 * set the ACKd head to current head location for reliable
30441991Sheppo 	 */
30451991Sheppo 	ldcp->tx_ackd_head = ldcp->tx_head;
30461991Sheppo 
30471991Sheppo 	/* mark channel ready if HV report link is UP (peer alloc'd Rx queue) */
30481991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_UP ||
30491991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
30501991Sheppo 		ldcp->tstate |= TS_LINK_READY;
30511991Sheppo 		ldcp->status = LDC_READY;
30521991Sheppo 	}
30531991Sheppo 
30541991Sheppo 	/*
30551991Sheppo 	 * if channel is being opened in RAW mode - no handshake is needed
30561991Sheppo 	 * switch the channel READY and UP state
30571991Sheppo 	 */
30581991Sheppo 	if (ldcp->mode == LDC_MODE_RAW) {
30591991Sheppo 		ldcp->tstate = TS_UP;	/* set bits associated with LDC UP */
30601991Sheppo 		ldcp->status = LDC_UP;
30611991Sheppo 	}
30621991Sheppo 
30631991Sheppo 	mutex_exit(&ldcp->lock);
30641991Sheppo 
30651991Sheppo 	/*
30661991Sheppo 	 * Increment number of open channels
30671991Sheppo 	 */
30681991Sheppo 	mutex_enter(&ldcssp->lock);
30691991Sheppo 	ldcssp->channels_open++;
30701991Sheppo 	mutex_exit(&ldcssp->lock);
30711991Sheppo 
30723010Slm66018 	D1(ldcp->id,
30732793Slm66018 	    "ldc_open: (0x%llx) channel (0x%p) open for use "
30742793Slm66018 	    "(tstate=0x%x, status=0x%x)\n",
30752793Slm66018 	    ldcp->id, ldcp, ldcp->tstate, ldcp->status);
30761991Sheppo 
30771991Sheppo 	return (0);
30781991Sheppo }
30791991Sheppo 
30801991Sheppo /*
30811991Sheppo  * Close the LDC connection. It will return EBUSY if there
30821991Sheppo  * are memory segments or descriptor rings either bound to or
30831991Sheppo  * mapped over the channel
30841991Sheppo  */
30851991Sheppo int
30861991Sheppo ldc_close(ldc_handle_t handle)
30871991Sheppo {
30881991Sheppo 	ldc_chan_t 	*ldcp;
30892336Snarayan 	int		rv = 0, retries = 0;
30901991Sheppo 	boolean_t	chk_done = B_FALSE;
30911991Sheppo 
30921991Sheppo 	if (handle == NULL) {
30931991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_close: invalid channel handle\n");
30941991Sheppo 		return (EINVAL);
30951991Sheppo 	}
30961991Sheppo 	ldcp = (ldc_chan_t *)handle;
30971991Sheppo 
30981991Sheppo 	mutex_enter(&ldcp->lock);
30991991Sheppo 
31001991Sheppo 	/* return error if channel is not open */
31012793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) < TS_OPEN) {
31021991Sheppo 		DWARN(ldcp->id,
31031991Sheppo 		    "ldc_close: (0x%llx) channel is not open\n", ldcp->id);
31041991Sheppo 		mutex_exit(&ldcp->lock);
31051991Sheppo 		return (EFAULT);
31061991Sheppo 	}
31071991Sheppo 
31081991Sheppo 	/* if any memory handles, drings, are bound or mapped cannot close */
31091991Sheppo 	if (ldcp->mhdl_list != NULL) {
31101991Sheppo 		DWARN(ldcp->id,
31111991Sheppo 		    "ldc_close: (0x%llx) channel has bound memory handles\n",
31121991Sheppo 		    ldcp->id);
31131991Sheppo 		mutex_exit(&ldcp->lock);
31141991Sheppo 		return (EBUSY);
31151991Sheppo 	}
31161991Sheppo 	if (ldcp->exp_dring_list != NULL) {
31171991Sheppo 		DWARN(ldcp->id,
31181991Sheppo 		    "ldc_close: (0x%llx) channel has bound descriptor rings\n",
31191991Sheppo 		    ldcp->id);
31201991Sheppo 		mutex_exit(&ldcp->lock);
31211991Sheppo 		return (EBUSY);
31221991Sheppo 	}
31231991Sheppo 	if (ldcp->imp_dring_list != NULL) {
31241991Sheppo 		DWARN(ldcp->id,
31251991Sheppo 		    "ldc_close: (0x%llx) channel has mapped descriptor rings\n",
31261991Sheppo 		    ldcp->id);
31271991Sheppo 		mutex_exit(&ldcp->lock);
31281991Sheppo 		return (EBUSY);
31291991Sheppo 	}
31301991Sheppo 
31313151Ssg70180 	if (ldcp->cb_inprogress) {
31323151Ssg70180 		DWARN(ldcp->id, "ldc_close: (0x%llx) callback active\n",
31333151Ssg70180 		    ldcp->id);
31343151Ssg70180 		mutex_exit(&ldcp->lock);
31353151Ssg70180 		return (EWOULDBLOCK);
31363151Ssg70180 	}
31373151Ssg70180 
31382336Snarayan 	/* Obtain Tx lock */
31392336Snarayan 	mutex_enter(&ldcp->tx_lock);
31402336Snarayan 
31411991Sheppo 	/*
31421991Sheppo 	 * Wait for pending transmits to complete i.e Tx queue to drain
31431991Sheppo 	 * if there are pending pkts - wait 1 ms and retry again
31441991Sheppo 	 */
31451991Sheppo 	for (;;) {
31461991Sheppo 
31471991Sheppo 		rv = hv_ldc_tx_get_state(ldcp->id,
31481991Sheppo 		    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
31491991Sheppo 		if (rv) {
31501991Sheppo 			cmn_err(CE_WARN,
31511991Sheppo 			    "ldc_close: (0x%lx) cannot read qptrs\n", ldcp->id);
31522336Snarayan 			mutex_exit(&ldcp->tx_lock);
31531991Sheppo 			mutex_exit(&ldcp->lock);
31541991Sheppo 			return (EIO);
31551991Sheppo 		}
31561991Sheppo 
31571991Sheppo 		if (ldcp->tx_head == ldcp->tx_tail ||
31581991Sheppo 		    ldcp->link_state != LDC_CHANNEL_UP) {
31591991Sheppo 			break;
31601991Sheppo 		}
31611991Sheppo 
31621991Sheppo 		if (chk_done) {
31631991Sheppo 			DWARN(ldcp->id,
31641991Sheppo 			    "ldc_close: (0x%llx) Tx queue drain timeout\n",
31651991Sheppo 			    ldcp->id);
31661991Sheppo 			break;
31671991Sheppo 		}
31681991Sheppo 
31691991Sheppo 		/* wait for one ms and try again */
31701991Sheppo 		delay(drv_usectohz(1000));
31711991Sheppo 		chk_done = B_TRUE;
31721991Sheppo 	}
31731991Sheppo 
31741991Sheppo 	/*
31752841Snarayan 	 * Drain the Tx and Rx queues as we are closing the
31762841Snarayan 	 * channel. We dont care about any pending packets.
31772841Snarayan 	 * We have to also drain the queue prior to clearing
31782841Snarayan 	 * pending interrupts, otherwise the HV will trigger
31792841Snarayan 	 * an interrupt the moment the interrupt state is
31802841Snarayan 	 * cleared.
31812793Slm66018 	 */
31822793Slm66018 	(void) i_ldc_txq_reconf(ldcp);
3183*10055SKevin.Crowe@Sun.COM 	i_ldc_rxq_drain(ldcp);
31842793Slm66018 
31852793Slm66018 	/*
31861991Sheppo 	 * Unregister the channel with the nexus
31871991Sheppo 	 */
31882336Snarayan 	while ((rv = i_ldc_unregister_channel(ldcp)) != 0) {
31892336Snarayan 
31902336Snarayan 		mutex_exit(&ldcp->tx_lock);
31911991Sheppo 		mutex_exit(&ldcp->lock);
31922336Snarayan 
31932336Snarayan 		/* if any error other than EAGAIN return back */
31942841Snarayan 		if (rv != EAGAIN || retries >= ldc_max_retries) {
31952336Snarayan 			cmn_err(CE_WARN,
31962336Snarayan 			    "ldc_close: (0x%lx) unregister failed, %d\n",
31972336Snarayan 			    ldcp->id, rv);
31982336Snarayan 			return (rv);
31992336Snarayan 		}
32002336Snarayan 
32012336Snarayan 		/*
32022336Snarayan 		 * As there could be pending interrupts we need
32032336Snarayan 		 * to wait and try again
32042336Snarayan 		 */
32053151Ssg70180 		drv_usecwait(ldc_close_delay);
32062336Snarayan 		mutex_enter(&ldcp->lock);
32072336Snarayan 		mutex_enter(&ldcp->tx_lock);
32082336Snarayan 		retries++;
32091991Sheppo 	}
32101991Sheppo 
32118542SHaik.Aftandilian@Sun.COM 	ldcp->tstate &= ~TS_QCONF_RDY;
32128542SHaik.Aftandilian@Sun.COM 
32131991Sheppo 	/*
32141991Sheppo 	 * Unregister queues
32151991Sheppo 	 */
32161991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
32171991Sheppo 	if (rv) {
32181991Sheppo 		cmn_err(CE_WARN,
32191991Sheppo 		    "ldc_close: (0x%lx) channel TX queue unconf failed\n",
32201991Sheppo 		    ldcp->id);
32212336Snarayan 		mutex_exit(&ldcp->tx_lock);
32221991Sheppo 		mutex_exit(&ldcp->lock);
32231991Sheppo 		return (EIO);
32241991Sheppo 	}
32251991Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
32261991Sheppo 	if (rv) {
32271991Sheppo 		cmn_err(CE_WARN,
32281991Sheppo 		    "ldc_close: (0x%lx) channel RX queue unconf failed\n",
32291991Sheppo 		    ldcp->id);
32302336Snarayan 		mutex_exit(&ldcp->tx_lock);
32311991Sheppo 		mutex_exit(&ldcp->lock);
32321991Sheppo 		return (EIO);
32331991Sheppo 	}
32341991Sheppo 
32351991Sheppo 	/* Reset channel state information */
32361991Sheppo 	i_ldc_reset_state(ldcp);
32371991Sheppo 
32381991Sheppo 	/* Mark channel as down and in initialized state */
32391991Sheppo 	ldcp->tx_ackd_head = 0;
32401991Sheppo 	ldcp->tx_head = 0;
32412793Slm66018 	ldcp->tstate = TS_IN_RESET|TS_INIT;
32421991Sheppo 	ldcp->status = LDC_INIT;
32431991Sheppo 
32442336Snarayan 	mutex_exit(&ldcp->tx_lock);
32451991Sheppo 	mutex_exit(&ldcp->lock);
32461991Sheppo 
32471991Sheppo 	/* Decrement number of open channels */
32481991Sheppo 	mutex_enter(&ldcssp->lock);
32491991Sheppo 	ldcssp->channels_open--;
32501991Sheppo 	mutex_exit(&ldcssp->lock);
32511991Sheppo 
32521991Sheppo 	D1(ldcp->id, "ldc_close: (0x%llx) channel closed\n", ldcp->id);
32531991Sheppo 
32541991Sheppo 	return (0);
32551991Sheppo }
32561991Sheppo 
32571991Sheppo /*
32581991Sheppo  * Register channel callback
32591991Sheppo  */
32601991Sheppo int
32611991Sheppo ldc_reg_callback(ldc_handle_t handle,
32621991Sheppo     uint_t(*cb)(uint64_t event, caddr_t arg), caddr_t arg)
32631991Sheppo {
32641991Sheppo 	ldc_chan_t *ldcp;
32651991Sheppo 
32661991Sheppo 	if (handle == NULL) {
32671991Sheppo 		DWARN(DBG_ALL_LDCS,
32681991Sheppo 		    "ldc_reg_callback: invalid channel handle\n");
32691991Sheppo 		return (EINVAL);
32701991Sheppo 	}
32711991Sheppo 	if (((uint64_t)cb) < KERNELBASE) {
32721991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_reg_callback: invalid callback\n");
32731991Sheppo 		return (EINVAL);
32741991Sheppo 	}
32751991Sheppo 	ldcp = (ldc_chan_t *)handle;
32761991Sheppo 
32771991Sheppo 	mutex_enter(&ldcp->lock);
32781991Sheppo 
32791991Sheppo 	if (ldcp->cb) {
32801991Sheppo 		DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback exists\n",
32811991Sheppo 		    ldcp->id);
32821991Sheppo 		mutex_exit(&ldcp->lock);
32831991Sheppo 		return (EIO);
32841991Sheppo 	}
32851991Sheppo 	if (ldcp->cb_inprogress) {
32861991Sheppo 		DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback active\n",
32871991Sheppo 		    ldcp->id);
32881991Sheppo 		mutex_exit(&ldcp->lock);
32891991Sheppo 		return (EWOULDBLOCK);
32901991Sheppo 	}
32911991Sheppo 
32921991Sheppo 	ldcp->cb = cb;
32931991Sheppo 	ldcp->cb_arg = arg;
32941991Sheppo 	ldcp->cb_enabled = B_TRUE;
32951991Sheppo 
32961991Sheppo 	D1(ldcp->id,
32971991Sheppo 	    "ldc_reg_callback: (0x%llx) registered callback for channel\n",
32981991Sheppo 	    ldcp->id);
32991991Sheppo 
33001991Sheppo 	mutex_exit(&ldcp->lock);
33011991Sheppo 
33021991Sheppo 	return (0);
33031991Sheppo }
33041991Sheppo 
33051991Sheppo /*
33061991Sheppo  * Unregister channel callback
33071991Sheppo  */
33081991Sheppo int
33091991Sheppo ldc_unreg_callback(ldc_handle_t handle)
33101991Sheppo {
33111991Sheppo 	ldc_chan_t *ldcp;
33121991Sheppo 
33131991Sheppo 	if (handle == NULL) {
33141991Sheppo 		DWARN(DBG_ALL_LDCS,
33151991Sheppo 		    "ldc_unreg_callback: invalid channel handle\n");
33161991Sheppo 		return (EINVAL);
33171991Sheppo 	}
33181991Sheppo 	ldcp = (ldc_chan_t *)handle;
33191991Sheppo 
33201991Sheppo 	mutex_enter(&ldcp->lock);
33211991Sheppo 
33221991Sheppo 	if (ldcp->cb == NULL) {
33231991Sheppo 		DWARN(ldcp->id,
33241991Sheppo 		    "ldc_unreg_callback: (0x%llx) no callback exists\n",
33251991Sheppo 		    ldcp->id);
33261991Sheppo 		mutex_exit(&ldcp->lock);
33271991Sheppo 		return (EIO);
33281991Sheppo 	}
33291991Sheppo 	if (ldcp->cb_inprogress) {
33301991Sheppo 		DWARN(ldcp->id,
33311991Sheppo 		    "ldc_unreg_callback: (0x%llx) callback active\n",
33321991Sheppo 		    ldcp->id);
33331991Sheppo 		mutex_exit(&ldcp->lock);
33341991Sheppo 		return (EWOULDBLOCK);
33351991Sheppo 	}
33361991Sheppo 
33371991Sheppo 	ldcp->cb = NULL;
33381991Sheppo 	ldcp->cb_arg = NULL;
33391991Sheppo 	ldcp->cb_enabled = B_FALSE;
33401991Sheppo 
33411991Sheppo 	D1(ldcp->id,
33421991Sheppo 	    "ldc_unreg_callback: (0x%llx) unregistered callback for channel\n",
33431991Sheppo 	    ldcp->id);
33441991Sheppo 
33451991Sheppo 	mutex_exit(&ldcp->lock);
33461991Sheppo 
33471991Sheppo 	return (0);
33481991Sheppo }
33491991Sheppo 
33501991Sheppo 
33511991Sheppo /*
33521991Sheppo  * Bring a channel up by initiating a handshake with the peer
33531991Sheppo  * This call is asynchronous. It will complete at a later point
33541991Sheppo  * in time when the peer responds back with an RTR.
33551991Sheppo  */
33561991Sheppo int
33571991Sheppo ldc_up(ldc_handle_t handle)
33581991Sheppo {
33591991Sheppo 	int 		rv;
33601991Sheppo 	ldc_chan_t 	*ldcp;
33611991Sheppo 	ldc_msg_t 	*ldcmsg;
33623808Ssb155480 	uint64_t 	tx_tail, tstate, link_state;
33631991Sheppo 
33641991Sheppo 	if (handle == NULL) {
33651991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_up: invalid channel handle\n");
33661991Sheppo 		return (EINVAL);
33671991Sheppo 	}
33681991Sheppo 	ldcp = (ldc_chan_t *)handle;
33691991Sheppo 
33701991Sheppo 	mutex_enter(&ldcp->lock);
33711991Sheppo 
33722793Slm66018 	D1(ldcp->id, "ldc_up: (0x%llx) doing channel UP\n", ldcp->id);
33732793Slm66018 
33742793Slm66018 	/* clear the reset state */
33752793Slm66018 	tstate = ldcp->tstate;
33762793Slm66018 	ldcp->tstate &= ~TS_IN_RESET;
33772793Slm66018 
33781991Sheppo 	if (ldcp->tstate == TS_UP) {
33792793Slm66018 		DWARN(ldcp->id,
33801991Sheppo 		    "ldc_up: (0x%llx) channel is already in UP state\n",
33811991Sheppo 		    ldcp->id);
33822793Slm66018 
33832793Slm66018 		/* mark channel as up */
33842793Slm66018 		ldcp->status = LDC_UP;
33852793Slm66018 
33862793Slm66018 		/*
33872793Slm66018 		 * if channel was in reset state and there was
33882793Slm66018 		 * pending data clear interrupt state. this will
33892793Slm66018 		 * trigger an interrupt, causing the RX handler to
33902793Slm66018 		 * to invoke the client's callback
33912793Slm66018 		 */
33922793Slm66018 		if ((tstate & TS_IN_RESET) &&
33932793Slm66018 		    ldcp->rx_intr_state == LDC_INTR_PEND) {
33943010Slm66018 			D1(ldcp->id,
33952793Slm66018 			    "ldc_up: (0x%llx) channel has pending data, "
33962793Slm66018 			    "clearing interrupt\n", ldcp->id);
33972793Slm66018 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
33982793Slm66018 		}
33992793Slm66018 
34001991Sheppo 		mutex_exit(&ldcp->lock);
34011991Sheppo 		return (0);
34021991Sheppo 	}
34031991Sheppo 
34041991Sheppo 	/* if the channel is in RAW mode - mark it as UP, if READY */
34051991Sheppo 	if (ldcp->mode == LDC_MODE_RAW && ldcp->tstate >= TS_READY) {
34061991Sheppo 		ldcp->tstate = TS_UP;
34071991Sheppo 		mutex_exit(&ldcp->lock);
34081991Sheppo 		return (0);
34091991Sheppo 	}
34101991Sheppo 
34111991Sheppo 	/* Don't start another handshake if there is one in progress */
34121991Sheppo 	if (ldcp->hstate) {
34132793Slm66018 		D1(ldcp->id,
34141991Sheppo 		    "ldc_up: (0x%llx) channel handshake in progress\n",
34151991Sheppo 		    ldcp->id);
34161991Sheppo 		mutex_exit(&ldcp->lock);
34171991Sheppo 		return (0);
34181991Sheppo 	}
34191991Sheppo 
34202336Snarayan 	mutex_enter(&ldcp->tx_lock);
34212336Snarayan 
34223808Ssb155480 	/* save current link state */
34233808Ssb155480 	link_state = ldcp->link_state;
34243808Ssb155480 
34251991Sheppo 	/* get the current tail for the LDC msg */
34261991Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
34271991Sheppo 	if (rv) {
34283010Slm66018 		D1(ldcp->id, "ldc_up: (0x%llx) cannot initiate handshake\n",
34291991Sheppo 		    ldcp->id);
34302336Snarayan 		mutex_exit(&ldcp->tx_lock);
34311991Sheppo 		mutex_exit(&ldcp->lock);
34321991Sheppo 		return (ECONNREFUSED);
34331991Sheppo 	}
34341991Sheppo 
34353808Ssb155480 	/*
34363808Ssb155480 	 * If i_ldc_get_tx_tail() changed link_state to either RESET or UP,
34373808Ssb155480 	 * from a previous state of DOWN, then mark the channel as
34383808Ssb155480 	 * being ready for handshake.
34393808Ssb155480 	 */
34403808Ssb155480 	if ((link_state == LDC_CHANNEL_DOWN) &&
34413808Ssb155480 	    (link_state != ldcp->link_state)) {
34423808Ssb155480 
34433808Ssb155480 		ASSERT((ldcp->link_state == LDC_CHANNEL_RESET) ||
34443808Ssb155480 		    (ldcp->link_state == LDC_CHANNEL_UP));
34453808Ssb155480 
34463808Ssb155480 		if (ldcp->mode == LDC_MODE_RAW) {
34473808Ssb155480 			ldcp->status = LDC_UP;
34483808Ssb155480 			ldcp->tstate = TS_UP;
34493808Ssb155480 			mutex_exit(&ldcp->tx_lock);
34503808Ssb155480 			mutex_exit(&ldcp->lock);
34513808Ssb155480 			return (0);
34523808Ssb155480 		} else {
34533808Ssb155480 			ldcp->status = LDC_READY;
34543808Ssb155480 			ldcp->tstate |= TS_LINK_READY;
34553808Ssb155480 		}
34563808Ssb155480 
34573808Ssb155480 	}
34583808Ssb155480 
34591991Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
34601991Sheppo 	ZERO_PKT(ldcmsg);
34611991Sheppo 
34621991Sheppo 	ldcmsg->type = LDC_CTRL;
34631991Sheppo 	ldcmsg->stype = LDC_INFO;
34641991Sheppo 	ldcmsg->ctrl = LDC_VER;
34651991Sheppo 	ldcp->next_vidx = 0;
34661991Sheppo 	bcopy(&ldc_versions[0], ldcmsg->udata, sizeof (ldc_versions[0]));
34671991Sheppo 
34681991Sheppo 	DUMP_LDC_PKT(ldcp, "ldc_up snd ver", (uint64_t)ldcmsg);
34691991Sheppo 
34701991Sheppo 	/* initiate the send by calling into HV and set the new tail */
34711991Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
34724690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
34731991Sheppo 
34741991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
34751991Sheppo 	if (rv) {
34761991Sheppo 		DWARN(ldcp->id,
34771991Sheppo 		    "ldc_up: (0x%llx) cannot initiate handshake rv=%d\n",
34781991Sheppo 		    ldcp->id, rv);
34792336Snarayan 		mutex_exit(&ldcp->tx_lock);
34801991Sheppo 		mutex_exit(&ldcp->lock);
34811991Sheppo 		return (rv);
34821991Sheppo 	}
34831991Sheppo 
34842032Slm66018 	ldcp->hstate |= TS_SENT_VER;
34851991Sheppo 	ldcp->tx_tail = tx_tail;
34861991Sheppo 	D1(ldcp->id, "ldc_up: (0x%llx) channel up initiated\n", ldcp->id);
34871991Sheppo 
34882336Snarayan 	mutex_exit(&ldcp->tx_lock);
34891991Sheppo 	mutex_exit(&ldcp->lock);
34901991Sheppo 
34911991Sheppo 	return (rv);
34921991Sheppo }
34931991Sheppo 
34941991Sheppo 
34951991Sheppo /*
34962410Slm66018  * Bring a channel down by resetting its state and queues
34971991Sheppo  */
34981991Sheppo int
34992410Slm66018 ldc_down(ldc_handle_t handle)
35001991Sheppo {
35011991Sheppo 	ldc_chan_t 	*ldcp;
35021991Sheppo 
35031991Sheppo 	if (handle == NULL) {
35042410Slm66018 		DWARN(DBG_ALL_LDCS, "ldc_down: invalid channel handle\n");
35051991Sheppo 		return (EINVAL);
35061991Sheppo 	}
35071991Sheppo 	ldcp = (ldc_chan_t *)handle;
35081991Sheppo 	mutex_enter(&ldcp->lock);
35092336Snarayan 	mutex_enter(&ldcp->tx_lock);
35102793Slm66018 	i_ldc_reset(ldcp, B_TRUE);
35112336Snarayan 	mutex_exit(&ldcp->tx_lock);
35121991Sheppo 	mutex_exit(&ldcp->lock);
35131991Sheppo 
35141991Sheppo 	return (0);
35151991Sheppo }
35161991Sheppo 
35171991Sheppo /*
35181991Sheppo  * Get the current channel status
35191991Sheppo  */
35201991Sheppo int
35211991Sheppo ldc_status(ldc_handle_t handle, ldc_status_t *status)
35221991Sheppo {
35231991Sheppo 	ldc_chan_t *ldcp;
35241991Sheppo 
35251991Sheppo 	if (handle == NULL || status == NULL) {
35261991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_status: invalid argument\n");
35271991Sheppo 		return (EINVAL);
35281991Sheppo 	}
35291991Sheppo 	ldcp = (ldc_chan_t *)handle;
35301991Sheppo 
35311991Sheppo 	*status = ((ldc_chan_t *)handle)->status;
35321991Sheppo 
35333010Slm66018 	D1(ldcp->id,
35341991Sheppo 	    "ldc_status: (0x%llx) returned status %d\n", ldcp->id, *status);
35351991Sheppo 	return (0);
35361991Sheppo }
35371991Sheppo 
35381991Sheppo 
35391991Sheppo /*
35401991Sheppo  * Set the channel's callback mode - enable/disable callbacks
35411991Sheppo  */
35421991Sheppo int
35431991Sheppo ldc_set_cb_mode(ldc_handle_t handle, ldc_cb_mode_t cmode)
35441991Sheppo {
35451991Sheppo 	ldc_chan_t 	*ldcp;
35461991Sheppo 
35471991Sheppo 	if (handle == NULL) {
35481991Sheppo 		DWARN(DBG_ALL_LDCS,
35491991Sheppo 		    "ldc_set_intr_mode: invalid channel handle\n");
35501991Sheppo 		return (EINVAL);
35511991Sheppo 	}
35521991Sheppo 	ldcp = (ldc_chan_t *)handle;
35531991Sheppo 
35541991Sheppo 	/*
35551991Sheppo 	 * Record no callbacks should be invoked
35561991Sheppo 	 */
35571991Sheppo 	mutex_enter(&ldcp->lock);
35581991Sheppo 
35591991Sheppo 	switch (cmode) {
35601991Sheppo 	case LDC_CB_DISABLE:
35611991Sheppo 		if (!ldcp->cb_enabled) {
35621991Sheppo 			DWARN(ldcp->id,
35631991Sheppo 			    "ldc_set_cb_mode: (0x%llx) callbacks disabled\n",
35641991Sheppo 			    ldcp->id);
35651991Sheppo 			break;
35661991Sheppo 		}
35671991Sheppo 		ldcp->cb_enabled = B_FALSE;
35681991Sheppo 
35691991Sheppo 		D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) disabled callbacks\n",
35701991Sheppo 		    ldcp->id);
35711991Sheppo 		break;
35721991Sheppo 
35731991Sheppo 	case LDC_CB_ENABLE:
35741991Sheppo 		if (ldcp->cb_enabled) {
35751991Sheppo 			DWARN(ldcp->id,
35761991Sheppo 			    "ldc_set_cb_mode: (0x%llx) callbacks enabled\n",
35771991Sheppo 			    ldcp->id);
35781991Sheppo 			break;
35791991Sheppo 		}
35801991Sheppo 		ldcp->cb_enabled = B_TRUE;
35811991Sheppo 
35821991Sheppo 		D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) enabled callbacks\n",
35831991Sheppo 		    ldcp->id);
35841991Sheppo 		break;
35851991Sheppo 	}
35861991Sheppo 
35871991Sheppo 	mutex_exit(&ldcp->lock);
35881991Sheppo 
35891991Sheppo 	return (0);
35901991Sheppo }
35911991Sheppo 
35921991Sheppo /*
35931991Sheppo  * Check to see if there are packets on the incoming queue
35942410Slm66018  * Will return hasdata = B_FALSE if there are no packets
35951991Sheppo  */
35961991Sheppo int
35972410Slm66018 ldc_chkq(ldc_handle_t handle, boolean_t *hasdata)
35981991Sheppo {
35991991Sheppo 	int 		rv;
36001991Sheppo 	uint64_t 	rx_head, rx_tail;
36011991Sheppo 	ldc_chan_t 	*ldcp;
36021991Sheppo 
36031991Sheppo 	if (handle == NULL) {
36041991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_chkq: invalid channel handle\n");
36051991Sheppo 		return (EINVAL);
36061991Sheppo 	}
36071991Sheppo 	ldcp = (ldc_chan_t *)handle;
36081991Sheppo 
36092410Slm66018 	*hasdata = B_FALSE;
36101991Sheppo 
36111991Sheppo 	mutex_enter(&ldcp->lock);
36121991Sheppo 
36131991Sheppo 	if (ldcp->tstate != TS_UP) {
36141991Sheppo 		D1(ldcp->id,
36151991Sheppo 		    "ldc_chkq: (0x%llx) channel is not up\n", ldcp->id);
36161991Sheppo 		mutex_exit(&ldcp->lock);
36171991Sheppo 		return (ECONNRESET);
36181991Sheppo 	}
36191991Sheppo 
36201991Sheppo 	/* Read packet(s) from the queue */
36211991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
36221991Sheppo 	    &ldcp->link_state);
36231991Sheppo 	if (rv != 0) {
36241991Sheppo 		cmn_err(CE_WARN,
36251991Sheppo 		    "ldc_chkq: (0x%lx) unable to read queue ptrs", ldcp->id);
36261991Sheppo 		mutex_exit(&ldcp->lock);
36271991Sheppo 		return (EIO);
36281991Sheppo 	}
36295944Sha137994 
36301991Sheppo 	/* reset the channel state if the channel went down */
36311991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
36321991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
36332336Snarayan 		mutex_enter(&ldcp->tx_lock);
36342793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
36352336Snarayan 		mutex_exit(&ldcp->tx_lock);
36361991Sheppo 		mutex_exit(&ldcp->lock);
36371991Sheppo 		return (ECONNRESET);
36381991Sheppo 	}
36391991Sheppo 
36405944Sha137994 	switch (ldcp->mode) {
36415944Sha137994 	case LDC_MODE_RAW:
36425944Sha137994 		/*
36435944Sha137994 		 * In raw mode, there are no ctrl packets, so checking
36445944Sha137994 		 * if the queue is non-empty is sufficient.
36455944Sha137994 		 */
36465944Sha137994 		*hasdata = (rx_head != rx_tail);
36475944Sha137994 		break;
36485944Sha137994 
36495944Sha137994 	case LDC_MODE_UNRELIABLE:
36505944Sha137994 		/*
36515944Sha137994 		 * In unreliable mode, if the queue is non-empty, we need
36525944Sha137994 		 * to check if it actually contains unread data packets.
36535944Sha137994 		 * The queue may just contain ctrl packets.
36545944Sha137994 		 */
36556446Sha137994 		if (rx_head != rx_tail) {
36565944Sha137994 			*hasdata = (i_ldc_chkq(ldcp) == 0);
36576446Sha137994 			/*
36586446Sha137994 			 * If no data packets were found on the queue,
36596446Sha137994 			 * all packets must have been control packets
36606446Sha137994 			 * which will now have been processed, leaving
36616446Sha137994 			 * the queue empty. If the interrupt state
36626446Sha137994 			 * is pending, we need to clear the interrupt
36636446Sha137994 			 * here.
36646446Sha137994 			 */
36656446Sha137994 			if (*hasdata == B_FALSE &&
36666446Sha137994 			    ldcp->rx_intr_state == LDC_INTR_PEND) {
36676446Sha137994 				i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
36686446Sha137994 			}
36696446Sha137994 		}
36705944Sha137994 		break;
36715944Sha137994 
36726408Sha137994 	case LDC_MODE_RELIABLE:
36735944Sha137994 		/*
36746408Sha137994 		 * In reliable mode, first check for 'stream_remains' > 0.
36755944Sha137994 		 * Otherwise, if the data queue head and tail pointers
36765944Sha137994 		 * differ, there must be data to read.
36775944Sha137994 		 */
36785944Sha137994 		if (ldcp->stream_remains > 0)
36795944Sha137994 			*hasdata = B_TRUE;
36805944Sha137994 		else
36815944Sha137994 			*hasdata = (ldcp->rx_dq_head != ldcp->rx_dq_tail);
36825944Sha137994 		break;
36835944Sha137994 
36845944Sha137994 	default:
36855944Sha137994 		cmn_err(CE_WARN, "ldc_chkq: (0x%lx) unexpected channel mode "
36865944Sha137994 		    "(0x%x)", ldcp->id, ldcp->mode);
36875944Sha137994 		mutex_exit(&ldcp->lock);
36885944Sha137994 		return (EIO);
36891991Sheppo 	}
36901991Sheppo 
36911991Sheppo 	mutex_exit(&ldcp->lock);
36921991Sheppo 
36931991Sheppo 	return (0);
36941991Sheppo }
36951991Sheppo 
36961991Sheppo 
36971991Sheppo /*
36981991Sheppo  * Read 'size' amount of bytes or less. If incoming buffer
36991991Sheppo  * is more than 'size', ENOBUFS is returned.
37001991Sheppo  *
37011991Sheppo  * On return, size contains the number of bytes read.
37021991Sheppo  */
37031991Sheppo int
37041991Sheppo ldc_read(ldc_handle_t handle, caddr_t bufp, size_t *sizep)
37051991Sheppo {
37061991Sheppo 	ldc_chan_t 	*ldcp;
37071991Sheppo 	uint64_t 	rx_head = 0, rx_tail = 0;
37081991Sheppo 	int		rv = 0, exit_val;
37091991Sheppo 
37101991Sheppo 	if (handle == NULL) {
37111991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_read: invalid channel handle\n");
37121991Sheppo 		return (EINVAL);
37131991Sheppo 	}
37141991Sheppo 
37151991Sheppo 	ldcp = (ldc_chan_t *)handle;
37161991Sheppo 
37171991Sheppo 	/* channel lock */
37181991Sheppo 	mutex_enter(&ldcp->lock);
37191991Sheppo 
37201991Sheppo 	if (ldcp->tstate != TS_UP) {
37211991Sheppo 		DWARN(ldcp->id,
37221991Sheppo 		    "ldc_read: (0x%llx) channel is not in UP state\n",
37231991Sheppo 		    ldcp->id);
37241991Sheppo 		exit_val = ECONNRESET;
37256408Sha137994 	} else if (ldcp->mode == LDC_MODE_RELIABLE) {
37265944Sha137994 		TRACE_RXDQ_LENGTH(ldcp);
37275944Sha137994 		exit_val = ldcp->read_p(ldcp, bufp, sizep);
37286944Sha137994 
37296944Sha137994 		/*
37306944Sha137994 		 * For reliable mode channels, the interrupt
37316944Sha137994 		 * state is only set to pending during
37326944Sha137994 		 * interrupt handling when the secondary data
37336944Sha137994 		 * queue became full, leaving unprocessed
37346944Sha137994 		 * packets on the Rx queue. If the interrupt
37356944Sha137994 		 * state is pending and space is now available
37366944Sha137994 		 * on the data queue, clear the interrupt.
37376944Sha137994 		 */
37386944Sha137994 		if (ldcp->rx_intr_state == LDC_INTR_PEND &&
37396944Sha137994 		    Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail,
37406944Sha137994 		    ldcp->rx_dq_entries << LDC_PACKET_SHIFT) >=
37416944Sha137994 		    LDC_PACKET_SIZE) {
37426944Sha137994 			/* data queue is not full */
37436944Sha137994 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
37446944Sha137994 		}
37456944Sha137994 
37465944Sha137994 		mutex_exit(&ldcp->lock);
37475944Sha137994 		return (exit_val);
37481991Sheppo 	} else {
37491991Sheppo 		exit_val = ldcp->read_p(ldcp, bufp, sizep);
37501991Sheppo 	}
37511991Sheppo 
37521991Sheppo 	/*
37531991Sheppo 	 * if queue has been drained - clear interrupt
37541991Sheppo 	 */
37551991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
37561991Sheppo 	    &ldcp->link_state);
37573010Slm66018 	if (rv != 0) {
37583010Slm66018 		cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
37593010Slm66018 		    ldcp->id);
37603010Slm66018 		mutex_enter(&ldcp->tx_lock);
37613010Slm66018 		i_ldc_reset(ldcp, B_TRUE);
37623010Slm66018 		mutex_exit(&ldcp->tx_lock);
37633653Snarayan 		mutex_exit(&ldcp->lock);
37643010Slm66018 		return (ECONNRESET);
37653010Slm66018 	}
37662793Slm66018 
37672793Slm66018 	if (exit_val == 0) {
37682793Slm66018 		if (ldcp->link_state == LDC_CHANNEL_DOWN ||
37692793Slm66018 		    ldcp->link_state == LDC_CHANNEL_RESET) {
37702793Slm66018 			mutex_enter(&ldcp->tx_lock);
37712793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
37722793Slm66018 			exit_val = ECONNRESET;
37732793Slm66018 			mutex_exit(&ldcp->tx_lock);
37742793Slm66018 		}
37752793Slm66018 		if ((rv == 0) &&
37762793Slm66018 		    (ldcp->rx_intr_state == LDC_INTR_PEND) &&
37772793Slm66018 		    (rx_head == rx_tail)) {
37782793Slm66018 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
37792793Slm66018 		}
37801991Sheppo 	}
37811991Sheppo 
37821991Sheppo 	mutex_exit(&ldcp->lock);
37831991Sheppo 	return (exit_val);
37841991Sheppo }
37851991Sheppo 
37861991Sheppo /*
37871991Sheppo  * Basic raw mondo read -
37881991Sheppo  * no interpretation of mondo contents at all.
37891991Sheppo  *
37901991Sheppo  * Enter and exit with ldcp->lock held by caller
37911991Sheppo  */
37921991Sheppo static int
37931991Sheppo i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
37941991Sheppo {
37951991Sheppo 	uint64_t 	q_size_mask;
37961991Sheppo 	ldc_msg_t 	*msgp;
37971991Sheppo 	uint8_t		*msgbufp;
37981991Sheppo 	int		rv = 0, space;
37991991Sheppo 	uint64_t 	rx_head, rx_tail;
38001991Sheppo 
38011991Sheppo 	space = *sizep;
38021991Sheppo 
38031991Sheppo 	if (space < LDC_PAYLOAD_SIZE_RAW)
38041991Sheppo 		return (ENOBUFS);
38051991Sheppo 
38061991Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
38071991Sheppo 
38081991Sheppo 	/* compute mask for increment */
38091991Sheppo 	q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
38101991Sheppo 
38111991Sheppo 	/*
38121991Sheppo 	 * Read packet(s) from the queue
38131991Sheppo 	 */
38141991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
38151991Sheppo 	    &ldcp->link_state);
38161991Sheppo 	if (rv != 0) {
38171991Sheppo 		cmn_err(CE_WARN,
38181991Sheppo 		    "ldc_read_raw: (0x%lx) unable to read queue ptrs",
38191991Sheppo 		    ldcp->id);
38201991Sheppo 		return (EIO);
38211991Sheppo 	}
38221991Sheppo 	D1(ldcp->id, "ldc_read_raw: (0x%llx) rxh=0x%llx,"
38234690Snarayan 	    " rxt=0x%llx, st=0x%llx\n",
38244690Snarayan 	    ldcp->id, rx_head, rx_tail, ldcp->link_state);
38251991Sheppo 
38261991Sheppo 	/* reset the channel state if the channel went down */
38272793Slm66018 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
38282793Slm66018 	    ldcp->link_state == LDC_CHANNEL_RESET) {
38292336Snarayan 		mutex_enter(&ldcp->tx_lock);
38302793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
38312336Snarayan 		mutex_exit(&ldcp->tx_lock);
38321991Sheppo 		return (ECONNRESET);
38331991Sheppo 	}
38341991Sheppo 
38351991Sheppo 	/*
38361991Sheppo 	 * Check for empty queue
38371991Sheppo 	 */
38381991Sheppo 	if (rx_head == rx_tail) {
38391991Sheppo 		*sizep = 0;
38401991Sheppo 		return (0);
38411991Sheppo 	}
38421991Sheppo 
38431991Sheppo 	/* get the message */
38441991Sheppo 	msgp = (ldc_msg_t *)(ldcp->rx_q_va + rx_head);
38451991Sheppo 
38461991Sheppo 	/* if channel is in RAW mode, copy data and return */
38471991Sheppo 	msgbufp = (uint8_t *)&(msgp->raw[0]);
38481991Sheppo 
38491991Sheppo 	bcopy(msgbufp, target_bufp, LDC_PAYLOAD_SIZE_RAW);
38501991Sheppo 
38511991Sheppo 	DUMP_PAYLOAD(ldcp->id, msgbufp);
38521991Sheppo 
38531991Sheppo 	*sizep = LDC_PAYLOAD_SIZE_RAW;
38541991Sheppo 
38551991Sheppo 	rx_head = (rx_head + LDC_PACKET_SIZE) & q_size_mask;
38562032Slm66018 	rv = i_ldc_set_rx_head(ldcp, rx_head);
38571991Sheppo 
38581991Sheppo 	return (rv);
38591991Sheppo }
38601991Sheppo 
38611991Sheppo /*
38621991Sheppo  * Process LDC mondos to build larger packets
38631991Sheppo  * with either un-reliable or reliable delivery.
38641991Sheppo  *
38651991Sheppo  * Enter and exit with ldcp->lock held by caller
38661991Sheppo  */
38671991Sheppo static int
38681991Sheppo i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
38691991Sheppo {
38701991Sheppo 	int		rv = 0;
38711991Sheppo 	uint64_t 	rx_head = 0, rx_tail = 0;
38721991Sheppo 	uint64_t 	curr_head = 0;
38731991Sheppo 	ldc_msg_t 	*msg;
38741991Sheppo 	caddr_t 	target;
38751991Sheppo 	size_t 		len = 0, bytes_read = 0;
38762032Slm66018 	int 		retries = 0;
38775944Sha137994 	uint64_t 	q_va, q_size_mask;
38782336Snarayan 	uint64_t	first_fragment = 0;
38791991Sheppo 
38801991Sheppo 	target = target_bufp;
38811991Sheppo 
38821991Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
38831991Sheppo 
38842793Slm66018 	/* check if the buffer and size are valid */
38852793Slm66018 	if (target_bufp == NULL || *sizep == 0) {
38862793Slm66018 		DWARN(ldcp->id, "ldc_read: (0x%llx) invalid buffer/size\n",
38872793Slm66018 		    ldcp->id);
38882793Slm66018 		return (EINVAL);
38892793Slm66018 	}
38902793Slm66018 
38915944Sha137994 	/* Set q_va and compute increment mask for the appropriate queue */
38926408Sha137994 	if (ldcp->mode == LDC_MODE_RELIABLE) {
38935944Sha137994 		q_va	    = ldcp->rx_dq_va;
38945944Sha137994 		q_size_mask = (ldcp->rx_dq_entries-1)<<LDC_PACKET_SHIFT;
38955944Sha137994 	} else {
38965944Sha137994 		q_va	    = ldcp->rx_q_va;
38975944Sha137994 		q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
38985944Sha137994 	}
38991991Sheppo 
39001991Sheppo 	/*
39011991Sheppo 	 * Read packet(s) from the queue
39021991Sheppo 	 */
39035944Sha137994 	rv = ldcp->readq_get_state(ldcp, &curr_head, &rx_tail,
39041991Sheppo 	    &ldcp->link_state);
39051991Sheppo 	if (rv != 0) {
39062793Slm66018 		cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
39071991Sheppo 		    ldcp->id);
39082793Slm66018 		mutex_enter(&ldcp->tx_lock);
39092793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
39102793Slm66018 		mutex_exit(&ldcp->tx_lock);
39112793Slm66018 		return (ECONNRESET);
39121991Sheppo 	}
39131991Sheppo 	D1(ldcp->id, "ldc_read: (0x%llx) chd=0x%llx, tl=0x%llx, st=0x%llx\n",
39141991Sheppo 	    ldcp->id, curr_head, rx_tail, ldcp->link_state);
39151991Sheppo 
39161991Sheppo 	/* reset the channel state if the channel went down */
39172793Slm66018 	if (ldcp->link_state != LDC_CHANNEL_UP)
39182793Slm66018 		goto channel_is_reset;
39191991Sheppo 
39201991Sheppo 	for (;;) {
39211991Sheppo 
39221991Sheppo 		if (curr_head == rx_tail) {
39235944Sha137994 			/*
39245944Sha137994 			 * If a data queue is being used, check the Rx HV
39255944Sha137994 			 * queue. This will copy over any new data packets
39265944Sha137994 			 * that have arrived.
39275944Sha137994 			 */
39286408Sha137994 			if (ldcp->mode == LDC_MODE_RELIABLE)
39295944Sha137994 				(void) i_ldc_chkq(ldcp);
39305944Sha137994 
39315944Sha137994 			rv = ldcp->readq_get_state(ldcp,
39321991Sheppo 			    &rx_head, &rx_tail, &ldcp->link_state);
39331991Sheppo 			if (rv != 0) {
39341991Sheppo 				cmn_err(CE_WARN,
39351991Sheppo 				    "ldc_read: (0x%lx) cannot read queue ptrs",
39361991Sheppo 				    ldcp->id);
39372336Snarayan 				mutex_enter(&ldcp->tx_lock);
39382793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
39392336Snarayan 				mutex_exit(&ldcp->tx_lock);
39401991Sheppo 				return (ECONNRESET);
39411991Sheppo 			}
39425944Sha137994 
39432793Slm66018 			if (ldcp->link_state != LDC_CHANNEL_UP)
39442793Slm66018 				goto channel_is_reset;
39452793Slm66018 
39462793Slm66018 			if (curr_head == rx_tail) {
39472793Slm66018 
39482793Slm66018 				/* If in the middle of a fragmented xfer */
39492793Slm66018 				if (first_fragment != 0) {
39502793Slm66018 
39512793Slm66018 					/* wait for ldc_delay usecs */
39522793Slm66018 					drv_usecwait(ldc_delay);
39532793Slm66018 
39542793Slm66018 					if (++retries < ldc_max_retries)
39552793Slm66018 						continue;
39562793Slm66018 
39572793Slm66018 					*sizep = 0;
39586408Sha137994 					if (ldcp->mode != LDC_MODE_RELIABLE)
39595944Sha137994 						ldcp->last_msg_rcd =
39605944Sha137994 						    first_fragment - 1;
39612793Slm66018 					DWARN(DBG_ALL_LDCS, "ldc_read: "
39624690Snarayan 					    "(0x%llx) read timeout", ldcp->id);
39632793Slm66018 					return (EAGAIN);
39642793Slm66018 				}
39652032Slm66018 				*sizep = 0;
39662793Slm66018 				break;
39671991Sheppo 			}
39681991Sheppo 		}
39692032Slm66018 		retries = 0;
39701991Sheppo 
39711991Sheppo 		D2(ldcp->id,
39721991Sheppo 		    "ldc_read: (0x%llx) chd=0x%llx, rxhd=0x%llx, rxtl=0x%llx\n",
39731991Sheppo 		    ldcp->id, curr_head, rx_head, rx_tail);
39741991Sheppo 
39751991Sheppo 		/* get the message */
39765944Sha137994 		msg = (ldc_msg_t *)(q_va + curr_head);
39771991Sheppo 
39781991Sheppo 		DUMP_LDC_PKT(ldcp, "ldc_read received pkt",
39791991Sheppo 		    ldcp->rx_q_va + curr_head);
39801991Sheppo 
39811991Sheppo 		/* Check the message ID for the message received */
39826408Sha137994 		if (ldcp->mode != LDC_MODE_RELIABLE) {
39835944Sha137994 			if ((rv = i_ldc_check_seqid(ldcp, msg)) != 0) {
39845944Sha137994 
39855944Sha137994 				DWARN(ldcp->id, "ldc_read: (0x%llx) seqid "
39865944Sha137994 				    "error, q_ptrs=0x%lx,0x%lx",
39875944Sha137994 				    ldcp->id, rx_head, rx_tail);
39885944Sha137994 
39895944Sha137994 				/* throw away data */
39905944Sha137994 				bytes_read = 0;
39915944Sha137994 
39925944Sha137994 				/* Reset last_msg_rcd to start of message */
39935944Sha137994 				if (first_fragment != 0) {
39945944Sha137994 					ldcp->last_msg_rcd = first_fragment - 1;
39955944Sha137994 					first_fragment = 0;
39965944Sha137994 				}
39975944Sha137994 				/*
39985944Sha137994 				 * Send a NACK -- invalid seqid
39995944Sha137994 				 * get the current tail for the response
40005944Sha137994 				 */
40015944Sha137994 				rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK,
40025944Sha137994 				    (msg->ctrl & LDC_CTRL_MASK));
40035944Sha137994 				if (rv) {
40045944Sha137994 					cmn_err(CE_NOTE,
40055944Sha137994 					    "ldc_read: (0x%lx) err sending "
40065944Sha137994 					    "NACK msg\n", ldcp->id);
40075944Sha137994 
40085944Sha137994 					/* if cannot send NACK - reset chan */
40095944Sha137994 					mutex_enter(&ldcp->tx_lock);
40105944Sha137994 					i_ldc_reset(ldcp, B_FALSE);
40115944Sha137994 					mutex_exit(&ldcp->tx_lock);
40125944Sha137994 					rv = ECONNRESET;
40135944Sha137994 					break;
40145944Sha137994 				}
40155944Sha137994 
40165944Sha137994 				/* purge receive queue */
40175944Sha137994 				rv = i_ldc_set_rx_head(ldcp, rx_tail);
40185944Sha137994 
40192336Snarayan 				break;
40201991Sheppo 			}
40211991Sheppo 
40225944Sha137994 			/*
40235944Sha137994 			 * Process any messages of type CTRL messages
40245944Sha137994 			 * Future implementations should try to pass these
40255944Sha137994 			 * to LDC link by resetting the intr state.
40265944Sha137994 			 *
40275944Sha137994 			 * NOTE: not done as a switch() as type can be
40285944Sha137994 			 * both ctrl+data
40295944Sha137994 			 */
40305944Sha137994 			if (msg->type & LDC_CTRL) {
40315944Sha137994 				if (rv = i_ldc_ctrlmsg(ldcp, msg)) {
40325944Sha137994 					if (rv == EAGAIN)
40335944Sha137994 						continue;
40345944Sha137994 					rv = i_ldc_set_rx_head(ldcp, rx_tail);
40355944Sha137994 					*sizep = 0;
40365944Sha137994 					bytes_read = 0;
40375944Sha137994 					break;
40385944Sha137994 				}
40391991Sheppo 			}
40405944Sha137994 
40415944Sha137994 			/* process data ACKs */
40425944Sha137994 			if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
40435944Sha137994 				if (rv = i_ldc_process_data_ACK(ldcp, msg)) {
40445944Sha137994 					*sizep = 0;
40455944Sha137994 					bytes_read = 0;
40465944Sha137994 					break;
40475944Sha137994 				}
40482336Snarayan 			}
40495944Sha137994 
40505944Sha137994 			/* process data NACKs */
40515944Sha137994 			if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) {
40525944Sha137994 				DWARN(ldcp->id,
40535944Sha137994 				    "ldc_read: (0x%llx) received DATA/NACK",
40545944Sha137994 				    ldcp->id);
40555944Sha137994 				mutex_enter(&ldcp->tx_lock);
40565944Sha137994 				i_ldc_reset(ldcp, B_TRUE);
40575944Sha137994 				mutex_exit(&ldcp->tx_lock);
40585944Sha137994 				return (ECONNRESET);
40595944Sha137994 			}
40603560Snarayan 		}
40613560Snarayan 
40621991Sheppo 		/* process data messages */
40631991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
40641991Sheppo 
40651991Sheppo 			uint8_t *msgbuf = (uint8_t *)(
40666408Sha137994 			    (ldcp->mode == LDC_MODE_RELIABLE) ?
40674690Snarayan 			    msg->rdata : msg->udata);
40681991Sheppo 
40691991Sheppo 			D2(ldcp->id,
40701991Sheppo 			    "ldc_read: (0x%llx) received data msg\n", ldcp->id);
40711991Sheppo 
40721991Sheppo 			/* get the packet length */
40731991Sheppo 			len = (msg->env & LDC_LEN_MASK);
40741991Sheppo 
40751991Sheppo 				/*
40761991Sheppo 				 * FUTURE OPTIMIZATION:
40771991Sheppo 				 * dont need to set q head for every
40781991Sheppo 				 * packet we read just need to do this when
40791991Sheppo 				 * we are done or need to wait for more
40801991Sheppo 				 * mondos to make a full packet - this is
40811991Sheppo 				 * currently expensive.
40821991Sheppo 				 */
40831991Sheppo 
40842336Snarayan 			if (first_fragment == 0) {
40851991Sheppo 
40861991Sheppo 				/*
40871991Sheppo 				 * first packets should always have the start
40881991Sheppo 				 * bit set (even for a single packet). If not
40891991Sheppo 				 * throw away the packet
40901991Sheppo 				 */
40911991Sheppo 				if (!(msg->env & LDC_FRAG_START)) {
40921991Sheppo 
40931991Sheppo 					DWARN(DBG_ALL_LDCS,
40941991Sheppo 					    "ldc_read: (0x%llx) not start - "
40951991Sheppo 					    "frag=%x\n", ldcp->id,
40961991Sheppo 					    (msg->env) & LDC_FRAG_MASK);
40971991Sheppo 
40981991Sheppo 					/* toss pkt, inc head, cont reading */
40991991Sheppo 					bytes_read = 0;
41001991Sheppo 					target = target_bufp;
41011991Sheppo 					curr_head =
41024690Snarayan 					    (curr_head + LDC_PACKET_SIZE)
41034690Snarayan 					    & q_size_mask;
41045944Sha137994 					if (rv = ldcp->readq_set_head(ldcp,
41054690Snarayan 					    curr_head))
41061991Sheppo 						break;
41071991Sheppo 
41081991Sheppo 					continue;
41091991Sheppo 				}
41101991Sheppo 
41112336Snarayan 				first_fragment = msg->seqid;
41121991Sheppo 			} else {
41131991Sheppo 				/* check to see if this is a pkt w/ START bit */
41141991Sheppo 				if (msg->env & LDC_FRAG_START) {
41151991Sheppo 					DWARN(DBG_ALL_LDCS,
41161991Sheppo 					    "ldc_read:(0x%llx) unexpected pkt"
41171991Sheppo 					    " env=0x%x discarding %d bytes,"
41181991Sheppo 					    " lastmsg=%d, currentmsg=%d\n",
41191991Sheppo 					    ldcp->id, msg->env&LDC_FRAG_MASK,
41201991Sheppo 					    bytes_read, ldcp->last_msg_rcd,
41211991Sheppo 					    msg->seqid);
41221991Sheppo 
41231991Sheppo 					/* throw data we have read so far */
41241991Sheppo 					bytes_read = 0;
41251991Sheppo 					target = target_bufp;
41262336Snarayan 					first_fragment = msg->seqid;
41271991Sheppo 
41285944Sha137994 					if (rv = ldcp->readq_set_head(ldcp,
41294690Snarayan 					    curr_head))
41301991Sheppo 						break;
41311991Sheppo 				}
41321991Sheppo 			}
41331991Sheppo 
41341991Sheppo 			/* copy (next) pkt into buffer */
41351991Sheppo 			if (len <= (*sizep - bytes_read)) {
41361991Sheppo 				bcopy(msgbuf, target, len);
41371991Sheppo 				target += len;
41381991Sheppo 				bytes_read += len;
41391991Sheppo 			} else {
41401991Sheppo 				/*
41411991Sheppo 				 * there is not enough space in the buffer to
41421991Sheppo 				 * read this pkt. throw message away & continue
41431991Sheppo 				 * reading data from queue
41441991Sheppo 				 */
41451991Sheppo 				DWARN(DBG_ALL_LDCS,
41461991Sheppo 				    "ldc_read: (0x%llx) buffer too small, "
41471991Sheppo 				    "head=0x%lx, expect=%d, got=%d\n", ldcp->id,
41481991Sheppo 				    curr_head, *sizep, bytes_read+len);
41491991Sheppo 
41502336Snarayan 				first_fragment = 0;
41511991Sheppo 				target = target_bufp;
41521991Sheppo 				bytes_read = 0;
41531991Sheppo 
41541991Sheppo 				/* throw away everything received so far */
41555944Sha137994 				if (rv = ldcp->readq_set_head(ldcp, curr_head))
41561991Sheppo 					break;
41571991Sheppo 
41581991Sheppo 				/* continue reading remaining pkts */
41591991Sheppo 				continue;
41601991Sheppo 			}
41611991Sheppo 		}
41621991Sheppo 
41631991Sheppo 		/* set the message id */
41646408Sha137994 		if (ldcp->mode != LDC_MODE_RELIABLE)
41655944Sha137994 			ldcp->last_msg_rcd = msg->seqid;
41661991Sheppo 
41671991Sheppo 		/* move the head one position */
41681991Sheppo 		curr_head = (curr_head + LDC_PACKET_SIZE) & q_size_mask;
41691991Sheppo 
41701991Sheppo 		if (msg->env & LDC_FRAG_STOP) {
41711991Sheppo 
41721991Sheppo 			/*
41731991Sheppo 			 * All pkts that are part of this fragmented transfer
41741991Sheppo 			 * have been read or this was a single pkt read
41751991Sheppo 			 * or there was an error
41761991Sheppo 			 */
41771991Sheppo 
41781991Sheppo 			/* set the queue head */
41795944Sha137994 			if (rv = ldcp->readq_set_head(ldcp, curr_head))
41801991Sheppo 				bytes_read = 0;
41811991Sheppo 
41821991Sheppo 			*sizep = bytes_read;
41831991Sheppo 
41841991Sheppo 			break;
41851991Sheppo 		}
41861991Sheppo 
41874890Snarayan 		/* advance head if it is a CTRL packet or a DATA ACK packet */
41884890Snarayan 		if ((msg->type & LDC_CTRL) ||
41894890Snarayan 		    ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK))) {
41901991Sheppo 
41911991Sheppo 			/* set the queue head */
41925944Sha137994 			if (rv = ldcp->readq_set_head(ldcp, curr_head)) {
41931991Sheppo 				bytes_read = 0;
41941991Sheppo 				break;
41951991Sheppo 			}
41961991Sheppo 
41971991Sheppo 			D2(ldcp->id, "ldc_read: (0x%llx) set ACK qhead 0x%llx",
41981991Sheppo 			    ldcp->id, curr_head);
41991991Sheppo 		}
42001991Sheppo 
42011991Sheppo 	} /* for (;;) */
42021991Sheppo 
42031991Sheppo 	D2(ldcp->id, "ldc_read: (0x%llx) end size=%d", ldcp->id, *sizep);
42041991Sheppo 
42051991Sheppo 	return (rv);
42062793Slm66018 
42072793Slm66018 channel_is_reset:
42082793Slm66018 	mutex_enter(&ldcp->tx_lock);
42092793Slm66018 	i_ldc_reset(ldcp, B_FALSE);
42102793Slm66018 	mutex_exit(&ldcp->tx_lock);
42112793Slm66018 	return (ECONNRESET);
42121991Sheppo }
42131991Sheppo 
42141991Sheppo /*
42156408Sha137994  * Fetch and buffer incoming packets so we can hand them back as
42161991Sheppo  * a basic byte stream.
42171991Sheppo  *
42181991Sheppo  * Enter and exit with ldcp->lock held by caller
42191991Sheppo  */
42201991Sheppo static int
42211991Sheppo i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
42221991Sheppo {
42231991Sheppo 	int	rv;
42241991Sheppo 	size_t	size;
42251991Sheppo 
42261991Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
42271991Sheppo 
42281991Sheppo 	D2(ldcp->id, "i_ldc_read_stream: (0x%llx) buffer size=%d",
42294690Snarayan 	    ldcp->id, *sizep);
42301991Sheppo 
42311991Sheppo 	if (ldcp->stream_remains == 0) {
42321991Sheppo 		size = ldcp->mtu;
42331991Sheppo 		rv = i_ldc_read_packet(ldcp,
42344690Snarayan 		    (caddr_t)ldcp->stream_bufferp, &size);
42351991Sheppo 		D2(ldcp->id, "i_ldc_read_stream: read packet (0x%llx) size=%d",
42364690Snarayan 		    ldcp->id, size);
42371991Sheppo 
42381991Sheppo 		if (rv != 0)
42391991Sheppo 			return (rv);
42401991Sheppo 
42411991Sheppo 		ldcp->stream_remains = size;
42421991Sheppo 		ldcp->stream_offset = 0;
42431991Sheppo 	}
42441991Sheppo 
42451991Sheppo 	size = MIN(ldcp->stream_remains, *sizep);
42461991Sheppo 
42471991Sheppo 	bcopy(ldcp->stream_bufferp + ldcp->stream_offset, target_bufp, size);
42481991Sheppo 	ldcp->stream_offset += size;
42491991Sheppo 	ldcp->stream_remains -= size;
42501991Sheppo 
42511991Sheppo 	D2(ldcp->id, "i_ldc_read_stream: (0x%llx) fill from buffer size=%d",
42524690Snarayan 	    ldcp->id, size);
42531991Sheppo 
42541991Sheppo 	*sizep = size;
42551991Sheppo 	return (0);
42561991Sheppo }
42571991Sheppo 
42581991Sheppo /*
42591991Sheppo  * Write specified amount of bytes to the channel
42601991Sheppo  * in multiple pkts of pkt_payload size. Each
42611991Sheppo  * packet is tagged with an unique packet ID in
42622410Slm66018  * the case of a reliable link.
42631991Sheppo  *
42641991Sheppo  * On return, size contains the number of bytes written.
42651991Sheppo  */
42661991Sheppo int
42671991Sheppo ldc_write(ldc_handle_t handle, caddr_t buf, size_t *sizep)
42681991Sheppo {
42691991Sheppo 	ldc_chan_t	*ldcp;
42701991Sheppo 	int		rv = 0;
42711991Sheppo 
42721991Sheppo 	if (handle == NULL) {
42731991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_write: invalid channel handle\n");
42741991Sheppo 		return (EINVAL);
42751991Sheppo 	}
42761991Sheppo 	ldcp = (ldc_chan_t *)handle;
42771991Sheppo 
42782336Snarayan 	/* check if writes can occur */
42792336Snarayan 	if (!mutex_tryenter(&ldcp->tx_lock)) {
42802336Snarayan 		/*
42812336Snarayan 		 * Could not get the lock - channel could
42822336Snarayan 		 * be in the process of being unconfigured
42832336Snarayan 		 * or reader has encountered an error
42842336Snarayan 		 */
42852336Snarayan 		return (EAGAIN);
42862336Snarayan 	}
42871991Sheppo 
42881991Sheppo 	/* check if non-zero data to write */
42891991Sheppo 	if (buf == NULL || sizep == NULL) {
42901991Sheppo 		DWARN(ldcp->id, "ldc_write: (0x%llx) invalid data write\n",
42911991Sheppo 		    ldcp->id);
42922336Snarayan 		mutex_exit(&ldcp->tx_lock);
42931991Sheppo 		return (EINVAL);
42941991Sheppo 	}
42951991Sheppo 
42961991Sheppo 	if (*sizep == 0) {
42971991Sheppo 		DWARN(ldcp->id, "ldc_write: (0x%llx) write size of zero\n",
42981991Sheppo 		    ldcp->id);
42992336Snarayan 		mutex_exit(&ldcp->tx_lock);
43001991Sheppo 		return (0);
43011991Sheppo 	}
43021991Sheppo 
43031991Sheppo 	/* Check if channel is UP for data exchange */
43041991Sheppo 	if (ldcp->tstate != TS_UP) {
43051991Sheppo 		DWARN(ldcp->id,
43061991Sheppo 		    "ldc_write: (0x%llx) channel is not in UP state\n",
43071991Sheppo 		    ldcp->id);
43081991Sheppo 		*sizep = 0;
43091991Sheppo 		rv = ECONNRESET;
43101991Sheppo 	} else {
43111991Sheppo 		rv = ldcp->write_p(ldcp, buf, sizep);
43121991Sheppo 	}
43131991Sheppo 
43142336Snarayan 	mutex_exit(&ldcp->tx_lock);
43151991Sheppo 
43161991Sheppo 	return (rv);
43171991Sheppo }
43181991Sheppo 
43191991Sheppo /*
43201991Sheppo  * Write a raw packet to the channel
43211991Sheppo  * On return, size contains the number of bytes written.
43221991Sheppo  */
43231991Sheppo static int
43241991Sheppo i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
43251991Sheppo {
43261991Sheppo 	ldc_msg_t 	*ldcmsg;
43271991Sheppo 	uint64_t 	tx_head, tx_tail, new_tail;
43281991Sheppo 	int		rv = 0;
43291991Sheppo 	size_t		size;
43301991Sheppo 
43312336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
43321991Sheppo 	ASSERT(ldcp->mode == LDC_MODE_RAW);
43331991Sheppo 
43341991Sheppo 	size = *sizep;
43351991Sheppo 
43361991Sheppo 	/*
43371991Sheppo 	 * Check to see if the packet size is less than or
43381991Sheppo 	 * equal to packet size support in raw mode
43391991Sheppo 	 */
43401991Sheppo 	if (size > ldcp->pkt_payload) {
43411991Sheppo 		DWARN(ldcp->id,
43421991Sheppo 		    "ldc_write: (0x%llx) invalid size (0x%llx) for RAW mode\n",
43431991Sheppo 		    ldcp->id, *sizep);
43441991Sheppo 		*sizep = 0;
43451991Sheppo 		return (EMSGSIZE);
43461991Sheppo 	}
43471991Sheppo 
43481991Sheppo 	/* get the qptrs for the tx queue */
43491991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
43501991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
43511991Sheppo 	if (rv != 0) {
43521991Sheppo 		cmn_err(CE_WARN,
43531991Sheppo 		    "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
43541991Sheppo 		*sizep = 0;
43551991Sheppo 		return (EIO);
43561991Sheppo 	}
43571991Sheppo 
43581991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
43591991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
43601991Sheppo 		DWARN(ldcp->id,
43611991Sheppo 		    "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
43622336Snarayan 
43631991Sheppo 		*sizep = 0;
43642336Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
43652793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
43662336Snarayan 			mutex_exit(&ldcp->lock);
43672336Snarayan 		} else {
43682336Snarayan 			/*
43692336Snarayan 			 * Release Tx lock, and then reacquire channel
43702336Snarayan 			 * and Tx lock in correct order
43712336Snarayan 			 */
43722336Snarayan 			mutex_exit(&ldcp->tx_lock);
43732336Snarayan 			mutex_enter(&ldcp->lock);
43742336Snarayan 			mutex_enter(&ldcp->tx_lock);
43752793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
43762336Snarayan 			mutex_exit(&ldcp->lock);
43772336Snarayan 		}
43781991Sheppo 		return (ECONNRESET);
43791991Sheppo 	}
43801991Sheppo 
43811991Sheppo 	tx_tail = ldcp->tx_tail;
43821991Sheppo 	tx_head = ldcp->tx_head;
43831991Sheppo 	new_tail = (tx_tail + LDC_PACKET_SIZE) &
43844690Snarayan 	    ((ldcp->tx_q_entries-1) << LDC_PACKET_SHIFT);
43851991Sheppo 
43861991Sheppo 	if (new_tail == tx_head) {
43871991Sheppo 		DWARN(DBG_ALL_LDCS,
43881991Sheppo 		    "ldc_write: (0x%llx) TX queue is full\n", ldcp->id);
43891991Sheppo 		*sizep = 0;
43901991Sheppo 		return (EWOULDBLOCK);
43911991Sheppo 	}
43921991Sheppo 
43931991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
43941991Sheppo 	    ldcp->id, size);
43951991Sheppo 
43961991Sheppo 	/* Send the data now */
43971991Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
43981991Sheppo 
43992336Snarayan 	/* copy the data into pkt */
44001991Sheppo 	bcopy((uint8_t *)buf, ldcmsg, size);
44011991Sheppo 
44022336Snarayan 	/* increment tail */
44031991Sheppo 	tx_tail = new_tail;
44041991Sheppo 
44051991Sheppo 	/*
44061991Sheppo 	 * All packets have been copied into the TX queue
44071991Sheppo 	 * update the tail ptr in the HV
44081991Sheppo 	 */
44091991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
44101991Sheppo 	if (rv) {
44111991Sheppo 		if (rv == EWOULDBLOCK) {
44121991Sheppo 			DWARN(ldcp->id, "ldc_write: (0x%llx) write timed out\n",
44131991Sheppo 			    ldcp->id);
44141991Sheppo 			*sizep = 0;
44151991Sheppo 			return (EWOULDBLOCK);
44161991Sheppo 		}
44171991Sheppo 
44181991Sheppo 		*sizep = 0;
44192336Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
44202793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
44212336Snarayan 			mutex_exit(&ldcp->lock);
44222336Snarayan 		} else {
44232336Snarayan 			/*
44242336Snarayan 			 * Release Tx lock, and then reacquire channel
44252336Snarayan 			 * and Tx lock in correct order
44262336Snarayan 			 */
44272336Snarayan 			mutex_exit(&ldcp->tx_lock);
44282336Snarayan 			mutex_enter(&ldcp->lock);
44292336Snarayan 			mutex_enter(&ldcp->tx_lock);
44302793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
44312336Snarayan 			mutex_exit(&ldcp->lock);
44322336Snarayan 		}
44331991Sheppo 		return (ECONNRESET);
44341991Sheppo 	}
44351991Sheppo 
44361991Sheppo 	ldcp->tx_tail = tx_tail;
44371991Sheppo 	*sizep = size;
44381991Sheppo 
44391991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, size);
44401991Sheppo 
44411991Sheppo 	return (rv);
44421991Sheppo }
44431991Sheppo 
44441991Sheppo 
44451991Sheppo /*
44461991Sheppo  * Write specified amount of bytes to the channel
44471991Sheppo  * in multiple pkts of pkt_payload size. Each
44481991Sheppo  * packet is tagged with an unique packet ID in
44492410Slm66018  * the case of a reliable link.
44501991Sheppo  *
44511991Sheppo  * On return, size contains the number of bytes written.
44521991Sheppo  * This function needs to ensure that the write size is < MTU size
44531991Sheppo  */
44541991Sheppo static int
44551991Sheppo i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t buf, size_t *size)
44561991Sheppo {
44571991Sheppo 	ldc_msg_t 	*ldcmsg;
44581991Sheppo 	uint64_t 	tx_head, tx_tail, new_tail, start;
44591991Sheppo 	uint64_t	txq_size_mask, numavail;
44601991Sheppo 	uint8_t 	*msgbuf, *source = (uint8_t *)buf;
44611991Sheppo 	size_t 		len, bytes_written = 0, remaining;
44621991Sheppo 	int		rv;
44631991Sheppo 	uint32_t	curr_seqid;
44641991Sheppo 
44652336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
44661991Sheppo 
44671991Sheppo 	ASSERT(ldcp->mode == LDC_MODE_RELIABLE ||
44686408Sha137994 	    ldcp->mode == LDC_MODE_UNRELIABLE);
44691991Sheppo 
44701991Sheppo 	/* compute mask for increment */
44711991Sheppo 	txq_size_mask = (ldcp->tx_q_entries - 1) << LDC_PACKET_SHIFT;
44721991Sheppo 
44731991Sheppo 	/* get the qptrs for the tx queue */
44741991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
44751991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
44761991Sheppo 	if (rv != 0) {
44771991Sheppo 		cmn_err(CE_WARN,
44781991Sheppo 		    "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
44791991Sheppo 		*size = 0;
44801991Sheppo 		return (EIO);
44811991Sheppo 	}
44821991Sheppo 
44831991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
44841991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
44851991Sheppo 		DWARN(ldcp->id,
44861991Sheppo 		    "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
44871991Sheppo 		*size = 0;
44882336Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
44892793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
44902336Snarayan 			mutex_exit(&ldcp->lock);
44912336Snarayan 		} else {
44922336Snarayan 			/*
44932336Snarayan 			 * Release Tx lock, and then reacquire channel
44942336Snarayan 			 * and Tx lock in correct order
44952336Snarayan 			 */
44962336Snarayan 			mutex_exit(&ldcp->tx_lock);
44972336Snarayan 			mutex_enter(&ldcp->lock);
44982336Snarayan 			mutex_enter(&ldcp->tx_lock);
44992793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
45002336Snarayan 			mutex_exit(&ldcp->lock);
45012336Snarayan 		}
45021991Sheppo 		return (ECONNRESET);
45031991Sheppo 	}
45041991Sheppo 
45051991Sheppo 	tx_tail = ldcp->tx_tail;
45061991Sheppo 	new_tail = (tx_tail + LDC_PACKET_SIZE) %
45074690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
45081991Sheppo 
45091991Sheppo 	/*
45104690Snarayan 	 * Check to see if the queue is full. The check is done using
45114690Snarayan 	 * the appropriate head based on the link mode.
45121991Sheppo 	 */
45134690Snarayan 	i_ldc_get_tx_head(ldcp, &tx_head);
45144690Snarayan 
45151991Sheppo 	if (new_tail == tx_head) {
45161991Sheppo 		DWARN(DBG_ALL_LDCS,
45171991Sheppo 		    "ldc_write: (0x%llx) TX queue is full\n", ldcp->id);
45181991Sheppo 		*size = 0;
45191991Sheppo 		return (EWOULDBLOCK);
45201991Sheppo 	}
45211991Sheppo 
45221991Sheppo 	/*
45231991Sheppo 	 * Make sure that the LDC Tx queue has enough space
45241991Sheppo 	 */
45251991Sheppo 	numavail = (tx_head >> LDC_PACKET_SHIFT) - (tx_tail >> LDC_PACKET_SHIFT)
45264690Snarayan 	    + ldcp->tx_q_entries - 1;
45271991Sheppo 	numavail %= ldcp->tx_q_entries;
45281991Sheppo 
45291991Sheppo 	if (*size > (numavail * ldcp->pkt_payload)) {
45301991Sheppo 		DWARN(DBG_ALL_LDCS,
45311991Sheppo 		    "ldc_write: (0x%llx) TX queue has no space\n", ldcp->id);
45321991Sheppo 		return (EWOULDBLOCK);
45331991Sheppo 	}
45341991Sheppo 
45351991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
45361991Sheppo 	    ldcp->id, *size);
45371991Sheppo 
45381991Sheppo 	/* Send the data now */
45391991Sheppo 	bytes_written = 0;
45401991Sheppo 	curr_seqid = ldcp->last_msg_snt;
45411991Sheppo 	start = tx_tail;
45421991Sheppo 
45431991Sheppo 	while (*size > bytes_written) {
45441991Sheppo 
45451991Sheppo 		ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
45461991Sheppo 
45476408Sha137994 		msgbuf = (uint8_t *)((ldcp->mode == LDC_MODE_RELIABLE) ?
45484690Snarayan 		    ldcmsg->rdata : ldcmsg->udata);
45491991Sheppo 
45501991Sheppo 		ldcmsg->type = LDC_DATA;
45511991Sheppo 		ldcmsg->stype = LDC_INFO;
45521991Sheppo 		ldcmsg->ctrl = 0;
45531991Sheppo 
45541991Sheppo 		remaining = *size - bytes_written;
45551991Sheppo 		len = min(ldcp->pkt_payload, remaining);
45561991Sheppo 		ldcmsg->env = (uint8_t)len;
45571991Sheppo 
45581991Sheppo 		curr_seqid++;
45591991Sheppo 		ldcmsg->seqid = curr_seqid;
45601991Sheppo 
45611991Sheppo 		/* copy the data into pkt */
45621991Sheppo 		bcopy(source, msgbuf, len);
45631991Sheppo 
45641991Sheppo 		source += len;
45651991Sheppo 		bytes_written += len;
45661991Sheppo 
45671991Sheppo 		/* increment tail */
45681991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) & txq_size_mask;
45691991Sheppo 
45701991Sheppo 		ASSERT(tx_tail != tx_head);
45711991Sheppo 	}
45721991Sheppo 
45731991Sheppo 	/* Set the start and stop bits */
45741991Sheppo 	ldcmsg->env |= LDC_FRAG_STOP;
45751991Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + start);
45761991Sheppo 	ldcmsg->env |= LDC_FRAG_START;
45771991Sheppo 
45781991Sheppo 	/*
45791991Sheppo 	 * All packets have been copied into the TX queue
45801991Sheppo 	 * update the tail ptr in the HV
45811991Sheppo 	 */
45821991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
45831991Sheppo 	if (rv == 0) {
45841991Sheppo 		ldcp->tx_tail = tx_tail;
45851991Sheppo 		ldcp->last_msg_snt = curr_seqid;
45861991Sheppo 		*size = bytes_written;
45871991Sheppo 	} else {
45881991Sheppo 		int rv2;
45891991Sheppo 
45901991Sheppo 		if (rv != EWOULDBLOCK) {
45911991Sheppo 			*size = 0;
45922336Snarayan 			if (mutex_tryenter(&ldcp->lock)) {
45932793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
45942336Snarayan 				mutex_exit(&ldcp->lock);
45952336Snarayan 			} else {
45962336Snarayan 				/*
45972336Snarayan 				 * Release Tx lock, and then reacquire channel
45982336Snarayan 				 * and Tx lock in correct order
45992336Snarayan 				 */
46002336Snarayan 				mutex_exit(&ldcp->tx_lock);
46012336Snarayan 				mutex_enter(&ldcp->lock);
46022336Snarayan 				mutex_enter(&ldcp->tx_lock);
46032793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
46042336Snarayan 				mutex_exit(&ldcp->lock);
46052336Snarayan 			}
46061991Sheppo 			return (ECONNRESET);
46071991Sheppo 		}
46081991Sheppo 
46093010Slm66018 		D1(ldcp->id, "hv_tx_set_tail returns 0x%x (head 0x%x, "
46104690Snarayan 		    "old tail 0x%x, new tail 0x%x, qsize=0x%x)\n",
46114690Snarayan 		    rv, ldcp->tx_head, ldcp->tx_tail, tx_tail,
46124690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
46131991Sheppo 
46141991Sheppo 		rv2 = hv_ldc_tx_get_state(ldcp->id,
46151991Sheppo 		    &tx_head, &tx_tail, &ldcp->link_state);
46161991Sheppo 
46173010Slm66018 		D1(ldcp->id, "hv_ldc_tx_get_state returns 0x%x "
46184690Snarayan 		    "(head 0x%x, tail 0x%x state 0x%x)\n",
46194690Snarayan 		    rv2, tx_head, tx_tail, ldcp->link_state);
46201991Sheppo 
46211991Sheppo 		*size = 0;
46221991Sheppo 	}
46231991Sheppo 
46241991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, *size);
46251991Sheppo 
46261991Sheppo 	return (rv);
46271991Sheppo }
46281991Sheppo 
46291991Sheppo /*
46301991Sheppo  * Write specified amount of bytes to the channel
46311991Sheppo  * in multiple pkts of pkt_payload size. Each
46321991Sheppo  * packet is tagged with an unique packet ID in
46332410Slm66018  * the case of a reliable link.
46341991Sheppo  *
46351991Sheppo  * On return, size contains the number of bytes written.
46361991Sheppo  * This function needs to ensure that the write size is < MTU size
46371991Sheppo  */
46381991Sheppo static int
46391991Sheppo i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
46401991Sheppo {
46412336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
46426408Sha137994 	ASSERT(ldcp->mode == LDC_MODE_RELIABLE);
46431991Sheppo 
46441991Sheppo 	/* Truncate packet to max of MTU size */
46451991Sheppo 	if (*sizep > ldcp->mtu) *sizep = ldcp->mtu;
46461991Sheppo 	return (i_ldc_write_packet(ldcp, buf, sizep));
46471991Sheppo }
46481991Sheppo 
46491991Sheppo 
46501991Sheppo /*
46511991Sheppo  * Interfaces for channel nexus to register/unregister with LDC module
46521991Sheppo  * The nexus will register functions to be used to register individual
46531991Sheppo  * channels with the nexus and enable interrupts for the channels
46541991Sheppo  */
46551991Sheppo int
46561991Sheppo ldc_register(ldc_cnex_t *cinfo)
46571991Sheppo {
46581991Sheppo 	ldc_chan_t	*ldcp;
46591991Sheppo 
46601991Sheppo 	if (cinfo == NULL || cinfo->dip == NULL ||
46611991Sheppo 	    cinfo->reg_chan == NULL || cinfo->unreg_chan == NULL ||
46621991Sheppo 	    cinfo->add_intr == NULL || cinfo->rem_intr == NULL ||
46631991Sheppo 	    cinfo->clr_intr == NULL) {
46641991Sheppo 
46651991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_register: invalid nexus info\n");
46661991Sheppo 		return (EINVAL);
46671991Sheppo 	}
46681991Sheppo 
46691991Sheppo 	mutex_enter(&ldcssp->lock);
46701991Sheppo 
46711991Sheppo 	/* nexus registration */
46721991Sheppo 	ldcssp->cinfo.dip = cinfo->dip;
46731991Sheppo 	ldcssp->cinfo.reg_chan = cinfo->reg_chan;
46741991Sheppo 	ldcssp->cinfo.unreg_chan = cinfo->unreg_chan;
46751991Sheppo 	ldcssp->cinfo.add_intr = cinfo->add_intr;
46761991Sheppo 	ldcssp->cinfo.rem_intr = cinfo->rem_intr;
46771991Sheppo 	ldcssp->cinfo.clr_intr = cinfo->clr_intr;
46781991Sheppo 
46791991Sheppo 	/* register any channels that might have been previously initialized */
46801991Sheppo 	ldcp = ldcssp->chan_list;
46811991Sheppo 	while (ldcp) {
46821991Sheppo 		if ((ldcp->tstate & TS_QCONF_RDY) &&
46831991Sheppo 		    (ldcp->tstate & TS_CNEX_RDY) == 0)
46841991Sheppo 			(void) i_ldc_register_channel(ldcp);
46851991Sheppo 
46861991Sheppo 		ldcp = ldcp->next;
46871991Sheppo 	}
46881991Sheppo 
46891991Sheppo 	mutex_exit(&ldcssp->lock);
46901991Sheppo 
46911991Sheppo 	return (0);
46921991Sheppo }
46931991Sheppo 
46941991Sheppo int
46951991Sheppo ldc_unregister(ldc_cnex_t *cinfo)
46961991Sheppo {
46971991Sheppo 	if (cinfo == NULL || cinfo->dip == NULL) {
46981991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid nexus info\n");
46991991Sheppo 		return (EINVAL);
47001991Sheppo 	}
47011991Sheppo 
47021991Sheppo 	mutex_enter(&ldcssp->lock);
47031991Sheppo 
47041991Sheppo 	if (cinfo->dip != ldcssp->cinfo.dip) {
47051991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid dip\n");
47061991Sheppo 		mutex_exit(&ldcssp->lock);
47071991Sheppo 		return (EINVAL);
47081991Sheppo 	}
47091991Sheppo 
47101991Sheppo 	/* nexus unregister */
47111991Sheppo 	ldcssp->cinfo.dip = NULL;
47121991Sheppo 	ldcssp->cinfo.reg_chan = NULL;
47131991Sheppo 	ldcssp->cinfo.unreg_chan = NULL;
47141991Sheppo 	ldcssp->cinfo.add_intr = NULL;
47151991Sheppo 	ldcssp->cinfo.rem_intr = NULL;
47161991Sheppo 	ldcssp->cinfo.clr_intr = NULL;
47171991Sheppo 
47181991Sheppo 	mutex_exit(&ldcssp->lock);
47191991Sheppo 
47201991Sheppo 	return (0);
47211991Sheppo }
4722