xref: /onnv-gate/usr/src/uts/sun4v/io/ldc.c (revision 5944:12a4b3347aac)
11991Sheppo /*
21991Sheppo  * CDDL HEADER START
31991Sheppo  *
41991Sheppo  * The contents of this file are subject to the terms of the
51991Sheppo  * Common Development and Distribution License (the "License").
61991Sheppo  * You may not use this file except in compliance with the License.
71991Sheppo  *
81991Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91991Sheppo  * or http://www.opensolaris.org/os/licensing.
101991Sheppo  * See the License for the specific language governing permissions
111991Sheppo  * and limitations under the License.
121991Sheppo  *
131991Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141991Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151991Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161991Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171991Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181991Sheppo  *
191991Sheppo  * CDDL HEADER END
201991Sheppo  */
211991Sheppo 
221991Sheppo /*
23*5944Sha137994  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241991Sheppo  * Use is subject to license terms.
251991Sheppo  */
261991Sheppo 
271991Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
281991Sheppo 
291991Sheppo /*
302410Slm66018  * sun4v LDC Link Layer
311991Sheppo  */
321991Sheppo #include <sys/types.h>
331991Sheppo #include <sys/file.h>
341991Sheppo #include <sys/errno.h>
351991Sheppo #include <sys/open.h>
361991Sheppo #include <sys/cred.h>
371991Sheppo #include <sys/kmem.h>
381991Sheppo #include <sys/conf.h>
391991Sheppo #include <sys/cmn_err.h>
401991Sheppo #include <sys/ksynch.h>
411991Sheppo #include <sys/modctl.h>
421991Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */
431991Sheppo #include <sys/debug.h>
441991Sheppo #include <sys/types.h>
451991Sheppo #include <sys/cred.h>
461991Sheppo #include <sys/promif.h>
471991Sheppo #include <sys/ddi.h>
481991Sheppo #include <sys/sunddi.h>
491991Sheppo #include <sys/cyclic.h>
501991Sheppo #include <sys/machsystm.h>
511991Sheppo #include <sys/vm.h>
521991Sheppo #include <sys/cpu.h>
531991Sheppo #include <sys/intreg.h>
541991Sheppo #include <sys/machcpuvar.h>
552531Snarayan #include <sys/mmu.h>
562531Snarayan #include <sys/pte.h>
572531Snarayan #include <vm/hat.h>
582531Snarayan #include <vm/as.h>
592531Snarayan #include <vm/hat_sfmmu.h>
602531Snarayan #include <sys/vm_machparam.h>
612531Snarayan #include <vm/seg_kmem.h>
622531Snarayan #include <vm/seg_kpm.h>
631991Sheppo #include <sys/note.h>
641991Sheppo #include <sys/ivintr.h>
651991Sheppo #include <sys/hypervisor_api.h>
661991Sheppo #include <sys/ldc.h>
671991Sheppo #include <sys/ldc_impl.h>
681991Sheppo #include <sys/cnex.h>
691991Sheppo #include <sys/hsvc.h>
70*5944Sha137994 #include <sys/sdt.h>
711991Sheppo 
721991Sheppo /* Core internal functions */
731991Sheppo static int i_ldc_h2v_error(int h_error);
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);
762841Snarayan static int i_ldc_rxq_drain(ldc_chan_t *ldcp);
771991Sheppo static void i_ldc_reset_state(ldc_chan_t *ldcp);
782793Slm66018 static void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset);
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 
87*5944Sha137994 static int  i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head);
88*5944Sha137994 static void i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head);
89*5944Sha137994 static uint64_t i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head,
90*5944Sha137994     uint64_t *tail, uint64_t *link_state);
91*5944Sha137994 static uint64_t i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head,
92*5944Sha137994     uint64_t *tail, uint64_t *link_state);
93*5944Sha137994 static int i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head,
94*5944Sha137994     uint64_t rx_tail);
95*5944Sha137994 static uint_t i_ldc_chkq(ldc_chan_t *ldcp);
96*5944Sha137994 
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);
100*5944Sha137994 static uint_t i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client,
101*5944Sha137994     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 /* Memory synchronization internal functions */
1291991Sheppo static int i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle,
1301991Sheppo     uint8_t direction, uint64_t offset, size_t size);
1311991Sheppo static int i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle,
1321991Sheppo     uint8_t direction, uint64_t start, uint64_t end);
1331991Sheppo 
1341991Sheppo /* LDC Version */
1351991Sheppo static ldc_ver_t ldc_versions[] = { {1, 0} };
1361991Sheppo 
1371991Sheppo /* number of supported versions */
1381991Sheppo #define	LDC_NUM_VERS	(sizeof (ldc_versions) / sizeof (ldc_versions[0]))
1391991Sheppo 
140*5944Sha137994 /* Invalid value for the ldc_chan_t rx_ack_head field */
141*5944Sha137994 #define	ACKPEEK_HEAD_INVALID	((uint64_t)-1)
142*5944Sha137994 
143*5944Sha137994 
1441991Sheppo /* Module State Pointer */
1451991Sheppo static ldc_soft_state_t *ldcssp;
1461991Sheppo 
1471991Sheppo static struct modldrv md = {
1481991Sheppo 	&mod_miscops,			/* This is a misc module */
1491991Sheppo 	"sun4v LDC module v%I%",	/* Name of the module */
1501991Sheppo };
1511991Sheppo 
1521991Sheppo static struct modlinkage ml = {
1531991Sheppo 	MODREV_1,
1541991Sheppo 	&md,
1551991Sheppo 	NULL
1561991Sheppo };
1571991Sheppo 
1581991Sheppo static uint64_t ldc_sup_minor;		/* Supported minor number */
1591991Sheppo static hsvc_info_t ldc_hsvc = {
1601991Sheppo 	HSVC_REV_1, NULL, HSVC_GROUP_LDC, 1, 0, "ldc"
1611991Sheppo };
1621991Sheppo 
1632531Snarayan /*
1642531Snarayan  * LDC framework supports mapping remote domain's memory
1652531Snarayan  * either directly or via shadow memory pages. Default
1662531Snarayan  * support is currently implemented via shadow copy.
1672531Snarayan  * Direct map can be enabled by setting 'ldc_shmem_enabled'
1682531Snarayan  */
1692531Snarayan int ldc_shmem_enabled = 0;
1702410Slm66018 
1712032Slm66018 /*
1722410Slm66018  * The no. of MTU size messages that can be stored in
1732410Slm66018  * the LDC Tx queue. The number of Tx queue entries is
1742410Slm66018  * then computed as (mtu * mtu_msgs)/sizeof(queue_entry)
1752410Slm66018  */
1762410Slm66018 uint64_t ldc_mtu_msgs = LDC_MTU_MSGS;
1772410Slm66018 
1782410Slm66018 /*
1792410Slm66018  * The minimum queue length. This is the size of the smallest
1802410Slm66018  * LDC queue. If the computed value is less than this default,
1812410Slm66018  * the queue length is rounded up to 'ldc_queue_entries'.
1822410Slm66018  */
1832410Slm66018 uint64_t ldc_queue_entries = LDC_QUEUE_ENTRIES;
1842410Slm66018 
1852410Slm66018 /*
186*5944Sha137994  * The length of the reliable-mode data queue in terms of the LDC
187*5944Sha137994  * receive queue length. i.e., the number of times larger than the
188*5944Sha137994  * LDC receive queue that the data queue should be. The HV receive
189*5944Sha137994  * queue is required to be a power of 2 and this implementation
190*5944Sha137994  * assumes the data queue will also be a power of 2. By making the
191*5944Sha137994  * multiplier a power of 2, we ensure the data queue will be a
192*5944Sha137994  * power of 2. We use a multiplier because the receive queue is
193*5944Sha137994  * sized to be sane relative to the MTU and the same is needed for
194*5944Sha137994  * the data queue.
195*5944Sha137994  */
196*5944Sha137994 uint64_t ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER;
197*5944Sha137994 
198*5944Sha137994 /*
1992410Slm66018  * Pages exported for remote access over each channel is
2002410Slm66018  * maintained in a table registered with the Hypervisor.
2012410Slm66018  * The default number of entries in the table is set to
2022410Slm66018  * 'ldc_mtbl_entries'.
2032410Slm66018  */
2042410Slm66018 uint64_t ldc_maptable_entries = LDC_MTBL_ENTRIES;
2052410Slm66018 
2062410Slm66018 /*
2072410Slm66018  * LDC retry count and delay - when the HV returns EWOULDBLOCK
2082410Slm66018  * the operation is retried 'ldc_max_retries' times with a
2092410Slm66018  * wait of 'ldc_delay' usecs between each retry.
2102032Slm66018  */
2112032Slm66018 int ldc_max_retries = LDC_MAX_RETRIES;
2122032Slm66018 clock_t ldc_delay = LDC_DELAY;
2132032Slm66018 
2143151Ssg70180 /*
2153151Ssg70180  * delay between each retry of channel unregistration in
2163151Ssg70180  * ldc_close(), to wait for pending interrupts to complete.
2173151Ssg70180  */
2183151Ssg70180 clock_t ldc_close_delay = LDC_CLOSE_DELAY;
2193151Ssg70180 
2201991Sheppo #ifdef DEBUG
2211991Sheppo 
2221991Sheppo /*
2231991Sheppo  * Print debug messages
2241991Sheppo  *
2251991Sheppo  * set ldcdbg to 0x7 for enabling all msgs
2261991Sheppo  * 0x4 - Warnings
2271991Sheppo  * 0x2 - All debug messages
2281991Sheppo  * 0x1 - Minimal debug messages
2291991Sheppo  *
2301991Sheppo  * set ldcdbgchan to the channel number you want to debug
2311991Sheppo  * setting it to -1 prints debug messages for all channels
2321991Sheppo  * NOTE: ldcdbgchan has no effect on error messages
2331991Sheppo  */
2341991Sheppo 
2351991Sheppo #define	DBG_ALL_LDCS -1
2361991Sheppo 
2371991Sheppo int ldcdbg = 0x0;
2381991Sheppo int64_t ldcdbgchan = DBG_ALL_LDCS;
2393560Snarayan uint64_t ldc_inject_err_flag = 0;
2401991Sheppo 
2411991Sheppo static void
2421991Sheppo ldcdebug(int64_t id, const char *fmt, ...)
2431991Sheppo {
2441991Sheppo 	char buf[512];
2451991Sheppo 	va_list ap;
2461991Sheppo 
2471991Sheppo 	/*
2481991Sheppo 	 * Do not return if,
2491991Sheppo 	 * caller wants to print it anyway - (id == DBG_ALL_LDCS)
2501991Sheppo 	 * debug channel is set to all LDCs - (ldcdbgchan == DBG_ALL_LDCS)
2511991Sheppo 	 * debug channel = caller specified channel
2521991Sheppo 	 */
2531991Sheppo 	if ((id != DBG_ALL_LDCS) &&
2541991Sheppo 	    (ldcdbgchan != DBG_ALL_LDCS) &&
2551991Sheppo 	    (ldcdbgchan != id)) {
2561991Sheppo 		return;
2571991Sheppo 	}
2581991Sheppo 
2591991Sheppo 	va_start(ap, fmt);
2601991Sheppo 	(void) vsprintf(buf, fmt, ap);
2611991Sheppo 	va_end(ap);
2621991Sheppo 
2632793Slm66018 	cmn_err(CE_CONT, "?%s", buf);
2642793Slm66018 }
2652793Slm66018 
2663560Snarayan #define	LDC_ERR_RESET	0x1
2673560Snarayan #define	LDC_ERR_PKTLOSS	0x2
268*5944Sha137994 #define	LDC_ERR_DQFULL	0x4
2693560Snarayan 
2702793Slm66018 static boolean_t
2713560Snarayan ldc_inject_error(ldc_chan_t *ldcp, uint64_t error)
2722793Slm66018 {
2732793Slm66018 	if ((ldcdbgchan != DBG_ALL_LDCS) && (ldcdbgchan != ldcp->id))
2742793Slm66018 		return (B_FALSE);
2752793Slm66018 
2763560Snarayan 	if ((ldc_inject_err_flag & error) == 0)
2772793Slm66018 		return (B_FALSE);
2782793Slm66018 
2792793Slm66018 	/* clear the injection state */
2803560Snarayan 	ldc_inject_err_flag &= ~error;
2812793Slm66018 
2822793Slm66018 	return (B_TRUE);
2831991Sheppo }
2841991Sheppo 
2851991Sheppo #define	D1		\
2861991Sheppo if (ldcdbg & 0x01)	\
2871991Sheppo 	ldcdebug
2881991Sheppo 
2891991Sheppo #define	D2		\
2901991Sheppo if (ldcdbg & 0x02)	\
2911991Sheppo 	ldcdebug
2921991Sheppo 
2931991Sheppo #define	DWARN		\
2941991Sheppo if (ldcdbg & 0x04)	\
2951991Sheppo 	ldcdebug
2961991Sheppo 
2971991Sheppo #define	DUMP_PAYLOAD(id, addr)						\
2981991Sheppo {									\
2991991Sheppo 	char buf[65*3];							\
3001991Sheppo 	int i;								\
3011991Sheppo 	uint8_t *src = (uint8_t *)addr;					\
3021991Sheppo 	for (i = 0; i < 64; i++, src++)					\
3031991Sheppo 		(void) sprintf(&buf[i * 3], "|%02x", *src);		\
3041991Sheppo 	(void) sprintf(&buf[i * 3], "|\n");				\
3051991Sheppo 	D2((id), "payload: %s", buf);					\
3061991Sheppo }
3071991Sheppo 
3081991Sheppo #define	DUMP_LDC_PKT(c, s, addr)					\
3091991Sheppo {									\
3101991Sheppo 	ldc_msg_t *msg = (ldc_msg_t *)(addr);				\
3111991Sheppo 	uint32_t mid = ((c)->mode != LDC_MODE_RAW) ? msg->seqid : 0;	\
3121991Sheppo 	if (msg->type == LDC_DATA) {                                    \
3131991Sheppo 	    D2((c)->id, "%s: msg%d (/%x/%x/%x/,env[%c%c,sz=%d])",	\
3141991Sheppo 	    (s), mid, msg->type, msg->stype, msg->ctrl,			\
3151991Sheppo 	    (msg->env & LDC_FRAG_START) ? 'B' : ' ',                    \
3161991Sheppo 	    (msg->env & LDC_FRAG_STOP) ? 'E' : ' ',                     \
3171991Sheppo 	    (msg->env & LDC_LEN_MASK));					\
3181991Sheppo 	} else { 							\
3191991Sheppo 	    D2((c)->id, "%s: msg%d (/%x/%x/%x/,env=%x)", (s),		\
3201991Sheppo 	    mid, msg->type, msg->stype, msg->ctrl, msg->env);		\
3211991Sheppo 	} 								\
3221991Sheppo }
3231991Sheppo 
3243560Snarayan #define	LDC_INJECT_RESET(_ldcp)	ldc_inject_error(_ldcp, LDC_ERR_RESET)
3253560Snarayan #define	LDC_INJECT_PKTLOSS(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_PKTLOSS)
326*5944Sha137994 #define	LDC_INJECT_DQFULL(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DQFULL)
3272793Slm66018 
3281991Sheppo #else
3291991Sheppo 
3301991Sheppo #define	DBG_ALL_LDCS -1
3311991Sheppo 
3321991Sheppo #define	D1
3331991Sheppo #define	D2
3341991Sheppo #define	DWARN
3351991Sheppo 
3361991Sheppo #define	DUMP_PAYLOAD(id, addr)
3371991Sheppo #define	DUMP_LDC_PKT(c, s, addr)
3381991Sheppo 
3392793Slm66018 #define	LDC_INJECT_RESET(_ldcp)	(B_FALSE)
3403560Snarayan #define	LDC_INJECT_PKTLOSS(_ldcp) (B_FALSE)
341*5944Sha137994 #define	LDC_INJECT_DQFULL(_ldcp) (B_FALSE)
3422793Slm66018 
3431991Sheppo #endif
3441991Sheppo 
345*5944Sha137994 /*
346*5944Sha137994  * dtrace SDT probes to ease tracing of the rx data queue and HV queue
347*5944Sha137994  * lengths. Just pass the head, tail, and entries values so that the
348*5944Sha137994  * length can be calculated in a dtrace script when the probe is enabled.
349*5944Sha137994  */
350*5944Sha137994 #define	TRACE_RXDQ_LENGTH(ldcp)						\
351*5944Sha137994 	DTRACE_PROBE4(rxdq__size,					\
352*5944Sha137994 	uint64_t, ldcp->id,						\
353*5944Sha137994 	uint64_t, ldcp->rx_dq_head,					\
354*5944Sha137994 	uint64_t, ldcp->rx_dq_tail,					\
355*5944Sha137994 	uint64_t, ldcp->rx_dq_entries)
356*5944Sha137994 
357*5944Sha137994 #define	TRACE_RXHVQ_LENGTH(ldcp, head, tail)				\
358*5944Sha137994 	DTRACE_PROBE4(rxhvq__size,					\
359*5944Sha137994 	uint64_t, ldcp->id,						\
360*5944Sha137994 	uint64_t, head,							\
361*5944Sha137994 	uint64_t, tail,							\
362*5944Sha137994 	uint64_t, ldcp->rx_q_entries)
363*5944Sha137994 
364*5944Sha137994 /* A dtrace SDT probe to ease tracing of data queue copy operations */
365*5944Sha137994 #define	TRACE_RXDQ_COPY(ldcp, bytes)					\
366*5944Sha137994 	DTRACE_PROBE2(rxdq__copy, uint64_t, ldcp->id, uint64_t, bytes)	\
367*5944Sha137994 
368*5944Sha137994 /* The amount of contiguous space at the tail of the queue */
369*5944Sha137994 #define	Q_CONTIG_SPACE(head, tail, size)				\
370*5944Sha137994 	((head) <= (tail) ? ((size) - (tail)) :				\
371*5944Sha137994 	((head) - (tail) - LDC_PACKET_SIZE))
372*5944Sha137994 
3731991Sheppo #define	ZERO_PKT(p)			\
3741991Sheppo 	bzero((p), sizeof (ldc_msg_t));
3751991Sheppo 
3761991Sheppo #define	IDX2COOKIE(idx, pg_szc, pg_shift)				\
3771991Sheppo 	(((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift)))
3781991Sheppo 
3791991Sheppo int
3801991Sheppo _init(void)
3811991Sheppo {
3821991Sheppo 	int status;
3831991Sheppo 
3841991Sheppo 	status = hsvc_register(&ldc_hsvc, &ldc_sup_minor);
3851991Sheppo 	if (status != 0) {
3864423Sjb145095 		cmn_err(CE_NOTE, "!%s: cannot negotiate hypervisor LDC services"
3871991Sheppo 		    " group: 0x%lx major: %ld minor: %ld errno: %d",
3881991Sheppo 		    ldc_hsvc.hsvc_modname, ldc_hsvc.hsvc_group,
3891991Sheppo 		    ldc_hsvc.hsvc_major, ldc_hsvc.hsvc_minor, status);
3901991Sheppo 		return (-1);
3911991Sheppo 	}
3921991Sheppo 
3931991Sheppo 	/* allocate soft state structure */
3941991Sheppo 	ldcssp = kmem_zalloc(sizeof (ldc_soft_state_t), KM_SLEEP);
3951991Sheppo 
3961991Sheppo 	/* Link the module into the system */
3971991Sheppo 	status = mod_install(&ml);
3981991Sheppo 	if (status != 0) {
3991991Sheppo 		kmem_free(ldcssp, sizeof (ldc_soft_state_t));
4001991Sheppo 		return (status);
4011991Sheppo 	}
4021991Sheppo 
4031991Sheppo 	/* Initialize the LDC state structure */
4041991Sheppo 	mutex_init(&ldcssp->lock, NULL, MUTEX_DRIVER, NULL);
4051991Sheppo 
4061991Sheppo 	mutex_enter(&ldcssp->lock);
4071991Sheppo 
4082531Snarayan 	/* Create a cache for memory handles */
4092531Snarayan 	ldcssp->memhdl_cache = kmem_cache_create("ldc_memhdl_cache",
4102531Snarayan 	    sizeof (ldc_mhdl_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
4112531Snarayan 	if (ldcssp->memhdl_cache == NULL) {
4122531Snarayan 		DWARN(DBG_ALL_LDCS, "_init: ldc_memhdl cache create failed\n");
4132531Snarayan 		mutex_exit(&ldcssp->lock);
4142531Snarayan 		return (-1);
4152531Snarayan 	}
4162531Snarayan 
4172531Snarayan 	/* Create cache for memory segment structures */
4182531Snarayan 	ldcssp->memseg_cache = kmem_cache_create("ldc_memseg_cache",
4192531Snarayan 	    sizeof (ldc_memseg_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
4202531Snarayan 	if (ldcssp->memseg_cache == NULL) {
4212531Snarayan 		DWARN(DBG_ALL_LDCS, "_init: ldc_memseg cache create failed\n");
4222531Snarayan 		mutex_exit(&ldcssp->lock);
4232531Snarayan 		return (-1);
4242531Snarayan 	}
4252531Snarayan 
4262531Snarayan 
4271991Sheppo 	ldcssp->channel_count = 0;
4281991Sheppo 	ldcssp->channels_open = 0;
4291991Sheppo 	ldcssp->chan_list = NULL;
4301991Sheppo 	ldcssp->dring_list = NULL;
4311991Sheppo 
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 
4591991Sheppo 	/* Free descriptor rings */
4601991Sheppo 	dringp = ldcssp->dring_list;
4611991Sheppo 	while (dringp != NULL) {
4624690Snarayan 		tmp_dringp = dringp->next;
4631991Sheppo 
4641991Sheppo 		rv = ldc_mem_dring_info((ldc_dring_handle_t)dringp, &minfo);
4651991Sheppo 		if (rv == 0 && minfo.status != LDC_UNBOUND) {
4661991Sheppo 			if (minfo.status == LDC_BOUND) {
4671991Sheppo 				(void) ldc_mem_dring_unbind(
4684690Snarayan 				    (ldc_dring_handle_t)dringp);
4691991Sheppo 			}
4701991Sheppo 			if (minfo.status == LDC_MAPPED) {
4711991Sheppo 				(void) ldc_mem_dring_unmap(
4724690Snarayan 				    (ldc_dring_handle_t)dringp);
4731991Sheppo 			}
4741991Sheppo 		}
4751991Sheppo 
4761991Sheppo 		(void) ldc_mem_dring_destroy((ldc_dring_handle_t)dringp);
4774690Snarayan 		dringp = tmp_dringp;
4781991Sheppo 	}
4791991Sheppo 	ldcssp->dring_list = NULL;
4801991Sheppo 
4814690Snarayan 	/* close and finalize channels */
4824690Snarayan 	ldcp = ldcssp->chan_list;
4834690Snarayan 	while (ldcp != NULL) {
4844690Snarayan 		tmp_ldcp = ldcp->next;
4854690Snarayan 
4864690Snarayan 		(void) ldc_close((ldc_handle_t)ldcp);
4874690Snarayan 		(void) ldc_fini((ldc_handle_t)ldcp);
4884690Snarayan 
4894690Snarayan 		ldcp = tmp_ldcp;
4904690Snarayan 	}
4914690Snarayan 	ldcssp->chan_list = NULL;
4924690Snarayan 
4932531Snarayan 	/* Destroy kmem caches */
4942531Snarayan 	kmem_cache_destroy(ldcssp->memhdl_cache);
4952531Snarayan 	kmem_cache_destroy(ldcssp->memseg_cache);
4962531Snarayan 
4971991Sheppo 	/*
4981991Sheppo 	 * We have successfully "removed" the driver.
4991991Sheppo 	 * Destroying soft states
5001991Sheppo 	 */
5011991Sheppo 	mutex_destroy(&ldcssp->lock);
5021991Sheppo 	kmem_free(ldcssp, sizeof (ldc_soft_state_t));
5031991Sheppo 
5041991Sheppo 	(void) hsvc_unregister(&ldc_hsvc);
5051991Sheppo 
5061991Sheppo 	return (status);
5071991Sheppo }
5081991Sheppo 
5091991Sheppo /* -------------------------------------------------------------------------- */
5101991Sheppo 
5111991Sheppo /*
5122410Slm66018  * LDC Link Layer Internal Functions
5131991Sheppo  */
5141991Sheppo 
5151991Sheppo /*
5161991Sheppo  * Translate HV Errors to sun4v error codes
5171991Sheppo  */
5181991Sheppo static int
5191991Sheppo i_ldc_h2v_error(int h_error)
5201991Sheppo {
5211991Sheppo 	switch (h_error) {
5221991Sheppo 
5231991Sheppo 	case	H_EOK:
5241991Sheppo 		return (0);
5251991Sheppo 
5261991Sheppo 	case	H_ENORADDR:
5271991Sheppo 		return (EFAULT);
5281991Sheppo 
5291991Sheppo 	case	H_EBADPGSZ:
5301991Sheppo 	case	H_EINVAL:
5311991Sheppo 		return (EINVAL);
5321991Sheppo 
5331991Sheppo 	case	H_EWOULDBLOCK:
5341991Sheppo 		return (EWOULDBLOCK);
5351991Sheppo 
5361991Sheppo 	case	H_ENOACCESS:
5371991Sheppo 	case	H_ENOMAP:
5381991Sheppo 		return (EACCES);
5391991Sheppo 
5401991Sheppo 	case	H_EIO:
5411991Sheppo 	case	H_ECPUERROR:
5421991Sheppo 		return (EIO);
5431991Sheppo 
5441991Sheppo 	case	H_ENOTSUPPORTED:
5451991Sheppo 		return (ENOTSUP);
5461991Sheppo 
5471991Sheppo 	case 	H_ETOOMANY:
5481991Sheppo 		return (ENOSPC);
5491991Sheppo 
5501991Sheppo 	case	H_ECHANNEL:
5511991Sheppo 		return (ECHRNG);
5521991Sheppo 	default:
5531991Sheppo 		break;
5541991Sheppo 	}
5551991Sheppo 
5561991Sheppo 	return (EIO);
5571991Sheppo }
5581991Sheppo 
5591991Sheppo /*
5601991Sheppo  * Reconfigure the transmit queue
5611991Sheppo  */
5621991Sheppo static int
5631991Sheppo i_ldc_txq_reconf(ldc_chan_t *ldcp)
5641991Sheppo {
5651991Sheppo 	int rv;
5661991Sheppo 
5671991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
5682336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
5692336Snarayan 
5701991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
5711991Sheppo 	if (rv) {
5721991Sheppo 		cmn_err(CE_WARN,
5732793Slm66018 		    "i_ldc_txq_reconf: (0x%lx) cannot set qconf", ldcp->id);
5741991Sheppo 		return (EIO);
5751991Sheppo 	}
5761991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id, &(ldcp->tx_head),
5771991Sheppo 	    &(ldcp->tx_tail), &(ldcp->link_state));
5781991Sheppo 	if (rv) {
5791991Sheppo 		cmn_err(CE_WARN,
5802793Slm66018 		    "i_ldc_txq_reconf: (0x%lx) cannot get qptrs", ldcp->id);
5811991Sheppo 		return (EIO);
5821991Sheppo 	}
5832793Slm66018 	D1(ldcp->id, "i_ldc_txq_reconf: (0x%llx) h=0x%llx,t=0x%llx,"
5841991Sheppo 	    "s=0x%llx\n", ldcp->id, ldcp->tx_head, ldcp->tx_tail,
5851991Sheppo 	    ldcp->link_state);
5861991Sheppo 
5871991Sheppo 	return (0);
5881991Sheppo }
5891991Sheppo 
5901991Sheppo /*
5911991Sheppo  * Reconfigure the receive queue
5921991Sheppo  */
5931991Sheppo static int
5942793Slm66018 i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset)
5951991Sheppo {
5961991Sheppo 	int rv;
5971991Sheppo 	uint64_t rx_head, rx_tail;
5981991Sheppo 
5991991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
6001991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
6011991Sheppo 	    &(ldcp->link_state));
6021991Sheppo 	if (rv) {
6031991Sheppo 		cmn_err(CE_WARN,
6042793Slm66018 		    "i_ldc_rxq_reconf: (0x%lx) cannot get state",
6051991Sheppo 		    ldcp->id);
6061991Sheppo 		return (EIO);
6071991Sheppo 	}
6081991Sheppo 
6092793Slm66018 	if (force_reset || (ldcp->tstate & ~TS_IN_RESET) == TS_UP) {
6101991Sheppo 		rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra,
6114690Snarayan 		    ldcp->rx_q_entries);
6121991Sheppo 		if (rv) {
6131991Sheppo 			cmn_err(CE_WARN,
6142793Slm66018 			    "i_ldc_rxq_reconf: (0x%lx) cannot set qconf",
6151991Sheppo 			    ldcp->id);
6161991Sheppo 			return (EIO);
6171991Sheppo 		}
6182793Slm66018 		D1(ldcp->id, "i_ldc_rxq_reconf: (0x%llx) completed q reconf",
6191991Sheppo 		    ldcp->id);
6201991Sheppo 	}
6211991Sheppo 
6221991Sheppo 	return (0);
6231991Sheppo }
6241991Sheppo 
6252841Snarayan 
6262841Snarayan /*
6272841Snarayan  * Drain the contents of the receive queue
6282841Snarayan  */
6292841Snarayan static int
6302841Snarayan i_ldc_rxq_drain(ldc_chan_t *ldcp)
6312841Snarayan {
6322841Snarayan 	int rv;
6332841Snarayan 	uint64_t rx_head, rx_tail;
6342841Snarayan 
6352841Snarayan 	ASSERT(MUTEX_HELD(&ldcp->lock));
6362841Snarayan 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
6372841Snarayan 	    &(ldcp->link_state));
6382841Snarayan 	if (rv) {
6392841Snarayan 		cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot get state",
6402841Snarayan 		    ldcp->id);
6412841Snarayan 		return (EIO);
6422841Snarayan 	}
6432841Snarayan 
6442841Snarayan 	/* flush contents by setting the head = tail */
6452841Snarayan 	return (i_ldc_set_rx_head(ldcp, rx_tail));
6462841Snarayan }
6472841Snarayan 
6482841Snarayan 
6491991Sheppo /*
6501991Sheppo  * Reset LDC state structure and its contents
6511991Sheppo  */
6521991Sheppo static void
6531991Sheppo i_ldc_reset_state(ldc_chan_t *ldcp)
6541991Sheppo {
6551991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
6561991Sheppo 	ldcp->last_msg_snt = LDC_INIT_SEQID;
6571991Sheppo 	ldcp->last_ack_rcd = 0;
6581991Sheppo 	ldcp->last_msg_rcd = 0;
6591991Sheppo 	ldcp->tx_ackd_head = ldcp->tx_head;
660*5944Sha137994 	ldcp->stream_remains = 0;
6611991Sheppo 	ldcp->next_vidx = 0;
6621991Sheppo 	ldcp->hstate = 0;
6631991Sheppo 	ldcp->tstate = TS_OPEN;
6641991Sheppo 	ldcp->status = LDC_OPEN;
665*5944Sha137994 	ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
666*5944Sha137994 	ldcp->rx_dq_head = 0;
667*5944Sha137994 	ldcp->rx_dq_tail = 0;
6681991Sheppo 
6691991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_UP ||
6701991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
6711991Sheppo 
6721991Sheppo 		if (ldcp->mode == LDC_MODE_RAW) {
6731991Sheppo 			ldcp->status = LDC_UP;
6741991Sheppo 			ldcp->tstate = TS_UP;
6751991Sheppo 		} else {
6761991Sheppo 			ldcp->status = LDC_READY;
6771991Sheppo 			ldcp->tstate |= TS_LINK_READY;
6781991Sheppo 		}
6791991Sheppo 	}
6801991Sheppo }
6811991Sheppo 
6821991Sheppo /*
6831991Sheppo  * Reset a LDC channel
6841991Sheppo  */
6851991Sheppo static void
6862793Slm66018 i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset)
6871991Sheppo {
6883560Snarayan 	DWARN(ldcp->id, "i_ldc_reset: (0x%llx) channel reset\n", ldcp->id);
6891991Sheppo 
6902336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->lock));
6912336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
6922336Snarayan 
6932793Slm66018 	/* reconfig Tx and Rx queues */
6941991Sheppo 	(void) i_ldc_txq_reconf(ldcp);
6952793Slm66018 	(void) i_ldc_rxq_reconf(ldcp, force_reset);
6962793Slm66018 
6972793Slm66018 	/* Clear Tx and Rx interrupts */
6982793Slm66018 	(void) i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
6992793Slm66018 	(void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
7002793Slm66018 
7012793Slm66018 	/* Reset channel state */
7021991Sheppo 	i_ldc_reset_state(ldcp);
7032793Slm66018 
7042793Slm66018 	/* Mark channel in reset */
7052793Slm66018 	ldcp->tstate |= TS_IN_RESET;
7061991Sheppo }
7071991Sheppo 
7082531Snarayan 
7091991Sheppo /*
7101991Sheppo  * Clear pending interrupts
7111991Sheppo  */
7121991Sheppo static void
7131991Sheppo i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype)
7141991Sheppo {
7151991Sheppo 	ldc_cnex_t *cinfo = &ldcssp->cinfo;
7161991Sheppo 
7171991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
7182793Slm66018 	ASSERT(cinfo->dip != NULL);
7192793Slm66018 
7202793Slm66018 	switch (itype) {
7212793Slm66018 	case CNEX_TX_INTR:
7222531Snarayan 		/* check Tx interrupt */
7232793Slm66018 		if (ldcp->tx_intr_state)
7242793Slm66018 			ldcp->tx_intr_state = LDC_INTR_NONE;
7252793Slm66018 		else
7262793Slm66018 			return;
7272793Slm66018 		break;
7282793Slm66018 
7292793Slm66018 	case CNEX_RX_INTR:
7302531Snarayan 		/* check Rx interrupt */
7312793Slm66018 		if (ldcp->rx_intr_state)
7322793Slm66018 			ldcp->rx_intr_state = LDC_INTR_NONE;
7332793Slm66018 		else
7342793Slm66018 			return;
7352793Slm66018 		break;
7362793Slm66018 	}
7372793Slm66018 
7382793Slm66018 	(void) cinfo->clr_intr(cinfo->dip, ldcp->id, itype);
7392793Slm66018 	D2(ldcp->id,
7402793Slm66018 	    "i_ldc_clear_intr: (0x%llx) cleared 0x%x intr\n",
7412793Slm66018 	    ldcp->id, itype);
7421991Sheppo }
7431991Sheppo 
7441991Sheppo /*
7451991Sheppo  * Set the receive queue head
7462032Slm66018  * Resets connection and returns an error if it fails.
7471991Sheppo  */
7481991Sheppo static int
7491991Sheppo i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head)
7501991Sheppo {
7512032Slm66018 	int 	rv;
7522032Slm66018 	int 	retries;
7531991Sheppo 
7541991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
7552032Slm66018 	for (retries = 0; retries < ldc_max_retries; retries++) {
7562032Slm66018 
7572032Slm66018 		if ((rv = hv_ldc_rx_set_qhead(ldcp->id, head)) == 0)
7582032Slm66018 			return (0);
7592032Slm66018 
7602032Slm66018 		if (rv != H_EWOULDBLOCK)
7612032Slm66018 			break;
7622032Slm66018 
7632032Slm66018 		/* wait for ldc_delay usecs */
7642032Slm66018 		drv_usecwait(ldc_delay);
7652032Slm66018 	}
7662032Slm66018 
7672032Slm66018 	cmn_err(CE_WARN, "ldc_rx_set_qhead: (0x%lx) cannot set qhead 0x%lx",
7684690Snarayan 	    ldcp->id, head);
7692336Snarayan 	mutex_enter(&ldcp->tx_lock);
7702793Slm66018 	i_ldc_reset(ldcp, B_TRUE);
7712336Snarayan 	mutex_exit(&ldcp->tx_lock);
7722032Slm66018 
7732032Slm66018 	return (ECONNRESET);
7741991Sheppo }
7751991Sheppo 
7764690Snarayan /*
7774690Snarayan  * Returns the tx_head to be used for transfer
7784690Snarayan  */
7794690Snarayan static void
7804690Snarayan i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head)
7814690Snarayan {
7824690Snarayan 	ldc_msg_t 	*pkt;
7834690Snarayan 
7844690Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
7854690Snarayan 
7864690Snarayan 	/* get current Tx head */
7874690Snarayan 	*head = ldcp->tx_head;
7884690Snarayan 
7894690Snarayan 	/*
7904690Snarayan 	 * Reliable mode will use the ACKd head instead of the regular tx_head.
7914690Snarayan 	 * Also in Reliable mode, advance ackd_head for all non DATA/INFO pkts,
7924690Snarayan 	 * up to the current location of tx_head. This needs to be done
7934690Snarayan 	 * as the peer will only ACK DATA/INFO pkts.
7944690Snarayan 	 */
7954690Snarayan 	if (ldcp->mode == LDC_MODE_RELIABLE || ldcp->mode == LDC_MODE_STREAM) {
7964690Snarayan 		while (ldcp->tx_ackd_head != ldcp->tx_head) {
7974690Snarayan 			pkt = (ldc_msg_t *)(ldcp->tx_q_va + ldcp->tx_ackd_head);
7984690Snarayan 			if ((pkt->type & LDC_DATA) && (pkt->stype & LDC_INFO)) {
7994690Snarayan 				break;
8004690Snarayan 			}
8014690Snarayan 			/* advance ACKd head */
8024690Snarayan 			ldcp->tx_ackd_head =
8034690Snarayan 			    (ldcp->tx_ackd_head + LDC_PACKET_SIZE) %
8044690Snarayan 			    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
8054690Snarayan 		}
8064690Snarayan 		*head = ldcp->tx_ackd_head;
8074690Snarayan 	}
8084690Snarayan }
8091991Sheppo 
8101991Sheppo /*
8111991Sheppo  * Returns the tx_tail to be used for transfer
8121991Sheppo  * Re-reads the TX queue ptrs if and only if the
8131991Sheppo  * the cached head and tail are equal (queue is full)
8141991Sheppo  */
8151991Sheppo static int
8161991Sheppo i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail)
8171991Sheppo {
8181991Sheppo 	int 		rv;
8191991Sheppo 	uint64_t 	current_head, new_tail;
8201991Sheppo 
8212336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
8221991Sheppo 	/* Read the head and tail ptrs from HV */
8231991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
8241991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
8251991Sheppo 	if (rv) {
8261991Sheppo 		cmn_err(CE_WARN,
8271991Sheppo 		    "i_ldc_get_tx_tail: (0x%lx) cannot read qptrs\n",
8281991Sheppo 		    ldcp->id);
8291991Sheppo 		return (EIO);
8301991Sheppo 	}
8311991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN) {
8323010Slm66018 		D1(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) channel not ready\n",
8331991Sheppo 		    ldcp->id);
8341991Sheppo 		return (ECONNRESET);
8351991Sheppo 	}
8361991Sheppo 
8374690Snarayan 	i_ldc_get_tx_head(ldcp, &current_head);
8381991Sheppo 
8391991Sheppo 	/* increment the tail */
8401991Sheppo 	new_tail = (ldcp->tx_tail + LDC_PACKET_SIZE) %
8414690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
8421991Sheppo 
8431991Sheppo 	if (new_tail == current_head) {
8441991Sheppo 		DWARN(ldcp->id,
8451991Sheppo 		    "i_ldc_get_tx_tail: (0x%llx) TX queue is full\n",
8461991Sheppo 		    ldcp->id);
8471991Sheppo 		return (EWOULDBLOCK);
8481991Sheppo 	}
8491991Sheppo 
8501991Sheppo 	D2(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) head=0x%llx, tail=0x%llx\n",
8511991Sheppo 	    ldcp->id, ldcp->tx_head, ldcp->tx_tail);
8521991Sheppo 
8531991Sheppo 	*tail = ldcp->tx_tail;
8541991Sheppo 	return (0);
8551991Sheppo }
8561991Sheppo 
8571991Sheppo /*
8581991Sheppo  * Set the tail pointer. If HV returns EWOULDBLOCK, it will back off
8592032Slm66018  * and retry ldc_max_retries times before returning an error.
8601991Sheppo  * Returns 0, EWOULDBLOCK or EIO
8611991Sheppo  */
8621991Sheppo static int
8631991Sheppo i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail)
8641991Sheppo {
8651991Sheppo 	int		rv, retval = EWOULDBLOCK;
8662032Slm66018 	int 		retries;
8671991Sheppo 
8682336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
8692032Slm66018 	for (retries = 0; retries < ldc_max_retries; retries++) {
8701991Sheppo 
8711991Sheppo 		if ((rv = hv_ldc_tx_set_qtail(ldcp->id, tail)) == 0) {
8721991Sheppo 			retval = 0;
8731991Sheppo 			break;
8741991Sheppo 		}
8751991Sheppo 		if (rv != H_EWOULDBLOCK) {
8761991Sheppo 			DWARN(ldcp->id, "i_ldc_set_tx_tail: (0x%llx) set "
8771991Sheppo 			    "qtail=0x%llx failed, rv=%d\n", ldcp->id, tail, rv);
8781991Sheppo 			retval = EIO;
8791991Sheppo 			break;
8801991Sheppo 		}
8811991Sheppo 
8822032Slm66018 		/* wait for ldc_delay usecs */
8832032Slm66018 		drv_usecwait(ldc_delay);
8841991Sheppo 	}
8851991Sheppo 	return (retval);
8861991Sheppo }
8871991Sheppo 
8881991Sheppo /*
889*5944Sha137994  * Copy a data packet from the HV receive queue to the data queue.
890*5944Sha137994  * Caller must ensure that the data queue is not already full.
891*5944Sha137994  *
892*5944Sha137994  * The *head argument represents the current head pointer for the HV
893*5944Sha137994  * receive queue. After copying a packet from the HV receive queue,
894*5944Sha137994  * the *head pointer will be updated. This allows the caller to update
895*5944Sha137994  * the head pointer in HV using the returned *head value.
896*5944Sha137994  */
897*5944Sha137994 void
898*5944Sha137994 i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head)
899*5944Sha137994 {
900*5944Sha137994 	uint64_t	q_size, dq_size;
901*5944Sha137994 
902*5944Sha137994 	ASSERT(MUTEX_HELD(&ldcp->lock));
903*5944Sha137994 
904*5944Sha137994 	q_size  = ldcp->rx_q_entries << LDC_PACKET_SHIFT;
905*5944Sha137994 	dq_size = ldcp->rx_dq_entries << LDC_PACKET_SHIFT;
906*5944Sha137994 
907*5944Sha137994 	ASSERT(Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail,
908*5944Sha137994 	    dq_size) >= LDC_PACKET_SIZE);
909*5944Sha137994 
910*5944Sha137994 	bcopy((void *)(ldcp->rx_q_va + *head),
911*5944Sha137994 	    (void *)(ldcp->rx_dq_va + ldcp->rx_dq_tail), LDC_PACKET_SIZE);
912*5944Sha137994 	TRACE_RXDQ_COPY(ldcp, LDC_PACKET_SIZE);
913*5944Sha137994 
914*5944Sha137994 	/* Update rx head */
915*5944Sha137994 	*head = (*head + LDC_PACKET_SIZE) % q_size;
916*5944Sha137994 
917*5944Sha137994 	/* Update dq tail */
918*5944Sha137994 	ldcp->rx_dq_tail = (ldcp->rx_dq_tail + LDC_PACKET_SIZE) % dq_size;
919*5944Sha137994 }
920*5944Sha137994 
921*5944Sha137994 /*
922*5944Sha137994  * Update the Rx data queue head pointer
923*5944Sha137994  */
924*5944Sha137994 static int
925*5944Sha137994 i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head)
926*5944Sha137994 {
927*5944Sha137994 	ldcp->rx_dq_head = head;
928*5944Sha137994 	return (0);
929*5944Sha137994 }
930*5944Sha137994 
931*5944Sha137994 /*
932*5944Sha137994  * Get the Rx data queue head and tail pointers
933*5944Sha137994  */
934*5944Sha137994 static uint64_t
935*5944Sha137994 i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail,
936*5944Sha137994     uint64_t *link_state)
937*5944Sha137994 {
938*5944Sha137994 	_NOTE(ARGUNUSED(link_state))
939*5944Sha137994 	*head = ldcp->rx_dq_head;
940*5944Sha137994 	*tail = ldcp->rx_dq_tail;
941*5944Sha137994 	return (0);
942*5944Sha137994 }
943*5944Sha137994 
944*5944Sha137994 /*
945*5944Sha137994  * Wrapper for the Rx HV queue set head function. Giving the
946*5944Sha137994  * data queue and HV queue set head functions the same type.
947*5944Sha137994  */
948*5944Sha137994 static uint64_t
949*5944Sha137994 i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail,
950*5944Sha137994     uint64_t *link_state)
951*5944Sha137994 {
952*5944Sha137994 	return (i_ldc_h2v_error(hv_ldc_rx_get_state(ldcp->id, head, tail,
953*5944Sha137994 	    link_state)));
954*5944Sha137994 }
955*5944Sha137994 
956*5944Sha137994 /*
957*5944Sha137994  * LDC receive interrupt handler
958*5944Sha137994  *    triggered for channel with data pending to read
959*5944Sha137994  *    i.e. Rx queue content changes
960*5944Sha137994  */
961*5944Sha137994 static uint_t
962*5944Sha137994 i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2)
963*5944Sha137994 {
964*5944Sha137994 	_NOTE(ARGUNUSED(arg2))
965*5944Sha137994 
966*5944Sha137994 	ldc_chan_t	*ldcp;
967*5944Sha137994 	boolean_t	notify;
968*5944Sha137994 	uint64_t	event;
969*5944Sha137994 	int		rv;
970*5944Sha137994 
971*5944Sha137994 	/* Get the channel for which interrupt was received */
972*5944Sha137994 	if (arg1 == NULL) {
973*5944Sha137994 		cmn_err(CE_WARN, "i_ldc_rx_hdlr: invalid arg\n");
974*5944Sha137994 		return (DDI_INTR_UNCLAIMED);
975*5944Sha137994 	}
976*5944Sha137994 
977*5944Sha137994 	ldcp = (ldc_chan_t *)arg1;
978*5944Sha137994 
979*5944Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
980*5944Sha137994 	    ldcp->id, ldcp);
981*5944Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (%llx) USR%lx/TS%lx/HS%lx, LSTATE=%lx\n",
982*5944Sha137994 	    ldcp->id, ldcp->status, ldcp->tstate, ldcp->hstate,
983*5944Sha137994 	    ldcp->link_state);
984*5944Sha137994 
985*5944Sha137994 	/* Lock channel */
986*5944Sha137994 	mutex_enter(&ldcp->lock);
987*5944Sha137994 
988*5944Sha137994 	/* Mark the interrupt as being actively handled */
989*5944Sha137994 	ldcp->rx_intr_state = LDC_INTR_ACTIVE;
990*5944Sha137994 
991*5944Sha137994 	(void) i_ldc_rx_process_hvq(ldcp, &notify, &event);
992*5944Sha137994 
993*5944Sha137994 	if (ldcp->mode != LDC_MODE_STREAM) {
994*5944Sha137994 		/*
995*5944Sha137994 		 * If there are no data packets on the queue, clear
996*5944Sha137994 		 * the interrupt. Otherwise, the ldc_read will clear
997*5944Sha137994 		 * interrupts after draining the queue. To indicate the
998*5944Sha137994 		 * interrupt has not yet been cleared, it is marked
999*5944Sha137994 		 * as pending.
1000*5944Sha137994 		 */
1001*5944Sha137994 		if ((event & LDC_EVT_READ) == 0) {
1002*5944Sha137994 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
1003*5944Sha137994 		} else {
1004*5944Sha137994 			ldcp->rx_intr_state = LDC_INTR_PEND;
1005*5944Sha137994 		}
1006*5944Sha137994 	}
1007*5944Sha137994 
1008*5944Sha137994 	/* if callbacks are disabled, do not notify */
1009*5944Sha137994 	if (notify && ldcp->cb_enabled) {
1010*5944Sha137994 		ldcp->cb_inprogress = B_TRUE;
1011*5944Sha137994 		mutex_exit(&ldcp->lock);
1012*5944Sha137994 		rv = ldcp->cb(event, ldcp->cb_arg);
1013*5944Sha137994 		if (rv) {
1014*5944Sha137994 			DWARN(ldcp->id,
1015*5944Sha137994 			    "i_ldc_rx_hdlr: (0x%llx) callback failure",
1016*5944Sha137994 			    ldcp->id);
1017*5944Sha137994 		}
1018*5944Sha137994 		mutex_enter(&ldcp->lock);
1019*5944Sha137994 		ldcp->cb_inprogress = B_FALSE;
1020*5944Sha137994 	}
1021*5944Sha137994 
1022*5944Sha137994 	if (ldcp->mode == LDC_MODE_STREAM) {
1023*5944Sha137994 		/*
1024*5944Sha137994 		 * If we are using a secondary data queue, clear the
1025*5944Sha137994 		 * interrupt. We should have processed all CTRL packets
1026*5944Sha137994 		 * and copied all DATA packets to the secondary queue.
1027*5944Sha137994 		 * Even if secondary queue filled up, clear the interrupts,
1028*5944Sha137994 		 * this will trigger another interrupt and force the
1029*5944Sha137994 		 * handler to copy more data.
1030*5944Sha137994 		 */
1031*5944Sha137994 		i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
1032*5944Sha137994 	}
1033*5944Sha137994 
1034*5944Sha137994 	mutex_exit(&ldcp->lock);
1035*5944Sha137994 
1036*5944Sha137994 	D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) exiting handler", ldcp->id);
1037*5944Sha137994 
1038*5944Sha137994 	return (DDI_INTR_CLAIMED);
1039*5944Sha137994 }
1040*5944Sha137994 
1041*5944Sha137994 /*
1042*5944Sha137994  * Wrapper for the Rx HV queue processing function to be used when
1043*5944Sha137994  * checking the Rx HV queue for data packets. Unlike the interrupt
1044*5944Sha137994  * handler code flow, the Rx interrupt is not cleared here and
1045*5944Sha137994  * callbacks are not made.
1046*5944Sha137994  */
1047*5944Sha137994 static uint_t
1048*5944Sha137994 i_ldc_chkq(ldc_chan_t *ldcp)
1049*5944Sha137994 {
1050*5944Sha137994 	boolean_t	notify;
1051*5944Sha137994 	uint64_t	event;
1052*5944Sha137994 
1053*5944Sha137994 	return (i_ldc_rx_process_hvq(ldcp, &notify, &event));
1054*5944Sha137994 }
1055*5944Sha137994 
1056*5944Sha137994 /*
10571991Sheppo  * Send a LDC message
10581991Sheppo  */
10591991Sheppo static int
10601991Sheppo i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
10611991Sheppo     uint8_t ctrlmsg)
10621991Sheppo {
10631991Sheppo 	int		rv;
10641991Sheppo 	ldc_msg_t 	*pkt;
10651991Sheppo 	uint64_t	tx_tail;
10664690Snarayan 	uint32_t	curr_seqid;
10671991Sheppo 
10682336Snarayan 	/* Obtain Tx lock */
10692336Snarayan 	mutex_enter(&ldcp->tx_lock);
10702336Snarayan 
10714690Snarayan 	curr_seqid = ldcp->last_msg_snt;
10724690Snarayan 
10731991Sheppo 	/* get the current tail for the message */
10741991Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
10751991Sheppo 	if (rv) {
10761991Sheppo 		DWARN(ldcp->id,
10771991Sheppo 		    "i_ldc_send_pkt: (0x%llx) error sending pkt, "
10781991Sheppo 		    "type=0x%x,subtype=0x%x,ctrl=0x%x\n",
10791991Sheppo 		    ldcp->id, pkttype, subtype, ctrlmsg);
10802336Snarayan 		mutex_exit(&ldcp->tx_lock);
10811991Sheppo 		return (rv);
10821991Sheppo 	}
10831991Sheppo 
10841991Sheppo 	pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
10851991Sheppo 	ZERO_PKT(pkt);
10861991Sheppo 
10871991Sheppo 	/* Initialize the packet */
10881991Sheppo 	pkt->type = pkttype;
10891991Sheppo 	pkt->stype = subtype;
10901991Sheppo 	pkt->ctrl = ctrlmsg;
10911991Sheppo 
10921991Sheppo 	/* Store ackid/seqid iff it is RELIABLE mode & not a RTS/RTR message */
10931991Sheppo 	if (((ctrlmsg & LDC_CTRL_MASK) != LDC_RTS) &&
10941991Sheppo 	    ((ctrlmsg & LDC_CTRL_MASK) != LDC_RTR)) {
10951991Sheppo 		curr_seqid++;
10961991Sheppo 		if (ldcp->mode != LDC_MODE_RAW) {
10971991Sheppo 			pkt->seqid = curr_seqid;
10981991Sheppo 			pkt->ackid = ldcp->last_msg_rcd;
10991991Sheppo 		}
11001991Sheppo 	}
11011991Sheppo 	DUMP_LDC_PKT(ldcp, "i_ldc_send_pkt", (uint64_t)pkt);
11021991Sheppo 
11031991Sheppo 	/* initiate the send by calling into HV and set the new tail */
11041991Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
11054690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
11061991Sheppo 
11071991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
11081991Sheppo 	if (rv) {
11091991Sheppo 		DWARN(ldcp->id,
11101991Sheppo 		    "i_ldc_send_pkt:(0x%llx) error sending pkt, "
11111991Sheppo 		    "type=0x%x,stype=0x%x,ctrl=0x%x\n",
11121991Sheppo 		    ldcp->id, pkttype, subtype, ctrlmsg);
11132336Snarayan 		mutex_exit(&ldcp->tx_lock);
11141991Sheppo 		return (EIO);
11151991Sheppo 	}
11161991Sheppo 
11171991Sheppo 	ldcp->last_msg_snt = curr_seqid;
11181991Sheppo 	ldcp->tx_tail = tx_tail;
11191991Sheppo 
11202336Snarayan 	mutex_exit(&ldcp->tx_lock);
11211991Sheppo 	return (0);
11221991Sheppo }
11231991Sheppo 
11241991Sheppo /*
11251991Sheppo  * Checks if packet was received in right order
11262410Slm66018  * in the case of a reliable link.
11271991Sheppo  * Returns 0 if in order, else EIO
11281991Sheppo  */
11291991Sheppo static int
11301991Sheppo i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *msg)
11311991Sheppo {
11321991Sheppo 	/* No seqid checking for RAW mode */
11331991Sheppo 	if (ldcp->mode == LDC_MODE_RAW)
11341991Sheppo 		return (0);
11351991Sheppo 
11361991Sheppo 	/* No seqid checking for version, RTS, RTR message */
11371991Sheppo 	if (msg->ctrl == LDC_VER ||
11381991Sheppo 	    msg->ctrl == LDC_RTS ||
11391991Sheppo 	    msg->ctrl == LDC_RTR)
11401991Sheppo 		return (0);
11411991Sheppo 
11421991Sheppo 	/* Initial seqid to use is sent in RTS/RTR and saved in last_msg_rcd */
11431991Sheppo 	if (msg->seqid != (ldcp->last_msg_rcd + 1)) {
11441991Sheppo 		DWARN(ldcp->id,
11451991Sheppo 		    "i_ldc_check_seqid: (0x%llx) out-of-order pkt, got 0x%x, "
11461991Sheppo 		    "expecting 0x%x\n", ldcp->id, msg->seqid,
11471991Sheppo 		    (ldcp->last_msg_rcd + 1));
11481991Sheppo 		return (EIO);
11491991Sheppo 	}
11501991Sheppo 
11513560Snarayan #ifdef DEBUG
11523560Snarayan 	if (LDC_INJECT_PKTLOSS(ldcp)) {
11533560Snarayan 		DWARN(ldcp->id,
11543560Snarayan 		    "i_ldc_check_seqid: (0x%llx) inject pkt loss\n", ldcp->id);
11553560Snarayan 		return (EIO);
11563560Snarayan 	}
11573560Snarayan #endif
11583560Snarayan 
11591991Sheppo 	return (0);
11601991Sheppo }
11611991Sheppo 
11621991Sheppo 
11631991Sheppo /*
11641991Sheppo  * Process an incoming version ctrl message
11651991Sheppo  */
11661991Sheppo static int
11671991Sheppo i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg)
11681991Sheppo {
11691991Sheppo 	int 		rv = 0, idx = ldcp->next_vidx;
11701991Sheppo 	ldc_msg_t 	*pkt;
11711991Sheppo 	uint64_t	tx_tail;
11721991Sheppo 	ldc_ver_t	*rcvd_ver;
11731991Sheppo 
11741991Sheppo 	/* get the received version */
11751991Sheppo 	rcvd_ver = (ldc_ver_t *)((uint64_t)msg + LDC_PAYLOAD_VER_OFF);
11761991Sheppo 
11771991Sheppo 	D2(ldcp->id, "i_ldc_process_VER: (0x%llx) received VER v%u.%u\n",
11781991Sheppo 	    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
11791991Sheppo 
11802336Snarayan 	/* Obtain Tx lock */
11812336Snarayan 	mutex_enter(&ldcp->tx_lock);
11822336Snarayan 
11831991Sheppo 	switch (msg->stype) {
11841991Sheppo 	case LDC_INFO:
11851991Sheppo 
11862793Slm66018 		if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) {
11872793Slm66018 			(void) i_ldc_txq_reconf(ldcp);
11882793Slm66018 			i_ldc_reset_state(ldcp);
11892793Slm66018 			mutex_exit(&ldcp->tx_lock);
11902793Slm66018 			return (EAGAIN);
11912793Slm66018 		}
11922793Slm66018 
11931991Sheppo 		/* get the current tail and pkt for the response */
11941991Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
11951991Sheppo 		if (rv != 0) {
11961991Sheppo 			DWARN(ldcp->id,
11971991Sheppo 			    "i_ldc_process_VER: (0x%llx) err sending "
11981991Sheppo 			    "version ACK/NACK\n", ldcp->id);
11992793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
12002336Snarayan 			mutex_exit(&ldcp->tx_lock);
12011991Sheppo 			return (ECONNRESET);
12021991Sheppo 		}
12031991Sheppo 
12041991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
12051991Sheppo 		ZERO_PKT(pkt);
12061991Sheppo 
12071991Sheppo 		/* initialize the packet */
12081991Sheppo 		pkt->type = LDC_CTRL;
12091991Sheppo 		pkt->ctrl = LDC_VER;
12101991Sheppo 
12111991Sheppo 		for (;;) {
12121991Sheppo 
12131991Sheppo 			D1(ldcp->id, "i_ldc_process_VER: got %u.%u chk %u.%u\n",
12141991Sheppo 			    rcvd_ver->major, rcvd_ver->minor,
12151991Sheppo 			    ldc_versions[idx].major, ldc_versions[idx].minor);
12161991Sheppo 
12171991Sheppo 			if (rcvd_ver->major == ldc_versions[idx].major) {
12181991Sheppo 				/* major version match - ACK version */
12191991Sheppo 				pkt->stype = LDC_ACK;
12201991Sheppo 
12211991Sheppo 				/*
12221991Sheppo 				 * lower minor version to the one this endpt
12231991Sheppo 				 * supports, if necessary
12241991Sheppo 				 */
12251991Sheppo 				if (rcvd_ver->minor > ldc_versions[idx].minor)
12261991Sheppo 					rcvd_ver->minor =
12274690Snarayan 					    ldc_versions[idx].minor;
12281991Sheppo 				bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver));
12291991Sheppo 
12301991Sheppo 				break;
12311991Sheppo 			}
12321991Sheppo 
12331991Sheppo 			if (rcvd_ver->major > ldc_versions[idx].major) {
12341991Sheppo 
12351991Sheppo 				D1(ldcp->id, "i_ldc_process_VER: using next"
12361991Sheppo 				    " lower idx=%d, v%u.%u\n", idx,
12371991Sheppo 				    ldc_versions[idx].major,
12381991Sheppo 				    ldc_versions[idx].minor);
12391991Sheppo 
12401991Sheppo 				/* nack with next lower version */
12411991Sheppo 				pkt->stype = LDC_NACK;
12421991Sheppo 				bcopy(&ldc_versions[idx], pkt->udata,
12431991Sheppo 				    sizeof (ldc_versions[idx]));
12441991Sheppo 				ldcp->next_vidx = idx;
12451991Sheppo 				break;
12461991Sheppo 			}
12471991Sheppo 
12481991Sheppo 			/* next major version */
12491991Sheppo 			idx++;
12501991Sheppo 
12511991Sheppo 			D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx);
12521991Sheppo 
12531991Sheppo 			if (idx == LDC_NUM_VERS) {
12541991Sheppo 				/* no version match - send NACK */
12551991Sheppo 				pkt->stype = LDC_NACK;
12561991Sheppo 				bzero(pkt->udata, sizeof (ldc_ver_t));
12571991Sheppo 				ldcp->next_vidx = 0;
12581991Sheppo 				break;
12591991Sheppo 			}
12601991Sheppo 		}
12611991Sheppo 
12621991Sheppo 		/* initiate the send by calling into HV and set the new tail */
12631991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
12644690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
12651991Sheppo 
12661991Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
12671991Sheppo 		if (rv == 0) {
12681991Sheppo 			ldcp->tx_tail = tx_tail;
12691991Sheppo 			if (pkt->stype == LDC_ACK) {
12701991Sheppo 				D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent"
12711991Sheppo 				    " version ACK\n", ldcp->id);
12721991Sheppo 				/* Save the ACK'd version */
12731991Sheppo 				ldcp->version.major = rcvd_ver->major;
12741991Sheppo 				ldcp->version.minor = rcvd_ver->minor;
12752032Slm66018 				ldcp->hstate |= TS_RCVD_VER;
12761991Sheppo 				ldcp->tstate |= TS_VER_DONE;
12773560Snarayan 				D1(DBG_ALL_LDCS,
12782793Slm66018 				    "(0x%llx) Sent ACK, "
12792793Slm66018 				    "Agreed on version v%u.%u\n",
12801991Sheppo 				    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
12811991Sheppo 			}
12821991Sheppo 		} else {
12831991Sheppo 			DWARN(ldcp->id,
12841991Sheppo 			    "i_ldc_process_VER: (0x%llx) error sending "
12851991Sheppo 			    "ACK/NACK\n", ldcp->id);
12862793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
12872336Snarayan 			mutex_exit(&ldcp->tx_lock);
12881991Sheppo 			return (ECONNRESET);
12891991Sheppo 		}
12901991Sheppo 
12911991Sheppo 		break;
12921991Sheppo 
12931991Sheppo 	case LDC_ACK:
12942793Slm66018 		if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) {
12952793Slm66018 			if (ldcp->version.major != rcvd_ver->major ||
12964690Snarayan 			    ldcp->version.minor != rcvd_ver->minor) {
12972793Slm66018 
12982793Slm66018 				/* mismatched version - reset connection */
12992793Slm66018 				DWARN(ldcp->id,
13004690Snarayan 				    "i_ldc_process_VER: (0x%llx) recvd"
13014690Snarayan 				    " ACK ver != sent ACK ver\n", ldcp->id);
13022793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
13032793Slm66018 				mutex_exit(&ldcp->tx_lock);
13042793Slm66018 				return (ECONNRESET);
13052793Slm66018 			}
13062793Slm66018 		} else {
13072793Slm66018 			/* SUCCESS - we have agreed on a version */
13082793Slm66018 			ldcp->version.major = rcvd_ver->major;
13092793Slm66018 			ldcp->version.minor = rcvd_ver->minor;
13102793Slm66018 			ldcp->tstate |= TS_VER_DONE;
13112793Slm66018 		}
13122793Slm66018 
13133010Slm66018 		D1(ldcp->id, "(0x%llx) Got ACK, Agreed on version v%u.%u\n",
13141991Sheppo 		    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
13151991Sheppo 
13161991Sheppo 		/* initiate RTS-RTR-RDX handshake */
13171991Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
13181991Sheppo 		if (rv) {
13191991Sheppo 			DWARN(ldcp->id,
13202793Slm66018 		    "i_ldc_process_VER: (0x%llx) cannot send RTS\n",
13211991Sheppo 			    ldcp->id);
13222793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
13232336Snarayan 			mutex_exit(&ldcp->tx_lock);
13241991Sheppo 			return (ECONNRESET);
13251991Sheppo 		}
13261991Sheppo 
13271991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
13281991Sheppo 		ZERO_PKT(pkt);
13291991Sheppo 
13301991Sheppo 		pkt->type = LDC_CTRL;
13311991Sheppo 		pkt->stype = LDC_INFO;
13321991Sheppo 		pkt->ctrl = LDC_RTS;
13331991Sheppo 		pkt->env = ldcp->mode;
13341991Sheppo 		if (ldcp->mode != LDC_MODE_RAW)
13351991Sheppo 			pkt->seqid = LDC_INIT_SEQID;
13361991Sheppo 
13371991Sheppo 		ldcp->last_msg_rcd = LDC_INIT_SEQID;
13381991Sheppo 
13391991Sheppo 		DUMP_LDC_PKT(ldcp, "i_ldc_process_VER snd rts", (uint64_t)pkt);
13401991Sheppo 
13411991Sheppo 		/* initiate the send by calling into HV and set the new tail */
13421991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
13434690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
13441991Sheppo 
13451991Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
13461991Sheppo 		if (rv) {
13471991Sheppo 			D2(ldcp->id,
13481991Sheppo 			    "i_ldc_process_VER: (0x%llx) no listener\n",
13491991Sheppo 			    ldcp->id);
13502793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
13512336Snarayan 			mutex_exit(&ldcp->tx_lock);
13521991Sheppo 			return (ECONNRESET);
13531991Sheppo 		}
13541991Sheppo 
13551991Sheppo 		ldcp->tx_tail = tx_tail;
13561991Sheppo 		ldcp->hstate |= TS_SENT_RTS;
13571991Sheppo 
13581991Sheppo 		break;
13591991Sheppo 
13601991Sheppo 	case LDC_NACK:
13611991Sheppo 		/* check if version in NACK is zero */
13621991Sheppo 		if (rcvd_ver->major == 0 && rcvd_ver->minor == 0) {
13631991Sheppo 			/* version handshake failure */
13641991Sheppo 			DWARN(DBG_ALL_LDCS,
13651991Sheppo 			    "i_ldc_process_VER: (0x%llx) no version match\n",
13661991Sheppo 			    ldcp->id);
13672793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
13682336Snarayan 			mutex_exit(&ldcp->tx_lock);
13691991Sheppo 			return (ECONNRESET);
13701991Sheppo 		}
13711991Sheppo 
13721991Sheppo 		/* get the current tail and pkt for the response */
13731991Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
13741991Sheppo 		if (rv != 0) {
13751991Sheppo 			cmn_err(CE_NOTE,
13761991Sheppo 			    "i_ldc_process_VER: (0x%lx) err sending "
13771991Sheppo 			    "version ACK/NACK\n", ldcp->id);
13782793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
13792336Snarayan 			mutex_exit(&ldcp->tx_lock);
13801991Sheppo 			return (ECONNRESET);
13811991Sheppo 		}
13821991Sheppo 
13831991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
13841991Sheppo 		ZERO_PKT(pkt);
13851991Sheppo 
13861991Sheppo 		/* initialize the packet */
13871991Sheppo 		pkt->type = LDC_CTRL;
13881991Sheppo 		pkt->ctrl = LDC_VER;
13891991Sheppo 		pkt->stype = LDC_INFO;
13901991Sheppo 
13911991Sheppo 		/* check ver in NACK msg has a match */
13921991Sheppo 		for (;;) {
13931991Sheppo 			if (rcvd_ver->major == ldc_versions[idx].major) {
13941991Sheppo 				/*
13951991Sheppo 				 * major version match - resubmit request
13961991Sheppo 				 * if lower minor version to the one this endpt
13971991Sheppo 				 * supports, if necessary
13981991Sheppo 				 */
13991991Sheppo 				if (rcvd_ver->minor > ldc_versions[idx].minor)
14001991Sheppo 					rcvd_ver->minor =
14014690Snarayan 					    ldc_versions[idx].minor;
14021991Sheppo 				bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver));
14031991Sheppo 				break;
14041991Sheppo 			}
14051991Sheppo 
14061991Sheppo 			if (rcvd_ver->major > ldc_versions[idx].major) {
14071991Sheppo 
14081991Sheppo 				D1(ldcp->id, "i_ldc_process_VER: using next"
14091991Sheppo 				    " lower idx=%d, v%u.%u\n", idx,
14101991Sheppo 				    ldc_versions[idx].major,
14111991Sheppo 				    ldc_versions[idx].minor);
14121991Sheppo 
14131991Sheppo 				/* send next lower version */
14141991Sheppo 				bcopy(&ldc_versions[idx], pkt->udata,
14151991Sheppo 				    sizeof (ldc_versions[idx]));
14161991Sheppo 				ldcp->next_vidx = idx;
14171991Sheppo 				break;
14181991Sheppo 			}
14191991Sheppo 
14201991Sheppo 			/* next version */
14211991Sheppo 			idx++;
14221991Sheppo 
14231991Sheppo 			D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx);
14241991Sheppo 
14251991Sheppo 			if (idx == LDC_NUM_VERS) {
14261991Sheppo 				/* no version match - terminate */
14271991Sheppo 				ldcp->next_vidx = 0;
14282336Snarayan 				mutex_exit(&ldcp->tx_lock);
14291991Sheppo 				return (ECONNRESET);
14301991Sheppo 			}
14311991Sheppo 		}
14321991Sheppo 
14331991Sheppo 		/* initiate the send by calling into HV and set the new tail */
14341991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
14354690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
14361991Sheppo 
14371991Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
14381991Sheppo 		if (rv == 0) {
14391991Sheppo 			D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent version"
14401991Sheppo 			    "INFO v%u.%u\n", ldcp->id, ldc_versions[idx].major,
14411991Sheppo 			    ldc_versions[idx].minor);
14421991Sheppo 			ldcp->tx_tail = tx_tail;
14431991Sheppo 		} else {
14441991Sheppo 			cmn_err(CE_NOTE,
14451991Sheppo 			    "i_ldc_process_VER: (0x%lx) error sending version"
14461991Sheppo 			    "INFO\n", ldcp->id);
14472793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
14482336Snarayan 			mutex_exit(&ldcp->tx_lock);
14491991Sheppo 			return (ECONNRESET);
14501991Sheppo 		}
14511991Sheppo 
14521991Sheppo 		break;
14531991Sheppo 	}
14541991Sheppo 
14552336Snarayan 	mutex_exit(&ldcp->tx_lock);
14561991Sheppo 	return (rv);
14571991Sheppo }
14581991Sheppo 
14591991Sheppo 
14601991Sheppo /*
14611991Sheppo  * Process an incoming RTS ctrl message
14621991Sheppo  */
14631991Sheppo static int
14641991Sheppo i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg)
14651991Sheppo {
14661991Sheppo 	int 		rv = 0;
14671991Sheppo 	ldc_msg_t 	*pkt;
14681991Sheppo 	uint64_t	tx_tail;
14691991Sheppo 	boolean_t	sent_NACK = B_FALSE;
14701991Sheppo 
14711991Sheppo 	D2(ldcp->id, "i_ldc_process_RTS: (0x%llx) received RTS\n", ldcp->id);
14721991Sheppo 
14731991Sheppo 	switch (msg->stype) {
14741991Sheppo 	case LDC_NACK:
14751991Sheppo 		DWARN(ldcp->id,
14761991Sheppo 		    "i_ldc_process_RTS: (0x%llx) RTS NACK received\n",
14771991Sheppo 		    ldcp->id);
14781991Sheppo 
14791991Sheppo 		/* Reset the channel -- as we cannot continue */
14802336Snarayan 		mutex_enter(&ldcp->tx_lock);
14812793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
14822336Snarayan 		mutex_exit(&ldcp->tx_lock);
14831991Sheppo 		rv = ECONNRESET;
14841991Sheppo 		break;
14851991Sheppo 
14861991Sheppo 	case LDC_INFO:
14871991Sheppo 
14881991Sheppo 		/* check mode */
14891991Sheppo 		if (ldcp->mode != (ldc_mode_t)msg->env) {
14901991Sheppo 			cmn_err(CE_NOTE,
14911991Sheppo 			    "i_ldc_process_RTS: (0x%lx) mode mismatch\n",
14921991Sheppo 			    ldcp->id);
14931991Sheppo 			/*
14941991Sheppo 			 * send NACK in response to MODE message
14951991Sheppo 			 * get the current tail for the response
14961991Sheppo 			 */
14971991Sheppo 			rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTS);
14981991Sheppo 			if (rv) {
14991991Sheppo 				/* if cannot send NACK - reset channel */
15002336Snarayan 				mutex_enter(&ldcp->tx_lock);
15012793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
15022336Snarayan 				mutex_exit(&ldcp->tx_lock);
15031991Sheppo 				rv = ECONNRESET;
15041991Sheppo 				break;
15051991Sheppo 			}
15061991Sheppo 			sent_NACK = B_TRUE;
15071991Sheppo 		}
15081991Sheppo 		break;
15091991Sheppo 	default:
15101991Sheppo 		DWARN(ldcp->id, "i_ldc_process_RTS: (0x%llx) unexp ACK\n",
15111991Sheppo 		    ldcp->id);
15122336Snarayan 		mutex_enter(&ldcp->tx_lock);
15132793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
15142336Snarayan 		mutex_exit(&ldcp->tx_lock);
15151991Sheppo 		rv = ECONNRESET;
15161991Sheppo 		break;
15171991Sheppo 	}
15181991Sheppo 
15191991Sheppo 	/*
15201991Sheppo 	 * If either the connection was reset (when rv != 0) or
15211991Sheppo 	 * a NACK was sent, we return. In the case of a NACK
15221991Sheppo 	 * we dont want to consume the packet that came in but
15231991Sheppo 	 * not record that we received the RTS
15241991Sheppo 	 */
15251991Sheppo 	if (rv || sent_NACK)
15261991Sheppo 		return (rv);
15271991Sheppo 
15281991Sheppo 	/* record RTS received */
15291991Sheppo 	ldcp->hstate |= TS_RCVD_RTS;
15301991Sheppo 
15311991Sheppo 	/* store initial SEQID info */
15321991Sheppo 	ldcp->last_msg_snt = msg->seqid;
15331991Sheppo 
15342336Snarayan 	/* Obtain Tx lock */
15352336Snarayan 	mutex_enter(&ldcp->tx_lock);
15362336Snarayan 
15371991Sheppo 	/* get the current tail for the response */
15381991Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
15391991Sheppo 	if (rv != 0) {
15401991Sheppo 		cmn_err(CE_NOTE,
15411991Sheppo 		    "i_ldc_process_RTS: (0x%lx) err sending RTR\n",
15421991Sheppo 		    ldcp->id);
15432793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
15442336Snarayan 		mutex_exit(&ldcp->tx_lock);
15451991Sheppo 		return (ECONNRESET);
15461991Sheppo 	}
15471991Sheppo 
15481991Sheppo 	pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
15491991Sheppo 	ZERO_PKT(pkt);
15501991Sheppo 
15511991Sheppo 	/* initialize the packet */
15521991Sheppo 	pkt->type = LDC_CTRL;
15531991Sheppo 	pkt->stype = LDC_INFO;
15541991Sheppo 	pkt->ctrl = LDC_RTR;
15551991Sheppo 	pkt->env = ldcp->mode;
15561991Sheppo 	if (ldcp->mode != LDC_MODE_RAW)
15571991Sheppo 		pkt->seqid = LDC_INIT_SEQID;
15581991Sheppo 
15591991Sheppo 	ldcp->last_msg_rcd = msg->seqid;
15601991Sheppo 
15611991Sheppo 	/* initiate the send by calling into HV and set the new tail */
15621991Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
15634690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
15641991Sheppo 
15651991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
15661991Sheppo 	if (rv == 0) {
15671991Sheppo 		D2(ldcp->id,
15681991Sheppo 		    "i_ldc_process_RTS: (0x%llx) sent RTR\n", ldcp->id);
15691991Sheppo 		DUMP_LDC_PKT(ldcp, "i_ldc_process_RTS sent rtr", (uint64_t)pkt);
15701991Sheppo 
15711991Sheppo 		ldcp->tx_tail = tx_tail;
15721991Sheppo 		ldcp->hstate |= TS_SENT_RTR;
15731991Sheppo 
15741991Sheppo 	} else {
15751991Sheppo 		cmn_err(CE_NOTE,
15761991Sheppo 		    "i_ldc_process_RTS: (0x%lx) error sending RTR\n",
15771991Sheppo 		    ldcp->id);
15782793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
15792336Snarayan 		mutex_exit(&ldcp->tx_lock);
15801991Sheppo 		return (ECONNRESET);
15811991Sheppo 	}
15821991Sheppo 
15832336Snarayan 	mutex_exit(&ldcp->tx_lock);
15841991Sheppo 	return (0);
15851991Sheppo }
15861991Sheppo 
15871991Sheppo /*
15881991Sheppo  * Process an incoming RTR ctrl message
15891991Sheppo  */
15901991Sheppo static int
15911991Sheppo i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg)
15921991Sheppo {
15931991Sheppo 	int 		rv = 0;
15941991Sheppo 	boolean_t	sent_NACK = B_FALSE;
15951991Sheppo 
15961991Sheppo 	D2(ldcp->id, "i_ldc_process_RTR: (0x%llx) received RTR\n", ldcp->id);
15971991Sheppo 
15981991Sheppo 	switch (msg->stype) {
15991991Sheppo 	case LDC_NACK:
16001991Sheppo 		/* RTR NACK received */
16011991Sheppo 		DWARN(ldcp->id,
16021991Sheppo 		    "i_ldc_process_RTR: (0x%llx) RTR NACK received\n",
16031991Sheppo 		    ldcp->id);
16041991Sheppo 
16051991Sheppo 		/* Reset the channel -- as we cannot continue */
16062336Snarayan 		mutex_enter(&ldcp->tx_lock);
16072793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
16082336Snarayan 		mutex_exit(&ldcp->tx_lock);
16091991Sheppo 		rv = ECONNRESET;
16101991Sheppo 
16111991Sheppo 		break;
16121991Sheppo 
16131991Sheppo 	case LDC_INFO:
16141991Sheppo 
16151991Sheppo 		/* check mode */
16161991Sheppo 		if (ldcp->mode != (ldc_mode_t)msg->env) {
16171991Sheppo 			DWARN(ldcp->id,
16183010Slm66018 			    "i_ldc_process_RTR: (0x%llx) mode mismatch, "
16193010Slm66018 			    "expecting 0x%x, got 0x%x\n",
16203010Slm66018 			    ldcp->id, ldcp->mode, (ldc_mode_t)msg->env);
16211991Sheppo 			/*
16221991Sheppo 			 * send NACK in response to MODE message
16231991Sheppo 			 * get the current tail for the response
16241991Sheppo 			 */
16251991Sheppo 			rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTR);
16261991Sheppo 			if (rv) {
16271991Sheppo 				/* if cannot send NACK - reset channel */
16282336Snarayan 				mutex_enter(&ldcp->tx_lock);
16292793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
16302336Snarayan 				mutex_exit(&ldcp->tx_lock);
16311991Sheppo 				rv = ECONNRESET;
16321991Sheppo 				break;
16331991Sheppo 			}
16341991Sheppo 			sent_NACK = B_TRUE;
16351991Sheppo 		}
16361991Sheppo 		break;
16371991Sheppo 
16381991Sheppo 	default:
16391991Sheppo 		DWARN(ldcp->id, "i_ldc_process_RTR: (0x%llx) unexp ACK\n",
16401991Sheppo 		    ldcp->id);
16411991Sheppo 
16421991Sheppo 		/* Reset the channel -- as we cannot continue */
16432336Snarayan 		mutex_enter(&ldcp->tx_lock);
16442793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
16452336Snarayan 		mutex_exit(&ldcp->tx_lock);
16461991Sheppo 		rv = ECONNRESET;
16471991Sheppo 		break;
16481991Sheppo 	}
16491991Sheppo 
16501991Sheppo 	/*
16511991Sheppo 	 * If either the connection was reset (when rv != 0) or
16521991Sheppo 	 * a NACK was sent, we return. In the case of a NACK
16531991Sheppo 	 * we dont want to consume the packet that came in but
16541991Sheppo 	 * not record that we received the RTR
16551991Sheppo 	 */
16561991Sheppo 	if (rv || sent_NACK)
16571991Sheppo 		return (rv);
16581991Sheppo 
16591991Sheppo 	ldcp->last_msg_snt = msg->seqid;
16601991Sheppo 	ldcp->hstate |= TS_RCVD_RTR;
16611991Sheppo 
16621991Sheppo 	rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_INFO, LDC_RDX);
16631991Sheppo 	if (rv) {
16641991Sheppo 		cmn_err(CE_NOTE,
16651991Sheppo 		    "i_ldc_process_RTR: (0x%lx) cannot send RDX\n",
16661991Sheppo 		    ldcp->id);
16672336Snarayan 		mutex_enter(&ldcp->tx_lock);
16682793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
16692336Snarayan 		mutex_exit(&ldcp->tx_lock);
16701991Sheppo 		return (ECONNRESET);
16711991Sheppo 	}
16721991Sheppo 	D2(ldcp->id,
16731991Sheppo 	    "i_ldc_process_RTR: (0x%llx) sent RDX\n", ldcp->id);
16741991Sheppo 
16751991Sheppo 	ldcp->hstate |= TS_SENT_RDX;
16761991Sheppo 	ldcp->tstate |= TS_HSHAKE_DONE;
16772793Slm66018 	if ((ldcp->tstate & TS_IN_RESET) == 0)
16782793Slm66018 		ldcp->status = LDC_UP;
16791991Sheppo 
16803010Slm66018 	D1(ldcp->id, "(0x%llx) Handshake Complete\n", ldcp->id);
16811991Sheppo 
16821991Sheppo 	return (0);
16831991Sheppo }
16841991Sheppo 
16851991Sheppo 
16861991Sheppo /*
16871991Sheppo  * Process an incoming RDX ctrl message
16881991Sheppo  */
16891991Sheppo static int
16901991Sheppo i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg)
16911991Sheppo {
16921991Sheppo 	int	rv = 0;
16931991Sheppo 
16941991Sheppo 	D2(ldcp->id, "i_ldc_process_RDX: (0x%llx) received RDX\n", ldcp->id);
16951991Sheppo 
16961991Sheppo 	switch (msg->stype) {
16971991Sheppo 	case LDC_NACK:
16981991Sheppo 		/* RDX NACK received */
16991991Sheppo 		DWARN(ldcp->id,
17001991Sheppo 		    "i_ldc_process_RDX: (0x%llx) RDX NACK received\n",
17011991Sheppo 		    ldcp->id);
17021991Sheppo 
17031991Sheppo 		/* Reset the channel -- as we cannot continue */
17042336Snarayan 		mutex_enter(&ldcp->tx_lock);
17052793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
17062336Snarayan 		mutex_exit(&ldcp->tx_lock);
17071991Sheppo 		rv = ECONNRESET;
17081991Sheppo 
17091991Sheppo 		break;
17101991Sheppo 
17111991Sheppo 	case LDC_INFO:
17121991Sheppo 
17131991Sheppo 		/*
17141991Sheppo 		 * if channel is UP and a RDX received after data transmission
17151991Sheppo 		 * has commenced it is an error
17161991Sheppo 		 */
17171991Sheppo 		if ((ldcp->tstate == TS_UP) && (ldcp->hstate & TS_RCVD_RDX)) {
17181991Sheppo 			DWARN(DBG_ALL_LDCS,
17191991Sheppo 			    "i_ldc_process_RDX: (0x%llx) unexpected RDX"
17201991Sheppo 			    " - LDC reset\n", ldcp->id);
17212336Snarayan 			mutex_enter(&ldcp->tx_lock);
17222793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
17232336Snarayan 			mutex_exit(&ldcp->tx_lock);
17241991Sheppo 			return (ECONNRESET);
17251991Sheppo 		}
17261991Sheppo 
17271991Sheppo 		ldcp->hstate |= TS_RCVD_RDX;
17281991Sheppo 		ldcp->tstate |= TS_HSHAKE_DONE;
17292793Slm66018 		if ((ldcp->tstate & TS_IN_RESET) == 0)
17302793Slm66018 			ldcp->status = LDC_UP;
17311991Sheppo 
17321991Sheppo 		D1(DBG_ALL_LDCS, "(0x%llx) Handshake Complete\n", ldcp->id);
17331991Sheppo 		break;
17341991Sheppo 
17351991Sheppo 	default:
17361991Sheppo 		DWARN(ldcp->id, "i_ldc_process_RDX: (0x%llx) unexp ACK\n",
17371991Sheppo 		    ldcp->id);
17381991Sheppo 
17391991Sheppo 		/* Reset the channel -- as we cannot continue */
17402336Snarayan 		mutex_enter(&ldcp->tx_lock);
17412793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
17422336Snarayan 		mutex_exit(&ldcp->tx_lock);
17431991Sheppo 		rv = ECONNRESET;
17441991Sheppo 		break;
17451991Sheppo 	}
17461991Sheppo 
17471991Sheppo 	return (rv);
17481991Sheppo }
17491991Sheppo 
17501991Sheppo /*
17511991Sheppo  * Process an incoming ACK for a data packet
17521991Sheppo  */
17531991Sheppo static int
17541991Sheppo i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg)
17551991Sheppo {
17561991Sheppo 	int		rv;
17571991Sheppo 	uint64_t 	tx_head;
17581991Sheppo 	ldc_msg_t	*pkt;
17591991Sheppo 
17602336Snarayan 	/* Obtain Tx lock */
17612336Snarayan 	mutex_enter(&ldcp->tx_lock);
17622336Snarayan 
17631991Sheppo 	/*
17642336Snarayan 	 * Read the current Tx head and tail
17651991Sheppo 	 */
17661991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
17671991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
17681991Sheppo 	if (rv != 0) {
17691991Sheppo 		cmn_err(CE_WARN,
17701991Sheppo 		    "i_ldc_process_data_ACK: (0x%lx) cannot read qptrs\n",
17711991Sheppo 		    ldcp->id);
17722336Snarayan 
17732336Snarayan 		/* Reset the channel -- as we cannot continue */
17742793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
17752336Snarayan 		mutex_exit(&ldcp->tx_lock);
17762336Snarayan 		return (ECONNRESET);
17771991Sheppo 	}
17781991Sheppo 
17791991Sheppo 	/*
17801991Sheppo 	 * loop from where the previous ACK location was to the
17811991Sheppo 	 * current head location. This is how far the HV has
17821991Sheppo 	 * actually send pkts. Pkts between head and tail are
17831991Sheppo 	 * yet to be sent by HV.
17841991Sheppo 	 */
17851991Sheppo 	tx_head = ldcp->tx_ackd_head;
17861991Sheppo 	for (;;) {
17871991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_head);
17881991Sheppo 		tx_head = (tx_head + LDC_PACKET_SIZE) %
17894690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
17901991Sheppo 
17911991Sheppo 		if (pkt->seqid == msg->ackid) {
17921991Sheppo 			D2(ldcp->id,
17931991Sheppo 			    "i_ldc_process_data_ACK: (0x%llx) found packet\n",
17941991Sheppo 			    ldcp->id);
17951991Sheppo 			ldcp->last_ack_rcd = msg->ackid;
17961991Sheppo 			ldcp->tx_ackd_head = tx_head;
17971991Sheppo 			break;
17981991Sheppo 		}
17991991Sheppo 		if (tx_head == ldcp->tx_head) {
18001991Sheppo 			/* could not find packet */
18011991Sheppo 			DWARN(ldcp->id,
18021991Sheppo 			    "i_ldc_process_data_ACK: (0x%llx) invalid ACKid\n",
18031991Sheppo 			    ldcp->id);
18042336Snarayan 
18052336Snarayan 			/* Reset the channel -- as we cannot continue */
18062793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
18072336Snarayan 			mutex_exit(&ldcp->tx_lock);
18082336Snarayan 			return (ECONNRESET);
18091991Sheppo 		}
18101991Sheppo 	}
18111991Sheppo 
18122336Snarayan 	mutex_exit(&ldcp->tx_lock);
18131991Sheppo 	return (0);
18141991Sheppo }
18151991Sheppo 
18161991Sheppo /*
18171991Sheppo  * Process incoming control message
18181991Sheppo  * Return 0 - session can continue
18191991Sheppo  *        EAGAIN - reprocess packet - state was changed
18201991Sheppo  *	  ECONNRESET - channel was reset
18211991Sheppo  */
18221991Sheppo static int
18231991Sheppo i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *msg)
18241991Sheppo {
18251991Sheppo 	int 		rv = 0;
18261991Sheppo 
18272793Slm66018 	D1(ldcp->id, "i_ldc_ctrlmsg: (%llx) tstate = %lx, hstate = %lx\n",
18282793Slm66018 	    ldcp->id, ldcp->tstate, ldcp->hstate);
18292793Slm66018 
18302793Slm66018 	switch (ldcp->tstate & ~TS_IN_RESET) {
18311991Sheppo 
18321991Sheppo 	case TS_OPEN:
18331991Sheppo 	case TS_READY:
18341991Sheppo 
18351991Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
18361991Sheppo 		case LDC_VER:
18371991Sheppo 			/* process version message */
18381991Sheppo 			rv = i_ldc_process_VER(ldcp, msg);
18391991Sheppo 			break;
18401991Sheppo 		default:
18411991Sheppo 			DWARN(ldcp->id,
18421991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
18431991Sheppo 			    "tstate=0x%x\n", ldcp->id,
18441991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
18451991Sheppo 			break;
18461991Sheppo 		}
18471991Sheppo 
18481991Sheppo 		break;
18491991Sheppo 
18501991Sheppo 	case TS_VREADY:
18511991Sheppo 
18521991Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
18531991Sheppo 		case LDC_VER:
18542793Slm66018 			/* process version message */
18552793Slm66018 			rv = i_ldc_process_VER(ldcp, msg);
18561991Sheppo 			break;
18571991Sheppo 		case LDC_RTS:
18581991Sheppo 			/* process RTS message */
18591991Sheppo 			rv = i_ldc_process_RTS(ldcp, msg);
18601991Sheppo 			break;
18611991Sheppo 		case LDC_RTR:
18621991Sheppo 			/* process RTR message */
18631991Sheppo 			rv = i_ldc_process_RTR(ldcp, msg);
18641991Sheppo 			break;
18651991Sheppo 		case LDC_RDX:
18661991Sheppo 			/* process RDX message */
18671991Sheppo 			rv = i_ldc_process_RDX(ldcp, msg);
18681991Sheppo 			break;
18691991Sheppo 		default:
18701991Sheppo 			DWARN(ldcp->id,
18711991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
18721991Sheppo 			    "tstate=0x%x\n", ldcp->id,
18731991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
18741991Sheppo 			break;
18751991Sheppo 		}
18761991Sheppo 
18771991Sheppo 		break;
18781991Sheppo 
18791991Sheppo 	case TS_UP:
18801991Sheppo 
18811991Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
18821991Sheppo 		case LDC_VER:
18831991Sheppo 			DWARN(ldcp->id,
18841991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexpected VER "
18851991Sheppo 			    "- LDC reset\n", ldcp->id);
18861991Sheppo 			/* peer is redoing version negotiation */
18872336Snarayan 			mutex_enter(&ldcp->tx_lock);
18881991Sheppo 			(void) i_ldc_txq_reconf(ldcp);
18891991Sheppo 			i_ldc_reset_state(ldcp);
18902336Snarayan 			mutex_exit(&ldcp->tx_lock);
18911991Sheppo 			rv = EAGAIN;
18921991Sheppo 			break;
18931991Sheppo 
18941991Sheppo 		case LDC_RDX:
18951991Sheppo 			/* process RDX message */
18961991Sheppo 			rv = i_ldc_process_RDX(ldcp, msg);
18971991Sheppo 			break;
18981991Sheppo 
18991991Sheppo 		default:
19001991Sheppo 			DWARN(ldcp->id,
19011991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
19021991Sheppo 			    "tstate=0x%x\n", ldcp->id,
19031991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
19041991Sheppo 			break;
19051991Sheppo 		}
19061991Sheppo 	}
19071991Sheppo 
19081991Sheppo 	return (rv);
19091991Sheppo }
19101991Sheppo 
19111991Sheppo /*
19121991Sheppo  * Register channel with the channel nexus
19131991Sheppo  */
19141991Sheppo static int
19151991Sheppo i_ldc_register_channel(ldc_chan_t *ldcp)
19161991Sheppo {
19171991Sheppo 	int		rv = 0;
19181991Sheppo 	ldc_cnex_t	*cinfo = &ldcssp->cinfo;
19191991Sheppo 
19201991Sheppo 	if (cinfo->dip == NULL) {
19211991Sheppo 		DWARN(ldcp->id,
19221991Sheppo 		    "i_ldc_register_channel: cnex has not registered\n");
19231991Sheppo 		return (EAGAIN);
19241991Sheppo 	}
19251991Sheppo 
19261991Sheppo 	rv = cinfo->reg_chan(cinfo->dip, ldcp->id, ldcp->devclass);
19271991Sheppo 	if (rv) {
19281991Sheppo 		DWARN(ldcp->id,
19291991Sheppo 		    "i_ldc_register_channel: cannot register channel\n");
19301991Sheppo 		return (rv);
19311991Sheppo 	}
19321991Sheppo 
19331991Sheppo 	rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR,
19341991Sheppo 	    i_ldc_tx_hdlr, ldcp, NULL);
19351991Sheppo 	if (rv) {
19361991Sheppo 		DWARN(ldcp->id,
19371991Sheppo 		    "i_ldc_register_channel: cannot add Tx interrupt\n");
19381991Sheppo 		(void) cinfo->unreg_chan(cinfo->dip, ldcp->id);
19391991Sheppo 		return (rv);
19401991Sheppo 	}
19411991Sheppo 
19421991Sheppo 	rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR,
19431991Sheppo 	    i_ldc_rx_hdlr, ldcp, NULL);
19441991Sheppo 	if (rv) {
19451991Sheppo 		DWARN(ldcp->id,
19461991Sheppo 		    "i_ldc_register_channel: cannot add Rx interrupt\n");
19471991Sheppo 		(void) cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
19481991Sheppo 		(void) cinfo->unreg_chan(cinfo->dip, ldcp->id);
19491991Sheppo 		return (rv);
19501991Sheppo 	}
19511991Sheppo 
19521991Sheppo 	ldcp->tstate |= TS_CNEX_RDY;
19531991Sheppo 
19541991Sheppo 	return (0);
19551991Sheppo }
19561991Sheppo 
19571991Sheppo /*
19581991Sheppo  * Unregister a channel with the channel nexus
19591991Sheppo  */
19601991Sheppo static int
19611991Sheppo i_ldc_unregister_channel(ldc_chan_t *ldcp)
19621991Sheppo {
19631991Sheppo 	int		rv = 0;
19641991Sheppo 	ldc_cnex_t	*cinfo = &ldcssp->cinfo;
19651991Sheppo 
19661991Sheppo 	if (cinfo->dip == NULL) {
19671991Sheppo 		DWARN(ldcp->id,
19681991Sheppo 		    "i_ldc_unregister_channel: cnex has not registered\n");
19691991Sheppo 		return (EAGAIN);
19701991Sheppo 	}
19711991Sheppo 
19721991Sheppo 	if (ldcp->tstate & TS_CNEX_RDY) {
19731991Sheppo 
19742336Snarayan 		/* Remove the Rx interrupt */
19751991Sheppo 		rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR);
19761991Sheppo 		if (rv) {
19772793Slm66018 			if (rv != EAGAIN) {
19782793Slm66018 				DWARN(ldcp->id,
19792793Slm66018 				    "i_ldc_unregister_channel: err removing "
19802793Slm66018 				    "Rx intr\n");
19812793Slm66018 				return (rv);
19822793Slm66018 			}
19832793Slm66018 
19842793Slm66018 			/*
19852793Slm66018 			 * If interrupts are pending and handler has
19862793Slm66018 			 * finished running, clear interrupt and try
19872793Slm66018 			 * again
19882793Slm66018 			 */
19892793Slm66018 			if (ldcp->rx_intr_state != LDC_INTR_PEND)
19902793Slm66018 				return (rv);
19912793Slm66018 
19922793Slm66018 			(void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
19932793Slm66018 			rv = cinfo->rem_intr(cinfo->dip, ldcp->id,
19942793Slm66018 			    CNEX_RX_INTR);
19952793Slm66018 			if (rv) {
19962793Slm66018 				DWARN(ldcp->id, "i_ldc_unregister_channel: "
19972793Slm66018 				    "err removing Rx interrupt\n");
19982793Slm66018 				return (rv);
19992793Slm66018 			}
20001991Sheppo 		}
20012336Snarayan 
20022336Snarayan 		/* Remove the Tx interrupt */
20031991Sheppo 		rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
20041991Sheppo 		if (rv) {
20051991Sheppo 			DWARN(ldcp->id,
20061991Sheppo 			    "i_ldc_unregister_channel: err removing Tx intr\n");
20072336Snarayan 			return (rv);
20081991Sheppo 		}
20092336Snarayan 
20102336Snarayan 		/* Unregister the channel */
20111991Sheppo 		rv = cinfo->unreg_chan(ldcssp->cinfo.dip, ldcp->id);
20121991Sheppo 		if (rv) {
20131991Sheppo 			DWARN(ldcp->id,
20141991Sheppo 			    "i_ldc_unregister_channel: cannot unreg channel\n");
20152336Snarayan 			return (rv);
20161991Sheppo 		}
20171991Sheppo 
20181991Sheppo 		ldcp->tstate &= ~TS_CNEX_RDY;
20191991Sheppo 	}
20201991Sheppo 
20211991Sheppo 	return (0);
20221991Sheppo }
20231991Sheppo 
20241991Sheppo 
20251991Sheppo /*
20261991Sheppo  * LDC transmit interrupt handler
20271991Sheppo  *    triggered for chanel up/down/reset events
20281991Sheppo  *    and Tx queue content changes
20291991Sheppo  */
20301991Sheppo static uint_t
20311991Sheppo i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2)
20321991Sheppo {
20331991Sheppo 	_NOTE(ARGUNUSED(arg2))
20341991Sheppo 
20351991Sheppo 	int 		rv;
20361991Sheppo 	ldc_chan_t 	*ldcp;
20371991Sheppo 	boolean_t 	notify_client = B_FALSE;
20382793Slm66018 	uint64_t	notify_event = 0, link_state;
20391991Sheppo 
20401991Sheppo 	/* Get the channel for which interrupt was received */
20411991Sheppo 	ASSERT(arg1 != NULL);
20421991Sheppo 	ldcp = (ldc_chan_t *)arg1;
20431991Sheppo 
20441991Sheppo 	D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
20451991Sheppo 	    ldcp->id, ldcp);
20461991Sheppo 
20471991Sheppo 	/* Lock channel */
20481991Sheppo 	mutex_enter(&ldcp->lock);
20491991Sheppo 
20502336Snarayan 	/* Obtain Tx lock */
20512336Snarayan 	mutex_enter(&ldcp->tx_lock);
20522336Snarayan 
20532531Snarayan 	/* mark interrupt as pending */
20542793Slm66018 	ldcp->tx_intr_state = LDC_INTR_ACTIVE;
20552793Slm66018 
20562793Slm66018 	/* save current link state */
20572793Slm66018 	link_state = ldcp->link_state;
20582531Snarayan 
20591991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id, &ldcp->tx_head, &ldcp->tx_tail,
20601991Sheppo 	    &ldcp->link_state);
20611991Sheppo 	if (rv) {
20621991Sheppo 		cmn_err(CE_WARN,
20631991Sheppo 		    "i_ldc_tx_hdlr: (0x%lx) cannot read queue ptrs rv=0x%d\n",
20641991Sheppo 		    ldcp->id, rv);
20652531Snarayan 		i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
20662336Snarayan 		mutex_exit(&ldcp->tx_lock);
20671991Sheppo 		mutex_exit(&ldcp->lock);
20681991Sheppo 		return (DDI_INTR_CLAIMED);
20691991Sheppo 	}
20701991Sheppo 
20711991Sheppo 	/*
20721991Sheppo 	 * reset the channel state if the channel went down
20731991Sheppo 	 * (other side unconfigured queue) or channel was reset
20741991Sheppo 	 * (other side reconfigured its queue)
20751991Sheppo 	 */
20762793Slm66018 	if (link_state != ldcp->link_state &&
20772793Slm66018 	    ldcp->link_state == LDC_CHANNEL_DOWN) {
20781991Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link down\n", ldcp->id);
20792793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
20801991Sheppo 		notify_client = B_TRUE;
20811991Sheppo 		notify_event = LDC_EVT_DOWN;
20821991Sheppo 	}
20831991Sheppo 
20842793Slm66018 	if (link_state != ldcp->link_state &&
20852793Slm66018 	    ldcp->link_state == LDC_CHANNEL_RESET) {
20861991Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link reset\n", ldcp->id);
20872793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
20881991Sheppo 		notify_client = B_TRUE;
20891991Sheppo 		notify_event = LDC_EVT_RESET;
20901991Sheppo 	}
20911991Sheppo 
20922793Slm66018 	if (link_state != ldcp->link_state &&
20932793Slm66018 	    (ldcp->tstate & ~TS_IN_RESET) == TS_OPEN &&
20942793Slm66018 	    ldcp->link_state == LDC_CHANNEL_UP) {
20951991Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link up\n", ldcp->id);
20961991Sheppo 		notify_client = B_TRUE;
20971991Sheppo 		notify_event = LDC_EVT_RESET;
20981991Sheppo 		ldcp->tstate |= TS_LINK_READY;
20991991Sheppo 		ldcp->status = LDC_READY;
21001991Sheppo 	}
21011991Sheppo 
21021991Sheppo 	/* if callbacks are disabled, do not notify */
21031991Sheppo 	if (!ldcp->cb_enabled)
21041991Sheppo 		notify_client = B_FALSE;
21051991Sheppo 
21063151Ssg70180 	i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
21074690Snarayan 	mutex_exit(&ldcp->tx_lock);
21081991Sheppo 
21091991Sheppo 	if (notify_client) {
21102793Slm66018 		ldcp->cb_inprogress = B_TRUE;
21112793Slm66018 		mutex_exit(&ldcp->lock);
21121991Sheppo 		rv = ldcp->cb(notify_event, ldcp->cb_arg);
21131991Sheppo 		if (rv) {
21141991Sheppo 			DWARN(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) callback "
21151991Sheppo 			    "failure", ldcp->id);
21161991Sheppo 		}
21171991Sheppo 		mutex_enter(&ldcp->lock);
21181991Sheppo 		ldcp->cb_inprogress = B_FALSE;
21192793Slm66018 	}
21202793Slm66018 
21211991Sheppo 	mutex_exit(&ldcp->lock);
21221991Sheppo 
21231991Sheppo 	D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) exiting handler", ldcp->id);
21241991Sheppo 
21251991Sheppo 	return (DDI_INTR_CLAIMED);
21261991Sheppo }
21271991Sheppo 
21281991Sheppo /*
2129*5944Sha137994  * Process the Rx HV queue.
2130*5944Sha137994  *
2131*5944Sha137994  * Returns 0 if data packets were found and no errors were encountered,
2132*5944Sha137994  * otherwise returns an error. In either case, the *notify argument is
2133*5944Sha137994  * set to indicate whether or not the client callback function should
2134*5944Sha137994  * be invoked. The *event argument is set to contain the callback event.
2135*5944Sha137994  *
2136*5944Sha137994  * Depending on the channel mode, packets are handled differently:
2137*5944Sha137994  *
2138*5944Sha137994  * RAW MODE
2139*5944Sha137994  * For raw mode channels, when a data packet is encountered,
2140*5944Sha137994  * processing stops and all packets are left on the queue to be removed
2141*5944Sha137994  * and processed by the ldc_read code path.
2142*5944Sha137994  *
2143*5944Sha137994  * UNRELIABLE MODE
2144*5944Sha137994  * For unreliable mode, when a data packet is encountered, processing
2145*5944Sha137994  * stops, and all packets are left on the queue to be removed and
2146*5944Sha137994  * processed by the ldc_read code path. Control packets are processed
2147*5944Sha137994  * inline if they are encountered before any data packets.
2148*5944Sha137994  *
2149*5944Sha137994  * STEAMING MODE
2150*5944Sha137994  * For streaming mode channels, all packets on the receive queue
2151*5944Sha137994  * are processed: data packets are copied to the data queue and
2152*5944Sha137994  * control packets are processed inline. Packets are only left on
2153*5944Sha137994  * the receive queue when the data queue is full.
21541991Sheppo  */
21551991Sheppo static uint_t
2156*5944Sha137994 i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client,
2157*5944Sha137994     uint64_t *notify_event)
21581991Sheppo {
21591991Sheppo 	int		rv;
21601991Sheppo 	uint64_t 	rx_head, rx_tail;
21611991Sheppo 	ldc_msg_t 	*msg;
21622793Slm66018 	uint64_t	link_state, first_fragment = 0;
2163*5944Sha137994 	boolean_t	trace_length = B_TRUE;
2164*5944Sha137994 
2165*5944Sha137994 	ASSERT(MUTEX_HELD(&ldcp->lock));
2166*5944Sha137994 	*notify_client = B_FALSE;
2167*5944Sha137994 	*notify_event = 0;
21681991Sheppo 
21691991Sheppo 	/*
21701991Sheppo 	 * Read packet(s) from the queue
21711991Sheppo 	 */
21721991Sheppo 	for (;;) {
21731991Sheppo 
21742793Slm66018 		link_state = ldcp->link_state;
21751991Sheppo 		rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
21761991Sheppo 		    &ldcp->link_state);
21771991Sheppo 		if (rv) {
21781991Sheppo 			cmn_err(CE_WARN,
2179*5944Sha137994 			    "i_ldc_rx_process_hvq: (0x%lx) cannot read "
21801991Sheppo 			    "queue ptrs, rv=0x%d\n", ldcp->id, rv);
21811991Sheppo 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
2182*5944Sha137994 			return (EIO);
21831991Sheppo 		}
21841991Sheppo 
21851991Sheppo 		/*
21861991Sheppo 		 * reset the channel state if the channel went down
21871991Sheppo 		 * (other side unconfigured queue) or channel was reset
21882793Slm66018 		 * (other side reconfigured its queue)
21891991Sheppo 		 */
21902793Slm66018 
21912793Slm66018 		if (link_state != ldcp->link_state) {
21923010Slm66018 
21932793Slm66018 			switch (ldcp->link_state) {
21942793Slm66018 			case LDC_CHANNEL_DOWN:
2195*5944Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: channel "
21962793Slm66018 				    "link down\n", ldcp->id);
21972793Slm66018 				mutex_enter(&ldcp->tx_lock);
21982793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
21992793Slm66018 				mutex_exit(&ldcp->tx_lock);
2200*5944Sha137994 				*notify_client = B_TRUE;
2201*5944Sha137994 				*notify_event = LDC_EVT_DOWN;
22022793Slm66018 				goto loop_exit;
22032793Slm66018 
22042793Slm66018 			case LDC_CHANNEL_UP:
2205*5944Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: "
22062793Slm66018 				    "channel link up\n", ldcp->id);
22072793Slm66018 
22082793Slm66018 				if ((ldcp->tstate & ~TS_IN_RESET) == TS_OPEN) {
2209*5944Sha137994 					*notify_client = B_TRUE;
2210*5944Sha137994 					*notify_event = LDC_EVT_RESET;
22112793Slm66018 					ldcp->tstate |= TS_LINK_READY;
22122793Slm66018 					ldcp->status = LDC_READY;
22132793Slm66018 				}
22142793Slm66018 				break;
22152793Slm66018 
22162793Slm66018 			case LDC_CHANNEL_RESET:
22172793Slm66018 			default:
22182793Slm66018 #ifdef DEBUG
22192793Slm66018 force_reset:
22202793Slm66018 #endif
2221*5944Sha137994 				D1(ldcp->id, "i_ldc_rx_process_hvq: channel "
22222793Slm66018 				    "link reset\n", ldcp->id);
22232793Slm66018 				mutex_enter(&ldcp->tx_lock);
22242793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
22252793Slm66018 				mutex_exit(&ldcp->tx_lock);
2226*5944Sha137994 				*notify_client = B_TRUE;
2227*5944Sha137994 				*notify_event = LDC_EVT_RESET;
22282793Slm66018 				break;
22292793Slm66018 			}
22301991Sheppo 		}
22312793Slm66018 
22322793Slm66018 #ifdef DEBUG
22332793Slm66018 		if (LDC_INJECT_RESET(ldcp))
22342793Slm66018 			goto force_reset;
22352793Slm66018 #endif
2236*5944Sha137994 		if (trace_length) {
2237*5944Sha137994 			TRACE_RXHVQ_LENGTH(ldcp, rx_head, rx_tail);
2238*5944Sha137994 			trace_length = B_FALSE;
2239*5944Sha137994 		}
22401991Sheppo 
22411991Sheppo 		if (rx_head == rx_tail) {
2242*5944Sha137994 			D2(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) "
2243*5944Sha137994 			    "No packets\n", ldcp->id);
22441991Sheppo 			break;
22451991Sheppo 		}
22462793Slm66018 
2247*5944Sha137994 		D2(ldcp->id, "i_ldc_rx_process_hvq: head=0x%llx, "
2248*5944Sha137994 		    "tail=0x%llx\n", rx_head, rx_tail);
2249*5944Sha137994 		DUMP_LDC_PKT(ldcp, "i_ldc_rx_process_hvq rcd",
22501991Sheppo 		    ldcp->rx_q_va + rx_head);
22511991Sheppo 
22521991Sheppo 		/* get the message */
22531991Sheppo 		msg = (ldc_msg_t *)(ldcp->rx_q_va + rx_head);
22541991Sheppo 
22551991Sheppo 		/* if channel is in RAW mode or data pkt, notify and return */
22561991Sheppo 		if (ldcp->mode == LDC_MODE_RAW) {
2257*5944Sha137994 			*notify_client = B_TRUE;
2258*5944Sha137994 			*notify_event |= LDC_EVT_READ;
22591991Sheppo 			break;
22601991Sheppo 		}
22611991Sheppo 
22621991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
22631991Sheppo 
22641991Sheppo 			/* discard packet if channel is not up */
22652793Slm66018 			if ((ldcp->tstate & ~TS_IN_RESET) != TS_UP) {
22661991Sheppo 
22671991Sheppo 				/* move the head one position */
22681991Sheppo 				rx_head = (rx_head + LDC_PACKET_SIZE) %
22694690Snarayan 				    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
22701991Sheppo 
22711991Sheppo 				if (rv = i_ldc_set_rx_head(ldcp, rx_head))
22721991Sheppo 					break;
22731991Sheppo 
22741991Sheppo 				continue;
22751991Sheppo 			} else {
2276*5944Sha137994 				uint64_t dq_head, dq_tail;
2277*5944Sha137994 
2278*5944Sha137994 				/* process only STREAM mode data packets */
2279*5944Sha137994 				if (ldcp->mode != LDC_MODE_STREAM) {
2280*5944Sha137994 					if ((ldcp->tstate & TS_IN_RESET) == 0)
2281*5944Sha137994 						*notify_client = B_TRUE;
2282*5944Sha137994 					*notify_event |= LDC_EVT_READ;
2283*5944Sha137994 					break;
2284*5944Sha137994 				}
2285*5944Sha137994 
2286*5944Sha137994 				/* don't process packet if queue full */
2287*5944Sha137994 				(void) i_ldc_dq_rx_get_state(ldcp, &dq_head,
2288*5944Sha137994 				    &dq_tail, NULL);
2289*5944Sha137994 				dq_tail = (dq_tail + LDC_PACKET_SIZE) %
2290*5944Sha137994 				    (ldcp->rx_dq_entries << LDC_PACKET_SHIFT);
2291*5944Sha137994 				if (dq_tail == dq_head ||
2292*5944Sha137994 				    LDC_INJECT_DQFULL(ldcp)) {
2293*5944Sha137994 					rv = ENOSPC;
2294*5944Sha137994 					break;
2295*5944Sha137994 				}
22961991Sheppo 			}
22971991Sheppo 		}
22981991Sheppo 
22991991Sheppo 		/* Check the sequence ID for the message received */
23002793Slm66018 		rv = i_ldc_check_seqid(ldcp, msg);
23012793Slm66018 		if (rv != 0) {
23021991Sheppo 
2303*5944Sha137994 			DWARN(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) "
2304*5944Sha137994 			    "seqid error, q_ptrs=0x%lx,0x%lx", ldcp->id,
2305*5944Sha137994 			    rx_head, rx_tail);
23061991Sheppo 
23071991Sheppo 			/* Reset last_msg_rcd to start of message */
23082336Snarayan 			if (first_fragment != 0) {
23092336Snarayan 				ldcp->last_msg_rcd = first_fragment - 1;
23102336Snarayan 				first_fragment = 0;
23111991Sheppo 			}
23122336Snarayan 
23131991Sheppo 			/*
23141991Sheppo 			 * Send a NACK due to seqid mismatch
23151991Sheppo 			 */
23164690Snarayan 			rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK,
23171991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK));
23181991Sheppo 
23191991Sheppo 			if (rv) {
2320*5944Sha137994 				cmn_err(CE_NOTE, "i_ldc_rx_process_hvq: "
2321*5944Sha137994 				    "(0x%lx) err sending CTRL/DATA NACK msg\n",
2322*5944Sha137994 				    ldcp->id);
23232336Snarayan 
23242336Snarayan 				/* if cannot send NACK - reset channel */
23252336Snarayan 				mutex_enter(&ldcp->tx_lock);
23262793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
23272336Snarayan 				mutex_exit(&ldcp->tx_lock);
23283560Snarayan 
2329*5944Sha137994 				*notify_client = B_TRUE;
2330*5944Sha137994 				*notify_event = LDC_EVT_RESET;
23312336Snarayan 				break;
23321991Sheppo 			}
23331991Sheppo 
23341991Sheppo 			/* purge receive queue */
23351991Sheppo 			(void) i_ldc_set_rx_head(ldcp, rx_tail);
23361991Sheppo 			break;
23371991Sheppo 		}
23381991Sheppo 
23391991Sheppo 		/* record the message ID */
23401991Sheppo 		ldcp->last_msg_rcd = msg->seqid;
23411991Sheppo 
23421991Sheppo 		/* process control messages */
23431991Sheppo 		if (msg->type & LDC_CTRL) {
23441991Sheppo 			/* save current internal state */
23451991Sheppo 			uint64_t tstate = ldcp->tstate;
23461991Sheppo 
23471991Sheppo 			rv = i_ldc_ctrlmsg(ldcp, msg);
23481991Sheppo 			if (rv == EAGAIN) {
23491991Sheppo 				/* re-process pkt - state was adjusted */
23501991Sheppo 				continue;
23511991Sheppo 			}
23521991Sheppo 			if (rv == ECONNRESET) {
2353*5944Sha137994 				*notify_client = B_TRUE;
2354*5944Sha137994 				*notify_event = LDC_EVT_RESET;
23551991Sheppo 				break;
23561991Sheppo 			}
23571991Sheppo 
23581991Sheppo 			/*
23591991Sheppo 			 * control message processing was successful
23601991Sheppo 			 * channel transitioned to ready for communication
23611991Sheppo 			 */
23621991Sheppo 			if (rv == 0 && ldcp->tstate == TS_UP &&
23632793Slm66018 			    (tstate & ~TS_IN_RESET) !=
23642793Slm66018 			    (ldcp->tstate & ~TS_IN_RESET)) {
2365*5944Sha137994 				*notify_client = B_TRUE;
2366*5944Sha137994 				*notify_event = LDC_EVT_UP;
23671991Sheppo 			}
23681991Sheppo 		}
23691991Sheppo 
23703560Snarayan 		/* process data NACKs */
23713560Snarayan 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) {
23723560Snarayan 			DWARN(ldcp->id,
2373*5944Sha137994 			    "i_ldc_rx_process_hvq: (0x%llx) received DATA/NACK",
23743560Snarayan 			    ldcp->id);
23753560Snarayan 			mutex_enter(&ldcp->tx_lock);
23763560Snarayan 			i_ldc_reset(ldcp, B_TRUE);
23773560Snarayan 			mutex_exit(&ldcp->tx_lock);
2378*5944Sha137994 			*notify_client = B_TRUE;
2379*5944Sha137994 			*notify_event = LDC_EVT_RESET;
23803560Snarayan 			break;
23813560Snarayan 		}
23823560Snarayan 
23831991Sheppo 		/* process data ACKs */
23841991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
23852336Snarayan 			if (rv = i_ldc_process_data_ACK(ldcp, msg)) {
2386*5944Sha137994 				*notify_client = B_TRUE;
2387*5944Sha137994 				*notify_event = LDC_EVT_RESET;
23882336Snarayan 				break;
23892336Snarayan 			}
23901991Sheppo 		}
23911991Sheppo 
2392*5944Sha137994 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
2393*5944Sha137994 			ASSERT(ldcp->mode == LDC_MODE_STREAM);
2394*5944Sha137994 
2395*5944Sha137994 			/*
2396*5944Sha137994 			 * Copy the data packet to the data queue. Note
2397*5944Sha137994 			 * that the copy routine updates the rx_head pointer.
2398*5944Sha137994 			 */
2399*5944Sha137994 			i_ldc_rxdq_copy(ldcp, &rx_head);
2400*5944Sha137994 
2401*5944Sha137994 			if ((ldcp->tstate & TS_IN_RESET) == 0)
2402*5944Sha137994 				*notify_client = B_TRUE;
2403*5944Sha137994 			*notify_event |= LDC_EVT_READ;
2404*5944Sha137994 		} else {
2405*5944Sha137994 			rx_head = (rx_head + LDC_PACKET_SIZE) %
2406*5944Sha137994 			    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
2407*5944Sha137994 		}
2408*5944Sha137994 
24091991Sheppo 		/* move the head one position */
24102032Slm66018 		if (rv = i_ldc_set_rx_head(ldcp, rx_head)) {
2411*5944Sha137994 			*notify_client = B_TRUE;
2412*5944Sha137994 			*notify_event = LDC_EVT_RESET;
24131991Sheppo 			break;
24142032Slm66018 		}
24151991Sheppo 
24161991Sheppo 	} /* for */
24171991Sheppo 
24182793Slm66018 loop_exit:
24192793Slm66018 
2420*5944Sha137994 	if (ldcp->mode == LDC_MODE_STREAM) {
2421*5944Sha137994 		/* ACK data packets */
2422*5944Sha137994 		if ((*notify_event &
2423*5944Sha137994 		    (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) {
2424*5944Sha137994 			int ack_rv;
2425*5944Sha137994 			ack_rv = i_ldc_send_pkt(ldcp, LDC_DATA, LDC_ACK, 0);
2426*5944Sha137994 			if (ack_rv && ack_rv != EWOULDBLOCK) {
2427*5944Sha137994 				cmn_err(CE_NOTE,
2428*5944Sha137994 				    "i_ldc_rx_process_hvq: (0x%lx) cannot "
2429*5944Sha137994 				    "send ACK\n", ldcp->id);
2430*5944Sha137994 
2431*5944Sha137994 				mutex_enter(&ldcp->tx_lock);
2432*5944Sha137994 				i_ldc_reset(ldcp, B_FALSE);
2433*5944Sha137994 				mutex_exit(&ldcp->tx_lock);
2434*5944Sha137994 
2435*5944Sha137994 				*notify_client = B_TRUE;
2436*5944Sha137994 				*notify_event = LDC_EVT_RESET;
2437*5944Sha137994 				goto skip_ackpeek;
2438*5944Sha137994 			}
2439*5944Sha137994 		}
2440*5944Sha137994 
2441*5944Sha137994 		/*
2442*5944Sha137994 		 * If we have no more space on the data queue, make sure
2443*5944Sha137994 		 * there are no ACKs on the rx queue waiting to be processed.
2444*5944Sha137994 		 */
2445*5944Sha137994 		if (rv == ENOSPC) {
2446*5944Sha137994 			if (i_ldc_rx_ackpeek(ldcp, rx_head, rx_tail) != 0) {
2447*5944Sha137994 				ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
2448*5944Sha137994 				*notify_client = B_TRUE;
2449*5944Sha137994 				*notify_event = LDC_EVT_RESET;
2450*5944Sha137994 			}
2451*5944Sha137994 		} else {
2452*5944Sha137994 			ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
24531991Sheppo 		}
2454*5944Sha137994 	}
2455*5944Sha137994 
2456*5944Sha137994 skip_ackpeek:
2457*5944Sha137994 
2458*5944Sha137994 	/* Return, indicating whether or not data packets were found */
2459*5944Sha137994 	if ((*notify_event & (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ)
2460*5944Sha137994 		return (0);
2461*5944Sha137994 
2462*5944Sha137994 	return (ENOMSG);
24631991Sheppo }
24641991Sheppo 
2465*5944Sha137994 /*
2466*5944Sha137994  * Process any ACK packets on the HV receive queue.
2467*5944Sha137994  *
2468*5944Sha137994  * This function is only used by STREAMING mode channels when the
2469*5944Sha137994  * secondary data queue fills up and there are packets remaining on
2470*5944Sha137994  * the HV receive queue.
2471*5944Sha137994  */
2472*5944Sha137994 int
2473*5944Sha137994 i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, uint64_t rx_tail)
2474*5944Sha137994 {
2475*5944Sha137994 	int		rv = 0;
2476*5944Sha137994 	ldc_msg_t	*msg;
2477*5944Sha137994 
2478*5944Sha137994 	if (ldcp->rx_ack_head == ACKPEEK_HEAD_INVALID)
2479*5944Sha137994 		ldcp->rx_ack_head = rx_head;
2480*5944Sha137994 
2481*5944Sha137994 	while (ldcp->rx_ack_head != rx_tail) {
2482*5944Sha137994 		msg = (ldc_msg_t *)(ldcp->rx_q_va + ldcp->rx_ack_head);
2483*5944Sha137994 
2484*5944Sha137994 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
2485*5944Sha137994 			if (rv = i_ldc_process_data_ACK(ldcp, msg))
2486*5944Sha137994 				break;
2487*5944Sha137994 			msg->stype &= ~LDC_ACK;
2488*5944Sha137994 		}
2489*5944Sha137994 
2490*5944Sha137994 		ldcp->rx_ack_head =
2491*5944Sha137994 		    (ldcp->rx_ack_head + LDC_PACKET_SIZE) %
2492*5944Sha137994 		    (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
2493*5944Sha137994 	}
2494*5944Sha137994 	return (rv);
2495*5944Sha137994 }
24961991Sheppo 
24971991Sheppo /* -------------------------------------------------------------------------- */
24981991Sheppo 
24991991Sheppo /*
25001991Sheppo  * LDC API functions
25011991Sheppo  */
25021991Sheppo 
25031991Sheppo /*
25041991Sheppo  * Initialize the channel. Allocate internal structure and memory for
25051991Sheppo  * TX/RX queues, and initialize locks.
25061991Sheppo  */
25071991Sheppo int
25081991Sheppo ldc_init(uint64_t id, ldc_attr_t *attr, ldc_handle_t *handle)
25091991Sheppo {
25101991Sheppo 	ldc_chan_t 	*ldcp;
25111991Sheppo 	int		rv, exit_val;
25121991Sheppo 	uint64_t	ra_base, nentries;
25132410Slm66018 	uint64_t	qlen;
25141991Sheppo 
25151991Sheppo 	exit_val = EINVAL;	/* guarantee an error if exit on failure */
25161991Sheppo 
25171991Sheppo 	if (attr == NULL) {
25181991Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid attr\n", id);
25191991Sheppo 		return (EINVAL);
25201991Sheppo 	}
25211991Sheppo 	if (handle == NULL) {
25221991Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid handle\n", id);
25231991Sheppo 		return (EINVAL);
25241991Sheppo 	}
25251991Sheppo 
25261991Sheppo 	/* check if channel is valid */
25271991Sheppo 	rv = hv_ldc_tx_qinfo(id, &ra_base, &nentries);
25281991Sheppo 	if (rv == H_ECHANNEL) {
25291991Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid channel id\n", id);
25301991Sheppo 		return (EINVAL);
25311991Sheppo 	}
25321991Sheppo 
25331991Sheppo 	/* check if the channel has already been initialized */
25341991Sheppo 	mutex_enter(&ldcssp->lock);
25351991Sheppo 	ldcp = ldcssp->chan_list;
25361991Sheppo 	while (ldcp != NULL) {
25371991Sheppo 		if (ldcp->id == id) {
25381991Sheppo 			DWARN(id, "ldc_init: (0x%llx) already initialized\n",
25391991Sheppo 			    id);
25401991Sheppo 			mutex_exit(&ldcssp->lock);
25411991Sheppo 			return (EADDRINUSE);
25421991Sheppo 		}
25431991Sheppo 		ldcp = ldcp->next;
25441991Sheppo 	}
25451991Sheppo 	mutex_exit(&ldcssp->lock);
25461991Sheppo 
25471991Sheppo 	ASSERT(ldcp == NULL);
25481991Sheppo 
25491991Sheppo 	*handle = 0;
25501991Sheppo 
25511991Sheppo 	/* Allocate an ldcp structure */
25521991Sheppo 	ldcp = kmem_zalloc(sizeof (ldc_chan_t), KM_SLEEP);
25531991Sheppo 
25542336Snarayan 	/*
25552336Snarayan 	 * Initialize the channel and Tx lock
25562336Snarayan 	 *
25572336Snarayan 	 * The channel 'lock' protects the entire channel and
25582336Snarayan 	 * should be acquired before initializing, resetting,
25592336Snarayan 	 * destroying or reading from a channel.
25602336Snarayan 	 *
25612336Snarayan 	 * The 'tx_lock' should be acquired prior to transmitting
25622336Snarayan 	 * data over the channel. The lock should also be acquired
25632336Snarayan 	 * prior to channel reconfiguration (in order to prevent
25642336Snarayan 	 * concurrent writes).
25652336Snarayan 	 *
25662336Snarayan 	 * ORDERING: When both locks are being acquired, to prevent
25672336Snarayan 	 * deadlocks, the channel lock should be always acquired prior
25682336Snarayan 	 * to the tx_lock.
25692336Snarayan 	 */
25701991Sheppo 	mutex_init(&ldcp->lock, NULL, MUTEX_DRIVER, NULL);
25712336Snarayan 	mutex_init(&ldcp->tx_lock, NULL, MUTEX_DRIVER, NULL);
25721991Sheppo 
25731991Sheppo 	/* Initialize the channel */
25741991Sheppo 	ldcp->id = id;
25751991Sheppo 	ldcp->cb = NULL;
25761991Sheppo 	ldcp->cb_arg = NULL;
25771991Sheppo 	ldcp->cb_inprogress = B_FALSE;
25781991Sheppo 	ldcp->cb_enabled = B_FALSE;
25791991Sheppo 	ldcp->next = NULL;
25801991Sheppo 
25811991Sheppo 	/* Read attributes */
25821991Sheppo 	ldcp->mode = attr->mode;
25831991Sheppo 	ldcp->devclass = attr->devclass;
25841991Sheppo 	ldcp->devinst = attr->instance;
25852410Slm66018 	ldcp->mtu = (attr->mtu > 0) ? attr->mtu : LDC_DEFAULT_MTU;
25861991Sheppo 
25871991Sheppo 	D1(ldcp->id,
25881991Sheppo 	    "ldc_init: (0x%llx) channel attributes, class=0x%x, "
25892410Slm66018 	    "instance=0x%llx, mode=%d, mtu=%d\n",
25902410Slm66018 	    ldcp->id, ldcp->devclass, ldcp->devinst, ldcp->mode, ldcp->mtu);
25911991Sheppo 
25921991Sheppo 	ldcp->next_vidx = 0;
25932793Slm66018 	ldcp->tstate = TS_IN_RESET;
25941991Sheppo 	ldcp->hstate = 0;
25951991Sheppo 	ldcp->last_msg_snt = LDC_INIT_SEQID;
25961991Sheppo 	ldcp->last_ack_rcd = 0;
25971991Sheppo 	ldcp->last_msg_rcd = 0;
2598*5944Sha137994 	ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
25991991Sheppo 
26001991Sheppo 	ldcp->stream_bufferp = NULL;
26011991Sheppo 	ldcp->exp_dring_list = NULL;
26021991Sheppo 	ldcp->imp_dring_list = NULL;
26031991Sheppo 	ldcp->mhdl_list = NULL;
26041991Sheppo 
26052793Slm66018 	ldcp->tx_intr_state = LDC_INTR_NONE;
26062793Slm66018 	ldcp->rx_intr_state = LDC_INTR_NONE;
26072793Slm66018 
26081991Sheppo 	/* Initialize payload size depending on whether channel is reliable */
26091991Sheppo 	switch (ldcp->mode) {
26101991Sheppo 	case LDC_MODE_RAW:
26111991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RAW;
26121991Sheppo 		ldcp->read_p = i_ldc_read_raw;
26131991Sheppo 		ldcp->write_p = i_ldc_write_raw;
26141991Sheppo 		break;
26151991Sheppo 	case LDC_MODE_UNRELIABLE:
26161991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_UNRELIABLE;
26171991Sheppo 		ldcp->read_p = i_ldc_read_packet;
26181991Sheppo 		ldcp->write_p = i_ldc_write_packet;
26191991Sheppo 		break;
26201991Sheppo 	case LDC_MODE_RELIABLE:
26211991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE;
26221991Sheppo 		ldcp->read_p = i_ldc_read_packet;
26231991Sheppo 		ldcp->write_p = i_ldc_write_packet;
26241991Sheppo 		break;
26251991Sheppo 	case LDC_MODE_STREAM:
26261991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE;
26271991Sheppo 
26281991Sheppo 		ldcp->stream_remains = 0;
26291991Sheppo 		ldcp->stream_offset = 0;
26301991Sheppo 		ldcp->stream_bufferp = kmem_alloc(ldcp->mtu, KM_SLEEP);
26311991Sheppo 		ldcp->read_p = i_ldc_read_stream;
26321991Sheppo 		ldcp->write_p = i_ldc_write_stream;
26331991Sheppo 		break;
26341991Sheppo 	default:
26351991Sheppo 		exit_val = EINVAL;
26361991Sheppo 		goto cleanup_on_exit;
26371991Sheppo 	}
26381991Sheppo 
26392410Slm66018 	/*
26402410Slm66018 	 * qlen is (mtu * ldc_mtu_msgs) / pkt_payload. If this
26412410Slm66018 	 * value is smaller than default length of ldc_queue_entries,
26424690Snarayan 	 * qlen is set to ldc_queue_entries. Ensure that computed
26434690Snarayan 	 * length is a power-of-two value.
26442410Slm66018 	 */
26452410Slm66018 	qlen = (ldcp->mtu * ldc_mtu_msgs) / ldcp->pkt_payload;
26464690Snarayan 	if (!ISP2(qlen)) {
26474690Snarayan 		uint64_t	tmp = 1;
26484690Snarayan 		while (qlen) {
26494690Snarayan 			qlen >>= 1; tmp <<= 1;
26504690Snarayan 		}
26514690Snarayan 		qlen = tmp;
26524690Snarayan 	}
26534690Snarayan 
26542410Slm66018 	ldcp->rx_q_entries =
26554690Snarayan 	    (qlen < ldc_queue_entries) ? ldc_queue_entries : qlen;
26562410Slm66018 	ldcp->tx_q_entries = ldcp->rx_q_entries;
26572410Slm66018 
26584690Snarayan 	D1(ldcp->id, "ldc_init: queue length = 0x%llx\n", ldcp->rx_q_entries);
26592410Slm66018 
26601991Sheppo 	/* Create a transmit queue */
26611991Sheppo 	ldcp->tx_q_va = (uint64_t)
26624690Snarayan 	    contig_mem_alloc(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
26631991Sheppo 	if (ldcp->tx_q_va == NULL) {
26641991Sheppo 		cmn_err(CE_WARN,
26651991Sheppo 		    "ldc_init: (0x%lx) TX queue allocation failed\n",
26661991Sheppo 		    ldcp->id);
26671991Sheppo 		exit_val = ENOMEM;
26681991Sheppo 		goto cleanup_on_exit;
26691991Sheppo 	}
26701991Sheppo 	ldcp->tx_q_ra = va_to_pa((caddr_t)ldcp->tx_q_va);
26711991Sheppo 
26721991Sheppo 	D2(ldcp->id, "ldc_init: txq_va=0x%llx, txq_ra=0x%llx, entries=0x%llx\n",
26731991Sheppo 	    ldcp->tx_q_va, ldcp->tx_q_ra, ldcp->tx_q_entries);
26741991Sheppo 
26751991Sheppo 	ldcp->tstate |= TS_TXQ_RDY;
26761991Sheppo 
26771991Sheppo 	/* Create a receive queue */
26781991Sheppo 	ldcp->rx_q_va = (uint64_t)
26794690Snarayan 	    contig_mem_alloc(ldcp->rx_q_entries << LDC_PACKET_SHIFT);
26801991Sheppo 	if (ldcp->rx_q_va == NULL) {
26811991Sheppo 		cmn_err(CE_WARN,
26821991Sheppo 		    "ldc_init: (0x%lx) RX queue allocation failed\n",
26831991Sheppo 		    ldcp->id);
26841991Sheppo 		exit_val = ENOMEM;
26851991Sheppo 		goto cleanup_on_exit;
26861991Sheppo 	}
26871991Sheppo 	ldcp->rx_q_ra = va_to_pa((caddr_t)ldcp->rx_q_va);
26881991Sheppo 
26891991Sheppo 	D2(ldcp->id, "ldc_init: rxq_va=0x%llx, rxq_ra=0x%llx, entries=0x%llx\n",
26901991Sheppo 	    ldcp->rx_q_va, ldcp->rx_q_ra, ldcp->rx_q_entries);
26911991Sheppo 
26921991Sheppo 	ldcp->tstate |= TS_RXQ_RDY;
26931991Sheppo 
2694*5944Sha137994 	/* Setup a separate read data queue */
2695*5944Sha137994 	if (ldcp->mode == LDC_MODE_STREAM) {
2696*5944Sha137994 		ldcp->readq_get_state = i_ldc_dq_rx_get_state;
2697*5944Sha137994 		ldcp->readq_set_head  = i_ldc_set_rxdq_head;
2698*5944Sha137994 
2699*5944Sha137994 		/* Make sure the data queue multiplier is a power of 2 */
2700*5944Sha137994 		if (!ISP2(ldc_rxdq_multiplier)) {
2701*5944Sha137994 			D1(ldcp->id, "ldc_init: (0x%llx) ldc_rxdq_multiplier "
2702*5944Sha137994 			    "not a power of 2, resetting", ldcp->id);
2703*5944Sha137994 			ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER;
2704*5944Sha137994 		}
2705*5944Sha137994 
2706*5944Sha137994 		ldcp->rx_dq_entries = ldc_rxdq_multiplier * ldcp->rx_q_entries;
2707*5944Sha137994 		ldcp->rx_dq_va = (uint64_t)
2708*5944Sha137994 		    kmem_alloc(ldcp->rx_dq_entries << LDC_PACKET_SHIFT,
2709*5944Sha137994 		    KM_SLEEP);
2710*5944Sha137994 		if (ldcp->rx_dq_va == NULL) {
2711*5944Sha137994 			cmn_err(CE_WARN,
2712*5944Sha137994 			    "ldc_init: (0x%lx) RX data queue "
2713*5944Sha137994 			    "allocation failed\n", ldcp->id);
2714*5944Sha137994 			exit_val = ENOMEM;
2715*5944Sha137994 			goto cleanup_on_exit;
2716*5944Sha137994 		}
2717*5944Sha137994 
2718*5944Sha137994 		ldcp->rx_dq_head = ldcp->rx_dq_tail = 0;
2719*5944Sha137994 
2720*5944Sha137994 		D2(ldcp->id, "ldc_init: rx_dq_va=0x%llx, "
2721*5944Sha137994 		    "rx_dq_entries=0x%llx\n", ldcp->rx_dq_va,
2722*5944Sha137994 		    ldcp->rx_dq_entries);
2723*5944Sha137994 	} else {
2724*5944Sha137994 		ldcp->readq_get_state = i_ldc_hvq_rx_get_state;
2725*5944Sha137994 		ldcp->readq_set_head  = i_ldc_set_rx_head;
2726*5944Sha137994 	}
2727*5944Sha137994 
27281991Sheppo 	/* Init descriptor ring and memory handle list lock */
27291991Sheppo 	mutex_init(&ldcp->exp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
27301991Sheppo 	mutex_init(&ldcp->imp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
27311991Sheppo 	mutex_init(&ldcp->mlist_lock, NULL, MUTEX_DRIVER, NULL);
27321991Sheppo 
27331991Sheppo 	/* mark status as INITialized */
27341991Sheppo 	ldcp->status = LDC_INIT;
27351991Sheppo 
27361991Sheppo 	/* Add to channel list */
27371991Sheppo 	mutex_enter(&ldcssp->lock);
27381991Sheppo 	ldcp->next = ldcssp->chan_list;
27391991Sheppo 	ldcssp->chan_list = ldcp;
27401991Sheppo 	ldcssp->channel_count++;
27411991Sheppo 	mutex_exit(&ldcssp->lock);
27421991Sheppo 
27431991Sheppo 	/* set the handle */
27441991Sheppo 	*handle = (ldc_handle_t)ldcp;
27451991Sheppo 
27461991Sheppo 	D1(ldcp->id, "ldc_init: (0x%llx) channel initialized\n", ldcp->id);
27471991Sheppo 
27481991Sheppo 	return (0);
27491991Sheppo 
27501991Sheppo cleanup_on_exit:
27511991Sheppo 
27521991Sheppo 	if (ldcp->mode == LDC_MODE_STREAM && ldcp->stream_bufferp)
27531991Sheppo 		kmem_free(ldcp->stream_bufferp, ldcp->mtu);
27541991Sheppo 
27551991Sheppo 	if (ldcp->tstate & TS_TXQ_RDY)
27561991Sheppo 		contig_mem_free((caddr_t)ldcp->tx_q_va,
27571991Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
27581991Sheppo 
27591991Sheppo 	if (ldcp->tstate & TS_RXQ_RDY)
27601991Sheppo 		contig_mem_free((caddr_t)ldcp->rx_q_va,
27611991Sheppo 		    (ldcp->rx_q_entries << LDC_PACKET_SHIFT));
27621991Sheppo 
27632336Snarayan 	mutex_destroy(&ldcp->tx_lock);
27641991Sheppo 	mutex_destroy(&ldcp->lock);
27651991Sheppo 
27661991Sheppo 	if (ldcp)
27671991Sheppo 		kmem_free(ldcp, sizeof (ldc_chan_t));
27681991Sheppo 
27691991Sheppo 	return (exit_val);
27701991Sheppo }
27711991Sheppo 
27721991Sheppo /*
27731991Sheppo  * Finalizes the LDC connection. It will return EBUSY if the
27741991Sheppo  * channel is open. A ldc_close() has to be done prior to
27751991Sheppo  * a ldc_fini operation. It frees TX/RX queues, associated
27761991Sheppo  * with the channel
27771991Sheppo  */
27781991Sheppo int
27791991Sheppo ldc_fini(ldc_handle_t handle)
27801991Sheppo {
27811991Sheppo 	ldc_chan_t 	*ldcp;
27821991Sheppo 	ldc_chan_t 	*tmp_ldcp;
27831991Sheppo 	uint64_t 	id;
27841991Sheppo 
27851991Sheppo 	if (handle == NULL) {
27861991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel handle\n");
27871991Sheppo 		return (EINVAL);
27881991Sheppo 	}
27891991Sheppo 	ldcp = (ldc_chan_t *)handle;
27901991Sheppo 	id = ldcp->id;
27911991Sheppo 
27921991Sheppo 	mutex_enter(&ldcp->lock);
27931991Sheppo 
27942793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) > TS_INIT) {
27951991Sheppo 		DWARN(ldcp->id, "ldc_fini: (0x%llx) channel is open\n",
27961991Sheppo 		    ldcp->id);
27971991Sheppo 		mutex_exit(&ldcp->lock);
27981991Sheppo 		return (EBUSY);
27991991Sheppo 	}
28001991Sheppo 
28011991Sheppo 	/* Remove from the channel list */
28021991Sheppo 	mutex_enter(&ldcssp->lock);
28031991Sheppo 	tmp_ldcp = ldcssp->chan_list;
28041991Sheppo 	if (tmp_ldcp == ldcp) {
28051991Sheppo 		ldcssp->chan_list = ldcp->next;
28061991Sheppo 		ldcp->next = NULL;
28071991Sheppo 	} else {
28081991Sheppo 		while (tmp_ldcp != NULL) {
28091991Sheppo 			if (tmp_ldcp->next == ldcp) {
28101991Sheppo 				tmp_ldcp->next = ldcp->next;
28111991Sheppo 				ldcp->next = NULL;
28121991Sheppo 				break;
28131991Sheppo 			}
28141991Sheppo 			tmp_ldcp = tmp_ldcp->next;
28151991Sheppo 		}
28161991Sheppo 		if (tmp_ldcp == NULL) {
28171991Sheppo 			DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel hdl\n");
28181991Sheppo 			mutex_exit(&ldcssp->lock);
28191991Sheppo 			mutex_exit(&ldcp->lock);
28201991Sheppo 			return (EINVAL);
28211991Sheppo 		}
28221991Sheppo 	}
28231991Sheppo 
28241991Sheppo 	ldcssp->channel_count--;
28251991Sheppo 
28261991Sheppo 	mutex_exit(&ldcssp->lock);
28271991Sheppo 
28281991Sheppo 	/* Free the map table for this channel */
28291991Sheppo 	if (ldcp->mtbl) {
28301991Sheppo 		(void) hv_ldc_set_map_table(ldcp->id, NULL, NULL);
28312793Slm66018 		if (ldcp->mtbl->contigmem)
28322793Slm66018 			contig_mem_free(ldcp->mtbl->table, ldcp->mtbl->size);
28332793Slm66018 		else
28342793Slm66018 			kmem_free(ldcp->mtbl->table, ldcp->mtbl->size);
28351991Sheppo 		mutex_destroy(&ldcp->mtbl->lock);
28361991Sheppo 		kmem_free(ldcp->mtbl, sizeof (ldc_mtbl_t));
28371991Sheppo 	}
28381991Sheppo 
28391991Sheppo 	/* Destroy descriptor ring and memory handle list lock */
28401991Sheppo 	mutex_destroy(&ldcp->exp_dlist_lock);
28411991Sheppo 	mutex_destroy(&ldcp->imp_dlist_lock);
28421991Sheppo 	mutex_destroy(&ldcp->mlist_lock);
28431991Sheppo 
28441991Sheppo 	/* Free the stream buffer for STREAM_MODE */
28451991Sheppo 	if (ldcp->mode == LDC_MODE_STREAM && ldcp->stream_bufferp)
28461991Sheppo 		kmem_free(ldcp->stream_bufferp, ldcp->mtu);
28471991Sheppo 
28481991Sheppo 	/* Free the RX queue */
28491991Sheppo 	contig_mem_free((caddr_t)ldcp->rx_q_va,
28501991Sheppo 	    (ldcp->rx_q_entries << LDC_PACKET_SHIFT));
28511991Sheppo 	ldcp->tstate &= ~TS_RXQ_RDY;
28521991Sheppo 
2853*5944Sha137994 	/* Free the RX data queue */
2854*5944Sha137994 	if (ldcp->mode == LDC_MODE_STREAM) {
2855*5944Sha137994 		kmem_free((caddr_t)ldcp->rx_dq_va,
2856*5944Sha137994 		    (ldcp->rx_dq_entries << LDC_PACKET_SHIFT));
2857*5944Sha137994 	}
2858*5944Sha137994 
28591991Sheppo 	/* Free the TX queue */
28601991Sheppo 	contig_mem_free((caddr_t)ldcp->tx_q_va,
28611991Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
28621991Sheppo 	ldcp->tstate &= ~TS_TXQ_RDY;
28631991Sheppo 
28641991Sheppo 	mutex_exit(&ldcp->lock);
28651991Sheppo 
28661991Sheppo 	/* Destroy mutex */
28672336Snarayan 	mutex_destroy(&ldcp->tx_lock);
28681991Sheppo 	mutex_destroy(&ldcp->lock);
28691991Sheppo 
28701991Sheppo 	/* free channel structure */
28711991Sheppo 	kmem_free(ldcp, sizeof (ldc_chan_t));
28721991Sheppo 
28731991Sheppo 	D1(id, "ldc_fini: (0x%llx) channel finalized\n", id);
28741991Sheppo 
28751991Sheppo 	return (0);
28761991Sheppo }
28771991Sheppo 
28781991Sheppo /*
28791991Sheppo  * Open the LDC channel for use. It registers the TX/RX queues
28801991Sheppo  * with the Hypervisor. It also specifies the interrupt number
28811991Sheppo  * and target CPU for this channel
28821991Sheppo  */
28831991Sheppo int
28841991Sheppo ldc_open(ldc_handle_t handle)
28851991Sheppo {
28861991Sheppo 	ldc_chan_t 	*ldcp;
28871991Sheppo 	int 		rv;
28881991Sheppo 
28891991Sheppo 	if (handle == NULL) {
28901991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_open: invalid channel handle\n");
28911991Sheppo 		return (EINVAL);
28921991Sheppo 	}
28931991Sheppo 
28941991Sheppo 	ldcp = (ldc_chan_t *)handle;
28951991Sheppo 
28961991Sheppo 	mutex_enter(&ldcp->lock);
28971991Sheppo 
28981991Sheppo 	if (ldcp->tstate < TS_INIT) {
28991991Sheppo 		DWARN(ldcp->id,
29001991Sheppo 		    "ldc_open: (0x%llx) channel not initialized\n", ldcp->id);
29011991Sheppo 		mutex_exit(&ldcp->lock);
29021991Sheppo 		return (EFAULT);
29031991Sheppo 	}
29042793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) >= TS_OPEN) {
29051991Sheppo 		DWARN(ldcp->id,
29061991Sheppo 		    "ldc_open: (0x%llx) channel is already open\n", ldcp->id);
29071991Sheppo 		mutex_exit(&ldcp->lock);
29081991Sheppo 		return (EFAULT);
29091991Sheppo 	}
29101991Sheppo 
29111991Sheppo 	/*
29121991Sheppo 	 * Unregister/Register the tx queue with the hypervisor
29131991Sheppo 	 */
29141991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
29151991Sheppo 	if (rv) {
29161991Sheppo 		cmn_err(CE_WARN,
29171991Sheppo 		    "ldc_open: (0x%lx) channel tx queue unconf failed\n",
29181991Sheppo 		    ldcp->id);
29191991Sheppo 		mutex_exit(&ldcp->lock);
29201991Sheppo 		return (EIO);
29211991Sheppo 	}
29221991Sheppo 
29231991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
29241991Sheppo 	if (rv) {
29251991Sheppo 		cmn_err(CE_WARN,
29261991Sheppo 		    "ldc_open: (0x%lx) channel tx queue conf failed\n",
29271991Sheppo 		    ldcp->id);
29281991Sheppo 		mutex_exit(&ldcp->lock);
29291991Sheppo 		return (EIO);
29301991Sheppo 	}
29311991Sheppo 
29321991Sheppo 	D2(ldcp->id, "ldc_open: (0x%llx) registered tx queue with LDC\n",
29331991Sheppo 	    ldcp->id);
29341991Sheppo 
29351991Sheppo 	/*
29361991Sheppo 	 * Unregister/Register the rx queue with the hypervisor
29371991Sheppo 	 */
29381991Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
29391991Sheppo 	if (rv) {
29401991Sheppo 		cmn_err(CE_WARN,
29411991Sheppo 		    "ldc_open: (0x%lx) channel rx queue unconf failed\n",
29421991Sheppo 		    ldcp->id);
29431991Sheppo 		mutex_exit(&ldcp->lock);
29441991Sheppo 		return (EIO);
29451991Sheppo 	}
29461991Sheppo 
29471991Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, ldcp->rx_q_entries);
29481991Sheppo 	if (rv) {
29491991Sheppo 		cmn_err(CE_WARN,
29501991Sheppo 		    "ldc_open: (0x%lx) channel rx queue conf failed\n",
29511991Sheppo 		    ldcp->id);
29521991Sheppo 		mutex_exit(&ldcp->lock);
29531991Sheppo 		return (EIO);
29541991Sheppo 	}
29551991Sheppo 
29561991Sheppo 	D2(ldcp->id, "ldc_open: (0x%llx) registered rx queue with LDC\n",
29571991Sheppo 	    ldcp->id);
29581991Sheppo 
29591991Sheppo 	ldcp->tstate |= TS_QCONF_RDY;
29601991Sheppo 
29611991Sheppo 	/* Register the channel with the channel nexus */
29621991Sheppo 	rv = i_ldc_register_channel(ldcp);
29631991Sheppo 	if (rv && rv != EAGAIN) {
29641991Sheppo 		cmn_err(CE_WARN,
29651991Sheppo 		    "ldc_open: (0x%lx) channel register failed\n", ldcp->id);
29661991Sheppo 		(void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
29671991Sheppo 		(void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
29681991Sheppo 		mutex_exit(&ldcp->lock);
29691991Sheppo 		return (EIO);
29701991Sheppo 	}
29711991Sheppo 
29721991Sheppo 	/* mark channel in OPEN state */
29731991Sheppo 	ldcp->status = LDC_OPEN;
29741991Sheppo 
29751991Sheppo 	/* Read channel state */
29761991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
29771991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
29781991Sheppo 	if (rv) {
29791991Sheppo 		cmn_err(CE_WARN,
29801991Sheppo 		    "ldc_open: (0x%lx) cannot read channel state\n",
29811991Sheppo 		    ldcp->id);
29821991Sheppo 		(void) i_ldc_unregister_channel(ldcp);
29831991Sheppo 		(void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
29841991Sheppo 		(void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
29851991Sheppo 		mutex_exit(&ldcp->lock);
29861991Sheppo 		return (EIO);
29871991Sheppo 	}
29881991Sheppo 
29891991Sheppo 	/*
29901991Sheppo 	 * set the ACKd head to current head location for reliable &
29911991Sheppo 	 * streaming mode
29921991Sheppo 	 */
29931991Sheppo 	ldcp->tx_ackd_head = ldcp->tx_head;
29941991Sheppo 
29951991Sheppo 	/* mark channel ready if HV report link is UP (peer alloc'd Rx queue) */
29961991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_UP ||
29971991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
29981991Sheppo 		ldcp->tstate |= TS_LINK_READY;
29991991Sheppo 		ldcp->status = LDC_READY;
30001991Sheppo 	}
30011991Sheppo 
30021991Sheppo 	/*
30031991Sheppo 	 * if channel is being opened in RAW mode - no handshake is needed
30041991Sheppo 	 * switch the channel READY and UP state
30051991Sheppo 	 */
30061991Sheppo 	if (ldcp->mode == LDC_MODE_RAW) {
30071991Sheppo 		ldcp->tstate = TS_UP;	/* set bits associated with LDC UP */
30081991Sheppo 		ldcp->status = LDC_UP;
30091991Sheppo 	}
30101991Sheppo 
30111991Sheppo 	mutex_exit(&ldcp->lock);
30121991Sheppo 
30131991Sheppo 	/*
30141991Sheppo 	 * Increment number of open channels
30151991Sheppo 	 */
30161991Sheppo 	mutex_enter(&ldcssp->lock);
30171991Sheppo 	ldcssp->channels_open++;
30181991Sheppo 	mutex_exit(&ldcssp->lock);
30191991Sheppo 
30203010Slm66018 	D1(ldcp->id,
30212793Slm66018 	    "ldc_open: (0x%llx) channel (0x%p) open for use "
30222793Slm66018 	    "(tstate=0x%x, status=0x%x)\n",
30232793Slm66018 	    ldcp->id, ldcp, ldcp->tstate, ldcp->status);
30241991Sheppo 
30251991Sheppo 	return (0);
30261991Sheppo }
30271991Sheppo 
30281991Sheppo /*
30291991Sheppo  * Close the LDC connection. It will return EBUSY if there
30301991Sheppo  * are memory segments or descriptor rings either bound to or
30311991Sheppo  * mapped over the channel
30321991Sheppo  */
30331991Sheppo int
30341991Sheppo ldc_close(ldc_handle_t handle)
30351991Sheppo {
30361991Sheppo 	ldc_chan_t 	*ldcp;
30372336Snarayan 	int		rv = 0, retries = 0;
30381991Sheppo 	boolean_t	chk_done = B_FALSE;
30391991Sheppo 
30401991Sheppo 	if (handle == NULL) {
30411991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_close: invalid channel handle\n");
30421991Sheppo 		return (EINVAL);
30431991Sheppo 	}
30441991Sheppo 	ldcp = (ldc_chan_t *)handle;
30451991Sheppo 
30461991Sheppo 	mutex_enter(&ldcp->lock);
30471991Sheppo 
30481991Sheppo 	/* return error if channel is not open */
30492793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) < TS_OPEN) {
30501991Sheppo 		DWARN(ldcp->id,
30511991Sheppo 		    "ldc_close: (0x%llx) channel is not open\n", ldcp->id);
30521991Sheppo 		mutex_exit(&ldcp->lock);
30531991Sheppo 		return (EFAULT);
30541991Sheppo 	}
30551991Sheppo 
30561991Sheppo 	/* if any memory handles, drings, are bound or mapped cannot close */
30571991Sheppo 	if (ldcp->mhdl_list != NULL) {
30581991Sheppo 		DWARN(ldcp->id,
30591991Sheppo 		    "ldc_close: (0x%llx) channel has bound memory handles\n",
30601991Sheppo 		    ldcp->id);
30611991Sheppo 		mutex_exit(&ldcp->lock);
30621991Sheppo 		return (EBUSY);
30631991Sheppo 	}
30641991Sheppo 	if (ldcp->exp_dring_list != NULL) {
30651991Sheppo 		DWARN(ldcp->id,
30661991Sheppo 		    "ldc_close: (0x%llx) channel has bound descriptor rings\n",
30671991Sheppo 		    ldcp->id);
30681991Sheppo 		mutex_exit(&ldcp->lock);
30691991Sheppo 		return (EBUSY);
30701991Sheppo 	}
30711991Sheppo 	if (ldcp->imp_dring_list != NULL) {
30721991Sheppo 		DWARN(ldcp->id,
30731991Sheppo 		    "ldc_close: (0x%llx) channel has mapped descriptor rings\n",
30741991Sheppo 		    ldcp->id);
30751991Sheppo 		mutex_exit(&ldcp->lock);
30761991Sheppo 		return (EBUSY);
30771991Sheppo 	}
30781991Sheppo 
30793151Ssg70180 	if (ldcp->cb_inprogress) {
30803151Ssg70180 		DWARN(ldcp->id, "ldc_close: (0x%llx) callback active\n",
30813151Ssg70180 		    ldcp->id);
30823151Ssg70180 		mutex_exit(&ldcp->lock);
30833151Ssg70180 		return (EWOULDBLOCK);
30843151Ssg70180 	}
30853151Ssg70180 
30862336Snarayan 	/* Obtain Tx lock */
30872336Snarayan 	mutex_enter(&ldcp->tx_lock);
30882336Snarayan 
30891991Sheppo 	/*
30901991Sheppo 	 * Wait for pending transmits to complete i.e Tx queue to drain
30911991Sheppo 	 * if there are pending pkts - wait 1 ms and retry again
30921991Sheppo 	 */
30931991Sheppo 	for (;;) {
30941991Sheppo 
30951991Sheppo 		rv = hv_ldc_tx_get_state(ldcp->id,
30961991Sheppo 		    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
30971991Sheppo 		if (rv) {
30981991Sheppo 			cmn_err(CE_WARN,
30991991Sheppo 			    "ldc_close: (0x%lx) cannot read qptrs\n", ldcp->id);
31002336Snarayan 			mutex_exit(&ldcp->tx_lock);
31011991Sheppo 			mutex_exit(&ldcp->lock);
31021991Sheppo 			return (EIO);
31031991Sheppo 		}
31041991Sheppo 
31051991Sheppo 		if (ldcp->tx_head == ldcp->tx_tail ||
31061991Sheppo 		    ldcp->link_state != LDC_CHANNEL_UP) {
31071991Sheppo 			break;
31081991Sheppo 		}
31091991Sheppo 
31101991Sheppo 		if (chk_done) {
31111991Sheppo 			DWARN(ldcp->id,
31121991Sheppo 			    "ldc_close: (0x%llx) Tx queue drain timeout\n",
31131991Sheppo 			    ldcp->id);
31141991Sheppo 			break;
31151991Sheppo 		}
31161991Sheppo 
31171991Sheppo 		/* wait for one ms and try again */
31181991Sheppo 		delay(drv_usectohz(1000));
31191991Sheppo 		chk_done = B_TRUE;
31201991Sheppo 	}
31211991Sheppo 
31221991Sheppo 	/*
31232841Snarayan 	 * Drain the Tx and Rx queues as we are closing the
31242841Snarayan 	 * channel. We dont care about any pending packets.
31252841Snarayan 	 * We have to also drain the queue prior to clearing
31262841Snarayan 	 * pending interrupts, otherwise the HV will trigger
31272841Snarayan 	 * an interrupt the moment the interrupt state is
31282841Snarayan 	 * cleared.
31292793Slm66018 	 */
31302793Slm66018 	(void) i_ldc_txq_reconf(ldcp);
31312841Snarayan 	(void) i_ldc_rxq_drain(ldcp);
31322793Slm66018 
31332793Slm66018 	/*
31341991Sheppo 	 * Unregister the channel with the nexus
31351991Sheppo 	 */
31362336Snarayan 	while ((rv = i_ldc_unregister_channel(ldcp)) != 0) {
31372336Snarayan 
31382336Snarayan 		mutex_exit(&ldcp->tx_lock);
31391991Sheppo 		mutex_exit(&ldcp->lock);
31402336Snarayan 
31412336Snarayan 		/* if any error other than EAGAIN return back */
31422841Snarayan 		if (rv != EAGAIN || retries >= ldc_max_retries) {
31432336Snarayan 			cmn_err(CE_WARN,
31442336Snarayan 			    "ldc_close: (0x%lx) unregister failed, %d\n",
31452336Snarayan 			    ldcp->id, rv);
31462336Snarayan 			return (rv);
31472336Snarayan 		}
31482336Snarayan 
31492336Snarayan 		/*
31502336Snarayan 		 * As there could be pending interrupts we need
31512336Snarayan 		 * to wait and try again
31522336Snarayan 		 */
31533151Ssg70180 		drv_usecwait(ldc_close_delay);
31542336Snarayan 		mutex_enter(&ldcp->lock);
31552336Snarayan 		mutex_enter(&ldcp->tx_lock);
31562336Snarayan 		retries++;
31571991Sheppo 	}
31581991Sheppo 
31591991Sheppo 	/*
31601991Sheppo 	 * Unregister queues
31611991Sheppo 	 */
31621991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
31631991Sheppo 	if (rv) {
31641991Sheppo 		cmn_err(CE_WARN,
31651991Sheppo 		    "ldc_close: (0x%lx) channel TX queue unconf failed\n",
31661991Sheppo 		    ldcp->id);
31672336Snarayan 		mutex_exit(&ldcp->tx_lock);
31681991Sheppo 		mutex_exit(&ldcp->lock);
31691991Sheppo 		return (EIO);
31701991Sheppo 	}
31711991Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
31721991Sheppo 	if (rv) {
31731991Sheppo 		cmn_err(CE_WARN,
31741991Sheppo 		    "ldc_close: (0x%lx) channel RX queue unconf failed\n",
31751991Sheppo 		    ldcp->id);
31762336Snarayan 		mutex_exit(&ldcp->tx_lock);
31771991Sheppo 		mutex_exit(&ldcp->lock);
31781991Sheppo 		return (EIO);
31791991Sheppo 	}
31801991Sheppo 
31811991Sheppo 	ldcp->tstate &= ~TS_QCONF_RDY;
31821991Sheppo 
31831991Sheppo 	/* Reset channel state information */
31841991Sheppo 	i_ldc_reset_state(ldcp);
31851991Sheppo 
31861991Sheppo 	/* Mark channel as down and in initialized state */
31871991Sheppo 	ldcp->tx_ackd_head = 0;
31881991Sheppo 	ldcp->tx_head = 0;
31892793Slm66018 	ldcp->tstate = TS_IN_RESET|TS_INIT;
31901991Sheppo 	ldcp->status = LDC_INIT;
31911991Sheppo 
31922336Snarayan 	mutex_exit(&ldcp->tx_lock);
31931991Sheppo 	mutex_exit(&ldcp->lock);
31941991Sheppo 
31951991Sheppo 	/* Decrement number of open channels */
31961991Sheppo 	mutex_enter(&ldcssp->lock);
31971991Sheppo 	ldcssp->channels_open--;
31981991Sheppo 	mutex_exit(&ldcssp->lock);
31991991Sheppo 
32001991Sheppo 	D1(ldcp->id, "ldc_close: (0x%llx) channel closed\n", ldcp->id);
32011991Sheppo 
32021991Sheppo 	return (0);
32031991Sheppo }
32041991Sheppo 
32051991Sheppo /*
32061991Sheppo  * Register channel callback
32071991Sheppo  */
32081991Sheppo int
32091991Sheppo ldc_reg_callback(ldc_handle_t handle,
32101991Sheppo     uint_t(*cb)(uint64_t event, caddr_t arg), caddr_t arg)
32111991Sheppo {
32121991Sheppo 	ldc_chan_t *ldcp;
32131991Sheppo 
32141991Sheppo 	if (handle == NULL) {
32151991Sheppo 		DWARN(DBG_ALL_LDCS,
32161991Sheppo 		    "ldc_reg_callback: invalid channel handle\n");
32171991Sheppo 		return (EINVAL);
32181991Sheppo 	}
32191991Sheppo 	if (((uint64_t)cb) < KERNELBASE) {
32201991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_reg_callback: invalid callback\n");
32211991Sheppo 		return (EINVAL);
32221991Sheppo 	}
32231991Sheppo 	ldcp = (ldc_chan_t *)handle;
32241991Sheppo 
32251991Sheppo 	mutex_enter(&ldcp->lock);
32261991Sheppo 
32271991Sheppo 	if (ldcp->cb) {
32281991Sheppo 		DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback exists\n",
32291991Sheppo 		    ldcp->id);
32301991Sheppo 		mutex_exit(&ldcp->lock);
32311991Sheppo 		return (EIO);
32321991Sheppo 	}
32331991Sheppo 	if (ldcp->cb_inprogress) {
32341991Sheppo 		DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback active\n",
32351991Sheppo 		    ldcp->id);
32361991Sheppo 		mutex_exit(&ldcp->lock);
32371991Sheppo 		return (EWOULDBLOCK);
32381991Sheppo 	}
32391991Sheppo 
32401991Sheppo 	ldcp->cb = cb;
32411991Sheppo 	ldcp->cb_arg = arg;
32421991Sheppo 	ldcp->cb_enabled = B_TRUE;
32431991Sheppo 
32441991Sheppo 	D1(ldcp->id,
32451991Sheppo 	    "ldc_reg_callback: (0x%llx) registered callback for channel\n",
32461991Sheppo 	    ldcp->id);
32471991Sheppo 
32481991Sheppo 	mutex_exit(&ldcp->lock);
32491991Sheppo 
32501991Sheppo 	return (0);
32511991Sheppo }
32521991Sheppo 
32531991Sheppo /*
32541991Sheppo  * Unregister channel callback
32551991Sheppo  */
32561991Sheppo int
32571991Sheppo ldc_unreg_callback(ldc_handle_t handle)
32581991Sheppo {
32591991Sheppo 	ldc_chan_t *ldcp;
32601991Sheppo 
32611991Sheppo 	if (handle == NULL) {
32621991Sheppo 		DWARN(DBG_ALL_LDCS,
32631991Sheppo 		    "ldc_unreg_callback: invalid channel handle\n");
32641991Sheppo 		return (EINVAL);
32651991Sheppo 	}
32661991Sheppo 	ldcp = (ldc_chan_t *)handle;
32671991Sheppo 
32681991Sheppo 	mutex_enter(&ldcp->lock);
32691991Sheppo 
32701991Sheppo 	if (ldcp->cb == NULL) {
32711991Sheppo 		DWARN(ldcp->id,
32721991Sheppo 		    "ldc_unreg_callback: (0x%llx) no callback exists\n",
32731991Sheppo 		    ldcp->id);
32741991Sheppo 		mutex_exit(&ldcp->lock);
32751991Sheppo 		return (EIO);
32761991Sheppo 	}
32771991Sheppo 	if (ldcp->cb_inprogress) {
32781991Sheppo 		DWARN(ldcp->id,
32791991Sheppo 		    "ldc_unreg_callback: (0x%llx) callback active\n",
32801991Sheppo 		    ldcp->id);
32811991Sheppo 		mutex_exit(&ldcp->lock);
32821991Sheppo 		return (EWOULDBLOCK);
32831991Sheppo 	}
32841991Sheppo 
32851991Sheppo 	ldcp->cb = NULL;
32861991Sheppo 	ldcp->cb_arg = NULL;
32871991Sheppo 	ldcp->cb_enabled = B_FALSE;
32881991Sheppo 
32891991Sheppo 	D1(ldcp->id,
32901991Sheppo 	    "ldc_unreg_callback: (0x%llx) unregistered callback for channel\n",
32911991Sheppo 	    ldcp->id);
32921991Sheppo 
32931991Sheppo 	mutex_exit(&ldcp->lock);
32941991Sheppo 
32951991Sheppo 	return (0);
32961991Sheppo }
32971991Sheppo 
32981991Sheppo 
32991991Sheppo /*
33001991Sheppo  * Bring a channel up by initiating a handshake with the peer
33011991Sheppo  * This call is asynchronous. It will complete at a later point
33021991Sheppo  * in time when the peer responds back with an RTR.
33031991Sheppo  */
33041991Sheppo int
33051991Sheppo ldc_up(ldc_handle_t handle)
33061991Sheppo {
33071991Sheppo 	int 		rv;
33081991Sheppo 	ldc_chan_t 	*ldcp;
33091991Sheppo 	ldc_msg_t 	*ldcmsg;
33103808Ssb155480 	uint64_t 	tx_tail, tstate, link_state;
33111991Sheppo 
33121991Sheppo 	if (handle == NULL) {
33131991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_up: invalid channel handle\n");
33141991Sheppo 		return (EINVAL);
33151991Sheppo 	}
33161991Sheppo 	ldcp = (ldc_chan_t *)handle;
33171991Sheppo 
33181991Sheppo 	mutex_enter(&ldcp->lock);
33191991Sheppo 
33202793Slm66018 	D1(ldcp->id, "ldc_up: (0x%llx) doing channel UP\n", ldcp->id);
33212793Slm66018 
33222793Slm66018 	/* clear the reset state */
33232793Slm66018 	tstate = ldcp->tstate;
33242793Slm66018 	ldcp->tstate &= ~TS_IN_RESET;
33252793Slm66018 
33261991Sheppo 	if (ldcp->tstate == TS_UP) {
33272793Slm66018 		DWARN(ldcp->id,
33281991Sheppo 		    "ldc_up: (0x%llx) channel is already in UP state\n",
33291991Sheppo 		    ldcp->id);
33302793Slm66018 
33312793Slm66018 		/* mark channel as up */
33322793Slm66018 		ldcp->status = LDC_UP;
33332793Slm66018 
33342793Slm66018 		/*
33352793Slm66018 		 * if channel was in reset state and there was
33362793Slm66018 		 * pending data clear interrupt state. this will
33372793Slm66018 		 * trigger an interrupt, causing the RX handler to
33382793Slm66018 		 * to invoke the client's callback
33392793Slm66018 		 */
33402793Slm66018 		if ((tstate & TS_IN_RESET) &&
33412793Slm66018 		    ldcp->rx_intr_state == LDC_INTR_PEND) {
33423010Slm66018 			D1(ldcp->id,
33432793Slm66018 			    "ldc_up: (0x%llx) channel has pending data, "
33442793Slm66018 			    "clearing interrupt\n", ldcp->id);
33452793Slm66018 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
33462793Slm66018 		}
33472793Slm66018 
33481991Sheppo 		mutex_exit(&ldcp->lock);
33491991Sheppo 		return (0);
33501991Sheppo 	}
33511991Sheppo 
33521991Sheppo 	/* if the channel is in RAW mode - mark it as UP, if READY */
33531991Sheppo 	if (ldcp->mode == LDC_MODE_RAW && ldcp->tstate >= TS_READY) {
33541991Sheppo 		ldcp->tstate = TS_UP;
33551991Sheppo 		mutex_exit(&ldcp->lock);
33561991Sheppo 		return (0);
33571991Sheppo 	}
33581991Sheppo 
33591991Sheppo 	/* Don't start another handshake if there is one in progress */
33601991Sheppo 	if (ldcp->hstate) {
33612793Slm66018 		D1(ldcp->id,
33621991Sheppo 		    "ldc_up: (0x%llx) channel handshake in progress\n",
33631991Sheppo 		    ldcp->id);
33641991Sheppo 		mutex_exit(&ldcp->lock);
33651991Sheppo 		return (0);
33661991Sheppo 	}
33671991Sheppo 
33682336Snarayan 	mutex_enter(&ldcp->tx_lock);
33692336Snarayan 
33703808Ssb155480 	/* save current link state */
33713808Ssb155480 	link_state = ldcp->link_state;
33723808Ssb155480 
33731991Sheppo 	/* get the current tail for the LDC msg */
33741991Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
33751991Sheppo 	if (rv) {
33763010Slm66018 		D1(ldcp->id, "ldc_up: (0x%llx) cannot initiate handshake\n",
33771991Sheppo 		    ldcp->id);
33782336Snarayan 		mutex_exit(&ldcp->tx_lock);
33791991Sheppo 		mutex_exit(&ldcp->lock);
33801991Sheppo 		return (ECONNREFUSED);
33811991Sheppo 	}
33821991Sheppo 
33833808Ssb155480 	/*
33843808Ssb155480 	 * If i_ldc_get_tx_tail() changed link_state to either RESET or UP,
33853808Ssb155480 	 * from a previous state of DOWN, then mark the channel as
33863808Ssb155480 	 * being ready for handshake.
33873808Ssb155480 	 */
33883808Ssb155480 	if ((link_state == LDC_CHANNEL_DOWN) &&
33893808Ssb155480 	    (link_state != ldcp->link_state)) {
33903808Ssb155480 
33913808Ssb155480 		ASSERT((ldcp->link_state == LDC_CHANNEL_RESET) ||
33923808Ssb155480 		    (ldcp->link_state == LDC_CHANNEL_UP));
33933808Ssb155480 
33943808Ssb155480 		if (ldcp->mode == LDC_MODE_RAW) {
33953808Ssb155480 			ldcp->status = LDC_UP;
33963808Ssb155480 			ldcp->tstate = TS_UP;
33973808Ssb155480 			mutex_exit(&ldcp->tx_lock);
33983808Ssb155480 			mutex_exit(&ldcp->lock);
33993808Ssb155480 			return (0);
34003808Ssb155480 		} else {
34013808Ssb155480 			ldcp->status = LDC_READY;
34023808Ssb155480 			ldcp->tstate |= TS_LINK_READY;
34033808Ssb155480 		}
34043808Ssb155480 
34053808Ssb155480 	}
34063808Ssb155480 
34071991Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
34081991Sheppo 	ZERO_PKT(ldcmsg);
34091991Sheppo 
34101991Sheppo 	ldcmsg->type = LDC_CTRL;
34111991Sheppo 	ldcmsg->stype = LDC_INFO;
34121991Sheppo 	ldcmsg->ctrl = LDC_VER;
34131991Sheppo 	ldcp->next_vidx = 0;
34141991Sheppo 	bcopy(&ldc_versions[0], ldcmsg->udata, sizeof (ldc_versions[0]));
34151991Sheppo 
34161991Sheppo 	DUMP_LDC_PKT(ldcp, "ldc_up snd ver", (uint64_t)ldcmsg);
34171991Sheppo 
34181991Sheppo 	/* initiate the send by calling into HV and set the new tail */
34191991Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
34204690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
34211991Sheppo 
34221991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
34231991Sheppo 	if (rv) {
34241991Sheppo 		DWARN(ldcp->id,
34251991Sheppo 		    "ldc_up: (0x%llx) cannot initiate handshake rv=%d\n",
34261991Sheppo 		    ldcp->id, rv);
34272336Snarayan 		mutex_exit(&ldcp->tx_lock);
34281991Sheppo 		mutex_exit(&ldcp->lock);
34291991Sheppo 		return (rv);
34301991Sheppo 	}
34311991Sheppo 
34322032Slm66018 	ldcp->hstate |= TS_SENT_VER;
34331991Sheppo 	ldcp->tx_tail = tx_tail;
34341991Sheppo 	D1(ldcp->id, "ldc_up: (0x%llx) channel up initiated\n", ldcp->id);
34351991Sheppo 
34362336Snarayan 	mutex_exit(&ldcp->tx_lock);
34371991Sheppo 	mutex_exit(&ldcp->lock);
34381991Sheppo 
34391991Sheppo 	return (rv);
34401991Sheppo }
34411991Sheppo 
34421991Sheppo 
34431991Sheppo /*
34442410Slm66018  * Bring a channel down by resetting its state and queues
34451991Sheppo  */
34461991Sheppo int
34472410Slm66018 ldc_down(ldc_handle_t handle)
34481991Sheppo {
34491991Sheppo 	ldc_chan_t 	*ldcp;
34501991Sheppo 
34511991Sheppo 	if (handle == NULL) {
34522410Slm66018 		DWARN(DBG_ALL_LDCS, "ldc_down: invalid channel handle\n");
34531991Sheppo 		return (EINVAL);
34541991Sheppo 	}
34551991Sheppo 	ldcp = (ldc_chan_t *)handle;
34561991Sheppo 	mutex_enter(&ldcp->lock);
34572336Snarayan 	mutex_enter(&ldcp->tx_lock);
34582793Slm66018 	i_ldc_reset(ldcp, B_TRUE);
34592336Snarayan 	mutex_exit(&ldcp->tx_lock);
34601991Sheppo 	mutex_exit(&ldcp->lock);
34611991Sheppo 
34621991Sheppo 	return (0);
34631991Sheppo }
34641991Sheppo 
34651991Sheppo /*
34661991Sheppo  * Get the current channel status
34671991Sheppo  */
34681991Sheppo int
34691991Sheppo ldc_status(ldc_handle_t handle, ldc_status_t *status)
34701991Sheppo {
34711991Sheppo 	ldc_chan_t *ldcp;
34721991Sheppo 
34731991Sheppo 	if (handle == NULL || status == NULL) {
34741991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_status: invalid argument\n");
34751991Sheppo 		return (EINVAL);
34761991Sheppo 	}
34771991Sheppo 	ldcp = (ldc_chan_t *)handle;
34781991Sheppo 
34791991Sheppo 	*status = ((ldc_chan_t *)handle)->status;
34801991Sheppo 
34813010Slm66018 	D1(ldcp->id,
34821991Sheppo 	    "ldc_status: (0x%llx) returned status %d\n", ldcp->id, *status);
34831991Sheppo 	return (0);
34841991Sheppo }
34851991Sheppo 
34861991Sheppo 
34871991Sheppo /*
34881991Sheppo  * Set the channel's callback mode - enable/disable callbacks
34891991Sheppo  */
34901991Sheppo int
34911991Sheppo ldc_set_cb_mode(ldc_handle_t handle, ldc_cb_mode_t cmode)
34921991Sheppo {
34931991Sheppo 	ldc_chan_t 	*ldcp;
34941991Sheppo 
34951991Sheppo 	if (handle == NULL) {
34961991Sheppo 		DWARN(DBG_ALL_LDCS,
34971991Sheppo 		    "ldc_set_intr_mode: invalid channel handle\n");
34981991Sheppo 		return (EINVAL);
34991991Sheppo 	}
35001991Sheppo 	ldcp = (ldc_chan_t *)handle;
35011991Sheppo 
35021991Sheppo 	/*
35031991Sheppo 	 * Record no callbacks should be invoked
35041991Sheppo 	 */
35051991Sheppo 	mutex_enter(&ldcp->lock);
35061991Sheppo 
35071991Sheppo 	switch (cmode) {
35081991Sheppo 	case LDC_CB_DISABLE:
35091991Sheppo 		if (!ldcp->cb_enabled) {
35101991Sheppo 			DWARN(ldcp->id,
35111991Sheppo 			    "ldc_set_cb_mode: (0x%llx) callbacks disabled\n",
35121991Sheppo 			    ldcp->id);
35131991Sheppo 			break;
35141991Sheppo 		}
35151991Sheppo 		ldcp->cb_enabled = B_FALSE;
35161991Sheppo 
35171991Sheppo 		D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) disabled callbacks\n",
35181991Sheppo 		    ldcp->id);
35191991Sheppo 		break;
35201991Sheppo 
35211991Sheppo 	case LDC_CB_ENABLE:
35221991Sheppo 		if (ldcp->cb_enabled) {
35231991Sheppo 			DWARN(ldcp->id,
35241991Sheppo 			    "ldc_set_cb_mode: (0x%llx) callbacks enabled\n",
35251991Sheppo 			    ldcp->id);
35261991Sheppo 			break;
35271991Sheppo 		}
35281991Sheppo 		ldcp->cb_enabled = B_TRUE;
35291991Sheppo 
35301991Sheppo 		D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) enabled callbacks\n",
35311991Sheppo 		    ldcp->id);
35321991Sheppo 		break;
35331991Sheppo 	}
35341991Sheppo 
35351991Sheppo 	mutex_exit(&ldcp->lock);
35361991Sheppo 
35371991Sheppo 	return (0);
35381991Sheppo }
35391991Sheppo 
35401991Sheppo /*
35411991Sheppo  * Check to see if there are packets on the incoming queue
35422410Slm66018  * Will return hasdata = B_FALSE if there are no packets
35431991Sheppo  */
35441991Sheppo int
35452410Slm66018 ldc_chkq(ldc_handle_t handle, boolean_t *hasdata)
35461991Sheppo {
35471991Sheppo 	int 		rv;
35481991Sheppo 	uint64_t 	rx_head, rx_tail;
35491991Sheppo 	ldc_chan_t 	*ldcp;
35501991Sheppo 
35511991Sheppo 	if (handle == NULL) {
35521991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_chkq: invalid channel handle\n");
35531991Sheppo 		return (EINVAL);
35541991Sheppo 	}
35551991Sheppo 	ldcp = (ldc_chan_t *)handle;
35561991Sheppo 
35572410Slm66018 	*hasdata = B_FALSE;
35581991Sheppo 
35591991Sheppo 	mutex_enter(&ldcp->lock);
35601991Sheppo 
35611991Sheppo 	if (ldcp->tstate != TS_UP) {
35621991Sheppo 		D1(ldcp->id,
35631991Sheppo 		    "ldc_chkq: (0x%llx) channel is not up\n", ldcp->id);
35641991Sheppo 		mutex_exit(&ldcp->lock);
35651991Sheppo 		return (ECONNRESET);
35661991Sheppo 	}
35671991Sheppo 
35681991Sheppo 	/* Read packet(s) from the queue */
35691991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
35701991Sheppo 	    &ldcp->link_state);
35711991Sheppo 	if (rv != 0) {
35721991Sheppo 		cmn_err(CE_WARN,
35731991Sheppo 		    "ldc_chkq: (0x%lx) unable to read queue ptrs", ldcp->id);
35741991Sheppo 		mutex_exit(&ldcp->lock);
35751991Sheppo 		return (EIO);
35761991Sheppo 	}
3577*5944Sha137994 
35781991Sheppo 	/* reset the channel state if the channel went down */
35791991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
35801991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
35812336Snarayan 		mutex_enter(&ldcp->tx_lock);
35822793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
35832336Snarayan 		mutex_exit(&ldcp->tx_lock);
35841991Sheppo 		mutex_exit(&ldcp->lock);
35851991Sheppo 		return (ECONNRESET);
35861991Sheppo 	}
35871991Sheppo 
3588*5944Sha137994 	switch (ldcp->mode) {
3589*5944Sha137994 	case LDC_MODE_RAW:
3590*5944Sha137994 		/*
3591*5944Sha137994 		 * In raw mode, there are no ctrl packets, so checking
3592*5944Sha137994 		 * if the queue is non-empty is sufficient.
3593*5944Sha137994 		 */
3594*5944Sha137994 		*hasdata = (rx_head != rx_tail);
3595*5944Sha137994 		break;
3596*5944Sha137994 
3597*5944Sha137994 	case LDC_MODE_UNRELIABLE:
3598*5944Sha137994 		/*
3599*5944Sha137994 		 * In unreliable mode, if the queue is non-empty, we need
3600*5944Sha137994 		 * to check if it actually contains unread data packets.
3601*5944Sha137994 		 * The queue may just contain ctrl packets.
3602*5944Sha137994 		 */
3603*5944Sha137994 		if (rx_head != rx_tail)
3604*5944Sha137994 			*hasdata = (i_ldc_chkq(ldcp) == 0);
3605*5944Sha137994 		break;
3606*5944Sha137994 
3607*5944Sha137994 	case LDC_MODE_STREAM:
3608*5944Sha137994 		/*
3609*5944Sha137994 		 * In stream mode, first check for 'stream_remains' > 0.
3610*5944Sha137994 		 * Otherwise, if the data queue head and tail pointers
3611*5944Sha137994 		 * differ, there must be data to read.
3612*5944Sha137994 		 */
3613*5944Sha137994 		if (ldcp->stream_remains > 0)
3614*5944Sha137994 			*hasdata = B_TRUE;
3615*5944Sha137994 		else
3616*5944Sha137994 			*hasdata = (ldcp->rx_dq_head != ldcp->rx_dq_tail);
3617*5944Sha137994 		break;
3618*5944Sha137994 
3619*5944Sha137994 	default:
3620*5944Sha137994 		cmn_err(CE_WARN, "ldc_chkq: (0x%lx) unexpected channel mode "
3621*5944Sha137994 		    "(0x%x)", ldcp->id, ldcp->mode);
3622*5944Sha137994 		mutex_exit(&ldcp->lock);
3623*5944Sha137994 		return (EIO);
36241991Sheppo 	}
36251991Sheppo 
36261991Sheppo 	mutex_exit(&ldcp->lock);
36271991Sheppo 
36281991Sheppo 	return (0);
36291991Sheppo }
36301991Sheppo 
36311991Sheppo 
36321991Sheppo /*
36331991Sheppo  * Read 'size' amount of bytes or less. If incoming buffer
36341991Sheppo  * is more than 'size', ENOBUFS is returned.
36351991Sheppo  *
36361991Sheppo  * On return, size contains the number of bytes read.
36371991Sheppo  */
36381991Sheppo int
36391991Sheppo ldc_read(ldc_handle_t handle, caddr_t bufp, size_t *sizep)
36401991Sheppo {
36411991Sheppo 	ldc_chan_t 	*ldcp;
36421991Sheppo 	uint64_t 	rx_head = 0, rx_tail = 0;
36431991Sheppo 	int		rv = 0, exit_val;
36441991Sheppo 
36451991Sheppo 	if (handle == NULL) {
36461991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_read: invalid channel handle\n");
36471991Sheppo 		return (EINVAL);
36481991Sheppo 	}
36491991Sheppo 
36501991Sheppo 	ldcp = (ldc_chan_t *)handle;
36511991Sheppo 
36521991Sheppo 	/* channel lock */
36531991Sheppo 	mutex_enter(&ldcp->lock);
36541991Sheppo 
36551991Sheppo 	if (ldcp->tstate != TS_UP) {
36561991Sheppo 		DWARN(ldcp->id,
36571991Sheppo 		    "ldc_read: (0x%llx) channel is not in UP state\n",
36581991Sheppo 		    ldcp->id);
36591991Sheppo 		exit_val = ECONNRESET;
3660*5944Sha137994 	} else if (ldcp->mode == LDC_MODE_STREAM) {
3661*5944Sha137994 		TRACE_RXDQ_LENGTH(ldcp);
3662*5944Sha137994 		exit_val = ldcp->read_p(ldcp, bufp, sizep);
3663*5944Sha137994 		mutex_exit(&ldcp->lock);
3664*5944Sha137994 		return (exit_val);
36651991Sheppo 	} else {
36661991Sheppo 		exit_val = ldcp->read_p(ldcp, bufp, sizep);
36671991Sheppo 	}
36681991Sheppo 
36691991Sheppo 	/*
36701991Sheppo 	 * if queue has been drained - clear interrupt
36711991Sheppo 	 */
36721991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
36731991Sheppo 	    &ldcp->link_state);
36743010Slm66018 	if (rv != 0) {
36753010Slm66018 		cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
36763010Slm66018 		    ldcp->id);
36773010Slm66018 		mutex_enter(&ldcp->tx_lock);
36783010Slm66018 		i_ldc_reset(ldcp, B_TRUE);
36793010Slm66018 		mutex_exit(&ldcp->tx_lock);
36803653Snarayan 		mutex_exit(&ldcp->lock);
36813010Slm66018 		return (ECONNRESET);
36823010Slm66018 	}
36832793Slm66018 
36842793Slm66018 	if (exit_val == 0) {
36852793Slm66018 		if (ldcp->link_state == LDC_CHANNEL_DOWN ||
36862793Slm66018 		    ldcp->link_state == LDC_CHANNEL_RESET) {
36872793Slm66018 			mutex_enter(&ldcp->tx_lock);
36882793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
36892793Slm66018 			exit_val = ECONNRESET;
36902793Slm66018 			mutex_exit(&ldcp->tx_lock);
36912793Slm66018 		}
36922793Slm66018 		if ((rv == 0) &&
36932793Slm66018 		    (ldcp->rx_intr_state == LDC_INTR_PEND) &&
36942793Slm66018 		    (rx_head == rx_tail)) {
36952793Slm66018 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
36962793Slm66018 		}
36971991Sheppo 	}
36981991Sheppo 
36991991Sheppo 	mutex_exit(&ldcp->lock);
37001991Sheppo 	return (exit_val);
37011991Sheppo }
37021991Sheppo 
37031991Sheppo /*
37041991Sheppo  * Basic raw mondo read -
37051991Sheppo  * no interpretation of mondo contents at all.
37061991Sheppo  *
37071991Sheppo  * Enter and exit with ldcp->lock held by caller
37081991Sheppo  */
37091991Sheppo static int
37101991Sheppo i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
37111991Sheppo {
37121991Sheppo 	uint64_t 	q_size_mask;
37131991Sheppo 	ldc_msg_t 	*msgp;
37141991Sheppo 	uint8_t		*msgbufp;
37151991Sheppo 	int		rv = 0, space;
37161991Sheppo 	uint64_t 	rx_head, rx_tail;
37171991Sheppo 
37181991Sheppo 	space = *sizep;
37191991Sheppo 
37201991Sheppo 	if (space < LDC_PAYLOAD_SIZE_RAW)
37211991Sheppo 		return (ENOBUFS);
37221991Sheppo 
37231991Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
37241991Sheppo 
37251991Sheppo 	/* compute mask for increment */
37261991Sheppo 	q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
37271991Sheppo 
37281991Sheppo 	/*
37291991Sheppo 	 * Read packet(s) from the queue
37301991Sheppo 	 */
37311991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
37321991Sheppo 	    &ldcp->link_state);
37331991Sheppo 	if (rv != 0) {
37341991Sheppo 		cmn_err(CE_WARN,
37351991Sheppo 		    "ldc_read_raw: (0x%lx) unable to read queue ptrs",
37361991Sheppo 		    ldcp->id);
37371991Sheppo 		return (EIO);
37381991Sheppo 	}
37391991Sheppo 	D1(ldcp->id, "ldc_read_raw: (0x%llx) rxh=0x%llx,"
37404690Snarayan 	    " rxt=0x%llx, st=0x%llx\n",
37414690Snarayan 	    ldcp->id, rx_head, rx_tail, ldcp->link_state);
37421991Sheppo 
37431991Sheppo 	/* reset the channel state if the channel went down */
37442793Slm66018 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
37452793Slm66018 	    ldcp->link_state == LDC_CHANNEL_RESET) {
37462336Snarayan 		mutex_enter(&ldcp->tx_lock);
37472793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
37482336Snarayan 		mutex_exit(&ldcp->tx_lock);
37491991Sheppo 		return (ECONNRESET);
37501991Sheppo 	}
37511991Sheppo 
37521991Sheppo 	/*
37531991Sheppo 	 * Check for empty queue
37541991Sheppo 	 */
37551991Sheppo 	if (rx_head == rx_tail) {
37561991Sheppo 		*sizep = 0;
37571991Sheppo 		return (0);
37581991Sheppo 	}
37591991Sheppo 
37601991Sheppo 	/* get the message */
37611991Sheppo 	msgp = (ldc_msg_t *)(ldcp->rx_q_va + rx_head);
37621991Sheppo 
37631991Sheppo 	/* if channel is in RAW mode, copy data and return */
37641991Sheppo 	msgbufp = (uint8_t *)&(msgp->raw[0]);
37651991Sheppo 
37661991Sheppo 	bcopy(msgbufp, target_bufp, LDC_PAYLOAD_SIZE_RAW);
37671991Sheppo 
37681991Sheppo 	DUMP_PAYLOAD(ldcp->id, msgbufp);
37691991Sheppo 
37701991Sheppo 	*sizep = LDC_PAYLOAD_SIZE_RAW;
37711991Sheppo 
37721991Sheppo 	rx_head = (rx_head + LDC_PACKET_SIZE) & q_size_mask;
37732032Slm66018 	rv = i_ldc_set_rx_head(ldcp, rx_head);
37741991Sheppo 
37751991Sheppo 	return (rv);
37761991Sheppo }
37771991Sheppo 
37781991Sheppo /*
37791991Sheppo  * Process LDC mondos to build larger packets
37801991Sheppo  * with either un-reliable or reliable delivery.
37811991Sheppo  *
37821991Sheppo  * Enter and exit with ldcp->lock held by caller
37831991Sheppo  */
37841991Sheppo static int
37851991Sheppo i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
37861991Sheppo {
37871991Sheppo 	int		rv = 0;
37881991Sheppo 	uint64_t 	rx_head = 0, rx_tail = 0;
37891991Sheppo 	uint64_t 	curr_head = 0;
37901991Sheppo 	ldc_msg_t 	*msg;
37911991Sheppo 	caddr_t 	target;
37921991Sheppo 	size_t 		len = 0, bytes_read = 0;
37932032Slm66018 	int 		retries = 0;
3794*5944Sha137994 	uint64_t 	q_va, q_size_mask;
37952336Snarayan 	uint64_t	first_fragment = 0;
37961991Sheppo 
37971991Sheppo 	target = target_bufp;
37981991Sheppo 
37991991Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
38001991Sheppo 
38012793Slm66018 	/* check if the buffer and size are valid */
38022793Slm66018 	if (target_bufp == NULL || *sizep == 0) {
38032793Slm66018 		DWARN(ldcp->id, "ldc_read: (0x%llx) invalid buffer/size\n",
38042793Slm66018 		    ldcp->id);
38052793Slm66018 		return (EINVAL);
38062793Slm66018 	}
38072793Slm66018 
3808*5944Sha137994 	/* Set q_va and compute increment mask for the appropriate queue */
3809*5944Sha137994 	if (ldcp->mode == LDC_MODE_STREAM) {
3810*5944Sha137994 		q_va	    = ldcp->rx_dq_va;
3811*5944Sha137994 		q_size_mask = (ldcp->rx_dq_entries-1)<<LDC_PACKET_SHIFT;
3812*5944Sha137994 	} else {
3813*5944Sha137994 		q_va	    = ldcp->rx_q_va;
3814*5944Sha137994 		q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
3815*5944Sha137994 	}
38161991Sheppo 
38171991Sheppo 	/*
38181991Sheppo 	 * Read packet(s) from the queue
38191991Sheppo 	 */
3820*5944Sha137994 	rv = ldcp->readq_get_state(ldcp, &curr_head, &rx_tail,
38211991Sheppo 	    &ldcp->link_state);
38221991Sheppo 	if (rv != 0) {
38232793Slm66018 		cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
38241991Sheppo 		    ldcp->id);
38252793Slm66018 		mutex_enter(&ldcp->tx_lock);
38262793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
38272793Slm66018 		mutex_exit(&ldcp->tx_lock);
38282793Slm66018 		return (ECONNRESET);
38291991Sheppo 	}
38301991Sheppo 	D1(ldcp->id, "ldc_read: (0x%llx) chd=0x%llx, tl=0x%llx, st=0x%llx\n",
38311991Sheppo 	    ldcp->id, curr_head, rx_tail, ldcp->link_state);
38321991Sheppo 
38331991Sheppo 	/* reset the channel state if the channel went down */
38342793Slm66018 	if (ldcp->link_state != LDC_CHANNEL_UP)
38352793Slm66018 		goto channel_is_reset;
38361991Sheppo 
38371991Sheppo 	for (;;) {
38381991Sheppo 
38391991Sheppo 		if (curr_head == rx_tail) {
3840*5944Sha137994 			/*
3841*5944Sha137994 			 * If a data queue is being used, check the Rx HV
3842*5944Sha137994 			 * queue. This will copy over any new data packets
3843*5944Sha137994 			 * that have arrived.
3844*5944Sha137994 			 */
3845*5944Sha137994 			if (ldcp->mode == LDC_MODE_STREAM)
3846*5944Sha137994 				(void) i_ldc_chkq(ldcp);
3847*5944Sha137994 
3848*5944Sha137994 			rv = ldcp->readq_get_state(ldcp,
38491991Sheppo 			    &rx_head, &rx_tail, &ldcp->link_state);
38501991Sheppo 			if (rv != 0) {
38511991Sheppo 				cmn_err(CE_WARN,
38521991Sheppo 				    "ldc_read: (0x%lx) cannot read queue ptrs",
38531991Sheppo 				    ldcp->id);
38542336Snarayan 				mutex_enter(&ldcp->tx_lock);
38552793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
38562336Snarayan 				mutex_exit(&ldcp->tx_lock);
38571991Sheppo 				return (ECONNRESET);
38581991Sheppo 			}
3859*5944Sha137994 
38602793Slm66018 			if (ldcp->link_state != LDC_CHANNEL_UP)
38612793Slm66018 				goto channel_is_reset;
38622793Slm66018 
38632793Slm66018 			if (curr_head == rx_tail) {
38642793Slm66018 
38652793Slm66018 				/* If in the middle of a fragmented xfer */
38662793Slm66018 				if (first_fragment != 0) {
38672793Slm66018 
38682793Slm66018 					/* wait for ldc_delay usecs */
38692793Slm66018 					drv_usecwait(ldc_delay);
38702793Slm66018 
38712793Slm66018 					if (++retries < ldc_max_retries)
38722793Slm66018 						continue;
38732793Slm66018 
38742793Slm66018 					*sizep = 0;
3875*5944Sha137994 					if (ldcp->mode != LDC_MODE_STREAM)
3876*5944Sha137994 						ldcp->last_msg_rcd =
3877*5944Sha137994 						    first_fragment - 1;
38782793Slm66018 					DWARN(DBG_ALL_LDCS, "ldc_read: "
38794690Snarayan 					    "(0x%llx) read timeout", ldcp->id);
38802793Slm66018 					return (EAGAIN);
38812793Slm66018 				}
38822032Slm66018 				*sizep = 0;
38832793Slm66018 				break;
38841991Sheppo 			}
38851991Sheppo 		}
38862032Slm66018 		retries = 0;
38871991Sheppo 
38881991Sheppo 		D2(ldcp->id,
38891991Sheppo 		    "ldc_read: (0x%llx) chd=0x%llx, rxhd=0x%llx, rxtl=0x%llx\n",
38901991Sheppo 		    ldcp->id, curr_head, rx_head, rx_tail);
38911991Sheppo 
38921991Sheppo 		/* get the message */
3893*5944Sha137994 		msg = (ldc_msg_t *)(q_va + curr_head);
38941991Sheppo 
38951991Sheppo 		DUMP_LDC_PKT(ldcp, "ldc_read received pkt",
38961991Sheppo 		    ldcp->rx_q_va + curr_head);
38971991Sheppo 
38981991Sheppo 		/* Check the message ID for the message received */
3899*5944Sha137994 		if (ldcp->mode != LDC_MODE_STREAM) {
3900*5944Sha137994 			if ((rv = i_ldc_check_seqid(ldcp, msg)) != 0) {
3901*5944Sha137994 
3902*5944Sha137994 				DWARN(ldcp->id, "ldc_read: (0x%llx) seqid "
3903*5944Sha137994 				    "error, q_ptrs=0x%lx,0x%lx",
3904*5944Sha137994 				    ldcp->id, rx_head, rx_tail);
3905*5944Sha137994 
3906*5944Sha137994 				/* throw away data */
3907*5944Sha137994 				bytes_read = 0;
3908*5944Sha137994 
3909*5944Sha137994 				/* Reset last_msg_rcd to start of message */
3910*5944Sha137994 				if (first_fragment != 0) {
3911*5944Sha137994 					ldcp->last_msg_rcd = first_fragment - 1;
3912*5944Sha137994 					first_fragment = 0;
3913*5944Sha137994 				}
3914*5944Sha137994 				/*
3915*5944Sha137994 				 * Send a NACK -- invalid seqid
3916*5944Sha137994 				 * get the current tail for the response
3917*5944Sha137994 				 */
3918*5944Sha137994 				rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK,
3919*5944Sha137994 				    (msg->ctrl & LDC_CTRL_MASK));
3920*5944Sha137994 				if (rv) {
3921*5944Sha137994 					cmn_err(CE_NOTE,
3922*5944Sha137994 					    "ldc_read: (0x%lx) err sending "
3923*5944Sha137994 					    "NACK msg\n", ldcp->id);
3924*5944Sha137994 
3925*5944Sha137994 					/* if cannot send NACK - reset chan */
3926*5944Sha137994 					mutex_enter(&ldcp->tx_lock);
3927*5944Sha137994 					i_ldc_reset(ldcp, B_FALSE);
3928*5944Sha137994 					mutex_exit(&ldcp->tx_lock);
3929*5944Sha137994 					rv = ECONNRESET;
3930*5944Sha137994 					break;
3931*5944Sha137994 				}
3932*5944Sha137994 
3933*5944Sha137994 				/* purge receive queue */
3934*5944Sha137994 				rv = i_ldc_set_rx_head(ldcp, rx_tail);
3935*5944Sha137994 
39362336Snarayan 				break;
39371991Sheppo 			}
39381991Sheppo 
3939*5944Sha137994 			/*
3940*5944Sha137994 			 * Process any messages of type CTRL messages
3941*5944Sha137994 			 * Future implementations should try to pass these
3942*5944Sha137994 			 * to LDC link by resetting the intr state.
3943*5944Sha137994 			 *
3944*5944Sha137994 			 * NOTE: not done as a switch() as type can be
3945*5944Sha137994 			 * both ctrl+data
3946*5944Sha137994 			 */
3947*5944Sha137994 			if (msg->type & LDC_CTRL) {
3948*5944Sha137994 				if (rv = i_ldc_ctrlmsg(ldcp, msg)) {
3949*5944Sha137994 					if (rv == EAGAIN)
3950*5944Sha137994 						continue;
3951*5944Sha137994 					rv = i_ldc_set_rx_head(ldcp, rx_tail);
3952*5944Sha137994 					*sizep = 0;
3953*5944Sha137994 					bytes_read = 0;
3954*5944Sha137994 					break;
3955*5944Sha137994 				}
39561991Sheppo 			}
3957*5944Sha137994 
3958*5944Sha137994 			/* process data ACKs */
3959*5944Sha137994 			if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
3960*5944Sha137994 				if (rv = i_ldc_process_data_ACK(ldcp, msg)) {
3961*5944Sha137994 					*sizep = 0;
3962*5944Sha137994 					bytes_read = 0;
3963*5944Sha137994 					break;
3964*5944Sha137994 				}
39652336Snarayan 			}
3966*5944Sha137994 
3967*5944Sha137994 			/* process data NACKs */
3968*5944Sha137994 			if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) {
3969*5944Sha137994 				DWARN(ldcp->id,
3970*5944Sha137994 				    "ldc_read: (0x%llx) received DATA/NACK",
3971*5944Sha137994 				    ldcp->id);
3972*5944Sha137994 				mutex_enter(&ldcp->tx_lock);
3973*5944Sha137994 				i_ldc_reset(ldcp, B_TRUE);
3974*5944Sha137994 				mutex_exit(&ldcp->tx_lock);
3975*5944Sha137994 				return (ECONNRESET);
3976*5944Sha137994 			}
39773560Snarayan 		}
39783560Snarayan 
39791991Sheppo 		/* process data messages */
39801991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
39811991Sheppo 
39821991Sheppo 			uint8_t *msgbuf = (uint8_t *)(
39834690Snarayan 			    (ldcp->mode == LDC_MODE_RELIABLE ||
39844690Snarayan 			    ldcp->mode == LDC_MODE_STREAM) ?
39854690Snarayan 			    msg->rdata : msg->udata);
39861991Sheppo 
39871991Sheppo 			D2(ldcp->id,
39881991Sheppo 			    "ldc_read: (0x%llx) received data msg\n", ldcp->id);
39891991Sheppo 
39901991Sheppo 			/* get the packet length */
39911991Sheppo 			len = (msg->env & LDC_LEN_MASK);
39921991Sheppo 
39931991Sheppo 				/*
39941991Sheppo 				 * FUTURE OPTIMIZATION:
39951991Sheppo 				 * dont need to set q head for every
39961991Sheppo 				 * packet we read just need to do this when
39971991Sheppo 				 * we are done or need to wait for more
39981991Sheppo 				 * mondos to make a full packet - this is
39991991Sheppo 				 * currently expensive.
40001991Sheppo 				 */
40011991Sheppo 
40022336Snarayan 			if (first_fragment == 0) {
40031991Sheppo 
40041991Sheppo 				/*
40051991Sheppo 				 * first packets should always have the start
40061991Sheppo 				 * bit set (even for a single packet). If not
40071991Sheppo 				 * throw away the packet
40081991Sheppo 				 */
40091991Sheppo 				if (!(msg->env & LDC_FRAG_START)) {
40101991Sheppo 
40111991Sheppo 					DWARN(DBG_ALL_LDCS,
40121991Sheppo 					    "ldc_read: (0x%llx) not start - "
40131991Sheppo 					    "frag=%x\n", ldcp->id,
40141991Sheppo 					    (msg->env) & LDC_FRAG_MASK);
40151991Sheppo 
40161991Sheppo 					/* toss pkt, inc head, cont reading */
40171991Sheppo 					bytes_read = 0;
40181991Sheppo 					target = target_bufp;
40191991Sheppo 					curr_head =
40204690Snarayan 					    (curr_head + LDC_PACKET_SIZE)
40214690Snarayan 					    & q_size_mask;
4022*5944Sha137994 					if (rv = ldcp->readq_set_head(ldcp,
40234690Snarayan 					    curr_head))
40241991Sheppo 						break;
40251991Sheppo 
40261991Sheppo 					continue;
40271991Sheppo 				}
40281991Sheppo 
40292336Snarayan 				first_fragment = msg->seqid;
40301991Sheppo 			} else {
40311991Sheppo 				/* check to see if this is a pkt w/ START bit */
40321991Sheppo 				if (msg->env & LDC_FRAG_START) {
40331991Sheppo 					DWARN(DBG_ALL_LDCS,
40341991Sheppo 					    "ldc_read:(0x%llx) unexpected pkt"
40351991Sheppo 					    " env=0x%x discarding %d bytes,"
40361991Sheppo 					    " lastmsg=%d, currentmsg=%d\n",
40371991Sheppo 					    ldcp->id, msg->env&LDC_FRAG_MASK,
40381991Sheppo 					    bytes_read, ldcp->last_msg_rcd,
40391991Sheppo 					    msg->seqid);
40401991Sheppo 
40411991Sheppo 					/* throw data we have read so far */
40421991Sheppo 					bytes_read = 0;
40431991Sheppo 					target = target_bufp;
40442336Snarayan 					first_fragment = msg->seqid;
40451991Sheppo 
4046*5944Sha137994 					if (rv = ldcp->readq_set_head(ldcp,
40474690Snarayan 					    curr_head))
40481991Sheppo 						break;
40491991Sheppo 				}
40501991Sheppo 			}
40511991Sheppo 
40521991Sheppo 			/* copy (next) pkt into buffer */
40531991Sheppo 			if (len <= (*sizep - bytes_read)) {
40541991Sheppo 				bcopy(msgbuf, target, len);
40551991Sheppo 				target += len;
40561991Sheppo 				bytes_read += len;
40571991Sheppo 			} else {
40581991Sheppo 				/*
40591991Sheppo 				 * there is not enough space in the buffer to
40601991Sheppo 				 * read this pkt. throw message away & continue
40611991Sheppo 				 * reading data from queue
40621991Sheppo 				 */
40631991Sheppo 				DWARN(DBG_ALL_LDCS,
40641991Sheppo 				    "ldc_read: (0x%llx) buffer too small, "
40651991Sheppo 				    "head=0x%lx, expect=%d, got=%d\n", ldcp->id,
40661991Sheppo 				    curr_head, *sizep, bytes_read+len);
40671991Sheppo 
40682336Snarayan 				first_fragment = 0;
40691991Sheppo 				target = target_bufp;
40701991Sheppo 				bytes_read = 0;
40711991Sheppo 
40721991Sheppo 				/* throw away everything received so far */
4073*5944Sha137994 				if (rv = ldcp->readq_set_head(ldcp, curr_head))
40741991Sheppo 					break;
40751991Sheppo 
40761991Sheppo 				/* continue reading remaining pkts */
40771991Sheppo 				continue;
40781991Sheppo 			}
40791991Sheppo 		}
40801991Sheppo 
40811991Sheppo 		/* set the message id */
4082*5944Sha137994 		if (ldcp->mode != LDC_MODE_STREAM)
4083*5944Sha137994 			ldcp->last_msg_rcd = msg->seqid;
40841991Sheppo 
40851991Sheppo 		/* move the head one position */
40861991Sheppo 		curr_head = (curr_head + LDC_PACKET_SIZE) & q_size_mask;
40871991Sheppo 
40881991Sheppo 		if (msg->env & LDC_FRAG_STOP) {
40891991Sheppo 
40901991Sheppo 			/*
40911991Sheppo 			 * All pkts that are part of this fragmented transfer
40921991Sheppo 			 * have been read or this was a single pkt read
40931991Sheppo 			 * or there was an error
40941991Sheppo 			 */
40951991Sheppo 
40961991Sheppo 			/* set the queue head */
4097*5944Sha137994 			if (rv = ldcp->readq_set_head(ldcp, curr_head))
40981991Sheppo 				bytes_read = 0;
40991991Sheppo 
41001991Sheppo 			*sizep = bytes_read;
41011991Sheppo 
41021991Sheppo 			break;
41031991Sheppo 		}
41041991Sheppo 
41054890Snarayan 		/* advance head if it is a CTRL packet or a DATA ACK packet */
41064890Snarayan 		if ((msg->type & LDC_CTRL) ||
41074890Snarayan 		    ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK))) {
41081991Sheppo 
41091991Sheppo 			/* set the queue head */
4110*5944Sha137994 			if (rv = ldcp->readq_set_head(ldcp, curr_head)) {
41111991Sheppo 				bytes_read = 0;
41121991Sheppo 				break;
41131991Sheppo 			}
41141991Sheppo 
41151991Sheppo 			D2(ldcp->id, "ldc_read: (0x%llx) set ACK qhead 0x%llx",
41161991Sheppo 			    ldcp->id, curr_head);
41171991Sheppo 		}
41181991Sheppo 
41191991Sheppo 	} /* for (;;) */
41201991Sheppo 
41211991Sheppo 	D2(ldcp->id, "ldc_read: (0x%llx) end size=%d", ldcp->id, *sizep);
41221991Sheppo 
41231991Sheppo 	return (rv);
41242793Slm66018 
41252793Slm66018 channel_is_reset:
41262793Slm66018 	mutex_enter(&ldcp->tx_lock);
41272793Slm66018 	i_ldc_reset(ldcp, B_FALSE);
41282793Slm66018 	mutex_exit(&ldcp->tx_lock);
41292793Slm66018 	return (ECONNRESET);
41301991Sheppo }
41311991Sheppo 
41321991Sheppo /*
41331991Sheppo  * Use underlying reliable packet mechanism to fetch
41341991Sheppo  * and buffer incoming packets so we can hand them back as
41351991Sheppo  * a basic byte stream.
41361991Sheppo  *
41371991Sheppo  * Enter and exit with ldcp->lock held by caller
41381991Sheppo  */
41391991Sheppo static int
41401991Sheppo i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
41411991Sheppo {
41421991Sheppo 	int	rv;
41431991Sheppo 	size_t	size;
41441991Sheppo 
41451991Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
41461991Sheppo 
41471991Sheppo 	D2(ldcp->id, "i_ldc_read_stream: (0x%llx) buffer size=%d",
41484690Snarayan 	    ldcp->id, *sizep);
41491991Sheppo 
41501991Sheppo 	if (ldcp->stream_remains == 0) {
41511991Sheppo 		size = ldcp->mtu;
41521991Sheppo 		rv = i_ldc_read_packet(ldcp,
41534690Snarayan 		    (caddr_t)ldcp->stream_bufferp, &size);
41541991Sheppo 		D2(ldcp->id, "i_ldc_read_stream: read packet (0x%llx) size=%d",
41554690Snarayan 		    ldcp->id, size);
41561991Sheppo 
41571991Sheppo 		if (rv != 0)
41581991Sheppo 			return (rv);
41591991Sheppo 
41601991Sheppo 		ldcp->stream_remains = size;
41611991Sheppo 		ldcp->stream_offset = 0;
41621991Sheppo 	}
41631991Sheppo 
41641991Sheppo 	size = MIN(ldcp->stream_remains, *sizep);
41651991Sheppo 
41661991Sheppo 	bcopy(ldcp->stream_bufferp + ldcp->stream_offset, target_bufp, size);
41671991Sheppo 	ldcp->stream_offset += size;
41681991Sheppo 	ldcp->stream_remains -= size;
41691991Sheppo 
41701991Sheppo 	D2(ldcp->id, "i_ldc_read_stream: (0x%llx) fill from buffer size=%d",
41714690Snarayan 	    ldcp->id, size);
41721991Sheppo 
41731991Sheppo 	*sizep = size;
41741991Sheppo 	return (0);
41751991Sheppo }
41761991Sheppo 
41771991Sheppo /*
41781991Sheppo  * Write specified amount of bytes to the channel
41791991Sheppo  * in multiple pkts of pkt_payload size. Each
41801991Sheppo  * packet is tagged with an unique packet ID in
41812410Slm66018  * the case of a reliable link.
41821991Sheppo  *
41831991Sheppo  * On return, size contains the number of bytes written.
41841991Sheppo  */
41851991Sheppo int
41861991Sheppo ldc_write(ldc_handle_t handle, caddr_t buf, size_t *sizep)
41871991Sheppo {
41881991Sheppo 	ldc_chan_t	*ldcp;
41891991Sheppo 	int		rv = 0;
41901991Sheppo 
41911991Sheppo 	if (handle == NULL) {
41921991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_write: invalid channel handle\n");
41931991Sheppo 		return (EINVAL);
41941991Sheppo 	}
41951991Sheppo 	ldcp = (ldc_chan_t *)handle;
41961991Sheppo 
41972336Snarayan 	/* check if writes can occur */
41982336Snarayan 	if (!mutex_tryenter(&ldcp->tx_lock)) {
41992336Snarayan 		/*
42002336Snarayan 		 * Could not get the lock - channel could
42012336Snarayan 		 * be in the process of being unconfigured
42022336Snarayan 		 * or reader has encountered an error
42032336Snarayan 		 */
42042336Snarayan 		return (EAGAIN);
42052336Snarayan 	}
42061991Sheppo 
42071991Sheppo 	/* check if non-zero data to write */
42081991Sheppo 	if (buf == NULL || sizep == NULL) {
42091991Sheppo 		DWARN(ldcp->id, "ldc_write: (0x%llx) invalid data write\n",
42101991Sheppo 		    ldcp->id);
42112336Snarayan 		mutex_exit(&ldcp->tx_lock);
42121991Sheppo 		return (EINVAL);
42131991Sheppo 	}
42141991Sheppo 
42151991Sheppo 	if (*sizep == 0) {
42161991Sheppo 		DWARN(ldcp->id, "ldc_write: (0x%llx) write size of zero\n",
42171991Sheppo 		    ldcp->id);
42182336Snarayan 		mutex_exit(&ldcp->tx_lock);
42191991Sheppo 		return (0);
42201991Sheppo 	}
42211991Sheppo 
42221991Sheppo 	/* Check if channel is UP for data exchange */
42231991Sheppo 	if (ldcp->tstate != TS_UP) {
42241991Sheppo 		DWARN(ldcp->id,
42251991Sheppo 		    "ldc_write: (0x%llx) channel is not in UP state\n",
42261991Sheppo 		    ldcp->id);
42271991Sheppo 		*sizep = 0;
42281991Sheppo 		rv = ECONNRESET;
42291991Sheppo 	} else {
42301991Sheppo 		rv = ldcp->write_p(ldcp, buf, sizep);
42311991Sheppo 	}
42321991Sheppo 
42332336Snarayan 	mutex_exit(&ldcp->tx_lock);
42341991Sheppo 
42351991Sheppo 	return (rv);
42361991Sheppo }
42371991Sheppo 
42381991Sheppo /*
42391991Sheppo  * Write a raw packet to the channel
42401991Sheppo  * On return, size contains the number of bytes written.
42411991Sheppo  */
42421991Sheppo static int
42431991Sheppo i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
42441991Sheppo {
42451991Sheppo 	ldc_msg_t 	*ldcmsg;
42461991Sheppo 	uint64_t 	tx_head, tx_tail, new_tail;
42471991Sheppo 	int		rv = 0;
42481991Sheppo 	size_t		size;
42491991Sheppo 
42502336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
42511991Sheppo 	ASSERT(ldcp->mode == LDC_MODE_RAW);
42521991Sheppo 
42531991Sheppo 	size = *sizep;
42541991Sheppo 
42551991Sheppo 	/*
42561991Sheppo 	 * Check to see if the packet size is less than or
42571991Sheppo 	 * equal to packet size support in raw mode
42581991Sheppo 	 */
42591991Sheppo 	if (size > ldcp->pkt_payload) {
42601991Sheppo 		DWARN(ldcp->id,
42611991Sheppo 		    "ldc_write: (0x%llx) invalid size (0x%llx) for RAW mode\n",
42621991Sheppo 		    ldcp->id, *sizep);
42631991Sheppo 		*sizep = 0;
42641991Sheppo 		return (EMSGSIZE);
42651991Sheppo 	}
42661991Sheppo 
42671991Sheppo 	/* get the qptrs for the tx queue */
42681991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
42691991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
42701991Sheppo 	if (rv != 0) {
42711991Sheppo 		cmn_err(CE_WARN,
42721991Sheppo 		    "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
42731991Sheppo 		*sizep = 0;
42741991Sheppo 		return (EIO);
42751991Sheppo 	}
42761991Sheppo 
42771991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
42781991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
42791991Sheppo 		DWARN(ldcp->id,
42801991Sheppo 		    "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
42812336Snarayan 
42821991Sheppo 		*sizep = 0;
42832336Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
42842793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
42852336Snarayan 			mutex_exit(&ldcp->lock);
42862336Snarayan 		} else {
42872336Snarayan 			/*
42882336Snarayan 			 * Release Tx lock, and then reacquire channel
42892336Snarayan 			 * and Tx lock in correct order
42902336Snarayan 			 */
42912336Snarayan 			mutex_exit(&ldcp->tx_lock);
42922336Snarayan 			mutex_enter(&ldcp->lock);
42932336Snarayan 			mutex_enter(&ldcp->tx_lock);
42942793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
42952336Snarayan 			mutex_exit(&ldcp->lock);
42962336Snarayan 		}
42971991Sheppo 		return (ECONNRESET);
42981991Sheppo 	}
42991991Sheppo 
43001991Sheppo 	tx_tail = ldcp->tx_tail;
43011991Sheppo 	tx_head = ldcp->tx_head;
43021991Sheppo 	new_tail = (tx_tail + LDC_PACKET_SIZE) &
43034690Snarayan 	    ((ldcp->tx_q_entries-1) << LDC_PACKET_SHIFT);
43041991Sheppo 
43051991Sheppo 	if (new_tail == tx_head) {
43061991Sheppo 		DWARN(DBG_ALL_LDCS,
43071991Sheppo 		    "ldc_write: (0x%llx) TX queue is full\n", ldcp->id);
43081991Sheppo 		*sizep = 0;
43091991Sheppo 		return (EWOULDBLOCK);
43101991Sheppo 	}
43111991Sheppo 
43121991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
43131991Sheppo 	    ldcp->id, size);
43141991Sheppo 
43151991Sheppo 	/* Send the data now */
43161991Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
43171991Sheppo 
43182336Snarayan 	/* copy the data into pkt */
43191991Sheppo 	bcopy((uint8_t *)buf, ldcmsg, size);
43201991Sheppo 
43212336Snarayan 	/* increment tail */
43221991Sheppo 	tx_tail = new_tail;
43231991Sheppo 
43241991Sheppo 	/*
43251991Sheppo 	 * All packets have been copied into the TX queue
43261991Sheppo 	 * update the tail ptr in the HV
43271991Sheppo 	 */
43281991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
43291991Sheppo 	if (rv) {
43301991Sheppo 		if (rv == EWOULDBLOCK) {
43311991Sheppo 			DWARN(ldcp->id, "ldc_write: (0x%llx) write timed out\n",
43321991Sheppo 			    ldcp->id);
43331991Sheppo 			*sizep = 0;
43341991Sheppo 			return (EWOULDBLOCK);
43351991Sheppo 		}
43361991Sheppo 
43371991Sheppo 		*sizep = 0;
43382336Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
43392793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
43402336Snarayan 			mutex_exit(&ldcp->lock);
43412336Snarayan 		} else {
43422336Snarayan 			/*
43432336Snarayan 			 * Release Tx lock, and then reacquire channel
43442336Snarayan 			 * and Tx lock in correct order
43452336Snarayan 			 */
43462336Snarayan 			mutex_exit(&ldcp->tx_lock);
43472336Snarayan 			mutex_enter(&ldcp->lock);
43482336Snarayan 			mutex_enter(&ldcp->tx_lock);
43492793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
43502336Snarayan 			mutex_exit(&ldcp->lock);
43512336Snarayan 		}
43521991Sheppo 		return (ECONNRESET);
43531991Sheppo 	}
43541991Sheppo 
43551991Sheppo 	ldcp->tx_tail = tx_tail;
43561991Sheppo 	*sizep = size;
43571991Sheppo 
43581991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, size);
43591991Sheppo 
43601991Sheppo 	return (rv);
43611991Sheppo }
43621991Sheppo 
43631991Sheppo 
43641991Sheppo /*
43651991Sheppo  * Write specified amount of bytes to the channel
43661991Sheppo  * in multiple pkts of pkt_payload size. Each
43671991Sheppo  * packet is tagged with an unique packet ID in
43682410Slm66018  * the case of a reliable link.
43691991Sheppo  *
43701991Sheppo  * On return, size contains the number of bytes written.
43711991Sheppo  * This function needs to ensure that the write size is < MTU size
43721991Sheppo  */
43731991Sheppo static int
43741991Sheppo i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t buf, size_t *size)
43751991Sheppo {
43761991Sheppo 	ldc_msg_t 	*ldcmsg;
43771991Sheppo 	uint64_t 	tx_head, tx_tail, new_tail, start;
43781991Sheppo 	uint64_t	txq_size_mask, numavail;
43791991Sheppo 	uint8_t 	*msgbuf, *source = (uint8_t *)buf;
43801991Sheppo 	size_t 		len, bytes_written = 0, remaining;
43811991Sheppo 	int		rv;
43821991Sheppo 	uint32_t	curr_seqid;
43831991Sheppo 
43842336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
43851991Sheppo 
43861991Sheppo 	ASSERT(ldcp->mode == LDC_MODE_RELIABLE ||
43874690Snarayan 	    ldcp->mode == LDC_MODE_UNRELIABLE ||
43884690Snarayan 	    ldcp->mode == LDC_MODE_STREAM);
43891991Sheppo 
43901991Sheppo 	/* compute mask for increment */
43911991Sheppo 	txq_size_mask = (ldcp->tx_q_entries - 1) << LDC_PACKET_SHIFT;
43921991Sheppo 
43931991Sheppo 	/* get the qptrs for the tx queue */
43941991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
43951991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
43961991Sheppo 	if (rv != 0) {
43971991Sheppo 		cmn_err(CE_WARN,
43981991Sheppo 		    "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
43991991Sheppo 		*size = 0;
44001991Sheppo 		return (EIO);
44011991Sheppo 	}
44021991Sheppo 
44031991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
44041991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
44051991Sheppo 		DWARN(ldcp->id,
44061991Sheppo 		    "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
44071991Sheppo 		*size = 0;
44082336Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
44092793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
44102336Snarayan 			mutex_exit(&ldcp->lock);
44112336Snarayan 		} else {
44122336Snarayan 			/*
44132336Snarayan 			 * Release Tx lock, and then reacquire channel
44142336Snarayan 			 * and Tx lock in correct order
44152336Snarayan 			 */
44162336Snarayan 			mutex_exit(&ldcp->tx_lock);
44172336Snarayan 			mutex_enter(&ldcp->lock);
44182336Snarayan 			mutex_enter(&ldcp->tx_lock);
44192793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
44202336Snarayan 			mutex_exit(&ldcp->lock);
44212336Snarayan 		}
44221991Sheppo 		return (ECONNRESET);
44231991Sheppo 	}
44241991Sheppo 
44251991Sheppo 	tx_tail = ldcp->tx_tail;
44261991Sheppo 	new_tail = (tx_tail + LDC_PACKET_SIZE) %
44274690Snarayan 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
44281991Sheppo 
44291991Sheppo 	/*
44304690Snarayan 	 * Check to see if the queue is full. The check is done using
44314690Snarayan 	 * the appropriate head based on the link mode.
44321991Sheppo 	 */
44334690Snarayan 	i_ldc_get_tx_head(ldcp, &tx_head);
44344690Snarayan 
44351991Sheppo 	if (new_tail == tx_head) {
44361991Sheppo 		DWARN(DBG_ALL_LDCS,
44371991Sheppo 		    "ldc_write: (0x%llx) TX queue is full\n", ldcp->id);
44381991Sheppo 		*size = 0;
44391991Sheppo 		return (EWOULDBLOCK);
44401991Sheppo 	}
44411991Sheppo 
44421991Sheppo 	/*
44431991Sheppo 	 * Make sure that the LDC Tx queue has enough space
44441991Sheppo 	 */
44451991Sheppo 	numavail = (tx_head >> LDC_PACKET_SHIFT) - (tx_tail >> LDC_PACKET_SHIFT)
44464690Snarayan 	    + ldcp->tx_q_entries - 1;
44471991Sheppo 	numavail %= ldcp->tx_q_entries;
44481991Sheppo 
44491991Sheppo 	if (*size > (numavail * ldcp->pkt_payload)) {
44501991Sheppo 		DWARN(DBG_ALL_LDCS,
44511991Sheppo 		    "ldc_write: (0x%llx) TX queue has no space\n", ldcp->id);
44521991Sheppo 		return (EWOULDBLOCK);
44531991Sheppo 	}
44541991Sheppo 
44551991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
44561991Sheppo 	    ldcp->id, *size);
44571991Sheppo 
44581991Sheppo 	/* Send the data now */
44591991Sheppo 	bytes_written = 0;
44601991Sheppo 	curr_seqid = ldcp->last_msg_snt;
44611991Sheppo 	start = tx_tail;
44621991Sheppo 
44631991Sheppo 	while (*size > bytes_written) {
44641991Sheppo 
44651991Sheppo 		ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
44661991Sheppo 
44671991Sheppo 		msgbuf = (uint8_t *)((ldcp->mode == LDC_MODE_RELIABLE ||
44684690Snarayan 		    ldcp->mode == LDC_MODE_STREAM) ?
44694690Snarayan 		    ldcmsg->rdata : ldcmsg->udata);
44701991Sheppo 
44711991Sheppo 		ldcmsg->type = LDC_DATA;
44721991Sheppo 		ldcmsg->stype = LDC_INFO;
44731991Sheppo 		ldcmsg->ctrl = 0;
44741991Sheppo 
44751991Sheppo 		remaining = *size - bytes_written;
44761991Sheppo 		len = min(ldcp->pkt_payload, remaining);
44771991Sheppo 		ldcmsg->env = (uint8_t)len;
44781991Sheppo 
44791991Sheppo 		curr_seqid++;
44801991Sheppo 		ldcmsg->seqid = curr_seqid;
44811991Sheppo 
44821991Sheppo 		/* copy the data into pkt */
44831991Sheppo 		bcopy(source, msgbuf, len);
44841991Sheppo 
44851991Sheppo 		source += len;
44861991Sheppo 		bytes_written += len;
44871991Sheppo 
44881991Sheppo 		/* increment tail */
44891991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) & txq_size_mask;
44901991Sheppo 
44911991Sheppo 		ASSERT(tx_tail != tx_head);
44921991Sheppo 	}
44931991Sheppo 
44941991Sheppo 	/* Set the start and stop bits */
44951991Sheppo 	ldcmsg->env |= LDC_FRAG_STOP;
44961991Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + start);
44971991Sheppo 	ldcmsg->env |= LDC_FRAG_START;
44981991Sheppo 
44991991Sheppo 	/*
45001991Sheppo 	 * All packets have been copied into the TX queue
45011991Sheppo 	 * update the tail ptr in the HV
45021991Sheppo 	 */
45031991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
45041991Sheppo 	if (rv == 0) {
45051991Sheppo 		ldcp->tx_tail = tx_tail;
45061991Sheppo 		ldcp->last_msg_snt = curr_seqid;
45071991Sheppo 		*size = bytes_written;
45081991Sheppo 	} else {
45091991Sheppo 		int rv2;
45101991Sheppo 
45111991Sheppo 		if (rv != EWOULDBLOCK) {
45121991Sheppo 			*size = 0;
45132336Snarayan 			if (mutex_tryenter(&ldcp->lock)) {
45142793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
45152336Snarayan 				mutex_exit(&ldcp->lock);
45162336Snarayan 			} else {
45172336Snarayan 				/*
45182336Snarayan 				 * Release Tx lock, and then reacquire channel
45192336Snarayan 				 * and Tx lock in correct order
45202336Snarayan 				 */
45212336Snarayan 				mutex_exit(&ldcp->tx_lock);
45222336Snarayan 				mutex_enter(&ldcp->lock);
45232336Snarayan 				mutex_enter(&ldcp->tx_lock);
45242793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
45252336Snarayan 				mutex_exit(&ldcp->lock);
45262336Snarayan 			}
45271991Sheppo 			return (ECONNRESET);
45281991Sheppo 		}
45291991Sheppo 
45303010Slm66018 		D1(ldcp->id, "hv_tx_set_tail returns 0x%x (head 0x%x, "
45314690Snarayan 		    "old tail 0x%x, new tail 0x%x, qsize=0x%x)\n",
45324690Snarayan 		    rv, ldcp->tx_head, ldcp->tx_tail, tx_tail,
45334690Snarayan 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
45341991Sheppo 
45351991Sheppo 		rv2 = hv_ldc_tx_get_state(ldcp->id,
45361991Sheppo 		    &tx_head, &tx_tail, &ldcp->link_state);
45371991Sheppo 
45383010Slm66018 		D1(ldcp->id, "hv_ldc_tx_get_state returns 0x%x "
45394690Snarayan 		    "(head 0x%x, tail 0x%x state 0x%x)\n",
45404690Snarayan 		    rv2, tx_head, tx_tail, ldcp->link_state);
45411991Sheppo 
45421991Sheppo 		*size = 0;
45431991Sheppo 	}
45441991Sheppo 
45451991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, *size);
45461991Sheppo 
45471991Sheppo 	return (rv);
45481991Sheppo }
45491991Sheppo 
45501991Sheppo /*
45511991Sheppo  * Write specified amount of bytes to the channel
45521991Sheppo  * in multiple pkts of pkt_payload size. Each
45531991Sheppo  * packet is tagged with an unique packet ID in
45542410Slm66018  * the case of a reliable link.
45551991Sheppo  *
45561991Sheppo  * On return, size contains the number of bytes written.
45571991Sheppo  * This function needs to ensure that the write size is < MTU size
45581991Sheppo  */
45591991Sheppo static int
45601991Sheppo i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
45611991Sheppo {
45622336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
45631991Sheppo 	ASSERT(ldcp->mode == LDC_MODE_STREAM);
45641991Sheppo 
45651991Sheppo 	/* Truncate packet to max of MTU size */
45661991Sheppo 	if (*sizep > ldcp->mtu) *sizep = ldcp->mtu;
45671991Sheppo 	return (i_ldc_write_packet(ldcp, buf, sizep));
45681991Sheppo }
45691991Sheppo 
45701991Sheppo 
45711991Sheppo /*
45721991Sheppo  * Interfaces for channel nexus to register/unregister with LDC module
45731991Sheppo  * The nexus will register functions to be used to register individual
45741991Sheppo  * channels with the nexus and enable interrupts for the channels
45751991Sheppo  */
45761991Sheppo int
45771991Sheppo ldc_register(ldc_cnex_t *cinfo)
45781991Sheppo {
45791991Sheppo 	ldc_chan_t	*ldcp;
45801991Sheppo 
45811991Sheppo 	if (cinfo == NULL || cinfo->dip == NULL ||
45821991Sheppo 	    cinfo->reg_chan == NULL || cinfo->unreg_chan == NULL ||
45831991Sheppo 	    cinfo->add_intr == NULL || cinfo->rem_intr == NULL ||
45841991Sheppo 	    cinfo->clr_intr == NULL) {
45851991Sheppo 
45861991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_register: invalid nexus info\n");
45871991Sheppo 		return (EINVAL);
45881991Sheppo 	}
45891991Sheppo 
45901991Sheppo 	mutex_enter(&ldcssp->lock);
45911991Sheppo 
45921991Sheppo 	/* nexus registration */
45931991Sheppo 	ldcssp->cinfo.dip = cinfo->dip;
45941991Sheppo 	ldcssp->cinfo.reg_chan = cinfo->reg_chan;
45951991Sheppo 	ldcssp->cinfo.unreg_chan = cinfo->unreg_chan;
45961991Sheppo 	ldcssp->cinfo.add_intr = cinfo->add_intr;
45971991Sheppo 	ldcssp->cinfo.rem_intr = cinfo->rem_intr;
45981991Sheppo 	ldcssp->cinfo.clr_intr = cinfo->clr_intr;
45991991Sheppo 
46001991Sheppo 	/* register any channels that might have been previously initialized */
46011991Sheppo 	ldcp = ldcssp->chan_list;
46021991Sheppo 	while (ldcp) {
46031991Sheppo 		if ((ldcp->tstate & TS_QCONF_RDY) &&
46041991Sheppo 		    (ldcp->tstate & TS_CNEX_RDY) == 0)
46051991Sheppo 			(void) i_ldc_register_channel(ldcp);
46061991Sheppo 
46071991Sheppo 		ldcp = ldcp->next;
46081991Sheppo 	}
46091991Sheppo 
46101991Sheppo 	mutex_exit(&ldcssp->lock);
46111991Sheppo 
46121991Sheppo 	return (0);
46131991Sheppo }
46141991Sheppo 
46151991Sheppo int
46161991Sheppo ldc_unregister(ldc_cnex_t *cinfo)
46171991Sheppo {
46181991Sheppo 	if (cinfo == NULL || cinfo->dip == NULL) {
46191991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid nexus info\n");
46201991Sheppo 		return (EINVAL);
46211991Sheppo 	}
46221991Sheppo 
46231991Sheppo 	mutex_enter(&ldcssp->lock);
46241991Sheppo 
46251991Sheppo 	if (cinfo->dip != ldcssp->cinfo.dip) {
46261991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid dip\n");
46271991Sheppo 		mutex_exit(&ldcssp->lock);
46281991Sheppo 		return (EINVAL);
46291991Sheppo 	}
46301991Sheppo 
46311991Sheppo 	/* nexus unregister */
46321991Sheppo 	ldcssp->cinfo.dip = NULL;
46331991Sheppo 	ldcssp->cinfo.reg_chan = NULL;
46341991Sheppo 	ldcssp->cinfo.unreg_chan = NULL;
46351991Sheppo 	ldcssp->cinfo.add_intr = NULL;
46361991Sheppo 	ldcssp->cinfo.rem_intr = NULL;
46371991Sheppo 	ldcssp->cinfo.clr_intr = NULL;
46381991Sheppo 
46391991Sheppo 	mutex_exit(&ldcssp->lock);
46401991Sheppo 
46411991Sheppo 	return (0);
46421991Sheppo }
46431991Sheppo 
46441991Sheppo 
46451991Sheppo /* ------------------------------------------------------------------------- */
46461991Sheppo 
46471991Sheppo /*
46481991Sheppo  * Allocate a memory handle for the channel and link it into the list
46491991Sheppo  * Also choose which memory table to use if this is the first handle
46501991Sheppo  * being assigned to this channel
46511991Sheppo  */
46521991Sheppo int
46531991Sheppo ldc_mem_alloc_handle(ldc_handle_t handle, ldc_mem_handle_t *mhandle)
46541991Sheppo {
46551991Sheppo 	ldc_chan_t 	*ldcp;
46561991Sheppo 	ldc_mhdl_t	*mhdl;
46571991Sheppo 
46581991Sheppo 	if (handle == NULL) {
46591991Sheppo 		DWARN(DBG_ALL_LDCS,
46601991Sheppo 		    "ldc_mem_alloc_handle: invalid channel handle\n");
46611991Sheppo 		return (EINVAL);
46621991Sheppo 	}
46631991Sheppo 	ldcp = (ldc_chan_t *)handle;
46641991Sheppo 
46651991Sheppo 	mutex_enter(&ldcp->lock);
46661991Sheppo 
46671991Sheppo 	/* check to see if channel is initalized */
46682793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) < TS_INIT) {
46691991Sheppo 		DWARN(ldcp->id,
46701991Sheppo 		    "ldc_mem_alloc_handle: (0x%llx) channel not initialized\n",
46711991Sheppo 		    ldcp->id);
46721991Sheppo 		mutex_exit(&ldcp->lock);
46731991Sheppo 		return (EINVAL);
46741991Sheppo 	}
46751991Sheppo 
46761991Sheppo 	/* allocate handle for channel */
46772531Snarayan 	mhdl = kmem_cache_alloc(ldcssp->memhdl_cache, KM_SLEEP);
46781991Sheppo 
46791991Sheppo 	/* initialize the lock */
46801991Sheppo 	mutex_init(&mhdl->lock, NULL, MUTEX_DRIVER, NULL);
46811991Sheppo 
46822531Snarayan 	mhdl->myshadow = B_FALSE;
46832531Snarayan 	mhdl->memseg = NULL;
46842531Snarayan 	mhdl->ldcp = ldcp;
46851991Sheppo 	mhdl->status = LDC_UNBOUND;
46861991Sheppo 
46871991Sheppo 	/* insert memory handle (@ head) into list */
46881991Sheppo 	if (ldcp->mhdl_list == NULL) {
46891991Sheppo 		ldcp->mhdl_list = mhdl;
46901991Sheppo 		mhdl->next = NULL;
46911991Sheppo 	} else {
46921991Sheppo 		/* insert @ head */
46931991Sheppo 		mhdl->next = ldcp->mhdl_list;
46941991Sheppo 		ldcp->mhdl_list = mhdl;
46951991Sheppo 	}
46961991Sheppo 
46971991Sheppo 	/* return the handle */
46981991Sheppo 	*mhandle = (ldc_mem_handle_t)mhdl;
46991991Sheppo 
47001991Sheppo 	mutex_exit(&ldcp->lock);
47011991Sheppo 
47021991Sheppo 	D1(ldcp->id, "ldc_mem_alloc_handle: (0x%llx) allocated handle 0x%llx\n",
47031991Sheppo 	    ldcp->id, mhdl);
47041991Sheppo 
47051991Sheppo 	return (0);
47061991Sheppo }
47071991Sheppo 
47081991Sheppo /*
47091991Sheppo  * Free memory handle for the channel and unlink it from the list
47101991Sheppo  */
47111991Sheppo int
47121991Sheppo ldc_mem_free_handle(ldc_mem_handle_t mhandle)
47131991Sheppo {
47141991Sheppo 	ldc_mhdl_t 	*mhdl, *phdl;
47151991Sheppo 	ldc_chan_t 	*ldcp;
47161991Sheppo 
47171991Sheppo 	if (mhandle == NULL) {
47181991Sheppo 		DWARN(DBG_ALL_LDCS,
47191991Sheppo 		    "ldc_mem_free_handle: invalid memory handle\n");
47201991Sheppo 		return (EINVAL);
47211991Sheppo 	}
47221991Sheppo 	mhdl = (ldc_mhdl_t *)mhandle;
47231991Sheppo 
47241991Sheppo 	mutex_enter(&mhdl->lock);
47251991Sheppo 
47261991Sheppo 	ldcp = mhdl->ldcp;
47271991Sheppo 
47281991Sheppo 	if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED) {
47291991Sheppo 		DWARN(ldcp->id,
47301991Sheppo 		    "ldc_mem_free_handle: cannot free, 0x%llx hdl bound\n",
47311991Sheppo 		    mhdl);
47321991Sheppo 		mutex_exit(&mhdl->lock);
47331991Sheppo 		return (EINVAL);
47341991Sheppo 	}
47351991Sheppo 	mutex_exit(&mhdl->lock);
47361991Sheppo 
47371991Sheppo 	mutex_enter(&ldcp->mlist_lock);
47381991Sheppo 
47391991Sheppo 	phdl = ldcp->mhdl_list;
47401991Sheppo 
47411991Sheppo 	/* first handle */
47421991Sheppo 	if (phdl == mhdl) {
47431991Sheppo 		ldcp->mhdl_list = mhdl->next;
47441991Sheppo 		mutex_destroy(&mhdl->lock);
47452531Snarayan 		kmem_cache_free(ldcssp->memhdl_cache, mhdl);
47462531Snarayan 
47471991Sheppo 		D1(ldcp->id,
47481991Sheppo 		    "ldc_mem_free_handle: (0x%llx) freed handle 0x%llx\n",
47491991Sheppo 		    ldcp->id, mhdl);
47501991Sheppo 	} else {
47511991Sheppo 		/* walk the list - unlink and free */
47521991Sheppo 		while (phdl != NULL) {
47531991Sheppo 			if (phdl->next == mhdl) {
47541991Sheppo 				phdl->next = mhdl->next;
47551991Sheppo 				mutex_destroy(&mhdl->lock);
47562531Snarayan 				kmem_cache_free(ldcssp->memhdl_cache, mhdl);
47571991Sheppo 				D1(ldcp->id,
47581991Sheppo 				    "ldc_mem_free_handle: (0x%llx) freed "
47591991Sheppo 				    "handle 0x%llx\n", ldcp->id, mhdl);
47601991Sheppo 				break;
47611991Sheppo 			}
47621991Sheppo 			phdl = phdl->next;
47631991Sheppo 		}
47641991Sheppo 	}
47651991Sheppo 
47661991Sheppo 	if (phdl == NULL) {
47671991Sheppo 		DWARN(ldcp->id,
47681991Sheppo 		    "ldc_mem_free_handle: invalid handle 0x%llx\n", mhdl);
47691991Sheppo 		mutex_exit(&ldcp->mlist_lock);
47701991Sheppo 		return (EINVAL);
47711991Sheppo 	}
47721991Sheppo 
47731991Sheppo 	mutex_exit(&ldcp->mlist_lock);
47741991Sheppo 
47751991Sheppo 	return (0);
47761991Sheppo }
47771991Sheppo 
47781991Sheppo /*
47791991Sheppo  * Bind a memory handle to a virtual address.
47801991Sheppo  * The virtual address is converted to the corresponding real addresses.
47811991Sheppo  * Returns pointer to the first ldc_mem_cookie and the total number
47821991Sheppo  * of cookies for this virtual address. Other cookies can be obtained
47831991Sheppo  * using the ldc_mem_nextcookie() call. If the pages are stored in
47841991Sheppo  * consecutive locations in the table, a single cookie corresponding to
47851991Sheppo  * the first location is returned. The cookie size spans all the entries.
47861991Sheppo  *
47871991Sheppo  * If the VA corresponds to a page that is already being exported, reuse
47881991Sheppo  * the page and do not export it again. Bump the page's use count.
47891991Sheppo  */
47901991Sheppo int
47911991Sheppo ldc_mem_bind_handle(ldc_mem_handle_t mhandle, caddr_t vaddr, size_t len,
47921991Sheppo     uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount)
47931991Sheppo {
47941991Sheppo 	ldc_mhdl_t	*mhdl;
47951991Sheppo 	ldc_chan_t 	*ldcp;
47961991Sheppo 	ldc_mtbl_t	*mtbl;
47971991Sheppo 	ldc_memseg_t	*memseg;
47981991Sheppo 	ldc_mte_t	tmp_mte;
47991991Sheppo 	uint64_t	index, prev_index = 0;
48001991Sheppo 	int64_t		cookie_idx;
48011991Sheppo 	uintptr_t	raddr, ra_aligned;
48021991Sheppo 	uint64_t	psize, poffset, v_offset;
48031991Sheppo 	uint64_t	pg_shift, pg_size, pg_size_code, pg_mask;
48041991Sheppo 	pgcnt_t		npages;
48051991Sheppo 	caddr_t		v_align, addr;
48062531Snarayan 	int 		i, rv;
48071991Sheppo 
48081991Sheppo 	if (mhandle == NULL) {
48091991Sheppo 		DWARN(DBG_ALL_LDCS,
48101991Sheppo 		    "ldc_mem_bind_handle: invalid memory handle\n");
48111991Sheppo 		return (EINVAL);
48121991Sheppo 	}
48131991Sheppo 	mhdl = (ldc_mhdl_t *)mhandle;
48141991Sheppo 	ldcp = mhdl->ldcp;
48151991Sheppo 
48161991Sheppo 	/* clear count */
48171991Sheppo 	*ccount = 0;
48181991Sheppo 
48191991Sheppo 	mutex_enter(&mhdl->lock);
48201991Sheppo 
48211991Sheppo 	if (mhdl->status == LDC_BOUND || mhdl->memseg != NULL) {
48221991Sheppo 		DWARN(ldcp->id,
48231991Sheppo 		    "ldc_mem_bind_handle: (0x%x) handle already bound\n",
48241991Sheppo 		    mhandle);
48251991Sheppo 		mutex_exit(&mhdl->lock);
48261991Sheppo 		return (EINVAL);
48271991Sheppo 	}
48281991Sheppo 
48291991Sheppo 	/* Force address and size to be 8-byte aligned */
48301991Sheppo 	if ((((uintptr_t)vaddr | len) & 0x7) != 0) {
48311991Sheppo 		DWARN(ldcp->id,
48321991Sheppo 		    "ldc_mem_bind_handle: addr/size is not 8-byte aligned\n");
48331991Sheppo 		mutex_exit(&mhdl->lock);
48341991Sheppo 		return (EINVAL);
48351991Sheppo 	}
48361991Sheppo 
48372531Snarayan 	/*
48382531Snarayan 	 * If this channel is binding a memory handle for the
48392531Snarayan 	 * first time allocate it a memory map table and initialize it
48402531Snarayan 	 */
48412531Snarayan 	if ((mtbl = ldcp->mtbl) == NULL) {
48422531Snarayan 
48432531Snarayan 		mutex_enter(&ldcp->lock);
48442531Snarayan 
48452531Snarayan 		/* Allocate and initialize the map table structure */
48462531Snarayan 		mtbl = kmem_zalloc(sizeof (ldc_mtbl_t), KM_SLEEP);
48472531Snarayan 		mtbl->num_entries = mtbl->num_avail = ldc_maptable_entries;
48482531Snarayan 		mtbl->size = ldc_maptable_entries * sizeof (ldc_mte_slot_t);
48492531Snarayan 		mtbl->next_entry = NULL;
48502793Slm66018 		mtbl->contigmem = B_TRUE;
48512531Snarayan 
48522531Snarayan 		/* Allocate the table itself */
48532531Snarayan 		mtbl->table = (ldc_mte_slot_t *)
48544690Snarayan 		    contig_mem_alloc_align(mtbl->size, MMU_PAGESIZE);
48552531Snarayan 		if (mtbl->table == NULL) {
48562793Slm66018 
48572793Slm66018 			/* allocate a page of memory using kmem_alloc */
48582793Slm66018 			mtbl->table = kmem_alloc(MMU_PAGESIZE, KM_SLEEP);
48592793Slm66018 			mtbl->size = MMU_PAGESIZE;
48602793Slm66018 			mtbl->contigmem = B_FALSE;
48612793Slm66018 			mtbl->num_entries = mtbl->num_avail =
48624690Snarayan 			    mtbl->size / sizeof (ldc_mte_slot_t);
48632793Slm66018 			DWARN(ldcp->id,
48642793Slm66018 			    "ldc_mem_bind_handle: (0x%llx) reduced tbl size "
48652793Slm66018 			    "to %lx entries\n", ldcp->id, mtbl->num_entries);
48662531Snarayan 		}
48672531Snarayan 
48682531Snarayan 		/* zero out the memory */
48692531Snarayan 		bzero(mtbl->table, mtbl->size);
48702531Snarayan 
48712531Snarayan 		/* initialize the lock */
48722531Snarayan 		mutex_init(&mtbl->lock, NULL, MUTEX_DRIVER, NULL);
48732531Snarayan 
48742531Snarayan 		/* register table for this channel */
48752531Snarayan 		rv = hv_ldc_set_map_table(ldcp->id,
48762531Snarayan 		    va_to_pa(mtbl->table), mtbl->num_entries);
48772531Snarayan 		if (rv != 0) {
48782531Snarayan 			cmn_err(CE_WARN,
48792531Snarayan 			    "ldc_mem_bind_handle: (0x%lx) err %d mapping tbl",
48802531Snarayan 			    ldcp->id, rv);
48812793Slm66018 			if (mtbl->contigmem)
48822793Slm66018 				contig_mem_free(mtbl->table, mtbl->size);
48832793Slm66018 			else
48842793Slm66018 				kmem_free(mtbl->table, mtbl->size);
48852531Snarayan 			mutex_destroy(&mtbl->lock);
48862531Snarayan 			kmem_free(mtbl, sizeof (ldc_mtbl_t));
48872531Snarayan 			mutex_exit(&ldcp->lock);
48882531Snarayan 			mutex_exit(&mhdl->lock);
48892531Snarayan 			return (EIO);
48902531Snarayan 		}
48912531Snarayan 
48922531Snarayan 		ldcp->mtbl = mtbl;
48932531Snarayan 		mutex_exit(&ldcp->lock);
48942531Snarayan 
48952531Snarayan 		D1(ldcp->id,
48962531Snarayan 		    "ldc_mem_bind_handle: (0x%llx) alloc'd map table 0x%llx\n",
48972531Snarayan 		    ldcp->id, ldcp->mtbl->table);
48982531Snarayan 	}
48992531Snarayan 
49001991Sheppo 	/* FUTURE: get the page size, pgsz code, and shift */
49011991Sheppo 	pg_size = MMU_PAGESIZE;
49021991Sheppo 	pg_size_code = page_szc(pg_size);
49031991Sheppo 	pg_shift = page_get_shift(pg_size_code);
49041991Sheppo 	pg_mask = ~(pg_size - 1);
49051991Sheppo 
49061991Sheppo 	D1(ldcp->id, "ldc_mem_bind_handle: (0x%llx) binding "
49071991Sheppo 	    "va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n",
49081991Sheppo 	    ldcp->id, vaddr, pg_size, pg_size_code, pg_shift);
49091991Sheppo 
49101991Sheppo 	/* aligned VA and its offset */
49111991Sheppo 	v_align = (caddr_t)(((uintptr_t)vaddr) & ~(pg_size - 1));
49121991Sheppo 	v_offset = ((uintptr_t)vaddr) & (pg_size - 1);
49131991Sheppo 
49141991Sheppo 	npages = (len+v_offset)/pg_size;
49151991Sheppo 	npages = ((len+v_offset)%pg_size == 0) ? npages : npages+1;
49161991Sheppo 
49171991Sheppo 	D1(ldcp->id, "ldc_mem_bind_handle: binding "
49181991Sheppo 	    "(0x%llx) v=0x%llx,val=0x%llx,off=0x%x,pgs=0x%x\n",
49191991Sheppo 	    ldcp->id, vaddr, v_align, v_offset, npages);
49201991Sheppo 
49211991Sheppo 	/* lock the memory table - exclusive access to channel */
49221991Sheppo 	mutex_enter(&mtbl->lock);
49231991Sheppo 
49241991Sheppo 	if (npages > mtbl->num_avail) {
49252793Slm66018 		D1(ldcp->id, "ldc_mem_bind_handle: (0x%llx) no table entries\n",
49261991Sheppo 		    ldcp->id);
49271991Sheppo 		mutex_exit(&mtbl->lock);
49281991Sheppo 		mutex_exit(&mhdl->lock);
49291991Sheppo 		return (ENOMEM);
49301991Sheppo 	}
49311991Sheppo 
49321991Sheppo 	/* Allocate a memseg structure */
49332531Snarayan 	memseg = mhdl->memseg =
49344690Snarayan 	    kmem_cache_alloc(ldcssp->memseg_cache, KM_SLEEP);
49351991Sheppo 
49361991Sheppo 	/* Allocate memory to store all pages and cookies */
49371991Sheppo 	memseg->pages = kmem_zalloc((sizeof (ldc_page_t) * npages), KM_SLEEP);
49381991Sheppo 	memseg->cookies =
49394690Snarayan 	    kmem_zalloc((sizeof (ldc_mem_cookie_t) * npages), KM_SLEEP);
49401991Sheppo 
49411991Sheppo 	D2(ldcp->id, "ldc_mem_bind_handle: (0x%llx) processing 0x%llx pages\n",
49421991Sheppo 	    ldcp->id, npages);
49431991Sheppo 
49441991Sheppo 	addr = v_align;
49451991Sheppo 
49461991Sheppo 	/*
49472531Snarayan 	 * Check if direct shared memory map is enabled, if not change
49482531Snarayan 	 * the mapping type to include SHADOW_MAP.
49492531Snarayan 	 */
49502531Snarayan 	if (ldc_shmem_enabled == 0)
49512531Snarayan 		mtype = LDC_SHADOW_MAP;
49522531Snarayan 
49532531Snarayan 	/*
49541991Sheppo 	 * Table slots are used in a round-robin manner. The algorithm permits
49551991Sheppo 	 * inserting duplicate entries. Slots allocated earlier will typically
49561991Sheppo 	 * get freed before we get back to reusing the slot.Inserting duplicate
49571991Sheppo 	 * entries should be OK as we only lookup entries using the cookie addr
49581991Sheppo 	 * i.e. tbl index, during export, unexport and copy operation.
49591991Sheppo 	 *
49601991Sheppo 	 * One implementation what was tried was to search for a duplicate
49611991Sheppo 	 * page entry first and reuse it. The search overhead is very high and
49621991Sheppo 	 * in the vnet case dropped the perf by almost half, 50 to 24 mbps.
49631991Sheppo 	 * So it does make sense to avoid searching for duplicates.
49641991Sheppo 	 *
49651991Sheppo 	 * But during the process of searching for a free slot, if we find a
49661991Sheppo 	 * duplicate entry we will go ahead and use it, and bump its use count.
49671991Sheppo 	 */
49681991Sheppo 
49691991Sheppo 	/* index to start searching from */
49701991Sheppo 	index = mtbl->next_entry;
49711991Sheppo 	cookie_idx = -1;
49721991Sheppo 
49731991Sheppo 	tmp_mte.ll = 0;	/* initialise fields to 0 */
49741991Sheppo 
49751991Sheppo 	if (mtype & LDC_DIRECT_MAP) {
49761991Sheppo 		tmp_mte.mte_r = (perm & LDC_MEM_R) ? 1 : 0;
49771991Sheppo 		tmp_mte.mte_w = (perm & LDC_MEM_W) ? 1 : 0;
49781991Sheppo 		tmp_mte.mte_x = (perm & LDC_MEM_X) ? 1 : 0;
49791991Sheppo 	}
49801991Sheppo 
49811991Sheppo 	if (mtype & LDC_SHADOW_MAP) {
49821991Sheppo 		tmp_mte.mte_cr = (perm & LDC_MEM_R) ? 1 : 0;
49831991Sheppo 		tmp_mte.mte_cw = (perm & LDC_MEM_W) ? 1 : 0;
49841991Sheppo 	}
49851991Sheppo 
49861991Sheppo 	if (mtype & LDC_IO_MAP) {
49871991Sheppo 		tmp_mte.mte_ir = (perm & LDC_MEM_R) ? 1 : 0;
49881991Sheppo 		tmp_mte.mte_iw = (perm & LDC_MEM_W) ? 1 : 0;
49891991Sheppo 	}
49901991Sheppo 
49911991Sheppo 	D1(ldcp->id, "ldc_mem_bind_handle mte=0x%llx\n", tmp_mte.ll);
49921991Sheppo 
49931991Sheppo 	tmp_mte.mte_pgszc = pg_size_code;
49941991Sheppo 
49951991Sheppo 	/* initialize each mem table entry */
49961991Sheppo 	for (i = 0; i < npages; i++) {
49971991Sheppo 
49981991Sheppo 		/* check if slot is available in the table */
49991991Sheppo 		while (mtbl->table[index].entry.ll != 0) {
50001991Sheppo 
50011991Sheppo 			index = (index + 1) % mtbl->num_entries;
50021991Sheppo 
50031991Sheppo 			if (index == mtbl->next_entry) {
50041991Sheppo 				/* we have looped around */
50051991Sheppo 				DWARN(DBG_ALL_LDCS,
50061991Sheppo 				    "ldc_mem_bind_handle: (0x%llx) cannot find "
50071991Sheppo 				    "entry\n", ldcp->id);
50081991Sheppo 				*ccount = 0;
50091991Sheppo 
50101991Sheppo 				/* NOTE: free memory, remove previous entries */
50111991Sheppo 				/* this shouldnt happen as num_avail was ok */
50121991Sheppo 
50131991Sheppo 				mutex_exit(&mtbl->lock);
50141991Sheppo 				mutex_exit(&mhdl->lock);
50151991Sheppo 				return (ENOMEM);
50161991Sheppo 			}
50171991Sheppo 		}
50181991Sheppo 
50191991Sheppo 		/* get the real address */
50201991Sheppo 		raddr = va_to_pa((void *)addr);
50211991Sheppo 		ra_aligned = ((uintptr_t)raddr & pg_mask);
50221991Sheppo 
50231991Sheppo 		/* build the mte */
50241991Sheppo 		tmp_mte.mte_rpfn = ra_aligned >> pg_shift;
50251991Sheppo 
50261991Sheppo 		D1(ldcp->id, "ldc_mem_bind_handle mte=0x%llx\n", tmp_mte.ll);
50271991Sheppo 
50281991Sheppo 		/* update entry in table */
50291991Sheppo 		mtbl->table[index].entry = tmp_mte;
50301991Sheppo 
50311991Sheppo 		D2(ldcp->id, "ldc_mem_bind_handle: (0x%llx) stored MTE 0x%llx"
50321991Sheppo 		    " into loc 0x%llx\n", ldcp->id, tmp_mte.ll, index);
50331991Sheppo 
50341991Sheppo 		/* calculate the size and offset for this export range */
50351991Sheppo 		if (i == 0) {
50361991Sheppo 			/* first page */
50371991Sheppo 			psize = min((pg_size - v_offset), len);
50381991Sheppo 			poffset = v_offset;
50391991Sheppo 
50401991Sheppo 		} else if (i == (npages - 1)) {
50411991Sheppo 			/* last page */
50421991Sheppo 			psize =	(((uintptr_t)(vaddr + len)) &
50434690Snarayan 			    ((uint64_t)(pg_size-1)));
50441991Sheppo 			if (psize == 0)
50451991Sheppo 				psize = pg_size;
50461991Sheppo 			poffset = 0;
50471991Sheppo 
50481991Sheppo 		} else {
50491991Sheppo 			/* middle pages */
50501991Sheppo 			psize = pg_size;
50511991Sheppo 			poffset = 0;
50521991Sheppo 		}
50531991Sheppo 
50541991Sheppo 		/* store entry for this page */
50551991Sheppo 		memseg->pages[i].index = index;
50561991Sheppo 		memseg->pages[i].raddr = raddr;
50571991Sheppo 		memseg->pages[i].offset = poffset;
50581991Sheppo 		memseg->pages[i].size = psize;
50591991Sheppo 		memseg->pages[i].mte = &(mtbl->table[index]);
50601991Sheppo 
50611991Sheppo 		/* create the cookie */
50621991Sheppo 		if (i == 0 || (index != prev_index + 1)) {
50631991Sheppo 			cookie_idx++;
50641991Sheppo 			memseg->cookies[cookie_idx].addr =
50654690Snarayan 			    IDX2COOKIE(index, pg_size_code, pg_shift);
50661991Sheppo 			memseg->cookies[cookie_idx].addr |= poffset;
50671991Sheppo 			memseg->cookies[cookie_idx].size = psize;
50681991Sheppo 
50691991Sheppo 		} else {
50701991Sheppo 			memseg->cookies[cookie_idx].size += psize;
50711991Sheppo 		}
50721991Sheppo 
50731991Sheppo 		D1(ldcp->id, "ldc_mem_bind_handle: bound "
50741991Sheppo 		    "(0x%llx) va=0x%llx, idx=0x%llx, "
50751991Sheppo 		    "ra=0x%llx(sz=0x%x,off=0x%x)\n",
50761991Sheppo 		    ldcp->id, addr, index, raddr, psize, poffset);
50771991Sheppo 
50781991Sheppo 		/* decrement number of available entries */
50791991Sheppo 		mtbl->num_avail--;
50801991Sheppo 
50811991Sheppo 		/* increment va by page size */
50821991Sheppo 		addr += pg_size;
50831991Sheppo 
50841991Sheppo 		/* increment index */
50851991Sheppo 		prev_index = index;
50861991Sheppo 		index = (index + 1) % mtbl->num_entries;
50871991Sheppo 
50881991Sheppo 		/* save the next slot */
50891991Sheppo 		mtbl->next_entry = index;
50901991Sheppo 	}
50911991Sheppo 
50921991Sheppo 	mutex_exit(&mtbl->lock);
50931991Sheppo 
50941991Sheppo 	/* memory handle = bound */
50951991Sheppo 	mhdl->mtype = mtype;
50961991Sheppo 	mhdl->perm = perm;
50971991Sheppo 	mhdl->status = LDC_BOUND;
50981991Sheppo 
50991991Sheppo 	/* update memseg_t */
51001991Sheppo 	memseg->vaddr = vaddr;
51011991Sheppo 	memseg->raddr = memseg->pages[0].raddr;
51021991Sheppo 	memseg->size = len;
51031991Sheppo 	memseg->npages = npages;
51041991Sheppo 	memseg->ncookies = cookie_idx + 1;
51051991Sheppo 	memseg->next_cookie = (memseg->ncookies > 1) ? 1 : 0;
51061991Sheppo 
51071991Sheppo 	/* return count and first cookie */
51081991Sheppo 	*ccount = memseg->ncookies;
51091991Sheppo 	cookie->addr = memseg->cookies[0].addr;
51101991Sheppo 	cookie->size = memseg->cookies[0].size;
51111991Sheppo 
51121991Sheppo 	D1(ldcp->id,
51131991Sheppo 	    "ldc_mem_bind_handle: (0x%llx) bound 0x%llx, va=0x%llx, "
51141991Sheppo 	    "pgs=0x%llx cookies=0x%llx\n",
51151991Sheppo 	    ldcp->id, mhdl, vaddr, npages, memseg->ncookies);
51161991Sheppo 
51171991Sheppo 	mutex_exit(&mhdl->lock);
51181991Sheppo 	return (0);
51191991Sheppo }
51201991Sheppo 
51211991Sheppo /*
51221991Sheppo  * Return the next cookie associated with the specified memory handle
51231991Sheppo  */
51241991Sheppo int
51251991Sheppo ldc_mem_nextcookie(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie)
51261991Sheppo {
51271991Sheppo 	ldc_mhdl_t	*mhdl;
51281991Sheppo 	ldc_chan_t 	*ldcp;
51291991Sheppo 	ldc_memseg_t	*memseg;
51301991Sheppo 
51311991Sheppo 	if (mhandle == NULL) {
51321991Sheppo 		DWARN(DBG_ALL_LDCS,
51331991Sheppo 		    "ldc_mem_nextcookie: invalid memory handle\n");
51341991Sheppo 		return (EINVAL);
51351991Sheppo 	}
51361991Sheppo 	mhdl = (ldc_mhdl_t *)mhandle;
51371991Sheppo 
51381991Sheppo 	mutex_enter(&mhdl->lock);
51391991Sheppo 
51401991Sheppo 	ldcp = mhdl->ldcp;
51411991Sheppo 	memseg = mhdl->memseg;
51421991Sheppo 
51431991Sheppo 	if (cookie == 0) {
51441991Sheppo 		DWARN(ldcp->id,
51451991Sheppo 		    "ldc_mem_nextcookie:(0x%llx) invalid cookie arg\n",
51461991Sheppo 		    ldcp->id);
51471991Sheppo 		mutex_exit(&mhdl->lock);
51481991Sheppo 		return (EINVAL);
51491991Sheppo 	}
51501991Sheppo 
51511991Sheppo 	if (memseg->next_cookie != 0) {
51521991Sheppo 		cookie->addr = memseg->cookies[memseg->next_cookie].addr;
51531991Sheppo 		cookie->size = memseg->cookies[memseg->next_cookie].size;
51541991Sheppo 		memseg->next_cookie++;
51551991Sheppo 		if (memseg->next_cookie == memseg->ncookies)
51561991Sheppo 			memseg->next_cookie = 0;
51571991Sheppo 
51581991Sheppo 	} else {
51591991Sheppo 		DWARN(ldcp->id,
51601991Sheppo 		    "ldc_mem_nextcookie:(0x%llx) no more cookies\n", ldcp->id);
51611991Sheppo 		cookie->addr = 0;
51621991Sheppo 		cookie->size = 0;
51631991Sheppo 		mutex_exit(&mhdl->lock);
51641991Sheppo 		return (EINVAL);
51651991Sheppo 	}
51661991Sheppo 
51671991Sheppo 	D1(ldcp->id,
51681991Sheppo 	    "ldc_mem_nextcookie: (0x%llx) cookie addr=0x%llx,sz=0x%llx\n",
51691991Sheppo 	    ldcp->id, cookie->addr, cookie->size);
51701991Sheppo 
51711991Sheppo 	mutex_exit(&mhdl->lock);
51721991Sheppo 	return (0);
51731991Sheppo }
51741991Sheppo 
51751991Sheppo /*
51761991Sheppo  * Unbind the virtual memory region associated with the specified
51771991Sheppo  * memory handle. Allassociated cookies are freed and the corresponding
51781991Sheppo  * RA space is no longer exported.
51791991Sheppo  */
51801991Sheppo int
51811991Sheppo ldc_mem_unbind_handle(ldc_mem_handle_t mhandle)
51821991Sheppo {
51831991Sheppo 	ldc_mhdl_t	*mhdl;
51841991Sheppo 	ldc_chan_t 	*ldcp;
51851991Sheppo 	ldc_mtbl_t	*mtbl;
51861991Sheppo 	ldc_memseg_t	*memseg;
51872531Snarayan 	uint64_t	cookie_addr;
51882531Snarayan 	uint64_t	pg_shift, pg_size_code;
51892531Snarayan 	int		i, rv;
51901991Sheppo 
51911991Sheppo 	if (mhandle == NULL) {
51921991Sheppo 		DWARN(DBG_ALL_LDCS,
51931991Sheppo 		    "ldc_mem_unbind_handle: invalid memory handle\n");
51941991Sheppo 		return (EINVAL);
51951991Sheppo 	}
51961991Sheppo 	mhdl = (ldc_mhdl_t *)mhandle;
51971991Sheppo 
51981991Sheppo 	mutex_enter(&mhdl->lock);
51991991Sheppo 
52001991Sheppo 	if (mhdl->status == LDC_UNBOUND) {
52011991Sheppo 		DWARN(DBG_ALL_LDCS,
52021991Sheppo 		    "ldc_mem_unbind_handle: (0x%x) handle is not bound\n",
52031991Sheppo 		    mhandle);
52041991Sheppo 		mutex_exit(&mhdl->lock);
52051991Sheppo 		return (EINVAL);
52061991Sheppo 	}
52071991Sheppo 
52081991Sheppo 	ldcp = mhdl->ldcp;
52091991Sheppo 	mtbl = ldcp->mtbl;
52101991Sheppo 
52111991Sheppo 	memseg = mhdl->memseg;
52121991Sheppo 
52131991Sheppo 	/* lock the memory table - exclusive access to channel */
52141991Sheppo 	mutex_enter(&mtbl->lock);
52151991Sheppo 
52161991Sheppo 	/* undo the pages exported */
52171991Sheppo 	for (i = 0; i < memseg->npages; i++) {
52181991Sheppo 
52192531Snarayan 		/* check for mapped pages, revocation cookie != 0 */
52201991Sheppo 		if (memseg->pages[i].mte->cookie) {
52212531Snarayan 
52222531Snarayan 			pg_size_code = page_szc(memseg->pages[i].size);
52232531Snarayan 			pg_shift = page_get_shift(memseg->pages[i].size);
52242531Snarayan 			cookie_addr = IDX2COOKIE(memseg->pages[i].index,
52252531Snarayan 			    pg_size_code, pg_shift);
52262531Snarayan 
52272531Snarayan 			D1(ldcp->id, "ldc_mem_unbind_handle: (0x%llx) revoke "
52282531Snarayan 			    "cookie 0x%llx, rcookie 0x%llx\n", ldcp->id,
52292531Snarayan 			    cookie_addr, memseg->pages[i].mte->cookie);
52302531Snarayan 			rv = hv_ldc_revoke(ldcp->id, cookie_addr,
52312531Snarayan 			    memseg->pages[i].mte->cookie);
52322531Snarayan 			if (rv) {
52332531Snarayan 				DWARN(ldcp->id,
52342531Snarayan 				    "ldc_mem_unbind_handle: (0x%llx) cannot "
52352531Snarayan 				    "revoke mapping, cookie %llx\n", ldcp->id,
52362531Snarayan 				    cookie_addr);
52372531Snarayan 			}
52381991Sheppo 		}
52391991Sheppo 
52401991Sheppo 		/* clear the entry from the table */
52411991Sheppo 		memseg->pages[i].mte->entry.ll = 0;
52421991Sheppo 		mtbl->num_avail++;
52431991Sheppo 	}
52441991Sheppo 	mutex_exit(&mtbl->lock);
52451991Sheppo 
52461991Sheppo 	/* free the allocated memseg and page structures */
52471991Sheppo 	kmem_free(memseg->pages, (sizeof (ldc_page_t) * memseg->npages));
52481991Sheppo 	kmem_free(memseg->cookies,
52491991Sheppo 	    (sizeof (ldc_mem_cookie_t) * memseg->npages));
52502531Snarayan 	kmem_cache_free(ldcssp->memseg_cache, memseg);
52511991Sheppo 
52521991Sheppo 	/* uninitialize the memory handle */
52531991Sheppo 	mhdl->memseg = NULL;
52541991Sheppo 	mhdl->status = LDC_UNBOUND;
52551991Sheppo 
52561991Sheppo 	D1(ldcp->id, "ldc_mem_unbind_handle: (0x%llx) unbound handle 0x%llx\n",
52571991Sheppo 	    ldcp->id, mhdl);
52581991Sheppo 
52591991Sheppo 	mutex_exit(&mhdl->lock);
52601991Sheppo 	return (0);
52611991Sheppo }
52621991Sheppo 
52631991Sheppo /*
52641991Sheppo  * Get information about the dring. The base address of the descriptor
52651991Sheppo  * ring along with the type and permission are returned back.
52661991Sheppo  */
52671991Sheppo int
52681991Sheppo ldc_mem_info(ldc_mem_handle_t mhandle, ldc_mem_info_t *minfo)
52691991Sheppo {
52701991Sheppo 	ldc_mhdl_t	*mhdl;
52711991Sheppo 
52721991Sheppo 	if (mhandle == NULL) {
52731991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_mem_info: invalid memory handle\n");
52741991Sheppo 		return (EINVAL);
52751991Sheppo 	}
52761991Sheppo 	mhdl = (ldc_mhdl_t *)mhandle;
52771991Sheppo 
52781991Sheppo 	if (minfo == NULL) {
52791991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_mem_info: invalid args\n");
52801991Sheppo 		return (EINVAL);
52811991Sheppo 	}
52821991Sheppo 
52831991Sheppo 	mutex_enter(&mhdl->lock);
52841991Sheppo 
52851991Sheppo 	minfo->status = mhdl->status;
52861991Sheppo 	if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED) {
52871991Sheppo 		minfo->vaddr = mhdl->memseg->vaddr;
52881991Sheppo 		minfo->raddr = mhdl->memseg->raddr;
52891991Sheppo 		minfo->mtype = mhdl->mtype;
52901991Sheppo 		minfo->perm = mhdl->perm;
52911991Sheppo 	}
52921991Sheppo 	mutex_exit(&mhdl->lock);
52931991Sheppo 
52941991Sheppo 	return (0);
52951991Sheppo }
52961991Sheppo 
52971991Sheppo /*
52981991Sheppo  * Copy data either from or to the client specified virtual address
52991991Sheppo  * space to or from the exported memory associated with the cookies.
53001991Sheppo  * The direction argument determines whether the data is read from or
53011991Sheppo  * written to exported memory.
53021991Sheppo  */
53031991Sheppo int
53041991Sheppo ldc_mem_copy(ldc_handle_t handle, caddr_t vaddr, uint64_t off, size_t *size,
53051991Sheppo     ldc_mem_cookie_t *cookies, uint32_t ccount, uint8_t direction)
53061991Sheppo {
53071991Sheppo 	ldc_chan_t 	*ldcp;
53081991Sheppo 	uint64_t	local_voff, local_valign;
53091991Sheppo 	uint64_t	cookie_addr, cookie_size;
53101991Sheppo 	uint64_t	pg_shift, pg_size, pg_size_code;
53111991Sheppo 	uint64_t 	export_caddr, export_poff, export_psize, export_size;
53121991Sheppo 	uint64_t	local_ra, local_poff, local_psize;
53131991Sheppo 	uint64_t	copy_size, copied_len = 0, total_bal = 0, idx = 0;
53141991Sheppo 	pgcnt_t		npages;
53151991Sheppo 	size_t		len = *size;
53161991Sheppo 	int 		i, rv = 0;
53171991Sheppo 
53182793Slm66018 	uint64_t	chid;
53192793Slm66018 
53201991Sheppo 	if (handle == NULL) {
53211991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_mem_copy: invalid channel handle\n");
53221991Sheppo 		return (EINVAL);
53231991Sheppo 	}
53241991Sheppo 	ldcp = (ldc_chan_t *)handle;
53252793Slm66018 	chid = ldcp->id;
53261991Sheppo 
53271991Sheppo 	/* check to see if channel is UP */
53281991Sheppo 	if (ldcp->tstate != TS_UP) {
53292793Slm66018 		DWARN(chid, "ldc_mem_copy: (0x%llx) channel is not UP\n",
53302793Slm66018 		    chid);
53312793Slm66018 		return (ECONNRESET);
53321991Sheppo 	}
53331991Sheppo 
53341991Sheppo 	/* Force address and size to be 8-byte aligned */
53351991Sheppo 	if ((((uintptr_t)vaddr | len) & 0x7) != 0) {
53362793Slm66018 		DWARN(chid,
53371991Sheppo 		    "ldc_mem_copy: addr/sz is not 8-byte aligned\n");
53381991Sheppo 		return (EINVAL);
53391991Sheppo 	}
53401991Sheppo 
53411991Sheppo 	/* Find the size of the exported memory */
53421991Sheppo 	export_size = 0;
53431991Sheppo 	for (i = 0; i < ccount; i++)
53441991Sheppo 		export_size += cookies[i].size;
53451991Sheppo 
53461991Sheppo 	/* check to see if offset is valid */
53471991Sheppo 	if (off > export_size) {
53482793Slm66018 		DWARN(chid,
53491991Sheppo 		    "ldc_mem_copy: (0x%llx) start offset > export mem size\n",
53502793Slm66018 		    chid);
53511991Sheppo 		return (EINVAL);
53521991Sheppo 	}
53531991Sheppo 
53541991Sheppo 	/*
53551991Sheppo 	 * Check to see if the export size is smaller than the size we
53561991Sheppo 	 * are requesting to copy - if so flag an error
53571991Sheppo 	 */
53581991Sheppo 	if ((export_size - off) < *size) {
53592793Slm66018 		DWARN(chid,
53601991Sheppo 		    "ldc_mem_copy: (0x%llx) copy size > export mem size\n",
53612793Slm66018 		    chid);
53621991Sheppo 		return (EINVAL);
53631991Sheppo 	}
53641991Sheppo 
53651991Sheppo 	total_bal = min(export_size, *size);
53661991Sheppo 
53671991Sheppo 	/* FUTURE: get the page size, pgsz code, and shift */
53681991Sheppo 	pg_size = MMU_PAGESIZE;
53691991Sheppo 	pg_size_code = page_szc(pg_size);
53701991Sheppo 	pg_shift = page_get_shift(pg_size_code);
53711991Sheppo 
53722793Slm66018 	D1(chid, "ldc_mem_copy: copying data "
53731991Sheppo 	    "(0x%llx) va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n",
53742793Slm66018 	    chid, vaddr, pg_size, pg_size_code, pg_shift);
53751991Sheppo 
53761991Sheppo 	/* aligned VA and its offset */
53771991Sheppo 	local_valign = (((uintptr_t)vaddr) & ~(pg_size - 1));
53781991Sheppo 	local_voff = ((uintptr_t)vaddr) & (pg_size - 1);
53791991Sheppo 
53801991Sheppo 	npages = (len+local_voff)/pg_size;
53811991Sheppo 	npages = ((len+local_voff)%pg_size == 0) ? npages : npages+1;
53821991Sheppo 
53832793Slm66018 	D1(chid,
53841991Sheppo 	    "ldc_mem_copy: (0x%llx) v=0x%llx,val=0x%llx,off=0x%x,pgs=0x%x\n",
53852793Slm66018 	    chid, vaddr, local_valign, local_voff, npages);
53861991Sheppo 
53871991Sheppo 	local_ra = va_to_pa((void *)local_valign);
53881991Sheppo 	local_poff = local_voff;
53891991Sheppo 	local_psize = min(len, (pg_size - local_voff));
53901991Sheppo 
53911991Sheppo 	len -= local_psize;
53921991Sheppo 
53931991Sheppo 	/*
53941991Sheppo 	 * find the first cookie in the list of cookies
53951991Sheppo 	 * if the offset passed in is not zero
53961991Sheppo 	 */
53971991Sheppo 	for (idx = 0; idx < ccount; idx++) {
53981991Sheppo 		cookie_size = cookies[idx].size;
53991991Sheppo 		if (off < cookie_size)
54001991Sheppo 			break;
54011991Sheppo 		off -= cookie_size;
54021991Sheppo 	}
54031991Sheppo 
54041991Sheppo 	cookie_addr = cookies[idx].addr + off;
54051991Sheppo 	cookie_size = cookies[idx].size - off;
54061991Sheppo 
54071991Sheppo 	export_caddr = cookie_addr & ~(pg_size - 1);
54081991Sheppo 	export_poff = cookie_addr & (pg_size - 1);
54091991Sheppo 	export_psize = min(cookie_size, (pg_size - export_poff));
54101991Sheppo 
54111991Sheppo 	for (;;) {
54121991Sheppo 
54131991Sheppo 		copy_size = min(export_psize, local_psize);
54141991Sheppo 
54152793Slm66018 		D1(chid,
54161991Sheppo 		    "ldc_mem_copy:(0x%llx) dir=0x%x, caddr=0x%llx,"
54171991Sheppo 		    " loc_ra=0x%llx, exp_poff=0x%llx, loc_poff=0x%llx,"
54181991Sheppo 		    " exp_psz=0x%llx, loc_psz=0x%llx, copy_sz=0x%llx,"
54191991Sheppo 		    " total_bal=0x%llx\n",
54202793Slm66018 		    chid, direction, export_caddr, local_ra, export_poff,
54211991Sheppo 		    local_poff, export_psize, local_psize, copy_size,
54221991Sheppo 		    total_bal);
54231991Sheppo 
54242793Slm66018 		rv = hv_ldc_copy(chid, direction,
54251991Sheppo 		    (export_caddr + export_poff), (local_ra + local_poff),
54261991Sheppo 		    copy_size, &copied_len);
54271991Sheppo 
54281991Sheppo 		if (rv != 0) {
54292793Slm66018 			int 		error = EIO;
54302793Slm66018 			uint64_t	rx_hd, rx_tl;
54312793Slm66018 
54322793Slm66018 			DWARN(chid,
54332793Slm66018 			    "ldc_mem_copy: (0x%llx) err %d during copy\n",
54342793Slm66018 			    (unsigned long long)chid, rv);
54352793Slm66018 			DWARN(chid,
54362793Slm66018 			    "ldc_mem_copy: (0x%llx) dir=0x%x, caddr=0x%lx, "
54372531Snarayan 			    "loc_ra=0x%lx, exp_poff=0x%lx, loc_poff=0x%lx,"
54382531Snarayan 			    " exp_psz=0x%lx, loc_psz=0x%lx, copy_sz=0x%lx,"
54392531Snarayan 			    " copied_len=0x%lx, total_bal=0x%lx\n",
54402793Slm66018 			    chid, direction, export_caddr, local_ra,
54411991Sheppo 			    export_poff, local_poff, export_psize, local_psize,
54421991Sheppo 			    copy_size, copied_len, total_bal);
54431991Sheppo 
54441991Sheppo 			*size = *size - total_bal;
54452793Slm66018 
54462793Slm66018 			/*
54472793Slm66018 			 * check if reason for copy error was due to
54482793Slm66018 			 * a channel reset. we need to grab the lock
54492793Slm66018 			 * just in case we have to do a reset.
54502793Slm66018 			 */
54512793Slm66018 			mutex_enter(&ldcp->lock);
54522793Slm66018 			mutex_enter(&ldcp->tx_lock);
54532793Slm66018 
54542793Slm66018 			rv = hv_ldc_rx_get_state(ldcp->id,
54552793Slm66018 			    &rx_hd, &rx_tl, &(ldcp->link_state));
54562793Slm66018 			if (ldcp->link_state == LDC_CHANNEL_DOWN ||
54572793Slm66018 			    ldcp->link_state == LDC_CHANNEL_RESET) {
54582793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
54592793Slm66018 				error = ECONNRESET;
54602793Slm66018 			}
54612793Slm66018 
54622793Slm66018 			mutex_exit(&ldcp->tx_lock);
54631991Sheppo 			mutex_exit(&ldcp->lock);
54642793Slm66018 
54652793Slm66018 			return (error);
54661991Sheppo 		}
54671991Sheppo 
54681991Sheppo 		ASSERT(copied_len <= copy_size);
54691991Sheppo 
54702793Slm66018 		D2(chid, "ldc_mem_copy: copied=0x%llx\n", copied_len);
54711991Sheppo 		export_poff += copied_len;
54721991Sheppo 		local_poff += copied_len;
54731991Sheppo 		export_psize -= copied_len;
54741991Sheppo 		local_psize -= copied_len;
54751991Sheppo 		cookie_size -= copied_len;
54761991Sheppo 
54771991Sheppo 		total_bal -= copied_len;
54781991Sheppo 
54791991Sheppo 		if (copy_size != copied_len)
54801991Sheppo 			continue;
54811991Sheppo 
54821991Sheppo 		if (export_psize == 0 && total_bal != 0) {
54831991Sheppo 
54841991Sheppo 			if (cookie_size == 0) {
54851991Sheppo 				idx++;
54861991Sheppo 				cookie_addr = cookies[idx].addr;
54871991Sheppo 				cookie_size = cookies[idx].size;
54881991Sheppo 
54891991Sheppo 				export_caddr = cookie_addr & ~(pg_size - 1);
54901991Sheppo 				export_poff = cookie_addr & (pg_size - 1);
54911991Sheppo 				export_psize =
54924690Snarayan 				    min(cookie_size, (pg_size-export_poff));
54931991Sheppo 			} else {
54941991Sheppo 				export_caddr += pg_size;
54951991Sheppo 				export_poff = 0;
54961991Sheppo 				export_psize = min(cookie_size, pg_size);
54971991Sheppo 			}
54981991Sheppo 		}
54991991Sheppo 
55001991Sheppo 		if (local_psize == 0 && total_bal != 0) {
55011991Sheppo 			local_valign += pg_size;
55021991Sheppo 			local_ra = va_to_pa((void *)local_valign);
55031991Sheppo 			local_poff = 0;
55041991Sheppo 			local_psize = min(pg_size, len);
55051991Sheppo 			len -= local_psize;
55061991Sheppo 		}
55071991Sheppo 
55081991Sheppo 		/* check if we are all done */
55091991Sheppo 		if (total_bal == 0)
55101991Sheppo 			break;
55111991Sheppo 	}
55121991Sheppo 
55132793Slm66018 
55142793Slm66018 	D1(chid,
55151991Sheppo 	    "ldc_mem_copy: (0x%llx) done copying sz=0x%llx\n",
55162793Slm66018 	    chid, *size);
55171991Sheppo 
55181991Sheppo 	return (0);
55191991Sheppo }
55201991Sheppo 
55211991Sheppo /*
55221991Sheppo  * Copy data either from or to the client specified virtual address
55231991Sheppo  * space to or from HV physical memory.
55241991Sheppo  *
55251991Sheppo  * The direction argument determines whether the data is read from or
55261991Sheppo  * written to HV memory. direction values are LDC_COPY_IN/OUT similar
55271991Sheppo  * to the ldc_mem_copy interface
55281991Sheppo  */
55291991Sheppo int
55302793Slm66018 ldc_mem_rdwr_cookie(ldc_handle_t handle, caddr_t vaddr, size_t *size,
55311991Sheppo     caddr_t paddr, uint8_t direction)
55321991Sheppo {
55331991Sheppo 	ldc_chan_t 	*ldcp;
55341991Sheppo 	uint64_t	local_voff, local_valign;
55351991Sheppo 	uint64_t	pg_shift, pg_size, pg_size_code;
55361991Sheppo 	uint64_t 	target_pa, target_poff, target_psize, target_size;
55371991Sheppo 	uint64_t	local_ra, local_poff, local_psize;
55381991Sheppo 	uint64_t	copy_size, copied_len = 0;
55391991Sheppo 	pgcnt_t		npages;
55401991Sheppo 	size_t		len = *size;
55411991Sheppo 	int 		rv = 0;
55421991Sheppo 
55431991Sheppo 	if (handle == NULL) {
55441991Sheppo 		DWARN(DBG_ALL_LDCS,
55452793Slm66018 		    "ldc_mem_rdwr_cookie: invalid channel handle\n");
55461991Sheppo 		return (EINVAL);
55471991Sheppo 	}
55481991Sheppo 	ldcp = (ldc_chan_t *)handle;
55491991Sheppo 
55501991Sheppo 	mutex_enter(&ldcp->lock);
55511991Sheppo 
55521991Sheppo 	/* check to see if channel is UP */
55531991Sheppo 	if (ldcp->tstate != TS_UP) {
55541991Sheppo 		DWARN(ldcp->id,
55552793Slm66018 		    "ldc_mem_rdwr_cookie: (0x%llx) channel is not UP\n",
55561991Sheppo 		    ldcp->id);
55571991Sheppo 		mutex_exit(&ldcp->lock);
55582793Slm66018 		return (ECONNRESET);
55591991Sheppo 	}
55601991Sheppo 
55611991Sheppo 	/* Force address and size to be 8-byte aligned */
55621991Sheppo 	if ((((uintptr_t)vaddr | len) & 0x7) != 0) {
55631991Sheppo 		DWARN(ldcp->id,
55642793Slm66018 		    "ldc_mem_rdwr_cookie: addr/size is not 8-byte aligned\n");
55651991Sheppo 		mutex_exit(&ldcp->lock);
55661991Sheppo 		return (EINVAL);
55671991Sheppo 	}
55681991Sheppo 
55691991Sheppo 	target_size = *size;
55701991Sheppo 
55711991Sheppo 	/* FUTURE: get the page size, pgsz code, and shift */
55721991Sheppo 	pg_size = MMU_PAGESIZE;
55731991Sheppo 	pg_size_code = page_szc(pg_size);
55741991Sheppo 	pg_shift = page_get_shift(pg_size_code);
55751991Sheppo 
55762793Slm66018 	D1(ldcp->id, "ldc_mem_rdwr_cookie: copying data "
55771991Sheppo 	    "(0x%llx) va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n",
55781991Sheppo 	    ldcp->id, vaddr, pg_size, pg_size_code, pg_shift);
55791991Sheppo 
55801991Sheppo 	/* aligned VA and its offset */
55811991Sheppo 	local_valign = ((uintptr_t)vaddr) & ~(pg_size - 1);
55821991Sheppo 	local_voff = ((uintptr_t)vaddr) & (pg_size - 1);
55831991Sheppo 
55841991Sheppo 	npages = (len + local_voff) / pg_size;
55851991Sheppo 	npages = ((len + local_voff) % pg_size == 0) ? npages : npages+1;
55861991Sheppo 
55872793Slm66018 	D1(ldcp->id, "ldc_mem_rdwr_cookie: (0x%llx) v=0x%llx, "
55882793Slm66018 	    "val=0x%llx,off=0x%x,pgs=0x%x\n",
55891991Sheppo 	    ldcp->id, vaddr, local_valign, local_voff, npages);
55901991Sheppo 
55911991Sheppo 	local_ra = va_to_pa((void *)local_valign);
55921991Sheppo 	local_poff = local_voff;
55931991Sheppo 	local_psize = min(len, (pg_size - local_voff));
55941991Sheppo 
55951991Sheppo 	len -= local_psize;
55961991Sheppo 
55971991Sheppo 	target_pa = ((uintptr_t)paddr) & ~(pg_size - 1);
55981991Sheppo 	target_poff = ((uintptr_t)paddr) & (pg_size - 1);
55991991Sheppo 	target_psize = pg_size - target_poff;
56001991Sheppo 
56011991Sheppo 	for (;;) {
56021991Sheppo 
56031991Sheppo 		copy_size = min(target_psize, local_psize);
56041991Sheppo 
56051991Sheppo 		D1(ldcp->id,
56062793Slm66018 		    "ldc_mem_rdwr_cookie: (0x%llx) dir=0x%x, tar_pa=0x%llx,"
56071991Sheppo 		    " loc_ra=0x%llx, tar_poff=0x%llx, loc_poff=0x%llx,"
56081991Sheppo 		    " tar_psz=0x%llx, loc_psz=0x%llx, copy_sz=0x%llx,"
56091991Sheppo 		    " total_bal=0x%llx\n",
56101991Sheppo 		    ldcp->id, direction, target_pa, local_ra, target_poff,
56111991Sheppo 		    local_poff, target_psize, local_psize, copy_size,
56121991Sheppo 		    target_size);
56131991Sheppo 
56141991Sheppo 		rv = hv_ldc_copy(ldcp->id, direction,
56151991Sheppo 		    (target_pa + target_poff), (local_ra + local_poff),
56161991Sheppo 		    copy_size, &copied_len);
56171991Sheppo 
56181991Sheppo 		if (rv != 0) {
56192793Slm66018 			DWARN(DBG_ALL_LDCS,
56202793Slm66018 			    "ldc_mem_rdwr_cookie: (0x%lx) err %d during copy\n",
56211991Sheppo 			    ldcp->id, rv);
56221991Sheppo 			DWARN(DBG_ALL_LDCS,
56232793Slm66018 			    "ldc_mem_rdwr_cookie: (0x%llx) dir=%lld, "
56242793Slm66018 			    "tar_pa=0x%llx, loc_ra=0x%llx, tar_poff=0x%llx, "
56252793Slm66018 			    "loc_poff=0x%llx, tar_psz=0x%llx, loc_psz=0x%llx, "
56262793Slm66018 			    "copy_sz=0x%llx, total_bal=0x%llx\n",
56271991Sheppo 			    ldcp->id, direction, target_pa, local_ra,
56281991Sheppo 			    target_poff, local_poff, target_psize, local_psize,
56291991Sheppo 			    copy_size, target_size);
56301991Sheppo 
56311991Sheppo 			*size = *size - target_size;
56321991Sheppo 			mutex_exit(&ldcp->lock);
56331991Sheppo 			return (i_ldc_h2v_error(rv));
56341991Sheppo 		}
56351991Sheppo 
56362793Slm66018 		D2(ldcp->id, "ldc_mem_rdwr_cookie: copied=0x%llx\n",
56372793Slm66018 		    copied_len);
56381991Sheppo 		target_poff += copied_len;
56391991Sheppo 		local_poff += copied_len;
56401991Sheppo 		target_psize -= copied_len;
56411991Sheppo 		local_psize -= copied_len;
56421991Sheppo 
56431991Sheppo 		target_size -= copied_len;
56441991Sheppo 
56451991Sheppo 		if (copy_size != copied_len)
56461991Sheppo 			continue;
56471991Sheppo 
56481991Sheppo 		if (target_psize == 0 && target_size != 0) {
56491991Sheppo 			target_pa += pg_size;
56501991Sheppo 			target_poff = 0;
56511991Sheppo 			target_psize = min(pg_size, target_size);
56521991Sheppo 		}
56531991Sheppo 
56541991Sheppo 		if (local_psize == 0 && target_size != 0) {
56551991Sheppo 			local_valign += pg_size;
56561991Sheppo 			local_ra = va_to_pa((void *)local_valign);
56571991Sheppo 			local_poff = 0;
56581991Sheppo 			local_psize = min(pg_size, len);
56591991Sheppo 			len -= local_psize;
56601991Sheppo 		}
56611991Sheppo 
56621991Sheppo 		/* check if we are all done */
56631991Sheppo 		if (target_size == 0)
56641991Sheppo 			break;
56651991Sheppo 	}
56661991Sheppo 
56671991Sheppo 	mutex_exit(&ldcp->lock);
56681991Sheppo 
56692793Slm66018 	D1(ldcp->id, "ldc_mem_rdwr_cookie: (0x%llx) done copying sz=0x%llx\n",
56701991Sheppo 	    ldcp->id, *size);
56711991Sheppo 
56721991Sheppo 	return (0);
56731991Sheppo }
56741991Sheppo 
56751991Sheppo /*
56761991Sheppo  * Map an exported memory segment into the local address space. If the
56771991Sheppo  * memory range was exported for direct map access, a HV call is made
56781991Sheppo  * to allocate a RA range. If the map is done via a shadow copy, local
56791991Sheppo  * shadow memory is allocated and the base VA is returned in 'vaddr'. If
56801991Sheppo  * the mapping is a direct map then the RA is returned in 'raddr'.
56811991Sheppo  */
56821991Sheppo int
56831991Sheppo ldc_mem_map(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie, uint32_t ccount,
56842531Snarayan     uint8_t mtype, uint8_t perm, caddr_t *vaddr, caddr_t *raddr)
56851991Sheppo {
56862531Snarayan 	int		i, j, idx, rv, retries;
56871991Sheppo 	ldc_chan_t 	*ldcp;
56881991Sheppo 	ldc_mhdl_t	*mhdl;
56891991Sheppo 	ldc_memseg_t	*memseg;
56902531Snarayan 	caddr_t		tmpaddr;
56912531Snarayan 	uint64_t	map_perm = perm;
56922531Snarayan 	uint64_t	pg_size, pg_shift, pg_size_code, pg_mask;
56932531Snarayan 	uint64_t	exp_size = 0, base_off, map_size, npages;
56942531Snarayan 	uint64_t	cookie_addr, cookie_off, cookie_size;
56952531Snarayan 	tte_t		ldc_tte;
56961991Sheppo 
56971991Sheppo 	if (mhandle == NULL) {
56981991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_mem_map: invalid memory handle\n");
56991991Sheppo 		return (EINVAL);
57001991Sheppo 	}
57011991Sheppo 	mhdl = (ldc_mhdl_t *)mhandle;
57021991Sheppo 
57031991Sheppo 	mutex_enter(&mhdl->lock);
57041991Sheppo 
57051991Sheppo 	if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED ||
57061991Sheppo 	    mhdl->memseg != NULL) {
57071991Sheppo 		DWARN(DBG_ALL_LDCS,
57081991Sheppo 		    "ldc_mem_map: (0x%llx) handle bound/mapped\n", mhandle);
57091991Sheppo 		mutex_exit(&mhdl->lock);
57101991Sheppo 		return (EINVAL);
57111991Sheppo 	}
57121991Sheppo 
57131991Sheppo 	ldcp = mhdl->ldcp;
57141991Sheppo 
57151991Sheppo 	mutex_enter(&ldcp->lock);
57161991Sheppo 
57171991Sheppo 	if (ldcp->tstate != TS_UP) {
57181991Sheppo 		DWARN(ldcp->id,
57191991Sheppo 		    "ldc_mem_dring_map: (0x%llx) channel is not UP\n",
57201991Sheppo 		    ldcp->id);
57211991Sheppo 		mutex_exit(&ldcp->lock);
57221991Sheppo 		mutex_exit(&mhdl->lock);
57232793Slm66018 		return (ECONNRESET);
57241991Sheppo 	}
57251991Sheppo 
57261991Sheppo 	if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP|LDC_IO_MAP)) == 0) {
57271991Sheppo 		DWARN(ldcp->id, "ldc_mem_map: invalid map type\n");
57281991Sheppo 		mutex_exit(&ldcp->lock);
57291991Sheppo 		mutex_exit(&mhdl->lock);
57301991Sheppo 		return (EINVAL);
57311991Sheppo 	}
57321991Sheppo 
57331991Sheppo 	D1(ldcp->id, "ldc_mem_map: (0x%llx) cookie = 0x%llx,0x%llx\n",
57342336Snarayan 	    ldcp->id, cookie->addr, cookie->size);
57351991Sheppo 
57361991Sheppo 	/* FUTURE: get the page size, pgsz code, and shift */
57371991Sheppo 	pg_size = MMU_PAGESIZE;
57381991Sheppo 	pg_size_code = page_szc(pg_size);
57391991Sheppo 	pg_shift = page_get_shift(pg_size_code);
57402531Snarayan 	pg_mask = ~(pg_size - 1);
57411991Sheppo 
57421991Sheppo 	/* calculate the number of pages in the exported cookie */
57432531Snarayan 	base_off = cookie[0].addr & (pg_size - 1);
57442531Snarayan 	for (idx = 0; idx < ccount; idx++)
57451991Sheppo 		exp_size += cookie[idx].size;
57462531Snarayan 	map_size = P2ROUNDUP((exp_size + base_off), pg_size);
57472531Snarayan 	npages = (map_size >> pg_shift);
57481991Sheppo 
57491991Sheppo 	/* Allocate memseg structure */
57502531Snarayan 	memseg = mhdl->memseg =
57514690Snarayan 	    kmem_cache_alloc(ldcssp->memseg_cache, KM_SLEEP);
57521991Sheppo 
57531991Sheppo 	/* Allocate memory to store all pages and cookies */
57541991Sheppo 	memseg->pages =	kmem_zalloc((sizeof (ldc_page_t) * npages), KM_SLEEP);
57551991Sheppo 	memseg->cookies =
57564690Snarayan 	    kmem_zalloc((sizeof (ldc_mem_cookie_t) * ccount), KM_SLEEP);
57571991Sheppo 
57582531Snarayan 	D2(ldcp->id, "ldc_mem_map: (0x%llx) exp_size=0x%llx, map_size=0x%llx,"
57592531Snarayan 	    "pages=0x%llx\n", ldcp->id, exp_size, map_size, npages);
57602531Snarayan 
57612531Snarayan 	/*
57622531Snarayan 	 * Check if direct map over shared memory is enabled, if not change
57632531Snarayan 	 * the mapping type to SHADOW_MAP.
57642531Snarayan 	 */
57652531Snarayan 	if (ldc_shmem_enabled == 0)
57662531Snarayan 		mtype = LDC_SHADOW_MAP;
57672531Snarayan 
57682531Snarayan 	/*
57692531Snarayan 	 * Check to see if the client is requesting direct or shadow map
57702531Snarayan 	 * If direct map is requested, try to map remote memory first,
57712531Snarayan 	 * and if that fails, revert to shadow map
57722531Snarayan 	 */
57732531Snarayan 	if (mtype == LDC_DIRECT_MAP) {
57742531Snarayan 
57752531Snarayan 		/* Allocate kernel virtual space for mapping */
57762531Snarayan 		memseg->vaddr = vmem_xalloc(heap_arena, map_size,
57772531Snarayan 		    pg_size, 0, 0, NULL, NULL, VM_NOSLEEP);
57782531Snarayan 		if (memseg->vaddr == NULL) {
57792531Snarayan 			cmn_err(CE_WARN,
57802531Snarayan 			    "ldc_mem_map: (0x%lx) memory map failed\n",
57812531Snarayan 			    ldcp->id);
57822531Snarayan 			kmem_free(memseg->cookies,
57832531Snarayan 			    (sizeof (ldc_mem_cookie_t) * ccount));
57842531Snarayan 			kmem_free(memseg->pages,
57852531Snarayan 			    (sizeof (ldc_page_t) * npages));
57862531Snarayan 			kmem_cache_free(ldcssp->memseg_cache, memseg);
57872531Snarayan 
57882531Snarayan 			mutex_exit(&ldcp->lock);
57892531Snarayan 			mutex_exit(&mhdl->lock);
57902531Snarayan 			return (ENOMEM);
57912531Snarayan 		}
57922531Snarayan 
57932531Snarayan 		/* Unload previous mapping */
57942531Snarayan 		hat_unload(kas.a_hat, memseg->vaddr, map_size,
57952531Snarayan 		    HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK);
57962531Snarayan 
57972531Snarayan 		/* for each cookie passed in - map into address space */
57982531Snarayan 		idx = 0;
57992531Snarayan 		cookie_size = 0;
58002531Snarayan 		tmpaddr = memseg->vaddr;
58012531Snarayan 
58022531Snarayan 		for (i = 0; i < npages; i++) {
58032531Snarayan 
58042531Snarayan 			if (cookie_size == 0) {
58052531Snarayan 				ASSERT(idx < ccount);
58062531Snarayan 				cookie_addr = cookie[idx].addr & pg_mask;
58072531Snarayan 				cookie_off = cookie[idx].addr & (pg_size - 1);
58082531Snarayan 				cookie_size =
58092531Snarayan 				    P2ROUNDUP((cookie_off + cookie[idx].size),
58104690Snarayan 				    pg_size);
58112531Snarayan 				idx++;
58122531Snarayan 			}
58132531Snarayan 
58142531Snarayan 			D1(ldcp->id, "ldc_mem_map: (0x%llx) mapping "
58152531Snarayan 			    "cookie 0x%llx, bal=0x%llx\n", ldcp->id,
58162531Snarayan 			    cookie_addr, cookie_size);
58172531Snarayan 
58182531Snarayan 			/* map the cookie into address space */
58192531Snarayan 			for (retries = 0; retries < ldc_max_retries;
58202531Snarayan 			    retries++) {
58212531Snarayan 
58222531Snarayan 				rv = hv_ldc_mapin(ldcp->id, cookie_addr,
58232531Snarayan 				    &memseg->pages[i].raddr, &map_perm);
58242531Snarayan 				if (rv != H_EWOULDBLOCK && rv != H_ETOOMANY)
58252531Snarayan 					break;
58262531Snarayan 
58272531Snarayan 				drv_usecwait(ldc_delay);
58282531Snarayan 			}
58292531Snarayan 
58302531Snarayan 			if (rv || memseg->pages[i].raddr == 0) {
58312531Snarayan 				DWARN(ldcp->id,
58322531Snarayan 				    "ldc_mem_map: (0x%llx) hv mapin err %d\n",
58332531Snarayan 				    ldcp->id, rv);
58342531Snarayan 
58352531Snarayan 				/* remove previous mapins */
58362531Snarayan 				hat_unload(kas.a_hat, memseg->vaddr, map_size,
58372531Snarayan 				    HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK);
58382531Snarayan 				for (j = 0; j < i; j++) {
58392531Snarayan 					rv = hv_ldc_unmap(
58404690Snarayan 					    memseg->pages[j].raddr);
58412531Snarayan 					if (rv) {
58422531Snarayan 						DWARN(ldcp->id,
58432531Snarayan 						    "ldc_mem_map: (0x%llx) "
58442531Snarayan 						    "cannot unmap ra=0x%llx\n",
58454690Snarayan 						    ldcp->id,
58462531Snarayan 						    memseg->pages[j].raddr);
58472531Snarayan 					}
58482531Snarayan 				}
58492531Snarayan 
58502531Snarayan 				/* free kernel virtual space */
58512531Snarayan 				vmem_free(heap_arena, (void *)memseg->vaddr,
58522748Slm66018 				    map_size);
58532531Snarayan 
58542531Snarayan 				/* direct map failed - revert to shadow map */
58552531Snarayan 				mtype = LDC_SHADOW_MAP;
58562531Snarayan 				break;
58572531Snarayan 
58582531Snarayan 			} else {
58592531Snarayan 
58602531Snarayan 				D1(ldcp->id,
58612531Snarayan 				    "ldc_mem_map: (0x%llx) vtop map 0x%llx -> "
58622531Snarayan 				    "0x%llx, cookie=0x%llx, perm=0x%llx\n",
58632531Snarayan 				    ldcp->id, tmpaddr, memseg->pages[i].raddr,
58642531Snarayan 				    cookie_addr, perm);
58652531Snarayan 
58662531Snarayan 				/*
58672531Snarayan 				 * NOTE: Calling hat_devload directly, causes it
58682531Snarayan 				 * to look for page_t using the pfn. Since this
58692531Snarayan 				 * addr is greater than the memlist, it treates
58702531Snarayan 				 * it as non-memory
58712531Snarayan 				 */
58722531Snarayan 				sfmmu_memtte(&ldc_tte,
58732531Snarayan 				    (pfn_t)(memseg->pages[i].raddr >> pg_shift),
58742531Snarayan 				    PROT_READ | PROT_WRITE | HAT_NOSYNC, TTE8K);
58752531Snarayan 
58762531Snarayan 				D1(ldcp->id,
58772531Snarayan 				    "ldc_mem_map: (0x%llx) ra 0x%llx -> "
58782531Snarayan 				    "tte 0x%llx\n", ldcp->id,
58792531Snarayan 				    memseg->pages[i].raddr, ldc_tte);
58802531Snarayan 
58812531Snarayan 				sfmmu_tteload(kas.a_hat, &ldc_tte, tmpaddr,
58822531Snarayan 				    NULL, HAT_LOAD_LOCK);
58832531Snarayan 
58842531Snarayan 				cookie_size -= pg_size;
58852531Snarayan 				cookie_addr += pg_size;
58862531Snarayan 				tmpaddr += pg_size;
58872531Snarayan 			}
58882531Snarayan 		}
58892531Snarayan 	}
58902531Snarayan 
58911991Sheppo 	if (mtype == LDC_SHADOW_MAP) {
58921991Sheppo 		if (*vaddr == NULL) {
58932793Slm66018 			memseg->vaddr = kmem_zalloc(exp_size, KM_SLEEP);
58941991Sheppo 			mhdl->myshadow = B_TRUE;
58951991Sheppo 
58961991Sheppo 			D1(ldcp->id, "ldc_mem_map: (0x%llx) allocated "
58972531Snarayan 			    "shadow page va=0x%llx\n", ldcp->id, memseg->vaddr);
58981991Sheppo 		} else {
58991991Sheppo 			/*
59002531Snarayan 			 * Use client supplied memory for memseg->vaddr
59011991Sheppo 			 * WARNING: assuming that client mem is >= exp_size
59021991Sheppo 			 */
59032531Snarayan 			memseg->vaddr = *vaddr;
59041991Sheppo 		}
59052531Snarayan 
59062531Snarayan 		/* Save all page and cookie information */
59072531Snarayan 		for (i = 0, tmpaddr = memseg->vaddr; i < npages; i++) {
59082531Snarayan 			memseg->pages[i].raddr = va_to_pa(tmpaddr);
59092531Snarayan 			memseg->pages[i].size = pg_size;
59102531Snarayan 			tmpaddr += pg_size;
59112531Snarayan 		}
59122531Snarayan 
59132531Snarayan 	}
59142531Snarayan 
59152531Snarayan 	/* save all cookies */
59162531Snarayan 	bcopy(cookie, memseg->cookies, ccount * sizeof (ldc_mem_cookie_t));
59171991Sheppo 
59181991Sheppo 	/* update memseg_t */
59191991Sheppo 	memseg->raddr = memseg->pages[0].raddr;
59202531Snarayan 	memseg->size = (mtype == LDC_SHADOW_MAP) ? exp_size : map_size;
59211991Sheppo 	memseg->npages = npages;
59221991Sheppo 	memseg->ncookies = ccount;
59231991Sheppo 	memseg->next_cookie = 0;
59241991Sheppo 
59251991Sheppo 	/* memory handle = mapped */
59261991Sheppo 	mhdl->mtype = mtype;
59272531Snarayan 	mhdl->perm = perm;
59281991Sheppo 	mhdl->status = LDC_MAPPED;
59291991Sheppo 
59301991Sheppo 	D1(ldcp->id, "ldc_mem_map: (0x%llx) mapped 0x%llx, ra=0x%llx, "
59311991Sheppo 	    "va=0x%llx, pgs=0x%llx cookies=0x%llx\n",
59321991Sheppo 	    ldcp->id, mhdl, memseg->raddr, memseg->vaddr,
59331991Sheppo 	    memseg->npages, memseg->ncookies);
59341991Sheppo 
59352531Snarayan 	if (mtype == LDC_SHADOW_MAP)
59362531Snarayan 		base_off = 0;
59371991Sheppo 	if (raddr)
59382531Snarayan 		*raddr = (caddr_t)(memseg->raddr | base_off);
59391991Sheppo 	if (vaddr)
59402531Snarayan 		*vaddr = (caddr_t)((uintptr_t)memseg->vaddr | base_off);
59411991Sheppo 
59421991Sheppo 	mutex_exit(&ldcp->lock);
59431991Sheppo 	mutex_exit(&mhdl->lock);
59441991Sheppo 	return (0);
59451991Sheppo }
59461991Sheppo 
59471991Sheppo /*
59481991Sheppo  * Unmap a memory segment. Free shadow memory (if any).
59491991Sheppo  */
59501991Sheppo int
59511991Sheppo ldc_mem_unmap(ldc_mem_handle_t mhandle)
59521991Sheppo {
59532531Snarayan 	int		i, rv;
59541991Sheppo 	ldc_mhdl_t	*mhdl = (ldc_mhdl_t *)mhandle;
59551991Sheppo 	ldc_chan_t 	*ldcp;
59561991Sheppo 	ldc_memseg_t	*memseg;
59571991Sheppo 
59581991Sheppo 	if (mhdl == 0 || mhdl->status != LDC_MAPPED) {
59591991Sheppo 		DWARN(DBG_ALL_LDCS,
59601991Sheppo 		    "ldc_mem_unmap: (0x%llx) handle is not mapped\n",
59611991Sheppo 		    mhandle);
59621991Sheppo 		return (EINVAL);
59631991Sheppo 	}
59641991Sheppo 
59651991Sheppo 	mutex_enter(&mhdl->lock);
59661991Sheppo 
59671991Sheppo 	ldcp = mhdl->ldcp;
59681991Sheppo 	memseg = mhdl->memseg;
59691991Sheppo 
59701991Sheppo 	D1(ldcp->id, "ldc_mem_unmap: (0x%llx) unmapping handle 0x%llx\n",
59711991Sheppo 	    ldcp->id, mhdl);
59721991Sheppo 
59731991Sheppo 	/* if we allocated shadow memory - free it */
59741991Sheppo 	if (mhdl->mtype == LDC_SHADOW_MAP && mhdl->myshadow) {
59752793Slm66018 		kmem_free(memseg->vaddr, memseg->size);
59762531Snarayan 	} else if (mhdl->mtype == LDC_DIRECT_MAP) {
59772531Snarayan 
59782531Snarayan 		/* unmap in the case of DIRECT_MAP */
59792531Snarayan 		hat_unload(kas.a_hat, memseg->vaddr, memseg->size,
59802531Snarayan 		    HAT_UNLOAD_UNLOCK);
59812531Snarayan 
59822531Snarayan 		for (i = 0; i < memseg->npages; i++) {
59832531Snarayan 			rv = hv_ldc_unmap(memseg->pages[i].raddr);
59842531Snarayan 			if (rv) {
59852531Snarayan 				cmn_err(CE_WARN,
59862531Snarayan 				    "ldc_mem_map: (0x%lx) hv unmap err %d\n",
59872531Snarayan 				    ldcp->id, rv);
59882531Snarayan 			}
59892531Snarayan 		}
59902531Snarayan 
59912531Snarayan 		vmem_free(heap_arena, (void *)memseg->vaddr, memseg->size);
59921991Sheppo 	}
59931991Sheppo 
59941991Sheppo 	/* free the allocated memseg and page structures */
59951991Sheppo 	kmem_free(memseg->pages, (sizeof (ldc_page_t) * memseg->npages));
59961991Sheppo 	kmem_free(memseg->cookies,
59971991Sheppo 	    (sizeof (ldc_mem_cookie_t) * memseg->ncookies));
59982531Snarayan 	kmem_cache_free(ldcssp->memseg_cache, memseg);
59991991Sheppo 
60001991Sheppo 	/* uninitialize the memory handle */
60011991Sheppo 	mhdl->memseg = NULL;
60021991Sheppo 	mhdl->status = LDC_UNBOUND;
60031991Sheppo 
60041991Sheppo 	D1(ldcp->id, "ldc_mem_unmap: (0x%llx) unmapped handle 0x%llx\n",
60051991Sheppo 	    ldcp->id, mhdl);
60061991Sheppo 
60071991Sheppo 	mutex_exit(&mhdl->lock);
60081991Sheppo 	return (0);
60091991Sheppo }
60101991Sheppo 
60111991Sheppo /*
60121991Sheppo  * Internal entry point for LDC mapped memory entry consistency
60131991Sheppo  * semantics. Acquire copies the contents of the remote memory
60141991Sheppo  * into the local shadow copy. The release operation copies the local
60151991Sheppo  * contents into the remote memory. The offset and size specify the
60161991Sheppo  * bounds for the memory range being synchronized.
60171991Sheppo  */
60181991Sheppo static int
60191991Sheppo i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle, uint8_t direction,
60201991Sheppo     uint64_t offset, size_t size)
60211991Sheppo {
60221991Sheppo 	int 		err;
60231991Sheppo 	ldc_mhdl_t	*mhdl;
60241991Sheppo 	ldc_chan_t	*ldcp;
60251991Sheppo 	ldc_memseg_t	*memseg;
60261991Sheppo 	caddr_t		local_vaddr;
60271991Sheppo 	size_t		copy_size;
60281991Sheppo 
60291991Sheppo 	if (mhandle == NULL) {
60301991Sheppo 		DWARN(DBG_ALL_LDCS,
60311991Sheppo 		    "i_ldc_mem_acquire_release: invalid memory handle\n");
60321991Sheppo 		return (EINVAL);
60331991Sheppo 	}
60341991Sheppo 	mhdl = (ldc_mhdl_t *)mhandle;
60351991Sheppo 
60361991Sheppo 	mutex_enter(&mhdl->lock);
60371991Sheppo 
60381991Sheppo 	if (mhdl->status != LDC_MAPPED || mhdl->ldcp == NULL) {
60391991Sheppo 		DWARN(DBG_ALL_LDCS,
60401991Sheppo 		    "i_ldc_mem_acquire_release: not mapped memory\n");
60411991Sheppo 		mutex_exit(&mhdl->lock);
60421991Sheppo 		return (EINVAL);
60431991Sheppo 	}
60441991Sheppo 
60452531Snarayan 	/* do nothing for direct map */
60462531Snarayan 	if (mhdl->mtype == LDC_DIRECT_MAP) {
60472531Snarayan 		mutex_exit(&mhdl->lock);
60482531Snarayan 		return (0);
60492531Snarayan 	}
60502531Snarayan 
60512531Snarayan 	/* do nothing if COPY_IN+MEM_W and COPY_OUT+MEM_R */
60522531Snarayan 	if ((direction == LDC_COPY_IN && (mhdl->perm & LDC_MEM_R) == 0) ||
60532531Snarayan 	    (direction == LDC_COPY_OUT && (mhdl->perm & LDC_MEM_W) == 0)) {
60542531Snarayan 		mutex_exit(&mhdl->lock);
60552531Snarayan 		return (0);
60562531Snarayan 	}
60572531Snarayan 
60581991Sheppo 	if (offset >= mhdl->memseg->size ||
60591991Sheppo 	    (offset + size) > mhdl->memseg->size) {
60601991Sheppo 		DWARN(DBG_ALL_LDCS,
60611991Sheppo 		    "i_ldc_mem_acquire_release: memory out of range\n");
60621991Sheppo 		mutex_exit(&mhdl->lock);
60631991Sheppo 		return (EINVAL);
60641991Sheppo 	}
60651991Sheppo 
60661991Sheppo 	/* get the channel handle and memory segment */
60671991Sheppo 	ldcp = mhdl->ldcp;
60681991Sheppo 	memseg = mhdl->memseg;
60691991Sheppo 
60701991Sheppo 	if (mhdl->mtype == LDC_SHADOW_MAP) {
60711991Sheppo 
60721991Sheppo 		local_vaddr = memseg->vaddr + offset;
60731991Sheppo 		copy_size = size;
60741991Sheppo 
60751991Sheppo 		/* copy to/from remote from/to local memory */
60761991Sheppo 		err = ldc_mem_copy((ldc_handle_t)ldcp, local_vaddr, offset,
60771991Sheppo 		    &copy_size, memseg->cookies, memseg->ncookies,
60781991Sheppo 		    direction);
60791991Sheppo 		if (err || copy_size != size) {
60803010Slm66018 			DWARN(ldcp->id,
60811991Sheppo 			    "i_ldc_mem_acquire_release: copy failed\n");
60821991Sheppo 			mutex_exit(&mhdl->lock);
60831991Sheppo 			return (err);
60841991Sheppo 		}
60851991Sheppo 	}
60861991Sheppo 
60871991Sheppo 	mutex_exit(&mhdl->lock);
60881991Sheppo 
60891991Sheppo 	return (0);
60901991Sheppo }
60911991Sheppo 
60921991Sheppo /*
60931991Sheppo  * Ensure that the contents in the remote memory seg are consistent
60941991Sheppo  * with the contents if of local segment
60951991Sheppo  */
60961991Sheppo int
60971991Sheppo ldc_mem_acquire(ldc_mem_handle_t mhandle, uint64_t offset, uint64_t size)
60981991Sheppo {
60991991Sheppo 	return (i_ldc_mem_acquire_release(mhandle, LDC_COPY_IN, offset, size));
61001991Sheppo }
61011991Sheppo 
61021991Sheppo 
61031991Sheppo /*
61041991Sheppo  * Ensure that the contents in the local memory seg are consistent
61051991Sheppo  * with the contents if of remote segment
61061991Sheppo  */
61071991Sheppo int
61081991Sheppo ldc_mem_release(ldc_mem_handle_t mhandle, uint64_t offset, uint64_t size)
61091991Sheppo {
61101991Sheppo 	return (i_ldc_mem_acquire_release(mhandle, LDC_COPY_OUT, offset, size));
61111991Sheppo }
61121991Sheppo 
61131991Sheppo /*
61141991Sheppo  * Allocate a descriptor ring. The size of each each descriptor
61151991Sheppo  * must be 8-byte aligned and the entire ring should be a multiple
61161991Sheppo  * of MMU_PAGESIZE.
61171991Sheppo  */
61181991Sheppo int
61191991Sheppo ldc_mem_dring_create(uint32_t len, uint32_t dsize, ldc_dring_handle_t *dhandle)
61201991Sheppo {
61211991Sheppo 	ldc_dring_t *dringp;
61221991Sheppo 	size_t size = (dsize * len);
61231991Sheppo 
61241991Sheppo 	D1(DBG_ALL_LDCS, "ldc_mem_dring_create: len=0x%x, size=0x%x\n",
61251991Sheppo 	    len, dsize);
61261991Sheppo 
61271991Sheppo 	if (dhandle == NULL) {
61281991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid dhandle\n");
61291991Sheppo 		return (EINVAL);
61301991Sheppo 	}
61311991Sheppo 
61321991Sheppo 	if (len == 0) {
61331991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid length\n");
61341991Sheppo 		return (EINVAL);
61351991Sheppo 	}
61361991Sheppo 
61371991Sheppo 	/* descriptor size should be 8-byte aligned */
61381991Sheppo 	if (dsize == 0 || (dsize & 0x7)) {
61391991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid size\n");
61401991Sheppo 		return (EINVAL);
61411991Sheppo 	}
61421991Sheppo 
61431991Sheppo 	*dhandle = 0;
61441991Sheppo 
61451991Sheppo 	/* Allocate a desc ring structure */
61461991Sheppo 	dringp = kmem_zalloc(sizeof (ldc_dring_t), KM_SLEEP);
61471991Sheppo 
61481991Sheppo 	/* Initialize dring */
61491991Sheppo 	dringp->length = len;
61501991Sheppo 	dringp->dsize = dsize;
61511991Sheppo 
61521991Sheppo 	/* round off to multiple of pagesize */
61531991Sheppo 	dringp->size = (size & MMU_PAGEMASK);
61541991Sheppo 	if (size & MMU_PAGEOFFSET)
61551991Sheppo 		dringp->size += MMU_PAGESIZE;
61561991Sheppo 
61571991Sheppo 	dringp->status = LDC_UNBOUND;
61581991Sheppo 
61591991Sheppo 	/* allocate descriptor ring memory */
61602793Slm66018 	dringp->base = kmem_zalloc(dringp->size, KM_SLEEP);
61611991Sheppo 
61621991Sheppo 	/* initialize the desc ring lock */
61631991Sheppo 	mutex_init(&dringp->lock, NULL, MUTEX_DRIVER, NULL);
61641991Sheppo 
61651991Sheppo 	/* Add descriptor ring to the head of global list */
61661991Sheppo 	mutex_enter(&ldcssp->lock);
61671991Sheppo 	dringp->next = ldcssp->dring_list;
61681991Sheppo 	ldcssp->dring_list = dringp;
61691991Sheppo 	mutex_exit(&ldcssp->lock);
61701991Sheppo 
61711991Sheppo 	*dhandle = (ldc_dring_handle_t)dringp;
61721991Sheppo 
61731991Sheppo 	D1(DBG_ALL_LDCS, "ldc_mem_dring_create: dring allocated\n");
61741991Sheppo 
61751991Sheppo 	return (0);
61761991Sheppo }
61771991Sheppo 
61781991Sheppo 
61791991Sheppo /*
61801991Sheppo  * Destroy a descriptor ring.
61811991Sheppo  */
61821991Sheppo int
61831991Sheppo ldc_mem_dring_destroy(ldc_dring_handle_t dhandle)
61841991Sheppo {
61851991Sheppo 	ldc_dring_t *dringp;
61861991Sheppo 	ldc_dring_t *tmp_dringp;
61871991Sheppo 
61881991Sheppo 	D1(DBG_ALL_LDCS, "ldc_mem_dring_destroy: entered\n");
61891991Sheppo 
61901991Sheppo 	if (dhandle == NULL) {
61911991Sheppo 		DWARN(DBG_ALL_LDCS,
61921991Sheppo 		    "ldc_mem_dring_destroy: invalid desc ring handle\n");
61931991Sheppo 		return (EINVAL);
61941991Sheppo 	}
61951991Sheppo 	dringp = (ldc_dring_t *)dhandle;
61961991Sheppo 
61971991Sheppo 	if (dringp->status == LDC_BOUND) {
61981991Sheppo 		DWARN(DBG_ALL_LDCS,
61991991Sheppo 		    "ldc_mem_dring_destroy: desc ring is bound\n");
62001991Sheppo 		return (EACCES);
62011991Sheppo 	}
62021991Sheppo 
62031991Sheppo 	mutex_enter(&dringp->lock);
62041991Sheppo 	mutex_enter(&ldcssp->lock);
62051991Sheppo 
62061991Sheppo 	/* remove from linked list - if not bound */
62071991Sheppo 	tmp_dringp = ldcssp->dring_list;
62081991Sheppo 	if (tmp_dringp == dringp) {
62091991Sheppo 		ldcssp->dring_list = dringp->next;
62101991Sheppo 		dringp->next = NULL;
62111991Sheppo 
62121991Sheppo 	} else {
62131991Sheppo 		while (tmp_dringp != NULL) {
62141991Sheppo 			if (tmp_dringp->next == dringp) {
62151991Sheppo 				tmp_dringp->next = dringp->next;
62161991Sheppo 				dringp->next = NULL;
62171991Sheppo 				break;
62181991Sheppo 			}
62191991Sheppo 			tmp_dringp = tmp_dringp->next;
62201991Sheppo 		}
62211991Sheppo 		if (tmp_dringp == NULL) {
62221991Sheppo 			DWARN(DBG_ALL_LDCS,
62231991Sheppo 			    "ldc_mem_dring_destroy: invalid descriptor\n");
62241991Sheppo 			mutex_exit(&ldcssp->lock);
62251991Sheppo 			mutex_exit(&dringp->lock);
62261991Sheppo 			return (EINVAL);
62271991Sheppo 		}
62281991Sheppo 	}
62291991Sheppo 
62301991Sheppo 	mutex_exit(&ldcssp->lock);
62311991Sheppo 
62321991Sheppo 	/* free the descriptor ring */
62332793Slm66018 	kmem_free(dringp->base, dringp->size);
62341991Sheppo 
62351991Sheppo 	mutex_exit(&dringp->lock);
62361991Sheppo 
62371991Sheppo 	/* destroy dring lock */
62381991Sheppo 	mutex_destroy(&dringp->lock);
62391991Sheppo 
62401991Sheppo 	/* free desc ring object */
62411991Sheppo 	kmem_free(dringp, sizeof (ldc_dring_t));
62421991Sheppo 
62431991Sheppo 	return (0);
62441991Sheppo }
62451991Sheppo 
62461991Sheppo /*
62471991Sheppo  * Bind a previously allocated dring to a channel. The channel should
62481991Sheppo  * be OPEN in order to bind the ring to the channel. Returns back a
62491991Sheppo  * descriptor ring cookie. The descriptor ring is exported for remote
62501991Sheppo  * access by the client at the other end of the channel. An entry for
62511991Sheppo  * dring pages is stored in map table (via call to ldc_mem_bind_handle).
62521991Sheppo  */
62531991Sheppo int
62541991Sheppo ldc_mem_dring_bind(ldc_handle_t handle, ldc_dring_handle_t dhandle,
62551991Sheppo     uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount)
62561991Sheppo {
62571991Sheppo 	int		err;
62581991Sheppo 	ldc_chan_t 	*ldcp;
62591991Sheppo 	ldc_dring_t	*dringp;
62601991Sheppo 	ldc_mem_handle_t mhandle;
62611991Sheppo 
62621991Sheppo 	/* check to see if channel is initalized */
62631991Sheppo 	if (handle == NULL) {
62641991Sheppo 		DWARN(DBG_ALL_LDCS,
62651991Sheppo 		    "ldc_mem_dring_bind: invalid channel handle\n");
62661991Sheppo 		return (EINVAL);
62671991Sheppo 	}
62681991Sheppo 	ldcp = (ldc_chan_t *)handle;
62691991Sheppo 
62701991Sheppo 	if (dhandle == NULL) {
62711991Sheppo 		DWARN(DBG_ALL_LDCS,
62721991Sheppo 		    "ldc_mem_dring_bind: invalid desc ring handle\n");
62731991Sheppo 		return (EINVAL);
62741991Sheppo 	}
62751991Sheppo 	dringp = (ldc_dring_t *)dhandle;
62761991Sheppo 
62771991Sheppo 	if (cookie == NULL) {
62781991Sheppo 		DWARN(ldcp->id,
62791991Sheppo 		    "ldc_mem_dring_bind: invalid cookie arg\n");
62801991Sheppo 		return (EINVAL);
62811991Sheppo 	}
62821991Sheppo 
62831991Sheppo 	mutex_enter(&dringp->lock);
62841991Sheppo 
62851991Sheppo 	if (dringp->status == LDC_BOUND) {
62861991Sheppo 		DWARN(DBG_ALL_LDCS,
62871991Sheppo 		    "ldc_mem_dring_bind: (0x%llx) descriptor ring is bound\n",
62881991Sheppo 		    ldcp->id);
62891991Sheppo 		mutex_exit(&dringp->lock);
62901991Sheppo 		return (EINVAL);
62911991Sheppo 	}
62921991Sheppo 
62931991Sheppo 	if ((perm & LDC_MEM_RW) == 0) {
62941991Sheppo 		DWARN(DBG_ALL_LDCS,
62951991Sheppo 		    "ldc_mem_dring_bind: invalid permissions\n");
62961991Sheppo 		mutex_exit(&dringp->lock);
62971991Sheppo 		return (EINVAL);
62981991Sheppo 	}
62991991Sheppo 
63001991Sheppo 	if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP|LDC_IO_MAP)) == 0) {
63011991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_mem_dring_bind: invalid type\n");
63021991Sheppo 		mutex_exit(&dringp->lock);
63031991Sheppo 		return (EINVAL);
63041991Sheppo 	}
63051991Sheppo 
63061991Sheppo 	dringp->ldcp = ldcp;
63071991Sheppo 
63081991Sheppo 	/* create an memory handle */
63091991Sheppo 	err = ldc_mem_alloc_handle(handle, &mhandle);
63101991Sheppo 	if (err || mhandle == NULL) {
63111991Sheppo 		DWARN(DBG_ALL_LDCS,
63121991Sheppo 		    "ldc_mem_dring_bind: (0x%llx) error allocating mhandle\n",
63131991Sheppo 		    ldcp->id);
63141991Sheppo 		mutex_exit(&dringp->lock);
63151991Sheppo 		return (err);
63161991Sheppo 	}
63171991Sheppo 	dringp->mhdl = mhandle;
63181991Sheppo 
63191991Sheppo 	/* bind the descriptor ring to channel */
63201991Sheppo 	err = ldc_mem_bind_handle(mhandle, dringp->base, dringp->size,
63211991Sheppo 	    mtype, perm, cookie, ccount);
63221991Sheppo 	if (err) {
63231991Sheppo 		DWARN(ldcp->id,
63241991Sheppo 		    "ldc_mem_dring_bind: (0x%llx) error binding mhandle\n",
63251991Sheppo 		    ldcp->id);
63261991Sheppo 		mutex_exit(&dringp->lock);
63271991Sheppo 		return (err);
63281991Sheppo 	}
63291991Sheppo 
63301991Sheppo 	/*
63311991Sheppo 	 * For now return error if we get more than one cookie
63321991Sheppo 	 * FUTURE: Return multiple cookies ..
63331991Sheppo 	 */
63341991Sheppo 	if (*ccount > 1) {
63351991Sheppo 		(void) ldc_mem_unbind_handle(mhandle);
63361991Sheppo 		(void) ldc_mem_free_handle(mhandle);
63371991Sheppo 
63381991Sheppo 		dringp->ldcp = NULL;
63391991Sheppo 		dringp->mhdl = NULL;
63401991Sheppo 		*ccount = 0;
63411991Sheppo 
63421991Sheppo 		mutex_exit(&dringp->lock);
63431991Sheppo 		return (EAGAIN);
63441991Sheppo 	}
63451991Sheppo 
63461991Sheppo 	/* Add descriptor ring to channel's exported dring list */
63471991Sheppo 	mutex_enter(&ldcp->exp_dlist_lock);
63481991Sheppo 	dringp->ch_next = ldcp->exp_dring_list;
63491991Sheppo 	ldcp->exp_dring_list = dringp;
63501991Sheppo 	mutex_exit(&ldcp->exp_dlist_lock);
63511991Sheppo 
63521991Sheppo 	dringp->status = LDC_BOUND;
63531991Sheppo 
63541991Sheppo 	mutex_exit(&dringp->lock);
63551991Sheppo 
63561991Sheppo 	return (0);
63571991Sheppo }
63581991Sheppo 
63591991Sheppo /*
63601991Sheppo  * Return the next cookie associated with the specified dring handle
63611991Sheppo  */
63621991Sheppo int
63631991Sheppo ldc_mem_dring_nextcookie(ldc_dring_handle_t dhandle, ldc_mem_cookie_t *cookie)
63641991Sheppo {
63651991Sheppo 	int		rv = 0;
63661991Sheppo 	ldc_dring_t 	*dringp;
63671991Sheppo 	ldc_chan_t	*ldcp;
63681991Sheppo 
63691991Sheppo 	if (dhandle == NULL) {
63701991Sheppo 		DWARN(DBG_ALL_LDCS,
63711991Sheppo 		    "ldc_mem_dring_nextcookie: invalid desc ring handle\n");
63721991Sheppo 		return (EINVAL);
63731991Sheppo 	}
63741991Sheppo 	dringp = (ldc_dring_t *)dhandle;
63751991Sheppo 	mutex_enter(&dringp->lock);
63761991Sheppo 
63771991Sheppo 	if (dringp->status != LDC_BOUND) {
63781991Sheppo 		DWARN(DBG_ALL_LDCS,
63791991Sheppo 		    "ldc_mem_dring_nextcookie: descriptor ring 0x%llx "
63801991Sheppo 		    "is not bound\n", dringp);
63811991Sheppo 		mutex_exit(&dringp->lock);
63821991Sheppo 		return (EINVAL);
63831991Sheppo 	}
63841991Sheppo 
63851991Sheppo 	ldcp = dringp->ldcp;
63861991Sheppo 
63871991Sheppo 	if (cookie == NULL) {
63881991Sheppo 		DWARN(ldcp->id,
63891991Sheppo 		    "ldc_mem_dring_nextcookie:(0x%llx) invalid cookie arg\n",
63901991Sheppo 		    ldcp->id);
63911991Sheppo 		mutex_exit(&dringp->lock);
63921991Sheppo 		return (EINVAL);
63931991Sheppo 	}
63941991Sheppo 
63951991Sheppo 	rv = ldc_mem_nextcookie((ldc_mem_handle_t)dringp->mhdl, cookie);
63961991Sheppo 	mutex_exit(&dringp->lock);
63971991Sheppo 
63981991Sheppo 	return (rv);
63991991Sheppo }
64001991Sheppo /*
64011991Sheppo  * Unbind a previously bound dring from a channel.
64021991Sheppo  */
64031991Sheppo int
64041991Sheppo ldc_mem_dring_unbind(ldc_dring_handle_t dhandle)
64051991Sheppo {
64061991Sheppo 	ldc_dring_t 	*dringp;
64071991Sheppo 	ldc_dring_t	*tmp_dringp;
64081991Sheppo 	ldc_chan_t	*ldcp;
64091991Sheppo 
64101991Sheppo 	if (dhandle == NULL) {
64111991Sheppo 		DWARN(DBG_ALL_LDCS,
64121991Sheppo 		    "ldc_mem_dring_unbind: invalid desc ring handle\n");
64131991Sheppo 		return (EINVAL);
64141991Sheppo 	}
64151991Sheppo 	dringp = (ldc_dring_t *)dhandle;
64161991Sheppo 
64171991Sheppo 	mutex_enter(&dringp->lock);
64181991Sheppo 
64191991Sheppo 	if (dringp->status == LDC_UNBOUND) {
64201991Sheppo 		DWARN(DBG_ALL_LDCS,
64211991Sheppo 		    "ldc_mem_dring_bind: descriptor ring 0x%llx is unbound\n",
64221991Sheppo 		    dringp);
64231991Sheppo 		mutex_exit(&dringp->lock);
64241991Sheppo 		return (EINVAL);
64251991Sheppo 	}
64261991Sheppo 	ldcp = dringp->ldcp;
64271991Sheppo 
64281991Sheppo 	mutex_enter(&ldcp->exp_dlist_lock);
64291991Sheppo 
64301991Sheppo 	tmp_dringp = ldcp->exp_dring_list;
64311991Sheppo 	if (tmp_dringp == dringp) {
64321991Sheppo 		ldcp->exp_dring_list = dringp->ch_next;
64331991Sheppo 		dringp->ch_next = NULL;
64341991Sheppo 
64351991Sheppo 	} else {
64361991Sheppo 		while (tmp_dringp != NULL) {
64371991Sheppo 			if (tmp_dringp->ch_next == dringp) {
64381991Sheppo 				tmp_dringp->ch_next = dringp->ch_next;
64391991Sheppo 				dringp->ch_next = NULL;
64401991Sheppo 				break;
64411991Sheppo 			}
64421991Sheppo 			tmp_dringp = tmp_dringp->ch_next;
64431991Sheppo 		}
64441991Sheppo 		if (tmp_dringp == NULL) {
64451991Sheppo 			DWARN(DBG_ALL_LDCS,
64461991Sheppo 			    "ldc_mem_dring_unbind: invalid descriptor\n");
64471991Sheppo 			mutex_exit(&ldcp->exp_dlist_lock);
64481991Sheppo 			mutex_exit(&dringp->lock);
64491991Sheppo 			return (EINVAL);
64501991Sheppo 		}
64511991Sheppo 	}
64521991Sheppo 
64531991Sheppo 	mutex_exit(&ldcp->exp_dlist_lock);
64541991Sheppo 
64551991Sheppo 	(void) ldc_mem_unbind_handle((ldc_mem_handle_t)dringp->mhdl);
64561991Sheppo 	(void) ldc_mem_free_handle((ldc_mem_handle_t)dringp->mhdl);
64571991Sheppo 
64581991Sheppo 	dringp->ldcp = NULL;
64591991Sheppo 	dringp->mhdl = NULL;
64601991Sheppo 	dringp->status = LDC_UNBOUND;
64611991Sheppo 
64621991Sheppo 	mutex_exit(&dringp->lock);
64631991Sheppo 
64641991Sheppo 	return (0);
64651991Sheppo }
64661991Sheppo 
64671991Sheppo /*
64681991Sheppo  * Get information about the dring. The base address of the descriptor
64691991Sheppo  * ring along with the type and permission are returned back.
64701991Sheppo  */
64711991Sheppo int
64721991Sheppo ldc_mem_dring_info(ldc_dring_handle_t dhandle, ldc_mem_info_t *minfo)
64731991Sheppo {
64741991Sheppo 	ldc_dring_t	*dringp;
64751991Sheppo 	int		rv;
64761991Sheppo 
64771991Sheppo 	if (dhandle == NULL) {
64781991Sheppo 		DWARN(DBG_ALL_LDCS,
64791991Sheppo 		    "ldc_mem_dring_info: invalid desc ring handle\n");
64801991Sheppo 		return (EINVAL);
64811991Sheppo 	}
64821991Sheppo 	dringp = (ldc_dring_t *)dhandle;
64831991Sheppo 
64841991Sheppo 	mutex_enter(&dringp->lock);
64851991Sheppo 
64861991Sheppo 	if (dringp->mhdl) {
64871991Sheppo 		rv = ldc_mem_info(dringp->mhdl, minfo);
64881991Sheppo 		if (rv) {
64891991Sheppo 			DWARN(DBG_ALL_LDCS,
64901991Sheppo 			    "ldc_mem_dring_info: error reading mem info\n");
64911991Sheppo 			mutex_exit(&dringp->lock);
64921991Sheppo 			return (rv);
64931991Sheppo 		}
64941991Sheppo 	} else {
64951991Sheppo 		minfo->vaddr = dringp->base;
64961991Sheppo 		minfo->raddr = NULL;
64971991Sheppo 		minfo->status = dringp->status;
64981991Sheppo 	}
64991991Sheppo 
65001991Sheppo 	mutex_exit(&dringp->lock);
65011991Sheppo 
65021991Sheppo 	return (0);
65031991Sheppo }
65041991Sheppo 
65051991Sheppo /*
65061991Sheppo  * Map an exported descriptor ring into the local address space. If the
65071991Sheppo  * descriptor ring was exported for direct map access, a HV call is made
65081991Sheppo  * to allocate a RA range. If the map is done via a shadow copy, local
65091991Sheppo  * shadow memory is allocated.
65101991Sheppo  */
65111991Sheppo int
65121991Sheppo ldc_mem_dring_map(ldc_handle_t handle, ldc_mem_cookie_t *cookie,
65131991Sheppo     uint32_t ccount, uint32_t len, uint32_t dsize, uint8_t mtype,
65141991Sheppo     ldc_dring_handle_t *dhandle)
65151991Sheppo {
65161991Sheppo 	int		err;
65171991Sheppo 	ldc_chan_t 	*ldcp = (ldc_chan_t *)handle;
65181991Sheppo 	ldc_mem_handle_t mhandle;
65191991Sheppo 	ldc_dring_t	*dringp;
65201991Sheppo 	size_t		dring_size;
65211991Sheppo 
65221991Sheppo 	if (dhandle == NULL) {
65231991Sheppo 		DWARN(DBG_ALL_LDCS,
65241991Sheppo 		    "ldc_mem_dring_map: invalid dhandle\n");
65251991Sheppo 		return (EINVAL);
65261991Sheppo 	}
65271991Sheppo 
65281991Sheppo 	/* check to see if channel is initalized */
65291991Sheppo 	if (handle == NULL) {
65301991Sheppo 		DWARN(DBG_ALL_LDCS,
65311991Sheppo 		    "ldc_mem_dring_map: invalid channel handle\n");
65321991Sheppo 		return (EINVAL);
65331991Sheppo 	}
65341991Sheppo 	ldcp = (ldc_chan_t *)handle;
65351991Sheppo 
65361991Sheppo 	if (cookie == NULL) {
65371991Sheppo 		DWARN(ldcp->id,
65381991Sheppo 		    "ldc_mem_dring_map: (0x%llx) invalid cookie\n",
65391991Sheppo 		    ldcp->id);
65401991Sheppo 		return (EINVAL);
65411991Sheppo 	}
65421991Sheppo 
65431991Sheppo 	/* FUTURE: For now we support only one cookie per dring */
65441991Sheppo 	ASSERT(ccount == 1);
65451991Sheppo 
65461991Sheppo 	if (cookie->size < (dsize * len)) {
65471991Sheppo 		DWARN(ldcp->id,
65481991Sheppo 		    "ldc_mem_dring_map: (0x%llx) invalid dsize/len\n",
65491991Sheppo 		    ldcp->id);
65501991Sheppo 		return (EINVAL);
65511991Sheppo 	}
65521991Sheppo 
65531991Sheppo 	*dhandle = 0;
65541991Sheppo 
65551991Sheppo 	/* Allocate an dring structure */
65561991Sheppo 	dringp = kmem_zalloc(sizeof (ldc_dring_t), KM_SLEEP);
65571991Sheppo 
65581991Sheppo 	D1(ldcp->id,
65591991Sheppo 	    "ldc_mem_dring_map: 0x%x,0x%x,0x%x,0x%llx,0x%llx\n",
65601991Sheppo 	    mtype, len, dsize, cookie->addr, cookie->size);
65611991Sheppo 
65621991Sheppo 	/* Initialize dring */
65631991Sheppo 	dringp->length = len;
65641991Sheppo 	dringp->dsize = dsize;
65651991Sheppo 
65661991Sheppo 	/* round of to multiple of page size */
65671991Sheppo 	dring_size = len * dsize;
65681991Sheppo 	dringp->size = (dring_size & MMU_PAGEMASK);
65691991Sheppo 	if (dring_size & MMU_PAGEOFFSET)
65701991Sheppo 		dringp->size += MMU_PAGESIZE;
65711991Sheppo 
65721991Sheppo 	dringp->ldcp = ldcp;
65731991Sheppo 
65741991Sheppo 	/* create an memory handle */
65751991Sheppo 	err = ldc_mem_alloc_handle(handle, &mhandle);
65761991Sheppo 	if (err || mhandle == NULL) {
65771991Sheppo 		DWARN(DBG_ALL_LDCS,
65781991Sheppo 		    "ldc_mem_dring_map: cannot alloc hdl err=%d\n",
65791991Sheppo 		    err);
65801991Sheppo 		kmem_free(dringp, sizeof (ldc_dring_t));
65811991Sheppo 		return (ENOMEM);
65821991Sheppo 	}
65831991Sheppo 
65841991Sheppo 	dringp->mhdl = mhandle;
65851991Sheppo 	dringp->base = NULL;
65861991Sheppo 
65871991Sheppo 	/* map the dring into local memory */
65882531Snarayan 	err = ldc_mem_map(mhandle, cookie, ccount, mtype, LDC_MEM_RW,
65891991Sheppo 	    &(dringp->base), NULL);
65901991Sheppo 	if (err || dringp->base == NULL) {
65911991Sheppo 		cmn_err(CE_WARN,
65921991Sheppo 		    "ldc_mem_dring_map: cannot map desc ring err=%d\n", err);
65931991Sheppo 		(void) ldc_mem_free_handle(mhandle);
65941991Sheppo 		kmem_free(dringp, sizeof (ldc_dring_t));
65951991Sheppo 		return (ENOMEM);
65961991Sheppo 	}
65971991Sheppo 
65981991Sheppo 	/* initialize the desc ring lock */
65991991Sheppo 	mutex_init(&dringp->lock, NULL, MUTEX_DRIVER, NULL);
66001991Sheppo 
66011991Sheppo 	/* Add descriptor ring to channel's imported dring list */
66021991Sheppo 	mutex_enter(&ldcp->imp_dlist_lock);
66031991Sheppo 	dringp->ch_next = ldcp->imp_dring_list;
66041991Sheppo 	ldcp->imp_dring_list = dringp;
66051991Sheppo 	mutex_exit(&ldcp->imp_dlist_lock);
66061991Sheppo 
66071991Sheppo 	dringp->status = LDC_MAPPED;
66081991Sheppo 
66091991Sheppo 	*dhandle = (ldc_dring_handle_t)dringp;
66101991Sheppo 
66111991Sheppo 	return (0);
66121991Sheppo }
66131991Sheppo 
66141991Sheppo /*
66151991Sheppo  * Unmap a descriptor ring. Free shadow memory (if any).
66161991Sheppo  */
66171991Sheppo int
66181991Sheppo ldc_mem_dring_unmap(ldc_dring_handle_t dhandle)
66191991Sheppo {
66201991Sheppo 	ldc_dring_t 	*dringp;
66211991Sheppo 	ldc_dring_t	*tmp_dringp;
66221991Sheppo 	ldc_chan_t	*ldcp;
66231991Sheppo 
66241991Sheppo 	if (dhandle == NULL) {
66251991Sheppo 		DWARN(DBG_ALL_LDCS,
66261991Sheppo 		    "ldc_mem_dring_unmap: invalid desc ring handle\n");
66271991Sheppo 		return (EINVAL);
66281991Sheppo 	}
66291991Sheppo 	dringp = (ldc_dring_t *)dhandle;
66301991Sheppo 
66311991Sheppo 	if (dringp->status != LDC_MAPPED) {
66321991Sheppo 		DWARN(DBG_ALL_LDCS,
66331991Sheppo 		    "ldc_mem_dring_unmap: not a mapped desc ring\n");
66341991Sheppo 		return (EINVAL);
66351991Sheppo 	}
66361991Sheppo 
66371991Sheppo 	mutex_enter(&dringp->lock);
66381991Sheppo 
66391991Sheppo 	ldcp = dringp->ldcp;
66401991Sheppo 
66411991Sheppo 	mutex_enter(&ldcp->imp_dlist_lock);
66421991Sheppo 
66431991Sheppo 	/* find and unlink the desc ring from channel import list */
66441991Sheppo 	tmp_dringp = ldcp->imp_dring_list;
66451991Sheppo 	if (tmp_dringp == dringp) {
66461991Sheppo 		ldcp->imp_dring_list = dringp->ch_next;
66471991Sheppo 		dringp->ch_next = NULL;
66481991Sheppo 
66491991Sheppo 	} else {
66501991Sheppo 		while (tmp_dringp != NULL) {
66511991Sheppo 			if (tmp_dringp->ch_next == dringp) {
66521991Sheppo 				tmp_dringp->ch_next = dringp->ch_next;
66531991Sheppo 				dringp->ch_next = NULL;
66541991Sheppo 				break;
66551991Sheppo 			}
66561991Sheppo 			tmp_dringp = tmp_dringp->ch_next;
66571991Sheppo 		}
66581991Sheppo 		if (tmp_dringp == NULL) {
66591991Sheppo 			DWARN(DBG_ALL_LDCS,
66601991Sheppo 			    "ldc_mem_dring_unmap: invalid descriptor\n");
66611991Sheppo 			mutex_exit(&ldcp->imp_dlist_lock);
66621991Sheppo 			mutex_exit(&dringp->lock);
66631991Sheppo 			return (EINVAL);
66641991Sheppo 		}
66651991Sheppo 	}
66661991Sheppo 
66671991Sheppo 	mutex_exit(&ldcp->imp_dlist_lock);
66681991Sheppo 
66691991Sheppo 	/* do a LDC memory handle unmap and free */
66701991Sheppo 	(void) ldc_mem_unmap(dringp->mhdl);
66711991Sheppo 	(void) ldc_mem_free_handle((ldc_mem_handle_t)dringp->mhdl);
66721991Sheppo 
66731991Sheppo 	dringp->status = 0;
66741991Sheppo 	dringp->ldcp = NULL;
66751991Sheppo 
66761991Sheppo 	mutex_exit(&dringp->lock);
66771991Sheppo 
66781991Sheppo 	/* destroy dring lock */
66791991Sheppo 	mutex_destroy(&dringp->lock);
66801991Sheppo 
66811991Sheppo 	/* free desc ring object */
66821991Sheppo 	kmem_free(dringp, sizeof (ldc_dring_t));
66831991Sheppo 
66841991Sheppo 	return (0);
66851991Sheppo }
66861991Sheppo 
66871991Sheppo /*
66881991Sheppo  * Internal entry point for descriptor ring access entry consistency
66891991Sheppo  * semantics. Acquire copies the contents of the remote descriptor ring
66901991Sheppo  * into the local shadow copy. The release operation copies the local
66911991Sheppo  * contents into the remote dring. The start and end locations specify
66921991Sheppo  * bounds for the entries being synchronized.
66931991Sheppo  */
66941991Sheppo static int
66951991Sheppo i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle,
66961991Sheppo     uint8_t direction, uint64_t start, uint64_t end)
66971991Sheppo {
66981991Sheppo 	int 			err;
66991991Sheppo 	ldc_dring_t		*dringp;
67001991Sheppo 	ldc_chan_t		*ldcp;
67011991Sheppo 	uint64_t		soff;
67021991Sheppo 	size_t			copy_size;
67031991Sheppo 
67041991Sheppo 	if (dhandle == NULL) {
67051991Sheppo 		DWARN(DBG_ALL_LDCS,
67061991Sheppo 		    "i_ldc_dring_acquire_release: invalid desc ring handle\n");
67071991Sheppo 		return (EINVAL);
67081991Sheppo 	}
67091991Sheppo 	dringp = (ldc_dring_t *)dhandle;
67101991Sheppo 	mutex_enter(&dringp->lock);
67111991Sheppo 
67121991Sheppo 	if (dringp->status != LDC_MAPPED || dringp->ldcp == NULL) {
67131991Sheppo 		DWARN(DBG_ALL_LDCS,
67141991Sheppo 		    "i_ldc_dring_acquire_release: not a mapped desc ring\n");
67151991Sheppo 		mutex_exit(&dringp->lock);
67161991Sheppo 		return (EINVAL);
67171991Sheppo 	}
67181991Sheppo 
67191991Sheppo 	if (start >= dringp->length || end >= dringp->length) {
67201991Sheppo 		DWARN(DBG_ALL_LDCS,
67211991Sheppo 		    "i_ldc_dring_acquire_release: index out of range\n");
67221991Sheppo 		mutex_exit(&dringp->lock);
67231991Sheppo 		return (EINVAL);
67241991Sheppo 	}
67251991Sheppo 
67261991Sheppo 	/* get the channel handle */
67271991Sheppo 	ldcp = dringp->ldcp;
67281991Sheppo 
67291991Sheppo 	copy_size = (start <= end) ? (((end - start) + 1) * dringp->dsize) :
67304690Snarayan 	    ((dringp->length - start) * dringp->dsize);
67311991Sheppo 
67321991Sheppo 	/* Calculate the relative offset for the first desc */
67331991Sheppo 	soff = (start * dringp->dsize);
67341991Sheppo 
67351991Sheppo 	/* copy to/from remote from/to local memory */
67361991Sheppo 	D1(ldcp->id, "i_ldc_dring_acquire_release: c1 off=0x%llx sz=0x%llx\n",
67371991Sheppo 	    soff, copy_size);
67381991Sheppo 	err = i_ldc_mem_acquire_release((ldc_mem_handle_t)dringp->mhdl,
67391991Sheppo 	    direction, soff, copy_size);
67401991Sheppo 	if (err) {
67411991Sheppo 		DWARN(ldcp->id,
67421991Sheppo 		    "i_ldc_dring_acquire_release: copy failed\n");
67431991Sheppo 		mutex_exit(&dringp->lock);
67441991Sheppo 		return (err);
67451991Sheppo 	}
67461991Sheppo 
67471991Sheppo 	/* do the balance */
67481991Sheppo 	if (start > end) {
67491991Sheppo 		copy_size = ((end + 1) * dringp->dsize);
67501991Sheppo 		soff = 0;
67511991Sheppo 
67521991Sheppo 		/* copy to/from remote from/to local memory */
67531991Sheppo 		D1(ldcp->id, "i_ldc_dring_acquire_release: c2 "
67541991Sheppo 		    "off=0x%llx sz=0x%llx\n", soff, copy_size);
67551991Sheppo 		err = i_ldc_mem_acquire_release((ldc_mem_handle_t)dringp->mhdl,
67561991Sheppo 		    direction, soff, copy_size);
67571991Sheppo 		if (err) {
67581991Sheppo 			DWARN(ldcp->id,
67591991Sheppo 			    "i_ldc_dring_acquire_release: copy failed\n");
67601991Sheppo 			mutex_exit(&dringp->lock);
67611991Sheppo 			return (err);
67621991Sheppo 		}
67631991Sheppo 	}
67641991Sheppo 
67651991Sheppo 	mutex_exit(&dringp->lock);
67661991Sheppo 
67671991Sheppo 	return (0);
67681991Sheppo }
67691991Sheppo 
67701991Sheppo /*
67711991Sheppo  * Ensure that the contents in the local dring are consistent
67721991Sheppo  * with the contents if of remote dring
67731991Sheppo  */
67741991Sheppo int
67751991Sheppo ldc_mem_dring_acquire(ldc_dring_handle_t dhandle, uint64_t start, uint64_t end)
67761991Sheppo {
67771991Sheppo 	return (i_ldc_dring_acquire_release(dhandle, LDC_COPY_IN, start, end));
67781991Sheppo }
67791991Sheppo 
67801991Sheppo /*
67811991Sheppo  * Ensure that the contents in the remote dring are consistent
67821991Sheppo  * with the contents if of local dring
67831991Sheppo  */
67841991Sheppo int
67851991Sheppo ldc_mem_dring_release(ldc_dring_handle_t dhandle, uint64_t start, uint64_t end)
67861991Sheppo {
67871991Sheppo 	return (i_ldc_dring_acquire_release(dhandle, LDC_COPY_OUT, start, end));
67881991Sheppo }
67891991Sheppo 
67901991Sheppo 
67911991Sheppo /* ------------------------------------------------------------------------- */
6792