xref: /onnv-gate/usr/src/uts/sun4v/io/ldc.c (revision 3151:9a7f99c63ca3)
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 /*
231991Sheppo  * Copyright 2006 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>
701991Sheppo 
711991Sheppo /* Core internal functions */
721991Sheppo static int i_ldc_h2v_error(int h_error);
731991Sheppo static int i_ldc_txq_reconf(ldc_chan_t *ldcp);
742793Slm66018 static int i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset);
752841Snarayan static int i_ldc_rxq_drain(ldc_chan_t *ldcp);
761991Sheppo static void i_ldc_reset_state(ldc_chan_t *ldcp);
772793Slm66018 static void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset);
781991Sheppo 
791991Sheppo static int i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail);
801991Sheppo static int i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail);
811991Sheppo static int i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head);
821991Sheppo static int i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
831991Sheppo     uint8_t ctrlmsg);
841991Sheppo 
851991Sheppo /* Interrupt handling functions */
861991Sheppo static uint_t i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2);
871991Sheppo static uint_t i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2);
881991Sheppo static void i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype);
891991Sheppo 
901991Sheppo /* Read method functions */
911991Sheppo static int i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep);
921991Sheppo static int i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp,
931991Sheppo 	size_t *sizep);
941991Sheppo static int i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp,
951991Sheppo 	size_t *sizep);
961991Sheppo 
971991Sheppo /* Write method functions */
981991Sheppo static int i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t target_bufp,
991991Sheppo 	size_t *sizep);
1001991Sheppo static int i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t target_bufp,
1011991Sheppo 	size_t *sizep);
1021991Sheppo static int i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t target_bufp,
1031991Sheppo 	size_t *sizep);
1041991Sheppo 
1051991Sheppo /* Pkt processing internal functions */
1061991Sheppo static int i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg);
1071991Sheppo static int i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg);
1081991Sheppo static int i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg);
1091991Sheppo static int i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg);
1101991Sheppo static int i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg);
1111991Sheppo static int i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg);
1121991Sheppo static int i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg);
1131991Sheppo 
1141991Sheppo /* Memory synchronization internal functions */
1151991Sheppo static int i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle,
1161991Sheppo     uint8_t direction, uint64_t offset, size_t size);
1171991Sheppo static int i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle,
1181991Sheppo     uint8_t direction, uint64_t start, uint64_t end);
1191991Sheppo 
1201991Sheppo /* LDC Version */
1211991Sheppo static ldc_ver_t ldc_versions[] = { {1, 0} };
1221991Sheppo 
1231991Sheppo /* number of supported versions */
1241991Sheppo #define	LDC_NUM_VERS	(sizeof (ldc_versions) / sizeof (ldc_versions[0]))
1251991Sheppo 
1261991Sheppo /* Module State Pointer */
1271991Sheppo static ldc_soft_state_t *ldcssp;
1281991Sheppo 
1291991Sheppo static struct modldrv md = {
1301991Sheppo 	&mod_miscops,			/* This is a misc module */
1311991Sheppo 	"sun4v LDC module v%I%",	/* Name of the module */
1321991Sheppo };
1331991Sheppo 
1341991Sheppo static struct modlinkage ml = {
1351991Sheppo 	MODREV_1,
1361991Sheppo 	&md,
1371991Sheppo 	NULL
1381991Sheppo };
1391991Sheppo 
1401991Sheppo static uint64_t ldc_sup_minor;		/* Supported minor number */
1411991Sheppo static hsvc_info_t ldc_hsvc = {
1421991Sheppo 	HSVC_REV_1, NULL, HSVC_GROUP_LDC, 1, 0, "ldc"
1431991Sheppo };
1441991Sheppo 
1451991Sheppo static uint64_t intr_sup_minor;		/* Supported minor number */
1461991Sheppo static hsvc_info_t intr_hsvc = {
1471991Sheppo 	HSVC_REV_1, NULL, HSVC_GROUP_INTR, 1, 0, "ldc"
1481991Sheppo };
1491991Sheppo 
1502531Snarayan /*
1512531Snarayan  * LDC framework supports mapping remote domain's memory
1522531Snarayan  * either directly or via shadow memory pages. Default
1532531Snarayan  * support is currently implemented via shadow copy.
1542531Snarayan  * Direct map can be enabled by setting 'ldc_shmem_enabled'
1552531Snarayan  */
1562531Snarayan int ldc_shmem_enabled = 0;
1572410Slm66018 
1582032Slm66018 /*
1592410Slm66018  * The no. of MTU size messages that can be stored in
1602410Slm66018  * the LDC Tx queue. The number of Tx queue entries is
1612410Slm66018  * then computed as (mtu * mtu_msgs)/sizeof(queue_entry)
1622410Slm66018  */
1632410Slm66018 uint64_t ldc_mtu_msgs = LDC_MTU_MSGS;
1642410Slm66018 
1652410Slm66018 /*
1662410Slm66018  * The minimum queue length. This is the size of the smallest
1672410Slm66018  * LDC queue. If the computed value is less than this default,
1682410Slm66018  * the queue length is rounded up to 'ldc_queue_entries'.
1692410Slm66018  */
1702410Slm66018 uint64_t ldc_queue_entries = LDC_QUEUE_ENTRIES;
1712410Slm66018 
1722410Slm66018 /*
1732410Slm66018  * Pages exported for remote access over each channel is
1742410Slm66018  * maintained in a table registered with the Hypervisor.
1752410Slm66018  * The default number of entries in the table is set to
1762410Slm66018  * 'ldc_mtbl_entries'.
1772410Slm66018  */
1782410Slm66018 uint64_t ldc_maptable_entries = LDC_MTBL_ENTRIES;
1792410Slm66018 
1802410Slm66018 /*
1812410Slm66018  * LDC retry count and delay - when the HV returns EWOULDBLOCK
1822410Slm66018  * the operation is retried 'ldc_max_retries' times with a
1832410Slm66018  * wait of 'ldc_delay' usecs between each retry.
1842032Slm66018  */
1852032Slm66018 int ldc_max_retries = LDC_MAX_RETRIES;
1862032Slm66018 clock_t ldc_delay = LDC_DELAY;
1872032Slm66018 
188*3151Ssg70180 /*
189*3151Ssg70180  * delay between each retry of channel unregistration in
190*3151Ssg70180  * ldc_close(), to wait for pending interrupts to complete.
191*3151Ssg70180  */
192*3151Ssg70180 clock_t ldc_close_delay = LDC_CLOSE_DELAY;
193*3151Ssg70180 
1941991Sheppo #ifdef DEBUG
1951991Sheppo 
1961991Sheppo /*
1971991Sheppo  * Print debug messages
1981991Sheppo  *
1991991Sheppo  * set ldcdbg to 0x7 for enabling all msgs
2001991Sheppo  * 0x4 - Warnings
2011991Sheppo  * 0x2 - All debug messages
2021991Sheppo  * 0x1 - Minimal debug messages
2031991Sheppo  *
2041991Sheppo  * set ldcdbgchan to the channel number you want to debug
2051991Sheppo  * setting it to -1 prints debug messages for all channels
2061991Sheppo  * NOTE: ldcdbgchan has no effect on error messages
2071991Sheppo  */
2081991Sheppo 
2091991Sheppo #define	DBG_ALL_LDCS -1
2101991Sheppo 
2111991Sheppo int ldcdbg = 0x0;
2121991Sheppo int64_t ldcdbgchan = DBG_ALL_LDCS;
2132793Slm66018 boolean_t ldc_inject_reset_flag = B_FALSE;
2141991Sheppo 
2151991Sheppo static void
2161991Sheppo ldcdebug(int64_t id, const char *fmt, ...)
2171991Sheppo {
2181991Sheppo 	char buf[512];
2191991Sheppo 	va_list ap;
2201991Sheppo 
2211991Sheppo 	/*
2221991Sheppo 	 * Do not return if,
2231991Sheppo 	 * caller wants to print it anyway - (id == DBG_ALL_LDCS)
2241991Sheppo 	 * debug channel is set to all LDCs - (ldcdbgchan == DBG_ALL_LDCS)
2251991Sheppo 	 * debug channel = caller specified channel
2261991Sheppo 	 */
2271991Sheppo 	if ((id != DBG_ALL_LDCS) &&
2281991Sheppo 	    (ldcdbgchan != DBG_ALL_LDCS) &&
2291991Sheppo 	    (ldcdbgchan != id)) {
2301991Sheppo 		return;
2311991Sheppo 	}
2321991Sheppo 
2331991Sheppo 	va_start(ap, fmt);
2341991Sheppo 	(void) vsprintf(buf, fmt, ap);
2351991Sheppo 	va_end(ap);
2361991Sheppo 
2372793Slm66018 	cmn_err(CE_CONT, "?%s", buf);
2382793Slm66018 }
2392793Slm66018 
2402793Slm66018 static boolean_t
2412793Slm66018 ldc_inject_reset(ldc_chan_t *ldcp)
2422793Slm66018 {
2432793Slm66018 	if ((ldcdbgchan != DBG_ALL_LDCS) && (ldcdbgchan != ldcp->id))
2442793Slm66018 		return (B_FALSE);
2452793Slm66018 
2462793Slm66018 	if (!ldc_inject_reset_flag)
2472793Slm66018 		return (B_FALSE);
2482793Slm66018 
2492793Slm66018 	/* clear the injection state */
2502793Slm66018 	ldc_inject_reset_flag = 0;
2512793Slm66018 
2522793Slm66018 	return (B_TRUE);
2531991Sheppo }
2541991Sheppo 
2551991Sheppo #define	D1		\
2561991Sheppo if (ldcdbg & 0x01)	\
2571991Sheppo 	ldcdebug
2581991Sheppo 
2591991Sheppo #define	D2		\
2601991Sheppo if (ldcdbg & 0x02)	\
2611991Sheppo 	ldcdebug
2621991Sheppo 
2631991Sheppo #define	DWARN		\
2641991Sheppo if (ldcdbg & 0x04)	\
2651991Sheppo 	ldcdebug
2661991Sheppo 
2671991Sheppo #define	DUMP_PAYLOAD(id, addr)						\
2681991Sheppo {									\
2691991Sheppo 	char buf[65*3];							\
2701991Sheppo 	int i;								\
2711991Sheppo 	uint8_t *src = (uint8_t *)addr;					\
2721991Sheppo 	for (i = 0; i < 64; i++, src++)					\
2731991Sheppo 		(void) sprintf(&buf[i * 3], "|%02x", *src);		\
2741991Sheppo 	(void) sprintf(&buf[i * 3], "|\n");				\
2751991Sheppo 	D2((id), "payload: %s", buf);					\
2761991Sheppo }
2771991Sheppo 
2781991Sheppo #define	DUMP_LDC_PKT(c, s, addr)					\
2791991Sheppo {									\
2801991Sheppo 	ldc_msg_t *msg = (ldc_msg_t *)(addr);				\
2811991Sheppo 	uint32_t mid = ((c)->mode != LDC_MODE_RAW) ? msg->seqid : 0;	\
2821991Sheppo 	if (msg->type == LDC_DATA) {                                    \
2831991Sheppo 	    D2((c)->id, "%s: msg%d (/%x/%x/%x/,env[%c%c,sz=%d])",	\
2841991Sheppo 	    (s), mid, msg->type, msg->stype, msg->ctrl,			\
2851991Sheppo 	    (msg->env & LDC_FRAG_START) ? 'B' : ' ',                    \
2861991Sheppo 	    (msg->env & LDC_FRAG_STOP) ? 'E' : ' ',                     \
2871991Sheppo 	    (msg->env & LDC_LEN_MASK));					\
2881991Sheppo 	} else { 							\
2891991Sheppo 	    D2((c)->id, "%s: msg%d (/%x/%x/%x/,env=%x)", (s),		\
2901991Sheppo 	    mid, msg->type, msg->stype, msg->ctrl, msg->env);		\
2911991Sheppo 	} 								\
2921991Sheppo }
2931991Sheppo 
2942793Slm66018 #define	LDC_INJECT_RESET(_ldcp)	ldc_inject_reset(_ldcp)
2952793Slm66018 
2961991Sheppo #else
2971991Sheppo 
2981991Sheppo #define	DBG_ALL_LDCS -1
2991991Sheppo 
3001991Sheppo #define	D1
3011991Sheppo #define	D2
3021991Sheppo #define	DWARN
3031991Sheppo 
3041991Sheppo #define	DUMP_PAYLOAD(id, addr)
3051991Sheppo #define	DUMP_LDC_PKT(c, s, addr)
3061991Sheppo 
3072793Slm66018 #define	LDC_INJECT_RESET(_ldcp)	(B_FALSE)
3082793Slm66018 
3091991Sheppo #endif
3101991Sheppo 
3111991Sheppo #define	ZERO_PKT(p)			\
3121991Sheppo 	bzero((p), sizeof (ldc_msg_t));
3131991Sheppo 
3141991Sheppo #define	IDX2COOKIE(idx, pg_szc, pg_shift)				\
3151991Sheppo 	(((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift)))
3161991Sheppo 
3171991Sheppo 
3181991Sheppo int
3191991Sheppo _init(void)
3201991Sheppo {
3211991Sheppo 	int status;
3221991Sheppo 
3231991Sheppo 	status = hsvc_register(&ldc_hsvc, &ldc_sup_minor);
3241991Sheppo 	if (status != 0) {
3251991Sheppo 		cmn_err(CE_WARN, "%s: cannot negotiate hypervisor LDC services"
3261991Sheppo 		    " group: 0x%lx major: %ld minor: %ld errno: %d",
3271991Sheppo 		    ldc_hsvc.hsvc_modname, ldc_hsvc.hsvc_group,
3281991Sheppo 		    ldc_hsvc.hsvc_major, ldc_hsvc.hsvc_minor, status);
3291991Sheppo 		return (-1);
3301991Sheppo 	}
3311991Sheppo 
3321991Sheppo 	status = hsvc_register(&intr_hsvc, &intr_sup_minor);
3331991Sheppo 	if (status != 0) {
3341991Sheppo 		cmn_err(CE_WARN, "%s: cannot negotiate hypervisor interrupt "
3351991Sheppo 		    "services group: 0x%lx major: %ld minor: %ld errno: %d",
3361991Sheppo 		    intr_hsvc.hsvc_modname, intr_hsvc.hsvc_group,
3371991Sheppo 		    intr_hsvc.hsvc_major, intr_hsvc.hsvc_minor, status);
3381991Sheppo 		(void) hsvc_unregister(&ldc_hsvc);
3391991Sheppo 		return (-1);
3401991Sheppo 	}
3411991Sheppo 
3421991Sheppo 	/* allocate soft state structure */
3431991Sheppo 	ldcssp = kmem_zalloc(sizeof (ldc_soft_state_t), KM_SLEEP);
3441991Sheppo 
3451991Sheppo 	/* Link the module into the system */
3461991Sheppo 	status = mod_install(&ml);
3471991Sheppo 	if (status != 0) {
3481991Sheppo 		kmem_free(ldcssp, sizeof (ldc_soft_state_t));
3491991Sheppo 		return (status);
3501991Sheppo 	}
3511991Sheppo 
3521991Sheppo 	/* Initialize the LDC state structure */
3531991Sheppo 	mutex_init(&ldcssp->lock, NULL, MUTEX_DRIVER, NULL);
3541991Sheppo 
3551991Sheppo 	mutex_enter(&ldcssp->lock);
3561991Sheppo 
3572531Snarayan 	/* Create a cache for memory handles */
3582531Snarayan 	ldcssp->memhdl_cache = kmem_cache_create("ldc_memhdl_cache",
3592531Snarayan 	    sizeof (ldc_mhdl_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
3602531Snarayan 	if (ldcssp->memhdl_cache == NULL) {
3612531Snarayan 		DWARN(DBG_ALL_LDCS, "_init: ldc_memhdl cache create failed\n");
3622531Snarayan 		mutex_exit(&ldcssp->lock);
3632531Snarayan 		return (-1);
3642531Snarayan 	}
3652531Snarayan 
3662531Snarayan 	/* Create cache for memory segment structures */
3672531Snarayan 	ldcssp->memseg_cache = kmem_cache_create("ldc_memseg_cache",
3682531Snarayan 	    sizeof (ldc_memseg_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
3692531Snarayan 	if (ldcssp->memseg_cache == NULL) {
3702531Snarayan 		DWARN(DBG_ALL_LDCS, "_init: ldc_memseg cache create failed\n");
3712531Snarayan 		mutex_exit(&ldcssp->lock);
3722531Snarayan 		return (-1);
3732531Snarayan 	}
3742531Snarayan 
3752531Snarayan 
3761991Sheppo 	ldcssp->channel_count = 0;
3771991Sheppo 	ldcssp->channels_open = 0;
3781991Sheppo 	ldcssp->chan_list = NULL;
3791991Sheppo 	ldcssp->dring_list = NULL;
3801991Sheppo 
3811991Sheppo 	mutex_exit(&ldcssp->lock);
3821991Sheppo 
3831991Sheppo 	return (0);
3841991Sheppo }
3851991Sheppo 
3861991Sheppo int
3871991Sheppo _info(struct modinfo *modinfop)
3881991Sheppo {
3891991Sheppo 	/* Report status of the dynamically loadable driver module */
3901991Sheppo 	return (mod_info(&ml, modinfop));
3911991Sheppo }
3921991Sheppo 
3931991Sheppo int
3941991Sheppo _fini(void)
3951991Sheppo {
3961991Sheppo 	int 		rv, status;
3971991Sheppo 	ldc_chan_t 	*ldcp;
3981991Sheppo 	ldc_dring_t 	*dringp;
3991991Sheppo 	ldc_mem_info_t 	minfo;
4001991Sheppo 
4011991Sheppo 	/* Unlink the driver module from the system */
4021991Sheppo 	status = mod_remove(&ml);
4031991Sheppo 	if (status) {
4041991Sheppo 		DWARN(DBG_ALL_LDCS, "_fini: mod_remove failed\n");
4051991Sheppo 		return (EIO);
4061991Sheppo 	}
4071991Sheppo 
4081991Sheppo 	/* close and finalize channels */
4091991Sheppo 	ldcp = ldcssp->chan_list;
4101991Sheppo 	while (ldcp != NULL) {
4111991Sheppo 		(void) ldc_close((ldc_handle_t)ldcp);
4121991Sheppo 		(void) ldc_fini((ldc_handle_t)ldcp);
4131991Sheppo 
4141991Sheppo 		ldcp = ldcp->next;
4151991Sheppo 	}
4161991Sheppo 
4171991Sheppo 	/* Free descriptor rings */
4181991Sheppo 	dringp = ldcssp->dring_list;
4191991Sheppo 	while (dringp != NULL) {
4201991Sheppo 		dringp = dringp->next;
4211991Sheppo 
4221991Sheppo 		rv = ldc_mem_dring_info((ldc_dring_handle_t)dringp, &minfo);
4231991Sheppo 		if (rv == 0 && minfo.status != LDC_UNBOUND) {
4241991Sheppo 			if (minfo.status == LDC_BOUND) {
4251991Sheppo 				(void) ldc_mem_dring_unbind(
4261991Sheppo 						(ldc_dring_handle_t)dringp);
4271991Sheppo 			}
4281991Sheppo 			if (minfo.status == LDC_MAPPED) {
4291991Sheppo 				(void) ldc_mem_dring_unmap(
4301991Sheppo 						(ldc_dring_handle_t)dringp);
4311991Sheppo 			}
4321991Sheppo 		}
4331991Sheppo 
4341991Sheppo 		(void) ldc_mem_dring_destroy((ldc_dring_handle_t)dringp);
4351991Sheppo 	}
4361991Sheppo 	ldcssp->dring_list = NULL;
4371991Sheppo 
4382531Snarayan 	/* Destroy kmem caches */
4392531Snarayan 	kmem_cache_destroy(ldcssp->memhdl_cache);
4402531Snarayan 	kmem_cache_destroy(ldcssp->memseg_cache);
4412531Snarayan 
4421991Sheppo 	/*
4431991Sheppo 	 * We have successfully "removed" the driver.
4441991Sheppo 	 * Destroying soft states
4451991Sheppo 	 */
4461991Sheppo 	mutex_destroy(&ldcssp->lock);
4471991Sheppo 	kmem_free(ldcssp, sizeof (ldc_soft_state_t));
4481991Sheppo 
4491991Sheppo 	(void) hsvc_unregister(&ldc_hsvc);
4501991Sheppo 	(void) hsvc_unregister(&intr_hsvc);
4511991Sheppo 
4521991Sheppo 	return (status);
4531991Sheppo }
4541991Sheppo 
4551991Sheppo /* -------------------------------------------------------------------------- */
4561991Sheppo 
4571991Sheppo /*
4582410Slm66018  * LDC Link Layer Internal Functions
4591991Sheppo  */
4601991Sheppo 
4611991Sheppo /*
4621991Sheppo  * Translate HV Errors to sun4v error codes
4631991Sheppo  */
4641991Sheppo static int
4651991Sheppo i_ldc_h2v_error(int h_error)
4661991Sheppo {
4671991Sheppo 	switch (h_error) {
4681991Sheppo 
4691991Sheppo 	case	H_EOK:
4701991Sheppo 		return (0);
4711991Sheppo 
4721991Sheppo 	case	H_ENORADDR:
4731991Sheppo 		return (EFAULT);
4741991Sheppo 
4751991Sheppo 	case	H_EBADPGSZ:
4761991Sheppo 	case	H_EINVAL:
4771991Sheppo 		return (EINVAL);
4781991Sheppo 
4791991Sheppo 	case	H_EWOULDBLOCK:
4801991Sheppo 		return (EWOULDBLOCK);
4811991Sheppo 
4821991Sheppo 	case	H_ENOACCESS:
4831991Sheppo 	case	H_ENOMAP:
4841991Sheppo 		return (EACCES);
4851991Sheppo 
4861991Sheppo 	case	H_EIO:
4871991Sheppo 	case	H_ECPUERROR:
4881991Sheppo 		return (EIO);
4891991Sheppo 
4901991Sheppo 	case	H_ENOTSUPPORTED:
4911991Sheppo 		return (ENOTSUP);
4921991Sheppo 
4931991Sheppo 	case 	H_ETOOMANY:
4941991Sheppo 		return (ENOSPC);
4951991Sheppo 
4961991Sheppo 	case	H_ECHANNEL:
4971991Sheppo 		return (ECHRNG);
4981991Sheppo 	default:
4991991Sheppo 		break;
5001991Sheppo 	}
5011991Sheppo 
5021991Sheppo 	return (EIO);
5031991Sheppo }
5041991Sheppo 
5051991Sheppo /*
5061991Sheppo  * Reconfigure the transmit queue
5071991Sheppo  */
5081991Sheppo static int
5091991Sheppo i_ldc_txq_reconf(ldc_chan_t *ldcp)
5101991Sheppo {
5111991Sheppo 	int rv;
5121991Sheppo 
5131991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
5142336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
5152336Snarayan 
5161991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
5171991Sheppo 	if (rv) {
5181991Sheppo 		cmn_err(CE_WARN,
5192793Slm66018 		    "i_ldc_txq_reconf: (0x%lx) cannot set qconf", ldcp->id);
5201991Sheppo 		return (EIO);
5211991Sheppo 	}
5221991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id, &(ldcp->tx_head),
5231991Sheppo 	    &(ldcp->tx_tail), &(ldcp->link_state));
5241991Sheppo 	if (rv) {
5251991Sheppo 		cmn_err(CE_WARN,
5262793Slm66018 		    "i_ldc_txq_reconf: (0x%lx) cannot get qptrs", ldcp->id);
5271991Sheppo 		return (EIO);
5281991Sheppo 	}
5292793Slm66018 	D1(ldcp->id, "i_ldc_txq_reconf: (0x%llx) h=0x%llx,t=0x%llx,"
5301991Sheppo 	    "s=0x%llx\n", ldcp->id, ldcp->tx_head, ldcp->tx_tail,
5311991Sheppo 	    ldcp->link_state);
5321991Sheppo 
5331991Sheppo 	return (0);
5341991Sheppo }
5351991Sheppo 
5361991Sheppo /*
5371991Sheppo  * Reconfigure the receive queue
5381991Sheppo  */
5391991Sheppo static int
5402793Slm66018 i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset)
5411991Sheppo {
5421991Sheppo 	int rv;
5431991Sheppo 	uint64_t rx_head, rx_tail;
5441991Sheppo 
5451991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
5461991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
5471991Sheppo 	    &(ldcp->link_state));
5481991Sheppo 	if (rv) {
5491991Sheppo 		cmn_err(CE_WARN,
5502793Slm66018 		    "i_ldc_rxq_reconf: (0x%lx) cannot get state",
5511991Sheppo 		    ldcp->id);
5521991Sheppo 		return (EIO);
5531991Sheppo 	}
5541991Sheppo 
5552793Slm66018 	if (force_reset || (ldcp->tstate & ~TS_IN_RESET) == TS_UP) {
5561991Sheppo 		rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra,
5571991Sheppo 			ldcp->rx_q_entries);
5581991Sheppo 		if (rv) {
5591991Sheppo 			cmn_err(CE_WARN,
5602793Slm66018 			    "i_ldc_rxq_reconf: (0x%lx) cannot set qconf",
5611991Sheppo 			    ldcp->id);
5621991Sheppo 			return (EIO);
5631991Sheppo 		}
5642793Slm66018 		D1(ldcp->id, "i_ldc_rxq_reconf: (0x%llx) completed q reconf",
5651991Sheppo 		    ldcp->id);
5661991Sheppo 	}
5671991Sheppo 
5681991Sheppo 	return (0);
5691991Sheppo }
5701991Sheppo 
5712841Snarayan 
5722841Snarayan /*
5732841Snarayan  * Drain the contents of the receive queue
5742841Snarayan  */
5752841Snarayan static int
5762841Snarayan i_ldc_rxq_drain(ldc_chan_t *ldcp)
5772841Snarayan {
5782841Snarayan 	int rv;
5792841Snarayan 	uint64_t rx_head, rx_tail;
5802841Snarayan 
5812841Snarayan 	ASSERT(MUTEX_HELD(&ldcp->lock));
5822841Snarayan 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
5832841Snarayan 	    &(ldcp->link_state));
5842841Snarayan 	if (rv) {
5852841Snarayan 		cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot get state",
5862841Snarayan 		    ldcp->id);
5872841Snarayan 		return (EIO);
5882841Snarayan 	}
5892841Snarayan 
5902841Snarayan 	/* flush contents by setting the head = tail */
5912841Snarayan 	return (i_ldc_set_rx_head(ldcp, rx_tail));
5922841Snarayan }
5932841Snarayan 
5942841Snarayan 
5951991Sheppo /*
5961991Sheppo  * Reset LDC state structure and its contents
5971991Sheppo  */
5981991Sheppo static void
5991991Sheppo i_ldc_reset_state(ldc_chan_t *ldcp)
6001991Sheppo {
6011991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
6021991Sheppo 	ldcp->last_msg_snt = LDC_INIT_SEQID;
6031991Sheppo 	ldcp->last_ack_rcd = 0;
6041991Sheppo 	ldcp->last_msg_rcd = 0;
6051991Sheppo 	ldcp->tx_ackd_head = ldcp->tx_head;
6061991Sheppo 	ldcp->next_vidx = 0;
6071991Sheppo 	ldcp->hstate = 0;
6081991Sheppo 	ldcp->tstate = TS_OPEN;
6091991Sheppo 	ldcp->status = LDC_OPEN;
6101991Sheppo 
6111991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_UP ||
6121991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
6131991Sheppo 
6141991Sheppo 		if (ldcp->mode == LDC_MODE_RAW) {
6151991Sheppo 			ldcp->status = LDC_UP;
6161991Sheppo 			ldcp->tstate = TS_UP;
6171991Sheppo 		} else {
6181991Sheppo 			ldcp->status = LDC_READY;
6191991Sheppo 			ldcp->tstate |= TS_LINK_READY;
6201991Sheppo 		}
6211991Sheppo 	}
6221991Sheppo }
6231991Sheppo 
6241991Sheppo /*
6251991Sheppo  * Reset a LDC channel
6261991Sheppo  */
6271991Sheppo static void
6282793Slm66018 i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset)
6291991Sheppo {
6303010Slm66018 	D1(ldcp->id, "i_ldc_reset: (0x%llx) channel reset\n", ldcp->id);
6311991Sheppo 
6322336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->lock));
6332336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
6342336Snarayan 
6352793Slm66018 	/* reconfig Tx and Rx queues */
6361991Sheppo 	(void) i_ldc_txq_reconf(ldcp);
6372793Slm66018 	(void) i_ldc_rxq_reconf(ldcp, force_reset);
6382793Slm66018 
6392793Slm66018 	/* Clear Tx and Rx interrupts */
6402793Slm66018 	(void) i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
6412793Slm66018 	(void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
6422793Slm66018 
6432793Slm66018 	/* Reset channel state */
6441991Sheppo 	i_ldc_reset_state(ldcp);
6452793Slm66018 
6462793Slm66018 	/* Mark channel in reset */
6472793Slm66018 	ldcp->tstate |= TS_IN_RESET;
6481991Sheppo }
6491991Sheppo 
6502531Snarayan 
6511991Sheppo /*
6521991Sheppo  * Clear pending interrupts
6531991Sheppo  */
6541991Sheppo static void
6551991Sheppo i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype)
6561991Sheppo {
6571991Sheppo 	ldc_cnex_t *cinfo = &ldcssp->cinfo;
6581991Sheppo 
6591991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
6602793Slm66018 	ASSERT(cinfo->dip != NULL);
6612793Slm66018 
6622793Slm66018 	switch (itype) {
6632793Slm66018 	case CNEX_TX_INTR:
6642531Snarayan 		/* check Tx interrupt */
6652793Slm66018 		if (ldcp->tx_intr_state)
6662793Slm66018 			ldcp->tx_intr_state = LDC_INTR_NONE;
6672793Slm66018 		else
6682793Slm66018 			return;
6692793Slm66018 		break;
6702793Slm66018 
6712793Slm66018 	case CNEX_RX_INTR:
6722531Snarayan 		/* check Rx interrupt */
6732793Slm66018 		if (ldcp->rx_intr_state)
6742793Slm66018 			ldcp->rx_intr_state = LDC_INTR_NONE;
6752793Slm66018 		else
6762793Slm66018 			return;
6772793Slm66018 		break;
6782793Slm66018 	}
6792793Slm66018 
6802793Slm66018 	(void) cinfo->clr_intr(cinfo->dip, ldcp->id, itype);
6812793Slm66018 	D2(ldcp->id,
6822793Slm66018 	    "i_ldc_clear_intr: (0x%llx) cleared 0x%x intr\n",
6832793Slm66018 	    ldcp->id, itype);
6841991Sheppo }
6851991Sheppo 
6861991Sheppo /*
6871991Sheppo  * Set the receive queue head
6882032Slm66018  * Resets connection and returns an error if it fails.
6891991Sheppo  */
6901991Sheppo static int
6911991Sheppo i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head)
6921991Sheppo {
6932032Slm66018 	int 	rv;
6942032Slm66018 	int 	retries;
6951991Sheppo 
6961991Sheppo 	ASSERT(MUTEX_HELD(&ldcp->lock));
6972032Slm66018 	for (retries = 0; retries < ldc_max_retries; retries++) {
6982032Slm66018 
6992032Slm66018 		if ((rv = hv_ldc_rx_set_qhead(ldcp->id, head)) == 0)
7002032Slm66018 			return (0);
7012032Slm66018 
7022032Slm66018 		if (rv != H_EWOULDBLOCK)
7032032Slm66018 			break;
7042032Slm66018 
7052032Slm66018 		/* wait for ldc_delay usecs */
7062032Slm66018 		drv_usecwait(ldc_delay);
7072032Slm66018 	}
7082032Slm66018 
7092032Slm66018 	cmn_err(CE_WARN, "ldc_rx_set_qhead: (0x%lx) cannot set qhead 0x%lx",
7102032Slm66018 		ldcp->id, head);
7112336Snarayan 	mutex_enter(&ldcp->tx_lock);
7122793Slm66018 	i_ldc_reset(ldcp, B_TRUE);
7132336Snarayan 	mutex_exit(&ldcp->tx_lock);
7142032Slm66018 
7152032Slm66018 	return (ECONNRESET);
7161991Sheppo }
7171991Sheppo 
7181991Sheppo 
7191991Sheppo /*
7201991Sheppo  * Returns the tx_tail to be used for transfer
7211991Sheppo  * Re-reads the TX queue ptrs if and only if the
7221991Sheppo  * the cached head and tail are equal (queue is full)
7231991Sheppo  */
7241991Sheppo static int
7251991Sheppo i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail)
7261991Sheppo {
7271991Sheppo 	int 		rv;
7281991Sheppo 	uint64_t 	current_head, new_tail;
7291991Sheppo 
7302336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
7311991Sheppo 	/* Read the head and tail ptrs from HV */
7321991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
7331991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
7341991Sheppo 	if (rv) {
7351991Sheppo 		cmn_err(CE_WARN,
7361991Sheppo 		    "i_ldc_get_tx_tail: (0x%lx) cannot read qptrs\n",
7371991Sheppo 		    ldcp->id);
7381991Sheppo 		return (EIO);
7391991Sheppo 	}
7401991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN) {
7413010Slm66018 		D1(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) channel not ready\n",
7421991Sheppo 		    ldcp->id);
7431991Sheppo 		return (ECONNRESET);
7441991Sheppo 	}
7451991Sheppo 
7461991Sheppo 	/* In reliable mode, check against last ACKd msg */
7471991Sheppo 	current_head = (ldcp->mode == LDC_MODE_RELIABLE ||
7481991Sheppo 		ldcp->mode == LDC_MODE_STREAM)
7491991Sheppo 		? ldcp->tx_ackd_head : ldcp->tx_head;
7501991Sheppo 
7511991Sheppo 	/* increment the tail */
7521991Sheppo 	new_tail = (ldcp->tx_tail + LDC_PACKET_SIZE) %
7531991Sheppo 		(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
7541991Sheppo 
7551991Sheppo 	if (new_tail == current_head) {
7561991Sheppo 		DWARN(ldcp->id,
7571991Sheppo 		    "i_ldc_get_tx_tail: (0x%llx) TX queue is full\n",
7581991Sheppo 		    ldcp->id);
7591991Sheppo 		return (EWOULDBLOCK);
7601991Sheppo 	}
7611991Sheppo 
7621991Sheppo 	D2(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) head=0x%llx, tail=0x%llx\n",
7631991Sheppo 	    ldcp->id, ldcp->tx_head, ldcp->tx_tail);
7641991Sheppo 
7651991Sheppo 	*tail = ldcp->tx_tail;
7661991Sheppo 	return (0);
7671991Sheppo }
7681991Sheppo 
7691991Sheppo /*
7701991Sheppo  * Set the tail pointer. If HV returns EWOULDBLOCK, it will back off
7712032Slm66018  * and retry ldc_max_retries times before returning an error.
7721991Sheppo  * Returns 0, EWOULDBLOCK or EIO
7731991Sheppo  */
7741991Sheppo static int
7751991Sheppo i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail)
7761991Sheppo {
7771991Sheppo 	int		rv, retval = EWOULDBLOCK;
7782032Slm66018 	int 		retries;
7791991Sheppo 
7802336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
7812032Slm66018 	for (retries = 0; retries < ldc_max_retries; retries++) {
7821991Sheppo 
7831991Sheppo 		if ((rv = hv_ldc_tx_set_qtail(ldcp->id, tail)) == 0) {
7841991Sheppo 			retval = 0;
7851991Sheppo 			break;
7861991Sheppo 		}
7871991Sheppo 		if (rv != H_EWOULDBLOCK) {
7881991Sheppo 			DWARN(ldcp->id, "i_ldc_set_tx_tail: (0x%llx) set "
7891991Sheppo 			    "qtail=0x%llx failed, rv=%d\n", ldcp->id, tail, rv);
7901991Sheppo 			retval = EIO;
7911991Sheppo 			break;
7921991Sheppo 		}
7931991Sheppo 
7942032Slm66018 		/* wait for ldc_delay usecs */
7952032Slm66018 		drv_usecwait(ldc_delay);
7961991Sheppo 	}
7971991Sheppo 	return (retval);
7981991Sheppo }
7991991Sheppo 
8001991Sheppo /*
8011991Sheppo  * Send a LDC message
8021991Sheppo  */
8031991Sheppo static int
8041991Sheppo i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
8051991Sheppo     uint8_t ctrlmsg)
8061991Sheppo {
8071991Sheppo 	int		rv;
8081991Sheppo 	ldc_msg_t 	*pkt;
8091991Sheppo 	uint64_t	tx_tail;
8101991Sheppo 	uint32_t	curr_seqid = ldcp->last_msg_snt;
8111991Sheppo 
8122336Snarayan 	/* Obtain Tx lock */
8132336Snarayan 	mutex_enter(&ldcp->tx_lock);
8142336Snarayan 
8151991Sheppo 	/* get the current tail for the message */
8161991Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
8171991Sheppo 	if (rv) {
8181991Sheppo 		DWARN(ldcp->id,
8191991Sheppo 		    "i_ldc_send_pkt: (0x%llx) error sending pkt, "
8201991Sheppo 		    "type=0x%x,subtype=0x%x,ctrl=0x%x\n",
8211991Sheppo 		    ldcp->id, pkttype, subtype, ctrlmsg);
8222336Snarayan 		mutex_exit(&ldcp->tx_lock);
8231991Sheppo 		return (rv);
8241991Sheppo 	}
8251991Sheppo 
8261991Sheppo 	pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
8271991Sheppo 	ZERO_PKT(pkt);
8281991Sheppo 
8291991Sheppo 	/* Initialize the packet */
8301991Sheppo 	pkt->type = pkttype;
8311991Sheppo 	pkt->stype = subtype;
8321991Sheppo 	pkt->ctrl = ctrlmsg;
8331991Sheppo 
8341991Sheppo 	/* Store ackid/seqid iff it is RELIABLE mode & not a RTS/RTR message */
8351991Sheppo 	if (((ctrlmsg & LDC_CTRL_MASK) != LDC_RTS) &&
8361991Sheppo 	    ((ctrlmsg & LDC_CTRL_MASK) != LDC_RTR)) {
8371991Sheppo 		curr_seqid++;
8381991Sheppo 		if (ldcp->mode != LDC_MODE_RAW) {
8391991Sheppo 			pkt->seqid = curr_seqid;
8401991Sheppo 			pkt->ackid = ldcp->last_msg_rcd;
8411991Sheppo 		}
8421991Sheppo 	}
8431991Sheppo 	DUMP_LDC_PKT(ldcp, "i_ldc_send_pkt", (uint64_t)pkt);
8441991Sheppo 
8451991Sheppo 	/* initiate the send by calling into HV and set the new tail */
8461991Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
8471991Sheppo 		(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
8481991Sheppo 
8491991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
8501991Sheppo 	if (rv) {
8511991Sheppo 		DWARN(ldcp->id,
8521991Sheppo 		    "i_ldc_send_pkt:(0x%llx) error sending pkt, "
8531991Sheppo 		    "type=0x%x,stype=0x%x,ctrl=0x%x\n",
8541991Sheppo 		    ldcp->id, pkttype, subtype, ctrlmsg);
8552336Snarayan 		mutex_exit(&ldcp->tx_lock);
8561991Sheppo 		return (EIO);
8571991Sheppo 	}
8581991Sheppo 
8591991Sheppo 	ldcp->last_msg_snt = curr_seqid;
8601991Sheppo 	ldcp->tx_tail = tx_tail;
8611991Sheppo 
8622336Snarayan 	mutex_exit(&ldcp->tx_lock);
8631991Sheppo 	return (0);
8641991Sheppo }
8651991Sheppo 
8661991Sheppo /*
8671991Sheppo  * Checks if packet was received in right order
8682410Slm66018  * in the case of a reliable link.
8691991Sheppo  * Returns 0 if in order, else EIO
8701991Sheppo  */
8711991Sheppo static int
8721991Sheppo i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *msg)
8731991Sheppo {
8741991Sheppo 	/* No seqid checking for RAW mode */
8751991Sheppo 	if (ldcp->mode == LDC_MODE_RAW)
8761991Sheppo 		return (0);
8771991Sheppo 
8781991Sheppo 	/* No seqid checking for version, RTS, RTR message */
8791991Sheppo 	if (msg->ctrl == LDC_VER ||
8801991Sheppo 	    msg->ctrl == LDC_RTS ||
8811991Sheppo 	    msg->ctrl == LDC_RTR)
8821991Sheppo 		return (0);
8831991Sheppo 
8841991Sheppo 	/* Initial seqid to use is sent in RTS/RTR and saved in last_msg_rcd */
8851991Sheppo 	if (msg->seqid != (ldcp->last_msg_rcd + 1)) {
8861991Sheppo 		DWARN(ldcp->id,
8871991Sheppo 		    "i_ldc_check_seqid: (0x%llx) out-of-order pkt, got 0x%x, "
8881991Sheppo 		    "expecting 0x%x\n", ldcp->id, msg->seqid,
8891991Sheppo 		    (ldcp->last_msg_rcd + 1));
8901991Sheppo 		return (EIO);
8911991Sheppo 	}
8921991Sheppo 
8931991Sheppo 	return (0);
8941991Sheppo }
8951991Sheppo 
8961991Sheppo 
8971991Sheppo /*
8981991Sheppo  * Process an incoming version ctrl message
8991991Sheppo  */
9001991Sheppo static int
9011991Sheppo i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg)
9021991Sheppo {
9031991Sheppo 	int 		rv = 0, idx = ldcp->next_vidx;
9041991Sheppo 	ldc_msg_t 	*pkt;
9051991Sheppo 	uint64_t	tx_tail;
9061991Sheppo 	ldc_ver_t	*rcvd_ver;
9071991Sheppo 
9081991Sheppo 	/* get the received version */
9091991Sheppo 	rcvd_ver = (ldc_ver_t *)((uint64_t)msg + LDC_PAYLOAD_VER_OFF);
9101991Sheppo 
9111991Sheppo 	D2(ldcp->id, "i_ldc_process_VER: (0x%llx) received VER v%u.%u\n",
9121991Sheppo 	    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
9131991Sheppo 
9142336Snarayan 	/* Obtain Tx lock */
9152336Snarayan 	mutex_enter(&ldcp->tx_lock);
9162336Snarayan 
9171991Sheppo 	switch (msg->stype) {
9181991Sheppo 	case LDC_INFO:
9191991Sheppo 
9202793Slm66018 		if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) {
9212793Slm66018 			(void) i_ldc_txq_reconf(ldcp);
9222793Slm66018 			i_ldc_reset_state(ldcp);
9232793Slm66018 			mutex_exit(&ldcp->tx_lock);
9242793Slm66018 			return (EAGAIN);
9252793Slm66018 		}
9262793Slm66018 
9271991Sheppo 		/* get the current tail and pkt for the response */
9281991Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
9291991Sheppo 		if (rv != 0) {
9301991Sheppo 			DWARN(ldcp->id,
9311991Sheppo 			    "i_ldc_process_VER: (0x%llx) err sending "
9321991Sheppo 			    "version ACK/NACK\n", ldcp->id);
9332793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
9342336Snarayan 			mutex_exit(&ldcp->tx_lock);
9351991Sheppo 			return (ECONNRESET);
9361991Sheppo 		}
9371991Sheppo 
9381991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
9391991Sheppo 		ZERO_PKT(pkt);
9401991Sheppo 
9411991Sheppo 		/* initialize the packet */
9421991Sheppo 		pkt->type = LDC_CTRL;
9431991Sheppo 		pkt->ctrl = LDC_VER;
9441991Sheppo 
9451991Sheppo 		for (;;) {
9461991Sheppo 
9471991Sheppo 			D1(ldcp->id, "i_ldc_process_VER: got %u.%u chk %u.%u\n",
9481991Sheppo 			    rcvd_ver->major, rcvd_ver->minor,
9491991Sheppo 			    ldc_versions[idx].major, ldc_versions[idx].minor);
9501991Sheppo 
9511991Sheppo 			if (rcvd_ver->major == ldc_versions[idx].major) {
9521991Sheppo 				/* major version match - ACK version */
9531991Sheppo 				pkt->stype = LDC_ACK;
9541991Sheppo 
9551991Sheppo 				/*
9561991Sheppo 				 * lower minor version to the one this endpt
9571991Sheppo 				 * supports, if necessary
9581991Sheppo 				 */
9591991Sheppo 				if (rcvd_ver->minor > ldc_versions[idx].minor)
9601991Sheppo 					rcvd_ver->minor =
9611991Sheppo 						ldc_versions[idx].minor;
9621991Sheppo 				bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver));
9631991Sheppo 
9641991Sheppo 				break;
9651991Sheppo 			}
9661991Sheppo 
9671991Sheppo 			if (rcvd_ver->major > ldc_versions[idx].major) {
9681991Sheppo 
9691991Sheppo 				D1(ldcp->id, "i_ldc_process_VER: using next"
9701991Sheppo 				    " lower idx=%d, v%u.%u\n", idx,
9711991Sheppo 				    ldc_versions[idx].major,
9721991Sheppo 				    ldc_versions[idx].minor);
9731991Sheppo 
9741991Sheppo 				/* nack with next lower version */
9751991Sheppo 				pkt->stype = LDC_NACK;
9761991Sheppo 				bcopy(&ldc_versions[idx], pkt->udata,
9771991Sheppo 				    sizeof (ldc_versions[idx]));
9781991Sheppo 				ldcp->next_vidx = idx;
9791991Sheppo 				break;
9801991Sheppo 			}
9811991Sheppo 
9821991Sheppo 			/* next major version */
9831991Sheppo 			idx++;
9841991Sheppo 
9851991Sheppo 			D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx);
9861991Sheppo 
9871991Sheppo 			if (idx == LDC_NUM_VERS) {
9881991Sheppo 				/* no version match - send NACK */
9891991Sheppo 				pkt->stype = LDC_NACK;
9901991Sheppo 				bzero(pkt->udata, sizeof (ldc_ver_t));
9911991Sheppo 				ldcp->next_vidx = 0;
9921991Sheppo 				break;
9931991Sheppo 			}
9941991Sheppo 		}
9951991Sheppo 
9961991Sheppo 		/* initiate the send by calling into HV and set the new tail */
9971991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
9981991Sheppo 			(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
9991991Sheppo 
10001991Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
10011991Sheppo 		if (rv == 0) {
10021991Sheppo 			ldcp->tx_tail = tx_tail;
10031991Sheppo 			if (pkt->stype == LDC_ACK) {
10041991Sheppo 				D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent"
10051991Sheppo 				    " version ACK\n", ldcp->id);
10061991Sheppo 				/* Save the ACK'd version */
10071991Sheppo 				ldcp->version.major = rcvd_ver->major;
10081991Sheppo 				ldcp->version.minor = rcvd_ver->minor;
10092032Slm66018 				ldcp->hstate |= TS_RCVD_VER;
10101991Sheppo 				ldcp->tstate |= TS_VER_DONE;
10111991Sheppo 				DWARN(DBG_ALL_LDCS,
10122793Slm66018 				    "(0x%llx) Sent ACK, "
10132793Slm66018 				    "Agreed on version v%u.%u\n",
10141991Sheppo 				    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
10151991Sheppo 			}
10161991Sheppo 		} else {
10171991Sheppo 			DWARN(ldcp->id,
10181991Sheppo 			    "i_ldc_process_VER: (0x%llx) error sending "
10191991Sheppo 			    "ACK/NACK\n", ldcp->id);
10202793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
10212336Snarayan 			mutex_exit(&ldcp->tx_lock);
10221991Sheppo 			return (ECONNRESET);
10231991Sheppo 		}
10241991Sheppo 
10251991Sheppo 		break;
10261991Sheppo 
10271991Sheppo 	case LDC_ACK:
10282793Slm66018 		if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) {
10292793Slm66018 			if (ldcp->version.major != rcvd_ver->major ||
10302793Slm66018 				ldcp->version.minor != rcvd_ver->minor) {
10312793Slm66018 
10322793Slm66018 				/* mismatched version - reset connection */
10332793Slm66018 				DWARN(ldcp->id,
10342793Slm66018 					"i_ldc_process_VER: (0x%llx) recvd"
10352793Slm66018 					" ACK ver != sent ACK ver\n", ldcp->id);
10362793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
10372793Slm66018 				mutex_exit(&ldcp->tx_lock);
10382793Slm66018 				return (ECONNRESET);
10392793Slm66018 			}
10402793Slm66018 		} else {
10412793Slm66018 			/* SUCCESS - we have agreed on a version */
10422793Slm66018 			ldcp->version.major = rcvd_ver->major;
10432793Slm66018 			ldcp->version.minor = rcvd_ver->minor;
10442793Slm66018 			ldcp->tstate |= TS_VER_DONE;
10452793Slm66018 		}
10462793Slm66018 
10473010Slm66018 		D1(ldcp->id, "(0x%llx) Got ACK, Agreed on version v%u.%u\n",
10481991Sheppo 		    ldcp->id, rcvd_ver->major, rcvd_ver->minor);
10491991Sheppo 
10501991Sheppo 		/* initiate RTS-RTR-RDX handshake */
10511991Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
10521991Sheppo 		if (rv) {
10531991Sheppo 			DWARN(ldcp->id,
10542793Slm66018 		    "i_ldc_process_VER: (0x%llx) cannot send RTS\n",
10551991Sheppo 			    ldcp->id);
10562793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
10572336Snarayan 			mutex_exit(&ldcp->tx_lock);
10581991Sheppo 			return (ECONNRESET);
10591991Sheppo 		}
10601991Sheppo 
10611991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
10621991Sheppo 		ZERO_PKT(pkt);
10631991Sheppo 
10641991Sheppo 		pkt->type = LDC_CTRL;
10651991Sheppo 		pkt->stype = LDC_INFO;
10661991Sheppo 		pkt->ctrl = LDC_RTS;
10671991Sheppo 		pkt->env = ldcp->mode;
10681991Sheppo 		if (ldcp->mode != LDC_MODE_RAW)
10691991Sheppo 			pkt->seqid = LDC_INIT_SEQID;
10701991Sheppo 
10711991Sheppo 		ldcp->last_msg_rcd = LDC_INIT_SEQID;
10721991Sheppo 
10731991Sheppo 		DUMP_LDC_PKT(ldcp, "i_ldc_process_VER snd rts", (uint64_t)pkt);
10741991Sheppo 
10751991Sheppo 		/* initiate the send by calling into HV and set the new tail */
10761991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
10771991Sheppo 			(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
10781991Sheppo 
10791991Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
10801991Sheppo 		if (rv) {
10811991Sheppo 			D2(ldcp->id,
10821991Sheppo 			    "i_ldc_process_VER: (0x%llx) no listener\n",
10831991Sheppo 			    ldcp->id);
10842793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
10852336Snarayan 			mutex_exit(&ldcp->tx_lock);
10861991Sheppo 			return (ECONNRESET);
10871991Sheppo 		}
10881991Sheppo 
10891991Sheppo 		ldcp->tx_tail = tx_tail;
10901991Sheppo 		ldcp->hstate |= TS_SENT_RTS;
10911991Sheppo 
10921991Sheppo 		break;
10931991Sheppo 
10941991Sheppo 	case LDC_NACK:
10951991Sheppo 		/* check if version in NACK is zero */
10961991Sheppo 		if (rcvd_ver->major == 0 && rcvd_ver->minor == 0) {
10971991Sheppo 			/* version handshake failure */
10981991Sheppo 			DWARN(DBG_ALL_LDCS,
10991991Sheppo 			    "i_ldc_process_VER: (0x%llx) no version match\n",
11001991Sheppo 			    ldcp->id);
11012793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
11022336Snarayan 			mutex_exit(&ldcp->tx_lock);
11031991Sheppo 			return (ECONNRESET);
11041991Sheppo 		}
11051991Sheppo 
11061991Sheppo 		/* get the current tail and pkt for the response */
11071991Sheppo 		rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
11081991Sheppo 		if (rv != 0) {
11091991Sheppo 			cmn_err(CE_NOTE,
11101991Sheppo 			    "i_ldc_process_VER: (0x%lx) err sending "
11111991Sheppo 			    "version ACK/NACK\n", ldcp->id);
11122793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
11132336Snarayan 			mutex_exit(&ldcp->tx_lock);
11141991Sheppo 			return (ECONNRESET);
11151991Sheppo 		}
11161991Sheppo 
11171991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
11181991Sheppo 		ZERO_PKT(pkt);
11191991Sheppo 
11201991Sheppo 		/* initialize the packet */
11211991Sheppo 		pkt->type = LDC_CTRL;
11221991Sheppo 		pkt->ctrl = LDC_VER;
11231991Sheppo 		pkt->stype = LDC_INFO;
11241991Sheppo 
11251991Sheppo 		/* check ver in NACK msg has a match */
11261991Sheppo 		for (;;) {
11271991Sheppo 			if (rcvd_ver->major == ldc_versions[idx].major) {
11281991Sheppo 				/*
11291991Sheppo 				 * major version match - resubmit request
11301991Sheppo 				 * if lower minor version to the one this endpt
11311991Sheppo 				 * supports, if necessary
11321991Sheppo 				 */
11331991Sheppo 				if (rcvd_ver->minor > ldc_versions[idx].minor)
11341991Sheppo 					rcvd_ver->minor =
11351991Sheppo 						ldc_versions[idx].minor;
11361991Sheppo 				bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver));
11371991Sheppo 				break;
11381991Sheppo 
11391991Sheppo 			}
11401991Sheppo 
11411991Sheppo 			if (rcvd_ver->major > ldc_versions[idx].major) {
11421991Sheppo 
11431991Sheppo 				D1(ldcp->id, "i_ldc_process_VER: using next"
11441991Sheppo 				    " lower idx=%d, v%u.%u\n", idx,
11451991Sheppo 				    ldc_versions[idx].major,
11461991Sheppo 				    ldc_versions[idx].minor);
11471991Sheppo 
11481991Sheppo 				/* send next lower version */
11491991Sheppo 				bcopy(&ldc_versions[idx], pkt->udata,
11501991Sheppo 				    sizeof (ldc_versions[idx]));
11511991Sheppo 				ldcp->next_vidx = idx;
11521991Sheppo 				break;
11531991Sheppo 			}
11541991Sheppo 
11551991Sheppo 			/* next version */
11561991Sheppo 			idx++;
11571991Sheppo 
11581991Sheppo 			D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx);
11591991Sheppo 
11601991Sheppo 			if (idx == LDC_NUM_VERS) {
11611991Sheppo 				/* no version match - terminate */
11621991Sheppo 				ldcp->next_vidx = 0;
11632336Snarayan 				mutex_exit(&ldcp->tx_lock);
11641991Sheppo 				return (ECONNRESET);
11651991Sheppo 			}
11661991Sheppo 		}
11671991Sheppo 
11681991Sheppo 		/* initiate the send by calling into HV and set the new tail */
11691991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) %
11701991Sheppo 			(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
11711991Sheppo 
11721991Sheppo 		rv = i_ldc_set_tx_tail(ldcp, tx_tail);
11731991Sheppo 		if (rv == 0) {
11741991Sheppo 			D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent version"
11751991Sheppo 			    "INFO v%u.%u\n", ldcp->id, ldc_versions[idx].major,
11761991Sheppo 			    ldc_versions[idx].minor);
11771991Sheppo 			ldcp->tx_tail = tx_tail;
11781991Sheppo 		} else {
11791991Sheppo 			cmn_err(CE_NOTE,
11801991Sheppo 			    "i_ldc_process_VER: (0x%lx) error sending version"
11811991Sheppo 			    "INFO\n", ldcp->id);
11822793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
11832336Snarayan 			mutex_exit(&ldcp->tx_lock);
11841991Sheppo 			return (ECONNRESET);
11851991Sheppo 		}
11861991Sheppo 
11871991Sheppo 		break;
11881991Sheppo 	}
11891991Sheppo 
11902336Snarayan 	mutex_exit(&ldcp->tx_lock);
11911991Sheppo 	return (rv);
11921991Sheppo }
11931991Sheppo 
11941991Sheppo 
11951991Sheppo /*
11961991Sheppo  * Process an incoming RTS ctrl message
11971991Sheppo  */
11981991Sheppo static int
11991991Sheppo i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg)
12001991Sheppo {
12011991Sheppo 	int 		rv = 0;
12021991Sheppo 	ldc_msg_t 	*pkt;
12031991Sheppo 	uint64_t	tx_tail;
12041991Sheppo 	boolean_t	sent_NACK = B_FALSE;
12051991Sheppo 
12061991Sheppo 	D2(ldcp->id, "i_ldc_process_RTS: (0x%llx) received RTS\n", ldcp->id);
12071991Sheppo 
12081991Sheppo 	switch (msg->stype) {
12091991Sheppo 	case LDC_NACK:
12101991Sheppo 		DWARN(ldcp->id,
12111991Sheppo 		    "i_ldc_process_RTS: (0x%llx) RTS NACK received\n",
12121991Sheppo 		    ldcp->id);
12131991Sheppo 
12141991Sheppo 		/* Reset the channel -- as we cannot continue */
12152336Snarayan 		mutex_enter(&ldcp->tx_lock);
12162793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
12172336Snarayan 		mutex_exit(&ldcp->tx_lock);
12181991Sheppo 		rv = ECONNRESET;
12191991Sheppo 		break;
12201991Sheppo 
12211991Sheppo 	case LDC_INFO:
12221991Sheppo 
12231991Sheppo 		/* check mode */
12241991Sheppo 		if (ldcp->mode != (ldc_mode_t)msg->env) {
12251991Sheppo 			cmn_err(CE_NOTE,
12261991Sheppo 			    "i_ldc_process_RTS: (0x%lx) mode mismatch\n",
12271991Sheppo 			    ldcp->id);
12281991Sheppo 			/*
12291991Sheppo 			 * send NACK in response to MODE message
12301991Sheppo 			 * get the current tail for the response
12311991Sheppo 			 */
12321991Sheppo 			rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTS);
12331991Sheppo 			if (rv) {
12341991Sheppo 				/* if cannot send NACK - reset channel */
12352336Snarayan 				mutex_enter(&ldcp->tx_lock);
12362793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
12372336Snarayan 				mutex_exit(&ldcp->tx_lock);
12381991Sheppo 				rv = ECONNRESET;
12391991Sheppo 				break;
12401991Sheppo 			}
12411991Sheppo 			sent_NACK = B_TRUE;
12421991Sheppo 		}
12431991Sheppo 		break;
12441991Sheppo 	default:
12451991Sheppo 		DWARN(ldcp->id, "i_ldc_process_RTS: (0x%llx) unexp ACK\n",
12461991Sheppo 		    ldcp->id);
12472336Snarayan 		mutex_enter(&ldcp->tx_lock);
12482793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
12492336Snarayan 		mutex_exit(&ldcp->tx_lock);
12501991Sheppo 		rv = ECONNRESET;
12511991Sheppo 		break;
12521991Sheppo 	}
12531991Sheppo 
12541991Sheppo 	/*
12551991Sheppo 	 * If either the connection was reset (when rv != 0) or
12561991Sheppo 	 * a NACK was sent, we return. In the case of a NACK
12571991Sheppo 	 * we dont want to consume the packet that came in but
12581991Sheppo 	 * not record that we received the RTS
12591991Sheppo 	 */
12601991Sheppo 	if (rv || sent_NACK)
12611991Sheppo 		return (rv);
12621991Sheppo 
12631991Sheppo 	/* record RTS received */
12641991Sheppo 	ldcp->hstate |= TS_RCVD_RTS;
12651991Sheppo 
12661991Sheppo 	/* store initial SEQID info */
12671991Sheppo 	ldcp->last_msg_snt = msg->seqid;
12681991Sheppo 
12692336Snarayan 	/* Obtain Tx lock */
12702336Snarayan 	mutex_enter(&ldcp->tx_lock);
12712336Snarayan 
12721991Sheppo 	/* get the current tail for the response */
12731991Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
12741991Sheppo 	if (rv != 0) {
12751991Sheppo 		cmn_err(CE_NOTE,
12761991Sheppo 		    "i_ldc_process_RTS: (0x%lx) err sending RTR\n",
12771991Sheppo 		    ldcp->id);
12782793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
12792336Snarayan 		mutex_exit(&ldcp->tx_lock);
12801991Sheppo 		return (ECONNRESET);
12811991Sheppo 	}
12821991Sheppo 
12831991Sheppo 	pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
12841991Sheppo 	ZERO_PKT(pkt);
12851991Sheppo 
12861991Sheppo 	/* initialize the packet */
12871991Sheppo 	pkt->type = LDC_CTRL;
12881991Sheppo 	pkt->stype = LDC_INFO;
12891991Sheppo 	pkt->ctrl = LDC_RTR;
12901991Sheppo 	pkt->env = ldcp->mode;
12911991Sheppo 	if (ldcp->mode != LDC_MODE_RAW)
12921991Sheppo 		pkt->seqid = LDC_INIT_SEQID;
12931991Sheppo 
12941991Sheppo 	ldcp->last_msg_rcd = msg->seqid;
12951991Sheppo 
12961991Sheppo 	/* initiate the send by calling into HV and set the new tail */
12971991Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
12981991Sheppo 		(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
12991991Sheppo 
13001991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
13011991Sheppo 	if (rv == 0) {
13021991Sheppo 		D2(ldcp->id,
13031991Sheppo 		    "i_ldc_process_RTS: (0x%llx) sent RTR\n", ldcp->id);
13041991Sheppo 		DUMP_LDC_PKT(ldcp, "i_ldc_process_RTS sent rtr", (uint64_t)pkt);
13051991Sheppo 
13061991Sheppo 		ldcp->tx_tail = tx_tail;
13071991Sheppo 		ldcp->hstate |= TS_SENT_RTR;
13081991Sheppo 
13091991Sheppo 	} else {
13101991Sheppo 		cmn_err(CE_NOTE,
13111991Sheppo 		    "i_ldc_process_RTS: (0x%lx) error sending RTR\n",
13121991Sheppo 		    ldcp->id);
13132793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
13142336Snarayan 		mutex_exit(&ldcp->tx_lock);
13151991Sheppo 		return (ECONNRESET);
13161991Sheppo 	}
13171991Sheppo 
13182336Snarayan 	mutex_exit(&ldcp->tx_lock);
13191991Sheppo 	return (0);
13201991Sheppo }
13211991Sheppo 
13221991Sheppo /*
13231991Sheppo  * Process an incoming RTR ctrl message
13241991Sheppo  */
13251991Sheppo static int
13261991Sheppo i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg)
13271991Sheppo {
13281991Sheppo 	int 		rv = 0;
13291991Sheppo 	boolean_t	sent_NACK = B_FALSE;
13301991Sheppo 
13311991Sheppo 	D2(ldcp->id, "i_ldc_process_RTR: (0x%llx) received RTR\n", ldcp->id);
13321991Sheppo 
13331991Sheppo 	switch (msg->stype) {
13341991Sheppo 	case LDC_NACK:
13351991Sheppo 		/* RTR NACK received */
13361991Sheppo 		DWARN(ldcp->id,
13371991Sheppo 		    "i_ldc_process_RTR: (0x%llx) RTR NACK received\n",
13381991Sheppo 		    ldcp->id);
13391991Sheppo 
13401991Sheppo 		/* Reset the channel -- as we cannot continue */
13412336Snarayan 		mutex_enter(&ldcp->tx_lock);
13422793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
13432336Snarayan 		mutex_exit(&ldcp->tx_lock);
13441991Sheppo 		rv = ECONNRESET;
13451991Sheppo 
13461991Sheppo 		break;
13471991Sheppo 
13481991Sheppo 	case LDC_INFO:
13491991Sheppo 
13501991Sheppo 		/* check mode */
13511991Sheppo 		if (ldcp->mode != (ldc_mode_t)msg->env) {
13521991Sheppo 			DWARN(ldcp->id,
13533010Slm66018 			    "i_ldc_process_RTR: (0x%llx) mode mismatch, "
13543010Slm66018 			    "expecting 0x%x, got 0x%x\n",
13553010Slm66018 			    ldcp->id, ldcp->mode, (ldc_mode_t)msg->env);
13561991Sheppo 			/*
13571991Sheppo 			 * send NACK in response to MODE message
13581991Sheppo 			 * get the current tail for the response
13591991Sheppo 			 */
13601991Sheppo 			rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTR);
13611991Sheppo 			if (rv) {
13621991Sheppo 				/* if cannot send NACK - reset channel */
13632336Snarayan 				mutex_enter(&ldcp->tx_lock);
13642793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
13652336Snarayan 				mutex_exit(&ldcp->tx_lock);
13661991Sheppo 				rv = ECONNRESET;
13671991Sheppo 				break;
13681991Sheppo 			}
13691991Sheppo 			sent_NACK = B_TRUE;
13701991Sheppo 		}
13711991Sheppo 		break;
13721991Sheppo 
13731991Sheppo 	default:
13741991Sheppo 		DWARN(ldcp->id, "i_ldc_process_RTR: (0x%llx) unexp ACK\n",
13751991Sheppo 		    ldcp->id);
13761991Sheppo 
13771991Sheppo 		/* Reset the channel -- as we cannot continue */
13782336Snarayan 		mutex_enter(&ldcp->tx_lock);
13792793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
13802336Snarayan 		mutex_exit(&ldcp->tx_lock);
13811991Sheppo 		rv = ECONNRESET;
13821991Sheppo 		break;
13831991Sheppo 	}
13841991Sheppo 
13851991Sheppo 	/*
13861991Sheppo 	 * If either the connection was reset (when rv != 0) or
13871991Sheppo 	 * a NACK was sent, we return. In the case of a NACK
13881991Sheppo 	 * we dont want to consume the packet that came in but
13891991Sheppo 	 * not record that we received the RTR
13901991Sheppo 	 */
13911991Sheppo 	if (rv || sent_NACK)
13921991Sheppo 		return (rv);
13931991Sheppo 
13941991Sheppo 	ldcp->last_msg_snt = msg->seqid;
13951991Sheppo 	ldcp->hstate |= TS_RCVD_RTR;
13961991Sheppo 
13971991Sheppo 	rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_INFO, LDC_RDX);
13981991Sheppo 	if (rv) {
13991991Sheppo 		cmn_err(CE_NOTE,
14001991Sheppo 		    "i_ldc_process_RTR: (0x%lx) cannot send RDX\n",
14011991Sheppo 		    ldcp->id);
14022336Snarayan 		mutex_enter(&ldcp->tx_lock);
14032793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
14042336Snarayan 		mutex_exit(&ldcp->tx_lock);
14051991Sheppo 		return (ECONNRESET);
14061991Sheppo 	}
14071991Sheppo 	D2(ldcp->id,
14081991Sheppo 	    "i_ldc_process_RTR: (0x%llx) sent RDX\n", ldcp->id);
14091991Sheppo 
14101991Sheppo 	ldcp->hstate |= TS_SENT_RDX;
14111991Sheppo 	ldcp->tstate |= TS_HSHAKE_DONE;
14122793Slm66018 	if ((ldcp->tstate & TS_IN_RESET) == 0)
14132793Slm66018 		ldcp->status = LDC_UP;
14141991Sheppo 
14153010Slm66018 	D1(ldcp->id, "(0x%llx) Handshake Complete\n", ldcp->id);
14161991Sheppo 
14171991Sheppo 	return (0);
14181991Sheppo }
14191991Sheppo 
14201991Sheppo 
14211991Sheppo /*
14221991Sheppo  * Process an incoming RDX ctrl message
14231991Sheppo  */
14241991Sheppo static int
14251991Sheppo i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg)
14261991Sheppo {
14271991Sheppo 	int	rv = 0;
14281991Sheppo 
14291991Sheppo 	D2(ldcp->id, "i_ldc_process_RDX: (0x%llx) received RDX\n", ldcp->id);
14301991Sheppo 
14311991Sheppo 	switch (msg->stype) {
14321991Sheppo 	case LDC_NACK:
14331991Sheppo 		/* RDX NACK received */
14341991Sheppo 		DWARN(ldcp->id,
14351991Sheppo 		    "i_ldc_process_RDX: (0x%llx) RDX NACK received\n",
14361991Sheppo 		    ldcp->id);
14371991Sheppo 
14381991Sheppo 		/* Reset the channel -- as we cannot continue */
14392336Snarayan 		mutex_enter(&ldcp->tx_lock);
14402793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
14412336Snarayan 		mutex_exit(&ldcp->tx_lock);
14421991Sheppo 		rv = ECONNRESET;
14431991Sheppo 
14441991Sheppo 		break;
14451991Sheppo 
14461991Sheppo 	case LDC_INFO:
14471991Sheppo 
14481991Sheppo 		/*
14491991Sheppo 		 * if channel is UP and a RDX received after data transmission
14501991Sheppo 		 * has commenced it is an error
14511991Sheppo 		 */
14521991Sheppo 		if ((ldcp->tstate == TS_UP) && (ldcp->hstate & TS_RCVD_RDX)) {
14531991Sheppo 			DWARN(DBG_ALL_LDCS,
14541991Sheppo 			    "i_ldc_process_RDX: (0x%llx) unexpected RDX"
14551991Sheppo 			    " - LDC reset\n", ldcp->id);
14562336Snarayan 			mutex_enter(&ldcp->tx_lock);
14572793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
14582336Snarayan 			mutex_exit(&ldcp->tx_lock);
14591991Sheppo 			return (ECONNRESET);
14601991Sheppo 		}
14611991Sheppo 
14621991Sheppo 		ldcp->hstate |= TS_RCVD_RDX;
14631991Sheppo 		ldcp->tstate |= TS_HSHAKE_DONE;
14642793Slm66018 		if ((ldcp->tstate & TS_IN_RESET) == 0)
14652793Slm66018 			ldcp->status = LDC_UP;
14661991Sheppo 
14671991Sheppo 		D1(DBG_ALL_LDCS, "(0x%llx) Handshake Complete\n", ldcp->id);
14681991Sheppo 		break;
14691991Sheppo 
14701991Sheppo 	default:
14711991Sheppo 		DWARN(ldcp->id, "i_ldc_process_RDX: (0x%llx) unexp ACK\n",
14721991Sheppo 		    ldcp->id);
14731991Sheppo 
14741991Sheppo 		/* Reset the channel -- as we cannot continue */
14752336Snarayan 		mutex_enter(&ldcp->tx_lock);
14762793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
14772336Snarayan 		mutex_exit(&ldcp->tx_lock);
14781991Sheppo 		rv = ECONNRESET;
14791991Sheppo 		break;
14801991Sheppo 	}
14811991Sheppo 
14821991Sheppo 	return (rv);
14831991Sheppo }
14841991Sheppo 
14851991Sheppo /*
14861991Sheppo  * Process an incoming ACK for a data packet
14871991Sheppo  */
14881991Sheppo static int
14891991Sheppo i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg)
14901991Sheppo {
14911991Sheppo 	int		rv;
14921991Sheppo 	uint64_t 	tx_head;
14931991Sheppo 	ldc_msg_t	*pkt;
14941991Sheppo 
14952336Snarayan 	/* Obtain Tx lock */
14962336Snarayan 	mutex_enter(&ldcp->tx_lock);
14972336Snarayan 
14981991Sheppo 	/*
14992336Snarayan 	 * Read the current Tx head and tail
15001991Sheppo 	 */
15011991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
15021991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
15031991Sheppo 	if (rv != 0) {
15041991Sheppo 		cmn_err(CE_WARN,
15051991Sheppo 		    "i_ldc_process_data_ACK: (0x%lx) cannot read qptrs\n",
15061991Sheppo 		    ldcp->id);
15072336Snarayan 
15082336Snarayan 		/* Reset the channel -- as we cannot continue */
15092793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
15102336Snarayan 		mutex_exit(&ldcp->tx_lock);
15112336Snarayan 		return (ECONNRESET);
15121991Sheppo 	}
15131991Sheppo 
15141991Sheppo 	/*
15151991Sheppo 	 * loop from where the previous ACK location was to the
15161991Sheppo 	 * current head location. This is how far the HV has
15171991Sheppo 	 * actually send pkts. Pkts between head and tail are
15181991Sheppo 	 * yet to be sent by HV.
15191991Sheppo 	 */
15201991Sheppo 	tx_head = ldcp->tx_ackd_head;
15211991Sheppo 	for (;;) {
15221991Sheppo 		pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_head);
15231991Sheppo 		tx_head = (tx_head + LDC_PACKET_SIZE) %
15241991Sheppo 			(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
15251991Sheppo 
15261991Sheppo 		if (pkt->seqid == msg->ackid) {
15271991Sheppo 			D2(ldcp->id,
15281991Sheppo 			    "i_ldc_process_data_ACK: (0x%llx) found packet\n",
15291991Sheppo 			    ldcp->id);
15301991Sheppo 			ldcp->last_ack_rcd = msg->ackid;
15311991Sheppo 			ldcp->tx_ackd_head = tx_head;
15321991Sheppo 			break;
15331991Sheppo 		}
15341991Sheppo 		if (tx_head == ldcp->tx_head) {
15351991Sheppo 			/* could not find packet */
15361991Sheppo 			DWARN(ldcp->id,
15371991Sheppo 			    "i_ldc_process_data_ACK: (0x%llx) invalid ACKid\n",
15381991Sheppo 			    ldcp->id);
15392336Snarayan 
15402336Snarayan 			/* Reset the channel -- as we cannot continue */
15412793Slm66018 			i_ldc_reset(ldcp, B_TRUE);
15422336Snarayan 			mutex_exit(&ldcp->tx_lock);
15432336Snarayan 			return (ECONNRESET);
15441991Sheppo 		}
15451991Sheppo 	}
15461991Sheppo 
15472336Snarayan 	mutex_exit(&ldcp->tx_lock);
15481991Sheppo 	return (0);
15491991Sheppo }
15501991Sheppo 
15511991Sheppo /*
15521991Sheppo  * Process incoming control message
15531991Sheppo  * Return 0 - session can continue
15541991Sheppo  *        EAGAIN - reprocess packet - state was changed
15551991Sheppo  *	  ECONNRESET - channel was reset
15561991Sheppo  */
15571991Sheppo static int
15581991Sheppo i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *msg)
15591991Sheppo {
15601991Sheppo 	int 		rv = 0;
15611991Sheppo 
15622793Slm66018 	D1(ldcp->id, "i_ldc_ctrlmsg: (%llx) tstate = %lx, hstate = %lx\n",
15632793Slm66018 	    ldcp->id, ldcp->tstate, ldcp->hstate);
15642793Slm66018 
15652793Slm66018 	switch (ldcp->tstate & ~TS_IN_RESET) {
15661991Sheppo 
15671991Sheppo 	case TS_OPEN:
15681991Sheppo 	case TS_READY:
15691991Sheppo 
15701991Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
15711991Sheppo 		case LDC_VER:
15721991Sheppo 			/* process version message */
15731991Sheppo 			rv = i_ldc_process_VER(ldcp, msg);
15741991Sheppo 			break;
15751991Sheppo 		default:
15761991Sheppo 			DWARN(ldcp->id,
15771991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
15781991Sheppo 			    "tstate=0x%x\n", ldcp->id,
15791991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
15801991Sheppo 			break;
15811991Sheppo 		}
15821991Sheppo 
15831991Sheppo 		break;
15841991Sheppo 
15851991Sheppo 	case TS_VREADY:
15861991Sheppo 
15871991Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
15881991Sheppo 		case LDC_VER:
15892793Slm66018 			/* process version message */
15902793Slm66018 			rv = i_ldc_process_VER(ldcp, msg);
15911991Sheppo 			break;
15921991Sheppo 		case LDC_RTS:
15931991Sheppo 			/* process RTS message */
15941991Sheppo 			rv = i_ldc_process_RTS(ldcp, msg);
15951991Sheppo 			break;
15961991Sheppo 		case LDC_RTR:
15971991Sheppo 			/* process RTR message */
15981991Sheppo 			rv = i_ldc_process_RTR(ldcp, msg);
15991991Sheppo 			break;
16001991Sheppo 		case LDC_RDX:
16011991Sheppo 			/* process RDX message */
16021991Sheppo 			rv = i_ldc_process_RDX(ldcp, msg);
16031991Sheppo 			break;
16041991Sheppo 		default:
16051991Sheppo 			DWARN(ldcp->id,
16061991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
16071991Sheppo 			    "tstate=0x%x\n", ldcp->id,
16081991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
16091991Sheppo 			break;
16101991Sheppo 		}
16111991Sheppo 
16121991Sheppo 		break;
16131991Sheppo 
16141991Sheppo 	case TS_UP:
16151991Sheppo 
16161991Sheppo 		switch (msg->ctrl & LDC_CTRL_MASK) {
16171991Sheppo 		case LDC_VER:
16181991Sheppo 			DWARN(ldcp->id,
16191991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexpected VER "
16201991Sheppo 			    "- LDC reset\n", ldcp->id);
16211991Sheppo 			/* peer is redoing version negotiation */
16222336Snarayan 			mutex_enter(&ldcp->tx_lock);
16231991Sheppo 			(void) i_ldc_txq_reconf(ldcp);
16241991Sheppo 			i_ldc_reset_state(ldcp);
16252336Snarayan 			mutex_exit(&ldcp->tx_lock);
16261991Sheppo 			rv = EAGAIN;
16271991Sheppo 			break;
16281991Sheppo 
16291991Sheppo 		case LDC_RDX:
16301991Sheppo 			/* process RDX message */
16311991Sheppo 			rv = i_ldc_process_RDX(ldcp, msg);
16321991Sheppo 			break;
16331991Sheppo 
16341991Sheppo 		default:
16351991Sheppo 			DWARN(ldcp->id,
16361991Sheppo 			    "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
16371991Sheppo 			    "tstate=0x%x\n", ldcp->id,
16381991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
16391991Sheppo 			break;
16401991Sheppo 		}
16411991Sheppo 	}
16421991Sheppo 
16431991Sheppo 	return (rv);
16441991Sheppo }
16451991Sheppo 
16461991Sheppo /*
16471991Sheppo  * Register channel with the channel nexus
16481991Sheppo  */
16491991Sheppo static int
16501991Sheppo i_ldc_register_channel(ldc_chan_t *ldcp)
16511991Sheppo {
16521991Sheppo 	int		rv = 0;
16531991Sheppo 	ldc_cnex_t	*cinfo = &ldcssp->cinfo;
16541991Sheppo 
16551991Sheppo 	if (cinfo->dip == NULL) {
16561991Sheppo 		DWARN(ldcp->id,
16571991Sheppo 		    "i_ldc_register_channel: cnex has not registered\n");
16581991Sheppo 		return (EAGAIN);
16591991Sheppo 	}
16601991Sheppo 
16611991Sheppo 	rv = cinfo->reg_chan(cinfo->dip, ldcp->id, ldcp->devclass);
16621991Sheppo 	if (rv) {
16631991Sheppo 		DWARN(ldcp->id,
16641991Sheppo 		    "i_ldc_register_channel: cannot register channel\n");
16651991Sheppo 		return (rv);
16661991Sheppo 	}
16671991Sheppo 
16681991Sheppo 	rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR,
16691991Sheppo 	    i_ldc_tx_hdlr, ldcp, NULL);
16701991Sheppo 	if (rv) {
16711991Sheppo 		DWARN(ldcp->id,
16721991Sheppo 		    "i_ldc_register_channel: cannot add Tx interrupt\n");
16731991Sheppo 		(void) cinfo->unreg_chan(cinfo->dip, ldcp->id);
16741991Sheppo 		return (rv);
16751991Sheppo 	}
16761991Sheppo 
16771991Sheppo 	rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR,
16781991Sheppo 	    i_ldc_rx_hdlr, ldcp, NULL);
16791991Sheppo 	if (rv) {
16801991Sheppo 		DWARN(ldcp->id,
16811991Sheppo 		    "i_ldc_register_channel: cannot add Rx interrupt\n");
16821991Sheppo 		(void) cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
16831991Sheppo 		(void) cinfo->unreg_chan(cinfo->dip, ldcp->id);
16841991Sheppo 		return (rv);
16851991Sheppo 	}
16861991Sheppo 
16871991Sheppo 	ldcp->tstate |= TS_CNEX_RDY;
16881991Sheppo 
16891991Sheppo 	return (0);
16901991Sheppo }
16911991Sheppo 
16921991Sheppo /*
16931991Sheppo  * Unregister a channel with the channel nexus
16941991Sheppo  */
16951991Sheppo static int
16961991Sheppo i_ldc_unregister_channel(ldc_chan_t *ldcp)
16971991Sheppo {
16981991Sheppo 	int		rv = 0;
16991991Sheppo 	ldc_cnex_t	*cinfo = &ldcssp->cinfo;
17001991Sheppo 
17011991Sheppo 	if (cinfo->dip == NULL) {
17021991Sheppo 		DWARN(ldcp->id,
17031991Sheppo 		    "i_ldc_unregister_channel: cnex has not registered\n");
17041991Sheppo 		return (EAGAIN);
17051991Sheppo 	}
17061991Sheppo 
17071991Sheppo 	if (ldcp->tstate & TS_CNEX_RDY) {
17081991Sheppo 
17092336Snarayan 		/* Remove the Rx interrupt */
17101991Sheppo 		rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR);
17111991Sheppo 		if (rv) {
17122793Slm66018 			if (rv != EAGAIN) {
17132793Slm66018 				DWARN(ldcp->id,
17142793Slm66018 				    "i_ldc_unregister_channel: err removing "
17152793Slm66018 				    "Rx intr\n");
17162793Slm66018 				return (rv);
17172793Slm66018 			}
17182793Slm66018 
17192793Slm66018 			/*
17202793Slm66018 			 * If interrupts are pending and handler has
17212793Slm66018 			 * finished running, clear interrupt and try
17222793Slm66018 			 * again
17232793Slm66018 			 */
17242793Slm66018 			if (ldcp->rx_intr_state != LDC_INTR_PEND)
17252793Slm66018 				return (rv);
17262793Slm66018 
17272793Slm66018 			(void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
17282793Slm66018 			rv = cinfo->rem_intr(cinfo->dip, ldcp->id,
17292793Slm66018 			    CNEX_RX_INTR);
17302793Slm66018 			if (rv) {
17312793Slm66018 				DWARN(ldcp->id, "i_ldc_unregister_channel: "
17322793Slm66018 				    "err removing Rx interrupt\n");
17332793Slm66018 				return (rv);
17342793Slm66018 			}
17351991Sheppo 		}
17362336Snarayan 
17372336Snarayan 		/* Remove the Tx interrupt */
17381991Sheppo 		rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
17391991Sheppo 		if (rv) {
17401991Sheppo 			DWARN(ldcp->id,
17411991Sheppo 			    "i_ldc_unregister_channel: err removing Tx intr\n");
17422336Snarayan 			return (rv);
17431991Sheppo 		}
17442336Snarayan 
17452336Snarayan 		/* Unregister the channel */
17461991Sheppo 		rv = cinfo->unreg_chan(ldcssp->cinfo.dip, ldcp->id);
17471991Sheppo 		if (rv) {
17481991Sheppo 			DWARN(ldcp->id,
17491991Sheppo 			    "i_ldc_unregister_channel: cannot unreg channel\n");
17502336Snarayan 			return (rv);
17511991Sheppo 		}
17521991Sheppo 
17531991Sheppo 		ldcp->tstate &= ~TS_CNEX_RDY;
17541991Sheppo 	}
17551991Sheppo 
17561991Sheppo 	return (0);
17571991Sheppo }
17581991Sheppo 
17591991Sheppo 
17601991Sheppo /*
17611991Sheppo  * LDC transmit interrupt handler
17621991Sheppo  *    triggered for chanel up/down/reset events
17631991Sheppo  *    and Tx queue content changes
17641991Sheppo  */
17651991Sheppo static uint_t
17661991Sheppo i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2)
17671991Sheppo {
17681991Sheppo 	_NOTE(ARGUNUSED(arg2))
17691991Sheppo 
17701991Sheppo 	int 		rv;
17711991Sheppo 	ldc_chan_t 	*ldcp;
17721991Sheppo 	boolean_t 	notify_client = B_FALSE;
17732793Slm66018 	uint64_t	notify_event = 0, link_state;
17741991Sheppo 
17751991Sheppo 	/* Get the channel for which interrupt was received */
17761991Sheppo 	ASSERT(arg1 != NULL);
17771991Sheppo 	ldcp = (ldc_chan_t *)arg1;
17781991Sheppo 
17791991Sheppo 	D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
17801991Sheppo 	    ldcp->id, ldcp);
17811991Sheppo 
17821991Sheppo 	/* Lock channel */
17831991Sheppo 	mutex_enter(&ldcp->lock);
17841991Sheppo 
17852336Snarayan 	/* Obtain Tx lock */
17862336Snarayan 	mutex_enter(&ldcp->tx_lock);
17872336Snarayan 
17882531Snarayan 	/* mark interrupt as pending */
17892793Slm66018 	ldcp->tx_intr_state = LDC_INTR_ACTIVE;
17902793Slm66018 
17912793Slm66018 	/* save current link state */
17922793Slm66018 	link_state = ldcp->link_state;
17932531Snarayan 
17941991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id, &ldcp->tx_head, &ldcp->tx_tail,
17951991Sheppo 	    &ldcp->link_state);
17961991Sheppo 	if (rv) {
17971991Sheppo 		cmn_err(CE_WARN,
17981991Sheppo 		    "i_ldc_tx_hdlr: (0x%lx) cannot read queue ptrs rv=0x%d\n",
17991991Sheppo 		    ldcp->id, rv);
18002531Snarayan 		i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
18012336Snarayan 		mutex_exit(&ldcp->tx_lock);
18021991Sheppo 		mutex_exit(&ldcp->lock);
18031991Sheppo 		return (DDI_INTR_CLAIMED);
18041991Sheppo 	}
18051991Sheppo 
18061991Sheppo 	/*
18071991Sheppo 	 * reset the channel state if the channel went down
18081991Sheppo 	 * (other side unconfigured queue) or channel was reset
18091991Sheppo 	 * (other side reconfigured its queue)
18101991Sheppo 	 */
18112793Slm66018 	if (link_state != ldcp->link_state &&
18122793Slm66018 	    ldcp->link_state == LDC_CHANNEL_DOWN) {
18131991Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link down\n", ldcp->id);
18142793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
18151991Sheppo 		notify_client = B_TRUE;
18161991Sheppo 		notify_event = LDC_EVT_DOWN;
18171991Sheppo 	}
18181991Sheppo 
18192793Slm66018 	if (link_state != ldcp->link_state &&
18202793Slm66018 	    ldcp->link_state == LDC_CHANNEL_RESET) {
18211991Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link reset\n", ldcp->id);
18222793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
18231991Sheppo 		notify_client = B_TRUE;
18241991Sheppo 		notify_event = LDC_EVT_RESET;
18251991Sheppo 	}
18261991Sheppo 
18272793Slm66018 	if (link_state != ldcp->link_state &&
18282793Slm66018 	    (ldcp->tstate & ~TS_IN_RESET) == TS_OPEN &&
18292793Slm66018 	    ldcp->link_state == LDC_CHANNEL_UP) {
18301991Sheppo 		D1(ldcp->id, "i_ldc_tx_hdlr: channel link up\n", ldcp->id);
18311991Sheppo 		notify_client = B_TRUE;
18321991Sheppo 		notify_event = LDC_EVT_RESET;
18331991Sheppo 		ldcp->tstate |= TS_LINK_READY;
18341991Sheppo 		ldcp->status = LDC_READY;
18351991Sheppo 	}
18361991Sheppo 
18371991Sheppo 	/* if callbacks are disabled, do not notify */
18381991Sheppo 	if (!ldcp->cb_enabled)
18391991Sheppo 		notify_client = B_FALSE;
18401991Sheppo 
1841*3151Ssg70180 	i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
18421991Sheppo 
18431991Sheppo 	if (notify_client) {
18442793Slm66018 		ldcp->cb_inprogress = B_TRUE;
18452793Slm66018 		mutex_exit(&ldcp->tx_lock);
18462793Slm66018 		mutex_exit(&ldcp->lock);
18471991Sheppo 		rv = ldcp->cb(notify_event, ldcp->cb_arg);
18481991Sheppo 		if (rv) {
18491991Sheppo 			DWARN(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) callback "
18501991Sheppo 			    "failure", ldcp->id);
18511991Sheppo 		}
18521991Sheppo 		mutex_enter(&ldcp->lock);
18531991Sheppo 		ldcp->cb_inprogress = B_FALSE;
18542793Slm66018 	}
18552793Slm66018 
18561991Sheppo 	mutex_exit(&ldcp->lock);
18571991Sheppo 
18581991Sheppo 	D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) exiting handler", ldcp->id);
18591991Sheppo 
18601991Sheppo 	return (DDI_INTR_CLAIMED);
18611991Sheppo }
18621991Sheppo 
18631991Sheppo /*
18641991Sheppo  * LDC receive interrupt handler
18651991Sheppo  *    triggered for channel with data pending to read
18661991Sheppo  *    i.e. Rx queue content changes
18671991Sheppo  */
18681991Sheppo static uint_t
18691991Sheppo i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2)
18701991Sheppo {
18711991Sheppo 	_NOTE(ARGUNUSED(arg2))
18721991Sheppo 
18731991Sheppo 	int		rv;
18741991Sheppo 	uint64_t 	rx_head, rx_tail;
18751991Sheppo 	ldc_msg_t 	*msg;
18761991Sheppo 	ldc_chan_t 	*ldcp;
18771991Sheppo 	boolean_t 	notify_client = B_FALSE;
18781991Sheppo 	uint64_t	notify_event = 0;
18792793Slm66018 	uint64_t	link_state, first_fragment = 0;
18802793Slm66018 
18811991Sheppo 
18821991Sheppo 	/* Get the channel for which interrupt was received */
18831991Sheppo 	if (arg1 == NULL) {
18841991Sheppo 		cmn_err(CE_WARN, "i_ldc_rx_hdlr: invalid arg\n");
18851991Sheppo 		return (DDI_INTR_UNCLAIMED);
18861991Sheppo 	}
18871991Sheppo 
18881991Sheppo 	ldcp = (ldc_chan_t *)arg1;
18891991Sheppo 
18901991Sheppo 	D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
18911991Sheppo 	    ldcp->id, ldcp);
18922793Slm66018 	D1(ldcp->id, "i_ldc_rx_hdlr: (%llx) USR%lx/TS%lx/HS%lx, LSTATE=%lx\n",
18932793Slm66018 	    ldcp->id, ldcp->status, ldcp->tstate, ldcp->hstate,
18942793Slm66018 	    ldcp->link_state);
18951991Sheppo 
18961991Sheppo 	/* Lock channel */
18971991Sheppo 	mutex_enter(&ldcp->lock);
18981991Sheppo 
18991991Sheppo 	/* mark interrupt as pending */
19002793Slm66018 	ldcp->rx_intr_state = LDC_INTR_ACTIVE;
19011991Sheppo 
19021991Sheppo 	/*
19031991Sheppo 	 * Read packet(s) from the queue
19041991Sheppo 	 */
19051991Sheppo 	for (;;) {
19061991Sheppo 
19072793Slm66018 		link_state = ldcp->link_state;
19081991Sheppo 		rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
19091991Sheppo 		    &ldcp->link_state);
19101991Sheppo 		if (rv) {
19111991Sheppo 			cmn_err(CE_WARN,
19121991Sheppo 			    "i_ldc_rx_hdlr: (0x%lx) cannot read "
19131991Sheppo 			    "queue ptrs, rv=0x%d\n", ldcp->id, rv);
19141991Sheppo 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
19151991Sheppo 			mutex_exit(&ldcp->lock);
19161991Sheppo 			return (DDI_INTR_CLAIMED);
19171991Sheppo 		}
19181991Sheppo 
19191991Sheppo 		/*
19201991Sheppo 		 * reset the channel state if the channel went down
19211991Sheppo 		 * (other side unconfigured queue) or channel was reset
19222793Slm66018 		 * (other side reconfigured its queue)
19231991Sheppo 		 */
19242793Slm66018 
19252793Slm66018 		if (link_state != ldcp->link_state) {
19263010Slm66018 
19272793Slm66018 			switch (ldcp->link_state) {
19282793Slm66018 			case LDC_CHANNEL_DOWN:
19292793Slm66018 				D1(ldcp->id, "i_ldc_rx_hdlr: channel "
19302793Slm66018 				    "link down\n", ldcp->id);
19312793Slm66018 				mutex_enter(&ldcp->tx_lock);
19322793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
19332793Slm66018 				mutex_exit(&ldcp->tx_lock);
19342793Slm66018 				notify_client = B_TRUE;
19352793Slm66018 				notify_event = LDC_EVT_DOWN;
19362793Slm66018 				goto loop_exit;
19372793Slm66018 
19382793Slm66018 			case LDC_CHANNEL_UP:
19392793Slm66018 				D1(ldcp->id, "i_ldc_rx_hdlr: "
19402793Slm66018 				    "channel link up\n", ldcp->id);
19412793Slm66018 
19422793Slm66018 				if ((ldcp->tstate & ~TS_IN_RESET) == TS_OPEN) {
19432793Slm66018 					notify_client = B_TRUE;
19442793Slm66018 					notify_event = LDC_EVT_RESET;
19452793Slm66018 					ldcp->tstate |= TS_LINK_READY;
19462793Slm66018 					ldcp->status = LDC_READY;
19472793Slm66018 				}
19482793Slm66018 				break;
19492793Slm66018 
19502793Slm66018 			case LDC_CHANNEL_RESET:
19512793Slm66018 			default:
19522793Slm66018 #ifdef DEBUG
19532793Slm66018 force_reset:
19542793Slm66018 #endif
19552793Slm66018 				D1(ldcp->id, "i_ldc_rx_hdlr: channel "
19562793Slm66018 				    "link reset\n", ldcp->id);
19572793Slm66018 				mutex_enter(&ldcp->tx_lock);
19582793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
19592793Slm66018 				mutex_exit(&ldcp->tx_lock);
19602793Slm66018 				notify_client = B_TRUE;
19612793Slm66018 				notify_event = LDC_EVT_RESET;
19622793Slm66018 				break;
19632793Slm66018 			}
19641991Sheppo 		}
19652793Slm66018 
19662793Slm66018 #ifdef DEBUG
19672793Slm66018 		if (LDC_INJECT_RESET(ldcp))
19682793Slm66018 			goto force_reset;
19692793Slm66018 #endif
19701991Sheppo 
19711991Sheppo 		if (rx_head == rx_tail) {
19721991Sheppo 			D2(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) No packets\n",
19731991Sheppo 			    ldcp->id);
19741991Sheppo 			break;
19751991Sheppo 		}
19762793Slm66018 
19771991Sheppo 		D2(ldcp->id, "i_ldc_rx_hdlr: head=0x%llx, tail=0x%llx\n",
19781991Sheppo 		    rx_head, rx_tail);
19791991Sheppo 		DUMP_LDC_PKT(ldcp, "i_ldc_rx_hdlr rcd",
19801991Sheppo 		    ldcp->rx_q_va + rx_head);
19811991Sheppo 
19821991Sheppo 		/* get the message */
19831991Sheppo 		msg = (ldc_msg_t *)(ldcp->rx_q_va + rx_head);
19841991Sheppo 
19851991Sheppo 		/* if channel is in RAW mode or data pkt, notify and return */
19861991Sheppo 		if (ldcp->mode == LDC_MODE_RAW) {
19871991Sheppo 			notify_client = B_TRUE;
19881991Sheppo 			notify_event |= LDC_EVT_READ;
19891991Sheppo 			break;
19901991Sheppo 		}
19911991Sheppo 
19921991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
19931991Sheppo 
19941991Sheppo 			/* discard packet if channel is not up */
19952793Slm66018 			if ((ldcp->tstate & ~TS_IN_RESET) != TS_UP) {
19961991Sheppo 
19971991Sheppo 				/* move the head one position */
19981991Sheppo 				rx_head = (rx_head + LDC_PACKET_SIZE) %
19991991Sheppo 				(ldcp->rx_q_entries << LDC_PACKET_SHIFT);
20001991Sheppo 
20011991Sheppo 				if (rv = i_ldc_set_rx_head(ldcp, rx_head))
20021991Sheppo 					break;
20031991Sheppo 
20041991Sheppo 				continue;
20051991Sheppo 			} else {
20062793Slm66018 				if ((ldcp->tstate & TS_IN_RESET) == 0)
20072793Slm66018 					notify_client = B_TRUE;
20081991Sheppo 				notify_event |= LDC_EVT_READ;
20091991Sheppo 				break;
20101991Sheppo 			}
20111991Sheppo 		}
20121991Sheppo 
20131991Sheppo 		/* Check the sequence ID for the message received */
20142793Slm66018 		rv = i_ldc_check_seqid(ldcp, msg);
20152793Slm66018 		if (rv != 0) {
20161991Sheppo 
20171991Sheppo 			DWARN(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) seqid error, "
20181991Sheppo 			    "q_ptrs=0x%lx,0x%lx", ldcp->id, rx_head, rx_tail);
20191991Sheppo 
20201991Sheppo 			/* Reset last_msg_rcd to start of message */
20212336Snarayan 			if (first_fragment != 0) {
20222336Snarayan 				ldcp->last_msg_rcd = first_fragment - 1;
20232336Snarayan 				first_fragment = 0;
20241991Sheppo 			}
20252336Snarayan 
20261991Sheppo 			/*
20271991Sheppo 			 * Send a NACK due to seqid mismatch
20281991Sheppo 			 */
20291991Sheppo 			rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK,
20301991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK));
20311991Sheppo 
20321991Sheppo 			if (rv) {
20331991Sheppo 				cmn_err(CE_NOTE,
20341991Sheppo 				    "i_ldc_rx_hdlr: (0x%lx) err sending "
20351991Sheppo 				    "CTRL/NACK msg\n", ldcp->id);
20362336Snarayan 
20372336Snarayan 				/* if cannot send NACK - reset channel */
20382336Snarayan 				mutex_enter(&ldcp->tx_lock);
20392793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
20402336Snarayan 				mutex_exit(&ldcp->tx_lock);
20412336Snarayan 				rv = ECONNRESET;
20422336Snarayan 				break;
20431991Sheppo 			}
20441991Sheppo 
20451991Sheppo 			/* purge receive queue */
20461991Sheppo 			(void) i_ldc_set_rx_head(ldcp, rx_tail);
20471991Sheppo 			break;
20481991Sheppo 		}
20491991Sheppo 
20501991Sheppo 		/* record the message ID */
20511991Sheppo 		ldcp->last_msg_rcd = msg->seqid;
20521991Sheppo 
20531991Sheppo 		/* process control messages */
20541991Sheppo 		if (msg->type & LDC_CTRL) {
20551991Sheppo 			/* save current internal state */
20561991Sheppo 			uint64_t tstate = ldcp->tstate;
20571991Sheppo 
20581991Sheppo 			rv = i_ldc_ctrlmsg(ldcp, msg);
20591991Sheppo 			if (rv == EAGAIN) {
20601991Sheppo 				/* re-process pkt - state was adjusted */
20611991Sheppo 				continue;
20621991Sheppo 			}
20631991Sheppo 			if (rv == ECONNRESET) {
20641991Sheppo 				notify_client = B_TRUE;
20651991Sheppo 				notify_event = LDC_EVT_RESET;
20661991Sheppo 				break;
20671991Sheppo 			}
20681991Sheppo 
20691991Sheppo 			/*
20701991Sheppo 			 * control message processing was successful
20711991Sheppo 			 * channel transitioned to ready for communication
20721991Sheppo 			 */
20731991Sheppo 			if (rv == 0 && ldcp->tstate == TS_UP &&
20742793Slm66018 			    (tstate & ~TS_IN_RESET) !=
20752793Slm66018 			    (ldcp->tstate & ~TS_IN_RESET)) {
20761991Sheppo 				notify_client = B_TRUE;
20771991Sheppo 				notify_event = LDC_EVT_UP;
20781991Sheppo 			}
20791991Sheppo 		}
20801991Sheppo 
20811991Sheppo 		/* process data ACKs */
20821991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
20832336Snarayan 			if (rv = i_ldc_process_data_ACK(ldcp, msg)) {
20842336Snarayan 				notify_client = B_TRUE;
20852336Snarayan 				notify_event = LDC_EVT_RESET;
20862336Snarayan 				break;
20872336Snarayan 			}
20881991Sheppo 		}
20891991Sheppo 
20901991Sheppo 		/* move the head one position */
20911991Sheppo 		rx_head = (rx_head + LDC_PACKET_SIZE) %
20921991Sheppo 			(ldcp->rx_q_entries << LDC_PACKET_SHIFT);
20932032Slm66018 		if (rv = i_ldc_set_rx_head(ldcp, rx_head)) {
20942032Slm66018 			notify_client = B_TRUE;
20952032Slm66018 			notify_event = LDC_EVT_RESET;
20961991Sheppo 			break;
20972032Slm66018 		}
20981991Sheppo 
20991991Sheppo 	} /* for */
21001991Sheppo 
21012793Slm66018 loop_exit:
21022793Slm66018 
21031991Sheppo 	/* if callbacks are disabled, do not notify */
21041991Sheppo 	if (!ldcp->cb_enabled)
21051991Sheppo 		notify_client = B_FALSE;
21061991Sheppo 
21072793Slm66018 	/*
21082793Slm66018 	 * If there are data packets in the queue, the ldc_read will
21092793Slm66018 	 * clear interrupts after draining the queue, else clear interrupts
21102793Slm66018 	 */
21112793Slm66018 	if ((notify_event & LDC_EVT_READ) == 0) {
21122793Slm66018 		i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
21132793Slm66018 	} else
21142793Slm66018 		ldcp->rx_intr_state = LDC_INTR_PEND;
21152793Slm66018 
21161991Sheppo 
21171991Sheppo 	if (notify_client) {
2118*3151Ssg70180 		ldcp->cb_inprogress = B_TRUE;
2119*3151Ssg70180 		mutex_exit(&ldcp->lock);
21201991Sheppo 		rv = ldcp->cb(notify_event, ldcp->cb_arg);
21211991Sheppo 		if (rv) {
21221991Sheppo 			DWARN(ldcp->id,
21231991Sheppo 			    "i_ldc_rx_hdlr: (0x%llx) callback failure",
21241991Sheppo 			    ldcp->id);
21251991Sheppo 		}
2126*3151Ssg70180 		mutex_enter(&ldcp->lock);
2127*3151Ssg70180 		ldcp->cb_inprogress = B_FALSE;
2128*3151Ssg70180 	}
2129*3151Ssg70180 
2130*3151Ssg70180 	mutex_exit(&ldcp->lock);
21311991Sheppo 
21321991Sheppo 	D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) exiting handler", ldcp->id);
21331991Sheppo 	return (DDI_INTR_CLAIMED);
21341991Sheppo }
21351991Sheppo 
21361991Sheppo 
21371991Sheppo /* -------------------------------------------------------------------------- */
21381991Sheppo 
21391991Sheppo /*
21401991Sheppo  * LDC API functions
21411991Sheppo  */
21421991Sheppo 
21431991Sheppo /*
21441991Sheppo  * Initialize the channel. Allocate internal structure and memory for
21451991Sheppo  * TX/RX queues, and initialize locks.
21461991Sheppo  */
21471991Sheppo int
21481991Sheppo ldc_init(uint64_t id, ldc_attr_t *attr, ldc_handle_t *handle)
21491991Sheppo {
21501991Sheppo 	ldc_chan_t 	*ldcp;
21511991Sheppo 	int		rv, exit_val;
21521991Sheppo 	uint64_t	ra_base, nentries;
21532410Slm66018 	uint64_t	qlen;
21541991Sheppo 
21551991Sheppo 	exit_val = EINVAL;	/* guarantee an error if exit on failure */
21561991Sheppo 
21571991Sheppo 	if (attr == NULL) {
21581991Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid attr\n", id);
21591991Sheppo 		return (EINVAL);
21601991Sheppo 	}
21611991Sheppo 	if (handle == NULL) {
21621991Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid handle\n", id);
21631991Sheppo 		return (EINVAL);
21641991Sheppo 	}
21651991Sheppo 
21661991Sheppo 	/* check if channel is valid */
21671991Sheppo 	rv = hv_ldc_tx_qinfo(id, &ra_base, &nentries);
21681991Sheppo 	if (rv == H_ECHANNEL) {
21691991Sheppo 		DWARN(id, "ldc_init: (0x%llx) invalid channel id\n", id);
21701991Sheppo 		return (EINVAL);
21711991Sheppo 	}
21721991Sheppo 
21731991Sheppo 	/* check if the channel has already been initialized */
21741991Sheppo 	mutex_enter(&ldcssp->lock);
21751991Sheppo 	ldcp = ldcssp->chan_list;
21761991Sheppo 	while (ldcp != NULL) {
21771991Sheppo 		if (ldcp->id == id) {
21781991Sheppo 			DWARN(id, "ldc_init: (0x%llx) already initialized\n",
21791991Sheppo 			    id);
21801991Sheppo 			mutex_exit(&ldcssp->lock);
21811991Sheppo 			return (EADDRINUSE);
21821991Sheppo 		}
21831991Sheppo 		ldcp = ldcp->next;
21841991Sheppo 	}
21851991Sheppo 	mutex_exit(&ldcssp->lock);
21861991Sheppo 
21871991Sheppo 	ASSERT(ldcp == NULL);
21881991Sheppo 
21891991Sheppo 	*handle = 0;
21901991Sheppo 
21911991Sheppo 	/* Allocate an ldcp structure */
21921991Sheppo 	ldcp = kmem_zalloc(sizeof (ldc_chan_t), KM_SLEEP);
21931991Sheppo 
21942336Snarayan 	/*
21952336Snarayan 	 * Initialize the channel and Tx lock
21962336Snarayan 	 *
21972336Snarayan 	 * The channel 'lock' protects the entire channel and
21982336Snarayan 	 * should be acquired before initializing, resetting,
21992336Snarayan 	 * destroying or reading from a channel.
22002336Snarayan 	 *
22012336Snarayan 	 * The 'tx_lock' should be acquired prior to transmitting
22022336Snarayan 	 * data over the channel. The lock should also be acquired
22032336Snarayan 	 * prior to channel reconfiguration (in order to prevent
22042336Snarayan 	 * concurrent writes).
22052336Snarayan 	 *
22062336Snarayan 	 * ORDERING: When both locks are being acquired, to prevent
22072336Snarayan 	 * deadlocks, the channel lock should be always acquired prior
22082336Snarayan 	 * to the tx_lock.
22092336Snarayan 	 */
22101991Sheppo 	mutex_init(&ldcp->lock, NULL, MUTEX_DRIVER, NULL);
22112336Snarayan 	mutex_init(&ldcp->tx_lock, NULL, MUTEX_DRIVER, NULL);
22121991Sheppo 
22131991Sheppo 	/* Initialize the channel */
22141991Sheppo 	ldcp->id = id;
22151991Sheppo 	ldcp->cb = NULL;
22161991Sheppo 	ldcp->cb_arg = NULL;
22171991Sheppo 	ldcp->cb_inprogress = B_FALSE;
22181991Sheppo 	ldcp->cb_enabled = B_FALSE;
22191991Sheppo 	ldcp->next = NULL;
22201991Sheppo 
22211991Sheppo 	/* Read attributes */
22221991Sheppo 	ldcp->mode = attr->mode;
22231991Sheppo 	ldcp->devclass = attr->devclass;
22241991Sheppo 	ldcp->devinst = attr->instance;
22252410Slm66018 	ldcp->mtu = (attr->mtu > 0) ? attr->mtu : LDC_DEFAULT_MTU;
22261991Sheppo 
22271991Sheppo 	D1(ldcp->id,
22281991Sheppo 	    "ldc_init: (0x%llx) channel attributes, class=0x%x, "
22292410Slm66018 	    "instance=0x%llx, mode=%d, mtu=%d\n",
22302410Slm66018 	    ldcp->id, ldcp->devclass, ldcp->devinst, ldcp->mode, ldcp->mtu);
22311991Sheppo 
22321991Sheppo 	ldcp->next_vidx = 0;
22332793Slm66018 	ldcp->tstate = TS_IN_RESET;
22341991Sheppo 	ldcp->hstate = 0;
22351991Sheppo 	ldcp->last_msg_snt = LDC_INIT_SEQID;
22361991Sheppo 	ldcp->last_ack_rcd = 0;
22371991Sheppo 	ldcp->last_msg_rcd = 0;
22381991Sheppo 
22391991Sheppo 	ldcp->stream_bufferp = NULL;
22401991Sheppo 	ldcp->exp_dring_list = NULL;
22411991Sheppo 	ldcp->imp_dring_list = NULL;
22421991Sheppo 	ldcp->mhdl_list = NULL;
22431991Sheppo 
22442793Slm66018 	ldcp->tx_intr_state = LDC_INTR_NONE;
22452793Slm66018 	ldcp->rx_intr_state = LDC_INTR_NONE;
22462793Slm66018 
22471991Sheppo 	/* Initialize payload size depending on whether channel is reliable */
22481991Sheppo 	switch (ldcp->mode) {
22491991Sheppo 	case LDC_MODE_RAW:
22501991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RAW;
22511991Sheppo 		ldcp->read_p = i_ldc_read_raw;
22521991Sheppo 		ldcp->write_p = i_ldc_write_raw;
22531991Sheppo 		break;
22541991Sheppo 	case LDC_MODE_UNRELIABLE:
22551991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_UNRELIABLE;
22561991Sheppo 		ldcp->read_p = i_ldc_read_packet;
22571991Sheppo 		ldcp->write_p = i_ldc_write_packet;
22581991Sheppo 		break;
22591991Sheppo 	case LDC_MODE_RELIABLE:
22601991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE;
22611991Sheppo 		ldcp->read_p = i_ldc_read_packet;
22621991Sheppo 		ldcp->write_p = i_ldc_write_packet;
22631991Sheppo 		break;
22641991Sheppo 	case LDC_MODE_STREAM:
22651991Sheppo 		ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE;
22661991Sheppo 
22671991Sheppo 		ldcp->stream_remains = 0;
22681991Sheppo 		ldcp->stream_offset = 0;
22691991Sheppo 		ldcp->stream_bufferp = kmem_alloc(ldcp->mtu, KM_SLEEP);
22701991Sheppo 		ldcp->read_p = i_ldc_read_stream;
22711991Sheppo 		ldcp->write_p = i_ldc_write_stream;
22721991Sheppo 		break;
22731991Sheppo 	default:
22741991Sheppo 		exit_val = EINVAL;
22751991Sheppo 		goto cleanup_on_exit;
22761991Sheppo 	}
22771991Sheppo 
22782410Slm66018 	/*
22792410Slm66018 	 * qlen is (mtu * ldc_mtu_msgs) / pkt_payload. If this
22802410Slm66018 	 * value is smaller than default length of ldc_queue_entries,
22812410Slm66018 	 * qlen is set to ldc_queue_entries..
22822410Slm66018 	 */
22832410Slm66018 	qlen = (ldcp->mtu * ldc_mtu_msgs) / ldcp->pkt_payload;
22842410Slm66018 	ldcp->rx_q_entries =
22852410Slm66018 		(qlen < ldc_queue_entries) ? ldc_queue_entries : qlen;
22862410Slm66018 	ldcp->tx_q_entries = ldcp->rx_q_entries;
22872410Slm66018 
22882410Slm66018 	D1(ldcp->id, "ldc_init: queue length = 0x%llx\n", qlen);
22892410Slm66018 
22901991Sheppo 	/* Create a transmit queue */
22911991Sheppo 	ldcp->tx_q_va = (uint64_t)
22921991Sheppo 		contig_mem_alloc(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
22931991Sheppo 	if (ldcp->tx_q_va == NULL) {
22941991Sheppo 		cmn_err(CE_WARN,
22951991Sheppo 		    "ldc_init: (0x%lx) TX queue allocation failed\n",
22961991Sheppo 		    ldcp->id);
22971991Sheppo 		exit_val = ENOMEM;
22981991Sheppo 		goto cleanup_on_exit;
22991991Sheppo 	}
23001991Sheppo 	ldcp->tx_q_ra = va_to_pa((caddr_t)ldcp->tx_q_va);
23011991Sheppo 
23021991Sheppo 	D2(ldcp->id, "ldc_init: txq_va=0x%llx, txq_ra=0x%llx, entries=0x%llx\n",
23031991Sheppo 	    ldcp->tx_q_va, ldcp->tx_q_ra, ldcp->tx_q_entries);
23041991Sheppo 
23051991Sheppo 	ldcp->tstate |= TS_TXQ_RDY;
23061991Sheppo 
23071991Sheppo 	/* Create a receive queue */
23081991Sheppo 	ldcp->rx_q_va = (uint64_t)
23091991Sheppo 		contig_mem_alloc(ldcp->rx_q_entries << LDC_PACKET_SHIFT);
23101991Sheppo 	if (ldcp->rx_q_va == NULL) {
23111991Sheppo 		cmn_err(CE_WARN,
23121991Sheppo 		    "ldc_init: (0x%lx) RX queue allocation failed\n",
23131991Sheppo 		    ldcp->id);
23141991Sheppo 		exit_val = ENOMEM;
23151991Sheppo 		goto cleanup_on_exit;
23161991Sheppo 	}
23171991Sheppo 	ldcp->rx_q_ra = va_to_pa((caddr_t)ldcp->rx_q_va);
23181991Sheppo 
23191991Sheppo 	D2(ldcp->id, "ldc_init: rxq_va=0x%llx, rxq_ra=0x%llx, entries=0x%llx\n",
23201991Sheppo 	    ldcp->rx_q_va, ldcp->rx_q_ra, ldcp->rx_q_entries);
23211991Sheppo 
23221991Sheppo 	ldcp->tstate |= TS_RXQ_RDY;
23231991Sheppo 
23241991Sheppo 	/* Init descriptor ring and memory handle list lock */
23251991Sheppo 	mutex_init(&ldcp->exp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
23261991Sheppo 	mutex_init(&ldcp->imp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
23271991Sheppo 	mutex_init(&ldcp->mlist_lock, NULL, MUTEX_DRIVER, NULL);
23281991Sheppo 
23291991Sheppo 	/* mark status as INITialized */
23301991Sheppo 	ldcp->status = LDC_INIT;
23311991Sheppo 
23321991Sheppo 	/* Add to channel list */
23331991Sheppo 	mutex_enter(&ldcssp->lock);
23341991Sheppo 	ldcp->next = ldcssp->chan_list;
23351991Sheppo 	ldcssp->chan_list = ldcp;
23361991Sheppo 	ldcssp->channel_count++;
23371991Sheppo 	mutex_exit(&ldcssp->lock);
23381991Sheppo 
23391991Sheppo 	/* set the handle */
23401991Sheppo 	*handle = (ldc_handle_t)ldcp;
23411991Sheppo 
23421991Sheppo 	D1(ldcp->id, "ldc_init: (0x%llx) channel initialized\n", ldcp->id);
23431991Sheppo 
23441991Sheppo 	return (0);
23451991Sheppo 
23461991Sheppo cleanup_on_exit:
23471991Sheppo 
23481991Sheppo 	if (ldcp->mode == LDC_MODE_STREAM && ldcp->stream_bufferp)
23491991Sheppo 		kmem_free(ldcp->stream_bufferp, ldcp->mtu);
23501991Sheppo 
23511991Sheppo 	if (ldcp->tstate & TS_TXQ_RDY)
23521991Sheppo 		contig_mem_free((caddr_t)ldcp->tx_q_va,
23531991Sheppo 		    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
23541991Sheppo 
23551991Sheppo 	if (ldcp->tstate & TS_RXQ_RDY)
23561991Sheppo 		contig_mem_free((caddr_t)ldcp->rx_q_va,
23571991Sheppo 		    (ldcp->rx_q_entries << LDC_PACKET_SHIFT));
23581991Sheppo 
23592336Snarayan 	mutex_destroy(&ldcp->tx_lock);
23601991Sheppo 	mutex_destroy(&ldcp->lock);
23611991Sheppo 
23621991Sheppo 	if (ldcp)
23631991Sheppo 		kmem_free(ldcp, sizeof (ldc_chan_t));
23641991Sheppo 
23651991Sheppo 	return (exit_val);
23661991Sheppo }
23671991Sheppo 
23681991Sheppo /*
23691991Sheppo  * Finalizes the LDC connection. It will return EBUSY if the
23701991Sheppo  * channel is open. A ldc_close() has to be done prior to
23711991Sheppo  * a ldc_fini operation. It frees TX/RX queues, associated
23721991Sheppo  * with the channel
23731991Sheppo  */
23741991Sheppo int
23751991Sheppo ldc_fini(ldc_handle_t handle)
23761991Sheppo {
23771991Sheppo 	ldc_chan_t 	*ldcp;
23781991Sheppo 	ldc_chan_t 	*tmp_ldcp;
23791991Sheppo 	uint64_t 	id;
23801991Sheppo 
23811991Sheppo 	if (handle == NULL) {
23821991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel handle\n");
23831991Sheppo 		return (EINVAL);
23841991Sheppo 	}
23851991Sheppo 	ldcp = (ldc_chan_t *)handle;
23861991Sheppo 	id = ldcp->id;
23871991Sheppo 
23881991Sheppo 	mutex_enter(&ldcp->lock);
23891991Sheppo 
23902793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) > TS_INIT) {
23911991Sheppo 		DWARN(ldcp->id, "ldc_fini: (0x%llx) channel is open\n",
23921991Sheppo 		    ldcp->id);
23931991Sheppo 		mutex_exit(&ldcp->lock);
23941991Sheppo 		return (EBUSY);
23951991Sheppo 	}
23961991Sheppo 
23971991Sheppo 	/* Remove from the channel list */
23981991Sheppo 	mutex_enter(&ldcssp->lock);
23991991Sheppo 	tmp_ldcp = ldcssp->chan_list;
24001991Sheppo 	if (tmp_ldcp == ldcp) {
24011991Sheppo 		ldcssp->chan_list = ldcp->next;
24021991Sheppo 		ldcp->next = NULL;
24031991Sheppo 	} else {
24041991Sheppo 		while (tmp_ldcp != NULL) {
24051991Sheppo 			if (tmp_ldcp->next == ldcp) {
24061991Sheppo 				tmp_ldcp->next = ldcp->next;
24071991Sheppo 				ldcp->next = NULL;
24081991Sheppo 				break;
24091991Sheppo 			}
24101991Sheppo 			tmp_ldcp = tmp_ldcp->next;
24111991Sheppo 		}
24121991Sheppo 		if (tmp_ldcp == NULL) {
24131991Sheppo 			DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel hdl\n");
24141991Sheppo 			mutex_exit(&ldcssp->lock);
24151991Sheppo 			mutex_exit(&ldcp->lock);
24161991Sheppo 			return (EINVAL);
24171991Sheppo 		}
24181991Sheppo 	}
24191991Sheppo 
24201991Sheppo 	ldcssp->channel_count--;
24211991Sheppo 
24221991Sheppo 	mutex_exit(&ldcssp->lock);
24231991Sheppo 
24241991Sheppo 	/* Free the map table for this channel */
24251991Sheppo 	if (ldcp->mtbl) {
24261991Sheppo 		(void) hv_ldc_set_map_table(ldcp->id, NULL, NULL);
24272793Slm66018 		if (ldcp->mtbl->contigmem)
24282793Slm66018 			contig_mem_free(ldcp->mtbl->table, ldcp->mtbl->size);
24292793Slm66018 		else
24302793Slm66018 			kmem_free(ldcp->mtbl->table, ldcp->mtbl->size);
24311991Sheppo 		mutex_destroy(&ldcp->mtbl->lock);
24321991Sheppo 		kmem_free(ldcp->mtbl, sizeof (ldc_mtbl_t));
24331991Sheppo 	}
24341991Sheppo 
24351991Sheppo 	/* Destroy descriptor ring and memory handle list lock */
24361991Sheppo 	mutex_destroy(&ldcp->exp_dlist_lock);
24371991Sheppo 	mutex_destroy(&ldcp->imp_dlist_lock);
24381991Sheppo 	mutex_destroy(&ldcp->mlist_lock);
24391991Sheppo 
24401991Sheppo 	/* Free the stream buffer for STREAM_MODE */
24411991Sheppo 	if (ldcp->mode == LDC_MODE_STREAM && ldcp->stream_bufferp)
24421991Sheppo 		kmem_free(ldcp->stream_bufferp, ldcp->mtu);
24431991Sheppo 
24441991Sheppo 	/* Free the RX queue */
24451991Sheppo 	contig_mem_free((caddr_t)ldcp->rx_q_va,
24461991Sheppo 	    (ldcp->rx_q_entries << LDC_PACKET_SHIFT));
24471991Sheppo 	ldcp->tstate &= ~TS_RXQ_RDY;
24481991Sheppo 
24491991Sheppo 	/* Free the TX queue */
24501991Sheppo 	contig_mem_free((caddr_t)ldcp->tx_q_va,
24511991Sheppo 	    (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
24521991Sheppo 	ldcp->tstate &= ~TS_TXQ_RDY;
24531991Sheppo 
24541991Sheppo 	mutex_exit(&ldcp->lock);
24551991Sheppo 
24561991Sheppo 	/* Destroy mutex */
24572336Snarayan 	mutex_destroy(&ldcp->tx_lock);
24581991Sheppo 	mutex_destroy(&ldcp->lock);
24591991Sheppo 
24601991Sheppo 	/* free channel structure */
24611991Sheppo 	kmem_free(ldcp, sizeof (ldc_chan_t));
24621991Sheppo 
24631991Sheppo 	D1(id, "ldc_fini: (0x%llx) channel finalized\n", id);
24641991Sheppo 
24651991Sheppo 	return (0);
24661991Sheppo }
24671991Sheppo 
24681991Sheppo /*
24691991Sheppo  * Open the LDC channel for use. It registers the TX/RX queues
24701991Sheppo  * with the Hypervisor. It also specifies the interrupt number
24711991Sheppo  * and target CPU for this channel
24721991Sheppo  */
24731991Sheppo int
24741991Sheppo ldc_open(ldc_handle_t handle)
24751991Sheppo {
24761991Sheppo 	ldc_chan_t 	*ldcp;
24771991Sheppo 	int 		rv;
24781991Sheppo 
24791991Sheppo 	if (handle == NULL) {
24801991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_open: invalid channel handle\n");
24811991Sheppo 		return (EINVAL);
24821991Sheppo 	}
24831991Sheppo 
24841991Sheppo 	ldcp = (ldc_chan_t *)handle;
24851991Sheppo 
24861991Sheppo 	mutex_enter(&ldcp->lock);
24871991Sheppo 
24881991Sheppo 	if (ldcp->tstate < TS_INIT) {
24891991Sheppo 		DWARN(ldcp->id,
24901991Sheppo 		    "ldc_open: (0x%llx) channel not initialized\n", ldcp->id);
24911991Sheppo 		mutex_exit(&ldcp->lock);
24921991Sheppo 		return (EFAULT);
24931991Sheppo 	}
24942793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) >= TS_OPEN) {
24951991Sheppo 		DWARN(ldcp->id,
24961991Sheppo 		    "ldc_open: (0x%llx) channel is already open\n", ldcp->id);
24971991Sheppo 		mutex_exit(&ldcp->lock);
24981991Sheppo 		return (EFAULT);
24991991Sheppo 	}
25001991Sheppo 
25011991Sheppo 	/*
25021991Sheppo 	 * Unregister/Register the tx queue with the hypervisor
25031991Sheppo 	 */
25041991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
25051991Sheppo 	if (rv) {
25061991Sheppo 		cmn_err(CE_WARN,
25071991Sheppo 		    "ldc_open: (0x%lx) channel tx queue unconf failed\n",
25081991Sheppo 		    ldcp->id);
25091991Sheppo 		mutex_exit(&ldcp->lock);
25101991Sheppo 		return (EIO);
25111991Sheppo 	}
25121991Sheppo 
25131991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
25141991Sheppo 	if (rv) {
25151991Sheppo 		cmn_err(CE_WARN,
25161991Sheppo 		    "ldc_open: (0x%lx) channel tx queue conf failed\n",
25171991Sheppo 		    ldcp->id);
25181991Sheppo 		mutex_exit(&ldcp->lock);
25191991Sheppo 		return (EIO);
25201991Sheppo 	}
25211991Sheppo 
25221991Sheppo 	D2(ldcp->id, "ldc_open: (0x%llx) registered tx queue with LDC\n",
25231991Sheppo 	    ldcp->id);
25241991Sheppo 
25251991Sheppo 	/*
25261991Sheppo 	 * Unregister/Register the rx queue with the hypervisor
25271991Sheppo 	 */
25281991Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
25291991Sheppo 	if (rv) {
25301991Sheppo 		cmn_err(CE_WARN,
25311991Sheppo 		    "ldc_open: (0x%lx) channel rx queue unconf failed\n",
25321991Sheppo 		    ldcp->id);
25331991Sheppo 		mutex_exit(&ldcp->lock);
25341991Sheppo 		return (EIO);
25351991Sheppo 	}
25361991Sheppo 
25371991Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, ldcp->rx_q_entries);
25381991Sheppo 	if (rv) {
25391991Sheppo 		cmn_err(CE_WARN,
25401991Sheppo 		    "ldc_open: (0x%lx) channel rx queue conf failed\n",
25411991Sheppo 		    ldcp->id);
25421991Sheppo 		mutex_exit(&ldcp->lock);
25431991Sheppo 		return (EIO);
25441991Sheppo 	}
25451991Sheppo 
25461991Sheppo 	D2(ldcp->id, "ldc_open: (0x%llx) registered rx queue with LDC\n",
25471991Sheppo 	    ldcp->id);
25481991Sheppo 
25491991Sheppo 	ldcp->tstate |= TS_QCONF_RDY;
25501991Sheppo 
25511991Sheppo 	/* Register the channel with the channel nexus */
25521991Sheppo 	rv = i_ldc_register_channel(ldcp);
25531991Sheppo 	if (rv && rv != EAGAIN) {
25541991Sheppo 		cmn_err(CE_WARN,
25551991Sheppo 		    "ldc_open: (0x%lx) channel register failed\n", ldcp->id);
25561991Sheppo 		(void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
25571991Sheppo 		(void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
25581991Sheppo 		mutex_exit(&ldcp->lock);
25591991Sheppo 		return (EIO);
25601991Sheppo 	}
25611991Sheppo 
25621991Sheppo 	/* mark channel in OPEN state */
25631991Sheppo 	ldcp->status = LDC_OPEN;
25641991Sheppo 
25651991Sheppo 	/* Read channel state */
25661991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
25671991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
25681991Sheppo 	if (rv) {
25691991Sheppo 		cmn_err(CE_WARN,
25701991Sheppo 		    "ldc_open: (0x%lx) cannot read channel state\n",
25711991Sheppo 		    ldcp->id);
25721991Sheppo 		(void) i_ldc_unregister_channel(ldcp);
25731991Sheppo 		(void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
25741991Sheppo 		(void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
25751991Sheppo 		mutex_exit(&ldcp->lock);
25761991Sheppo 		return (EIO);
25771991Sheppo 	}
25781991Sheppo 
25791991Sheppo 	/*
25801991Sheppo 	 * set the ACKd head to current head location for reliable &
25811991Sheppo 	 * streaming mode
25821991Sheppo 	 */
25831991Sheppo 	ldcp->tx_ackd_head = ldcp->tx_head;
25841991Sheppo 
25851991Sheppo 	/* mark channel ready if HV report link is UP (peer alloc'd Rx queue) */
25861991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_UP ||
25871991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
25881991Sheppo 		ldcp->tstate |= TS_LINK_READY;
25891991Sheppo 		ldcp->status = LDC_READY;
25901991Sheppo 	}
25911991Sheppo 
25921991Sheppo 	/*
25931991Sheppo 	 * if channel is being opened in RAW mode - no handshake is needed
25941991Sheppo 	 * switch the channel READY and UP state
25951991Sheppo 	 */
25961991Sheppo 	if (ldcp->mode == LDC_MODE_RAW) {
25971991Sheppo 		ldcp->tstate = TS_UP;	/* set bits associated with LDC UP */
25981991Sheppo 		ldcp->status = LDC_UP;
25991991Sheppo 	}
26001991Sheppo 
26011991Sheppo 	mutex_exit(&ldcp->lock);
26021991Sheppo 
26031991Sheppo 	/*
26041991Sheppo 	 * Increment number of open channels
26051991Sheppo 	 */
26061991Sheppo 	mutex_enter(&ldcssp->lock);
26071991Sheppo 	ldcssp->channels_open++;
26081991Sheppo 	mutex_exit(&ldcssp->lock);
26091991Sheppo 
26103010Slm66018 	D1(ldcp->id,
26112793Slm66018 	    "ldc_open: (0x%llx) channel (0x%p) open for use "
26122793Slm66018 	    "(tstate=0x%x, status=0x%x)\n",
26132793Slm66018 	    ldcp->id, ldcp, ldcp->tstate, ldcp->status);
26141991Sheppo 
26151991Sheppo 	return (0);
26161991Sheppo }
26171991Sheppo 
26181991Sheppo /*
26191991Sheppo  * Close the LDC connection. It will return EBUSY if there
26201991Sheppo  * are memory segments or descriptor rings either bound to or
26211991Sheppo  * mapped over the channel
26221991Sheppo  */
26231991Sheppo int
26241991Sheppo ldc_close(ldc_handle_t handle)
26251991Sheppo {
26261991Sheppo 	ldc_chan_t 	*ldcp;
26272336Snarayan 	int		rv = 0, retries = 0;
26281991Sheppo 	boolean_t	chk_done = B_FALSE;
26291991Sheppo 
26301991Sheppo 	if (handle == NULL) {
26311991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_close: invalid channel handle\n");
26321991Sheppo 		return (EINVAL);
26331991Sheppo 	}
26341991Sheppo 	ldcp = (ldc_chan_t *)handle;
26351991Sheppo 
26361991Sheppo 	mutex_enter(&ldcp->lock);
26371991Sheppo 
26381991Sheppo 	/* return error if channel is not open */
26392793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) < TS_OPEN) {
26401991Sheppo 		DWARN(ldcp->id,
26411991Sheppo 		    "ldc_close: (0x%llx) channel is not open\n", ldcp->id);
26421991Sheppo 		mutex_exit(&ldcp->lock);
26431991Sheppo 		return (EFAULT);
26441991Sheppo 	}
26451991Sheppo 
26461991Sheppo 	/* if any memory handles, drings, are bound or mapped cannot close */
26471991Sheppo 	if (ldcp->mhdl_list != NULL) {
26481991Sheppo 		DWARN(ldcp->id,
26491991Sheppo 		    "ldc_close: (0x%llx) channel has bound memory handles\n",
26501991Sheppo 		    ldcp->id);
26511991Sheppo 		mutex_exit(&ldcp->lock);
26521991Sheppo 		return (EBUSY);
26531991Sheppo 	}
26541991Sheppo 	if (ldcp->exp_dring_list != NULL) {
26551991Sheppo 		DWARN(ldcp->id,
26561991Sheppo 		    "ldc_close: (0x%llx) channel has bound descriptor rings\n",
26571991Sheppo 		    ldcp->id);
26581991Sheppo 		mutex_exit(&ldcp->lock);
26591991Sheppo 		return (EBUSY);
26601991Sheppo 	}
26611991Sheppo 	if (ldcp->imp_dring_list != NULL) {
26621991Sheppo 		DWARN(ldcp->id,
26631991Sheppo 		    "ldc_close: (0x%llx) channel has mapped descriptor rings\n",
26641991Sheppo 		    ldcp->id);
26651991Sheppo 		mutex_exit(&ldcp->lock);
26661991Sheppo 		return (EBUSY);
26671991Sheppo 	}
26681991Sheppo 
2669*3151Ssg70180 	if (ldcp->cb_inprogress) {
2670*3151Ssg70180 		DWARN(ldcp->id, "ldc_close: (0x%llx) callback active\n",
2671*3151Ssg70180 		    ldcp->id);
2672*3151Ssg70180 		mutex_exit(&ldcp->lock);
2673*3151Ssg70180 		return (EWOULDBLOCK);
2674*3151Ssg70180 	}
2675*3151Ssg70180 
26762336Snarayan 	/* Obtain Tx lock */
26772336Snarayan 	mutex_enter(&ldcp->tx_lock);
26782336Snarayan 
26791991Sheppo 	/*
26801991Sheppo 	 * Wait for pending transmits to complete i.e Tx queue to drain
26811991Sheppo 	 * if there are pending pkts - wait 1 ms and retry again
26821991Sheppo 	 */
26831991Sheppo 	for (;;) {
26841991Sheppo 
26851991Sheppo 		rv = hv_ldc_tx_get_state(ldcp->id,
26861991Sheppo 		    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
26871991Sheppo 		if (rv) {
26881991Sheppo 			cmn_err(CE_WARN,
26891991Sheppo 			    "ldc_close: (0x%lx) cannot read qptrs\n", ldcp->id);
26902336Snarayan 			mutex_exit(&ldcp->tx_lock);
26911991Sheppo 			mutex_exit(&ldcp->lock);
26921991Sheppo 			return (EIO);
26931991Sheppo 		}
26941991Sheppo 
26951991Sheppo 		if (ldcp->tx_head == ldcp->tx_tail ||
26961991Sheppo 		    ldcp->link_state != LDC_CHANNEL_UP) {
26971991Sheppo 			break;
26981991Sheppo 		}
26991991Sheppo 
27001991Sheppo 		if (chk_done) {
27011991Sheppo 			DWARN(ldcp->id,
27021991Sheppo 			    "ldc_close: (0x%llx) Tx queue drain timeout\n",
27031991Sheppo 			    ldcp->id);
27041991Sheppo 			break;
27051991Sheppo 		}
27061991Sheppo 
27071991Sheppo 		/* wait for one ms and try again */
27081991Sheppo 		delay(drv_usectohz(1000));
27091991Sheppo 		chk_done = B_TRUE;
27101991Sheppo 	}
27111991Sheppo 
27121991Sheppo 	/*
27132841Snarayan 	 * Drain the Tx and Rx queues as we are closing the
27142841Snarayan 	 * channel. We dont care about any pending packets.
27152841Snarayan 	 * We have to also drain the queue prior to clearing
27162841Snarayan 	 * pending interrupts, otherwise the HV will trigger
27172841Snarayan 	 * an interrupt the moment the interrupt state is
27182841Snarayan 	 * cleared.
27192793Slm66018 	 */
27202793Slm66018 	(void) i_ldc_txq_reconf(ldcp);
27212841Snarayan 	(void) i_ldc_rxq_drain(ldcp);
27222793Slm66018 
27232793Slm66018 	/*
27241991Sheppo 	 * Unregister the channel with the nexus
27251991Sheppo 	 */
27262336Snarayan 	while ((rv = i_ldc_unregister_channel(ldcp)) != 0) {
27272336Snarayan 
27282336Snarayan 		mutex_exit(&ldcp->tx_lock);
27291991Sheppo 		mutex_exit(&ldcp->lock);
27302336Snarayan 
27312336Snarayan 		/* if any error other than EAGAIN return back */
27322841Snarayan 		if (rv != EAGAIN || retries >= ldc_max_retries) {
27332336Snarayan 			cmn_err(CE_WARN,
27342336Snarayan 			    "ldc_close: (0x%lx) unregister failed, %d\n",
27352336Snarayan 			    ldcp->id, rv);
27362336Snarayan 			return (rv);
27372336Snarayan 		}
27382336Snarayan 
27392336Snarayan 		/*
27402336Snarayan 		 * As there could be pending interrupts we need
27412336Snarayan 		 * to wait and try again
27422336Snarayan 		 */
2743*3151Ssg70180 		drv_usecwait(ldc_close_delay);
27442336Snarayan 		mutex_enter(&ldcp->lock);
27452336Snarayan 		mutex_enter(&ldcp->tx_lock);
27462336Snarayan 		retries++;
27471991Sheppo 	}
27481991Sheppo 
27491991Sheppo 	/*
27501991Sheppo 	 * Unregister queues
27511991Sheppo 	 */
27521991Sheppo 	rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
27531991Sheppo 	if (rv) {
27541991Sheppo 		cmn_err(CE_WARN,
27551991Sheppo 		    "ldc_close: (0x%lx) channel TX queue unconf failed\n",
27561991Sheppo 		    ldcp->id);
27572336Snarayan 		mutex_exit(&ldcp->tx_lock);
27581991Sheppo 		mutex_exit(&ldcp->lock);
27591991Sheppo 		return (EIO);
27601991Sheppo 	}
27611991Sheppo 	rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
27621991Sheppo 	if (rv) {
27631991Sheppo 		cmn_err(CE_WARN,
27641991Sheppo 		    "ldc_close: (0x%lx) channel RX queue unconf failed\n",
27651991Sheppo 		    ldcp->id);
27662336Snarayan 		mutex_exit(&ldcp->tx_lock);
27671991Sheppo 		mutex_exit(&ldcp->lock);
27681991Sheppo 		return (EIO);
27691991Sheppo 	}
27701991Sheppo 
27711991Sheppo 	ldcp->tstate &= ~TS_QCONF_RDY;
27721991Sheppo 
27731991Sheppo 	/* Reset channel state information */
27741991Sheppo 	i_ldc_reset_state(ldcp);
27751991Sheppo 
27761991Sheppo 	/* Mark channel as down and in initialized state */
27771991Sheppo 	ldcp->tx_ackd_head = 0;
27781991Sheppo 	ldcp->tx_head = 0;
27792793Slm66018 	ldcp->tstate = TS_IN_RESET|TS_INIT;
27801991Sheppo 	ldcp->status = LDC_INIT;
27811991Sheppo 
27822336Snarayan 	mutex_exit(&ldcp->tx_lock);
27831991Sheppo 	mutex_exit(&ldcp->lock);
27841991Sheppo 
27851991Sheppo 	/* Decrement number of open channels */
27861991Sheppo 	mutex_enter(&ldcssp->lock);
27871991Sheppo 	ldcssp->channels_open--;
27881991Sheppo 	mutex_exit(&ldcssp->lock);
27891991Sheppo 
27901991Sheppo 	D1(ldcp->id, "ldc_close: (0x%llx) channel closed\n", ldcp->id);
27911991Sheppo 
27921991Sheppo 	return (0);
27931991Sheppo }
27941991Sheppo 
27951991Sheppo /*
27961991Sheppo  * Register channel callback
27971991Sheppo  */
27981991Sheppo int
27991991Sheppo ldc_reg_callback(ldc_handle_t handle,
28001991Sheppo     uint_t(*cb)(uint64_t event, caddr_t arg), caddr_t arg)
28011991Sheppo {
28021991Sheppo 	ldc_chan_t *ldcp;
28031991Sheppo 
28041991Sheppo 	if (handle == NULL) {
28051991Sheppo 		DWARN(DBG_ALL_LDCS,
28061991Sheppo 		    "ldc_reg_callback: invalid channel handle\n");
28071991Sheppo 		return (EINVAL);
28081991Sheppo 	}
28091991Sheppo 	if (((uint64_t)cb) < KERNELBASE) {
28101991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_reg_callback: invalid callback\n");
28111991Sheppo 		return (EINVAL);
28121991Sheppo 	}
28131991Sheppo 	ldcp = (ldc_chan_t *)handle;
28141991Sheppo 
28151991Sheppo 	mutex_enter(&ldcp->lock);
28161991Sheppo 
28171991Sheppo 	if (ldcp->cb) {
28181991Sheppo 		DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback exists\n",
28191991Sheppo 		    ldcp->id);
28201991Sheppo 		mutex_exit(&ldcp->lock);
28211991Sheppo 		return (EIO);
28221991Sheppo 	}
28231991Sheppo 	if (ldcp->cb_inprogress) {
28241991Sheppo 		DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback active\n",
28251991Sheppo 		    ldcp->id);
28261991Sheppo 		mutex_exit(&ldcp->lock);
28271991Sheppo 		return (EWOULDBLOCK);
28281991Sheppo 	}
28291991Sheppo 
28301991Sheppo 	ldcp->cb = cb;
28311991Sheppo 	ldcp->cb_arg = arg;
28321991Sheppo 	ldcp->cb_enabled = B_TRUE;
28331991Sheppo 
28341991Sheppo 	D1(ldcp->id,
28351991Sheppo 	    "ldc_reg_callback: (0x%llx) registered callback for channel\n",
28361991Sheppo 	    ldcp->id);
28371991Sheppo 
28381991Sheppo 	mutex_exit(&ldcp->lock);
28391991Sheppo 
28401991Sheppo 	return (0);
28411991Sheppo }
28421991Sheppo 
28431991Sheppo /*
28441991Sheppo  * Unregister channel callback
28451991Sheppo  */
28461991Sheppo int
28471991Sheppo ldc_unreg_callback(ldc_handle_t handle)
28481991Sheppo {
28491991Sheppo 	ldc_chan_t *ldcp;
28501991Sheppo 
28511991Sheppo 	if (handle == NULL) {
28521991Sheppo 		DWARN(DBG_ALL_LDCS,
28531991Sheppo 		    "ldc_unreg_callback: invalid channel handle\n");
28541991Sheppo 		return (EINVAL);
28551991Sheppo 	}
28561991Sheppo 	ldcp = (ldc_chan_t *)handle;
28571991Sheppo 
28581991Sheppo 	mutex_enter(&ldcp->lock);
28591991Sheppo 
28601991Sheppo 	if (ldcp->cb == NULL) {
28611991Sheppo 		DWARN(ldcp->id,
28621991Sheppo 		    "ldc_unreg_callback: (0x%llx) no callback exists\n",
28631991Sheppo 		    ldcp->id);
28641991Sheppo 		mutex_exit(&ldcp->lock);
28651991Sheppo 		return (EIO);
28661991Sheppo 	}
28671991Sheppo 	if (ldcp->cb_inprogress) {
28681991Sheppo 		DWARN(ldcp->id,
28691991Sheppo 		    "ldc_unreg_callback: (0x%llx) callback active\n",
28701991Sheppo 		    ldcp->id);
28711991Sheppo 		mutex_exit(&ldcp->lock);
28721991Sheppo 		return (EWOULDBLOCK);
28731991Sheppo 	}
28741991Sheppo 
28751991Sheppo 	ldcp->cb = NULL;
28761991Sheppo 	ldcp->cb_arg = NULL;
28771991Sheppo 	ldcp->cb_enabled = B_FALSE;
28781991Sheppo 
28791991Sheppo 	D1(ldcp->id,
28801991Sheppo 	    "ldc_unreg_callback: (0x%llx) unregistered callback for channel\n",
28811991Sheppo 	    ldcp->id);
28821991Sheppo 
28831991Sheppo 	mutex_exit(&ldcp->lock);
28841991Sheppo 
28851991Sheppo 	return (0);
28861991Sheppo }
28871991Sheppo 
28881991Sheppo 
28891991Sheppo /*
28901991Sheppo  * Bring a channel up by initiating a handshake with the peer
28911991Sheppo  * This call is asynchronous. It will complete at a later point
28921991Sheppo  * in time when the peer responds back with an RTR.
28931991Sheppo  */
28941991Sheppo int
28951991Sheppo ldc_up(ldc_handle_t handle)
28961991Sheppo {
28971991Sheppo 	int 		rv;
28981991Sheppo 	ldc_chan_t 	*ldcp;
28991991Sheppo 	ldc_msg_t 	*ldcmsg;
29002793Slm66018 	uint64_t 	tx_tail, tstate;
29011991Sheppo 
29021991Sheppo 	if (handle == NULL) {
29031991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_up: invalid channel handle\n");
29041991Sheppo 		return (EINVAL);
29051991Sheppo 	}
29061991Sheppo 	ldcp = (ldc_chan_t *)handle;
29071991Sheppo 
29081991Sheppo 	mutex_enter(&ldcp->lock);
29091991Sheppo 
29102793Slm66018 	D1(ldcp->id, "ldc_up: (0x%llx) doing channel UP\n", ldcp->id);
29112793Slm66018 
29122793Slm66018 	/* clear the reset state */
29132793Slm66018 	tstate = ldcp->tstate;
29142793Slm66018 	ldcp->tstate &= ~TS_IN_RESET;
29152793Slm66018 
29161991Sheppo 	if (ldcp->tstate == TS_UP) {
29172793Slm66018 		DWARN(ldcp->id,
29181991Sheppo 		    "ldc_up: (0x%llx) channel is already in UP state\n",
29191991Sheppo 		    ldcp->id);
29202793Slm66018 
29212793Slm66018 		/* mark channel as up */
29222793Slm66018 		ldcp->status = LDC_UP;
29232793Slm66018 
29242793Slm66018 		/*
29252793Slm66018 		 * if channel was in reset state and there was
29262793Slm66018 		 * pending data clear interrupt state. this will
29272793Slm66018 		 * trigger an interrupt, causing the RX handler to
29282793Slm66018 		 * to invoke the client's callback
29292793Slm66018 		 */
29302793Slm66018 		if ((tstate & TS_IN_RESET) &&
29312793Slm66018 		    ldcp->rx_intr_state == LDC_INTR_PEND) {
29323010Slm66018 			D1(ldcp->id,
29332793Slm66018 			    "ldc_up: (0x%llx) channel has pending data, "
29342793Slm66018 			    "clearing interrupt\n", ldcp->id);
29352793Slm66018 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
29362793Slm66018 		}
29372793Slm66018 
29381991Sheppo 		mutex_exit(&ldcp->lock);
29391991Sheppo 		return (0);
29401991Sheppo 	}
29411991Sheppo 
29421991Sheppo 	/* if the channel is in RAW mode - mark it as UP, if READY */
29431991Sheppo 	if (ldcp->mode == LDC_MODE_RAW && ldcp->tstate >= TS_READY) {
29441991Sheppo 		ldcp->tstate = TS_UP;
29451991Sheppo 		mutex_exit(&ldcp->lock);
29461991Sheppo 		return (0);
29471991Sheppo 	}
29481991Sheppo 
29491991Sheppo 	/* Don't start another handshake if there is one in progress */
29501991Sheppo 	if (ldcp->hstate) {
29512793Slm66018 		D1(ldcp->id,
29521991Sheppo 		    "ldc_up: (0x%llx) channel handshake in progress\n",
29531991Sheppo 		    ldcp->id);
29541991Sheppo 		mutex_exit(&ldcp->lock);
29551991Sheppo 		return (0);
29561991Sheppo 	}
29571991Sheppo 
29582336Snarayan 	mutex_enter(&ldcp->tx_lock);
29592336Snarayan 
29601991Sheppo 	/* get the current tail for the LDC msg */
29611991Sheppo 	rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
29621991Sheppo 	if (rv) {
29633010Slm66018 		D1(ldcp->id, "ldc_up: (0x%llx) cannot initiate handshake\n",
29641991Sheppo 		    ldcp->id);
29652336Snarayan 		mutex_exit(&ldcp->tx_lock);
29661991Sheppo 		mutex_exit(&ldcp->lock);
29671991Sheppo 		return (ECONNREFUSED);
29681991Sheppo 	}
29691991Sheppo 
29701991Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
29711991Sheppo 	ZERO_PKT(ldcmsg);
29721991Sheppo 
29731991Sheppo 	ldcmsg->type = LDC_CTRL;
29741991Sheppo 	ldcmsg->stype = LDC_INFO;
29751991Sheppo 	ldcmsg->ctrl = LDC_VER;
29761991Sheppo 	ldcp->next_vidx = 0;
29771991Sheppo 	bcopy(&ldc_versions[0], ldcmsg->udata, sizeof (ldc_versions[0]));
29781991Sheppo 
29791991Sheppo 	DUMP_LDC_PKT(ldcp, "ldc_up snd ver", (uint64_t)ldcmsg);
29801991Sheppo 
29811991Sheppo 	/* initiate the send by calling into HV and set the new tail */
29821991Sheppo 	tx_tail = (tx_tail + LDC_PACKET_SIZE) %
29831991Sheppo 		(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
29841991Sheppo 
29851991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
29861991Sheppo 	if (rv) {
29871991Sheppo 		DWARN(ldcp->id,
29881991Sheppo 		    "ldc_up: (0x%llx) cannot initiate handshake rv=%d\n",
29891991Sheppo 		    ldcp->id, rv);
29902336Snarayan 		mutex_exit(&ldcp->tx_lock);
29911991Sheppo 		mutex_exit(&ldcp->lock);
29921991Sheppo 		return (rv);
29931991Sheppo 	}
29941991Sheppo 
29952032Slm66018 	ldcp->hstate |= TS_SENT_VER;
29961991Sheppo 	ldcp->tx_tail = tx_tail;
29971991Sheppo 	D1(ldcp->id, "ldc_up: (0x%llx) channel up initiated\n", ldcp->id);
29981991Sheppo 
29992336Snarayan 	mutex_exit(&ldcp->tx_lock);
30001991Sheppo 	mutex_exit(&ldcp->lock);
30011991Sheppo 
30021991Sheppo 	return (rv);
30031991Sheppo }
30041991Sheppo 
30051991Sheppo 
30061991Sheppo /*
30072410Slm66018  * Bring a channel down by resetting its state and queues
30081991Sheppo  */
30091991Sheppo int
30102410Slm66018 ldc_down(ldc_handle_t handle)
30111991Sheppo {
30121991Sheppo 	ldc_chan_t 	*ldcp;
30131991Sheppo 
30141991Sheppo 	if (handle == NULL) {
30152410Slm66018 		DWARN(DBG_ALL_LDCS, "ldc_down: invalid channel handle\n");
30161991Sheppo 		return (EINVAL);
30171991Sheppo 	}
30181991Sheppo 	ldcp = (ldc_chan_t *)handle;
30191991Sheppo 	mutex_enter(&ldcp->lock);
30202336Snarayan 	mutex_enter(&ldcp->tx_lock);
30212793Slm66018 	i_ldc_reset(ldcp, B_TRUE);
30222336Snarayan 	mutex_exit(&ldcp->tx_lock);
30231991Sheppo 	mutex_exit(&ldcp->lock);
30241991Sheppo 
30251991Sheppo 	return (0);
30261991Sheppo }
30271991Sheppo 
30281991Sheppo /*
30291991Sheppo  * Get the current channel status
30301991Sheppo  */
30311991Sheppo int
30321991Sheppo ldc_status(ldc_handle_t handle, ldc_status_t *status)
30331991Sheppo {
30341991Sheppo 	ldc_chan_t *ldcp;
30351991Sheppo 
30361991Sheppo 	if (handle == NULL || status == NULL) {
30371991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_status: invalid argument\n");
30381991Sheppo 		return (EINVAL);
30391991Sheppo 	}
30401991Sheppo 	ldcp = (ldc_chan_t *)handle;
30411991Sheppo 
30421991Sheppo 	*status = ((ldc_chan_t *)handle)->status;
30431991Sheppo 
30443010Slm66018 	D1(ldcp->id,
30451991Sheppo 	    "ldc_status: (0x%llx) returned status %d\n", ldcp->id, *status);
30461991Sheppo 	return (0);
30471991Sheppo }
30481991Sheppo 
30491991Sheppo 
30501991Sheppo /*
30511991Sheppo  * Set the channel's callback mode - enable/disable callbacks
30521991Sheppo  */
30531991Sheppo int
30541991Sheppo ldc_set_cb_mode(ldc_handle_t handle, ldc_cb_mode_t cmode)
30551991Sheppo {
30561991Sheppo 	ldc_chan_t 	*ldcp;
30571991Sheppo 
30581991Sheppo 	if (handle == NULL) {
30591991Sheppo 		DWARN(DBG_ALL_LDCS,
30601991Sheppo 		    "ldc_set_intr_mode: invalid channel handle\n");
30611991Sheppo 		return (EINVAL);
30621991Sheppo 	}
30631991Sheppo 	ldcp = (ldc_chan_t *)handle;
30641991Sheppo 
30651991Sheppo 	/*
30661991Sheppo 	 * Record no callbacks should be invoked
30671991Sheppo 	 */
30681991Sheppo 	mutex_enter(&ldcp->lock);
30691991Sheppo 
30701991Sheppo 	switch (cmode) {
30711991Sheppo 	case LDC_CB_DISABLE:
30721991Sheppo 		if (!ldcp->cb_enabled) {
30731991Sheppo 			DWARN(ldcp->id,
30741991Sheppo 			    "ldc_set_cb_mode: (0x%llx) callbacks disabled\n",
30751991Sheppo 			    ldcp->id);
30761991Sheppo 			break;
30771991Sheppo 		}
30781991Sheppo 		ldcp->cb_enabled = B_FALSE;
30791991Sheppo 
30801991Sheppo 		D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) disabled callbacks\n",
30811991Sheppo 		    ldcp->id);
30821991Sheppo 		break;
30831991Sheppo 
30841991Sheppo 	case LDC_CB_ENABLE:
30851991Sheppo 		if (ldcp->cb_enabled) {
30861991Sheppo 			DWARN(ldcp->id,
30871991Sheppo 			    "ldc_set_cb_mode: (0x%llx) callbacks enabled\n",
30881991Sheppo 			    ldcp->id);
30891991Sheppo 			break;
30901991Sheppo 		}
30911991Sheppo 		ldcp->cb_enabled = B_TRUE;
30921991Sheppo 
30931991Sheppo 		D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) enabled callbacks\n",
30941991Sheppo 		    ldcp->id);
30951991Sheppo 		break;
30961991Sheppo 	}
30971991Sheppo 
30981991Sheppo 	mutex_exit(&ldcp->lock);
30991991Sheppo 
31001991Sheppo 	return (0);
31011991Sheppo }
31021991Sheppo 
31031991Sheppo /*
31041991Sheppo  * Check to see if there are packets on the incoming queue
31052410Slm66018  * Will return hasdata = B_FALSE if there are no packets
31061991Sheppo  */
31071991Sheppo int
31082410Slm66018 ldc_chkq(ldc_handle_t handle, boolean_t *hasdata)
31091991Sheppo {
31101991Sheppo 	int 		rv;
31111991Sheppo 	uint64_t 	rx_head, rx_tail;
31121991Sheppo 	ldc_chan_t 	*ldcp;
31131991Sheppo 
31141991Sheppo 	if (handle == NULL) {
31151991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_chkq: invalid channel handle\n");
31161991Sheppo 		return (EINVAL);
31171991Sheppo 	}
31181991Sheppo 	ldcp = (ldc_chan_t *)handle;
31191991Sheppo 
31202410Slm66018 	*hasdata = B_FALSE;
31211991Sheppo 
31221991Sheppo 	mutex_enter(&ldcp->lock);
31231991Sheppo 
31241991Sheppo 	if (ldcp->tstate != TS_UP) {
31251991Sheppo 		D1(ldcp->id,
31261991Sheppo 		    "ldc_chkq: (0x%llx) channel is not up\n", ldcp->id);
31271991Sheppo 		mutex_exit(&ldcp->lock);
31281991Sheppo 		return (ECONNRESET);
31291991Sheppo 	}
31301991Sheppo 
31311991Sheppo 	/* Read packet(s) from the queue */
31321991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
31331991Sheppo 	    &ldcp->link_state);
31341991Sheppo 	if (rv != 0) {
31351991Sheppo 		cmn_err(CE_WARN,
31361991Sheppo 		    "ldc_chkq: (0x%lx) unable to read queue ptrs", ldcp->id);
31371991Sheppo 		mutex_exit(&ldcp->lock);
31381991Sheppo 		return (EIO);
31391991Sheppo 	}
31401991Sheppo 	/* reset the channel state if the channel went down */
31411991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
31421991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
31432336Snarayan 		mutex_enter(&ldcp->tx_lock);
31442793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
31452336Snarayan 		mutex_exit(&ldcp->tx_lock);
31461991Sheppo 		mutex_exit(&ldcp->lock);
31471991Sheppo 		return (ECONNRESET);
31481991Sheppo 	}
31491991Sheppo 
31502531Snarayan 	if ((rx_head != rx_tail) ||
31512531Snarayan 	    (ldcp->mode == LDC_MODE_STREAM && ldcp->stream_remains > 0)) {
31522531Snarayan 		D1(ldcp->id,
31532531Snarayan 		    "ldc_chkq: (0x%llx) queue has pkt(s) or buffered data\n",
31542531Snarayan 		    ldcp->id);
31552410Slm66018 		*hasdata = B_TRUE;
31561991Sheppo 	}
31571991Sheppo 
31581991Sheppo 	mutex_exit(&ldcp->lock);
31591991Sheppo 
31601991Sheppo 	return (0);
31611991Sheppo }
31621991Sheppo 
31631991Sheppo 
31641991Sheppo /*
31651991Sheppo  * Read 'size' amount of bytes or less. If incoming buffer
31661991Sheppo  * is more than 'size', ENOBUFS is returned.
31671991Sheppo  *
31681991Sheppo  * On return, size contains the number of bytes read.
31691991Sheppo  */
31701991Sheppo int
31711991Sheppo ldc_read(ldc_handle_t handle, caddr_t bufp, size_t *sizep)
31721991Sheppo {
31731991Sheppo 	ldc_chan_t 	*ldcp;
31741991Sheppo 	uint64_t 	rx_head = 0, rx_tail = 0;
31751991Sheppo 	int		rv = 0, exit_val;
31761991Sheppo 
31771991Sheppo 	if (handle == NULL) {
31781991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_read: invalid channel handle\n");
31791991Sheppo 		return (EINVAL);
31801991Sheppo 	}
31811991Sheppo 
31821991Sheppo 	ldcp = (ldc_chan_t *)handle;
31831991Sheppo 
31841991Sheppo 	/* channel lock */
31851991Sheppo 	mutex_enter(&ldcp->lock);
31861991Sheppo 
31871991Sheppo 	if (ldcp->tstate != TS_UP) {
31881991Sheppo 		DWARN(ldcp->id,
31891991Sheppo 		    "ldc_read: (0x%llx) channel is not in UP state\n",
31901991Sheppo 		    ldcp->id);
31911991Sheppo 		exit_val = ECONNRESET;
31921991Sheppo 	} else {
31931991Sheppo 		exit_val = ldcp->read_p(ldcp, bufp, sizep);
31941991Sheppo 	}
31951991Sheppo 
31961991Sheppo 	/*
31971991Sheppo 	 * if queue has been drained - clear interrupt
31981991Sheppo 	 */
31991991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
32001991Sheppo 	    &ldcp->link_state);
32013010Slm66018 	if (rv != 0) {
32023010Slm66018 		cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
32033010Slm66018 		    ldcp->id);
32043010Slm66018 		mutex_enter(&ldcp->tx_lock);
32053010Slm66018 		i_ldc_reset(ldcp, B_TRUE);
32063010Slm66018 		mutex_exit(&ldcp->tx_lock);
32073010Slm66018 		return (ECONNRESET);
32083010Slm66018 	}
32092793Slm66018 
32102793Slm66018 	if (exit_val == 0) {
32112793Slm66018 		if (ldcp->link_state == LDC_CHANNEL_DOWN ||
32122793Slm66018 		    ldcp->link_state == LDC_CHANNEL_RESET) {
32132793Slm66018 			mutex_enter(&ldcp->tx_lock);
32142793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
32152793Slm66018 			exit_val = ECONNRESET;
32162793Slm66018 			mutex_exit(&ldcp->tx_lock);
32172793Slm66018 		}
32182793Slm66018 		if ((rv == 0) &&
32192793Slm66018 		    (ldcp->rx_intr_state == LDC_INTR_PEND) &&
32202793Slm66018 		    (rx_head == rx_tail)) {
32212793Slm66018 			i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
32222793Slm66018 		}
32231991Sheppo 	}
32241991Sheppo 
32251991Sheppo 	mutex_exit(&ldcp->lock);
32261991Sheppo 	return (exit_val);
32271991Sheppo }
32281991Sheppo 
32291991Sheppo /*
32301991Sheppo  * Basic raw mondo read -
32311991Sheppo  * no interpretation of mondo contents at all.
32321991Sheppo  *
32331991Sheppo  * Enter and exit with ldcp->lock held by caller
32341991Sheppo  */
32351991Sheppo static int
32361991Sheppo i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
32371991Sheppo {
32381991Sheppo 	uint64_t 	q_size_mask;
32391991Sheppo 	ldc_msg_t 	*msgp;
32401991Sheppo 	uint8_t		*msgbufp;
32411991Sheppo 	int		rv = 0, space;
32421991Sheppo 	uint64_t 	rx_head, rx_tail;
32431991Sheppo 
32441991Sheppo 	space = *sizep;
32451991Sheppo 
32461991Sheppo 	if (space < LDC_PAYLOAD_SIZE_RAW)
32471991Sheppo 		return (ENOBUFS);
32481991Sheppo 
32491991Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
32501991Sheppo 
32511991Sheppo 	/* compute mask for increment */
32521991Sheppo 	q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
32531991Sheppo 
32541991Sheppo 	/*
32551991Sheppo 	 * Read packet(s) from the queue
32561991Sheppo 	 */
32571991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
32581991Sheppo 	    &ldcp->link_state);
32591991Sheppo 	if (rv != 0) {
32601991Sheppo 		cmn_err(CE_WARN,
32611991Sheppo 		    "ldc_read_raw: (0x%lx) unable to read queue ptrs",
32621991Sheppo 		    ldcp->id);
32631991Sheppo 		return (EIO);
32641991Sheppo 	}
32651991Sheppo 	D1(ldcp->id, "ldc_read_raw: (0x%llx) rxh=0x%llx,"
32661991Sheppo 		" rxt=0x%llx, st=0x%llx\n",
32671991Sheppo 		ldcp->id, rx_head, rx_tail, ldcp->link_state);
32681991Sheppo 
32691991Sheppo 	/* reset the channel state if the channel went down */
32702793Slm66018 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
32712793Slm66018 	    ldcp->link_state == LDC_CHANNEL_RESET) {
32722336Snarayan 		mutex_enter(&ldcp->tx_lock);
32732793Slm66018 		i_ldc_reset(ldcp, B_FALSE);
32742336Snarayan 		mutex_exit(&ldcp->tx_lock);
32751991Sheppo 		return (ECONNRESET);
32761991Sheppo 	}
32771991Sheppo 
32781991Sheppo 	/*
32791991Sheppo 	 * Check for empty queue
32801991Sheppo 	 */
32811991Sheppo 	if (rx_head == rx_tail) {
32821991Sheppo 		*sizep = 0;
32831991Sheppo 		return (0);
32841991Sheppo 	}
32851991Sheppo 
32861991Sheppo 	/* get the message */
32871991Sheppo 	msgp = (ldc_msg_t *)(ldcp->rx_q_va + rx_head);
32881991Sheppo 
32891991Sheppo 	/* if channel is in RAW mode, copy data and return */
32901991Sheppo 	msgbufp = (uint8_t *)&(msgp->raw[0]);
32911991Sheppo 
32921991Sheppo 	bcopy(msgbufp, target_bufp, LDC_PAYLOAD_SIZE_RAW);
32931991Sheppo 
32941991Sheppo 	DUMP_PAYLOAD(ldcp->id, msgbufp);
32951991Sheppo 
32961991Sheppo 	*sizep = LDC_PAYLOAD_SIZE_RAW;
32971991Sheppo 
32981991Sheppo 	rx_head = (rx_head + LDC_PACKET_SIZE) & q_size_mask;
32992032Slm66018 	rv = i_ldc_set_rx_head(ldcp, rx_head);
33001991Sheppo 
33011991Sheppo 	return (rv);
33021991Sheppo }
33031991Sheppo 
33041991Sheppo /*
33051991Sheppo  * Process LDC mondos to build larger packets
33061991Sheppo  * with either un-reliable or reliable delivery.
33071991Sheppo  *
33081991Sheppo  * Enter and exit with ldcp->lock held by caller
33091991Sheppo  */
33101991Sheppo static int
33111991Sheppo i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
33121991Sheppo {
33131991Sheppo 	int		rv = 0;
33141991Sheppo 	uint64_t 	rx_head = 0, rx_tail = 0;
33151991Sheppo 	uint64_t 	curr_head = 0;
33161991Sheppo 	ldc_msg_t 	*msg;
33171991Sheppo 	caddr_t 	target;
33181991Sheppo 	size_t 		len = 0, bytes_read = 0;
33192032Slm66018 	int 		retries = 0;
33201991Sheppo 	uint64_t 	q_size_mask;
33212336Snarayan 	uint64_t	first_fragment = 0;
33221991Sheppo 
33231991Sheppo 	target = target_bufp;
33241991Sheppo 
33251991Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
33261991Sheppo 
33272793Slm66018 	/* check if the buffer and size are valid */
33282793Slm66018 	if (target_bufp == NULL || *sizep == 0) {
33292793Slm66018 		DWARN(ldcp->id, "ldc_read: (0x%llx) invalid buffer/size\n",
33302793Slm66018 		    ldcp->id);
33312793Slm66018 		return (EINVAL);
33322793Slm66018 	}
33332793Slm66018 
33341991Sheppo 	/* compute mask for increment */
33351991Sheppo 	q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
33361991Sheppo 
33371991Sheppo 	/*
33381991Sheppo 	 * Read packet(s) from the queue
33391991Sheppo 	 */
33401991Sheppo 	rv = hv_ldc_rx_get_state(ldcp->id, &curr_head, &rx_tail,
33411991Sheppo 	    &ldcp->link_state);
33421991Sheppo 	if (rv != 0) {
33432793Slm66018 		cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
33441991Sheppo 		    ldcp->id);
33452793Slm66018 		mutex_enter(&ldcp->tx_lock);
33462793Slm66018 		i_ldc_reset(ldcp, B_TRUE);
33472793Slm66018 		mutex_exit(&ldcp->tx_lock);
33482793Slm66018 		return (ECONNRESET);
33491991Sheppo 	}
33501991Sheppo 	D1(ldcp->id, "ldc_read: (0x%llx) chd=0x%llx, tl=0x%llx, st=0x%llx\n",
33511991Sheppo 	    ldcp->id, curr_head, rx_tail, ldcp->link_state);
33521991Sheppo 
33531991Sheppo 	/* reset the channel state if the channel went down */
33542793Slm66018 	if (ldcp->link_state != LDC_CHANNEL_UP)
33552793Slm66018 		goto channel_is_reset;
33561991Sheppo 
33571991Sheppo 	for (;;) {
33581991Sheppo 
33591991Sheppo 		if (curr_head == rx_tail) {
33601991Sheppo 			rv = hv_ldc_rx_get_state(ldcp->id,
33611991Sheppo 			    &rx_head, &rx_tail, &ldcp->link_state);
33621991Sheppo 			if (rv != 0) {
33631991Sheppo 				cmn_err(CE_WARN,
33641991Sheppo 				    "ldc_read: (0x%lx) cannot read queue ptrs",
33651991Sheppo 				    ldcp->id);
33662336Snarayan 				mutex_enter(&ldcp->tx_lock);
33672793Slm66018 				i_ldc_reset(ldcp, B_TRUE);
33682336Snarayan 				mutex_exit(&ldcp->tx_lock);
33691991Sheppo 				return (ECONNRESET);
33701991Sheppo 			}
33712793Slm66018 			if (ldcp->link_state != LDC_CHANNEL_UP)
33722793Slm66018 				goto channel_is_reset;
33732793Slm66018 
33742793Slm66018 			if (curr_head == rx_tail) {
33752793Slm66018 
33762793Slm66018 				/* If in the middle of a fragmented xfer */
33772793Slm66018 				if (first_fragment != 0) {
33782793Slm66018 
33792793Slm66018 					/* wait for ldc_delay usecs */
33802793Slm66018 					drv_usecwait(ldc_delay);
33812793Slm66018 
33822793Slm66018 					if (++retries < ldc_max_retries)
33832793Slm66018 						continue;
33842793Slm66018 
33852793Slm66018 					*sizep = 0;
33862793Slm66018 					ldcp->last_msg_rcd = first_fragment - 1;
33872793Slm66018 					DWARN(DBG_ALL_LDCS, "ldc_read: "
33882793Slm66018 						"(0x%llx) read timeout",
33892793Slm66018 						ldcp->id);
33902793Slm66018 					return (EAGAIN);
33912793Slm66018 				}
33922032Slm66018 				*sizep = 0;
33932793Slm66018 				break;
33941991Sheppo 			}
33951991Sheppo 		}
33962032Slm66018 		retries = 0;
33971991Sheppo 
33981991Sheppo 		D2(ldcp->id,
33991991Sheppo 		    "ldc_read: (0x%llx) chd=0x%llx, rxhd=0x%llx, rxtl=0x%llx\n",
34001991Sheppo 		    ldcp->id, curr_head, rx_head, rx_tail);
34011991Sheppo 
34021991Sheppo 		/* get the message */
34031991Sheppo 		msg = (ldc_msg_t *)(ldcp->rx_q_va + curr_head);
34041991Sheppo 
34051991Sheppo 		DUMP_LDC_PKT(ldcp, "ldc_read received pkt",
34061991Sheppo 		    ldcp->rx_q_va + curr_head);
34071991Sheppo 
34081991Sheppo 		/* Check the message ID for the message received */
34091991Sheppo 		if ((rv = i_ldc_check_seqid(ldcp, msg)) != 0) {
34101991Sheppo 
34111991Sheppo 			DWARN(ldcp->id, "ldc_read: (0x%llx) seqid error, "
34121991Sheppo 			    "q_ptrs=0x%lx,0x%lx", ldcp->id, rx_head, rx_tail);
34131991Sheppo 
34142032Slm66018 			/* throw away data */
34152032Slm66018 			bytes_read = 0;
34162032Slm66018 
34171991Sheppo 			/* Reset last_msg_rcd to start of message */
34182336Snarayan 			if (first_fragment != 0) {
34192336Snarayan 				ldcp->last_msg_rcd = first_fragment - 1;
34202336Snarayan 				first_fragment = 0;
34211991Sheppo 			}
34221991Sheppo 			/*
34231991Sheppo 			 * Send a NACK -- invalid seqid
34241991Sheppo 			 * get the current tail for the response
34251991Sheppo 			 */
34261991Sheppo 			rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK,
34271991Sheppo 			    (msg->ctrl & LDC_CTRL_MASK));
34281991Sheppo 			if (rv) {
34291991Sheppo 				cmn_err(CE_NOTE,
34301991Sheppo 				    "ldc_read: (0x%lx) err sending "
34311991Sheppo 				    "NACK msg\n", ldcp->id);
34322336Snarayan 
34332336Snarayan 				/* if cannot send NACK - reset channel */
34342336Snarayan 				mutex_enter(&ldcp->tx_lock);
34352793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
34362336Snarayan 				mutex_exit(&ldcp->tx_lock);
34372336Snarayan 				rv = ECONNRESET;
34382336Snarayan 				break;
34391991Sheppo 			}
34401991Sheppo 
34411991Sheppo 			/* purge receive queue */
34422032Slm66018 			rv = i_ldc_set_rx_head(ldcp, rx_tail);
34431991Sheppo 
34441991Sheppo 			break;
34451991Sheppo 		}
34461991Sheppo 
34471991Sheppo 		/*
34481991Sheppo 		 * Process any messages of type CTRL messages
34492410Slm66018 		 * Future implementations should try to pass these
34502410Slm66018 		 * to LDC link by resetting the intr state.
34511991Sheppo 		 *
34521991Sheppo 		 * NOTE: not done as a switch() as type can be both ctrl+data
34531991Sheppo 		 */
34541991Sheppo 		if (msg->type & LDC_CTRL) {
34551991Sheppo 			if (rv = i_ldc_ctrlmsg(ldcp, msg)) {
34561991Sheppo 				if (rv == EAGAIN)
34571991Sheppo 					continue;
34582032Slm66018 				rv = i_ldc_set_rx_head(ldcp, rx_tail);
34591991Sheppo 				*sizep = 0;
34601991Sheppo 				bytes_read = 0;
34611991Sheppo 				break;
34621991Sheppo 			}
34631991Sheppo 		}
34641991Sheppo 
34651991Sheppo 		/* process data ACKs */
34661991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
34672336Snarayan 			if (rv = i_ldc_process_data_ACK(ldcp, msg)) {
34682336Snarayan 				*sizep = 0;
34692336Snarayan 				bytes_read = 0;
34702336Snarayan 				break;
34712336Snarayan 			}
34721991Sheppo 		}
34731991Sheppo 
34741991Sheppo 		/* process data messages */
34751991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
34761991Sheppo 
34771991Sheppo 			uint8_t *msgbuf = (uint8_t *)(
34781991Sheppo 				(ldcp->mode == LDC_MODE_RELIABLE ||
34791991Sheppo 				ldcp->mode == LDC_MODE_STREAM)
34801991Sheppo 				? msg->rdata : msg->udata);
34811991Sheppo 
34821991Sheppo 			D2(ldcp->id,
34831991Sheppo 			    "ldc_read: (0x%llx) received data msg\n", ldcp->id);
34841991Sheppo 
34851991Sheppo 			/* get the packet length */
34861991Sheppo 			len = (msg->env & LDC_LEN_MASK);
34871991Sheppo 
34881991Sheppo 				/*
34891991Sheppo 				 * FUTURE OPTIMIZATION:
34901991Sheppo 				 * dont need to set q head for every
34911991Sheppo 				 * packet we read just need to do this when
34921991Sheppo 				 * we are done or need to wait for more
34931991Sheppo 				 * mondos to make a full packet - this is
34941991Sheppo 				 * currently expensive.
34951991Sheppo 				 */
34961991Sheppo 
34972336Snarayan 			if (first_fragment == 0) {
34981991Sheppo 
34991991Sheppo 				/*
35001991Sheppo 				 * first packets should always have the start
35011991Sheppo 				 * bit set (even for a single packet). If not
35021991Sheppo 				 * throw away the packet
35031991Sheppo 				 */
35041991Sheppo 				if (!(msg->env & LDC_FRAG_START)) {
35051991Sheppo 
35061991Sheppo 					DWARN(DBG_ALL_LDCS,
35071991Sheppo 					    "ldc_read: (0x%llx) not start - "
35081991Sheppo 					    "frag=%x\n", ldcp->id,
35091991Sheppo 					    (msg->env) & LDC_FRAG_MASK);
35101991Sheppo 
35111991Sheppo 					/* toss pkt, inc head, cont reading */
35121991Sheppo 					bytes_read = 0;
35131991Sheppo 					target = target_bufp;
35141991Sheppo 					curr_head =
35151991Sheppo 						(curr_head + LDC_PACKET_SIZE)
35161991Sheppo 						& q_size_mask;
35171991Sheppo 					if (rv = i_ldc_set_rx_head(ldcp,
35181991Sheppo 						curr_head))
35191991Sheppo 						break;
35201991Sheppo 
35211991Sheppo 					continue;
35221991Sheppo 				}
35231991Sheppo 
35242336Snarayan 				first_fragment = msg->seqid;
35251991Sheppo 			} else {
35261991Sheppo 				/* check to see if this is a pkt w/ START bit */
35271991Sheppo 				if (msg->env & LDC_FRAG_START) {
35281991Sheppo 					DWARN(DBG_ALL_LDCS,
35291991Sheppo 					    "ldc_read:(0x%llx) unexpected pkt"
35301991Sheppo 					    " env=0x%x discarding %d bytes,"
35311991Sheppo 					    " lastmsg=%d, currentmsg=%d\n",
35321991Sheppo 					    ldcp->id, msg->env&LDC_FRAG_MASK,
35331991Sheppo 					    bytes_read, ldcp->last_msg_rcd,
35341991Sheppo 					    msg->seqid);
35351991Sheppo 
35361991Sheppo 					/* throw data we have read so far */
35371991Sheppo 					bytes_read = 0;
35381991Sheppo 					target = target_bufp;
35392336Snarayan 					first_fragment = msg->seqid;
35401991Sheppo 
35411991Sheppo 					if (rv = i_ldc_set_rx_head(ldcp,
35421991Sheppo 						curr_head))
35431991Sheppo 						break;
35441991Sheppo 				}
35451991Sheppo 			}
35461991Sheppo 
35471991Sheppo 			/* copy (next) pkt into buffer */
35481991Sheppo 			if (len <= (*sizep - bytes_read)) {
35491991Sheppo 				bcopy(msgbuf, target, len);
35501991Sheppo 				target += len;
35511991Sheppo 				bytes_read += len;
35521991Sheppo 			} else {
35531991Sheppo 				/*
35541991Sheppo 				 * there is not enough space in the buffer to
35551991Sheppo 				 * read this pkt. throw message away & continue
35561991Sheppo 				 * reading data from queue
35571991Sheppo 				 */
35581991Sheppo 				DWARN(DBG_ALL_LDCS,
35591991Sheppo 				    "ldc_read: (0x%llx) buffer too small, "
35601991Sheppo 				    "head=0x%lx, expect=%d, got=%d\n", ldcp->id,
35611991Sheppo 				    curr_head, *sizep, bytes_read+len);
35621991Sheppo 
35632336Snarayan 				first_fragment = 0;
35641991Sheppo 				target = target_bufp;
35651991Sheppo 				bytes_read = 0;
35661991Sheppo 
35671991Sheppo 				/* throw away everything received so far */
35681991Sheppo 				if (rv = i_ldc_set_rx_head(ldcp, curr_head))
35691991Sheppo 					break;
35701991Sheppo 
35711991Sheppo 				/* continue reading remaining pkts */
35721991Sheppo 				continue;
35731991Sheppo 			}
35741991Sheppo 		}
35751991Sheppo 
35761991Sheppo 		/* set the message id */
35771991Sheppo 		ldcp->last_msg_rcd = msg->seqid;
35781991Sheppo 
35791991Sheppo 		/* move the head one position */
35801991Sheppo 		curr_head = (curr_head + LDC_PACKET_SIZE) & q_size_mask;
35811991Sheppo 
35821991Sheppo 		if (msg->env & LDC_FRAG_STOP) {
35831991Sheppo 
35841991Sheppo 			/*
35851991Sheppo 			 * All pkts that are part of this fragmented transfer
35861991Sheppo 			 * have been read or this was a single pkt read
35871991Sheppo 			 * or there was an error
35881991Sheppo 			 */
35891991Sheppo 
35901991Sheppo 			/* set the queue head */
35911991Sheppo 			if (rv = i_ldc_set_rx_head(ldcp, curr_head))
35921991Sheppo 				bytes_read = 0;
35931991Sheppo 
35941991Sheppo 			*sizep = bytes_read;
35951991Sheppo 
35961991Sheppo 			break;
35971991Sheppo 		}
35981991Sheppo 
35991991Sheppo 		/* advance head if it is a DATA ACK */
36001991Sheppo 		if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
36011991Sheppo 
36021991Sheppo 			/* set the queue head */
36031991Sheppo 			if (rv = i_ldc_set_rx_head(ldcp, curr_head)) {
36041991Sheppo 				bytes_read = 0;
36051991Sheppo 				break;
36061991Sheppo 			}
36071991Sheppo 
36081991Sheppo 			D2(ldcp->id, "ldc_read: (0x%llx) set ACK qhead 0x%llx",
36091991Sheppo 			    ldcp->id, curr_head);
36101991Sheppo 		}
36111991Sheppo 
36121991Sheppo 	} /* for (;;) */
36131991Sheppo 
36141991Sheppo 
36151991Sheppo 	/*
36161991Sheppo 	 * If useful data was read - Send msg ACK
36171991Sheppo 	 * OPTIMIZE: do not send ACK for all msgs - use some frequency
36181991Sheppo 	 */
36191991Sheppo 	if ((bytes_read > 0) && (ldcp->mode == LDC_MODE_RELIABLE ||
36201991Sheppo 		ldcp->mode == LDC_MODE_STREAM)) {
36211991Sheppo 
36221991Sheppo 		rv = i_ldc_send_pkt(ldcp, LDC_DATA, LDC_ACK, 0);
36232793Slm66018 		if (rv && rv != EWOULDBLOCK) {
36241991Sheppo 			cmn_err(CE_NOTE,
36251991Sheppo 			    "ldc_read: (0x%lx) cannot send ACK\n", ldcp->id);
36262336Snarayan 
36272336Snarayan 			/* if cannot send ACK - reset channel */
36282793Slm66018 			goto channel_is_reset;
36291991Sheppo 		}
36301991Sheppo 	}
36311991Sheppo 
36321991Sheppo 	D2(ldcp->id, "ldc_read: (0x%llx) end size=%d", ldcp->id, *sizep);
36331991Sheppo 
36341991Sheppo 	return (rv);
36352793Slm66018 
36362793Slm66018 channel_is_reset:
36372793Slm66018 	mutex_enter(&ldcp->tx_lock);
36382793Slm66018 	i_ldc_reset(ldcp, B_FALSE);
36392793Slm66018 	mutex_exit(&ldcp->tx_lock);
36402793Slm66018 	return (ECONNRESET);
36411991Sheppo }
36421991Sheppo 
36431991Sheppo /*
36441991Sheppo  * Use underlying reliable packet mechanism to fetch
36451991Sheppo  * and buffer incoming packets so we can hand them back as
36461991Sheppo  * a basic byte stream.
36471991Sheppo  *
36481991Sheppo  * Enter and exit with ldcp->lock held by caller
36491991Sheppo  */
36501991Sheppo static int
36511991Sheppo i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
36521991Sheppo {
36531991Sheppo 	int	rv;
36541991Sheppo 	size_t	size;
36551991Sheppo 
36561991Sheppo 	ASSERT(mutex_owned(&ldcp->lock));
36571991Sheppo 
36581991Sheppo 	D2(ldcp->id, "i_ldc_read_stream: (0x%llx) buffer size=%d",
36591991Sheppo 		ldcp->id, *sizep);
36601991Sheppo 
36611991Sheppo 	if (ldcp->stream_remains == 0) {
36621991Sheppo 		size = ldcp->mtu;
36631991Sheppo 		rv = i_ldc_read_packet(ldcp,
36641991Sheppo 			(caddr_t)ldcp->stream_bufferp, &size);
36651991Sheppo 		D2(ldcp->id, "i_ldc_read_stream: read packet (0x%llx) size=%d",
36661991Sheppo 			ldcp->id, size);
36671991Sheppo 
36681991Sheppo 		if (rv != 0)
36691991Sheppo 			return (rv);
36701991Sheppo 
36711991Sheppo 		ldcp->stream_remains = size;
36721991Sheppo 		ldcp->stream_offset = 0;
36731991Sheppo 	}
36741991Sheppo 
36751991Sheppo 	size = MIN(ldcp->stream_remains, *sizep);
36761991Sheppo 
36771991Sheppo 	bcopy(ldcp->stream_bufferp + ldcp->stream_offset, target_bufp, size);
36781991Sheppo 	ldcp->stream_offset += size;
36791991Sheppo 	ldcp->stream_remains -= size;
36801991Sheppo 
36811991Sheppo 	D2(ldcp->id, "i_ldc_read_stream: (0x%llx) fill from buffer size=%d",
36821991Sheppo 		ldcp->id, size);
36831991Sheppo 
36841991Sheppo 	*sizep = size;
36851991Sheppo 	return (0);
36861991Sheppo }
36871991Sheppo 
36881991Sheppo /*
36891991Sheppo  * Write specified amount of bytes to the channel
36901991Sheppo  * in multiple pkts of pkt_payload size. Each
36911991Sheppo  * packet is tagged with an unique packet ID in
36922410Slm66018  * the case of a reliable link.
36931991Sheppo  *
36941991Sheppo  * On return, size contains the number of bytes written.
36951991Sheppo  */
36961991Sheppo int
36971991Sheppo ldc_write(ldc_handle_t handle, caddr_t buf, size_t *sizep)
36981991Sheppo {
36991991Sheppo 	ldc_chan_t	*ldcp;
37001991Sheppo 	int		rv = 0;
37011991Sheppo 
37021991Sheppo 	if (handle == NULL) {
37031991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_write: invalid channel handle\n");
37041991Sheppo 		return (EINVAL);
37051991Sheppo 	}
37061991Sheppo 	ldcp = (ldc_chan_t *)handle;
37071991Sheppo 
37082336Snarayan 	/* check if writes can occur */
37092336Snarayan 	if (!mutex_tryenter(&ldcp->tx_lock)) {
37102336Snarayan 		/*
37112336Snarayan 		 * Could not get the lock - channel could
37122336Snarayan 		 * be in the process of being unconfigured
37132336Snarayan 		 * or reader has encountered an error
37142336Snarayan 		 */
37152336Snarayan 		return (EAGAIN);
37162336Snarayan 	}
37171991Sheppo 
37181991Sheppo 	/* check if non-zero data to write */
37191991Sheppo 	if (buf == NULL || sizep == NULL) {
37201991Sheppo 		DWARN(ldcp->id, "ldc_write: (0x%llx) invalid data write\n",
37211991Sheppo 		    ldcp->id);
37222336Snarayan 		mutex_exit(&ldcp->tx_lock);
37231991Sheppo 		return (EINVAL);
37241991Sheppo 	}
37251991Sheppo 
37261991Sheppo 	if (*sizep == 0) {
37271991Sheppo 		DWARN(ldcp->id, "ldc_write: (0x%llx) write size of zero\n",
37281991Sheppo 		    ldcp->id);
37292336Snarayan 		mutex_exit(&ldcp->tx_lock);
37301991Sheppo 		return (0);
37311991Sheppo 	}
37321991Sheppo 
37331991Sheppo 	/* Check if channel is UP for data exchange */
37341991Sheppo 	if (ldcp->tstate != TS_UP) {
37351991Sheppo 		DWARN(ldcp->id,
37361991Sheppo 		    "ldc_write: (0x%llx) channel is not in UP state\n",
37371991Sheppo 		    ldcp->id);
37381991Sheppo 		*sizep = 0;
37391991Sheppo 		rv = ECONNRESET;
37401991Sheppo 	} else {
37411991Sheppo 		rv = ldcp->write_p(ldcp, buf, sizep);
37421991Sheppo 	}
37431991Sheppo 
37442336Snarayan 	mutex_exit(&ldcp->tx_lock);
37451991Sheppo 
37461991Sheppo 	return (rv);
37471991Sheppo }
37481991Sheppo 
37491991Sheppo /*
37501991Sheppo  * Write a raw packet to the channel
37511991Sheppo  * On return, size contains the number of bytes written.
37521991Sheppo  */
37531991Sheppo static int
37541991Sheppo i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
37551991Sheppo {
37561991Sheppo 	ldc_msg_t 	*ldcmsg;
37571991Sheppo 	uint64_t 	tx_head, tx_tail, new_tail;
37581991Sheppo 	int		rv = 0;
37591991Sheppo 	size_t		size;
37601991Sheppo 
37612336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
37621991Sheppo 	ASSERT(ldcp->mode == LDC_MODE_RAW);
37631991Sheppo 
37641991Sheppo 	size = *sizep;
37651991Sheppo 
37661991Sheppo 	/*
37671991Sheppo 	 * Check to see if the packet size is less than or
37681991Sheppo 	 * equal to packet size support in raw mode
37691991Sheppo 	 */
37701991Sheppo 	if (size > ldcp->pkt_payload) {
37711991Sheppo 		DWARN(ldcp->id,
37721991Sheppo 		    "ldc_write: (0x%llx) invalid size (0x%llx) for RAW mode\n",
37731991Sheppo 		    ldcp->id, *sizep);
37741991Sheppo 		*sizep = 0;
37751991Sheppo 		return (EMSGSIZE);
37761991Sheppo 	}
37771991Sheppo 
37781991Sheppo 	/* get the qptrs for the tx queue */
37791991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
37801991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
37811991Sheppo 	if (rv != 0) {
37821991Sheppo 		cmn_err(CE_WARN,
37831991Sheppo 		    "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
37841991Sheppo 		*sizep = 0;
37851991Sheppo 		return (EIO);
37861991Sheppo 	}
37871991Sheppo 
37881991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
37891991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
37901991Sheppo 		DWARN(ldcp->id,
37911991Sheppo 		    "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
37922336Snarayan 
37931991Sheppo 		*sizep = 0;
37942336Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
37952793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
37962336Snarayan 			mutex_exit(&ldcp->lock);
37972336Snarayan 		} else {
37982336Snarayan 			/*
37992336Snarayan 			 * Release Tx lock, and then reacquire channel
38002336Snarayan 			 * and Tx lock in correct order
38012336Snarayan 			 */
38022336Snarayan 			mutex_exit(&ldcp->tx_lock);
38032336Snarayan 			mutex_enter(&ldcp->lock);
38042336Snarayan 			mutex_enter(&ldcp->tx_lock);
38052793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
38062336Snarayan 			mutex_exit(&ldcp->lock);
38072336Snarayan 		}
38081991Sheppo 		return (ECONNRESET);
38091991Sheppo 	}
38101991Sheppo 
38111991Sheppo 	tx_tail = ldcp->tx_tail;
38121991Sheppo 	tx_head = ldcp->tx_head;
38131991Sheppo 	new_tail = (tx_tail + LDC_PACKET_SIZE) &
38141991Sheppo 		((ldcp->tx_q_entries-1) << LDC_PACKET_SHIFT);
38151991Sheppo 
38161991Sheppo 	if (new_tail == tx_head) {
38171991Sheppo 		DWARN(DBG_ALL_LDCS,
38181991Sheppo 		    "ldc_write: (0x%llx) TX queue is full\n", ldcp->id);
38191991Sheppo 		*sizep = 0;
38201991Sheppo 		return (EWOULDBLOCK);
38211991Sheppo 	}
38221991Sheppo 
38231991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
38241991Sheppo 	    ldcp->id, size);
38251991Sheppo 
38261991Sheppo 	/* Send the data now */
38271991Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
38281991Sheppo 
38292336Snarayan 	/* copy the data into pkt */
38301991Sheppo 	bcopy((uint8_t *)buf, ldcmsg, size);
38311991Sheppo 
38322336Snarayan 	/* increment tail */
38331991Sheppo 	tx_tail = new_tail;
38341991Sheppo 
38351991Sheppo 	/*
38361991Sheppo 	 * All packets have been copied into the TX queue
38371991Sheppo 	 * update the tail ptr in the HV
38381991Sheppo 	 */
38391991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
38401991Sheppo 	if (rv) {
38411991Sheppo 		if (rv == EWOULDBLOCK) {
38421991Sheppo 			DWARN(ldcp->id, "ldc_write: (0x%llx) write timed out\n",
38431991Sheppo 			    ldcp->id);
38441991Sheppo 			*sizep = 0;
38451991Sheppo 			return (EWOULDBLOCK);
38461991Sheppo 		}
38471991Sheppo 
38481991Sheppo 		*sizep = 0;
38492336Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
38502793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
38512336Snarayan 			mutex_exit(&ldcp->lock);
38522336Snarayan 		} else {
38532336Snarayan 			/*
38542336Snarayan 			 * Release Tx lock, and then reacquire channel
38552336Snarayan 			 * and Tx lock in correct order
38562336Snarayan 			 */
38572336Snarayan 			mutex_exit(&ldcp->tx_lock);
38582336Snarayan 			mutex_enter(&ldcp->lock);
38592336Snarayan 			mutex_enter(&ldcp->tx_lock);
38602793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
38612336Snarayan 			mutex_exit(&ldcp->lock);
38622336Snarayan 		}
38631991Sheppo 		return (ECONNRESET);
38641991Sheppo 	}
38651991Sheppo 
38661991Sheppo 	ldcp->tx_tail = tx_tail;
38671991Sheppo 	*sizep = size;
38681991Sheppo 
38691991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, size);
38701991Sheppo 
38711991Sheppo 	return (rv);
38721991Sheppo }
38731991Sheppo 
38741991Sheppo 
38751991Sheppo /*
38761991Sheppo  * Write specified amount of bytes to the channel
38771991Sheppo  * in multiple pkts of pkt_payload size. Each
38781991Sheppo  * packet is tagged with an unique packet ID in
38792410Slm66018  * the case of a reliable link.
38801991Sheppo  *
38811991Sheppo  * On return, size contains the number of bytes written.
38821991Sheppo  * This function needs to ensure that the write size is < MTU size
38831991Sheppo  */
38841991Sheppo static int
38851991Sheppo i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t buf, size_t *size)
38861991Sheppo {
38871991Sheppo 	ldc_msg_t 	*ldcmsg;
38881991Sheppo 	uint64_t 	tx_head, tx_tail, new_tail, start;
38891991Sheppo 	uint64_t	txq_size_mask, numavail;
38901991Sheppo 	uint8_t 	*msgbuf, *source = (uint8_t *)buf;
38911991Sheppo 	size_t 		len, bytes_written = 0, remaining;
38921991Sheppo 	int		rv;
38931991Sheppo 	uint32_t	curr_seqid;
38941991Sheppo 
38952336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
38961991Sheppo 
38971991Sheppo 	ASSERT(ldcp->mode == LDC_MODE_RELIABLE ||
38981991Sheppo 		ldcp->mode == LDC_MODE_UNRELIABLE ||
38991991Sheppo 		ldcp->mode == LDC_MODE_STREAM);
39001991Sheppo 
39011991Sheppo 	/* compute mask for increment */
39021991Sheppo 	txq_size_mask = (ldcp->tx_q_entries - 1) << LDC_PACKET_SHIFT;
39031991Sheppo 
39041991Sheppo 	/* get the qptrs for the tx queue */
39051991Sheppo 	rv = hv_ldc_tx_get_state(ldcp->id,
39061991Sheppo 	    &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
39071991Sheppo 	if (rv != 0) {
39081991Sheppo 		cmn_err(CE_WARN,
39091991Sheppo 		    "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
39101991Sheppo 		*size = 0;
39111991Sheppo 		return (EIO);
39121991Sheppo 	}
39131991Sheppo 
39141991Sheppo 	if (ldcp->link_state == LDC_CHANNEL_DOWN ||
39151991Sheppo 	    ldcp->link_state == LDC_CHANNEL_RESET) {
39161991Sheppo 		DWARN(ldcp->id,
39171991Sheppo 		    "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
39181991Sheppo 		*size = 0;
39192336Snarayan 		if (mutex_tryenter(&ldcp->lock)) {
39202793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
39212336Snarayan 			mutex_exit(&ldcp->lock);
39222336Snarayan 		} else {
39232336Snarayan 			/*
39242336Snarayan 			 * Release Tx lock, and then reacquire channel
39252336Snarayan 			 * and Tx lock in correct order
39262336Snarayan 			 */
39272336Snarayan 			mutex_exit(&ldcp->tx_lock);
39282336Snarayan 			mutex_enter(&ldcp->lock);
39292336Snarayan 			mutex_enter(&ldcp->tx_lock);
39302793Slm66018 			i_ldc_reset(ldcp, B_FALSE);
39312336Snarayan 			mutex_exit(&ldcp->lock);
39322336Snarayan 		}
39331991Sheppo 		return (ECONNRESET);
39341991Sheppo 	}
39351991Sheppo 
39361991Sheppo 	tx_tail = ldcp->tx_tail;
39371991Sheppo 	new_tail = (tx_tail + LDC_PACKET_SIZE) %
39381991Sheppo 		(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
39391991Sheppo 
39401991Sheppo 	/*
39412410Slm66018 	 * Link mode determines whether we use HV Tx head or the
39421991Sheppo 	 * private protocol head (corresponding to last ACKd pkt) for
39431991Sheppo 	 * determining how much we can write
39441991Sheppo 	 */
39451991Sheppo 	tx_head = (ldcp->mode == LDC_MODE_RELIABLE ||
39461991Sheppo 		ldcp->mode == LDC_MODE_STREAM)
39471991Sheppo 		? ldcp->tx_ackd_head : ldcp->tx_head;
39481991Sheppo 	if (new_tail == tx_head) {
39491991Sheppo 		DWARN(DBG_ALL_LDCS,
39501991Sheppo 		    "ldc_write: (0x%llx) TX queue is full\n", ldcp->id);
39511991Sheppo 		*size = 0;
39521991Sheppo 		return (EWOULDBLOCK);
39531991Sheppo 	}
39541991Sheppo 
39551991Sheppo 	/*
39561991Sheppo 	 * Make sure that the LDC Tx queue has enough space
39571991Sheppo 	 */
39581991Sheppo 	numavail = (tx_head >> LDC_PACKET_SHIFT) - (tx_tail >> LDC_PACKET_SHIFT)
39591991Sheppo 		+ ldcp->tx_q_entries - 1;
39601991Sheppo 	numavail %= ldcp->tx_q_entries;
39611991Sheppo 
39621991Sheppo 	if (*size > (numavail * ldcp->pkt_payload)) {
39631991Sheppo 		DWARN(DBG_ALL_LDCS,
39641991Sheppo 		    "ldc_write: (0x%llx) TX queue has no space\n", ldcp->id);
39651991Sheppo 		return (EWOULDBLOCK);
39661991Sheppo 	}
39671991Sheppo 
39681991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
39691991Sheppo 	    ldcp->id, *size);
39701991Sheppo 
39711991Sheppo 	/* Send the data now */
39721991Sheppo 	bytes_written = 0;
39731991Sheppo 	curr_seqid = ldcp->last_msg_snt;
39741991Sheppo 	start = tx_tail;
39751991Sheppo 
39761991Sheppo 	while (*size > bytes_written) {
39771991Sheppo 
39781991Sheppo 		ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
39791991Sheppo 
39801991Sheppo 		msgbuf = (uint8_t *)((ldcp->mode == LDC_MODE_RELIABLE ||
39811991Sheppo 			ldcp->mode == LDC_MODE_STREAM)
39821991Sheppo 			? ldcmsg->rdata : ldcmsg->udata);
39831991Sheppo 
39841991Sheppo 		ldcmsg->type = LDC_DATA;
39851991Sheppo 		ldcmsg->stype = LDC_INFO;
39861991Sheppo 		ldcmsg->ctrl = 0;
39871991Sheppo 
39881991Sheppo 		remaining = *size - bytes_written;
39891991Sheppo 		len = min(ldcp->pkt_payload, remaining);
39901991Sheppo 		ldcmsg->env = (uint8_t)len;
39911991Sheppo 
39921991Sheppo 		curr_seqid++;
39931991Sheppo 		ldcmsg->seqid = curr_seqid;
39941991Sheppo 
39951991Sheppo 		/* copy the data into pkt */
39961991Sheppo 		bcopy(source, msgbuf, len);
39971991Sheppo 
39981991Sheppo 		source += len;
39991991Sheppo 		bytes_written += len;
40001991Sheppo 
40011991Sheppo 		/* increment tail */
40021991Sheppo 		tx_tail = (tx_tail + LDC_PACKET_SIZE) & txq_size_mask;
40031991Sheppo 
40041991Sheppo 		ASSERT(tx_tail != tx_head);
40051991Sheppo 	}
40061991Sheppo 
40071991Sheppo 	/* Set the start and stop bits */
40081991Sheppo 	ldcmsg->env |= LDC_FRAG_STOP;
40091991Sheppo 	ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + start);
40101991Sheppo 	ldcmsg->env |= LDC_FRAG_START;
40111991Sheppo 
40121991Sheppo 	/*
40131991Sheppo 	 * All packets have been copied into the TX queue
40141991Sheppo 	 * update the tail ptr in the HV
40151991Sheppo 	 */
40161991Sheppo 	rv = i_ldc_set_tx_tail(ldcp, tx_tail);
40171991Sheppo 	if (rv == 0) {
40181991Sheppo 		ldcp->tx_tail = tx_tail;
40191991Sheppo 		ldcp->last_msg_snt = curr_seqid;
40201991Sheppo 		*size = bytes_written;
40211991Sheppo 	} else {
40221991Sheppo 		int rv2;
40231991Sheppo 
40241991Sheppo 		if (rv != EWOULDBLOCK) {
40251991Sheppo 			*size = 0;
40262336Snarayan 			if (mutex_tryenter(&ldcp->lock)) {
40272793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
40282336Snarayan 				mutex_exit(&ldcp->lock);
40292336Snarayan 			} else {
40302336Snarayan 				/*
40312336Snarayan 				 * Release Tx lock, and then reacquire channel
40322336Snarayan 				 * and Tx lock in correct order
40332336Snarayan 				 */
40342336Snarayan 				mutex_exit(&ldcp->tx_lock);
40352336Snarayan 				mutex_enter(&ldcp->lock);
40362336Snarayan 				mutex_enter(&ldcp->tx_lock);
40372793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
40382336Snarayan 				mutex_exit(&ldcp->lock);
40392336Snarayan 			}
40401991Sheppo 			return (ECONNRESET);
40411991Sheppo 		}
40421991Sheppo 
40433010Slm66018 		D1(ldcp->id, "hv_tx_set_tail returns 0x%x (head 0x%x, "
40441991Sheppo 			"old tail 0x%x, new tail 0x%x, qsize=0x%x)\n",
40451991Sheppo 			rv, ldcp->tx_head, ldcp->tx_tail, tx_tail,
40461991Sheppo 			(ldcp->tx_q_entries << LDC_PACKET_SHIFT));
40471991Sheppo 
40481991Sheppo 		rv2 = hv_ldc_tx_get_state(ldcp->id,
40491991Sheppo 		    &tx_head, &tx_tail, &ldcp->link_state);
40501991Sheppo 
40513010Slm66018 		D1(ldcp->id, "hv_ldc_tx_get_state returns 0x%x "
40521991Sheppo 			"(head 0x%x, tail 0x%x state 0x%x)\n",
40531991Sheppo 			rv2, tx_head, tx_tail, ldcp->link_state);
40541991Sheppo 
40551991Sheppo 		*size = 0;
40561991Sheppo 	}
40571991Sheppo 
40581991Sheppo 	D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, *size);
40591991Sheppo 
40601991Sheppo 	return (rv);
40611991Sheppo }
40621991Sheppo 
40631991Sheppo /*
40641991Sheppo  * Write specified amount of bytes to the channel
40651991Sheppo  * in multiple pkts of pkt_payload size. Each
40661991Sheppo  * packet is tagged with an unique packet ID in
40672410Slm66018  * the case of a reliable link.
40681991Sheppo  *
40691991Sheppo  * On return, size contains the number of bytes written.
40701991Sheppo  * This function needs to ensure that the write size is < MTU size
40711991Sheppo  */
40721991Sheppo static int
40731991Sheppo i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
40741991Sheppo {
40752336Snarayan 	ASSERT(MUTEX_HELD(&ldcp->tx_lock));
40761991Sheppo 	ASSERT(ldcp->mode == LDC_MODE_STREAM);
40771991Sheppo 
40781991Sheppo 	/* Truncate packet to max of MTU size */
40791991Sheppo 	if (*sizep > ldcp->mtu) *sizep = ldcp->mtu;
40801991Sheppo 	return (i_ldc_write_packet(ldcp, buf, sizep));
40811991Sheppo }
40821991Sheppo 
40831991Sheppo 
40841991Sheppo /*
40851991Sheppo  * Interfaces for channel nexus to register/unregister with LDC module
40861991Sheppo  * The nexus will register functions to be used to register individual
40871991Sheppo  * channels with the nexus and enable interrupts for the channels
40881991Sheppo  */
40891991Sheppo int
40901991Sheppo ldc_register(ldc_cnex_t *cinfo)
40911991Sheppo {
40921991Sheppo 	ldc_chan_t	*ldcp;
40931991Sheppo 
40941991Sheppo 	if (cinfo == NULL || cinfo->dip == NULL ||
40951991Sheppo 	    cinfo->reg_chan == NULL || cinfo->unreg_chan == NULL ||
40961991Sheppo 	    cinfo->add_intr == NULL || cinfo->rem_intr == NULL ||
40971991Sheppo 	    cinfo->clr_intr == NULL) {
40981991Sheppo 
40991991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_register: invalid nexus info\n");
41001991Sheppo 		return (EINVAL);
41011991Sheppo 	}
41021991Sheppo 
41031991Sheppo 	mutex_enter(&ldcssp->lock);
41041991Sheppo 
41051991Sheppo 	/* nexus registration */
41061991Sheppo 	ldcssp->cinfo.dip = cinfo->dip;
41071991Sheppo 	ldcssp->cinfo.reg_chan = cinfo->reg_chan;
41081991Sheppo 	ldcssp->cinfo.unreg_chan = cinfo->unreg_chan;
41091991Sheppo 	ldcssp->cinfo.add_intr = cinfo->add_intr;
41101991Sheppo 	ldcssp->cinfo.rem_intr = cinfo->rem_intr;
41111991Sheppo 	ldcssp->cinfo.clr_intr = cinfo->clr_intr;
41121991Sheppo 
41131991Sheppo 	/* register any channels that might have been previously initialized */
41141991Sheppo 	ldcp = ldcssp->chan_list;
41151991Sheppo 	while (ldcp) {
41161991Sheppo 		if ((ldcp->tstate & TS_QCONF_RDY) &&
41171991Sheppo 		    (ldcp->tstate & TS_CNEX_RDY) == 0)
41181991Sheppo 			(void) i_ldc_register_channel(ldcp);
41191991Sheppo 
41201991Sheppo 		ldcp = ldcp->next;
41211991Sheppo 	}
41221991Sheppo 
41231991Sheppo 	mutex_exit(&ldcssp->lock);
41241991Sheppo 
41251991Sheppo 	return (0);
41261991Sheppo }
41271991Sheppo 
41281991Sheppo int
41291991Sheppo ldc_unregister(ldc_cnex_t *cinfo)
41301991Sheppo {
41311991Sheppo 	if (cinfo == NULL || cinfo->dip == NULL) {
41321991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid nexus info\n");
41331991Sheppo 		return (EINVAL);
41341991Sheppo 	}
41351991Sheppo 
41361991Sheppo 	mutex_enter(&ldcssp->lock);
41371991Sheppo 
41381991Sheppo 	if (cinfo->dip != ldcssp->cinfo.dip) {
41391991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid dip\n");
41401991Sheppo 		mutex_exit(&ldcssp->lock);
41411991Sheppo 		return (EINVAL);
41421991Sheppo 	}
41431991Sheppo 
41441991Sheppo 	/* nexus unregister */
41451991Sheppo 	ldcssp->cinfo.dip = NULL;
41461991Sheppo 	ldcssp->cinfo.reg_chan = NULL;
41471991Sheppo 	ldcssp->cinfo.unreg_chan = NULL;
41481991Sheppo 	ldcssp->cinfo.add_intr = NULL;
41491991Sheppo 	ldcssp->cinfo.rem_intr = NULL;
41501991Sheppo 	ldcssp->cinfo.clr_intr = NULL;
41511991Sheppo 
41521991Sheppo 	mutex_exit(&ldcssp->lock);
41531991Sheppo 
41541991Sheppo 	return (0);
41551991Sheppo }
41561991Sheppo 
41571991Sheppo 
41581991Sheppo /* ------------------------------------------------------------------------- */
41591991Sheppo 
41601991Sheppo /*
41611991Sheppo  * Allocate a memory handle for the channel and link it into the list
41621991Sheppo  * Also choose which memory table to use if this is the first handle
41631991Sheppo  * being assigned to this channel
41641991Sheppo  */
41651991Sheppo int
41661991Sheppo ldc_mem_alloc_handle(ldc_handle_t handle, ldc_mem_handle_t *mhandle)
41671991Sheppo {
41681991Sheppo 	ldc_chan_t 	*ldcp;
41691991Sheppo 	ldc_mhdl_t	*mhdl;
41701991Sheppo 
41711991Sheppo 	if (handle == NULL) {
41721991Sheppo 		DWARN(DBG_ALL_LDCS,
41731991Sheppo 		    "ldc_mem_alloc_handle: invalid channel handle\n");
41741991Sheppo 		return (EINVAL);
41751991Sheppo 	}
41761991Sheppo 	ldcp = (ldc_chan_t *)handle;
41771991Sheppo 
41781991Sheppo 	mutex_enter(&ldcp->lock);
41791991Sheppo 
41801991Sheppo 	/* check to see if channel is initalized */
41812793Slm66018 	if ((ldcp->tstate & ~TS_IN_RESET) < TS_INIT) {
41821991Sheppo 		DWARN(ldcp->id,
41831991Sheppo 		    "ldc_mem_alloc_handle: (0x%llx) channel not initialized\n",
41841991Sheppo 		    ldcp->id);
41851991Sheppo 		mutex_exit(&ldcp->lock);
41861991Sheppo 		return (EINVAL);
41871991Sheppo 	}
41881991Sheppo 
41891991Sheppo 	/* allocate handle for channel */
41902531Snarayan 	mhdl = kmem_cache_alloc(ldcssp->memhdl_cache, KM_SLEEP);
41911991Sheppo 
41921991Sheppo 	/* initialize the lock */
41931991Sheppo 	mutex_init(&mhdl->lock, NULL, MUTEX_DRIVER, NULL);
41941991Sheppo 
41952531Snarayan 	mhdl->myshadow = B_FALSE;
41962531Snarayan 	mhdl->memseg = NULL;
41972531Snarayan 	mhdl->ldcp = ldcp;
41981991Sheppo 	mhdl->status = LDC_UNBOUND;
41991991Sheppo 
42001991Sheppo 	/* insert memory handle (@ head) into list */
42011991Sheppo 	if (ldcp->mhdl_list == NULL) {
42021991Sheppo 		ldcp->mhdl_list = mhdl;
42031991Sheppo 		mhdl->next = NULL;
42041991Sheppo 	} else {
42051991Sheppo 		/* insert @ head */
42061991Sheppo 		mhdl->next = ldcp->mhdl_list;
42071991Sheppo 		ldcp->mhdl_list = mhdl;
42081991Sheppo 	}
42091991Sheppo 
42101991Sheppo 	/* return the handle */
42111991Sheppo 	*mhandle = (ldc_mem_handle_t)mhdl;
42121991Sheppo 
42131991Sheppo 	mutex_exit(&ldcp->lock);
42141991Sheppo 
42151991Sheppo 	D1(ldcp->id, "ldc_mem_alloc_handle: (0x%llx) allocated handle 0x%llx\n",
42161991Sheppo 	    ldcp->id, mhdl);
42171991Sheppo 
42181991Sheppo 	return (0);
42191991Sheppo }
42201991Sheppo 
42211991Sheppo /*
42221991Sheppo  * Free memory handle for the channel and unlink it from the list
42231991Sheppo  */
42241991Sheppo int
42251991Sheppo ldc_mem_free_handle(ldc_mem_handle_t mhandle)
42261991Sheppo {
42271991Sheppo 	ldc_mhdl_t 	*mhdl, *phdl;
42281991Sheppo 	ldc_chan_t 	*ldcp;
42291991Sheppo 
42301991Sheppo 	if (mhandle == NULL) {
42311991Sheppo 		DWARN(DBG_ALL_LDCS,
42321991Sheppo 		    "ldc_mem_free_handle: invalid memory handle\n");
42331991Sheppo 		return (EINVAL);
42341991Sheppo 	}
42351991Sheppo 	mhdl = (ldc_mhdl_t *)mhandle;
42361991Sheppo 
42371991Sheppo 	mutex_enter(&mhdl->lock);
42381991Sheppo 
42391991Sheppo 	ldcp = mhdl->ldcp;
42401991Sheppo 
42411991Sheppo 	if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED) {
42421991Sheppo 		DWARN(ldcp->id,
42431991Sheppo 		    "ldc_mem_free_handle: cannot free, 0x%llx hdl bound\n",
42441991Sheppo 		    mhdl);
42451991Sheppo 		mutex_exit(&mhdl->lock);
42461991Sheppo 		return (EINVAL);
42471991Sheppo 	}
42481991Sheppo 	mutex_exit(&mhdl->lock);
42491991Sheppo 
42501991Sheppo 	mutex_enter(&ldcp->mlist_lock);
42511991Sheppo 
42521991Sheppo 	phdl = ldcp->mhdl_list;
42531991Sheppo 
42541991Sheppo 	/* first handle */
42551991Sheppo 	if (phdl == mhdl) {
42561991Sheppo 		ldcp->mhdl_list = mhdl->next;
42571991Sheppo 		mutex_destroy(&mhdl->lock);
42582531Snarayan 		kmem_cache_free(ldcssp->memhdl_cache, mhdl);
42592531Snarayan 
42601991Sheppo 		D1(ldcp->id,
42611991Sheppo 		    "ldc_mem_free_handle: (0x%llx) freed handle 0x%llx\n",
42621991Sheppo 		    ldcp->id, mhdl);
42631991Sheppo 	} else {
42641991Sheppo 		/* walk the list - unlink and free */
42651991Sheppo 		while (phdl != NULL) {
42661991Sheppo 			if (phdl->next == mhdl) {
42671991Sheppo 				phdl->next = mhdl->next;
42681991Sheppo 				mutex_destroy(&mhdl->lock);
42692531Snarayan 				kmem_cache_free(ldcssp->memhdl_cache, mhdl);
42701991Sheppo 				D1(ldcp->id,
42711991Sheppo 				    "ldc_mem_free_handle: (0x%llx) freed "
42721991Sheppo 				    "handle 0x%llx\n", ldcp->id, mhdl);
42731991Sheppo 				break;
42741991Sheppo 			}
42751991Sheppo 			phdl = phdl->next;
42761991Sheppo 		}
42771991Sheppo 	}
42781991Sheppo 
42791991Sheppo 	if (phdl == NULL) {
42801991Sheppo 		DWARN(ldcp->id,
42811991Sheppo 		    "ldc_mem_free_handle: invalid handle 0x%llx\n", mhdl);
42821991Sheppo 		mutex_exit(&ldcp->mlist_lock);
42831991Sheppo 		return (EINVAL);
42841991Sheppo 	}
42851991Sheppo 
42861991Sheppo 	mutex_exit(&ldcp->mlist_lock);
42871991Sheppo 
42881991Sheppo 	return (0);
42891991Sheppo }
42901991Sheppo 
42911991Sheppo /*
42921991Sheppo  * Bind a memory handle to a virtual address.
42931991Sheppo  * The virtual address is converted to the corresponding real addresses.
42941991Sheppo  * Returns pointer to the first ldc_mem_cookie and the total number
42951991Sheppo  * of cookies for this virtual address. Other cookies can be obtained
42961991Sheppo  * using the ldc_mem_nextcookie() call. If the pages are stored in
42971991Sheppo  * consecutive locations in the table, a single cookie corresponding to
42981991Sheppo  * the first location is returned. The cookie size spans all the entries.
42991991Sheppo  *
43001991Sheppo  * If the VA corresponds to a page that is already being exported, reuse
43011991Sheppo  * the page and do not export it again. Bump the page's use count.
43021991Sheppo  */
43031991Sheppo int
43041991Sheppo ldc_mem_bind_handle(ldc_mem_handle_t mhandle, caddr_t vaddr, size_t len,
43051991Sheppo     uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount)
43061991Sheppo {
43071991Sheppo 	ldc_mhdl_t	*mhdl;
43081991Sheppo 	ldc_chan_t 	*ldcp;
43091991Sheppo 	ldc_mtbl_t	*mtbl;
43101991Sheppo 	ldc_memseg_t	*memseg;
43111991Sheppo 	ldc_mte_t	tmp_mte;
43121991Sheppo 	uint64_t	index, prev_index = 0;
43131991Sheppo 	int64_t		cookie_idx;
43141991Sheppo 	uintptr_t	raddr, ra_aligned;
43151991Sheppo 	uint64_t	psize, poffset, v_offset;
43161991Sheppo 	uint64_t	pg_shift, pg_size, pg_size_code, pg_mask;
43171991Sheppo 	pgcnt_t		npages;
43181991Sheppo 	caddr_t		v_align, addr;
43192531Snarayan 	int 		i, rv;
43201991Sheppo 
43211991Sheppo 	if (mhandle == NULL) {
43221991Sheppo 		DWARN(DBG_ALL_LDCS,
43231991Sheppo 		    "ldc_mem_bind_handle: invalid memory handle\n");
43241991Sheppo 		return (EINVAL);
43251991Sheppo 	}
43261991Sheppo 	mhdl = (ldc_mhdl_t *)mhandle;
43271991Sheppo 	ldcp = mhdl->ldcp;
43281991Sheppo 
43291991Sheppo 	/* clear count */
43301991Sheppo 	*ccount = 0;
43311991Sheppo 
43321991Sheppo 	mutex_enter(&mhdl->lock);
43331991Sheppo 
43341991Sheppo 	if (mhdl->status == LDC_BOUND || mhdl->memseg != NULL) {
43351991Sheppo 		DWARN(ldcp->id,
43361991Sheppo 		    "ldc_mem_bind_handle: (0x%x) handle already bound\n",
43371991Sheppo 		    mhandle);
43381991Sheppo 		mutex_exit(&mhdl->lock);
43391991Sheppo 		return (EINVAL);
43401991Sheppo 	}
43411991Sheppo 
43421991Sheppo 	/* Force address and size to be 8-byte aligned */
43431991Sheppo 	if ((((uintptr_t)vaddr | len) & 0x7) != 0) {
43441991Sheppo 		DWARN(ldcp->id,
43451991Sheppo 		    "ldc_mem_bind_handle: addr/size is not 8-byte aligned\n");
43461991Sheppo 		mutex_exit(&mhdl->lock);
43471991Sheppo 		return (EINVAL);
43481991Sheppo 	}
43491991Sheppo 
43502531Snarayan 	/*
43512531Snarayan 	 * If this channel is binding a memory handle for the
43522531Snarayan 	 * first time allocate it a memory map table and initialize it
43532531Snarayan 	 */
43542531Snarayan 	if ((mtbl = ldcp->mtbl) == NULL) {
43552531Snarayan 
43562531Snarayan 		mutex_enter(&ldcp->lock);
43572531Snarayan 
43582531Snarayan 		/* Allocate and initialize the map table structure */
43592531Snarayan 		mtbl = kmem_zalloc(sizeof (ldc_mtbl_t), KM_SLEEP);
43602531Snarayan 		mtbl->num_entries = mtbl->num_avail = ldc_maptable_entries;
43612531Snarayan 		mtbl->size = ldc_maptable_entries * sizeof (ldc_mte_slot_t);
43622531Snarayan 		mtbl->next_entry = NULL;
43632793Slm66018 		mtbl->contigmem = B_TRUE;
43642531Snarayan 
43652531Snarayan 		/* Allocate the table itself */
43662531Snarayan 		mtbl->table = (ldc_mte_slot_t *)
43672531Snarayan 			contig_mem_alloc_align(mtbl->size, MMU_PAGESIZE);
43682531Snarayan 		if (mtbl->table == NULL) {
43692793Slm66018 
43702793Slm66018 			/* allocate a page of memory using kmem_alloc */
43712793Slm66018 			mtbl->table = kmem_alloc(MMU_PAGESIZE, KM_SLEEP);
43722793Slm66018 			mtbl->size = MMU_PAGESIZE;
43732793Slm66018 			mtbl->contigmem = B_FALSE;
43742793Slm66018 			mtbl->num_entries = mtbl->num_avail =
43752793Slm66018 				mtbl->size / sizeof (ldc_mte_slot_t);
43762793Slm66018 			DWARN(ldcp->id,
43772793Slm66018 			    "ldc_mem_bind_handle: (0x%llx) reduced tbl size "
43782793Slm66018 			    "to %lx entries\n", ldcp->id, mtbl->num_entries);
43792531Snarayan 		}
43802531Snarayan 
43812531Snarayan 		/* zero out the memory */
43822531Snarayan 		bzero(mtbl->table, mtbl->size);
43832531Snarayan 
43842531Snarayan 		/* initialize the lock */
43852531Snarayan 		mutex_init(&mtbl->lock, NULL, MUTEX_DRIVER, NULL);
43862531Snarayan 
43872531Snarayan 		/* register table for this channel */
43882531Snarayan 		rv = hv_ldc_set_map_table(ldcp->id,
43892531Snarayan 		    va_to_pa(mtbl->table), mtbl->num_entries);
43902531Snarayan 		if (rv != 0) {
43912531Snarayan 			cmn_err(CE_WARN,
43922531Snarayan 			    "ldc_mem_bind_handle: (0x%lx) err %d mapping tbl",
43932531Snarayan 			    ldcp->id, rv);
43942793Slm66018 			if (mtbl->contigmem)
43952793Slm66018 				contig_mem_free(mtbl->table, mtbl->size);
43962793Slm66018 			else
43972793Slm66018 				kmem_free(mtbl->table, mtbl->size);
43982531Snarayan 			mutex_destroy(&mtbl->lock);
43992531Snarayan 			kmem_free(mtbl, sizeof (ldc_mtbl_t));
44002531Snarayan 			mutex_exit(&ldcp->lock);
44012531Snarayan 			mutex_exit(&mhdl->lock);
44022531Snarayan 			return (EIO);
44032531Snarayan 		}
44042531Snarayan 
44052531Snarayan 		ldcp->mtbl = mtbl;
44062531Snarayan 		mutex_exit(&ldcp->lock);
44072531Snarayan 
44082531Snarayan 		D1(ldcp->id,
44092531Snarayan 		    "ldc_mem_bind_handle: (0x%llx) alloc'd map table 0x%llx\n",
44102531Snarayan 		    ldcp->id, ldcp->mtbl->table);
44112531Snarayan 	}
44122531Snarayan 
44131991Sheppo 	/* FUTURE: get the page size, pgsz code, and shift */
44141991Sheppo 	pg_size = MMU_PAGESIZE;
44151991Sheppo 	pg_size_code = page_szc(pg_size);
44161991Sheppo 	pg_shift = page_get_shift(pg_size_code);
44171991Sheppo 	pg_mask = ~(pg_size - 1);
44181991Sheppo 
44191991Sheppo 	D1(ldcp->id, "ldc_mem_bind_handle: (0x%llx) binding "
44201991Sheppo 	    "va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n",
44211991Sheppo 	    ldcp->id, vaddr, pg_size, pg_size_code, pg_shift);
44221991Sheppo 
44231991Sheppo 	/* aligned VA and its offset */
44241991Sheppo 	v_align = (caddr_t)(((uintptr_t)vaddr) & ~(pg_size - 1));
44251991Sheppo 	v_offset = ((uintptr_t)vaddr) & (pg_size - 1);
44261991Sheppo 
44271991Sheppo 	npages = (len+v_offset)/pg_size;
44281991Sheppo 	npages = ((len+v_offset)%pg_size == 0) ? npages : npages+1;
44291991Sheppo 
44301991Sheppo 	D1(ldcp->id, "ldc_mem_bind_handle: binding "
44311991Sheppo 	    "(0x%llx) v=0x%llx,val=0x%llx,off=0x%x,pgs=0x%x\n",
44321991Sheppo 	    ldcp->id, vaddr, v_align, v_offset, npages);
44331991Sheppo 
44341991Sheppo 	/* lock the memory table - exclusive access to channel */
44351991Sheppo 	mutex_enter(&mtbl->lock);
44361991Sheppo 
44371991Sheppo 	if (npages > mtbl->num_avail) {
44382793Slm66018 		D1(ldcp->id, "ldc_mem_bind_handle: (0x%llx) no table entries\n",
44391991Sheppo 		    ldcp->id);
44401991Sheppo 		mutex_exit(&mtbl->lock);
44411991Sheppo 		mutex_exit(&mhdl->lock);
44421991Sheppo 		return (ENOMEM);
44431991Sheppo 	}
44441991Sheppo 
44451991Sheppo 	/* Allocate a memseg structure */
44462531Snarayan 	memseg = mhdl->memseg =
44472531Snarayan 		kmem_cache_alloc(ldcssp->memseg_cache, KM_SLEEP);
44481991Sheppo 
44491991Sheppo 	/* Allocate memory to store all pages and cookies */
44501991Sheppo 	memseg->pages = kmem_zalloc((sizeof (ldc_page_t) * npages), KM_SLEEP);
44511991Sheppo 	memseg->cookies =
44521991Sheppo 		kmem_zalloc((sizeof (ldc_mem_cookie_t) * npages), KM_SLEEP);
44531991Sheppo 
44541991Sheppo 	D2(ldcp->id, "ldc_mem_bind_handle: (0x%llx) processing 0x%llx pages\n",
44551991Sheppo 	    ldcp->id, npages);
44561991Sheppo 
44571991Sheppo 	addr = v_align;
44581991Sheppo 
44591991Sheppo 	/*
44602531Snarayan 	 * Check if direct shared memory map is enabled, if not change
44612531Snarayan 	 * the mapping type to include SHADOW_MAP.
44622531Snarayan 	 */
44632531Snarayan 	if (ldc_shmem_enabled == 0)
44642531Snarayan 		mtype = LDC_SHADOW_MAP;
44652531Snarayan 
44662531Snarayan 	/*
44671991Sheppo 	 * Table slots are used in a round-robin manner. The algorithm permits
44681991Sheppo 	 * inserting duplicate entries. Slots allocated earlier will typically
44691991Sheppo 	 * get freed before we get back to reusing the slot.Inserting duplicate
44701991Sheppo 	 * entries should be OK as we only lookup entries using the cookie addr
44711991Sheppo 	 * i.e. tbl index, during export, unexport and copy operation.
44721991Sheppo 	 *
44731991Sheppo 	 * One implementation what was tried was to search for a duplicate
44741991Sheppo 	 * page entry first and reuse it. The search overhead is very high and
44751991Sheppo 	 * in the vnet case dropped the perf by almost half, 50 to 24 mbps.
44761991Sheppo 	 * So it does make sense to avoid searching for duplicates.
44771991Sheppo 	 *
44781991Sheppo 	 * But during the process of searching for a free slot, if we find a
44791991Sheppo 	 * duplicate entry we will go ahead and use it, and bump its use count.
44801991Sheppo 	 */
44811991Sheppo 
44821991Sheppo 	/* index to start searching from */
44831991Sheppo 	index = mtbl->next_entry;
44841991Sheppo 	cookie_idx = -1;
44851991Sheppo 
44861991Sheppo 	tmp_mte.ll = 0;	/* initialise fields to 0 */
44871991Sheppo 
44881991Sheppo 	if (mtype & LDC_DIRECT_MAP) {
44891991Sheppo 		tmp_mte.mte_r = (perm & LDC_MEM_R) ? 1 : 0;
44901991Sheppo 		tmp_mte.mte_w = (perm & LDC_MEM_W) ? 1 : 0;
44911991Sheppo 		tmp_mte.mte_x = (perm & LDC_MEM_X) ? 1 : 0;
44921991Sheppo 	}
44931991Sheppo 
44941991Sheppo 	if (mtype & LDC_SHADOW_MAP) {
44951991Sheppo 		tmp_mte.mte_cr = (perm & LDC_MEM_R) ? 1 : 0;
44961991Sheppo 		tmp_mte.mte_cw = (perm & LDC_MEM_W) ? 1 : 0;
44971991Sheppo 	}
44981991Sheppo 
44991991Sheppo 	if (mtype & LDC_IO_MAP) {
45001991Sheppo 		tmp_mte.mte_ir = (perm & LDC_MEM_R) ? 1 : 0;
45011991Sheppo 		tmp_mte.mte_iw = (perm & LDC_MEM_W) ? 1 : 0;
45021991Sheppo 	}
45031991Sheppo 
45041991Sheppo 	D1(ldcp->id, "ldc_mem_bind_handle mte=0x%llx\n", tmp_mte.ll);
45051991Sheppo 
45061991Sheppo 	tmp_mte.mte_pgszc = pg_size_code;
45071991Sheppo 
45081991Sheppo 	/* initialize each mem table entry */
45091991Sheppo 	for (i = 0; i < npages; i++) {
45101991Sheppo 
45111991Sheppo 		/* check if slot is available in the table */
45121991Sheppo 		while (mtbl->table[index].entry.ll != 0) {
45131991Sheppo 
45141991Sheppo 			index = (index + 1) % mtbl->num_entries;
45151991Sheppo 
45161991Sheppo 			if (index == mtbl->next_entry) {
45171991Sheppo 				/* we have looped around */
45181991Sheppo 				DWARN(DBG_ALL_LDCS,
45191991Sheppo 				    "ldc_mem_bind_handle: (0x%llx) cannot find "
45201991Sheppo 				    "entry\n", ldcp->id);
45211991Sheppo 				*ccount = 0;
45221991Sheppo 
45231991Sheppo 				/* NOTE: free memory, remove previous entries */
45241991Sheppo 				/* this shouldnt happen as num_avail was ok */
45251991Sheppo 
45261991Sheppo 				mutex_exit(&mtbl->lock);
45271991Sheppo 				mutex_exit(&mhdl->lock);
45281991Sheppo 				return (ENOMEM);
45291991Sheppo 			}
45301991Sheppo 		}
45311991Sheppo 
45321991Sheppo 		/* get the real address */
45331991Sheppo 		raddr = va_to_pa((void *)addr);
45341991Sheppo 		ra_aligned = ((uintptr_t)raddr & pg_mask);
45351991Sheppo 
45361991Sheppo 		/* build the mte */
45371991Sheppo 		tmp_mte.mte_rpfn = ra_aligned >> pg_shift;
45381991Sheppo 
45391991Sheppo 		D1(ldcp->id, "ldc_mem_bind_handle mte=0x%llx\n", tmp_mte.ll);
45401991Sheppo 
45411991Sheppo 		/* update entry in table */
45421991Sheppo 		mtbl->table[index].entry = tmp_mte;
45431991Sheppo 
45441991Sheppo 		D2(ldcp->id, "ldc_mem_bind_handle: (0x%llx) stored MTE 0x%llx"
45451991Sheppo 		    " into loc 0x%llx\n", ldcp->id, tmp_mte.ll, index);
45461991Sheppo 
45471991Sheppo 		/* calculate the size and offset for this export range */
45481991Sheppo 		if (i == 0) {
45491991Sheppo 			/* first page */
45501991Sheppo 			psize = min((pg_size - v_offset), len);
45511991Sheppo 			poffset = v_offset;
45521991Sheppo 
45531991Sheppo 		} else if (i == (npages - 1)) {
45541991Sheppo 			/* last page */
45551991Sheppo 			psize =	(((uintptr_t)(vaddr + len)) &
45561991Sheppo 				    ((uint64_t)(pg_size-1)));
45571991Sheppo 			if (psize == 0)
45581991Sheppo 				psize = pg_size;
45591991Sheppo 			poffset = 0;
45601991Sheppo 
45611991Sheppo 		} else {
45621991Sheppo 			/* middle pages */
45631991Sheppo 			psize = pg_size;
45641991Sheppo 			poffset = 0;
45651991Sheppo 		}
45661991Sheppo 
45671991Sheppo 		/* store entry for this page */
45681991Sheppo 		memseg->pages[i].index = index;
45691991Sheppo 		memseg->pages[i].raddr = raddr;
45701991Sheppo 		memseg->pages[i].offset = poffset;
45711991Sheppo 		memseg->pages[i].size = psize;
45721991Sheppo 		memseg->pages[i].mte = &(mtbl->table[index]);
45731991Sheppo 
45741991Sheppo 		/* create the cookie */
45751991Sheppo 		if (i == 0 || (index != prev_index + 1)) {
45761991Sheppo 			cookie_idx++;
45771991Sheppo 			memseg->cookies[cookie_idx].addr =
45781991Sheppo 				IDX2COOKIE(index, pg_size_code, pg_shift);
45791991Sheppo 			memseg->cookies[cookie_idx].addr |= poffset;
45801991Sheppo 			memseg->cookies[cookie_idx].size = psize;
45811991Sheppo 
45821991Sheppo 		} else {
45831991Sheppo 			memseg->cookies[cookie_idx].size += psize;
45841991Sheppo 		}
45851991Sheppo 
45861991Sheppo 		D1(ldcp->id, "ldc_mem_bind_handle: bound "
45871991Sheppo 		    "(0x%llx) va=0x%llx, idx=0x%llx, "
45881991Sheppo 		    "ra=0x%llx(sz=0x%x,off=0x%x)\n",
45891991Sheppo 		    ldcp->id, addr, index, raddr, psize, poffset);
45901991Sheppo 
45911991Sheppo 		/* decrement number of available entries */
45921991Sheppo 		mtbl->num_avail--;
45931991Sheppo 
45941991Sheppo 		/* increment va by page size */
45951991Sheppo 		addr += pg_size;
45961991Sheppo 
45971991Sheppo 		/* increment index */
45981991Sheppo 		prev_index = index;
45991991Sheppo 		index = (index + 1) % mtbl->num_entries;
46001991Sheppo 
46011991Sheppo 		/* save the next slot */
46021991Sheppo 		mtbl->next_entry = index;
46031991Sheppo 	}
46041991Sheppo 
46051991Sheppo 	mutex_exit(&mtbl->lock);
46061991Sheppo 
46071991Sheppo 	/* memory handle = bound */
46081991Sheppo 	mhdl->mtype = mtype;
46091991Sheppo 	mhdl->perm = perm;
46101991Sheppo 	mhdl->status = LDC_BOUND;
46111991Sheppo 
46121991Sheppo 	/* update memseg_t */
46131991Sheppo 	memseg->vaddr = vaddr;
46141991Sheppo 	memseg->raddr = memseg->pages[0].raddr;
46151991Sheppo 	memseg->size = len;
46161991Sheppo 	memseg->npages = npages;
46171991Sheppo 	memseg->ncookies = cookie_idx + 1;
46181991Sheppo 	memseg->next_cookie = (memseg->ncookies > 1) ? 1 : 0;
46191991Sheppo 
46201991Sheppo 	/* return count and first cookie */
46211991Sheppo 	*ccount = memseg->ncookies;
46221991Sheppo 	cookie->addr = memseg->cookies[0].addr;
46231991Sheppo 	cookie->size = memseg->cookies[0].size;
46241991Sheppo 
46251991Sheppo 	D1(ldcp->id,
46261991Sheppo 	    "ldc_mem_bind_handle: (0x%llx) bound 0x%llx, va=0x%llx, "
46271991Sheppo 	    "pgs=0x%llx cookies=0x%llx\n",
46281991Sheppo 	    ldcp->id, mhdl, vaddr, npages, memseg->ncookies);
46291991Sheppo 
46301991Sheppo 	mutex_exit(&mhdl->lock);
46311991Sheppo 	return (0);
46321991Sheppo }
46331991Sheppo 
46341991Sheppo /*
46351991Sheppo  * Return the next cookie associated with the specified memory handle
46361991Sheppo  */
46371991Sheppo int
46381991Sheppo ldc_mem_nextcookie(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie)
46391991Sheppo {
46401991Sheppo 	ldc_mhdl_t	*mhdl;
46411991Sheppo 	ldc_chan_t 	*ldcp;
46421991Sheppo 	ldc_memseg_t	*memseg;
46431991Sheppo 
46441991Sheppo 	if (mhandle == NULL) {
46451991Sheppo 		DWARN(DBG_ALL_LDCS,
46461991Sheppo 		    "ldc_mem_nextcookie: invalid memory handle\n");
46471991Sheppo 		return (EINVAL);
46481991Sheppo 	}
46491991Sheppo 	mhdl = (ldc_mhdl_t *)mhandle;
46501991Sheppo 
46511991Sheppo 	mutex_enter(&mhdl->lock);
46521991Sheppo 
46531991Sheppo 	ldcp = mhdl->ldcp;
46541991Sheppo 	memseg = mhdl->memseg;
46551991Sheppo 
46561991Sheppo 	if (cookie == 0) {
46571991Sheppo 		DWARN(ldcp->id,
46581991Sheppo 		    "ldc_mem_nextcookie:(0x%llx) invalid cookie arg\n",
46591991Sheppo 		    ldcp->id);
46601991Sheppo 		mutex_exit(&mhdl->lock);
46611991Sheppo 		return (EINVAL);
46621991Sheppo 	}
46631991Sheppo 
46641991Sheppo 	if (memseg->next_cookie != 0) {
46651991Sheppo 		cookie->addr = memseg->cookies[memseg->next_cookie].addr;
46661991Sheppo 		cookie->size = memseg->cookies[memseg->next_cookie].size;
46671991Sheppo 		memseg->next_cookie++;
46681991Sheppo 		if (memseg->next_cookie == memseg->ncookies)
46691991Sheppo 			memseg->next_cookie = 0;
46701991Sheppo 
46711991Sheppo 	} else {
46721991Sheppo 		DWARN(ldcp->id,
46731991Sheppo 		    "ldc_mem_nextcookie:(0x%llx) no more cookies\n", ldcp->id);
46741991Sheppo 		cookie->addr = 0;
46751991Sheppo 		cookie->size = 0;
46761991Sheppo 		mutex_exit(&mhdl->lock);
46771991Sheppo 		return (EINVAL);
46781991Sheppo 	}
46791991Sheppo 
46801991Sheppo 	D1(ldcp->id,
46811991Sheppo 	    "ldc_mem_nextcookie: (0x%llx) cookie addr=0x%llx,sz=0x%llx\n",
46821991Sheppo 	    ldcp->id, cookie->addr, cookie->size);
46831991Sheppo 
46841991Sheppo 	mutex_exit(&mhdl->lock);
46851991Sheppo 	return (0);
46861991Sheppo }
46871991Sheppo 
46881991Sheppo /*
46891991Sheppo  * Unbind the virtual memory region associated with the specified
46901991Sheppo  * memory handle. Allassociated cookies are freed and the corresponding
46911991Sheppo  * RA space is no longer exported.
46921991Sheppo  */
46931991Sheppo int
46941991Sheppo ldc_mem_unbind_handle(ldc_mem_handle_t mhandle)
46951991Sheppo {
46961991Sheppo 	ldc_mhdl_t	*mhdl;
46971991Sheppo 	ldc_chan_t 	*ldcp;
46981991Sheppo 	ldc_mtbl_t	*mtbl;
46991991Sheppo 	ldc_memseg_t	*memseg;
47002531Snarayan 	uint64_t	cookie_addr;
47012531Snarayan 	uint64_t	pg_shift, pg_size_code;
47022531Snarayan 	int		i, rv;
47031991Sheppo 
47041991Sheppo 	if (mhandle == NULL) {
47051991Sheppo 		DWARN(DBG_ALL_LDCS,
47061991Sheppo 		    "ldc_mem_unbind_handle: invalid memory handle\n");
47071991Sheppo 		return (EINVAL);
47081991Sheppo 	}
47091991Sheppo 	mhdl = (ldc_mhdl_t *)mhandle;
47101991Sheppo 
47111991Sheppo 	mutex_enter(&mhdl->lock);
47121991Sheppo 
47131991Sheppo 	if (mhdl->status == LDC_UNBOUND) {
47141991Sheppo 		DWARN(DBG_ALL_LDCS,
47151991Sheppo 		    "ldc_mem_unbind_handle: (0x%x) handle is not bound\n",
47161991Sheppo 		    mhandle);
47171991Sheppo 		mutex_exit(&mhdl->lock);
47181991Sheppo 		return (EINVAL);
47191991Sheppo 	}
47201991Sheppo 
47211991Sheppo 	ldcp = mhdl->ldcp;
47221991Sheppo 	mtbl = ldcp->mtbl;
47231991Sheppo 
47241991Sheppo 	memseg = mhdl->memseg;
47251991Sheppo 
47261991Sheppo 	/* lock the memory table - exclusive access to channel */
47271991Sheppo 	mutex_enter(&mtbl->lock);
47281991Sheppo 
47291991Sheppo 	/* undo the pages exported */
47301991Sheppo 	for (i = 0; i < memseg->npages; i++) {
47311991Sheppo 
47322531Snarayan 		/* check for mapped pages, revocation cookie != 0 */
47331991Sheppo 		if (memseg->pages[i].mte->cookie) {
47342531Snarayan 
47352531Snarayan 			pg_size_code = page_szc(memseg->pages[i].size);
47362531Snarayan 			pg_shift = page_get_shift(memseg->pages[i].size);
47372531Snarayan 			cookie_addr = IDX2COOKIE(memseg->pages[i].index,
47382531Snarayan 			    pg_size_code, pg_shift);
47392531Snarayan 
47402531Snarayan 			D1(ldcp->id, "ldc_mem_unbind_handle: (0x%llx) revoke "
47412531Snarayan 			    "cookie 0x%llx, rcookie 0x%llx\n", ldcp->id,
47422531Snarayan 			    cookie_addr, memseg->pages[i].mte->cookie);
47432531Snarayan 			rv = hv_ldc_revoke(ldcp->id, cookie_addr,
47442531Snarayan 			    memseg->pages[i].mte->cookie);
47452531Snarayan 			if (rv) {
47462531Snarayan 				DWARN(ldcp->id,
47472531Snarayan 				    "ldc_mem_unbind_handle: (0x%llx) cannot "
47482531Snarayan 				    "revoke mapping, cookie %llx\n", ldcp->id,
47492531Snarayan 				    cookie_addr);
47502531Snarayan 			}
47511991Sheppo 		}
47521991Sheppo 
47531991Sheppo 		/* clear the entry from the table */
47541991Sheppo 		memseg->pages[i].mte->entry.ll = 0;
47551991Sheppo 		mtbl->num_avail++;
47561991Sheppo 	}
47571991Sheppo 	mutex_exit(&mtbl->lock);
47581991Sheppo 
47591991Sheppo 	/* free the allocated memseg and page structures */
47601991Sheppo 	kmem_free(memseg->pages, (sizeof (ldc_page_t) * memseg->npages));
47611991Sheppo 	kmem_free(memseg->cookies,
47621991Sheppo 	    (sizeof (ldc_mem_cookie_t) * memseg->npages));
47632531Snarayan 	kmem_cache_free(ldcssp->memseg_cache, memseg);
47641991Sheppo 
47651991Sheppo 	/* uninitialize the memory handle */
47661991Sheppo 	mhdl->memseg = NULL;
47671991Sheppo 	mhdl->status = LDC_UNBOUND;
47681991Sheppo 
47691991Sheppo 	D1(ldcp->id, "ldc_mem_unbind_handle: (0x%llx) unbound handle 0x%llx\n",
47701991Sheppo 	    ldcp->id, mhdl);
47711991Sheppo 
47721991Sheppo 	mutex_exit(&mhdl->lock);
47731991Sheppo 	return (0);
47741991Sheppo }
47751991Sheppo 
47761991Sheppo /*
47771991Sheppo  * Get information about the dring. The base address of the descriptor
47781991Sheppo  * ring along with the type and permission are returned back.
47791991Sheppo  */
47801991Sheppo int
47811991Sheppo ldc_mem_info(ldc_mem_handle_t mhandle, ldc_mem_info_t *minfo)
47821991Sheppo {
47831991Sheppo 	ldc_mhdl_t	*mhdl;
47841991Sheppo 
47851991Sheppo 	if (mhandle == NULL) {
47861991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_mem_info: invalid memory handle\n");
47871991Sheppo 		return (EINVAL);
47881991Sheppo 	}
47891991Sheppo 	mhdl = (ldc_mhdl_t *)mhandle;
47901991Sheppo 
47911991Sheppo 	if (minfo == NULL) {
47921991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_mem_info: invalid args\n");
47931991Sheppo 		return (EINVAL);
47941991Sheppo 	}
47951991Sheppo 
47961991Sheppo 	mutex_enter(&mhdl->lock);
47971991Sheppo 
47981991Sheppo 	minfo->status = mhdl->status;
47991991Sheppo 	if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED) {
48001991Sheppo 		minfo->vaddr = mhdl->memseg->vaddr;
48011991Sheppo 		minfo->raddr = mhdl->memseg->raddr;
48021991Sheppo 		minfo->mtype = mhdl->mtype;
48031991Sheppo 		minfo->perm = mhdl->perm;
48041991Sheppo 	}
48051991Sheppo 	mutex_exit(&mhdl->lock);
48061991Sheppo 
48071991Sheppo 	return (0);
48081991Sheppo }
48091991Sheppo 
48101991Sheppo /*
48111991Sheppo  * Copy data either from or to the client specified virtual address
48121991Sheppo  * space to or from the exported memory associated with the cookies.
48131991Sheppo  * The direction argument determines whether the data is read from or
48141991Sheppo  * written to exported memory.
48151991Sheppo  */
48161991Sheppo int
48171991Sheppo ldc_mem_copy(ldc_handle_t handle, caddr_t vaddr, uint64_t off, size_t *size,
48181991Sheppo     ldc_mem_cookie_t *cookies, uint32_t ccount, uint8_t direction)
48191991Sheppo {
48201991Sheppo 	ldc_chan_t 	*ldcp;
48211991Sheppo 	uint64_t	local_voff, local_valign;
48221991Sheppo 	uint64_t	cookie_addr, cookie_size;
48231991Sheppo 	uint64_t	pg_shift, pg_size, pg_size_code;
48241991Sheppo 	uint64_t 	export_caddr, export_poff, export_psize, export_size;
48251991Sheppo 	uint64_t	local_ra, local_poff, local_psize;
48261991Sheppo 	uint64_t	copy_size, copied_len = 0, total_bal = 0, idx = 0;
48271991Sheppo 	pgcnt_t		npages;
48281991Sheppo 	size_t		len = *size;
48291991Sheppo 	int 		i, rv = 0;
48301991Sheppo 
48312793Slm66018 	uint64_t	chid;
48322793Slm66018 
48331991Sheppo 	if (handle == NULL) {
48341991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_mem_copy: invalid channel handle\n");
48351991Sheppo 		return (EINVAL);
48361991Sheppo 	}
48371991Sheppo 	ldcp = (ldc_chan_t *)handle;
48382793Slm66018 	chid = ldcp->id;
48391991Sheppo 
48401991Sheppo 	/* check to see if channel is UP */
48411991Sheppo 	if (ldcp->tstate != TS_UP) {
48422793Slm66018 		DWARN(chid, "ldc_mem_copy: (0x%llx) channel is not UP\n",
48432793Slm66018 		    chid);
48442793Slm66018 		return (ECONNRESET);
48451991Sheppo 	}
48461991Sheppo 
48471991Sheppo 	/* Force address and size to be 8-byte aligned */
48481991Sheppo 	if ((((uintptr_t)vaddr | len) & 0x7) != 0) {
48492793Slm66018 		DWARN(chid,
48501991Sheppo 		    "ldc_mem_copy: addr/sz is not 8-byte aligned\n");
48511991Sheppo 		return (EINVAL);
48521991Sheppo 	}
48531991Sheppo 
48541991Sheppo 	/* Find the size of the exported memory */
48551991Sheppo 	export_size = 0;
48561991Sheppo 	for (i = 0; i < ccount; i++)
48571991Sheppo 		export_size += cookies[i].size;
48581991Sheppo 
48591991Sheppo 	/* check to see if offset is valid */
48601991Sheppo 	if (off > export_size) {
48612793Slm66018 		DWARN(chid,
48621991Sheppo 		    "ldc_mem_copy: (0x%llx) start offset > export mem size\n",
48632793Slm66018 		    chid);
48641991Sheppo 		return (EINVAL);
48651991Sheppo 	}
48661991Sheppo 
48671991Sheppo 	/*
48681991Sheppo 	 * Check to see if the export size is smaller than the size we
48691991Sheppo 	 * are requesting to copy - if so flag an error
48701991Sheppo 	 */
48711991Sheppo 	if ((export_size - off) < *size) {
48722793Slm66018 		DWARN(chid,
48731991Sheppo 		    "ldc_mem_copy: (0x%llx) copy size > export mem size\n",
48742793Slm66018 		    chid);
48751991Sheppo 		return (EINVAL);
48761991Sheppo 	}
48771991Sheppo 
48781991Sheppo 	total_bal = min(export_size, *size);
48791991Sheppo 
48801991Sheppo 	/* FUTURE: get the page size, pgsz code, and shift */
48811991Sheppo 	pg_size = MMU_PAGESIZE;
48821991Sheppo 	pg_size_code = page_szc(pg_size);
48831991Sheppo 	pg_shift = page_get_shift(pg_size_code);
48841991Sheppo 
48852793Slm66018 	D1(chid, "ldc_mem_copy: copying data "
48861991Sheppo 	    "(0x%llx) va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n",
48872793Slm66018 	    chid, vaddr, pg_size, pg_size_code, pg_shift);
48881991Sheppo 
48891991Sheppo 	/* aligned VA and its offset */
48901991Sheppo 	local_valign = (((uintptr_t)vaddr) & ~(pg_size - 1));
48911991Sheppo 	local_voff = ((uintptr_t)vaddr) & (pg_size - 1);
48921991Sheppo 
48931991Sheppo 	npages = (len+local_voff)/pg_size;
48941991Sheppo 	npages = ((len+local_voff)%pg_size == 0) ? npages : npages+1;
48951991Sheppo 
48962793Slm66018 	D1(chid,
48971991Sheppo 	    "ldc_mem_copy: (0x%llx) v=0x%llx,val=0x%llx,off=0x%x,pgs=0x%x\n",
48982793Slm66018 	    chid, vaddr, local_valign, local_voff, npages);
48991991Sheppo 
49001991Sheppo 	local_ra = va_to_pa((void *)local_valign);
49011991Sheppo 	local_poff = local_voff;
49021991Sheppo 	local_psize = min(len, (pg_size - local_voff));
49031991Sheppo 
49041991Sheppo 	len -= local_psize;
49051991Sheppo 
49061991Sheppo 	/*
49071991Sheppo 	 * find the first cookie in the list of cookies
49081991Sheppo 	 * if the offset passed in is not zero
49091991Sheppo 	 */
49101991Sheppo 	for (idx = 0; idx < ccount; idx++) {
49111991Sheppo 		cookie_size = cookies[idx].size;
49121991Sheppo 		if (off < cookie_size)
49131991Sheppo 			break;
49141991Sheppo 		off -= cookie_size;
49151991Sheppo 	}
49161991Sheppo 
49171991Sheppo 	cookie_addr = cookies[idx].addr + off;
49181991Sheppo 	cookie_size = cookies[idx].size - off;
49191991Sheppo 
49201991Sheppo 	export_caddr = cookie_addr & ~(pg_size - 1);
49211991Sheppo 	export_poff = cookie_addr & (pg_size - 1);
49221991Sheppo 	export_psize = min(cookie_size, (pg_size - export_poff));
49231991Sheppo 
49241991Sheppo 	for (;;) {
49251991Sheppo 
49261991Sheppo 		copy_size = min(export_psize, local_psize);
49271991Sheppo 
49282793Slm66018 		D1(chid,
49291991Sheppo 		    "ldc_mem_copy:(0x%llx) dir=0x%x, caddr=0x%llx,"
49301991Sheppo 		    " loc_ra=0x%llx, exp_poff=0x%llx, loc_poff=0x%llx,"
49311991Sheppo 		    " exp_psz=0x%llx, loc_psz=0x%llx, copy_sz=0x%llx,"
49321991Sheppo 		    " total_bal=0x%llx\n",
49332793Slm66018 		    chid, direction, export_caddr, local_ra, export_poff,
49341991Sheppo 		    local_poff, export_psize, local_psize, copy_size,
49351991Sheppo 		    total_bal);
49361991Sheppo 
49372793Slm66018 		rv = hv_ldc_copy(chid, direction,
49381991Sheppo 		    (export_caddr + export_poff), (local_ra + local_poff),
49391991Sheppo 		    copy_size, &copied_len);
49401991Sheppo 
49411991Sheppo 		if (rv != 0) {
49422793Slm66018 			int 		error = EIO;
49432793Slm66018 			uint64_t	rx_hd, rx_tl;
49442793Slm66018 
49452793Slm66018 			DWARN(chid,
49462793Slm66018 			    "ldc_mem_copy: (0x%llx) err %d during copy\n",
49472793Slm66018 			    (unsigned long long)chid, rv);
49482793Slm66018 			DWARN(chid,
49492793Slm66018 			    "ldc_mem_copy: (0x%llx) dir=0x%x, caddr=0x%lx, "
49502531Snarayan 			    "loc_ra=0x%lx, exp_poff=0x%lx, loc_poff=0x%lx,"
49512531Snarayan 			    " exp_psz=0x%lx, loc_psz=0x%lx, copy_sz=0x%lx,"
49522531Snarayan 			    " copied_len=0x%lx, total_bal=0x%lx\n",
49532793Slm66018 			    chid, direction, export_caddr, local_ra,
49541991Sheppo 			    export_poff, local_poff, export_psize, local_psize,
49551991Sheppo 			    copy_size, copied_len, total_bal);
49561991Sheppo 
49571991Sheppo 			*size = *size - total_bal;
49582793Slm66018 
49592793Slm66018 			/*
49602793Slm66018 			 * check if reason for copy error was due to
49612793Slm66018 			 * a channel reset. we need to grab the lock
49622793Slm66018 			 * just in case we have to do a reset.
49632793Slm66018 			 */
49642793Slm66018 			mutex_enter(&ldcp->lock);
49652793Slm66018 			mutex_enter(&ldcp->tx_lock);
49662793Slm66018 
49672793Slm66018 			rv = hv_ldc_rx_get_state(ldcp->id,
49682793Slm66018 			    &rx_hd, &rx_tl, &(ldcp->link_state));
49692793Slm66018 			if (ldcp->link_state == LDC_CHANNEL_DOWN ||
49702793Slm66018 			    ldcp->link_state == LDC_CHANNEL_RESET) {
49712793Slm66018 				i_ldc_reset(ldcp, B_FALSE);
49722793Slm66018 				error = ECONNRESET;
49732793Slm66018 			}
49742793Slm66018 
49752793Slm66018 			mutex_exit(&ldcp->tx_lock);
49761991Sheppo 			mutex_exit(&ldcp->lock);
49772793Slm66018 
49782793Slm66018 			return (error);
49791991Sheppo 		}
49801991Sheppo 
49811991Sheppo 		ASSERT(copied_len <= copy_size);
49821991Sheppo 
49832793Slm66018 		D2(chid, "ldc_mem_copy: copied=0x%llx\n", copied_len);
49841991Sheppo 		export_poff += copied_len;
49851991Sheppo 		local_poff += copied_len;
49861991Sheppo 		export_psize -= copied_len;
49871991Sheppo 		local_psize -= copied_len;
49881991Sheppo 		cookie_size -= copied_len;
49891991Sheppo 
49901991Sheppo 		total_bal -= copied_len;
49911991Sheppo 
49921991Sheppo 		if (copy_size != copied_len)
49931991Sheppo 			continue;
49941991Sheppo 
49951991Sheppo 		if (export_psize == 0 && total_bal != 0) {
49961991Sheppo 
49971991Sheppo 			if (cookie_size == 0) {
49981991Sheppo 				idx++;
49991991Sheppo 				cookie_addr = cookies[idx].addr;
50001991Sheppo 				cookie_size = cookies[idx].size;
50011991Sheppo 
50021991Sheppo 				export_caddr = cookie_addr & ~(pg_size - 1);
50031991Sheppo 				export_poff = cookie_addr & (pg_size - 1);
50041991Sheppo 				export_psize =
50051991Sheppo 					min(cookie_size, (pg_size-export_poff));
50061991Sheppo 			} else {
50071991Sheppo 				export_caddr += pg_size;
50081991Sheppo 				export_poff = 0;
50091991Sheppo 				export_psize = min(cookie_size, pg_size);
50101991Sheppo 			}
50111991Sheppo 		}
50121991Sheppo 
50131991Sheppo 		if (local_psize == 0 && total_bal != 0) {
50141991Sheppo 			local_valign += pg_size;
50151991Sheppo 			local_ra = va_to_pa((void *)local_valign);
50161991Sheppo 			local_poff = 0;
50171991Sheppo 			local_psize = min(pg_size, len);
50181991Sheppo 			len -= local_psize;
50191991Sheppo 		}
50201991Sheppo 
50211991Sheppo 		/* check if we are all done */
50221991Sheppo 		if (total_bal == 0)
50231991Sheppo 			break;
50241991Sheppo 	}
50251991Sheppo 
50262793Slm66018 
50272793Slm66018 	D1(chid,
50281991Sheppo 	    "ldc_mem_copy: (0x%llx) done copying sz=0x%llx\n",
50292793Slm66018 	    chid, *size);
50301991Sheppo 
50311991Sheppo 	return (0);
50321991Sheppo }
50331991Sheppo 
50341991Sheppo /*
50351991Sheppo  * Copy data either from or to the client specified virtual address
50361991Sheppo  * space to or from HV physical memory.
50371991Sheppo  *
50381991Sheppo  * The direction argument determines whether the data is read from or
50391991Sheppo  * written to HV memory. direction values are LDC_COPY_IN/OUT similar
50401991Sheppo  * to the ldc_mem_copy interface
50411991Sheppo  */
50421991Sheppo int
50432793Slm66018 ldc_mem_rdwr_cookie(ldc_handle_t handle, caddr_t vaddr, size_t *size,
50441991Sheppo     caddr_t paddr, uint8_t direction)
50451991Sheppo {
50461991Sheppo 	ldc_chan_t 	*ldcp;
50471991Sheppo 	uint64_t	local_voff, local_valign;
50481991Sheppo 	uint64_t	pg_shift, pg_size, pg_size_code;
50491991Sheppo 	uint64_t 	target_pa, target_poff, target_psize, target_size;
50501991Sheppo 	uint64_t	local_ra, local_poff, local_psize;
50511991Sheppo 	uint64_t	copy_size, copied_len = 0;
50521991Sheppo 	pgcnt_t		npages;
50531991Sheppo 	size_t		len = *size;
50541991Sheppo 	int 		rv = 0;
50551991Sheppo 
50561991Sheppo 	if (handle == NULL) {
50571991Sheppo 		DWARN(DBG_ALL_LDCS,
50582793Slm66018 		    "ldc_mem_rdwr_cookie: invalid channel handle\n");
50591991Sheppo 		return (EINVAL);
50601991Sheppo 	}
50611991Sheppo 	ldcp = (ldc_chan_t *)handle;
50621991Sheppo 
50631991Sheppo 	mutex_enter(&ldcp->lock);
50641991Sheppo 
50651991Sheppo 	/* check to see if channel is UP */
50661991Sheppo 	if (ldcp->tstate != TS_UP) {
50671991Sheppo 		DWARN(ldcp->id,
50682793Slm66018 		    "ldc_mem_rdwr_cookie: (0x%llx) channel is not UP\n",
50691991Sheppo 		    ldcp->id);
50701991Sheppo 		mutex_exit(&ldcp->lock);
50712793Slm66018 		return (ECONNRESET);
50721991Sheppo 	}
50731991Sheppo 
50741991Sheppo 	/* Force address and size to be 8-byte aligned */
50751991Sheppo 	if ((((uintptr_t)vaddr | len) & 0x7) != 0) {
50761991Sheppo 		DWARN(ldcp->id,
50772793Slm66018 		    "ldc_mem_rdwr_cookie: addr/size is not 8-byte aligned\n");
50781991Sheppo 		mutex_exit(&ldcp->lock);
50791991Sheppo 		return (EINVAL);
50801991Sheppo 	}
50811991Sheppo 
50821991Sheppo 	target_size = *size;
50831991Sheppo 
50841991Sheppo 	/* FUTURE: get the page size, pgsz code, and shift */
50851991Sheppo 	pg_size = MMU_PAGESIZE;
50861991Sheppo 	pg_size_code = page_szc(pg_size);
50871991Sheppo 	pg_shift = page_get_shift(pg_size_code);
50881991Sheppo 
50892793Slm66018 	D1(ldcp->id, "ldc_mem_rdwr_cookie: copying data "
50901991Sheppo 	    "(0x%llx) va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n",
50911991Sheppo 	    ldcp->id, vaddr, pg_size, pg_size_code, pg_shift);
50921991Sheppo 
50931991Sheppo 	/* aligned VA and its offset */
50941991Sheppo 	local_valign = ((uintptr_t)vaddr) & ~(pg_size - 1);
50951991Sheppo 	local_voff = ((uintptr_t)vaddr) & (pg_size - 1);
50961991Sheppo 
50971991Sheppo 	npages = (len + local_voff) / pg_size;
50981991Sheppo 	npages = ((len + local_voff) % pg_size == 0) ? npages : npages+1;
50991991Sheppo 
51002793Slm66018 	D1(ldcp->id, "ldc_mem_rdwr_cookie: (0x%llx) v=0x%llx, "
51012793Slm66018 	    "val=0x%llx,off=0x%x,pgs=0x%x\n",
51021991Sheppo 	    ldcp->id, vaddr, local_valign, local_voff, npages);
51031991Sheppo 
51041991Sheppo 	local_ra = va_to_pa((void *)local_valign);
51051991Sheppo 	local_poff = local_voff;
51061991Sheppo 	local_psize = min(len, (pg_size - local_voff));
51071991Sheppo 
51081991Sheppo 	len -= local_psize;
51091991Sheppo 
51101991Sheppo 	target_pa = ((uintptr_t)paddr) & ~(pg_size - 1);
51111991Sheppo 	target_poff = ((uintptr_t)paddr) & (pg_size - 1);
51121991Sheppo 	target_psize = pg_size - target_poff;
51131991Sheppo 
51141991Sheppo 	for (;;) {
51151991Sheppo 
51161991Sheppo 		copy_size = min(target_psize, local_psize);
51171991Sheppo 
51181991Sheppo 		D1(ldcp->id,
51192793Slm66018 		    "ldc_mem_rdwr_cookie: (0x%llx) dir=0x%x, tar_pa=0x%llx,"
51201991Sheppo 		    " loc_ra=0x%llx, tar_poff=0x%llx, loc_poff=0x%llx,"
51211991Sheppo 		    " tar_psz=0x%llx, loc_psz=0x%llx, copy_sz=0x%llx,"
51221991Sheppo 		    " total_bal=0x%llx\n",
51231991Sheppo 		    ldcp->id, direction, target_pa, local_ra, target_poff,
51241991Sheppo 		    local_poff, target_psize, local_psize, copy_size,
51251991Sheppo 		    target_size);
51261991Sheppo 
51271991Sheppo 		rv = hv_ldc_copy(ldcp->id, direction,
51281991Sheppo 		    (target_pa + target_poff), (local_ra + local_poff),
51291991Sheppo 		    copy_size, &copied_len);
51301991Sheppo 
51311991Sheppo 		if (rv != 0) {
51322793Slm66018 			DWARN(DBG_ALL_LDCS,
51332793Slm66018 			    "ldc_mem_rdwr_cookie: (0x%lx) err %d during copy\n",
51341991Sheppo 			    ldcp->id, rv);
51351991Sheppo 			DWARN(DBG_ALL_LDCS,
51362793Slm66018 			    "ldc_mem_rdwr_cookie: (0x%llx) dir=%lld, "
51372793Slm66018 			    "tar_pa=0x%llx, loc_ra=0x%llx, tar_poff=0x%llx, "
51382793Slm66018 			    "loc_poff=0x%llx, tar_psz=0x%llx, loc_psz=0x%llx, "
51392793Slm66018 			    "copy_sz=0x%llx, total_bal=0x%llx\n",
51401991Sheppo 			    ldcp->id, direction, target_pa, local_ra,
51411991Sheppo 			    target_poff, local_poff, target_psize, local_psize,
51421991Sheppo 			    copy_size, target_size);
51431991Sheppo 
51441991Sheppo 			*size = *size - target_size;
51451991Sheppo 			mutex_exit(&ldcp->lock);
51461991Sheppo 			return (i_ldc_h2v_error(rv));
51471991Sheppo 		}
51481991Sheppo 
51492793Slm66018 		D2(ldcp->id, "ldc_mem_rdwr_cookie: copied=0x%llx\n",
51502793Slm66018 		    copied_len);
51511991Sheppo 		target_poff += copied_len;
51521991Sheppo 		local_poff += copied_len;
51531991Sheppo 		target_psize -= copied_len;
51541991Sheppo 		local_psize -= copied_len;
51551991Sheppo 
51561991Sheppo 		target_size -= copied_len;
51571991Sheppo 
51581991Sheppo 		if (copy_size != copied_len)
51591991Sheppo 			continue;
51601991Sheppo 
51611991Sheppo 		if (target_psize == 0 && target_size != 0) {
51621991Sheppo 			target_pa += pg_size;
51631991Sheppo 			target_poff = 0;
51641991Sheppo 			target_psize = min(pg_size, target_size);
51651991Sheppo 		}
51661991Sheppo 
51671991Sheppo 		if (local_psize == 0 && target_size != 0) {
51681991Sheppo 			local_valign += pg_size;
51691991Sheppo 			local_ra = va_to_pa((void *)local_valign);
51701991Sheppo 			local_poff = 0;
51711991Sheppo 			local_psize = min(pg_size, len);
51721991Sheppo 			len -= local_psize;
51731991Sheppo 		}
51741991Sheppo 
51751991Sheppo 		/* check if we are all done */
51761991Sheppo 		if (target_size == 0)
51771991Sheppo 			break;
51781991Sheppo 	}
51791991Sheppo 
51801991Sheppo 	mutex_exit(&ldcp->lock);
51811991Sheppo 
51822793Slm66018 	D1(ldcp->id, "ldc_mem_rdwr_cookie: (0x%llx) done copying sz=0x%llx\n",
51831991Sheppo 	    ldcp->id, *size);
51841991Sheppo 
51851991Sheppo 	return (0);
51861991Sheppo }
51871991Sheppo 
51881991Sheppo /*
51891991Sheppo  * Map an exported memory segment into the local address space. If the
51901991Sheppo  * memory range was exported for direct map access, a HV call is made
51911991Sheppo  * to allocate a RA range. If the map is done via a shadow copy, local
51921991Sheppo  * shadow memory is allocated and the base VA is returned in 'vaddr'. If
51931991Sheppo  * the mapping is a direct map then the RA is returned in 'raddr'.
51941991Sheppo  */
51951991Sheppo int
51961991Sheppo ldc_mem_map(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie, uint32_t ccount,
51972531Snarayan     uint8_t mtype, uint8_t perm, caddr_t *vaddr, caddr_t *raddr)
51981991Sheppo {
51992531Snarayan 	int		i, j, idx, rv, retries;
52001991Sheppo 	ldc_chan_t 	*ldcp;
52011991Sheppo 	ldc_mhdl_t	*mhdl;
52021991Sheppo 	ldc_memseg_t	*memseg;
52032531Snarayan 	caddr_t		tmpaddr;
52042531Snarayan 	uint64_t	map_perm = perm;
52052531Snarayan 	uint64_t	pg_size, pg_shift, pg_size_code, pg_mask;
52062531Snarayan 	uint64_t	exp_size = 0, base_off, map_size, npages;
52072531Snarayan 	uint64_t	cookie_addr, cookie_off, cookie_size;
52082531Snarayan 	tte_t		ldc_tte;
52091991Sheppo 
52101991Sheppo 	if (mhandle == NULL) {
52111991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_mem_map: invalid memory handle\n");
52121991Sheppo 		return (EINVAL);
52131991Sheppo 	}
52141991Sheppo 	mhdl = (ldc_mhdl_t *)mhandle;
52151991Sheppo 
52161991Sheppo 	mutex_enter(&mhdl->lock);
52171991Sheppo 
52181991Sheppo 	if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED ||
52191991Sheppo 	    mhdl->memseg != NULL) {
52201991Sheppo 		DWARN(DBG_ALL_LDCS,
52211991Sheppo 		    "ldc_mem_map: (0x%llx) handle bound/mapped\n", mhandle);
52221991Sheppo 		mutex_exit(&mhdl->lock);
52231991Sheppo 		return (EINVAL);
52241991Sheppo 	}
52251991Sheppo 
52261991Sheppo 	ldcp = mhdl->ldcp;
52271991Sheppo 
52281991Sheppo 	mutex_enter(&ldcp->lock);
52291991Sheppo 
52301991Sheppo 	if (ldcp->tstate != TS_UP) {
52311991Sheppo 		DWARN(ldcp->id,
52321991Sheppo 		    "ldc_mem_dring_map: (0x%llx) channel is not UP\n",
52331991Sheppo 		    ldcp->id);
52341991Sheppo 		mutex_exit(&ldcp->lock);
52351991Sheppo 		mutex_exit(&mhdl->lock);
52362793Slm66018 		return (ECONNRESET);
52371991Sheppo 	}
52381991Sheppo 
52391991Sheppo 	if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP|LDC_IO_MAP)) == 0) {
52401991Sheppo 		DWARN(ldcp->id, "ldc_mem_map: invalid map type\n");
52411991Sheppo 		mutex_exit(&ldcp->lock);
52421991Sheppo 		mutex_exit(&mhdl->lock);
52431991Sheppo 		return (EINVAL);
52441991Sheppo 	}
52451991Sheppo 
52461991Sheppo 	D1(ldcp->id, "ldc_mem_map: (0x%llx) cookie = 0x%llx,0x%llx\n",
52472336Snarayan 	    ldcp->id, cookie->addr, cookie->size);
52481991Sheppo 
52491991Sheppo 	/* FUTURE: get the page size, pgsz code, and shift */
52501991Sheppo 	pg_size = MMU_PAGESIZE;
52511991Sheppo 	pg_size_code = page_szc(pg_size);
52521991Sheppo 	pg_shift = page_get_shift(pg_size_code);
52532531Snarayan 	pg_mask = ~(pg_size - 1);
52541991Sheppo 
52551991Sheppo 	/* calculate the number of pages in the exported cookie */
52562531Snarayan 	base_off = cookie[0].addr & (pg_size - 1);
52572531Snarayan 	for (idx = 0; idx < ccount; idx++)
52581991Sheppo 		exp_size += cookie[idx].size;
52592531Snarayan 	map_size = P2ROUNDUP((exp_size + base_off), pg_size);
52602531Snarayan 	npages = (map_size >> pg_shift);
52611991Sheppo 
52621991Sheppo 	/* Allocate memseg structure */
52632531Snarayan 	memseg = mhdl->memseg =
52642531Snarayan 		kmem_cache_alloc(ldcssp->memseg_cache, KM_SLEEP);
52651991Sheppo 
52661991Sheppo 	/* Allocate memory to store all pages and cookies */
52671991Sheppo 	memseg->pages =	kmem_zalloc((sizeof (ldc_page_t) * npages), KM_SLEEP);
52681991Sheppo 	memseg->cookies =
52691991Sheppo 		kmem_zalloc((sizeof (ldc_mem_cookie_t) * ccount), KM_SLEEP);
52701991Sheppo 
52712531Snarayan 	D2(ldcp->id, "ldc_mem_map: (0x%llx) exp_size=0x%llx, map_size=0x%llx,"
52722531Snarayan 	    "pages=0x%llx\n", ldcp->id, exp_size, map_size, npages);
52732531Snarayan 
52742531Snarayan 	/*
52752531Snarayan 	 * Check if direct map over shared memory is enabled, if not change
52762531Snarayan 	 * the mapping type to SHADOW_MAP.
52772531Snarayan 	 */
52782531Snarayan 	if (ldc_shmem_enabled == 0)
52792531Snarayan 		mtype = LDC_SHADOW_MAP;
52802531Snarayan 
52812531Snarayan 	/*
52822531Snarayan 	 * Check to see if the client is requesting direct or shadow map
52832531Snarayan 	 * If direct map is requested, try to map remote memory first,
52842531Snarayan 	 * and if that fails, revert to shadow map
52852531Snarayan 	 */
52862531Snarayan 	if (mtype == LDC_DIRECT_MAP) {
52872531Snarayan 
52882531Snarayan 		/* Allocate kernel virtual space for mapping */
52892531Snarayan 		memseg->vaddr = vmem_xalloc(heap_arena, map_size,
52902531Snarayan 		    pg_size, 0, 0, NULL, NULL, VM_NOSLEEP);
52912531Snarayan 		if (memseg->vaddr == NULL) {
52922531Snarayan 			cmn_err(CE_WARN,
52932531Snarayan 			    "ldc_mem_map: (0x%lx) memory map failed\n",
52942531Snarayan 			    ldcp->id);
52952531Snarayan 			kmem_free(memseg->cookies,
52962531Snarayan 			    (sizeof (ldc_mem_cookie_t) * ccount));
52972531Snarayan 			kmem_free(memseg->pages,
52982531Snarayan 			    (sizeof (ldc_page_t) * npages));
52992531Snarayan 			kmem_cache_free(ldcssp->memseg_cache, memseg);
53002531Snarayan 
53012531Snarayan 			mutex_exit(&ldcp->lock);
53022531Snarayan 			mutex_exit(&mhdl->lock);
53032531Snarayan 			return (ENOMEM);
53042531Snarayan 		}
53052531Snarayan 
53062531Snarayan 		/* Unload previous mapping */
53072531Snarayan 		hat_unload(kas.a_hat, memseg->vaddr, map_size,
53082531Snarayan 		    HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK);
53092531Snarayan 
53102531Snarayan 		/* for each cookie passed in - map into address space */
53112531Snarayan 		idx = 0;
53122531Snarayan 		cookie_size = 0;
53132531Snarayan 		tmpaddr = memseg->vaddr;
53142531Snarayan 
53152531Snarayan 		for (i = 0; i < npages; i++) {
53162531Snarayan 
53172531Snarayan 			if (cookie_size == 0) {
53182531Snarayan 				ASSERT(idx < ccount);
53192531Snarayan 				cookie_addr = cookie[idx].addr & pg_mask;
53202531Snarayan 				cookie_off = cookie[idx].addr & (pg_size - 1);
53212531Snarayan 				cookie_size =
53222531Snarayan 				    P2ROUNDUP((cookie_off + cookie[idx].size),
53232531Snarayan 					pg_size);
53242531Snarayan 				idx++;
53252531Snarayan 			}
53262531Snarayan 
53272531Snarayan 			D1(ldcp->id, "ldc_mem_map: (0x%llx) mapping "
53282531Snarayan 			    "cookie 0x%llx, bal=0x%llx\n", ldcp->id,
53292531Snarayan 			    cookie_addr, cookie_size);
53302531Snarayan 
53312531Snarayan 			/* map the cookie into address space */
53322531Snarayan 			for (retries = 0; retries < ldc_max_retries;
53332531Snarayan 			    retries++) {
53342531Snarayan 
53352531Snarayan 				rv = hv_ldc_mapin(ldcp->id, cookie_addr,
53362531Snarayan 				    &memseg->pages[i].raddr, &map_perm);
53372531Snarayan 				if (rv != H_EWOULDBLOCK && rv != H_ETOOMANY)
53382531Snarayan 					break;
53392531Snarayan 
53402531Snarayan 				drv_usecwait(ldc_delay);
53412531Snarayan 			}
53422531Snarayan 
53432531Snarayan 			if (rv || memseg->pages[i].raddr == 0) {
53442531Snarayan 				DWARN(ldcp->id,
53452531Snarayan 				    "ldc_mem_map: (0x%llx) hv mapin err %d\n",
53462531Snarayan 				    ldcp->id, rv);
53472531Snarayan 
53482531Snarayan 				/* remove previous mapins */
53492531Snarayan 				hat_unload(kas.a_hat, memseg->vaddr, map_size,
53502531Snarayan 				    HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK);
53512531Snarayan 				for (j = 0; j < i; j++) {
53522531Snarayan 					rv = hv_ldc_unmap(
53532531Snarayan 							memseg->pages[j].raddr);
53542531Snarayan 					if (rv) {
53552531Snarayan 						DWARN(ldcp->id,
53562531Snarayan 						    "ldc_mem_map: (0x%llx) "
53572531Snarayan 						    "cannot unmap ra=0x%llx\n",
53582531Snarayan 					    ldcp->id,
53592531Snarayan 						    memseg->pages[j].raddr);
53602531Snarayan 					}
53612531Snarayan 				}
53622531Snarayan 
53632531Snarayan 				/* free kernel virtual space */
53642531Snarayan 				vmem_free(heap_arena, (void *)memseg->vaddr,
53652748Slm66018 				    map_size);
53662531Snarayan 
53672531Snarayan 				/* direct map failed - revert to shadow map */
53682531Snarayan 				mtype = LDC_SHADOW_MAP;
53692531Snarayan 				break;
53702531Snarayan 
53712531Snarayan 			} else {
53722531Snarayan 
53732531Snarayan 				D1(ldcp->id,
53742531Snarayan 				    "ldc_mem_map: (0x%llx) vtop map 0x%llx -> "
53752531Snarayan 				    "0x%llx, cookie=0x%llx, perm=0x%llx\n",
53762531Snarayan 				    ldcp->id, tmpaddr, memseg->pages[i].raddr,
53772531Snarayan 				    cookie_addr, perm);
53782531Snarayan 
53792531Snarayan 				/*
53802531Snarayan 				 * NOTE: Calling hat_devload directly, causes it
53812531Snarayan 				 * to look for page_t using the pfn. Since this
53822531Snarayan 				 * addr is greater than the memlist, it treates
53832531Snarayan 				 * it as non-memory
53842531Snarayan 				 */
53852531Snarayan 				sfmmu_memtte(&ldc_tte,
53862531Snarayan 				    (pfn_t)(memseg->pages[i].raddr >> pg_shift),
53872531Snarayan 				    PROT_READ | PROT_WRITE | HAT_NOSYNC, TTE8K);
53882531Snarayan 
53892531Snarayan 				D1(ldcp->id,
53902531Snarayan 				    "ldc_mem_map: (0x%llx) ra 0x%llx -> "
53912531Snarayan 				    "tte 0x%llx\n", ldcp->id,
53922531Snarayan 				    memseg->pages[i].raddr, ldc_tte);
53932531Snarayan 
53942531Snarayan 				sfmmu_tteload(kas.a_hat, &ldc_tte, tmpaddr,
53952531Snarayan 				    NULL, HAT_LOAD_LOCK);
53962531Snarayan 
53972531Snarayan 				cookie_size -= pg_size;
53982531Snarayan 				cookie_addr += pg_size;
53992531Snarayan 				tmpaddr += pg_size;
54002531Snarayan 			}
54012531Snarayan 		}
54022531Snarayan 	}
54032531Snarayan 
54041991Sheppo 	if (mtype == LDC_SHADOW_MAP) {
54051991Sheppo 		if (*vaddr == NULL) {
54062793Slm66018 			memseg->vaddr = kmem_zalloc(exp_size, KM_SLEEP);
54071991Sheppo 			mhdl->myshadow = B_TRUE;
54081991Sheppo 
54091991Sheppo 			D1(ldcp->id, "ldc_mem_map: (0x%llx) allocated "
54102531Snarayan 			    "shadow page va=0x%llx\n", ldcp->id, memseg->vaddr);
54111991Sheppo 		} else {
54121991Sheppo 			/*
54132531Snarayan 			 * Use client supplied memory for memseg->vaddr
54141991Sheppo 			 * WARNING: assuming that client mem is >= exp_size
54151991Sheppo 			 */
54162531Snarayan 			memseg->vaddr = *vaddr;
54171991Sheppo 		}
54182531Snarayan 
54192531Snarayan 		/* Save all page and cookie information */
54202531Snarayan 		for (i = 0, tmpaddr = memseg->vaddr; i < npages; i++) {
54212531Snarayan 			memseg->pages[i].raddr = va_to_pa(tmpaddr);
54222531Snarayan 			memseg->pages[i].size = pg_size;
54232531Snarayan 			tmpaddr += pg_size;
54242531Snarayan 		}
54252531Snarayan 
54262531Snarayan 	}
54272531Snarayan 
54282531Snarayan 	/* save all cookies */
54292531Snarayan 	bcopy(cookie, memseg->cookies, ccount * sizeof (ldc_mem_cookie_t));
54301991Sheppo 
54311991Sheppo 	/* update memseg_t */
54321991Sheppo 	memseg->raddr = memseg->pages[0].raddr;
54332531Snarayan 	memseg->size = (mtype == LDC_SHADOW_MAP) ? exp_size : map_size;
54341991Sheppo 	memseg->npages = npages;
54351991Sheppo 	memseg->ncookies = ccount;
54361991Sheppo 	memseg->next_cookie = 0;
54371991Sheppo 
54381991Sheppo 	/* memory handle = mapped */
54391991Sheppo 	mhdl->mtype = mtype;
54402531Snarayan 	mhdl->perm = perm;
54411991Sheppo 	mhdl->status = LDC_MAPPED;
54421991Sheppo 
54431991Sheppo 	D1(ldcp->id, "ldc_mem_map: (0x%llx) mapped 0x%llx, ra=0x%llx, "
54441991Sheppo 	    "va=0x%llx, pgs=0x%llx cookies=0x%llx\n",
54451991Sheppo 	    ldcp->id, mhdl, memseg->raddr, memseg->vaddr,
54461991Sheppo 	    memseg->npages, memseg->ncookies);
54471991Sheppo 
54482531Snarayan 	if (mtype == LDC_SHADOW_MAP)
54492531Snarayan 		base_off = 0;
54501991Sheppo 	if (raddr)
54512531Snarayan 		*raddr = (caddr_t)(memseg->raddr | base_off);
54521991Sheppo 	if (vaddr)
54532531Snarayan 		*vaddr = (caddr_t)((uintptr_t)memseg->vaddr | base_off);
54541991Sheppo 
54551991Sheppo 	mutex_exit(&ldcp->lock);
54561991Sheppo 	mutex_exit(&mhdl->lock);
54571991Sheppo 	return (0);
54581991Sheppo }
54591991Sheppo 
54601991Sheppo /*
54611991Sheppo  * Unmap a memory segment. Free shadow memory (if any).
54621991Sheppo  */
54631991Sheppo int
54641991Sheppo ldc_mem_unmap(ldc_mem_handle_t mhandle)
54651991Sheppo {
54662531Snarayan 	int		i, rv;
54671991Sheppo 	ldc_mhdl_t	*mhdl = (ldc_mhdl_t *)mhandle;
54681991Sheppo 	ldc_chan_t 	*ldcp;
54691991Sheppo 	ldc_memseg_t	*memseg;
54701991Sheppo 
54711991Sheppo 	if (mhdl == 0 || mhdl->status != LDC_MAPPED) {
54721991Sheppo 		DWARN(DBG_ALL_LDCS,
54731991Sheppo 		    "ldc_mem_unmap: (0x%llx) handle is not mapped\n",
54741991Sheppo 		    mhandle);
54751991Sheppo 		return (EINVAL);
54761991Sheppo 	}
54771991Sheppo 
54781991Sheppo 	mutex_enter(&mhdl->lock);
54791991Sheppo 
54801991Sheppo 	ldcp = mhdl->ldcp;
54811991Sheppo 	memseg = mhdl->memseg;
54821991Sheppo 
54831991Sheppo 	D1(ldcp->id, "ldc_mem_unmap: (0x%llx) unmapping handle 0x%llx\n",
54841991Sheppo 	    ldcp->id, mhdl);
54851991Sheppo 
54861991Sheppo 	/* if we allocated shadow memory - free it */
54871991Sheppo 	if (mhdl->mtype == LDC_SHADOW_MAP && mhdl->myshadow) {
54882793Slm66018 		kmem_free(memseg->vaddr, memseg->size);
54892531Snarayan 	} else if (mhdl->mtype == LDC_DIRECT_MAP) {
54902531Snarayan 
54912531Snarayan 		/* unmap in the case of DIRECT_MAP */
54922531Snarayan 		hat_unload(kas.a_hat, memseg->vaddr, memseg->size,
54932531Snarayan 		    HAT_UNLOAD_UNLOCK);
54942531Snarayan 
54952531Snarayan 		for (i = 0; i < memseg->npages; i++) {
54962531Snarayan 			rv = hv_ldc_unmap(memseg->pages[i].raddr);
54972531Snarayan 			if (rv) {
54982531Snarayan 				cmn_err(CE_WARN,
54992531Snarayan 				    "ldc_mem_map: (0x%lx) hv unmap err %d\n",
55002531Snarayan 				    ldcp->id, rv);
55012531Snarayan 			}
55022531Snarayan 		}
55032531Snarayan 
55042531Snarayan 		vmem_free(heap_arena, (void *)memseg->vaddr, memseg->size);
55051991Sheppo 	}
55061991Sheppo 
55071991Sheppo 	/* free the allocated memseg and page structures */
55081991Sheppo 	kmem_free(memseg->pages, (sizeof (ldc_page_t) * memseg->npages));
55091991Sheppo 	kmem_free(memseg->cookies,
55101991Sheppo 	    (sizeof (ldc_mem_cookie_t) * memseg->ncookies));
55112531Snarayan 	kmem_cache_free(ldcssp->memseg_cache, memseg);
55121991Sheppo 
55131991Sheppo 	/* uninitialize the memory handle */
55141991Sheppo 	mhdl->memseg = NULL;
55151991Sheppo 	mhdl->status = LDC_UNBOUND;
55161991Sheppo 
55171991Sheppo 	D1(ldcp->id, "ldc_mem_unmap: (0x%llx) unmapped handle 0x%llx\n",
55181991Sheppo 	    ldcp->id, mhdl);
55191991Sheppo 
55201991Sheppo 	mutex_exit(&mhdl->lock);
55211991Sheppo 	return (0);
55221991Sheppo }
55231991Sheppo 
55241991Sheppo /*
55251991Sheppo  * Internal entry point for LDC mapped memory entry consistency
55261991Sheppo  * semantics. Acquire copies the contents of the remote memory
55271991Sheppo  * into the local shadow copy. The release operation copies the local
55281991Sheppo  * contents into the remote memory. The offset and size specify the
55291991Sheppo  * bounds for the memory range being synchronized.
55301991Sheppo  */
55311991Sheppo static int
55321991Sheppo i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle, uint8_t direction,
55331991Sheppo     uint64_t offset, size_t size)
55341991Sheppo {
55351991Sheppo 	int 		err;
55361991Sheppo 	ldc_mhdl_t	*mhdl;
55371991Sheppo 	ldc_chan_t	*ldcp;
55381991Sheppo 	ldc_memseg_t	*memseg;
55391991Sheppo 	caddr_t		local_vaddr;
55401991Sheppo 	size_t		copy_size;
55411991Sheppo 
55421991Sheppo 	if (mhandle == NULL) {
55431991Sheppo 		DWARN(DBG_ALL_LDCS,
55441991Sheppo 		    "i_ldc_mem_acquire_release: invalid memory handle\n");
55451991Sheppo 		return (EINVAL);
55461991Sheppo 	}
55471991Sheppo 	mhdl = (ldc_mhdl_t *)mhandle;
55481991Sheppo 
55491991Sheppo 	mutex_enter(&mhdl->lock);
55501991Sheppo 
55511991Sheppo 	if (mhdl->status != LDC_MAPPED || mhdl->ldcp == NULL) {
55521991Sheppo 		DWARN(DBG_ALL_LDCS,
55531991Sheppo 		    "i_ldc_mem_acquire_release: not mapped memory\n");
55541991Sheppo 		mutex_exit(&mhdl->lock);
55551991Sheppo 		return (EINVAL);
55561991Sheppo 	}
55571991Sheppo 
55582531Snarayan 	/* do nothing for direct map */
55592531Snarayan 	if (mhdl->mtype == LDC_DIRECT_MAP) {
55602531Snarayan 		mutex_exit(&mhdl->lock);
55612531Snarayan 		return (0);
55622531Snarayan 	}
55632531Snarayan 
55642531Snarayan 	/* do nothing if COPY_IN+MEM_W and COPY_OUT+MEM_R */
55652531Snarayan 	if ((direction == LDC_COPY_IN && (mhdl->perm & LDC_MEM_R) == 0) ||
55662531Snarayan 	    (direction == LDC_COPY_OUT && (mhdl->perm & LDC_MEM_W) == 0)) {
55672531Snarayan 		mutex_exit(&mhdl->lock);
55682531Snarayan 		return (0);
55692531Snarayan 	}
55702531Snarayan 
55711991Sheppo 	if (offset >= mhdl->memseg->size ||
55721991Sheppo 	    (offset + size) > mhdl->memseg->size) {
55731991Sheppo 		DWARN(DBG_ALL_LDCS,
55741991Sheppo 		    "i_ldc_mem_acquire_release: memory out of range\n");
55751991Sheppo 		mutex_exit(&mhdl->lock);
55761991Sheppo 		return (EINVAL);
55771991Sheppo 	}
55781991Sheppo 
55791991Sheppo 	/* get the channel handle and memory segment */
55801991Sheppo 	ldcp = mhdl->ldcp;
55811991Sheppo 	memseg = mhdl->memseg;
55821991Sheppo 
55831991Sheppo 	if (mhdl->mtype == LDC_SHADOW_MAP) {
55841991Sheppo 
55851991Sheppo 		local_vaddr = memseg->vaddr + offset;
55861991Sheppo 		copy_size = size;
55871991Sheppo 
55881991Sheppo 		/* copy to/from remote from/to local memory */
55891991Sheppo 		err = ldc_mem_copy((ldc_handle_t)ldcp, local_vaddr, offset,
55901991Sheppo 		    &copy_size, memseg->cookies, memseg->ncookies,
55911991Sheppo 		    direction);
55921991Sheppo 		if (err || copy_size != size) {
55933010Slm66018 			DWARN(ldcp->id,
55941991Sheppo 			    "i_ldc_mem_acquire_release: copy failed\n");
55951991Sheppo 			mutex_exit(&mhdl->lock);
55961991Sheppo 			return (err);
55971991Sheppo 		}
55981991Sheppo 	}
55991991Sheppo 
56001991Sheppo 	mutex_exit(&mhdl->lock);
56011991Sheppo 
56021991Sheppo 	return (0);
56031991Sheppo }
56041991Sheppo 
56051991Sheppo /*
56061991Sheppo  * Ensure that the contents in the remote memory seg are consistent
56071991Sheppo  * with the contents if of local segment
56081991Sheppo  */
56091991Sheppo int
56101991Sheppo ldc_mem_acquire(ldc_mem_handle_t mhandle, uint64_t offset, uint64_t size)
56111991Sheppo {
56121991Sheppo 	return (i_ldc_mem_acquire_release(mhandle, LDC_COPY_IN, offset, size));
56131991Sheppo }
56141991Sheppo 
56151991Sheppo 
56161991Sheppo /*
56171991Sheppo  * Ensure that the contents in the local memory seg are consistent
56181991Sheppo  * with the contents if of remote segment
56191991Sheppo  */
56201991Sheppo int
56211991Sheppo ldc_mem_release(ldc_mem_handle_t mhandle, uint64_t offset, uint64_t size)
56221991Sheppo {
56231991Sheppo 	return (i_ldc_mem_acquire_release(mhandle, LDC_COPY_OUT, offset, size));
56241991Sheppo }
56251991Sheppo 
56261991Sheppo /*
56271991Sheppo  * Allocate a descriptor ring. The size of each each descriptor
56281991Sheppo  * must be 8-byte aligned and the entire ring should be a multiple
56291991Sheppo  * of MMU_PAGESIZE.
56301991Sheppo  */
56311991Sheppo int
56321991Sheppo ldc_mem_dring_create(uint32_t len, uint32_t dsize, ldc_dring_handle_t *dhandle)
56331991Sheppo {
56341991Sheppo 	ldc_dring_t *dringp;
56351991Sheppo 	size_t size = (dsize * len);
56361991Sheppo 
56371991Sheppo 	D1(DBG_ALL_LDCS, "ldc_mem_dring_create: len=0x%x, size=0x%x\n",
56381991Sheppo 	    len, dsize);
56391991Sheppo 
56401991Sheppo 	if (dhandle == NULL) {
56411991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid dhandle\n");
56421991Sheppo 		return (EINVAL);
56431991Sheppo 	}
56441991Sheppo 
56451991Sheppo 	if (len == 0) {
56461991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid length\n");
56471991Sheppo 		return (EINVAL);
56481991Sheppo 	}
56491991Sheppo 
56501991Sheppo 	/* descriptor size should be 8-byte aligned */
56511991Sheppo 	if (dsize == 0 || (dsize & 0x7)) {
56521991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid size\n");
56531991Sheppo 		return (EINVAL);
56541991Sheppo 	}
56551991Sheppo 
56561991Sheppo 	*dhandle = 0;
56571991Sheppo 
56581991Sheppo 	/* Allocate a desc ring structure */
56591991Sheppo 	dringp = kmem_zalloc(sizeof (ldc_dring_t), KM_SLEEP);
56601991Sheppo 
56611991Sheppo 	/* Initialize dring */
56621991Sheppo 	dringp->length = len;
56631991Sheppo 	dringp->dsize = dsize;
56641991Sheppo 
56651991Sheppo 	/* round off to multiple of pagesize */
56661991Sheppo 	dringp->size = (size & MMU_PAGEMASK);
56671991Sheppo 	if (size & MMU_PAGEOFFSET)
56681991Sheppo 		dringp->size += MMU_PAGESIZE;
56691991Sheppo 
56701991Sheppo 	dringp->status = LDC_UNBOUND;
56711991Sheppo 
56721991Sheppo 	/* allocate descriptor ring memory */
56732793Slm66018 	dringp->base = kmem_zalloc(dringp->size, KM_SLEEP);
56741991Sheppo 
56751991Sheppo 	/* initialize the desc ring lock */
56761991Sheppo 	mutex_init(&dringp->lock, NULL, MUTEX_DRIVER, NULL);
56771991Sheppo 
56781991Sheppo 	/* Add descriptor ring to the head of global list */
56791991Sheppo 	mutex_enter(&ldcssp->lock);
56801991Sheppo 	dringp->next = ldcssp->dring_list;
56811991Sheppo 	ldcssp->dring_list = dringp;
56821991Sheppo 	mutex_exit(&ldcssp->lock);
56831991Sheppo 
56841991Sheppo 	*dhandle = (ldc_dring_handle_t)dringp;
56851991Sheppo 
56861991Sheppo 	D1(DBG_ALL_LDCS, "ldc_mem_dring_create: dring allocated\n");
56871991Sheppo 
56881991Sheppo 	return (0);
56891991Sheppo }
56901991Sheppo 
56911991Sheppo 
56921991Sheppo /*
56931991Sheppo  * Destroy a descriptor ring.
56941991Sheppo  */
56951991Sheppo int
56961991Sheppo ldc_mem_dring_destroy(ldc_dring_handle_t dhandle)
56971991Sheppo {
56981991Sheppo 	ldc_dring_t *dringp;
56991991Sheppo 	ldc_dring_t *tmp_dringp;
57001991Sheppo 
57011991Sheppo 	D1(DBG_ALL_LDCS, "ldc_mem_dring_destroy: entered\n");
57021991Sheppo 
57031991Sheppo 	if (dhandle == NULL) {
57041991Sheppo 		DWARN(DBG_ALL_LDCS,
57051991Sheppo 		    "ldc_mem_dring_destroy: invalid desc ring handle\n");
57061991Sheppo 		return (EINVAL);
57071991Sheppo 	}
57081991Sheppo 	dringp = (ldc_dring_t *)dhandle;
57091991Sheppo 
57101991Sheppo 	if (dringp->status == LDC_BOUND) {
57111991Sheppo 		DWARN(DBG_ALL_LDCS,
57121991Sheppo 		    "ldc_mem_dring_destroy: desc ring is bound\n");
57131991Sheppo 		return (EACCES);
57141991Sheppo 	}
57151991Sheppo 
57161991Sheppo 	mutex_enter(&dringp->lock);
57171991Sheppo 	mutex_enter(&ldcssp->lock);
57181991Sheppo 
57191991Sheppo 	/* remove from linked list - if not bound */
57201991Sheppo 	tmp_dringp = ldcssp->dring_list;
57211991Sheppo 	if (tmp_dringp == dringp) {
57221991Sheppo 		ldcssp->dring_list = dringp->next;
57231991Sheppo 		dringp->next = NULL;
57241991Sheppo 
57251991Sheppo 	} else {
57261991Sheppo 		while (tmp_dringp != NULL) {
57271991Sheppo 			if (tmp_dringp->next == dringp) {
57281991Sheppo 				tmp_dringp->next = dringp->next;
57291991Sheppo 				dringp->next = NULL;
57301991Sheppo 				break;
57311991Sheppo 			}
57321991Sheppo 			tmp_dringp = tmp_dringp->next;
57331991Sheppo 		}
57341991Sheppo 		if (tmp_dringp == NULL) {
57351991Sheppo 			DWARN(DBG_ALL_LDCS,
57361991Sheppo 			    "ldc_mem_dring_destroy: invalid descriptor\n");
57371991Sheppo 			mutex_exit(&ldcssp->lock);
57381991Sheppo 			mutex_exit(&dringp->lock);
57391991Sheppo 			return (EINVAL);
57401991Sheppo 		}
57411991Sheppo 	}
57421991Sheppo 
57431991Sheppo 	mutex_exit(&ldcssp->lock);
57441991Sheppo 
57451991Sheppo 	/* free the descriptor ring */
57462793Slm66018 	kmem_free(dringp->base, dringp->size);
57471991Sheppo 
57481991Sheppo 	mutex_exit(&dringp->lock);
57491991Sheppo 
57501991Sheppo 	/* destroy dring lock */
57511991Sheppo 	mutex_destroy(&dringp->lock);
57521991Sheppo 
57531991Sheppo 	/* free desc ring object */
57541991Sheppo 	kmem_free(dringp, sizeof (ldc_dring_t));
57551991Sheppo 
57561991Sheppo 	return (0);
57571991Sheppo }
57581991Sheppo 
57591991Sheppo /*
57601991Sheppo  * Bind a previously allocated dring to a channel. The channel should
57611991Sheppo  * be OPEN in order to bind the ring to the channel. Returns back a
57621991Sheppo  * descriptor ring cookie. The descriptor ring is exported for remote
57631991Sheppo  * access by the client at the other end of the channel. An entry for
57641991Sheppo  * dring pages is stored in map table (via call to ldc_mem_bind_handle).
57651991Sheppo  */
57661991Sheppo int
57671991Sheppo ldc_mem_dring_bind(ldc_handle_t handle, ldc_dring_handle_t dhandle,
57681991Sheppo     uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount)
57691991Sheppo {
57701991Sheppo 	int		err;
57711991Sheppo 	ldc_chan_t 	*ldcp;
57721991Sheppo 	ldc_dring_t	*dringp;
57731991Sheppo 	ldc_mem_handle_t mhandle;
57741991Sheppo 
57751991Sheppo 	/* check to see if channel is initalized */
57761991Sheppo 	if (handle == NULL) {
57771991Sheppo 		DWARN(DBG_ALL_LDCS,
57781991Sheppo 		    "ldc_mem_dring_bind: invalid channel handle\n");
57791991Sheppo 		return (EINVAL);
57801991Sheppo 	}
57811991Sheppo 	ldcp = (ldc_chan_t *)handle;
57821991Sheppo 
57831991Sheppo 	if (dhandle == NULL) {
57841991Sheppo 		DWARN(DBG_ALL_LDCS,
57851991Sheppo 		    "ldc_mem_dring_bind: invalid desc ring handle\n");
57861991Sheppo 		return (EINVAL);
57871991Sheppo 	}
57881991Sheppo 	dringp = (ldc_dring_t *)dhandle;
57891991Sheppo 
57901991Sheppo 	if (cookie == NULL) {
57911991Sheppo 		DWARN(ldcp->id,
57921991Sheppo 		    "ldc_mem_dring_bind: invalid cookie arg\n");
57931991Sheppo 		return (EINVAL);
57941991Sheppo 	}
57951991Sheppo 
57961991Sheppo 	mutex_enter(&dringp->lock);
57971991Sheppo 
57981991Sheppo 	if (dringp->status == LDC_BOUND) {
57991991Sheppo 		DWARN(DBG_ALL_LDCS,
58001991Sheppo 		    "ldc_mem_dring_bind: (0x%llx) descriptor ring is bound\n",
58011991Sheppo 		    ldcp->id);
58021991Sheppo 		mutex_exit(&dringp->lock);
58031991Sheppo 		return (EINVAL);
58041991Sheppo 	}
58051991Sheppo 
58061991Sheppo 	if ((perm & LDC_MEM_RW) == 0) {
58071991Sheppo 		DWARN(DBG_ALL_LDCS,
58081991Sheppo 		    "ldc_mem_dring_bind: invalid permissions\n");
58091991Sheppo 		mutex_exit(&dringp->lock);
58101991Sheppo 		return (EINVAL);
58111991Sheppo 	}
58121991Sheppo 
58131991Sheppo 	if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP|LDC_IO_MAP)) == 0) {
58141991Sheppo 		DWARN(DBG_ALL_LDCS, "ldc_mem_dring_bind: invalid type\n");
58151991Sheppo 		mutex_exit(&dringp->lock);
58161991Sheppo 		return (EINVAL);
58171991Sheppo 	}
58181991Sheppo 
58191991Sheppo 	dringp->ldcp = ldcp;
58201991Sheppo 
58211991Sheppo 	/* create an memory handle */
58221991Sheppo 	err = ldc_mem_alloc_handle(handle, &mhandle);
58231991Sheppo 	if (err || mhandle == NULL) {
58241991Sheppo 		DWARN(DBG_ALL_LDCS,
58251991Sheppo 		    "ldc_mem_dring_bind: (0x%llx) error allocating mhandle\n",
58261991Sheppo 		    ldcp->id);
58271991Sheppo 		mutex_exit(&dringp->lock);
58281991Sheppo 		return (err);
58291991Sheppo 	}
58301991Sheppo 	dringp->mhdl = mhandle;
58311991Sheppo 
58321991Sheppo 	/* bind the descriptor ring to channel */
58331991Sheppo 	err = ldc_mem_bind_handle(mhandle, dringp->base, dringp->size,
58341991Sheppo 	    mtype, perm, cookie, ccount);
58351991Sheppo 	if (err) {
58361991Sheppo 		DWARN(ldcp->id,
58371991Sheppo 		    "ldc_mem_dring_bind: (0x%llx) error binding mhandle\n",
58381991Sheppo 		    ldcp->id);
58391991Sheppo 		mutex_exit(&dringp->lock);
58401991Sheppo 		return (err);
58411991Sheppo 	}
58421991Sheppo 
58431991Sheppo 	/*
58441991Sheppo 	 * For now return error if we get more than one cookie
58451991Sheppo 	 * FUTURE: Return multiple cookies ..
58461991Sheppo 	 */
58471991Sheppo 	if (*ccount > 1) {
58481991Sheppo 		(void) ldc_mem_unbind_handle(mhandle);
58491991Sheppo 		(void) ldc_mem_free_handle(mhandle);
58501991Sheppo 
58511991Sheppo 		dringp->ldcp = NULL;
58521991Sheppo 		dringp->mhdl = NULL;
58531991Sheppo 		*ccount = 0;
58541991Sheppo 
58551991Sheppo 		mutex_exit(&dringp->lock);
58561991Sheppo 		return (EAGAIN);
58571991Sheppo 	}
58581991Sheppo 
58591991Sheppo 	/* Add descriptor ring to channel's exported dring list */
58601991Sheppo 	mutex_enter(&ldcp->exp_dlist_lock);
58611991Sheppo 	dringp->ch_next = ldcp->exp_dring_list;
58621991Sheppo 	ldcp->exp_dring_list = dringp;
58631991Sheppo 	mutex_exit(&ldcp->exp_dlist_lock);
58641991Sheppo 
58651991Sheppo 	dringp->status = LDC_BOUND;
58661991Sheppo 
58671991Sheppo 	mutex_exit(&dringp->lock);
58681991Sheppo 
58691991Sheppo 	return (0);
58701991Sheppo }
58711991Sheppo 
58721991Sheppo /*
58731991Sheppo  * Return the next cookie associated with the specified dring handle
58741991Sheppo  */
58751991Sheppo int
58761991Sheppo ldc_mem_dring_nextcookie(ldc_dring_handle_t dhandle, ldc_mem_cookie_t *cookie)
58771991Sheppo {
58781991Sheppo 	int		rv = 0;
58791991Sheppo 	ldc_dring_t 	*dringp;
58801991Sheppo 	ldc_chan_t	*ldcp;
58811991Sheppo 
58821991Sheppo 	if (dhandle == NULL) {
58831991Sheppo 		DWARN(DBG_ALL_LDCS,
58841991Sheppo 		    "ldc_mem_dring_nextcookie: invalid desc ring handle\n");
58851991Sheppo 		return (EINVAL);
58861991Sheppo 	}
58871991Sheppo 	dringp = (ldc_dring_t *)dhandle;
58881991Sheppo 	mutex_enter(&dringp->lock);
58891991Sheppo 
58901991Sheppo 	if (dringp->status != LDC_BOUND) {
58911991Sheppo 		DWARN(DBG_ALL_LDCS,
58921991Sheppo 		    "ldc_mem_dring_nextcookie: descriptor ring 0x%llx "
58931991Sheppo 		    "is not bound\n", dringp);
58941991Sheppo 		mutex_exit(&dringp->lock);
58951991Sheppo 		return (EINVAL);
58961991Sheppo 	}
58971991Sheppo 
58981991Sheppo 	ldcp = dringp->ldcp;
58991991Sheppo 
59001991Sheppo 	if (cookie == NULL) {
59011991Sheppo 		DWARN(ldcp->id,
59021991Sheppo 		    "ldc_mem_dring_nextcookie:(0x%llx) invalid cookie arg\n",
59031991Sheppo 		    ldcp->id);
59041991Sheppo 		mutex_exit(&dringp->lock);
59051991Sheppo 		return (EINVAL);
59061991Sheppo 	}
59071991Sheppo 
59081991Sheppo 	rv = ldc_mem_nextcookie((ldc_mem_handle_t)dringp->mhdl, cookie);
59091991Sheppo 	mutex_exit(&dringp->lock);
59101991Sheppo 
59111991Sheppo 	return (rv);
59121991Sheppo }
59131991Sheppo /*
59141991Sheppo  * Unbind a previously bound dring from a channel.
59151991Sheppo  */
59161991Sheppo int
59171991Sheppo ldc_mem_dring_unbind(ldc_dring_handle_t dhandle)
59181991Sheppo {
59191991Sheppo 	ldc_dring_t 	*dringp;
59201991Sheppo 	ldc_dring_t	*tmp_dringp;
59211991Sheppo 	ldc_chan_t	*ldcp;
59221991Sheppo 
59231991Sheppo 	if (dhandle == NULL) {
59241991Sheppo 		DWARN(DBG_ALL_LDCS,
59251991Sheppo 		    "ldc_mem_dring_unbind: invalid desc ring handle\n");
59261991Sheppo 		return (EINVAL);
59271991Sheppo 	}
59281991Sheppo 	dringp = (ldc_dring_t *)dhandle;
59291991Sheppo 
59301991Sheppo 	mutex_enter(&dringp->lock);
59311991Sheppo 
59321991Sheppo 	if (dringp->status == LDC_UNBOUND) {
59331991Sheppo 		DWARN(DBG_ALL_LDCS,
59341991Sheppo 		    "ldc_mem_dring_bind: descriptor ring 0x%llx is unbound\n",
59351991Sheppo 		    dringp);
59361991Sheppo 		mutex_exit(&dringp->lock);
59371991Sheppo 		return (EINVAL);
59381991Sheppo 	}
59391991Sheppo 	ldcp = dringp->ldcp;
59401991Sheppo 
59411991Sheppo 	mutex_enter(&ldcp->exp_dlist_lock);
59421991Sheppo 
59431991Sheppo 	tmp_dringp = ldcp->exp_dring_list;
59441991Sheppo 	if (tmp_dringp == dringp) {
59451991Sheppo 		ldcp->exp_dring_list = dringp->ch_next;
59461991Sheppo 		dringp->ch_next = NULL;
59471991Sheppo 
59481991Sheppo 	} else {
59491991Sheppo 		while (tmp_dringp != NULL) {
59501991Sheppo 			if (tmp_dringp->ch_next == dringp) {
59511991Sheppo 				tmp_dringp->ch_next = dringp->ch_next;
59521991Sheppo 				dringp->ch_next = NULL;
59531991Sheppo 				break;
59541991Sheppo 			}
59551991Sheppo 			tmp_dringp = tmp_dringp->ch_next;
59561991Sheppo 		}
59571991Sheppo 		if (tmp_dringp == NULL) {
59581991Sheppo 			DWARN(DBG_ALL_LDCS,
59591991Sheppo 			    "ldc_mem_dring_unbind: invalid descriptor\n");
59601991Sheppo 			mutex_exit(&ldcp->exp_dlist_lock);
59611991Sheppo 			mutex_exit(&dringp->lock);
59621991Sheppo 			return (EINVAL);
59631991Sheppo 		}
59641991Sheppo 	}
59651991Sheppo 
59661991Sheppo 	mutex_exit(&ldcp->exp_dlist_lock);
59671991Sheppo 
59681991Sheppo 	(void) ldc_mem_unbind_handle((ldc_mem_handle_t)dringp->mhdl);
59691991Sheppo 	(void) ldc_mem_free_handle((ldc_mem_handle_t)dringp->mhdl);
59701991Sheppo 
59711991Sheppo 	dringp->ldcp = NULL;
59721991Sheppo 	dringp->mhdl = NULL;
59731991Sheppo 	dringp->status = LDC_UNBOUND;
59741991Sheppo 
59751991Sheppo 	mutex_exit(&dringp->lock);
59761991Sheppo 
59771991Sheppo 	return (0);
59781991Sheppo }
59791991Sheppo 
59801991Sheppo /*
59811991Sheppo  * Get information about the dring. The base address of the descriptor
59821991Sheppo  * ring along with the type and permission are returned back.
59831991Sheppo  */
59841991Sheppo int
59851991Sheppo ldc_mem_dring_info(ldc_dring_handle_t dhandle, ldc_mem_info_t *minfo)
59861991Sheppo {
59871991Sheppo 	ldc_dring_t	*dringp;
59881991Sheppo 	int		rv;
59891991Sheppo 
59901991Sheppo 	if (dhandle == NULL) {
59911991Sheppo 		DWARN(DBG_ALL_LDCS,
59921991Sheppo 		    "ldc_mem_dring_info: invalid desc ring handle\n");
59931991Sheppo 		return (EINVAL);
59941991Sheppo 	}
59951991Sheppo 	dringp = (ldc_dring_t *)dhandle;
59961991Sheppo 
59971991Sheppo 	mutex_enter(&dringp->lock);
59981991Sheppo 
59991991Sheppo 	if (dringp->mhdl) {
60001991Sheppo 		rv = ldc_mem_info(dringp->mhdl, minfo);
60011991Sheppo 		if (rv) {
60021991Sheppo 			DWARN(DBG_ALL_LDCS,
60031991Sheppo 			    "ldc_mem_dring_info: error reading mem info\n");
60041991Sheppo 			mutex_exit(&dringp->lock);
60051991Sheppo 			return (rv);
60061991Sheppo 		}
60071991Sheppo 	} else {
60081991Sheppo 		minfo->vaddr = dringp->base;
60091991Sheppo 		minfo->raddr = NULL;
60101991Sheppo 		minfo->status = dringp->status;
60111991Sheppo 	}
60121991Sheppo 
60131991Sheppo 	mutex_exit(&dringp->lock);
60141991Sheppo 
60151991Sheppo 	return (0);
60161991Sheppo }
60171991Sheppo 
60181991Sheppo /*
60191991Sheppo  * Map an exported descriptor ring into the local address space. If the
60201991Sheppo  * descriptor ring was exported for direct map access, a HV call is made
60211991Sheppo  * to allocate a RA range. If the map is done via a shadow copy, local
60221991Sheppo  * shadow memory is allocated.
60231991Sheppo  */
60241991Sheppo int
60251991Sheppo ldc_mem_dring_map(ldc_handle_t handle, ldc_mem_cookie_t *cookie,
60261991Sheppo     uint32_t ccount, uint32_t len, uint32_t dsize, uint8_t mtype,
60271991Sheppo     ldc_dring_handle_t *dhandle)
60281991Sheppo {
60291991Sheppo 	int		err;
60301991Sheppo 	ldc_chan_t 	*ldcp = (ldc_chan_t *)handle;
60311991Sheppo 	ldc_mem_handle_t mhandle;
60321991Sheppo 	ldc_dring_t	*dringp;
60331991Sheppo 	size_t		dring_size;
60341991Sheppo 
60351991Sheppo 	if (dhandle == NULL) {
60361991Sheppo 		DWARN(DBG_ALL_LDCS,
60371991Sheppo 		    "ldc_mem_dring_map: invalid dhandle\n");
60381991Sheppo 		return (EINVAL);
60391991Sheppo 	}
60401991Sheppo 
60411991Sheppo 	/* check to see if channel is initalized */
60421991Sheppo 	if (handle == NULL) {
60431991Sheppo 		DWARN(DBG_ALL_LDCS,
60441991Sheppo 		    "ldc_mem_dring_map: invalid channel handle\n");
60451991Sheppo 		return (EINVAL);
60461991Sheppo 	}
60471991Sheppo 	ldcp = (ldc_chan_t *)handle;
60481991Sheppo 
60491991Sheppo 	if (cookie == NULL) {
60501991Sheppo 		DWARN(ldcp->id,
60511991Sheppo 		    "ldc_mem_dring_map: (0x%llx) invalid cookie\n",
60521991Sheppo 		    ldcp->id);
60531991Sheppo 		return (EINVAL);
60541991Sheppo 	}
60551991Sheppo 
60561991Sheppo 	/* FUTURE: For now we support only one cookie per dring */
60571991Sheppo 	ASSERT(ccount == 1);
60581991Sheppo 
60591991Sheppo 	if (cookie->size < (dsize * len)) {
60601991Sheppo 		DWARN(ldcp->id,
60611991Sheppo 		    "ldc_mem_dring_map: (0x%llx) invalid dsize/len\n",
60621991Sheppo 		    ldcp->id);
60631991Sheppo 		return (EINVAL);
60641991Sheppo 	}
60651991Sheppo 
60661991Sheppo 	*dhandle = 0;
60671991Sheppo 
60681991Sheppo 	/* Allocate an dring structure */
60691991Sheppo 	dringp = kmem_zalloc(sizeof (ldc_dring_t), KM_SLEEP);
60701991Sheppo 
60711991Sheppo 	D1(ldcp->id,
60721991Sheppo 	    "ldc_mem_dring_map: 0x%x,0x%x,0x%x,0x%llx,0x%llx\n",
60731991Sheppo 	    mtype, len, dsize, cookie->addr, cookie->size);
60741991Sheppo 
60751991Sheppo 	/* Initialize dring */
60761991Sheppo 	dringp->length = len;
60771991Sheppo 	dringp->dsize = dsize;
60781991Sheppo 
60791991Sheppo 	/* round of to multiple of page size */
60801991Sheppo 	dring_size = len * dsize;
60811991Sheppo 	dringp->size = (dring_size & MMU_PAGEMASK);
60821991Sheppo 	if (dring_size & MMU_PAGEOFFSET)
60831991Sheppo 		dringp->size += MMU_PAGESIZE;
60841991Sheppo 
60851991Sheppo 	dringp->ldcp = ldcp;
60861991Sheppo 
60871991Sheppo 	/* create an memory handle */
60881991Sheppo 	err = ldc_mem_alloc_handle(handle, &mhandle);
60891991Sheppo 	if (err || mhandle == NULL) {
60901991Sheppo 		DWARN(DBG_ALL_LDCS,
60911991Sheppo 		    "ldc_mem_dring_map: cannot alloc hdl err=%d\n",
60921991Sheppo 		    err);
60931991Sheppo 		kmem_free(dringp, sizeof (ldc_dring_t));
60941991Sheppo 		return (ENOMEM);
60951991Sheppo 	}
60961991Sheppo 
60971991Sheppo 	dringp->mhdl = mhandle;
60981991Sheppo 	dringp->base = NULL;
60991991Sheppo 
61001991Sheppo 	/* map the dring into local memory */
61012531Snarayan 	err = ldc_mem_map(mhandle, cookie, ccount, mtype, LDC_MEM_RW,
61021991Sheppo 	    &(dringp->base), NULL);
61031991Sheppo 	if (err || dringp->base == NULL) {
61041991Sheppo 		cmn_err(CE_WARN,
61051991Sheppo 		    "ldc_mem_dring_map: cannot map desc ring err=%d\n", err);
61061991Sheppo 		(void) ldc_mem_free_handle(mhandle);
61071991Sheppo 		kmem_free(dringp, sizeof (ldc_dring_t));
61081991Sheppo 		return (ENOMEM);
61091991Sheppo 	}
61101991Sheppo 
61111991Sheppo 	/* initialize the desc ring lock */
61121991Sheppo 	mutex_init(&dringp->lock, NULL, MUTEX_DRIVER, NULL);
61131991Sheppo 
61141991Sheppo 	/* Add descriptor ring to channel's imported dring list */
61151991Sheppo 	mutex_enter(&ldcp->imp_dlist_lock);
61161991Sheppo 	dringp->ch_next = ldcp->imp_dring_list;
61171991Sheppo 	ldcp->imp_dring_list = dringp;
61181991Sheppo 	mutex_exit(&ldcp->imp_dlist_lock);
61191991Sheppo 
61201991Sheppo 	dringp->status = LDC_MAPPED;
61211991Sheppo 
61221991Sheppo 	*dhandle = (ldc_dring_handle_t)dringp;
61231991Sheppo 
61241991Sheppo 	return (0);
61251991Sheppo }
61261991Sheppo 
61271991Sheppo /*
61281991Sheppo  * Unmap a descriptor ring. Free shadow memory (if any).
61291991Sheppo  */
61301991Sheppo int
61311991Sheppo ldc_mem_dring_unmap(ldc_dring_handle_t dhandle)
61321991Sheppo {
61331991Sheppo 	ldc_dring_t 	*dringp;
61341991Sheppo 	ldc_dring_t	*tmp_dringp;
61351991Sheppo 	ldc_chan_t	*ldcp;
61361991Sheppo 
61371991Sheppo 	if (dhandle == NULL) {
61381991Sheppo 		DWARN(DBG_ALL_LDCS,
61391991Sheppo 		    "ldc_mem_dring_unmap: invalid desc ring handle\n");
61401991Sheppo 		return (EINVAL);
61411991Sheppo 	}
61421991Sheppo 	dringp = (ldc_dring_t *)dhandle;
61431991Sheppo 
61441991Sheppo 	if (dringp->status != LDC_MAPPED) {
61451991Sheppo 		DWARN(DBG_ALL_LDCS,
61461991Sheppo 		    "ldc_mem_dring_unmap: not a mapped desc ring\n");
61471991Sheppo 		return (EINVAL);
61481991Sheppo 	}
61491991Sheppo 
61501991Sheppo 	mutex_enter(&dringp->lock);
61511991Sheppo 
61521991Sheppo 	ldcp = dringp->ldcp;
61531991Sheppo 
61541991Sheppo 	mutex_enter(&ldcp->imp_dlist_lock);
61551991Sheppo 
61561991Sheppo 	/* find and unlink the desc ring from channel import list */
61571991Sheppo 	tmp_dringp = ldcp->imp_dring_list;
61581991Sheppo 	if (tmp_dringp == dringp) {
61591991Sheppo 		ldcp->imp_dring_list = dringp->ch_next;
61601991Sheppo 		dringp->ch_next = NULL;
61611991Sheppo 
61621991Sheppo 	} else {
61631991Sheppo 		while (tmp_dringp != NULL) {
61641991Sheppo 			if (tmp_dringp->ch_next == dringp) {
61651991Sheppo 				tmp_dringp->ch_next = dringp->ch_next;
61661991Sheppo 				dringp->ch_next = NULL;
61671991Sheppo 				break;
61681991Sheppo 			}
61691991Sheppo 			tmp_dringp = tmp_dringp->ch_next;
61701991Sheppo 		}
61711991Sheppo 		if (tmp_dringp == NULL) {
61721991Sheppo 			DWARN(DBG_ALL_LDCS,
61731991Sheppo 			    "ldc_mem_dring_unmap: invalid descriptor\n");
61741991Sheppo 			mutex_exit(&ldcp->imp_dlist_lock);
61751991Sheppo 			mutex_exit(&dringp->lock);
61761991Sheppo 			return (EINVAL);
61771991Sheppo 		}
61781991Sheppo 	}
61791991Sheppo 
61801991Sheppo 	mutex_exit(&ldcp->imp_dlist_lock);
61811991Sheppo 
61821991Sheppo 	/* do a LDC memory handle unmap and free */
61831991Sheppo 	(void) ldc_mem_unmap(dringp->mhdl);
61841991Sheppo 	(void) ldc_mem_free_handle((ldc_mem_handle_t)dringp->mhdl);
61851991Sheppo 
61861991Sheppo 	dringp->status = 0;
61871991Sheppo 	dringp->ldcp = NULL;
61881991Sheppo 
61891991Sheppo 	mutex_exit(&dringp->lock);
61901991Sheppo 
61911991Sheppo 	/* destroy dring lock */
61921991Sheppo 	mutex_destroy(&dringp->lock);
61931991Sheppo 
61941991Sheppo 	/* free desc ring object */
61951991Sheppo 	kmem_free(dringp, sizeof (ldc_dring_t));
61961991Sheppo 
61971991Sheppo 	return (0);
61981991Sheppo }
61991991Sheppo 
62001991Sheppo /*
62011991Sheppo  * Internal entry point for descriptor ring access entry consistency
62021991Sheppo  * semantics. Acquire copies the contents of the remote descriptor ring
62031991Sheppo  * into the local shadow copy. The release operation copies the local
62041991Sheppo  * contents into the remote dring. The start and end locations specify
62051991Sheppo  * bounds for the entries being synchronized.
62061991Sheppo  */
62071991Sheppo static int
62081991Sheppo i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle,
62091991Sheppo     uint8_t direction, uint64_t start, uint64_t end)
62101991Sheppo {
62111991Sheppo 	int 			err;
62121991Sheppo 	ldc_dring_t		*dringp;
62131991Sheppo 	ldc_chan_t		*ldcp;
62141991Sheppo 	uint64_t		soff;
62151991Sheppo 	size_t			copy_size;
62161991Sheppo 
62171991Sheppo 	if (dhandle == NULL) {
62181991Sheppo 		DWARN(DBG_ALL_LDCS,
62191991Sheppo 		    "i_ldc_dring_acquire_release: invalid desc ring handle\n");
62201991Sheppo 		return (EINVAL);
62211991Sheppo 	}
62221991Sheppo 	dringp = (ldc_dring_t *)dhandle;
62231991Sheppo 	mutex_enter(&dringp->lock);
62241991Sheppo 
62251991Sheppo 	if (dringp->status != LDC_MAPPED || dringp->ldcp == NULL) {
62261991Sheppo 		DWARN(DBG_ALL_LDCS,
62271991Sheppo 		    "i_ldc_dring_acquire_release: not a mapped desc ring\n");
62281991Sheppo 		mutex_exit(&dringp->lock);
62291991Sheppo 		return (EINVAL);
62301991Sheppo 	}
62311991Sheppo 
62321991Sheppo 	if (start >= dringp->length || end >= dringp->length) {
62331991Sheppo 		DWARN(DBG_ALL_LDCS,
62341991Sheppo 		    "i_ldc_dring_acquire_release: index out of range\n");
62351991Sheppo 		mutex_exit(&dringp->lock);
62361991Sheppo 		return (EINVAL);
62371991Sheppo 	}
62381991Sheppo 
62391991Sheppo 	/* get the channel handle */
62401991Sheppo 	ldcp = dringp->ldcp;
62411991Sheppo 
62421991Sheppo 	copy_size = (start <= end) ? (((end - start) + 1) * dringp->dsize) :
62431991Sheppo 		((dringp->length - start) * dringp->dsize);
62441991Sheppo 
62451991Sheppo 	/* Calculate the relative offset for the first desc */
62461991Sheppo 	soff = (start * dringp->dsize);
62471991Sheppo 
62481991Sheppo 	/* copy to/from remote from/to local memory */
62491991Sheppo 	D1(ldcp->id, "i_ldc_dring_acquire_release: c1 off=0x%llx sz=0x%llx\n",
62501991Sheppo 	    soff, copy_size);
62511991Sheppo 	err = i_ldc_mem_acquire_release((ldc_mem_handle_t)dringp->mhdl,
62521991Sheppo 	    direction, soff, copy_size);
62531991Sheppo 	if (err) {
62541991Sheppo 		DWARN(ldcp->id,
62551991Sheppo 		    "i_ldc_dring_acquire_release: copy failed\n");
62561991Sheppo 		mutex_exit(&dringp->lock);
62571991Sheppo 		return (err);
62581991Sheppo 	}
62591991Sheppo 
62601991Sheppo 	/* do the balance */
62611991Sheppo 	if (start > end) {
62621991Sheppo 		copy_size = ((end + 1) * dringp->dsize);
62631991Sheppo 		soff = 0;
62641991Sheppo 
62651991Sheppo 		/* copy to/from remote from/to local memory */
62661991Sheppo 		D1(ldcp->id, "i_ldc_dring_acquire_release: c2 "
62671991Sheppo 		    "off=0x%llx sz=0x%llx\n", soff, copy_size);
62681991Sheppo 		err = i_ldc_mem_acquire_release((ldc_mem_handle_t)dringp->mhdl,
62691991Sheppo 		    direction, soff, copy_size);
62701991Sheppo 		if (err) {
62711991Sheppo 			DWARN(ldcp->id,
62721991Sheppo 			    "i_ldc_dring_acquire_release: copy failed\n");
62731991Sheppo 			mutex_exit(&dringp->lock);
62741991Sheppo 			return (err);
62751991Sheppo 		}
62761991Sheppo 	}
62771991Sheppo 
62781991Sheppo 	mutex_exit(&dringp->lock);
62791991Sheppo 
62801991Sheppo 	return (0);
62811991Sheppo }
62821991Sheppo 
62831991Sheppo /*
62841991Sheppo  * Ensure that the contents in the local dring are consistent
62851991Sheppo  * with the contents if of remote dring
62861991Sheppo  */
62871991Sheppo int
62881991Sheppo ldc_mem_dring_acquire(ldc_dring_handle_t dhandle, uint64_t start, uint64_t end)
62891991Sheppo {
62901991Sheppo 	return (i_ldc_dring_acquire_release(dhandle, LDC_COPY_IN, start, end));
62911991Sheppo }
62921991Sheppo 
62931991Sheppo /*
62941991Sheppo  * Ensure that the contents in the remote dring are consistent
62951991Sheppo  * with the contents if of local dring
62961991Sheppo  */
62971991Sheppo int
62981991Sheppo ldc_mem_dring_release(ldc_dring_handle_t dhandle, uint64_t start, uint64_t end)
62991991Sheppo {
63001991Sheppo 	return (i_ldc_dring_acquire_release(dhandle, LDC_COPY_OUT, start, end));
63011991Sheppo }
63021991Sheppo 
63031991Sheppo 
63041991Sheppo /* ------------------------------------------------------------------------- */
6305