11ae08745Sheppo /*
21ae08745Sheppo * CDDL HEADER START
31ae08745Sheppo *
41ae08745Sheppo * The contents of this file are subject to the terms of the
51ae08745Sheppo * Common Development and Distribution License (the "License").
61ae08745Sheppo * You may not use this file except in compliance with the License.
71ae08745Sheppo *
81ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91ae08745Sheppo * or http://www.opensolaris.org/os/licensing.
101ae08745Sheppo * See the License for the specific language governing permissions
111ae08745Sheppo * and limitations under the License.
121ae08745Sheppo *
131ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each
141ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the
161ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying
171ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner]
181ae08745Sheppo *
191ae08745Sheppo * CDDL HEADER END
201ae08745Sheppo */
211ae08745Sheppo
221ae08745Sheppo /*
23*34f94fbcSWENTAO YANG * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
241ae08745Sheppo */
251ae08745Sheppo
261ae08745Sheppo /*
27e1ebb9ecSlm66018 * sun4v LDC Link Layer
281ae08745Sheppo */
291ae08745Sheppo #include <sys/types.h>
301ae08745Sheppo #include <sys/file.h>
311ae08745Sheppo #include <sys/errno.h>
321ae08745Sheppo #include <sys/open.h>
331ae08745Sheppo #include <sys/cred.h>
341ae08745Sheppo #include <sys/kmem.h>
351ae08745Sheppo #include <sys/conf.h>
361ae08745Sheppo #include <sys/cmn_err.h>
371ae08745Sheppo #include <sys/ksynch.h>
381ae08745Sheppo #include <sys/modctl.h>
391ae08745Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */
401ae08745Sheppo #include <sys/debug.h>
411ae08745Sheppo #include <sys/cred.h>
421ae08745Sheppo #include <sys/promif.h>
431ae08745Sheppo #include <sys/ddi.h>
441ae08745Sheppo #include <sys/sunddi.h>
451ae08745Sheppo #include <sys/cyclic.h>
461ae08745Sheppo #include <sys/machsystm.h>
471ae08745Sheppo #include <sys/vm.h>
481ae08745Sheppo #include <sys/cpu.h>
491ae08745Sheppo #include <sys/intreg.h>
501ae08745Sheppo #include <sys/machcpuvar.h>
514bac2208Snarayan #include <sys/mmu.h>
524bac2208Snarayan #include <sys/pte.h>
534bac2208Snarayan #include <vm/hat.h>
544bac2208Snarayan #include <vm/as.h>
554bac2208Snarayan #include <vm/hat_sfmmu.h>
564bac2208Snarayan #include <sys/vm_machparam.h>
574bac2208Snarayan #include <vm/seg_kmem.h>
584bac2208Snarayan #include <vm/seg_kpm.h>
591ae08745Sheppo #include <sys/note.h>
601ae08745Sheppo #include <sys/ivintr.h>
611ae08745Sheppo #include <sys/hypervisor_api.h>
621ae08745Sheppo #include <sys/ldc.h>
631ae08745Sheppo #include <sys/ldc_impl.h>
641ae08745Sheppo #include <sys/cnex.h>
651ae08745Sheppo #include <sys/hsvc.h>
6658283286Sha137994 #include <sys/sdt.h>
675699897cSHaik Aftandilian #include <sys/kldc.h>
681ae08745Sheppo
691ae08745Sheppo /* Core internal functions */
7020ae46ebSha137994 int i_ldc_h2v_error(int h_error);
7120ae46ebSha137994 void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset);
7220ae46ebSha137994
731ae08745Sheppo static int i_ldc_txq_reconf(ldc_chan_t *ldcp);
743af08d82Slm66018 static int i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset);
75305dbad4SKevin Crowe static void i_ldc_rxq_drain(ldc_chan_t *ldcp);
761ae08745Sheppo static void i_ldc_reset_state(ldc_chan_t *ldcp);
775699897cSHaik Aftandilian static void i_ldc_debug_enter(void);
781ae08745Sheppo
791ae08745Sheppo static int i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail);
8022f747efSnarayan static void i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head);
811ae08745Sheppo static int i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail);
821ae08745Sheppo static int i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head);
831ae08745Sheppo static int i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
841ae08745Sheppo uint8_t ctrlmsg);
851ae08745Sheppo
8658283286Sha137994 static int i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head);
8758283286Sha137994 static void i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head);
8858283286Sha137994 static uint64_t i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head,
8958283286Sha137994 uint64_t *tail, uint64_t *link_state);
9058283286Sha137994 static uint64_t i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head,
9158283286Sha137994 uint64_t *tail, uint64_t *link_state);
9258283286Sha137994 static int i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head,
9358283286Sha137994 uint64_t rx_tail);
9458283286Sha137994 static uint_t i_ldc_chkq(ldc_chan_t *ldcp);
9558283286Sha137994
961ae08745Sheppo /* Interrupt handling functions */
971ae08745Sheppo static uint_t i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2);
981ae08745Sheppo static uint_t i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2);
9958283286Sha137994 static uint_t i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client,
10058283286Sha137994 uint64_t *notify_event);
1011ae08745Sheppo static void i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype);
1021ae08745Sheppo
1031ae08745Sheppo /* Read method functions */
1041ae08745Sheppo static int i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep);
1051ae08745Sheppo static int i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp,
1061ae08745Sheppo size_t *sizep);
1071ae08745Sheppo static int i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp,
1081ae08745Sheppo size_t *sizep);
1091ae08745Sheppo
1101ae08745Sheppo /* Write method functions */
1111ae08745Sheppo static int i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t target_bufp,
1121ae08745Sheppo size_t *sizep);
1131ae08745Sheppo static int i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t target_bufp,
1141ae08745Sheppo size_t *sizep);
1151ae08745Sheppo static int i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t target_bufp,
1161ae08745Sheppo size_t *sizep);
1171ae08745Sheppo
1181ae08745Sheppo /* Pkt processing internal functions */
1191ae08745Sheppo static int i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg);
1201ae08745Sheppo static int i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg);
1211ae08745Sheppo static int i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg);
1221ae08745Sheppo static int i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg);
1231ae08745Sheppo static int i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg);
1241ae08745Sheppo static int i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg);
1251ae08745Sheppo static int i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg);
1261ae08745Sheppo
127*34f94fbcSWENTAO YANG /* Imported functions */
128*34f94fbcSWENTAO YANG extern void i_ldc_mem_set_hsvc_vers(uint64_t major, uint64_t minor);
129*34f94fbcSWENTAO YANG extern void i_ldc_init_mapin(ldc_soft_state_t *ldcssp, uint64_t major,
130*34f94fbcSWENTAO YANG uint64_t minor);
131*34f94fbcSWENTAO YANG
1321ae08745Sheppo /* LDC Version */
1331ae08745Sheppo static ldc_ver_t ldc_versions[] = { {1, 0} };
1341ae08745Sheppo
1351ae08745Sheppo /* number of supported versions */
1361ae08745Sheppo #define LDC_NUM_VERS (sizeof (ldc_versions) / sizeof (ldc_versions[0]))
1371ae08745Sheppo
13858283286Sha137994 /* Invalid value for the ldc_chan_t rx_ack_head field */
13958283286Sha137994 #define ACKPEEK_HEAD_INVALID ((uint64_t)-1)
14058283286Sha137994
14158283286Sha137994
1421ae08745Sheppo /* Module State Pointer */
14320ae46ebSha137994 ldc_soft_state_t *ldcssp;
1441ae08745Sheppo
1451ae08745Sheppo static struct modldrv md = {
1461ae08745Sheppo &mod_miscops, /* This is a misc module */
147f500b196SRichard Bean "sun4v LDC module", /* Name of the module */
1481ae08745Sheppo };
1491ae08745Sheppo
1501ae08745Sheppo static struct modlinkage ml = {
1511ae08745Sheppo MODREV_1,
1521ae08745Sheppo &md,
1531ae08745Sheppo NULL
1541ae08745Sheppo };
1551ae08745Sheppo
1561ae08745Sheppo static uint64_t ldc_sup_minor; /* Supported minor number */
1571ae08745Sheppo static hsvc_info_t ldc_hsvc = {
158*34f94fbcSWENTAO YANG HSVC_REV_1, NULL, HSVC_GROUP_LDC, 1, 2, "ldc"
1591ae08745Sheppo };
1601ae08745Sheppo
1614bac2208Snarayan /*
162e1ebb9ecSlm66018 * The no. of MTU size messages that can be stored in
163e1ebb9ecSlm66018 * the LDC Tx queue. The number of Tx queue entries is
164e1ebb9ecSlm66018 * then computed as (mtu * mtu_msgs)/sizeof(queue_entry)
165e1ebb9ecSlm66018 */
166e1ebb9ecSlm66018 uint64_t ldc_mtu_msgs = LDC_MTU_MSGS;
167e1ebb9ecSlm66018
168e1ebb9ecSlm66018 /*
169e1ebb9ecSlm66018 * The minimum queue length. This is the size of the smallest
170e1ebb9ecSlm66018 * LDC queue. If the computed value is less than this default,
171e1ebb9ecSlm66018 * the queue length is rounded up to 'ldc_queue_entries'.
172e1ebb9ecSlm66018 */
173e1ebb9ecSlm66018 uint64_t ldc_queue_entries = LDC_QUEUE_ENTRIES;
174e1ebb9ecSlm66018
175e1ebb9ecSlm66018 /*
17658283286Sha137994 * The length of the reliable-mode data queue in terms of the LDC
17758283286Sha137994 * receive queue length. i.e., the number of times larger than the
17858283286Sha137994 * LDC receive queue that the data queue should be. The HV receive
17958283286Sha137994 * queue is required to be a power of 2 and this implementation
18058283286Sha137994 * assumes the data queue will also be a power of 2. By making the
18158283286Sha137994 * multiplier a power of 2, we ensure the data queue will be a
18258283286Sha137994 * power of 2. We use a multiplier because the receive queue is
18358283286Sha137994 * sized to be sane relative to the MTU and the same is needed for
18458283286Sha137994 * the data queue.
18558283286Sha137994 */
18658283286Sha137994 uint64_t ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER;
18758283286Sha137994
18858283286Sha137994 /*
189e1ebb9ecSlm66018 * LDC retry count and delay - when the HV returns EWOULDBLOCK
190e1ebb9ecSlm66018 * the operation is retried 'ldc_max_retries' times with a
191e1ebb9ecSlm66018 * wait of 'ldc_delay' usecs between each retry.
1920a55fbb7Slm66018 */
1930a55fbb7Slm66018 int ldc_max_retries = LDC_MAX_RETRIES;
1940a55fbb7Slm66018 clock_t ldc_delay = LDC_DELAY;
1950a55fbb7Slm66018
1964d39be2bSsg70180 /*
1975699897cSHaik Aftandilian * Channels which have a devclass satisfying the following
1985699897cSHaik Aftandilian * will be reset when entering the prom or kmdb.
1995699897cSHaik Aftandilian *
2005699897cSHaik Aftandilian * LDC_DEVCLASS_PROM_RESET(devclass) != 0
2015699897cSHaik Aftandilian *
2025699897cSHaik Aftandilian * By default, only block device service channels are reset.
2035699897cSHaik Aftandilian */
2045699897cSHaik Aftandilian #define LDC_DEVCLASS_BIT(dc) (0x1 << (dc))
2055699897cSHaik Aftandilian #define LDC_DEVCLASS_PROM_RESET(dc) \
2065699897cSHaik Aftandilian (LDC_DEVCLASS_BIT(dc) & ldc_debug_reset_mask)
207d16449dbSZach Kissel static uint64_t ldc_debug_reset_mask = LDC_DEVCLASS_BIT(LDC_DEV_BLK_SVC) |
208d16449dbSZach Kissel LDC_DEVCLASS_BIT(LDC_DEV_GENERIC);
2095699897cSHaik Aftandilian
2105699897cSHaik Aftandilian /*
2114d39be2bSsg70180 * delay between each retry of channel unregistration in
2124d39be2bSsg70180 * ldc_close(), to wait for pending interrupts to complete.
2134d39be2bSsg70180 */
2144d39be2bSsg70180 clock_t ldc_close_delay = LDC_CLOSE_DELAY;
2154d39be2bSsg70180
216*34f94fbcSWENTAO YANG
217*34f94fbcSWENTAO YANG /*
218*34f94fbcSWENTAO YANG * Reserved mapin space for descriptor rings.
219*34f94fbcSWENTAO YANG */
220*34f94fbcSWENTAO YANG uint64_t ldc_dring_direct_map_rsvd = LDC_DIRECT_MAP_SIZE_DEFAULT;
221*34f94fbcSWENTAO YANG
222*34f94fbcSWENTAO YANG /*
223*34f94fbcSWENTAO YANG * Maximum direct map space allowed per channel.
224*34f94fbcSWENTAO YANG */
225*34f94fbcSWENTAO YANG uint64_t ldc_direct_map_size_max = (16 * 1024 * 1024); /* 16 MB */
226*34f94fbcSWENTAO YANG
2271ae08745Sheppo #ifdef DEBUG
2281ae08745Sheppo
2291ae08745Sheppo /*
2301ae08745Sheppo * Print debug messages
2311ae08745Sheppo *
2321ae08745Sheppo * set ldcdbg to 0x7 for enabling all msgs
2331ae08745Sheppo * 0x4 - Warnings
2341ae08745Sheppo * 0x2 - All debug messages
2351ae08745Sheppo * 0x1 - Minimal debug messages
2361ae08745Sheppo *
2371ae08745Sheppo * set ldcdbgchan to the channel number you want to debug
2381ae08745Sheppo * setting it to -1 prints debug messages for all channels
2391ae08745Sheppo * NOTE: ldcdbgchan has no effect on error messages
2401ae08745Sheppo */
2411ae08745Sheppo
2421ae08745Sheppo int ldcdbg = 0x0;
2431ae08745Sheppo int64_t ldcdbgchan = DBG_ALL_LDCS;
24483d3bc6fSnarayan uint64_t ldc_inject_err_flag = 0;
2451ae08745Sheppo
24620ae46ebSha137994 void
ldcdebug(int64_t id,const char * fmt,...)2471ae08745Sheppo ldcdebug(int64_t id, const char *fmt, ...)
2481ae08745Sheppo {
2491ae08745Sheppo char buf[512];
2501ae08745Sheppo va_list ap;
2511ae08745Sheppo
2521ae08745Sheppo /*
2531ae08745Sheppo * Do not return if,
2541ae08745Sheppo * caller wants to print it anyway - (id == DBG_ALL_LDCS)
2551ae08745Sheppo * debug channel is set to all LDCs - (ldcdbgchan == DBG_ALL_LDCS)
2561ae08745Sheppo * debug channel = caller specified channel
2571ae08745Sheppo */
2581ae08745Sheppo if ((id != DBG_ALL_LDCS) &&
2591ae08745Sheppo (ldcdbgchan != DBG_ALL_LDCS) &&
2601ae08745Sheppo (ldcdbgchan != id)) {
2611ae08745Sheppo return;
2621ae08745Sheppo }
2631ae08745Sheppo
2641ae08745Sheppo va_start(ap, fmt);
2651ae08745Sheppo (void) vsprintf(buf, fmt, ap);
2661ae08745Sheppo va_end(ap);
2671ae08745Sheppo
2683af08d82Slm66018 cmn_err(CE_CONT, "?%s", buf);
2693af08d82Slm66018 }
2703af08d82Slm66018
27183d3bc6fSnarayan #define LDC_ERR_RESET 0x1
27283d3bc6fSnarayan #define LDC_ERR_PKTLOSS 0x2
27358283286Sha137994 #define LDC_ERR_DQFULL 0x4
274bbfa0259Sha137994 #define LDC_ERR_DRNGCLEAR 0x8
27583d3bc6fSnarayan
2763af08d82Slm66018 static boolean_t
ldc_inject_error(ldc_chan_t * ldcp,uint64_t error)27783d3bc6fSnarayan ldc_inject_error(ldc_chan_t *ldcp, uint64_t error)
2783af08d82Slm66018 {
2793af08d82Slm66018 if ((ldcdbgchan != DBG_ALL_LDCS) && (ldcdbgchan != ldcp->id))
2803af08d82Slm66018 return (B_FALSE);
2813af08d82Slm66018
28283d3bc6fSnarayan if ((ldc_inject_err_flag & error) == 0)
2833af08d82Slm66018 return (B_FALSE);
2843af08d82Slm66018
2853af08d82Slm66018 /* clear the injection state */
28683d3bc6fSnarayan ldc_inject_err_flag &= ~error;
2873af08d82Slm66018
2883af08d82Slm66018 return (B_TRUE);
2891ae08745Sheppo }
2901ae08745Sheppo
2911ae08745Sheppo #define D1 \
2921ae08745Sheppo if (ldcdbg & 0x01) \
2931ae08745Sheppo ldcdebug
2941ae08745Sheppo
2951ae08745Sheppo #define D2 \
2961ae08745Sheppo if (ldcdbg & 0x02) \
2971ae08745Sheppo ldcdebug
2981ae08745Sheppo
2991ae08745Sheppo #define DWARN \
3001ae08745Sheppo if (ldcdbg & 0x04) \
3011ae08745Sheppo ldcdebug
3021ae08745Sheppo
3031ae08745Sheppo #define DUMP_PAYLOAD(id, addr) \
3041ae08745Sheppo { \
3051ae08745Sheppo char buf[65*3]; \
3061ae08745Sheppo int i; \
3071ae08745Sheppo uint8_t *src = (uint8_t *)addr; \
3081ae08745Sheppo for (i = 0; i < 64; i++, src++) \
3091ae08745Sheppo (void) sprintf(&buf[i * 3], "|%02x", *src); \
3101ae08745Sheppo (void) sprintf(&buf[i * 3], "|\n"); \
3111ae08745Sheppo D2((id), "payload: %s", buf); \
3121ae08745Sheppo }
3131ae08745Sheppo
3141ae08745Sheppo #define DUMP_LDC_PKT(c, s, addr) \
3151ae08745Sheppo { \
3161ae08745Sheppo ldc_msg_t *msg = (ldc_msg_t *)(addr); \
3171ae08745Sheppo uint32_t mid = ((c)->mode != LDC_MODE_RAW) ? msg->seqid : 0; \
3181ae08745Sheppo if (msg->type == LDC_DATA) { \
3191ae08745Sheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env[%c%c,sz=%d])", \
3201ae08745Sheppo (s), mid, msg->type, msg->stype, msg->ctrl, \
3211ae08745Sheppo (msg->env & LDC_FRAG_START) ? 'B' : ' ', \
3221ae08745Sheppo (msg->env & LDC_FRAG_STOP) ? 'E' : ' ', \
3231ae08745Sheppo (msg->env & LDC_LEN_MASK)); \
3241ae08745Sheppo } else { \
3251ae08745Sheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env=%x)", (s), \
3261ae08745Sheppo mid, msg->type, msg->stype, msg->ctrl, msg->env); \
3271ae08745Sheppo } \
3281ae08745Sheppo }
3291ae08745Sheppo
33083d3bc6fSnarayan #define LDC_INJECT_RESET(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_RESET)
33183d3bc6fSnarayan #define LDC_INJECT_PKTLOSS(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_PKTLOSS)
33258283286Sha137994 #define LDC_INJECT_DQFULL(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DQFULL)
333bbfa0259Sha137994 #define LDC_INJECT_DRNGCLEAR(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DRNGCLEAR)
334bbfa0259Sha137994 extern void i_ldc_mem_inject_dring_clear(ldc_chan_t *ldcp);
3353af08d82Slm66018
3361ae08745Sheppo #else
3371ae08745Sheppo
3381ae08745Sheppo #define DBG_ALL_LDCS -1
3391ae08745Sheppo
3401ae08745Sheppo #define D1
3411ae08745Sheppo #define D2
3421ae08745Sheppo #define DWARN
3431ae08745Sheppo
3441ae08745Sheppo #define DUMP_PAYLOAD(id, addr)
3451ae08745Sheppo #define DUMP_LDC_PKT(c, s, addr)
3461ae08745Sheppo
3473af08d82Slm66018 #define LDC_INJECT_RESET(_ldcp) (B_FALSE)
34883d3bc6fSnarayan #define LDC_INJECT_PKTLOSS(_ldcp) (B_FALSE)
34958283286Sha137994 #define LDC_INJECT_DQFULL(_ldcp) (B_FALSE)
350bbfa0259Sha137994 #define LDC_INJECT_DRNGCLEAR(_ldcp) (B_FALSE)
3513af08d82Slm66018
3521ae08745Sheppo #endif
3531ae08745Sheppo
35458283286Sha137994 /*
35558283286Sha137994 * dtrace SDT probes to ease tracing of the rx data queue and HV queue
35658283286Sha137994 * lengths. Just pass the head, tail, and entries values so that the
35758283286Sha137994 * length can be calculated in a dtrace script when the probe is enabled.
35858283286Sha137994 */
35958283286Sha137994 #define TRACE_RXDQ_LENGTH(ldcp) \
36058283286Sha137994 DTRACE_PROBE4(rxdq__size, \
36158283286Sha137994 uint64_t, ldcp->id, \
36258283286Sha137994 uint64_t, ldcp->rx_dq_head, \
36358283286Sha137994 uint64_t, ldcp->rx_dq_tail, \
36458283286Sha137994 uint64_t, ldcp->rx_dq_entries)
36558283286Sha137994
36658283286Sha137994 #define TRACE_RXHVQ_LENGTH(ldcp, head, tail) \
36758283286Sha137994 DTRACE_PROBE4(rxhvq__size, \
36858283286Sha137994 uint64_t, ldcp->id, \
36958283286Sha137994 uint64_t, head, \
37058283286Sha137994 uint64_t, tail, \
37158283286Sha137994 uint64_t, ldcp->rx_q_entries)
37258283286Sha137994
37358283286Sha137994 /* A dtrace SDT probe to ease tracing of data queue copy operations */
37458283286Sha137994 #define TRACE_RXDQ_COPY(ldcp, bytes) \
37558283286Sha137994 DTRACE_PROBE2(rxdq__copy, uint64_t, ldcp->id, uint64_t, bytes) \
37658283286Sha137994
37758283286Sha137994 /* The amount of contiguous space at the tail of the queue */
37858283286Sha137994 #define Q_CONTIG_SPACE(head, tail, size) \
37958283286Sha137994 ((head) <= (tail) ? ((size) - (tail)) : \
38058283286Sha137994 ((head) - (tail) - LDC_PACKET_SIZE))
38158283286Sha137994
3821ae08745Sheppo #define ZERO_PKT(p) \
3831ae08745Sheppo bzero((p), sizeof (ldc_msg_t));
3841ae08745Sheppo
3851ae08745Sheppo #define IDX2COOKIE(idx, pg_szc, pg_shift) \
3861ae08745Sheppo (((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift)))
3871ae08745Sheppo
3881ae08745Sheppo int
_init(void)3891ae08745Sheppo _init(void)
3901ae08745Sheppo {
3911ae08745Sheppo int status;
3921ae08745Sheppo
3931ae08745Sheppo status = hsvc_register(&ldc_hsvc, &ldc_sup_minor);
3941ae08745Sheppo if (status != 0) {
395d66f8315Sjb145095 cmn_err(CE_NOTE, "!%s: cannot negotiate hypervisor LDC services"
3961ae08745Sheppo " group: 0x%lx major: %ld minor: %ld errno: %d",
3971ae08745Sheppo ldc_hsvc.hsvc_modname, ldc_hsvc.hsvc_group,
3981ae08745Sheppo ldc_hsvc.hsvc_major, ldc_hsvc.hsvc_minor, status);
3991ae08745Sheppo return (-1);
4001ae08745Sheppo }
4011ae08745Sheppo
402bbfa0259Sha137994 /* Initialize shared memory HV API version checking */
403bbfa0259Sha137994 i_ldc_mem_set_hsvc_vers(ldc_hsvc.hsvc_major, ldc_sup_minor);
404bbfa0259Sha137994
4051ae08745Sheppo /* allocate soft state structure */
4061ae08745Sheppo ldcssp = kmem_zalloc(sizeof (ldc_soft_state_t), KM_SLEEP);
4071ae08745Sheppo
408*34f94fbcSWENTAO YANG i_ldc_init_mapin(ldcssp, ldc_hsvc.hsvc_major, ldc_sup_minor);
409*34f94fbcSWENTAO YANG
4101ae08745Sheppo /* Link the module into the system */
4111ae08745Sheppo status = mod_install(&ml);
4121ae08745Sheppo if (status != 0) {
4131ae08745Sheppo kmem_free(ldcssp, sizeof (ldc_soft_state_t));
4141ae08745Sheppo return (status);
4151ae08745Sheppo }
4161ae08745Sheppo
4171ae08745Sheppo /* Initialize the LDC state structure */
4181ae08745Sheppo mutex_init(&ldcssp->lock, NULL, MUTEX_DRIVER, NULL);
4191ae08745Sheppo
4201ae08745Sheppo mutex_enter(&ldcssp->lock);
4211ae08745Sheppo
4224bac2208Snarayan /* Create a cache for memory handles */
4234bac2208Snarayan ldcssp->memhdl_cache = kmem_cache_create("ldc_memhdl_cache",
4244bac2208Snarayan sizeof (ldc_mhdl_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
4254bac2208Snarayan if (ldcssp->memhdl_cache == NULL) {
4264bac2208Snarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memhdl cache create failed\n");
4274bac2208Snarayan mutex_exit(&ldcssp->lock);
4284bac2208Snarayan return (-1);
4294bac2208Snarayan }
4304bac2208Snarayan
4314bac2208Snarayan /* Create cache for memory segment structures */
4324bac2208Snarayan ldcssp->memseg_cache = kmem_cache_create("ldc_memseg_cache",
4334bac2208Snarayan sizeof (ldc_memseg_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
4344bac2208Snarayan if (ldcssp->memseg_cache == NULL) {
4354bac2208Snarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memseg cache create failed\n");
4364bac2208Snarayan mutex_exit(&ldcssp->lock);
4374bac2208Snarayan return (-1);
4384bac2208Snarayan }
4394bac2208Snarayan
4404bac2208Snarayan
4411ae08745Sheppo ldcssp->channel_count = 0;
4421ae08745Sheppo ldcssp->channels_open = 0;
4431ae08745Sheppo ldcssp->chan_list = NULL;
4441ae08745Sheppo ldcssp->dring_list = NULL;
4451ae08745Sheppo
4465699897cSHaik Aftandilian /* Register debug_enter callback */
4475699897cSHaik Aftandilian kldc_set_debug_cb(&i_ldc_debug_enter);
4485699897cSHaik Aftandilian
4491ae08745Sheppo mutex_exit(&ldcssp->lock);
4501ae08745Sheppo
4511ae08745Sheppo return (0);
4521ae08745Sheppo }
4531ae08745Sheppo
4541ae08745Sheppo int
_info(struct modinfo * modinfop)4551ae08745Sheppo _info(struct modinfo *modinfop)
4561ae08745Sheppo {
4571ae08745Sheppo /* Report status of the dynamically loadable driver module */
4581ae08745Sheppo return (mod_info(&ml, modinfop));
4591ae08745Sheppo }
4601ae08745Sheppo
4611ae08745Sheppo int
_fini(void)4621ae08745Sheppo _fini(void)
4631ae08745Sheppo {
4641ae08745Sheppo int rv, status;
46522f747efSnarayan ldc_chan_t *tmp_ldcp, *ldcp;
46622f747efSnarayan ldc_dring_t *tmp_dringp, *dringp;
4671ae08745Sheppo ldc_mem_info_t minfo;
4681ae08745Sheppo
4691ae08745Sheppo /* Unlink the driver module from the system */
4701ae08745Sheppo status = mod_remove(&ml);
4711ae08745Sheppo if (status) {
4721ae08745Sheppo DWARN(DBG_ALL_LDCS, "_fini: mod_remove failed\n");
4731ae08745Sheppo return (EIO);
4741ae08745Sheppo }
4751ae08745Sheppo
4765699897cSHaik Aftandilian /* Unregister debug_enter callback */
4775699897cSHaik Aftandilian kldc_set_debug_cb(NULL);
4785699897cSHaik Aftandilian
4791ae08745Sheppo /* Free descriptor rings */
4801ae08745Sheppo dringp = ldcssp->dring_list;
4811ae08745Sheppo while (dringp != NULL) {
48222f747efSnarayan tmp_dringp = dringp->next;
4831ae08745Sheppo
4841ae08745Sheppo rv = ldc_mem_dring_info((ldc_dring_handle_t)dringp, &minfo);
4851ae08745Sheppo if (rv == 0 && minfo.status != LDC_UNBOUND) {
4861ae08745Sheppo if (minfo.status == LDC_BOUND) {
4871ae08745Sheppo (void) ldc_mem_dring_unbind(
4881ae08745Sheppo (ldc_dring_handle_t)dringp);
4891ae08745Sheppo }
4901ae08745Sheppo if (minfo.status == LDC_MAPPED) {
4911ae08745Sheppo (void) ldc_mem_dring_unmap(
4921ae08745Sheppo (ldc_dring_handle_t)dringp);
4931ae08745Sheppo }
4941ae08745Sheppo }
4951ae08745Sheppo
4961ae08745Sheppo (void) ldc_mem_dring_destroy((ldc_dring_handle_t)dringp);
49722f747efSnarayan dringp = tmp_dringp;
4981ae08745Sheppo }
4991ae08745Sheppo ldcssp->dring_list = NULL;
5001ae08745Sheppo
50122f747efSnarayan /* close and finalize channels */
50222f747efSnarayan ldcp = ldcssp->chan_list;
50322f747efSnarayan while (ldcp != NULL) {
50422f747efSnarayan tmp_ldcp = ldcp->next;
50522f747efSnarayan
50622f747efSnarayan (void) ldc_close((ldc_handle_t)ldcp);
50722f747efSnarayan (void) ldc_fini((ldc_handle_t)ldcp);
50822f747efSnarayan
50922f747efSnarayan ldcp = tmp_ldcp;
51022f747efSnarayan }
51122f747efSnarayan ldcssp->chan_list = NULL;
51222f747efSnarayan
5134bac2208Snarayan /* Destroy kmem caches */
5144bac2208Snarayan kmem_cache_destroy(ldcssp->memhdl_cache);
5154bac2208Snarayan kmem_cache_destroy(ldcssp->memseg_cache);
5164bac2208Snarayan
5171ae08745Sheppo /*
5181ae08745Sheppo * We have successfully "removed" the driver.
5191ae08745Sheppo * Destroying soft states
5201ae08745Sheppo */
5211ae08745Sheppo mutex_destroy(&ldcssp->lock);
5221ae08745Sheppo kmem_free(ldcssp, sizeof (ldc_soft_state_t));
5231ae08745Sheppo
5241ae08745Sheppo (void) hsvc_unregister(&ldc_hsvc);
5251ae08745Sheppo
5261ae08745Sheppo return (status);
5271ae08745Sheppo }
5281ae08745Sheppo
5291ae08745Sheppo /* -------------------------------------------------------------------------- */
5301ae08745Sheppo
5311ae08745Sheppo /*
532e1ebb9ecSlm66018 * LDC Link Layer Internal Functions
5331ae08745Sheppo */
5341ae08745Sheppo
5351ae08745Sheppo /*
5361ae08745Sheppo * Translate HV Errors to sun4v error codes
5371ae08745Sheppo */
53820ae46ebSha137994 int
i_ldc_h2v_error(int h_error)5391ae08745Sheppo i_ldc_h2v_error(int h_error)
5401ae08745Sheppo {
5411ae08745Sheppo switch (h_error) {
5421ae08745Sheppo
5431ae08745Sheppo case H_EOK:
5441ae08745Sheppo return (0);
5451ae08745Sheppo
5461ae08745Sheppo case H_ENORADDR:
5471ae08745Sheppo return (EFAULT);
5481ae08745Sheppo
5491ae08745Sheppo case H_EBADPGSZ:
5501ae08745Sheppo case H_EINVAL:
5511ae08745Sheppo return (EINVAL);
5521ae08745Sheppo
5531ae08745Sheppo case H_EWOULDBLOCK:
5541ae08745Sheppo return (EWOULDBLOCK);
5551ae08745Sheppo
5561ae08745Sheppo case H_ENOACCESS:
5571ae08745Sheppo case H_ENOMAP:
5581ae08745Sheppo return (EACCES);
5591ae08745Sheppo
5601ae08745Sheppo case H_EIO:
5611ae08745Sheppo case H_ECPUERROR:
5621ae08745Sheppo return (EIO);
5631ae08745Sheppo
5641ae08745Sheppo case H_ENOTSUPPORTED:
5651ae08745Sheppo return (ENOTSUP);
5661ae08745Sheppo
5671ae08745Sheppo case H_ETOOMANY:
5681ae08745Sheppo return (ENOSPC);
5691ae08745Sheppo
5701ae08745Sheppo case H_ECHANNEL:
5711ae08745Sheppo return (ECHRNG);
5721ae08745Sheppo default:
5731ae08745Sheppo break;
5741ae08745Sheppo }
5751ae08745Sheppo
5761ae08745Sheppo return (EIO);
5771ae08745Sheppo }
5781ae08745Sheppo
5791ae08745Sheppo /*
5801ae08745Sheppo * Reconfigure the transmit queue
5811ae08745Sheppo */
5821ae08745Sheppo static int
i_ldc_txq_reconf(ldc_chan_t * ldcp)5831ae08745Sheppo i_ldc_txq_reconf(ldc_chan_t *ldcp)
5841ae08745Sheppo {
5851ae08745Sheppo int rv;
5861ae08745Sheppo
5871ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock));
588d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock));
589d10e4ef2Snarayan
5901ae08745Sheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
5911ae08745Sheppo if (rv) {
5921ae08745Sheppo cmn_err(CE_WARN,
5933af08d82Slm66018 "i_ldc_txq_reconf: (0x%lx) cannot set qconf", ldcp->id);
5941ae08745Sheppo return (EIO);
5951ae08745Sheppo }
5961ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, &(ldcp->tx_head),
5971ae08745Sheppo &(ldcp->tx_tail), &(ldcp->link_state));
5981ae08745Sheppo if (rv) {
5991ae08745Sheppo cmn_err(CE_WARN,
6003af08d82Slm66018 "i_ldc_txq_reconf: (0x%lx) cannot get qptrs", ldcp->id);
6011ae08745Sheppo return (EIO);
6021ae08745Sheppo }
6033af08d82Slm66018 D1(ldcp->id, "i_ldc_txq_reconf: (0x%llx) h=0x%llx,t=0x%llx,"
6041ae08745Sheppo "s=0x%llx\n", ldcp->id, ldcp->tx_head, ldcp->tx_tail,
6051ae08745Sheppo ldcp->link_state);
6061ae08745Sheppo
6071ae08745Sheppo return (0);
6081ae08745Sheppo }
6091ae08745Sheppo
6101ae08745Sheppo /*
6111ae08745Sheppo * Reconfigure the receive queue
6121ae08745Sheppo */
6131ae08745Sheppo static int
i_ldc_rxq_reconf(ldc_chan_t * ldcp,boolean_t force_reset)6143af08d82Slm66018 i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset)
6151ae08745Sheppo {
6161ae08745Sheppo int rv;
6171ae08745Sheppo uint64_t rx_head, rx_tail;
6181ae08745Sheppo
6191ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock));
6201ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
6211ae08745Sheppo &(ldcp->link_state));
6221ae08745Sheppo if (rv) {
6231ae08745Sheppo cmn_err(CE_WARN,
6243af08d82Slm66018 "i_ldc_rxq_reconf: (0x%lx) cannot get state",
6251ae08745Sheppo ldcp->id);
6261ae08745Sheppo return (EIO);
6271ae08745Sheppo }
6281ae08745Sheppo
6293af08d82Slm66018 if (force_reset || (ldcp->tstate & ~TS_IN_RESET) == TS_UP) {
6301ae08745Sheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra,
6311ae08745Sheppo ldcp->rx_q_entries);
6321ae08745Sheppo if (rv) {
6331ae08745Sheppo cmn_err(CE_WARN,
6343af08d82Slm66018 "i_ldc_rxq_reconf: (0x%lx) cannot set qconf",
6351ae08745Sheppo ldcp->id);
6361ae08745Sheppo return (EIO);
6371ae08745Sheppo }
6383af08d82Slm66018 D1(ldcp->id, "i_ldc_rxq_reconf: (0x%llx) completed q reconf",
6391ae08745Sheppo ldcp->id);
6401ae08745Sheppo }
6411ae08745Sheppo
6421ae08745Sheppo return (0);
6431ae08745Sheppo }
6441ae08745Sheppo
645a8ea4edeSnarayan
646a8ea4edeSnarayan /*
647a8ea4edeSnarayan * Drain the contents of the receive queue
648a8ea4edeSnarayan */
649305dbad4SKevin Crowe static void
i_ldc_rxq_drain(ldc_chan_t * ldcp)650a8ea4edeSnarayan i_ldc_rxq_drain(ldc_chan_t *ldcp)
651a8ea4edeSnarayan {
652a8ea4edeSnarayan int rv;
653a8ea4edeSnarayan uint64_t rx_head, rx_tail;
654305dbad4SKevin Crowe int retries = 0;
655a8ea4edeSnarayan
656a8ea4edeSnarayan ASSERT(MUTEX_HELD(&ldcp->lock));
657a8ea4edeSnarayan rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
658a8ea4edeSnarayan &(ldcp->link_state));
659a8ea4edeSnarayan if (rv) {
660305dbad4SKevin Crowe cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot get state, "
661305dbad4SKevin Crowe "rv = 0x%x", ldcp->id, rv);
662305dbad4SKevin Crowe return;
663a8ea4edeSnarayan }
664a8ea4edeSnarayan
66532225099SZach Kissel /* If the queue is already empty just return success. */
66632225099SZach Kissel if (rx_head == rx_tail)
667305dbad4SKevin Crowe return;
66832225099SZach Kissel
669305dbad4SKevin Crowe /*
670305dbad4SKevin Crowe * We are draining the queue in order to close the channel.
671305dbad4SKevin Crowe * Call hv_ldc_rx_set_qhead directly instead of i_ldc_set_rx_head
672305dbad4SKevin Crowe * because we do not need to reset the channel if the set
673305dbad4SKevin Crowe * qhead fails.
674305dbad4SKevin Crowe */
675305dbad4SKevin Crowe if ((rv = hv_ldc_rx_set_qhead(ldcp->id, rx_tail)) == 0)
676305dbad4SKevin Crowe return;
677305dbad4SKevin Crowe
678305dbad4SKevin Crowe while ((rv == H_EWOULDBLOCK) && (retries++ < ldc_max_retries)) {
679305dbad4SKevin Crowe drv_usecwait(ldc_delay);
680305dbad4SKevin Crowe if ((rv = hv_ldc_rx_set_qhead(ldcp->id, rx_tail)) == 0)
681305dbad4SKevin Crowe return;
682305dbad4SKevin Crowe }
683305dbad4SKevin Crowe
684305dbad4SKevin Crowe cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot set qhead 0x%lx, "
685305dbad4SKevin Crowe "rv = 0x%x", ldcp->id, rx_tail, rv);
686a8ea4edeSnarayan }
687a8ea4edeSnarayan
688a8ea4edeSnarayan
6891ae08745Sheppo /*
6901ae08745Sheppo * Reset LDC state structure and its contents
6911ae08745Sheppo */
6921ae08745Sheppo static void
i_ldc_reset_state(ldc_chan_t * ldcp)6931ae08745Sheppo i_ldc_reset_state(ldc_chan_t *ldcp)
6941ae08745Sheppo {
6951ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock));
6961ae08745Sheppo ldcp->last_msg_snt = LDC_INIT_SEQID;
6971ae08745Sheppo ldcp->last_ack_rcd = 0;
6981ae08745Sheppo ldcp->last_msg_rcd = 0;
6991ae08745Sheppo ldcp->tx_ackd_head = ldcp->tx_head;
70058283286Sha137994 ldcp->stream_remains = 0;
7011ae08745Sheppo ldcp->next_vidx = 0;
7021ae08745Sheppo ldcp->hstate = 0;
7031ae08745Sheppo ldcp->tstate = TS_OPEN;
7041ae08745Sheppo ldcp->status = LDC_OPEN;
70558283286Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
70658283286Sha137994 ldcp->rx_dq_head = 0;
70758283286Sha137994 ldcp->rx_dq_tail = 0;
7081ae08745Sheppo
7091ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_UP ||
7101ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) {
7111ae08745Sheppo
7121ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW) {
7131ae08745Sheppo ldcp->status = LDC_UP;
7141ae08745Sheppo ldcp->tstate = TS_UP;
7151ae08745Sheppo } else {
7161ae08745Sheppo ldcp->status = LDC_READY;
7171ae08745Sheppo ldcp->tstate |= TS_LINK_READY;
7181ae08745Sheppo }
7191ae08745Sheppo }
7201ae08745Sheppo }
7211ae08745Sheppo
7221ae08745Sheppo /*
7231ae08745Sheppo * Reset a LDC channel
7241ae08745Sheppo */
72520ae46ebSha137994 void
i_ldc_reset(ldc_chan_t * ldcp,boolean_t force_reset)7263af08d82Slm66018 i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset)
7271ae08745Sheppo {
72883d3bc6fSnarayan DWARN(ldcp->id, "i_ldc_reset: (0x%llx) channel reset\n", ldcp->id);
7291ae08745Sheppo
730d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->lock));
731d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock));
732d10e4ef2Snarayan
7333af08d82Slm66018 /* reconfig Tx and Rx queues */
7341ae08745Sheppo (void) i_ldc_txq_reconf(ldcp);
7353af08d82Slm66018 (void) i_ldc_rxq_reconf(ldcp, force_reset);
7363af08d82Slm66018
7373af08d82Slm66018 /* Clear Tx and Rx interrupts */
7383af08d82Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
7393af08d82Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
7403af08d82Slm66018
7413af08d82Slm66018 /* Reset channel state */
7421ae08745Sheppo i_ldc_reset_state(ldcp);
7433af08d82Slm66018
7443af08d82Slm66018 /* Mark channel in reset */
7453af08d82Slm66018 ldcp->tstate |= TS_IN_RESET;
7461ae08745Sheppo }
7471ae08745Sheppo
7485699897cSHaik Aftandilian /*
7495699897cSHaik Aftandilian * Walk the channel list and reset channels if they are of the right
7505699897cSHaik Aftandilian * devclass and their Rx queues have been configured. No locks are
7515699897cSHaik Aftandilian * taken because the function is only invoked by the kernel just before
7525699897cSHaik Aftandilian * entering the prom or debugger when the system is single-threaded.
7535699897cSHaik Aftandilian */
7545699897cSHaik Aftandilian static void
i_ldc_debug_enter(void)7555699897cSHaik Aftandilian i_ldc_debug_enter(void)
7565699897cSHaik Aftandilian {
7575699897cSHaik Aftandilian ldc_chan_t *ldcp;
7585699897cSHaik Aftandilian
7595699897cSHaik Aftandilian ldcp = ldcssp->chan_list;
7605699897cSHaik Aftandilian while (ldcp != NULL) {
7615699897cSHaik Aftandilian if (((ldcp->tstate & TS_QCONF_RDY) == TS_QCONF_RDY) &&
7625699897cSHaik Aftandilian (LDC_DEVCLASS_PROM_RESET(ldcp->devclass) != 0)) {
7635699897cSHaik Aftandilian (void) hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra,
7645699897cSHaik Aftandilian ldcp->rx_q_entries);
7655699897cSHaik Aftandilian }
7665699897cSHaik Aftandilian ldcp = ldcp->next;
7675699897cSHaik Aftandilian }
7685699897cSHaik Aftandilian }
7694bac2208Snarayan
7701ae08745Sheppo /*
7711ae08745Sheppo * Clear pending interrupts
7721ae08745Sheppo */
7731ae08745Sheppo static void
i_ldc_clear_intr(ldc_chan_t * ldcp,cnex_intrtype_t itype)7741ae08745Sheppo i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype)
7751ae08745Sheppo {
7761ae08745Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo;
7771ae08745Sheppo
7781ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock));
7793af08d82Slm66018 ASSERT(cinfo->dip != NULL);
7804bac2208Snarayan
7813af08d82Slm66018 switch (itype) {
7823af08d82Slm66018 case CNEX_TX_INTR:
7834bac2208Snarayan /* check Tx interrupt */
7843af08d82Slm66018 if (ldcp->tx_intr_state)
7853af08d82Slm66018 ldcp->tx_intr_state = LDC_INTR_NONE;
7864bac2208Snarayan else
7874bac2208Snarayan return;
7883af08d82Slm66018 break;
7893af08d82Slm66018
7903af08d82Slm66018 case CNEX_RX_INTR:
7914bac2208Snarayan /* check Rx interrupt */
7923af08d82Slm66018 if (ldcp->rx_intr_state)
7933af08d82Slm66018 ldcp->rx_intr_state = LDC_INTR_NONE;
7944bac2208Snarayan else
7954bac2208Snarayan return;
7963af08d82Slm66018 break;
7974bac2208Snarayan }
7984bac2208Snarayan
7991ae08745Sheppo (void) cinfo->clr_intr(cinfo->dip, ldcp->id, itype);
8004bac2208Snarayan D2(ldcp->id,
8014bac2208Snarayan "i_ldc_clear_intr: (0x%llx) cleared 0x%x intr\n",
8024bac2208Snarayan ldcp->id, itype);
8031ae08745Sheppo }
8041ae08745Sheppo
8051ae08745Sheppo /*
8061ae08745Sheppo * Set the receive queue head
8070a55fbb7Slm66018 * Resets connection and returns an error if it fails.
8081ae08745Sheppo */
8091ae08745Sheppo static int
i_ldc_set_rx_head(ldc_chan_t * ldcp,uint64_t head)8101ae08745Sheppo i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head)
8111ae08745Sheppo {
8121ae08745Sheppo int rv;
8130a55fbb7Slm66018 int retries;
8141ae08745Sheppo
8151ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock));
8160a55fbb7Slm66018 for (retries = 0; retries < ldc_max_retries; retries++) {
8170a55fbb7Slm66018
8180a55fbb7Slm66018 if ((rv = hv_ldc_rx_set_qhead(ldcp->id, head)) == 0)
8190a55fbb7Slm66018 return (0);
8200a55fbb7Slm66018
8210a55fbb7Slm66018 if (rv != H_EWOULDBLOCK)
8220a55fbb7Slm66018 break;
8230a55fbb7Slm66018
8240a55fbb7Slm66018 /* wait for ldc_delay usecs */
8250a55fbb7Slm66018 drv_usecwait(ldc_delay);
8261ae08745Sheppo }
8271ae08745Sheppo
828305dbad4SKevin Crowe cmn_err(CE_WARN, "ldc_set_rx_qhead: (0x%lx) cannot set qhead 0x%lx, "
829305dbad4SKevin Crowe "rv = 0x%x", ldcp->id, head, rv);
830d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
8313af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
832d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
8330a55fbb7Slm66018
8340a55fbb7Slm66018 return (ECONNRESET);
8351ae08745Sheppo }
8361ae08745Sheppo
83722f747efSnarayan /*
83822f747efSnarayan * Returns the tx_head to be used for transfer
83922f747efSnarayan */
84022f747efSnarayan static void
i_ldc_get_tx_head(ldc_chan_t * ldcp,uint64_t * head)84122f747efSnarayan i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head)
84222f747efSnarayan {
84322f747efSnarayan ldc_msg_t *pkt;
84422f747efSnarayan
84522f747efSnarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock));
84622f747efSnarayan
84722f747efSnarayan /* get current Tx head */
84822f747efSnarayan *head = ldcp->tx_head;
84922f747efSnarayan
85022f747efSnarayan /*
85122f747efSnarayan * Reliable mode will use the ACKd head instead of the regular tx_head.
85222f747efSnarayan * Also in Reliable mode, advance ackd_head for all non DATA/INFO pkts,
85322f747efSnarayan * up to the current location of tx_head. This needs to be done
85422f747efSnarayan * as the peer will only ACK DATA/INFO pkts.
85522f747efSnarayan */
85620ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) {
85722f747efSnarayan while (ldcp->tx_ackd_head != ldcp->tx_head) {
85822f747efSnarayan pkt = (ldc_msg_t *)(ldcp->tx_q_va + ldcp->tx_ackd_head);
85922f747efSnarayan if ((pkt->type & LDC_DATA) && (pkt->stype & LDC_INFO)) {
86022f747efSnarayan break;
86122f747efSnarayan }
86222f747efSnarayan /* advance ACKd head */
86322f747efSnarayan ldcp->tx_ackd_head =
86422f747efSnarayan (ldcp->tx_ackd_head + LDC_PACKET_SIZE) %
86522f747efSnarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
86622f747efSnarayan }
86722f747efSnarayan *head = ldcp->tx_ackd_head;
86822f747efSnarayan }
86922f747efSnarayan }
8701ae08745Sheppo
8711ae08745Sheppo /*
8721ae08745Sheppo * Returns the tx_tail to be used for transfer
8731ae08745Sheppo * Re-reads the TX queue ptrs if and only if the
8741ae08745Sheppo * the cached head and tail are equal (queue is full)
8751ae08745Sheppo */
8761ae08745Sheppo static int
i_ldc_get_tx_tail(ldc_chan_t * ldcp,uint64_t * tail)8771ae08745Sheppo i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail)
8781ae08745Sheppo {
8791ae08745Sheppo int rv;
8801ae08745Sheppo uint64_t current_head, new_tail;
8811ae08745Sheppo
882d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock));
8831ae08745Sheppo /* Read the head and tail ptrs from HV */
8841ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id,
8851ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
8861ae08745Sheppo if (rv) {
8871ae08745Sheppo cmn_err(CE_WARN,
8881ae08745Sheppo "i_ldc_get_tx_tail: (0x%lx) cannot read qptrs\n",
8891ae08745Sheppo ldcp->id);
8901ae08745Sheppo return (EIO);
8911ae08745Sheppo }
8921ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN) {
893cb112a14Slm66018 D1(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) channel not ready\n",
8941ae08745Sheppo ldcp->id);
8951ae08745Sheppo return (ECONNRESET);
8961ae08745Sheppo }
8971ae08745Sheppo
89822f747efSnarayan i_ldc_get_tx_head(ldcp, ¤t_head);
8991ae08745Sheppo
9001ae08745Sheppo /* increment the tail */
9011ae08745Sheppo new_tail = (ldcp->tx_tail + LDC_PACKET_SIZE) %
9021ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
9031ae08745Sheppo
9041ae08745Sheppo if (new_tail == current_head) {
9051ae08745Sheppo DWARN(ldcp->id,
9061ae08745Sheppo "i_ldc_get_tx_tail: (0x%llx) TX queue is full\n",
9071ae08745Sheppo ldcp->id);
9081ae08745Sheppo return (EWOULDBLOCK);
9091ae08745Sheppo }
9101ae08745Sheppo
9111ae08745Sheppo D2(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) head=0x%llx, tail=0x%llx\n",
9121ae08745Sheppo ldcp->id, ldcp->tx_head, ldcp->tx_tail);
9131ae08745Sheppo
9141ae08745Sheppo *tail = ldcp->tx_tail;
9151ae08745Sheppo return (0);
9161ae08745Sheppo }
9171ae08745Sheppo
9181ae08745Sheppo /*
9191ae08745Sheppo * Set the tail pointer. If HV returns EWOULDBLOCK, it will back off
9200a55fbb7Slm66018 * and retry ldc_max_retries times before returning an error.
9211ae08745Sheppo * Returns 0, EWOULDBLOCK or EIO
9221ae08745Sheppo */
9231ae08745Sheppo static int
i_ldc_set_tx_tail(ldc_chan_t * ldcp,uint64_t tail)9241ae08745Sheppo i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail)
9251ae08745Sheppo {
9261ae08745Sheppo int rv, retval = EWOULDBLOCK;
9270a55fbb7Slm66018 int retries;
9281ae08745Sheppo
929d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock));
9300a55fbb7Slm66018 for (retries = 0; retries < ldc_max_retries; retries++) {
9311ae08745Sheppo
9321ae08745Sheppo if ((rv = hv_ldc_tx_set_qtail(ldcp->id, tail)) == 0) {
9331ae08745Sheppo retval = 0;
9341ae08745Sheppo break;
9351ae08745Sheppo }
9361ae08745Sheppo if (rv != H_EWOULDBLOCK) {
9371ae08745Sheppo DWARN(ldcp->id, "i_ldc_set_tx_tail: (0x%llx) set "
9381ae08745Sheppo "qtail=0x%llx failed, rv=%d\n", ldcp->id, tail, rv);
9391ae08745Sheppo retval = EIO;
9401ae08745Sheppo break;
9411ae08745Sheppo }
9421ae08745Sheppo
9430a55fbb7Slm66018 /* wait for ldc_delay usecs */
9440a55fbb7Slm66018 drv_usecwait(ldc_delay);
9451ae08745Sheppo }
9461ae08745Sheppo return (retval);
9471ae08745Sheppo }
9481ae08745Sheppo
9491ae08745Sheppo /*
95058283286Sha137994 * Copy a data packet from the HV receive queue to the data queue.
95158283286Sha137994 * Caller must ensure that the data queue is not already full.
95258283286Sha137994 *
95358283286Sha137994 * The *head argument represents the current head pointer for the HV
95458283286Sha137994 * receive queue. After copying a packet from the HV receive queue,
95558283286Sha137994 * the *head pointer will be updated. This allows the caller to update
95658283286Sha137994 * the head pointer in HV using the returned *head value.
95758283286Sha137994 */
95858283286Sha137994 void
i_ldc_rxdq_copy(ldc_chan_t * ldcp,uint64_t * head)95958283286Sha137994 i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head)
96058283286Sha137994 {
96158283286Sha137994 uint64_t q_size, dq_size;
96258283286Sha137994
96358283286Sha137994 ASSERT(MUTEX_HELD(&ldcp->lock));
96458283286Sha137994
96558283286Sha137994 q_size = ldcp->rx_q_entries << LDC_PACKET_SHIFT;
96658283286Sha137994 dq_size = ldcp->rx_dq_entries << LDC_PACKET_SHIFT;
96758283286Sha137994
96858283286Sha137994 ASSERT(Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail,
96958283286Sha137994 dq_size) >= LDC_PACKET_SIZE);
97058283286Sha137994
97158283286Sha137994 bcopy((void *)(ldcp->rx_q_va + *head),
97258283286Sha137994 (void *)(ldcp->rx_dq_va + ldcp->rx_dq_tail), LDC_PACKET_SIZE);
97358283286Sha137994 TRACE_RXDQ_COPY(ldcp, LDC_PACKET_SIZE);
97458283286Sha137994
97558283286Sha137994 /* Update rx head */
97658283286Sha137994 *head = (*head + LDC_PACKET_SIZE) % q_size;
97758283286Sha137994
97858283286Sha137994 /* Update dq tail */
97958283286Sha137994 ldcp->rx_dq_tail = (ldcp->rx_dq_tail + LDC_PACKET_SIZE) % dq_size;
98058283286Sha137994 }
98158283286Sha137994
98258283286Sha137994 /*
98358283286Sha137994 * Update the Rx data queue head pointer
98458283286Sha137994 */
98558283286Sha137994 static int
i_ldc_set_rxdq_head(ldc_chan_t * ldcp,uint64_t head)98658283286Sha137994 i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head)
98758283286Sha137994 {
98858283286Sha137994 ldcp->rx_dq_head = head;
98958283286Sha137994 return (0);
99058283286Sha137994 }
99158283286Sha137994
99258283286Sha137994 /*
99358283286Sha137994 * Get the Rx data queue head and tail pointers
99458283286Sha137994 */
99558283286Sha137994 static uint64_t
i_ldc_dq_rx_get_state(ldc_chan_t * ldcp,uint64_t * head,uint64_t * tail,uint64_t * link_state)99658283286Sha137994 i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail,
99758283286Sha137994 uint64_t *link_state)
99858283286Sha137994 {
99958283286Sha137994 _NOTE(ARGUNUSED(link_state))
100058283286Sha137994 *head = ldcp->rx_dq_head;
100158283286Sha137994 *tail = ldcp->rx_dq_tail;
100258283286Sha137994 return (0);
100358283286Sha137994 }
100458283286Sha137994
100558283286Sha137994 /*
100658283286Sha137994 * Wrapper for the Rx HV queue set head function. Giving the
100758283286Sha137994 * data queue and HV queue set head functions the same type.
100858283286Sha137994 */
100958283286Sha137994 static uint64_t
i_ldc_hvq_rx_get_state(ldc_chan_t * ldcp,uint64_t * head,uint64_t * tail,uint64_t * link_state)101058283286Sha137994 i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail,
101158283286Sha137994 uint64_t *link_state)
101258283286Sha137994 {
101358283286Sha137994 return (i_ldc_h2v_error(hv_ldc_rx_get_state(ldcp->id, head, tail,
101458283286Sha137994 link_state)));
101558283286Sha137994 }
101658283286Sha137994
101758283286Sha137994 /*
101858283286Sha137994 * LDC receive interrupt handler
101958283286Sha137994 * triggered for channel with data pending to read
102058283286Sha137994 * i.e. Rx queue content changes
102158283286Sha137994 */
102258283286Sha137994 static uint_t
i_ldc_rx_hdlr(caddr_t arg1,caddr_t arg2)102358283286Sha137994 i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2)
102458283286Sha137994 {
102558283286Sha137994 _NOTE(ARGUNUSED(arg2))
102658283286Sha137994
102758283286Sha137994 ldc_chan_t *ldcp;
102858283286Sha137994 boolean_t notify;
102958283286Sha137994 uint64_t event;
103012f80fa6Sha137994 int rv, status;
103158283286Sha137994
103258283286Sha137994 /* Get the channel for which interrupt was received */
103358283286Sha137994 if (arg1 == NULL) {
103458283286Sha137994 cmn_err(CE_WARN, "i_ldc_rx_hdlr: invalid arg\n");
103558283286Sha137994 return (DDI_INTR_UNCLAIMED);
103658283286Sha137994 }
103758283286Sha137994
103858283286Sha137994 ldcp = (ldc_chan_t *)arg1;
103958283286Sha137994
104058283286Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
104158283286Sha137994 ldcp->id, ldcp);
104258283286Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (%llx) USR%lx/TS%lx/HS%lx, LSTATE=%lx\n",
104358283286Sha137994 ldcp->id, ldcp->status, ldcp->tstate, ldcp->hstate,
104458283286Sha137994 ldcp->link_state);
104558283286Sha137994
104658283286Sha137994 /* Lock channel */
104758283286Sha137994 mutex_enter(&ldcp->lock);
104858283286Sha137994
104958283286Sha137994 /* Mark the interrupt as being actively handled */
105058283286Sha137994 ldcp->rx_intr_state = LDC_INTR_ACTIVE;
105158283286Sha137994
105212f80fa6Sha137994 status = i_ldc_rx_process_hvq(ldcp, ¬ify, &event);
105358283286Sha137994
105420ae46ebSha137994 if (ldcp->mode != LDC_MODE_RELIABLE) {
105558283286Sha137994 /*
105658283286Sha137994 * If there are no data packets on the queue, clear
105758283286Sha137994 * the interrupt. Otherwise, the ldc_read will clear
105858283286Sha137994 * interrupts after draining the queue. To indicate the
105958283286Sha137994 * interrupt has not yet been cleared, it is marked
106058283286Sha137994 * as pending.
106158283286Sha137994 */
106258283286Sha137994 if ((event & LDC_EVT_READ) == 0) {
106358283286Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
106458283286Sha137994 } else {
106558283286Sha137994 ldcp->rx_intr_state = LDC_INTR_PEND;
106658283286Sha137994 }
106758283286Sha137994 }
106858283286Sha137994
106958283286Sha137994 /* if callbacks are disabled, do not notify */
107058283286Sha137994 if (notify && ldcp->cb_enabled) {
107158283286Sha137994 ldcp->cb_inprogress = B_TRUE;
107258283286Sha137994 mutex_exit(&ldcp->lock);
107358283286Sha137994 rv = ldcp->cb(event, ldcp->cb_arg);
107458283286Sha137994 if (rv) {
107558283286Sha137994 DWARN(ldcp->id,
107658283286Sha137994 "i_ldc_rx_hdlr: (0x%llx) callback failure",
107758283286Sha137994 ldcp->id);
107858283286Sha137994 }
107958283286Sha137994 mutex_enter(&ldcp->lock);
108058283286Sha137994 ldcp->cb_inprogress = B_FALSE;
108158283286Sha137994 }
108258283286Sha137994
108320ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) {
108412f80fa6Sha137994 if (status == ENOSPC) {
108558283286Sha137994 /*
108612f80fa6Sha137994 * Here, ENOSPC indicates the secondary data
108712f80fa6Sha137994 * queue is full and the Rx queue is non-empty.
108812f80fa6Sha137994 * Much like how reliable and raw modes are
108912f80fa6Sha137994 * handled above, since the Rx queue is non-
109012f80fa6Sha137994 * empty, we mark the interrupt as pending to
109112f80fa6Sha137994 * indicate it has not yet been cleared.
109212f80fa6Sha137994 */
109312f80fa6Sha137994 ldcp->rx_intr_state = LDC_INTR_PEND;
109412f80fa6Sha137994 } else {
109512f80fa6Sha137994 /*
109612f80fa6Sha137994 * We have processed all CTRL packets and
109712f80fa6Sha137994 * copied all DATA packets to the secondary
109812f80fa6Sha137994 * queue. Clear the interrupt.
109958283286Sha137994 */
110058283286Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
110158283286Sha137994 }
110212f80fa6Sha137994 }
110358283286Sha137994
110458283286Sha137994 mutex_exit(&ldcp->lock);
110558283286Sha137994
110658283286Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) exiting handler", ldcp->id);
110758283286Sha137994
110858283286Sha137994 return (DDI_INTR_CLAIMED);
110958283286Sha137994 }
111058283286Sha137994
111158283286Sha137994 /*
111258283286Sha137994 * Wrapper for the Rx HV queue processing function to be used when
111358283286Sha137994 * checking the Rx HV queue for data packets. Unlike the interrupt
111458283286Sha137994 * handler code flow, the Rx interrupt is not cleared here and
111558283286Sha137994 * callbacks are not made.
111658283286Sha137994 */
111758283286Sha137994 static uint_t
i_ldc_chkq(ldc_chan_t * ldcp)111858283286Sha137994 i_ldc_chkq(ldc_chan_t *ldcp)
111958283286Sha137994 {
112058283286Sha137994 boolean_t notify;
112158283286Sha137994 uint64_t event;
112258283286Sha137994
112358283286Sha137994 return (i_ldc_rx_process_hvq(ldcp, ¬ify, &event));
112458283286Sha137994 }
112558283286Sha137994
112658283286Sha137994 /*
11271ae08745Sheppo * Send a LDC message
11281ae08745Sheppo */
11291ae08745Sheppo static int
i_ldc_send_pkt(ldc_chan_t * ldcp,uint8_t pkttype,uint8_t subtype,uint8_t ctrlmsg)11301ae08745Sheppo i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
11311ae08745Sheppo uint8_t ctrlmsg)
11321ae08745Sheppo {
11331ae08745Sheppo int rv;
11341ae08745Sheppo ldc_msg_t *pkt;
11351ae08745Sheppo uint64_t tx_tail;
113622f747efSnarayan uint32_t curr_seqid;
11371ae08745Sheppo
1138d10e4ef2Snarayan /* Obtain Tx lock */
1139d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
1140d10e4ef2Snarayan
114122f747efSnarayan curr_seqid = ldcp->last_msg_snt;
114222f747efSnarayan
11431ae08745Sheppo /* get the current tail for the message */
11441ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
11451ae08745Sheppo if (rv) {
11461ae08745Sheppo DWARN(ldcp->id,
11471ae08745Sheppo "i_ldc_send_pkt: (0x%llx) error sending pkt, "
11481ae08745Sheppo "type=0x%x,subtype=0x%x,ctrl=0x%x\n",
11491ae08745Sheppo ldcp->id, pkttype, subtype, ctrlmsg);
1150d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
11511ae08745Sheppo return (rv);
11521ae08745Sheppo }
11531ae08745Sheppo
11541ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
11551ae08745Sheppo ZERO_PKT(pkt);
11561ae08745Sheppo
11571ae08745Sheppo /* Initialize the packet */
11581ae08745Sheppo pkt->type = pkttype;
11591ae08745Sheppo pkt->stype = subtype;
11601ae08745Sheppo pkt->ctrl = ctrlmsg;
11611ae08745Sheppo
11621ae08745Sheppo /* Store ackid/seqid iff it is RELIABLE mode & not a RTS/RTR message */
11631ae08745Sheppo if (((ctrlmsg & LDC_CTRL_MASK) != LDC_RTS) &&
11641ae08745Sheppo ((ctrlmsg & LDC_CTRL_MASK) != LDC_RTR)) {
11651ae08745Sheppo curr_seqid++;
11661ae08745Sheppo if (ldcp->mode != LDC_MODE_RAW) {
11671ae08745Sheppo pkt->seqid = curr_seqid;
11681ae08745Sheppo pkt->ackid = ldcp->last_msg_rcd;
11691ae08745Sheppo }
11701ae08745Sheppo }
11711ae08745Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_send_pkt", (uint64_t)pkt);
11721ae08745Sheppo
11731ae08745Sheppo /* initiate the send by calling into HV and set the new tail */
11741ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) %
11751ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
11761ae08745Sheppo
11771ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail);
11781ae08745Sheppo if (rv) {
11791ae08745Sheppo DWARN(ldcp->id,
11801ae08745Sheppo "i_ldc_send_pkt:(0x%llx) error sending pkt, "
11811ae08745Sheppo "type=0x%x,stype=0x%x,ctrl=0x%x\n",
11821ae08745Sheppo ldcp->id, pkttype, subtype, ctrlmsg);
1183d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
11841ae08745Sheppo return (EIO);
11851ae08745Sheppo }
11861ae08745Sheppo
11871ae08745Sheppo ldcp->last_msg_snt = curr_seqid;
11881ae08745Sheppo ldcp->tx_tail = tx_tail;
11891ae08745Sheppo
1190d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
11911ae08745Sheppo return (0);
11921ae08745Sheppo }
11931ae08745Sheppo
11941ae08745Sheppo /*
11951ae08745Sheppo * Checks if packet was received in right order
1196e1ebb9ecSlm66018 * in the case of a reliable link.
11971ae08745Sheppo * Returns 0 if in order, else EIO
11981ae08745Sheppo */
11991ae08745Sheppo static int
i_ldc_check_seqid(ldc_chan_t * ldcp,ldc_msg_t * msg)12001ae08745Sheppo i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *msg)
12011ae08745Sheppo {
12021ae08745Sheppo /* No seqid checking for RAW mode */
12031ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW)
12041ae08745Sheppo return (0);
12051ae08745Sheppo
12061ae08745Sheppo /* No seqid checking for version, RTS, RTR message */
12071ae08745Sheppo if (msg->ctrl == LDC_VER ||
12081ae08745Sheppo msg->ctrl == LDC_RTS ||
12091ae08745Sheppo msg->ctrl == LDC_RTR)
12101ae08745Sheppo return (0);
12111ae08745Sheppo
12121ae08745Sheppo /* Initial seqid to use is sent in RTS/RTR and saved in last_msg_rcd */
12131ae08745Sheppo if (msg->seqid != (ldcp->last_msg_rcd + 1)) {
12141ae08745Sheppo DWARN(ldcp->id,
12151ae08745Sheppo "i_ldc_check_seqid: (0x%llx) out-of-order pkt, got 0x%x, "
12161ae08745Sheppo "expecting 0x%x\n", ldcp->id, msg->seqid,
12171ae08745Sheppo (ldcp->last_msg_rcd + 1));
12181ae08745Sheppo return (EIO);
12191ae08745Sheppo }
12201ae08745Sheppo
122183d3bc6fSnarayan #ifdef DEBUG
122283d3bc6fSnarayan if (LDC_INJECT_PKTLOSS(ldcp)) {
122383d3bc6fSnarayan DWARN(ldcp->id,
122483d3bc6fSnarayan "i_ldc_check_seqid: (0x%llx) inject pkt loss\n", ldcp->id);
122583d3bc6fSnarayan return (EIO);
122683d3bc6fSnarayan }
122783d3bc6fSnarayan #endif
122883d3bc6fSnarayan
12291ae08745Sheppo return (0);
12301ae08745Sheppo }
12311ae08745Sheppo
12321ae08745Sheppo
12331ae08745Sheppo /*
12341ae08745Sheppo * Process an incoming version ctrl message
12351ae08745Sheppo */
12361ae08745Sheppo static int
i_ldc_process_VER(ldc_chan_t * ldcp,ldc_msg_t * msg)12371ae08745Sheppo i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg)
12381ae08745Sheppo {
12391ae08745Sheppo int rv = 0, idx = ldcp->next_vidx;
12401ae08745Sheppo ldc_msg_t *pkt;
12411ae08745Sheppo uint64_t tx_tail;
12421ae08745Sheppo ldc_ver_t *rcvd_ver;
12431ae08745Sheppo
12441ae08745Sheppo /* get the received version */
12451ae08745Sheppo rcvd_ver = (ldc_ver_t *)((uint64_t)msg + LDC_PAYLOAD_VER_OFF);
12461ae08745Sheppo
12471ae08745Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) received VER v%u.%u\n",
12481ae08745Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor);
12491ae08745Sheppo
1250d10e4ef2Snarayan /* Obtain Tx lock */
1251d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
1252d10e4ef2Snarayan
12531ae08745Sheppo switch (msg->stype) {
12541ae08745Sheppo case LDC_INFO:
12551ae08745Sheppo
12563af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) {
12573af08d82Slm66018 (void) i_ldc_txq_reconf(ldcp);
12583af08d82Slm66018 i_ldc_reset_state(ldcp);
12593af08d82Slm66018 mutex_exit(&ldcp->tx_lock);
12603af08d82Slm66018 return (EAGAIN);
12613af08d82Slm66018 }
12623af08d82Slm66018
12631ae08745Sheppo /* get the current tail and pkt for the response */
12641ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
12651ae08745Sheppo if (rv != 0) {
12661ae08745Sheppo DWARN(ldcp->id,
12671ae08745Sheppo "i_ldc_process_VER: (0x%llx) err sending "
12681ae08745Sheppo "version ACK/NACK\n", ldcp->id);
12693af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1270d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
12711ae08745Sheppo return (ECONNRESET);
12721ae08745Sheppo }
12731ae08745Sheppo
12741ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
12751ae08745Sheppo ZERO_PKT(pkt);
12761ae08745Sheppo
12771ae08745Sheppo /* initialize the packet */
12781ae08745Sheppo pkt->type = LDC_CTRL;
12791ae08745Sheppo pkt->ctrl = LDC_VER;
12801ae08745Sheppo
12811ae08745Sheppo for (;;) {
12821ae08745Sheppo
12831ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: got %u.%u chk %u.%u\n",
12841ae08745Sheppo rcvd_ver->major, rcvd_ver->minor,
12851ae08745Sheppo ldc_versions[idx].major, ldc_versions[idx].minor);
12861ae08745Sheppo
12871ae08745Sheppo if (rcvd_ver->major == ldc_versions[idx].major) {
12881ae08745Sheppo /* major version match - ACK version */
12891ae08745Sheppo pkt->stype = LDC_ACK;
12901ae08745Sheppo
12911ae08745Sheppo /*
12921ae08745Sheppo * lower minor version to the one this endpt
12931ae08745Sheppo * supports, if necessary
12941ae08745Sheppo */
12951ae08745Sheppo if (rcvd_ver->minor > ldc_versions[idx].minor)
12961ae08745Sheppo rcvd_ver->minor =
12971ae08745Sheppo ldc_versions[idx].minor;
12981ae08745Sheppo bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver));
12991ae08745Sheppo
13001ae08745Sheppo break;
13011ae08745Sheppo }
13021ae08745Sheppo
13031ae08745Sheppo if (rcvd_ver->major > ldc_versions[idx].major) {
13041ae08745Sheppo
13051ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: using next"
13061ae08745Sheppo " lower idx=%d, v%u.%u\n", idx,
13071ae08745Sheppo ldc_versions[idx].major,
13081ae08745Sheppo ldc_versions[idx].minor);
13091ae08745Sheppo
13101ae08745Sheppo /* nack with next lower version */
13111ae08745Sheppo pkt->stype = LDC_NACK;
13121ae08745Sheppo bcopy(&ldc_versions[idx], pkt->udata,
13131ae08745Sheppo sizeof (ldc_versions[idx]));
13141ae08745Sheppo ldcp->next_vidx = idx;
13151ae08745Sheppo break;
13161ae08745Sheppo }
13171ae08745Sheppo
13181ae08745Sheppo /* next major version */
13191ae08745Sheppo idx++;
13201ae08745Sheppo
13211ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx);
13221ae08745Sheppo
13231ae08745Sheppo if (idx == LDC_NUM_VERS) {
13241ae08745Sheppo /* no version match - send NACK */
13251ae08745Sheppo pkt->stype = LDC_NACK;
13261ae08745Sheppo bzero(pkt->udata, sizeof (ldc_ver_t));
13271ae08745Sheppo ldcp->next_vidx = 0;
13281ae08745Sheppo break;
13291ae08745Sheppo }
13301ae08745Sheppo }
13311ae08745Sheppo
13321ae08745Sheppo /* initiate the send by calling into HV and set the new tail */
13331ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) %
13341ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
13351ae08745Sheppo
13361ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail);
13371ae08745Sheppo if (rv == 0) {
13381ae08745Sheppo ldcp->tx_tail = tx_tail;
13391ae08745Sheppo if (pkt->stype == LDC_ACK) {
13401ae08745Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent"
13411ae08745Sheppo " version ACK\n", ldcp->id);
13421ae08745Sheppo /* Save the ACK'd version */
13431ae08745Sheppo ldcp->version.major = rcvd_ver->major;
13441ae08745Sheppo ldcp->version.minor = rcvd_ver->minor;
13450a55fbb7Slm66018 ldcp->hstate |= TS_RCVD_VER;
13461ae08745Sheppo ldcp->tstate |= TS_VER_DONE;
134783d3bc6fSnarayan D1(DBG_ALL_LDCS,
13483af08d82Slm66018 "(0x%llx) Sent ACK, "
13493af08d82Slm66018 "Agreed on version v%u.%u\n",
13501ae08745Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor);
13511ae08745Sheppo }
13521ae08745Sheppo } else {
13531ae08745Sheppo DWARN(ldcp->id,
13541ae08745Sheppo "i_ldc_process_VER: (0x%llx) error sending "
13551ae08745Sheppo "ACK/NACK\n", ldcp->id);
13563af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1357d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
13581ae08745Sheppo return (ECONNRESET);
13591ae08745Sheppo }
13601ae08745Sheppo
13611ae08745Sheppo break;
13621ae08745Sheppo
13631ae08745Sheppo case LDC_ACK:
13643af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) {
13653af08d82Slm66018 if (ldcp->version.major != rcvd_ver->major ||
13663af08d82Slm66018 ldcp->version.minor != rcvd_ver->minor) {
13673af08d82Slm66018
13683af08d82Slm66018 /* mismatched version - reset connection */
13693af08d82Slm66018 DWARN(ldcp->id,
13703af08d82Slm66018 "i_ldc_process_VER: (0x%llx) recvd"
13713af08d82Slm66018 " ACK ver != sent ACK ver\n", ldcp->id);
13723af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
13733af08d82Slm66018 mutex_exit(&ldcp->tx_lock);
13743af08d82Slm66018 return (ECONNRESET);
13753af08d82Slm66018 }
13763af08d82Slm66018 } else {
13771ae08745Sheppo /* SUCCESS - we have agreed on a version */
13781ae08745Sheppo ldcp->version.major = rcvd_ver->major;
13791ae08745Sheppo ldcp->version.minor = rcvd_ver->minor;
13801ae08745Sheppo ldcp->tstate |= TS_VER_DONE;
13813af08d82Slm66018 }
13821ae08745Sheppo
1383cb112a14Slm66018 D1(ldcp->id, "(0x%llx) Got ACK, Agreed on version v%u.%u\n",
13841ae08745Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor);
13851ae08745Sheppo
13861ae08745Sheppo /* initiate RTS-RTR-RDX handshake */
13871ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
13881ae08745Sheppo if (rv) {
13891ae08745Sheppo DWARN(ldcp->id,
13901ae08745Sheppo "i_ldc_process_VER: (0x%llx) cannot send RTS\n",
13911ae08745Sheppo ldcp->id);
13923af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1393d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
13941ae08745Sheppo return (ECONNRESET);
13951ae08745Sheppo }
13961ae08745Sheppo
13971ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
13981ae08745Sheppo ZERO_PKT(pkt);
13991ae08745Sheppo
14001ae08745Sheppo pkt->type = LDC_CTRL;
14011ae08745Sheppo pkt->stype = LDC_INFO;
14021ae08745Sheppo pkt->ctrl = LDC_RTS;
14031ae08745Sheppo pkt->env = ldcp->mode;
14041ae08745Sheppo if (ldcp->mode != LDC_MODE_RAW)
14051ae08745Sheppo pkt->seqid = LDC_INIT_SEQID;
14061ae08745Sheppo
14071ae08745Sheppo ldcp->last_msg_rcd = LDC_INIT_SEQID;
14081ae08745Sheppo
14091ae08745Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_VER snd rts", (uint64_t)pkt);
14101ae08745Sheppo
14111ae08745Sheppo /* initiate the send by calling into HV and set the new tail */
14121ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) %
14131ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
14141ae08745Sheppo
14151ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail);
14161ae08745Sheppo if (rv) {
14171ae08745Sheppo D2(ldcp->id,
14181ae08745Sheppo "i_ldc_process_VER: (0x%llx) no listener\n",
14191ae08745Sheppo ldcp->id);
14203af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1421d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
14221ae08745Sheppo return (ECONNRESET);
14231ae08745Sheppo }
14241ae08745Sheppo
14251ae08745Sheppo ldcp->tx_tail = tx_tail;
14261ae08745Sheppo ldcp->hstate |= TS_SENT_RTS;
14271ae08745Sheppo
14281ae08745Sheppo break;
14291ae08745Sheppo
14301ae08745Sheppo case LDC_NACK:
14311ae08745Sheppo /* check if version in NACK is zero */
14321ae08745Sheppo if (rcvd_ver->major == 0 && rcvd_ver->minor == 0) {
14331ae08745Sheppo /* version handshake failure */
14341ae08745Sheppo DWARN(DBG_ALL_LDCS,
14351ae08745Sheppo "i_ldc_process_VER: (0x%llx) no version match\n",
14361ae08745Sheppo ldcp->id);
14373af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1438d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
14391ae08745Sheppo return (ECONNRESET);
14401ae08745Sheppo }
14411ae08745Sheppo
14421ae08745Sheppo /* get the current tail and pkt for the response */
14431ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
14441ae08745Sheppo if (rv != 0) {
14451ae08745Sheppo cmn_err(CE_NOTE,
14461ae08745Sheppo "i_ldc_process_VER: (0x%lx) err sending "
14471ae08745Sheppo "version ACK/NACK\n", ldcp->id);
14483af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1449d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
14501ae08745Sheppo return (ECONNRESET);
14511ae08745Sheppo }
14521ae08745Sheppo
14531ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
14541ae08745Sheppo ZERO_PKT(pkt);
14551ae08745Sheppo
14561ae08745Sheppo /* initialize the packet */
14571ae08745Sheppo pkt->type = LDC_CTRL;
14581ae08745Sheppo pkt->ctrl = LDC_VER;
14591ae08745Sheppo pkt->stype = LDC_INFO;
14601ae08745Sheppo
14611ae08745Sheppo /* check ver in NACK msg has a match */
14621ae08745Sheppo for (;;) {
14631ae08745Sheppo if (rcvd_ver->major == ldc_versions[idx].major) {
14641ae08745Sheppo /*
14651ae08745Sheppo * major version match - resubmit request
14661ae08745Sheppo * if lower minor version to the one this endpt
14671ae08745Sheppo * supports, if necessary
14681ae08745Sheppo */
14691ae08745Sheppo if (rcvd_ver->minor > ldc_versions[idx].minor)
14701ae08745Sheppo rcvd_ver->minor =
14711ae08745Sheppo ldc_versions[idx].minor;
14721ae08745Sheppo bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver));
14731ae08745Sheppo break;
14741ae08745Sheppo }
14751ae08745Sheppo
14761ae08745Sheppo if (rcvd_ver->major > ldc_versions[idx].major) {
14771ae08745Sheppo
14781ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: using next"
14791ae08745Sheppo " lower idx=%d, v%u.%u\n", idx,
14801ae08745Sheppo ldc_versions[idx].major,
14811ae08745Sheppo ldc_versions[idx].minor);
14821ae08745Sheppo
14831ae08745Sheppo /* send next lower version */
14841ae08745Sheppo bcopy(&ldc_versions[idx], pkt->udata,
14851ae08745Sheppo sizeof (ldc_versions[idx]));
14861ae08745Sheppo ldcp->next_vidx = idx;
14871ae08745Sheppo break;
14881ae08745Sheppo }
14891ae08745Sheppo
14901ae08745Sheppo /* next version */
14911ae08745Sheppo idx++;
14921ae08745Sheppo
14931ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx);
14941ae08745Sheppo
14951ae08745Sheppo if (idx == LDC_NUM_VERS) {
14961ae08745Sheppo /* no version match - terminate */
14971ae08745Sheppo ldcp->next_vidx = 0;
1498d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
14991ae08745Sheppo return (ECONNRESET);
15001ae08745Sheppo }
15011ae08745Sheppo }
15021ae08745Sheppo
15031ae08745Sheppo /* initiate the send by calling into HV and set the new tail */
15041ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) %
15051ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
15061ae08745Sheppo
15071ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail);
15081ae08745Sheppo if (rv == 0) {
15091ae08745Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent version"
15101ae08745Sheppo "INFO v%u.%u\n", ldcp->id, ldc_versions[idx].major,
15111ae08745Sheppo ldc_versions[idx].minor);
15121ae08745Sheppo ldcp->tx_tail = tx_tail;
15131ae08745Sheppo } else {
15141ae08745Sheppo cmn_err(CE_NOTE,
15151ae08745Sheppo "i_ldc_process_VER: (0x%lx) error sending version"
15161ae08745Sheppo "INFO\n", ldcp->id);
15173af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1518d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
15191ae08745Sheppo return (ECONNRESET);
15201ae08745Sheppo }
15211ae08745Sheppo
15221ae08745Sheppo break;
15231ae08745Sheppo }
15241ae08745Sheppo
1525d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
15261ae08745Sheppo return (rv);
15271ae08745Sheppo }
15281ae08745Sheppo
15291ae08745Sheppo
15301ae08745Sheppo /*
15311ae08745Sheppo * Process an incoming RTS ctrl message
15321ae08745Sheppo */
15331ae08745Sheppo static int
i_ldc_process_RTS(ldc_chan_t * ldcp,ldc_msg_t * msg)15341ae08745Sheppo i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg)
15351ae08745Sheppo {
15361ae08745Sheppo int rv = 0;
15371ae08745Sheppo ldc_msg_t *pkt;
15381ae08745Sheppo uint64_t tx_tail;
15391ae08745Sheppo boolean_t sent_NACK = B_FALSE;
15401ae08745Sheppo
15411ae08745Sheppo D2(ldcp->id, "i_ldc_process_RTS: (0x%llx) received RTS\n", ldcp->id);
15421ae08745Sheppo
15431ae08745Sheppo switch (msg->stype) {
15441ae08745Sheppo case LDC_NACK:
15451ae08745Sheppo DWARN(ldcp->id,
15461ae08745Sheppo "i_ldc_process_RTS: (0x%llx) RTS NACK received\n",
15471ae08745Sheppo ldcp->id);
15481ae08745Sheppo
15491ae08745Sheppo /* Reset the channel -- as we cannot continue */
1550d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
15513af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1552d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
15531ae08745Sheppo rv = ECONNRESET;
15541ae08745Sheppo break;
15551ae08745Sheppo
15561ae08745Sheppo case LDC_INFO:
15571ae08745Sheppo
15581ae08745Sheppo /* check mode */
15591ae08745Sheppo if (ldcp->mode != (ldc_mode_t)msg->env) {
15601ae08745Sheppo cmn_err(CE_NOTE,
15611ae08745Sheppo "i_ldc_process_RTS: (0x%lx) mode mismatch\n",
15621ae08745Sheppo ldcp->id);
15631ae08745Sheppo /*
15641ae08745Sheppo * send NACK in response to MODE message
15651ae08745Sheppo * get the current tail for the response
15661ae08745Sheppo */
15671ae08745Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTS);
15681ae08745Sheppo if (rv) {
15691ae08745Sheppo /* if cannot send NACK - reset channel */
1570d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
15713af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1572d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
15731ae08745Sheppo rv = ECONNRESET;
15741ae08745Sheppo break;
15751ae08745Sheppo }
15761ae08745Sheppo sent_NACK = B_TRUE;
15771ae08745Sheppo }
15781ae08745Sheppo break;
15791ae08745Sheppo default:
15801ae08745Sheppo DWARN(ldcp->id, "i_ldc_process_RTS: (0x%llx) unexp ACK\n",
15811ae08745Sheppo ldcp->id);
1582d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
15833af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1584d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
15851ae08745Sheppo rv = ECONNRESET;
15861ae08745Sheppo break;
15871ae08745Sheppo }
15881ae08745Sheppo
15891ae08745Sheppo /*
15901ae08745Sheppo * If either the connection was reset (when rv != 0) or
15911ae08745Sheppo * a NACK was sent, we return. In the case of a NACK
15921ae08745Sheppo * we dont want to consume the packet that came in but
15931ae08745Sheppo * not record that we received the RTS
15941ae08745Sheppo */
15951ae08745Sheppo if (rv || sent_NACK)
15961ae08745Sheppo return (rv);
15971ae08745Sheppo
15981ae08745Sheppo /* record RTS received */
15991ae08745Sheppo ldcp->hstate |= TS_RCVD_RTS;
16001ae08745Sheppo
16011ae08745Sheppo /* store initial SEQID info */
16021ae08745Sheppo ldcp->last_msg_snt = msg->seqid;
16031ae08745Sheppo
1604d10e4ef2Snarayan /* Obtain Tx lock */
1605d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
1606d10e4ef2Snarayan
16071ae08745Sheppo /* get the current tail for the response */
16081ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
16091ae08745Sheppo if (rv != 0) {
16101ae08745Sheppo cmn_err(CE_NOTE,
16111ae08745Sheppo "i_ldc_process_RTS: (0x%lx) err sending RTR\n",
16121ae08745Sheppo ldcp->id);
16133af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1614d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
16151ae08745Sheppo return (ECONNRESET);
16161ae08745Sheppo }
16171ae08745Sheppo
16181ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
16191ae08745Sheppo ZERO_PKT(pkt);
16201ae08745Sheppo
16211ae08745Sheppo /* initialize the packet */
16221ae08745Sheppo pkt->type = LDC_CTRL;
16231ae08745Sheppo pkt->stype = LDC_INFO;
16241ae08745Sheppo pkt->ctrl = LDC_RTR;
16251ae08745Sheppo pkt->env = ldcp->mode;
16261ae08745Sheppo if (ldcp->mode != LDC_MODE_RAW)
16271ae08745Sheppo pkt->seqid = LDC_INIT_SEQID;
16281ae08745Sheppo
16291ae08745Sheppo ldcp->last_msg_rcd = msg->seqid;
16301ae08745Sheppo
16311ae08745Sheppo /* initiate the send by calling into HV and set the new tail */
16321ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) %
16331ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
16341ae08745Sheppo
16351ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail);
16361ae08745Sheppo if (rv == 0) {
16371ae08745Sheppo D2(ldcp->id,
16381ae08745Sheppo "i_ldc_process_RTS: (0x%llx) sent RTR\n", ldcp->id);
16391ae08745Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_RTS sent rtr", (uint64_t)pkt);
16401ae08745Sheppo
16411ae08745Sheppo ldcp->tx_tail = tx_tail;
16421ae08745Sheppo ldcp->hstate |= TS_SENT_RTR;
16431ae08745Sheppo
16441ae08745Sheppo } else {
16451ae08745Sheppo cmn_err(CE_NOTE,
16461ae08745Sheppo "i_ldc_process_RTS: (0x%lx) error sending RTR\n",
16471ae08745Sheppo ldcp->id);
16483af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1649d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
16501ae08745Sheppo return (ECONNRESET);
16511ae08745Sheppo }
16521ae08745Sheppo
1653d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
16541ae08745Sheppo return (0);
16551ae08745Sheppo }
16561ae08745Sheppo
16571ae08745Sheppo /*
16581ae08745Sheppo * Process an incoming RTR ctrl message
16591ae08745Sheppo */
16601ae08745Sheppo static int
i_ldc_process_RTR(ldc_chan_t * ldcp,ldc_msg_t * msg)16611ae08745Sheppo i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg)
16621ae08745Sheppo {
16631ae08745Sheppo int rv = 0;
16641ae08745Sheppo boolean_t sent_NACK = B_FALSE;
16651ae08745Sheppo
16661ae08745Sheppo D2(ldcp->id, "i_ldc_process_RTR: (0x%llx) received RTR\n", ldcp->id);
16671ae08745Sheppo
16681ae08745Sheppo switch (msg->stype) {
16691ae08745Sheppo case LDC_NACK:
16701ae08745Sheppo /* RTR NACK received */
16711ae08745Sheppo DWARN(ldcp->id,
16721ae08745Sheppo "i_ldc_process_RTR: (0x%llx) RTR NACK received\n",
16731ae08745Sheppo ldcp->id);
16741ae08745Sheppo
16751ae08745Sheppo /* Reset the channel -- as we cannot continue */
1676d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
16773af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1678d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
16791ae08745Sheppo rv = ECONNRESET;
16801ae08745Sheppo
16811ae08745Sheppo break;
16821ae08745Sheppo
16831ae08745Sheppo case LDC_INFO:
16841ae08745Sheppo
16851ae08745Sheppo /* check mode */
16861ae08745Sheppo if (ldcp->mode != (ldc_mode_t)msg->env) {
16871ae08745Sheppo DWARN(ldcp->id,
1688cb112a14Slm66018 "i_ldc_process_RTR: (0x%llx) mode mismatch, "
1689cb112a14Slm66018 "expecting 0x%x, got 0x%x\n",
1690cb112a14Slm66018 ldcp->id, ldcp->mode, (ldc_mode_t)msg->env);
16911ae08745Sheppo /*
16921ae08745Sheppo * send NACK in response to MODE message
16931ae08745Sheppo * get the current tail for the response
16941ae08745Sheppo */
16951ae08745Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTR);
16961ae08745Sheppo if (rv) {
16971ae08745Sheppo /* if cannot send NACK - reset channel */
1698d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
16993af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1700d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
17011ae08745Sheppo rv = ECONNRESET;
17021ae08745Sheppo break;
17031ae08745Sheppo }
17041ae08745Sheppo sent_NACK = B_TRUE;
17051ae08745Sheppo }
17061ae08745Sheppo break;
17071ae08745Sheppo
17081ae08745Sheppo default:
17091ae08745Sheppo DWARN(ldcp->id, "i_ldc_process_RTR: (0x%llx) unexp ACK\n",
17101ae08745Sheppo ldcp->id);
17111ae08745Sheppo
17121ae08745Sheppo /* Reset the channel -- as we cannot continue */
1713d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
17143af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1715d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
17161ae08745Sheppo rv = ECONNRESET;
17171ae08745Sheppo break;
17181ae08745Sheppo }
17191ae08745Sheppo
17201ae08745Sheppo /*
17211ae08745Sheppo * If either the connection was reset (when rv != 0) or
17221ae08745Sheppo * a NACK was sent, we return. In the case of a NACK
17231ae08745Sheppo * we dont want to consume the packet that came in but
17241ae08745Sheppo * not record that we received the RTR
17251ae08745Sheppo */
17261ae08745Sheppo if (rv || sent_NACK)
17271ae08745Sheppo return (rv);
17281ae08745Sheppo
17291ae08745Sheppo ldcp->last_msg_snt = msg->seqid;
17301ae08745Sheppo ldcp->hstate |= TS_RCVD_RTR;
17311ae08745Sheppo
17321ae08745Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_INFO, LDC_RDX);
17331ae08745Sheppo if (rv) {
17341ae08745Sheppo cmn_err(CE_NOTE,
17351ae08745Sheppo "i_ldc_process_RTR: (0x%lx) cannot send RDX\n",
17361ae08745Sheppo ldcp->id);
1737d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
17383af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1739d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
17401ae08745Sheppo return (ECONNRESET);
17411ae08745Sheppo }
17421ae08745Sheppo D2(ldcp->id,
17431ae08745Sheppo "i_ldc_process_RTR: (0x%llx) sent RDX\n", ldcp->id);
17441ae08745Sheppo
17451ae08745Sheppo ldcp->hstate |= TS_SENT_RDX;
17461ae08745Sheppo ldcp->tstate |= TS_HSHAKE_DONE;
17473af08d82Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0)
17481ae08745Sheppo ldcp->status = LDC_UP;
17491ae08745Sheppo
1750cb112a14Slm66018 D1(ldcp->id, "(0x%llx) Handshake Complete\n", ldcp->id);
17511ae08745Sheppo
17521ae08745Sheppo return (0);
17531ae08745Sheppo }
17541ae08745Sheppo
17551ae08745Sheppo
17561ae08745Sheppo /*
17571ae08745Sheppo * Process an incoming RDX ctrl message
17581ae08745Sheppo */
17591ae08745Sheppo static int
i_ldc_process_RDX(ldc_chan_t * ldcp,ldc_msg_t * msg)17601ae08745Sheppo i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg)
17611ae08745Sheppo {
17621ae08745Sheppo int rv = 0;
17631ae08745Sheppo
17641ae08745Sheppo D2(ldcp->id, "i_ldc_process_RDX: (0x%llx) received RDX\n", ldcp->id);
17651ae08745Sheppo
17661ae08745Sheppo switch (msg->stype) {
17671ae08745Sheppo case LDC_NACK:
17681ae08745Sheppo /* RDX NACK received */
17691ae08745Sheppo DWARN(ldcp->id,
17701ae08745Sheppo "i_ldc_process_RDX: (0x%llx) RDX NACK received\n",
17711ae08745Sheppo ldcp->id);
17721ae08745Sheppo
17731ae08745Sheppo /* Reset the channel -- as we cannot continue */
1774d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
17753af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1776d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
17771ae08745Sheppo rv = ECONNRESET;
17781ae08745Sheppo
17791ae08745Sheppo break;
17801ae08745Sheppo
17811ae08745Sheppo case LDC_INFO:
17821ae08745Sheppo
17831ae08745Sheppo /*
17841ae08745Sheppo * if channel is UP and a RDX received after data transmission
17851ae08745Sheppo * has commenced it is an error
17861ae08745Sheppo */
17871ae08745Sheppo if ((ldcp->tstate == TS_UP) && (ldcp->hstate & TS_RCVD_RDX)) {
17881ae08745Sheppo DWARN(DBG_ALL_LDCS,
17891ae08745Sheppo "i_ldc_process_RDX: (0x%llx) unexpected RDX"
17901ae08745Sheppo " - LDC reset\n", ldcp->id);
1791d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
17923af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1793d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
17941ae08745Sheppo return (ECONNRESET);
17951ae08745Sheppo }
17961ae08745Sheppo
17971ae08745Sheppo ldcp->hstate |= TS_RCVD_RDX;
17981ae08745Sheppo ldcp->tstate |= TS_HSHAKE_DONE;
17993af08d82Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0)
18001ae08745Sheppo ldcp->status = LDC_UP;
18011ae08745Sheppo
18021ae08745Sheppo D1(DBG_ALL_LDCS, "(0x%llx) Handshake Complete\n", ldcp->id);
18031ae08745Sheppo break;
18041ae08745Sheppo
18051ae08745Sheppo default:
18061ae08745Sheppo DWARN(ldcp->id, "i_ldc_process_RDX: (0x%llx) unexp ACK\n",
18071ae08745Sheppo ldcp->id);
18081ae08745Sheppo
18091ae08745Sheppo /* Reset the channel -- as we cannot continue */
1810d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
18113af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1812d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
18131ae08745Sheppo rv = ECONNRESET;
18141ae08745Sheppo break;
18151ae08745Sheppo }
18161ae08745Sheppo
18171ae08745Sheppo return (rv);
18181ae08745Sheppo }
18191ae08745Sheppo
18201ae08745Sheppo /*
18211ae08745Sheppo * Process an incoming ACK for a data packet
18221ae08745Sheppo */
18231ae08745Sheppo static int
i_ldc_process_data_ACK(ldc_chan_t * ldcp,ldc_msg_t * msg)18241ae08745Sheppo i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg)
18251ae08745Sheppo {
18261ae08745Sheppo int rv;
18271ae08745Sheppo uint64_t tx_head;
18281ae08745Sheppo ldc_msg_t *pkt;
18291ae08745Sheppo
1830d10e4ef2Snarayan /* Obtain Tx lock */
1831d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
1832d10e4ef2Snarayan
18331ae08745Sheppo /*
1834d10e4ef2Snarayan * Read the current Tx head and tail
18351ae08745Sheppo */
18361ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id,
18371ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
18381ae08745Sheppo if (rv != 0) {
18391ae08745Sheppo cmn_err(CE_WARN,
18401ae08745Sheppo "i_ldc_process_data_ACK: (0x%lx) cannot read qptrs\n",
18411ae08745Sheppo ldcp->id);
1842d10e4ef2Snarayan
1843d10e4ef2Snarayan /* Reset the channel -- as we cannot continue */
18443af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1845d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
1846d10e4ef2Snarayan return (ECONNRESET);
18471ae08745Sheppo }
18481ae08745Sheppo
18491ae08745Sheppo /*
18501ae08745Sheppo * loop from where the previous ACK location was to the
18511ae08745Sheppo * current head location. This is how far the HV has
18521ae08745Sheppo * actually send pkts. Pkts between head and tail are
18531ae08745Sheppo * yet to be sent by HV.
18541ae08745Sheppo */
18551ae08745Sheppo tx_head = ldcp->tx_ackd_head;
18561ae08745Sheppo for (;;) {
18571ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_head);
18581ae08745Sheppo tx_head = (tx_head + LDC_PACKET_SIZE) %
18591ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
18601ae08745Sheppo
18611ae08745Sheppo if (pkt->seqid == msg->ackid) {
18621ae08745Sheppo D2(ldcp->id,
18631ae08745Sheppo "i_ldc_process_data_ACK: (0x%llx) found packet\n",
18641ae08745Sheppo ldcp->id);
18651ae08745Sheppo ldcp->last_ack_rcd = msg->ackid;
18661ae08745Sheppo ldcp->tx_ackd_head = tx_head;
18671ae08745Sheppo break;
18681ae08745Sheppo }
18691ae08745Sheppo if (tx_head == ldcp->tx_head) {
18701ae08745Sheppo /* could not find packet */
18711ae08745Sheppo DWARN(ldcp->id,
18721ae08745Sheppo "i_ldc_process_data_ACK: (0x%llx) invalid ACKid\n",
18731ae08745Sheppo ldcp->id);
1874d10e4ef2Snarayan
1875d10e4ef2Snarayan /* Reset the channel -- as we cannot continue */
18763af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
1877d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
1878d10e4ef2Snarayan return (ECONNRESET);
18791ae08745Sheppo }
18801ae08745Sheppo }
18811ae08745Sheppo
1882d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
18831ae08745Sheppo return (0);
18841ae08745Sheppo }
18851ae08745Sheppo
18861ae08745Sheppo /*
18871ae08745Sheppo * Process incoming control message
18881ae08745Sheppo * Return 0 - session can continue
18891ae08745Sheppo * EAGAIN - reprocess packet - state was changed
18901ae08745Sheppo * ECONNRESET - channel was reset
18911ae08745Sheppo */
18921ae08745Sheppo static int
i_ldc_ctrlmsg(ldc_chan_t * ldcp,ldc_msg_t * msg)18931ae08745Sheppo i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *msg)
18941ae08745Sheppo {
18951ae08745Sheppo int rv = 0;
18961ae08745Sheppo
18973af08d82Slm66018 D1(ldcp->id, "i_ldc_ctrlmsg: (%llx) tstate = %lx, hstate = %lx\n",
18983af08d82Slm66018 ldcp->id, ldcp->tstate, ldcp->hstate);
18993af08d82Slm66018
19003af08d82Slm66018 switch (ldcp->tstate & ~TS_IN_RESET) {
19011ae08745Sheppo
19021ae08745Sheppo case TS_OPEN:
19031ae08745Sheppo case TS_READY:
19041ae08745Sheppo
19051ae08745Sheppo switch (msg->ctrl & LDC_CTRL_MASK) {
19061ae08745Sheppo case LDC_VER:
19071ae08745Sheppo /* process version message */
19081ae08745Sheppo rv = i_ldc_process_VER(ldcp, msg);
19091ae08745Sheppo break;
19101ae08745Sheppo default:
19111ae08745Sheppo DWARN(ldcp->id,
19121ae08745Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
19131ae08745Sheppo "tstate=0x%x\n", ldcp->id,
19141ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
19151ae08745Sheppo break;
19161ae08745Sheppo }
19171ae08745Sheppo
19181ae08745Sheppo break;
19191ae08745Sheppo
19201ae08745Sheppo case TS_VREADY:
19211ae08745Sheppo
19221ae08745Sheppo switch (msg->ctrl & LDC_CTRL_MASK) {
19231ae08745Sheppo case LDC_VER:
19243af08d82Slm66018 /* process version message */
19253af08d82Slm66018 rv = i_ldc_process_VER(ldcp, msg);
19261ae08745Sheppo break;
19271ae08745Sheppo case LDC_RTS:
19281ae08745Sheppo /* process RTS message */
19291ae08745Sheppo rv = i_ldc_process_RTS(ldcp, msg);
19301ae08745Sheppo break;
19311ae08745Sheppo case LDC_RTR:
19321ae08745Sheppo /* process RTR message */
19331ae08745Sheppo rv = i_ldc_process_RTR(ldcp, msg);
19341ae08745Sheppo break;
19351ae08745Sheppo case LDC_RDX:
19361ae08745Sheppo /* process RDX message */
19371ae08745Sheppo rv = i_ldc_process_RDX(ldcp, msg);
19381ae08745Sheppo break;
19391ae08745Sheppo default:
19401ae08745Sheppo DWARN(ldcp->id,
19411ae08745Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
19421ae08745Sheppo "tstate=0x%x\n", ldcp->id,
19431ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
19441ae08745Sheppo break;
19451ae08745Sheppo }
19461ae08745Sheppo
19471ae08745Sheppo break;
19481ae08745Sheppo
19491ae08745Sheppo case TS_UP:
19501ae08745Sheppo
19511ae08745Sheppo switch (msg->ctrl & LDC_CTRL_MASK) {
19521ae08745Sheppo case LDC_VER:
19531ae08745Sheppo DWARN(ldcp->id,
19541ae08745Sheppo "i_ldc_ctrlmsg: (0x%llx) unexpected VER "
19551ae08745Sheppo "- LDC reset\n", ldcp->id);
19561ae08745Sheppo /* peer is redoing version negotiation */
1957d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
19581ae08745Sheppo (void) i_ldc_txq_reconf(ldcp);
19591ae08745Sheppo i_ldc_reset_state(ldcp);
1960d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
19611ae08745Sheppo rv = EAGAIN;
19621ae08745Sheppo break;
19631ae08745Sheppo
19641ae08745Sheppo case LDC_RDX:
19651ae08745Sheppo /* process RDX message */
19661ae08745Sheppo rv = i_ldc_process_RDX(ldcp, msg);
19671ae08745Sheppo break;
19681ae08745Sheppo
19691ae08745Sheppo default:
19701ae08745Sheppo DWARN(ldcp->id,
19711ae08745Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
19721ae08745Sheppo "tstate=0x%x\n", ldcp->id,
19731ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate);
19741ae08745Sheppo break;
19751ae08745Sheppo }
19761ae08745Sheppo }
19771ae08745Sheppo
19781ae08745Sheppo return (rv);
19791ae08745Sheppo }
19801ae08745Sheppo
19811ae08745Sheppo /*
19821ae08745Sheppo * Register channel with the channel nexus
19831ae08745Sheppo */
19841ae08745Sheppo static int
i_ldc_register_channel(ldc_chan_t * ldcp)19851ae08745Sheppo i_ldc_register_channel(ldc_chan_t *ldcp)
19861ae08745Sheppo {
19871ae08745Sheppo int rv = 0;
19881ae08745Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo;
19891ae08745Sheppo
19901ae08745Sheppo if (cinfo->dip == NULL) {
19911ae08745Sheppo DWARN(ldcp->id,
19921ae08745Sheppo "i_ldc_register_channel: cnex has not registered\n");
19931ae08745Sheppo return (EAGAIN);
19941ae08745Sheppo }
19951ae08745Sheppo
19961ae08745Sheppo rv = cinfo->reg_chan(cinfo->dip, ldcp->id, ldcp->devclass);
19971ae08745Sheppo if (rv) {
19981ae08745Sheppo DWARN(ldcp->id,
19991ae08745Sheppo "i_ldc_register_channel: cannot register channel\n");
20001ae08745Sheppo return (rv);
20011ae08745Sheppo }
20021ae08745Sheppo
20031ae08745Sheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR,
20041ae08745Sheppo i_ldc_tx_hdlr, ldcp, NULL);
20051ae08745Sheppo if (rv) {
20061ae08745Sheppo DWARN(ldcp->id,
20071ae08745Sheppo "i_ldc_register_channel: cannot add Tx interrupt\n");
20081ae08745Sheppo (void) cinfo->unreg_chan(cinfo->dip, ldcp->id);
20091ae08745Sheppo return (rv);
20101ae08745Sheppo }
20111ae08745Sheppo
20121ae08745Sheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR,
20131ae08745Sheppo i_ldc_rx_hdlr, ldcp, NULL);
20141ae08745Sheppo if (rv) {
20151ae08745Sheppo DWARN(ldcp->id,
20161ae08745Sheppo "i_ldc_register_channel: cannot add Rx interrupt\n");
20171ae08745Sheppo (void) cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
20181ae08745Sheppo (void) cinfo->unreg_chan(cinfo->dip, ldcp->id);
20191ae08745Sheppo return (rv);
20201ae08745Sheppo }
20211ae08745Sheppo
20221ae08745Sheppo ldcp->tstate |= TS_CNEX_RDY;
20231ae08745Sheppo
20241ae08745Sheppo return (0);
20251ae08745Sheppo }
20261ae08745Sheppo
20271ae08745Sheppo /*
20281ae08745Sheppo * Unregister a channel with the channel nexus
20291ae08745Sheppo */
20301ae08745Sheppo static int
i_ldc_unregister_channel(ldc_chan_t * ldcp)20311ae08745Sheppo i_ldc_unregister_channel(ldc_chan_t *ldcp)
20321ae08745Sheppo {
20331ae08745Sheppo int rv = 0;
20341ae08745Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo;
20351ae08745Sheppo
20361ae08745Sheppo if (cinfo->dip == NULL) {
20371ae08745Sheppo DWARN(ldcp->id,
20381ae08745Sheppo "i_ldc_unregister_channel: cnex has not registered\n");
20391ae08745Sheppo return (EAGAIN);
20401ae08745Sheppo }
20411ae08745Sheppo
20421ae08745Sheppo if (ldcp->tstate & TS_CNEX_RDY) {
20431ae08745Sheppo
2044d10e4ef2Snarayan /* Remove the Rx interrupt */
20451ae08745Sheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR);
20461ae08745Sheppo if (rv) {
20473af08d82Slm66018 if (rv != EAGAIN) {
20481ae08745Sheppo DWARN(ldcp->id,
20493af08d82Slm66018 "i_ldc_unregister_channel: err removing "
20503af08d82Slm66018 "Rx intr\n");
2051d10e4ef2Snarayan return (rv);
20521ae08745Sheppo }
2053d10e4ef2Snarayan
20543af08d82Slm66018 /*
20553af08d82Slm66018 * If interrupts are pending and handler has
20563af08d82Slm66018 * finished running, clear interrupt and try
20573af08d82Slm66018 * again
20583af08d82Slm66018 */
20593af08d82Slm66018 if (ldcp->rx_intr_state != LDC_INTR_PEND)
20603af08d82Slm66018 return (rv);
20613af08d82Slm66018
20623af08d82Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
20633af08d82Slm66018 rv = cinfo->rem_intr(cinfo->dip, ldcp->id,
20643af08d82Slm66018 CNEX_RX_INTR);
20653af08d82Slm66018 if (rv) {
20663af08d82Slm66018 DWARN(ldcp->id, "i_ldc_unregister_channel: "
20673af08d82Slm66018 "err removing Rx interrupt\n");
20683af08d82Slm66018 return (rv);
20693af08d82Slm66018 }
20703af08d82Slm66018 }
20713af08d82Slm66018
2072d10e4ef2Snarayan /* Remove the Tx interrupt */
20731ae08745Sheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
20741ae08745Sheppo if (rv) {
20751ae08745Sheppo DWARN(ldcp->id,
20761ae08745Sheppo "i_ldc_unregister_channel: err removing Tx intr\n");
2077d10e4ef2Snarayan return (rv);
20781ae08745Sheppo }
2079d10e4ef2Snarayan
2080d10e4ef2Snarayan /* Unregister the channel */
20811ae08745Sheppo rv = cinfo->unreg_chan(ldcssp->cinfo.dip, ldcp->id);
20821ae08745Sheppo if (rv) {
20831ae08745Sheppo DWARN(ldcp->id,
20841ae08745Sheppo "i_ldc_unregister_channel: cannot unreg channel\n");
2085d10e4ef2Snarayan return (rv);
20861ae08745Sheppo }
20871ae08745Sheppo
20881ae08745Sheppo ldcp->tstate &= ~TS_CNEX_RDY;
20891ae08745Sheppo }
20901ae08745Sheppo
20911ae08745Sheppo return (0);
20921ae08745Sheppo }
20931ae08745Sheppo
20941ae08745Sheppo
20951ae08745Sheppo /*
20961ae08745Sheppo * LDC transmit interrupt handler
20971ae08745Sheppo * triggered for chanel up/down/reset events
20981ae08745Sheppo * and Tx queue content changes
20991ae08745Sheppo */
21001ae08745Sheppo static uint_t
i_ldc_tx_hdlr(caddr_t arg1,caddr_t arg2)21011ae08745Sheppo i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2)
21021ae08745Sheppo {
21031ae08745Sheppo _NOTE(ARGUNUSED(arg2))
21041ae08745Sheppo
21051ae08745Sheppo int rv;
21061ae08745Sheppo ldc_chan_t *ldcp;
21071ae08745Sheppo boolean_t notify_client = B_FALSE;
21083af08d82Slm66018 uint64_t notify_event = 0, link_state;
21091ae08745Sheppo
21101ae08745Sheppo /* Get the channel for which interrupt was received */
21111ae08745Sheppo ASSERT(arg1 != NULL);
21121ae08745Sheppo ldcp = (ldc_chan_t *)arg1;
21131ae08745Sheppo
21141ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
21151ae08745Sheppo ldcp->id, ldcp);
21161ae08745Sheppo
21171ae08745Sheppo /* Lock channel */
21181ae08745Sheppo mutex_enter(&ldcp->lock);
21191ae08745Sheppo
2120d10e4ef2Snarayan /* Obtain Tx lock */
2121d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
2122d10e4ef2Snarayan
21234bac2208Snarayan /* mark interrupt as pending */
21243af08d82Slm66018 ldcp->tx_intr_state = LDC_INTR_ACTIVE;
21253af08d82Slm66018
21263af08d82Slm66018 /* save current link state */
21273af08d82Slm66018 link_state = ldcp->link_state;
21284bac2208Snarayan
21291ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, &ldcp->tx_head, &ldcp->tx_tail,
21301ae08745Sheppo &ldcp->link_state);
21311ae08745Sheppo if (rv) {
21321ae08745Sheppo cmn_err(CE_WARN,
21331ae08745Sheppo "i_ldc_tx_hdlr: (0x%lx) cannot read queue ptrs rv=0x%d\n",
21341ae08745Sheppo ldcp->id, rv);
21354bac2208Snarayan i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
2136d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
21371ae08745Sheppo mutex_exit(&ldcp->lock);
21381ae08745Sheppo return (DDI_INTR_CLAIMED);
21391ae08745Sheppo }
21401ae08745Sheppo
21411ae08745Sheppo /*
21421ae08745Sheppo * reset the channel state if the channel went down
21431ae08745Sheppo * (other side unconfigured queue) or channel was reset
21441ae08745Sheppo * (other side reconfigured its queue)
21451ae08745Sheppo */
21463af08d82Slm66018 if (link_state != ldcp->link_state &&
21473af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_DOWN) {
21481ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link down\n", ldcp->id);
21493af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
21501ae08745Sheppo notify_client = B_TRUE;
21511ae08745Sheppo notify_event = LDC_EVT_DOWN;
21521ae08745Sheppo }
21531ae08745Sheppo
21543af08d82Slm66018 if (link_state != ldcp->link_state &&
21553af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) {
21561ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link reset\n", ldcp->id);
21573af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
21581ae08745Sheppo notify_client = B_TRUE;
21591ae08745Sheppo notify_event = LDC_EVT_RESET;
21601ae08745Sheppo }
21611ae08745Sheppo
21623af08d82Slm66018 if (link_state != ldcp->link_state &&
21633af08d82Slm66018 (ldcp->tstate & ~TS_IN_RESET) == TS_OPEN &&
21643af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_UP) {
21651ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link up\n", ldcp->id);
21661ae08745Sheppo notify_client = B_TRUE;
21671ae08745Sheppo notify_event = LDC_EVT_RESET;
21681ae08745Sheppo ldcp->tstate |= TS_LINK_READY;
21691ae08745Sheppo ldcp->status = LDC_READY;
21701ae08745Sheppo }
21711ae08745Sheppo
21721ae08745Sheppo /* if callbacks are disabled, do not notify */
21731ae08745Sheppo if (!ldcp->cb_enabled)
21741ae08745Sheppo notify_client = B_FALSE;
21751ae08745Sheppo
21764d39be2bSsg70180 i_ldc_clear_intr(ldcp, CNEX_TX_INTR);
217722f747efSnarayan mutex_exit(&ldcp->tx_lock);
21781ae08745Sheppo
21791ae08745Sheppo if (notify_client) {
21803af08d82Slm66018 ldcp->cb_inprogress = B_TRUE;
21813af08d82Slm66018 mutex_exit(&ldcp->lock);
21821ae08745Sheppo rv = ldcp->cb(notify_event, ldcp->cb_arg);
21831ae08745Sheppo if (rv) {
21841ae08745Sheppo DWARN(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) callback "
21851ae08745Sheppo "failure", ldcp->id);
21861ae08745Sheppo }
21871ae08745Sheppo mutex_enter(&ldcp->lock);
21881ae08745Sheppo ldcp->cb_inprogress = B_FALSE;
21891ae08745Sheppo }
21901ae08745Sheppo
21911ae08745Sheppo mutex_exit(&ldcp->lock);
21921ae08745Sheppo
21931ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) exiting handler", ldcp->id);
21941ae08745Sheppo
21951ae08745Sheppo return (DDI_INTR_CLAIMED);
21961ae08745Sheppo }
21971ae08745Sheppo
21981ae08745Sheppo /*
219958283286Sha137994 * Process the Rx HV queue.
220058283286Sha137994 *
220158283286Sha137994 * Returns 0 if data packets were found and no errors were encountered,
220258283286Sha137994 * otherwise returns an error. In either case, the *notify argument is
220358283286Sha137994 * set to indicate whether or not the client callback function should
220458283286Sha137994 * be invoked. The *event argument is set to contain the callback event.
220558283286Sha137994 *
220658283286Sha137994 * Depending on the channel mode, packets are handled differently:
220758283286Sha137994 *
220858283286Sha137994 * RAW MODE
220958283286Sha137994 * For raw mode channels, when a data packet is encountered,
221058283286Sha137994 * processing stops and all packets are left on the queue to be removed
221158283286Sha137994 * and processed by the ldc_read code path.
221258283286Sha137994 *
221358283286Sha137994 * UNRELIABLE MODE
221458283286Sha137994 * For unreliable mode, when a data packet is encountered, processing
221558283286Sha137994 * stops, and all packets are left on the queue to be removed and
221658283286Sha137994 * processed by the ldc_read code path. Control packets are processed
221758283286Sha137994 * inline if they are encountered before any data packets.
221858283286Sha137994 *
221920ae46ebSha137994 * RELIABLE MODE
222020ae46ebSha137994 * For reliable mode channels, all packets on the receive queue
222158283286Sha137994 * are processed: data packets are copied to the data queue and
222258283286Sha137994 * control packets are processed inline. Packets are only left on
222358283286Sha137994 * the receive queue when the data queue is full.
22241ae08745Sheppo */
22251ae08745Sheppo static uint_t
i_ldc_rx_process_hvq(ldc_chan_t * ldcp,boolean_t * notify_client,uint64_t * notify_event)222658283286Sha137994 i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client,
222758283286Sha137994 uint64_t *notify_event)
22281ae08745Sheppo {
22291ae08745Sheppo int rv;
22301ae08745Sheppo uint64_t rx_head, rx_tail;
22311ae08745Sheppo ldc_msg_t *msg;
22323af08d82Slm66018 uint64_t link_state, first_fragment = 0;
223358283286Sha137994 boolean_t trace_length = B_TRUE;
22343af08d82Slm66018
223558283286Sha137994 ASSERT(MUTEX_HELD(&ldcp->lock));
223658283286Sha137994 *notify_client = B_FALSE;
223758283286Sha137994 *notify_event = 0;
22381ae08745Sheppo
22391ae08745Sheppo /*
22401ae08745Sheppo * Read packet(s) from the queue
22411ae08745Sheppo */
22421ae08745Sheppo for (;;) {
22431ae08745Sheppo
22443af08d82Slm66018 link_state = ldcp->link_state;
22451ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
22461ae08745Sheppo &ldcp->link_state);
22471ae08745Sheppo if (rv) {
22481ae08745Sheppo cmn_err(CE_WARN,
224958283286Sha137994 "i_ldc_rx_process_hvq: (0x%lx) cannot read "
22501ae08745Sheppo "queue ptrs, rv=0x%d\n", ldcp->id, rv);
22511ae08745Sheppo i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
225258283286Sha137994 return (EIO);
22531ae08745Sheppo }
22541ae08745Sheppo
22551ae08745Sheppo /*
22561ae08745Sheppo * reset the channel state if the channel went down
22571ae08745Sheppo * (other side unconfigured queue) or channel was reset
22583af08d82Slm66018 * (other side reconfigured its queue)
22591ae08745Sheppo */
22603af08d82Slm66018
22613af08d82Slm66018 if (link_state != ldcp->link_state) {
2262cb112a14Slm66018
22633af08d82Slm66018 switch (ldcp->link_state) {
22643af08d82Slm66018 case LDC_CHANNEL_DOWN:
226558283286Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: channel "
22663af08d82Slm66018 "link down\n", ldcp->id);
2267d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
22683af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
2269d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
227058283286Sha137994 *notify_client = B_TRUE;
227158283286Sha137994 *notify_event = LDC_EVT_DOWN;
22723af08d82Slm66018 goto loop_exit;
22731ae08745Sheppo
22743af08d82Slm66018 case LDC_CHANNEL_UP:
227558283286Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: "
22763af08d82Slm66018 "channel link up\n", ldcp->id);
22773af08d82Slm66018
22783af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_OPEN) {
227958283286Sha137994 *notify_client = B_TRUE;
228058283286Sha137994 *notify_event = LDC_EVT_RESET;
22811ae08745Sheppo ldcp->tstate |= TS_LINK_READY;
22821ae08745Sheppo ldcp->status = LDC_READY;
22831ae08745Sheppo }
22843af08d82Slm66018 break;
22853af08d82Slm66018
22863af08d82Slm66018 case LDC_CHANNEL_RESET:
22873af08d82Slm66018 default:
22883af08d82Slm66018 #ifdef DEBUG
22893af08d82Slm66018 force_reset:
22903af08d82Slm66018 #endif
229158283286Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: channel "
22923af08d82Slm66018 "link reset\n", ldcp->id);
22933af08d82Slm66018 mutex_enter(&ldcp->tx_lock);
22943af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
22953af08d82Slm66018 mutex_exit(&ldcp->tx_lock);
229658283286Sha137994 *notify_client = B_TRUE;
229758283286Sha137994 *notify_event = LDC_EVT_RESET;
22983af08d82Slm66018 break;
22993af08d82Slm66018 }
23003af08d82Slm66018 }
23013af08d82Slm66018
23023af08d82Slm66018 #ifdef DEBUG
23033af08d82Slm66018 if (LDC_INJECT_RESET(ldcp))
23043af08d82Slm66018 goto force_reset;
2305bbfa0259Sha137994 if (LDC_INJECT_DRNGCLEAR(ldcp))
2306bbfa0259Sha137994 i_ldc_mem_inject_dring_clear(ldcp);
23073af08d82Slm66018 #endif
230858283286Sha137994 if (trace_length) {
230958283286Sha137994 TRACE_RXHVQ_LENGTH(ldcp, rx_head, rx_tail);
231058283286Sha137994 trace_length = B_FALSE;
231158283286Sha137994 }
23121ae08745Sheppo
23131ae08745Sheppo if (rx_head == rx_tail) {
231458283286Sha137994 D2(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) "
231558283286Sha137994 "No packets\n", ldcp->id);
23161ae08745Sheppo break;
23171ae08745Sheppo }
23183af08d82Slm66018
231958283286Sha137994 D2(ldcp->id, "i_ldc_rx_process_hvq: head=0x%llx, "
232058283286Sha137994 "tail=0x%llx\n", rx_head, rx_tail);
232158283286Sha137994 DUMP_LDC_PKT(ldcp, "i_ldc_rx_process_hvq rcd",
23221ae08745Sheppo ldcp->rx_q_va + rx_head);
23231ae08745Sheppo
23241ae08745Sheppo /* get the message */
23251ae08745Sheppo msg = (ldc_msg_t *)(ldcp->rx_q_va + rx_head);
23261ae08745Sheppo
23271ae08745Sheppo /* if channel is in RAW mode or data pkt, notify and return */
23281ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW) {
232958283286Sha137994 *notify_client = B_TRUE;
233058283286Sha137994 *notify_event |= LDC_EVT_READ;
23311ae08745Sheppo break;
23321ae08745Sheppo }
23331ae08745Sheppo
23341ae08745Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
23351ae08745Sheppo
23361ae08745Sheppo /* discard packet if channel is not up */
23373af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) != TS_UP) {
23381ae08745Sheppo
23391ae08745Sheppo /* move the head one position */
23401ae08745Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) %
23411ae08745Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
23421ae08745Sheppo
23431ae08745Sheppo if (rv = i_ldc_set_rx_head(ldcp, rx_head))
23441ae08745Sheppo break;
23451ae08745Sheppo
23461ae08745Sheppo continue;
23471ae08745Sheppo } else {
234858283286Sha137994 uint64_t dq_head, dq_tail;
234958283286Sha137994
235020ae46ebSha137994 /* process only RELIABLE mode data packets */
235120ae46ebSha137994 if (ldcp->mode != LDC_MODE_RELIABLE) {
23523af08d82Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0)
235358283286Sha137994 *notify_client = B_TRUE;
235458283286Sha137994 *notify_event |= LDC_EVT_READ;
23551ae08745Sheppo break;
23561ae08745Sheppo }
235758283286Sha137994
235858283286Sha137994 /* don't process packet if queue full */
235958283286Sha137994 (void) i_ldc_dq_rx_get_state(ldcp, &dq_head,
236058283286Sha137994 &dq_tail, NULL);
236158283286Sha137994 dq_tail = (dq_tail + LDC_PACKET_SIZE) %
236258283286Sha137994 (ldcp->rx_dq_entries << LDC_PACKET_SHIFT);
236358283286Sha137994 if (dq_tail == dq_head ||
236458283286Sha137994 LDC_INJECT_DQFULL(ldcp)) {
236558283286Sha137994 rv = ENOSPC;
236658283286Sha137994 break;
236758283286Sha137994 }
236858283286Sha137994 }
23691ae08745Sheppo }
23701ae08745Sheppo
23711ae08745Sheppo /* Check the sequence ID for the message received */
23723af08d82Slm66018 rv = i_ldc_check_seqid(ldcp, msg);
23733af08d82Slm66018 if (rv != 0) {
23741ae08745Sheppo
237558283286Sha137994 DWARN(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) "
237658283286Sha137994 "seqid error, q_ptrs=0x%lx,0x%lx", ldcp->id,
237758283286Sha137994 rx_head, rx_tail);
23781ae08745Sheppo
23791ae08745Sheppo /* Reset last_msg_rcd to start of message */
2380d10e4ef2Snarayan if (first_fragment != 0) {
2381d10e4ef2Snarayan ldcp->last_msg_rcd = first_fragment - 1;
2382d10e4ef2Snarayan first_fragment = 0;
23831ae08745Sheppo }
2384d10e4ef2Snarayan
23851ae08745Sheppo /*
23861ae08745Sheppo * Send a NACK due to seqid mismatch
23871ae08745Sheppo */
238822f747efSnarayan rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK,
23891ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK));
23901ae08745Sheppo
23911ae08745Sheppo if (rv) {
239258283286Sha137994 cmn_err(CE_NOTE, "i_ldc_rx_process_hvq: "
239358283286Sha137994 "(0x%lx) err sending CTRL/DATA NACK msg\n",
239458283286Sha137994 ldcp->id);
2395d10e4ef2Snarayan
2396d10e4ef2Snarayan /* if cannot send NACK - reset channel */
2397d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
23983af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
2399d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
240083d3bc6fSnarayan
240158283286Sha137994 *notify_client = B_TRUE;
240258283286Sha137994 *notify_event = LDC_EVT_RESET;
2403d10e4ef2Snarayan break;
24041ae08745Sheppo }
24051ae08745Sheppo
24061ae08745Sheppo /* purge receive queue */
24071ae08745Sheppo (void) i_ldc_set_rx_head(ldcp, rx_tail);
24081ae08745Sheppo break;
24091ae08745Sheppo }
24101ae08745Sheppo
24111ae08745Sheppo /* record the message ID */
24121ae08745Sheppo ldcp->last_msg_rcd = msg->seqid;
24131ae08745Sheppo
24141ae08745Sheppo /* process control messages */
24151ae08745Sheppo if (msg->type & LDC_CTRL) {
24161ae08745Sheppo /* save current internal state */
24171ae08745Sheppo uint64_t tstate = ldcp->tstate;
24181ae08745Sheppo
24191ae08745Sheppo rv = i_ldc_ctrlmsg(ldcp, msg);
24201ae08745Sheppo if (rv == EAGAIN) {
24211ae08745Sheppo /* re-process pkt - state was adjusted */
24221ae08745Sheppo continue;
24231ae08745Sheppo }
24241ae08745Sheppo if (rv == ECONNRESET) {
242558283286Sha137994 *notify_client = B_TRUE;
242658283286Sha137994 *notify_event = LDC_EVT_RESET;
24271ae08745Sheppo break;
24281ae08745Sheppo }
24291ae08745Sheppo
24301ae08745Sheppo /*
24311ae08745Sheppo * control message processing was successful
24321ae08745Sheppo * channel transitioned to ready for communication
24331ae08745Sheppo */
24341ae08745Sheppo if (rv == 0 && ldcp->tstate == TS_UP &&
24353af08d82Slm66018 (tstate & ~TS_IN_RESET) !=
24363af08d82Slm66018 (ldcp->tstate & ~TS_IN_RESET)) {
243758283286Sha137994 *notify_client = B_TRUE;
243858283286Sha137994 *notify_event = LDC_EVT_UP;
24391ae08745Sheppo }
24401ae08745Sheppo }
24411ae08745Sheppo
244283d3bc6fSnarayan /* process data NACKs */
244383d3bc6fSnarayan if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) {
244483d3bc6fSnarayan DWARN(ldcp->id,
244558283286Sha137994 "i_ldc_rx_process_hvq: (0x%llx) received DATA/NACK",
244683d3bc6fSnarayan ldcp->id);
244783d3bc6fSnarayan mutex_enter(&ldcp->tx_lock);
244883d3bc6fSnarayan i_ldc_reset(ldcp, B_TRUE);
244983d3bc6fSnarayan mutex_exit(&ldcp->tx_lock);
245058283286Sha137994 *notify_client = B_TRUE;
245158283286Sha137994 *notify_event = LDC_EVT_RESET;
245283d3bc6fSnarayan break;
245383d3bc6fSnarayan }
245483d3bc6fSnarayan
24551ae08745Sheppo /* process data ACKs */
24561ae08745Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
2457d10e4ef2Snarayan if (rv = i_ldc_process_data_ACK(ldcp, msg)) {
245858283286Sha137994 *notify_client = B_TRUE;
245958283286Sha137994 *notify_event = LDC_EVT_RESET;
2460d10e4ef2Snarayan break;
2461d10e4ef2Snarayan }
24621ae08745Sheppo }
24631ae08745Sheppo
246458283286Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
246520ae46ebSha137994 ASSERT(ldcp->mode == LDC_MODE_RELIABLE);
246658283286Sha137994
246758283286Sha137994 /*
246858283286Sha137994 * Copy the data packet to the data queue. Note
246958283286Sha137994 * that the copy routine updates the rx_head pointer.
247058283286Sha137994 */
247158283286Sha137994 i_ldc_rxdq_copy(ldcp, &rx_head);
247258283286Sha137994
247358283286Sha137994 if ((ldcp->tstate & TS_IN_RESET) == 0)
247458283286Sha137994 *notify_client = B_TRUE;
247558283286Sha137994 *notify_event |= LDC_EVT_READ;
247658283286Sha137994 } else {
24771ae08745Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) %
24781ae08745Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
247958283286Sha137994 }
248058283286Sha137994
248158283286Sha137994 /* move the head one position */
24820a55fbb7Slm66018 if (rv = i_ldc_set_rx_head(ldcp, rx_head)) {
248358283286Sha137994 *notify_client = B_TRUE;
248458283286Sha137994 *notify_event = LDC_EVT_RESET;
24851ae08745Sheppo break;
24860a55fbb7Slm66018 }
24871ae08745Sheppo
24881ae08745Sheppo } /* for */
24891ae08745Sheppo
24903af08d82Slm66018 loop_exit:
24913af08d82Slm66018
249220ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) {
249358283286Sha137994 /* ACK data packets */
249458283286Sha137994 if ((*notify_event &
249558283286Sha137994 (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) {
249658283286Sha137994 int ack_rv;
249758283286Sha137994 ack_rv = i_ldc_send_pkt(ldcp, LDC_DATA, LDC_ACK, 0);
249858283286Sha137994 if (ack_rv && ack_rv != EWOULDBLOCK) {
249958283286Sha137994 cmn_err(CE_NOTE,
250058283286Sha137994 "i_ldc_rx_process_hvq: (0x%lx) cannot "
250158283286Sha137994 "send ACK\n", ldcp->id);
250258283286Sha137994
250358283286Sha137994 mutex_enter(&ldcp->tx_lock);
250458283286Sha137994 i_ldc_reset(ldcp, B_FALSE);
250558283286Sha137994 mutex_exit(&ldcp->tx_lock);
250658283286Sha137994
250758283286Sha137994 *notify_client = B_TRUE;
250858283286Sha137994 *notify_event = LDC_EVT_RESET;
250958283286Sha137994 goto skip_ackpeek;
251058283286Sha137994 }
251158283286Sha137994 }
25121ae08745Sheppo
25133af08d82Slm66018 /*
251458283286Sha137994 * If we have no more space on the data queue, make sure
251558283286Sha137994 * there are no ACKs on the rx queue waiting to be processed.
25163af08d82Slm66018 */
251758283286Sha137994 if (rv == ENOSPC) {
251858283286Sha137994 if (i_ldc_rx_ackpeek(ldcp, rx_head, rx_tail) != 0) {
251958283286Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
252058283286Sha137994 *notify_client = B_TRUE;
252158283286Sha137994 *notify_event = LDC_EVT_RESET;
25221ae08745Sheppo }
252312f80fa6Sha137994 return (rv);
252458283286Sha137994 } else {
252558283286Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
252658283286Sha137994 }
25271ae08745Sheppo }
25281ae08745Sheppo
252958283286Sha137994 skip_ackpeek:
25304d39be2bSsg70180
253158283286Sha137994 /* Return, indicating whether or not data packets were found */
253258283286Sha137994 if ((*notify_event & (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ)
253358283286Sha137994 return (0);
253458283286Sha137994
253558283286Sha137994 return (ENOMSG);
25361ae08745Sheppo }
25371ae08745Sheppo
253858283286Sha137994 /*
253958283286Sha137994 * Process any ACK packets on the HV receive queue.
254058283286Sha137994 *
254120ae46ebSha137994 * This function is only used by RELIABLE mode channels when the
254258283286Sha137994 * secondary data queue fills up and there are packets remaining on
254358283286Sha137994 * the HV receive queue.
254458283286Sha137994 */
254558283286Sha137994 int
i_ldc_rx_ackpeek(ldc_chan_t * ldcp,uint64_t rx_head,uint64_t rx_tail)254658283286Sha137994 i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, uint64_t rx_tail)
254758283286Sha137994 {
254858283286Sha137994 int rv = 0;
254958283286Sha137994 ldc_msg_t *msg;
255058283286Sha137994
255158283286Sha137994 if (ldcp->rx_ack_head == ACKPEEK_HEAD_INVALID)
255258283286Sha137994 ldcp->rx_ack_head = rx_head;
255358283286Sha137994
255458283286Sha137994 while (ldcp->rx_ack_head != rx_tail) {
255558283286Sha137994 msg = (ldc_msg_t *)(ldcp->rx_q_va + ldcp->rx_ack_head);
255658283286Sha137994
255758283286Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
255858283286Sha137994 if (rv = i_ldc_process_data_ACK(ldcp, msg))
255958283286Sha137994 break;
256058283286Sha137994 msg->stype &= ~LDC_ACK;
256158283286Sha137994 }
256258283286Sha137994
256358283286Sha137994 ldcp->rx_ack_head =
256458283286Sha137994 (ldcp->rx_ack_head + LDC_PACKET_SIZE) %
256558283286Sha137994 (ldcp->rx_q_entries << LDC_PACKET_SHIFT);
256658283286Sha137994 }
256758283286Sha137994 return (rv);
256858283286Sha137994 }
25691ae08745Sheppo
25701ae08745Sheppo /* -------------------------------------------------------------------------- */
25711ae08745Sheppo
25721ae08745Sheppo /*
25731ae08745Sheppo * LDC API functions
25741ae08745Sheppo */
25751ae08745Sheppo
25761ae08745Sheppo /*
25771ae08745Sheppo * Initialize the channel. Allocate internal structure and memory for
25781ae08745Sheppo * TX/RX queues, and initialize locks.
25791ae08745Sheppo */
25801ae08745Sheppo int
ldc_init(uint64_t id,ldc_attr_t * attr,ldc_handle_t * handle)25811ae08745Sheppo ldc_init(uint64_t id, ldc_attr_t *attr, ldc_handle_t *handle)
25821ae08745Sheppo {
25831ae08745Sheppo ldc_chan_t *ldcp;
25841ae08745Sheppo int rv, exit_val;
25851ae08745Sheppo uint64_t ra_base, nentries;
2586e1ebb9ecSlm66018 uint64_t qlen;
25871ae08745Sheppo
25881ae08745Sheppo exit_val = EINVAL; /* guarantee an error if exit on failure */
25891ae08745Sheppo
25901ae08745Sheppo if (attr == NULL) {
25911ae08745Sheppo DWARN(id, "ldc_init: (0x%llx) invalid attr\n", id);
25921ae08745Sheppo return (EINVAL);
25931ae08745Sheppo }
25941ae08745Sheppo if (handle == NULL) {
25951ae08745Sheppo DWARN(id, "ldc_init: (0x%llx) invalid handle\n", id);
25961ae08745Sheppo return (EINVAL);
25971ae08745Sheppo }
25981ae08745Sheppo
25991ae08745Sheppo /* check if channel is valid */
26001ae08745Sheppo rv = hv_ldc_tx_qinfo(id, &ra_base, &nentries);
26011ae08745Sheppo if (rv == H_ECHANNEL) {
26021ae08745Sheppo DWARN(id, "ldc_init: (0x%llx) invalid channel id\n", id);
26031ae08745Sheppo return (EINVAL);
26041ae08745Sheppo }
26051ae08745Sheppo
26061ae08745Sheppo /* check if the channel has already been initialized */
26071ae08745Sheppo mutex_enter(&ldcssp->lock);
26081ae08745Sheppo ldcp = ldcssp->chan_list;
26091ae08745Sheppo while (ldcp != NULL) {
26101ae08745Sheppo if (ldcp->id == id) {
26111ae08745Sheppo DWARN(id, "ldc_init: (0x%llx) already initialized\n",
26121ae08745Sheppo id);
26131ae08745Sheppo mutex_exit(&ldcssp->lock);
26141ae08745Sheppo return (EADDRINUSE);
26151ae08745Sheppo }
26161ae08745Sheppo ldcp = ldcp->next;
26171ae08745Sheppo }
26181ae08745Sheppo mutex_exit(&ldcssp->lock);
26191ae08745Sheppo
26201ae08745Sheppo ASSERT(ldcp == NULL);
26211ae08745Sheppo
26221ae08745Sheppo *handle = 0;
26231ae08745Sheppo
26241ae08745Sheppo /* Allocate an ldcp structure */
26251ae08745Sheppo ldcp = kmem_zalloc(sizeof (ldc_chan_t), KM_SLEEP);
26261ae08745Sheppo
2627d10e4ef2Snarayan /*
2628d10e4ef2Snarayan * Initialize the channel and Tx lock
2629d10e4ef2Snarayan *
2630d10e4ef2Snarayan * The channel 'lock' protects the entire channel and
2631d10e4ef2Snarayan * should be acquired before initializing, resetting,
2632d10e4ef2Snarayan * destroying or reading from a channel.
2633d10e4ef2Snarayan *
2634d10e4ef2Snarayan * The 'tx_lock' should be acquired prior to transmitting
2635d10e4ef2Snarayan * data over the channel. The lock should also be acquired
2636d10e4ef2Snarayan * prior to channel reconfiguration (in order to prevent
2637d10e4ef2Snarayan * concurrent writes).
2638d10e4ef2Snarayan *
2639d10e4ef2Snarayan * ORDERING: When both locks are being acquired, to prevent
2640d10e4ef2Snarayan * deadlocks, the channel lock should be always acquired prior
2641d10e4ef2Snarayan * to the tx_lock.
2642d10e4ef2Snarayan */
26431ae08745Sheppo mutex_init(&ldcp->lock, NULL, MUTEX_DRIVER, NULL);
2644d10e4ef2Snarayan mutex_init(&ldcp->tx_lock, NULL, MUTEX_DRIVER, NULL);
26451ae08745Sheppo
26461ae08745Sheppo /* Initialize the channel */
26471ae08745Sheppo ldcp->id = id;
26481ae08745Sheppo ldcp->cb = NULL;
26491ae08745Sheppo ldcp->cb_arg = NULL;
26501ae08745Sheppo ldcp->cb_inprogress = B_FALSE;
26511ae08745Sheppo ldcp->cb_enabled = B_FALSE;
26521ae08745Sheppo ldcp->next = NULL;
26531ae08745Sheppo
26541ae08745Sheppo /* Read attributes */
26551ae08745Sheppo ldcp->mode = attr->mode;
26561ae08745Sheppo ldcp->devclass = attr->devclass;
26571ae08745Sheppo ldcp->devinst = attr->instance;
2658e1ebb9ecSlm66018 ldcp->mtu = (attr->mtu > 0) ? attr->mtu : LDC_DEFAULT_MTU;
26591ae08745Sheppo
26601ae08745Sheppo D1(ldcp->id,
26611ae08745Sheppo "ldc_init: (0x%llx) channel attributes, class=0x%x, "
2662e1ebb9ecSlm66018 "instance=0x%llx, mode=%d, mtu=%d\n",
2663e1ebb9ecSlm66018 ldcp->id, ldcp->devclass, ldcp->devinst, ldcp->mode, ldcp->mtu);
26641ae08745Sheppo
26651ae08745Sheppo ldcp->next_vidx = 0;
26663af08d82Slm66018 ldcp->tstate = TS_IN_RESET;
26671ae08745Sheppo ldcp->hstate = 0;
26681ae08745Sheppo ldcp->last_msg_snt = LDC_INIT_SEQID;
26691ae08745Sheppo ldcp->last_ack_rcd = 0;
26701ae08745Sheppo ldcp->last_msg_rcd = 0;
267158283286Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID;
26721ae08745Sheppo
26731ae08745Sheppo ldcp->stream_bufferp = NULL;
26741ae08745Sheppo ldcp->exp_dring_list = NULL;
26751ae08745Sheppo ldcp->imp_dring_list = NULL;
26761ae08745Sheppo ldcp->mhdl_list = NULL;
26771ae08745Sheppo
26783af08d82Slm66018 ldcp->tx_intr_state = LDC_INTR_NONE;
26793af08d82Slm66018 ldcp->rx_intr_state = LDC_INTR_NONE;
26803af08d82Slm66018
26811ae08745Sheppo /* Initialize payload size depending on whether channel is reliable */
26821ae08745Sheppo switch (ldcp->mode) {
26831ae08745Sheppo case LDC_MODE_RAW:
26841ae08745Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RAW;
26851ae08745Sheppo ldcp->read_p = i_ldc_read_raw;
26861ae08745Sheppo ldcp->write_p = i_ldc_write_raw;
26871ae08745Sheppo break;
26881ae08745Sheppo case LDC_MODE_UNRELIABLE:
26891ae08745Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_UNRELIABLE;
26901ae08745Sheppo ldcp->read_p = i_ldc_read_packet;
26911ae08745Sheppo ldcp->write_p = i_ldc_write_packet;
26921ae08745Sheppo break;
26931ae08745Sheppo case LDC_MODE_RELIABLE:
26941ae08745Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE;
26951ae08745Sheppo
26961ae08745Sheppo ldcp->stream_remains = 0;
26971ae08745Sheppo ldcp->stream_offset = 0;
26981ae08745Sheppo ldcp->stream_bufferp = kmem_alloc(ldcp->mtu, KM_SLEEP);
26991ae08745Sheppo ldcp->read_p = i_ldc_read_stream;
27001ae08745Sheppo ldcp->write_p = i_ldc_write_stream;
27011ae08745Sheppo break;
27021ae08745Sheppo default:
27031ae08745Sheppo exit_val = EINVAL;
27041ae08745Sheppo goto cleanup_on_exit;
27051ae08745Sheppo }
27061ae08745Sheppo
2707e1ebb9ecSlm66018 /*
2708e1ebb9ecSlm66018 * qlen is (mtu * ldc_mtu_msgs) / pkt_payload. If this
2709e1ebb9ecSlm66018 * value is smaller than default length of ldc_queue_entries,
271022f747efSnarayan * qlen is set to ldc_queue_entries. Ensure that computed
271122f747efSnarayan * length is a power-of-two value.
2712e1ebb9ecSlm66018 */
2713e1ebb9ecSlm66018 qlen = (ldcp->mtu * ldc_mtu_msgs) / ldcp->pkt_payload;
271422f747efSnarayan if (!ISP2(qlen)) {
271522f747efSnarayan uint64_t tmp = 1;
271622f747efSnarayan while (qlen) {
271722f747efSnarayan qlen >>= 1; tmp <<= 1;
271822f747efSnarayan }
271922f747efSnarayan qlen = tmp;
272022f747efSnarayan }
272122f747efSnarayan
2722e1ebb9ecSlm66018 ldcp->rx_q_entries =
2723e1ebb9ecSlm66018 (qlen < ldc_queue_entries) ? ldc_queue_entries : qlen;
2724e1ebb9ecSlm66018 ldcp->tx_q_entries = ldcp->rx_q_entries;
2725e1ebb9ecSlm66018
272622f747efSnarayan D1(ldcp->id, "ldc_init: queue length = 0x%llx\n", ldcp->rx_q_entries);
2727e1ebb9ecSlm66018
27281ae08745Sheppo /* Create a transmit queue */
27291ae08745Sheppo ldcp->tx_q_va = (uint64_t)
27301ae08745Sheppo contig_mem_alloc(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
27311ae08745Sheppo if (ldcp->tx_q_va == NULL) {
27321ae08745Sheppo cmn_err(CE_WARN,
27331ae08745Sheppo "ldc_init: (0x%lx) TX queue allocation failed\n",
27341ae08745Sheppo ldcp->id);
27351ae08745Sheppo exit_val = ENOMEM;
27361ae08745Sheppo goto cleanup_on_exit;
27371ae08745Sheppo }
27381ae08745Sheppo ldcp->tx_q_ra = va_to_pa((caddr_t)ldcp->tx_q_va);
27391ae08745Sheppo
27401ae08745Sheppo D2(ldcp->id, "ldc_init: txq_va=0x%llx, txq_ra=0x%llx, entries=0x%llx\n",
27411ae08745Sheppo ldcp->tx_q_va, ldcp->tx_q_ra, ldcp->tx_q_entries);
27421ae08745Sheppo
27431ae08745Sheppo ldcp->tstate |= TS_TXQ_RDY;
27441ae08745Sheppo
27451ae08745Sheppo /* Create a receive queue */
27461ae08745Sheppo ldcp->rx_q_va = (uint64_t)
27471ae08745Sheppo contig_mem_alloc(ldcp->rx_q_entries << LDC_PACKET_SHIFT);
27481ae08745Sheppo if (ldcp->rx_q_va == NULL) {
27491ae08745Sheppo cmn_err(CE_WARN,
27501ae08745Sheppo "ldc_init: (0x%lx) RX queue allocation failed\n",
27511ae08745Sheppo ldcp->id);
27521ae08745Sheppo exit_val = ENOMEM;
27531ae08745Sheppo goto cleanup_on_exit;
27541ae08745Sheppo }
27551ae08745Sheppo ldcp->rx_q_ra = va_to_pa((caddr_t)ldcp->rx_q_va);
27561ae08745Sheppo
27571ae08745Sheppo D2(ldcp->id, "ldc_init: rxq_va=0x%llx, rxq_ra=0x%llx, entries=0x%llx\n",
27581ae08745Sheppo ldcp->rx_q_va, ldcp->rx_q_ra, ldcp->rx_q_entries);
27591ae08745Sheppo
27601ae08745Sheppo ldcp->tstate |= TS_RXQ_RDY;
27611ae08745Sheppo
276258283286Sha137994 /* Setup a separate read data queue */
276320ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) {
276458283286Sha137994 ldcp->readq_get_state = i_ldc_dq_rx_get_state;
276558283286Sha137994 ldcp->readq_set_head = i_ldc_set_rxdq_head;
276658283286Sha137994
276758283286Sha137994 /* Make sure the data queue multiplier is a power of 2 */
276858283286Sha137994 if (!ISP2(ldc_rxdq_multiplier)) {
276958283286Sha137994 D1(ldcp->id, "ldc_init: (0x%llx) ldc_rxdq_multiplier "
277058283286Sha137994 "not a power of 2, resetting", ldcp->id);
277158283286Sha137994 ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER;
277258283286Sha137994 }
277358283286Sha137994
277458283286Sha137994 ldcp->rx_dq_entries = ldc_rxdq_multiplier * ldcp->rx_q_entries;
277558283286Sha137994 ldcp->rx_dq_va = (uint64_t)
277658283286Sha137994 kmem_alloc(ldcp->rx_dq_entries << LDC_PACKET_SHIFT,
277758283286Sha137994 KM_SLEEP);
277858283286Sha137994 if (ldcp->rx_dq_va == NULL) {
277958283286Sha137994 cmn_err(CE_WARN,
278058283286Sha137994 "ldc_init: (0x%lx) RX data queue "
278158283286Sha137994 "allocation failed\n", ldcp->id);
278258283286Sha137994 exit_val = ENOMEM;
278358283286Sha137994 goto cleanup_on_exit;
278458283286Sha137994 }
278558283286Sha137994
278658283286Sha137994 ldcp->rx_dq_head = ldcp->rx_dq_tail = 0;
278758283286Sha137994
278858283286Sha137994 D2(ldcp->id, "ldc_init: rx_dq_va=0x%llx, "
278958283286Sha137994 "rx_dq_entries=0x%llx\n", ldcp->rx_dq_va,
279058283286Sha137994 ldcp->rx_dq_entries);
279158283286Sha137994 } else {
279258283286Sha137994 ldcp->readq_get_state = i_ldc_hvq_rx_get_state;
279358283286Sha137994 ldcp->readq_set_head = i_ldc_set_rx_head;
279458283286Sha137994 }
279558283286Sha137994
27961ae08745Sheppo /* Init descriptor ring and memory handle list lock */
27971ae08745Sheppo mutex_init(&ldcp->exp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
27981ae08745Sheppo mutex_init(&ldcp->imp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
27991ae08745Sheppo mutex_init(&ldcp->mlist_lock, NULL, MUTEX_DRIVER, NULL);
28001ae08745Sheppo
28011ae08745Sheppo /* mark status as INITialized */
28021ae08745Sheppo ldcp->status = LDC_INIT;
28031ae08745Sheppo
28041ae08745Sheppo /* Add to channel list */
28051ae08745Sheppo mutex_enter(&ldcssp->lock);
28061ae08745Sheppo ldcp->next = ldcssp->chan_list;
28071ae08745Sheppo ldcssp->chan_list = ldcp;
28081ae08745Sheppo ldcssp->channel_count++;
28091ae08745Sheppo mutex_exit(&ldcssp->lock);
28101ae08745Sheppo
28111ae08745Sheppo /* set the handle */
28121ae08745Sheppo *handle = (ldc_handle_t)ldcp;
28131ae08745Sheppo
28141ae08745Sheppo D1(ldcp->id, "ldc_init: (0x%llx) channel initialized\n", ldcp->id);
28151ae08745Sheppo
28161ae08745Sheppo return (0);
28171ae08745Sheppo
28181ae08745Sheppo cleanup_on_exit:
28191ae08745Sheppo
282020ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp)
28211ae08745Sheppo kmem_free(ldcp->stream_bufferp, ldcp->mtu);
28221ae08745Sheppo
28231ae08745Sheppo if (ldcp->tstate & TS_TXQ_RDY)
28241ae08745Sheppo contig_mem_free((caddr_t)ldcp->tx_q_va,
28251ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
28261ae08745Sheppo
28271ae08745Sheppo if (ldcp->tstate & TS_RXQ_RDY)
28281ae08745Sheppo contig_mem_free((caddr_t)ldcp->rx_q_va,
28291ae08745Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT));
28301ae08745Sheppo
2831d10e4ef2Snarayan mutex_destroy(&ldcp->tx_lock);
28321ae08745Sheppo mutex_destroy(&ldcp->lock);
28331ae08745Sheppo
28341ae08745Sheppo if (ldcp)
28351ae08745Sheppo kmem_free(ldcp, sizeof (ldc_chan_t));
28361ae08745Sheppo
28371ae08745Sheppo return (exit_val);
28381ae08745Sheppo }
28391ae08745Sheppo
28401ae08745Sheppo /*
28411ae08745Sheppo * Finalizes the LDC connection. It will return EBUSY if the
28421ae08745Sheppo * channel is open. A ldc_close() has to be done prior to
28431ae08745Sheppo * a ldc_fini operation. It frees TX/RX queues, associated
28441ae08745Sheppo * with the channel
28451ae08745Sheppo */
28461ae08745Sheppo int
ldc_fini(ldc_handle_t handle)28471ae08745Sheppo ldc_fini(ldc_handle_t handle)
28481ae08745Sheppo {
28491ae08745Sheppo ldc_chan_t *ldcp;
28501ae08745Sheppo ldc_chan_t *tmp_ldcp;
28511ae08745Sheppo uint64_t id;
28521ae08745Sheppo
28531ae08745Sheppo if (handle == NULL) {
28541ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel handle\n");
28551ae08745Sheppo return (EINVAL);
28561ae08745Sheppo }
28571ae08745Sheppo ldcp = (ldc_chan_t *)handle;
28581ae08745Sheppo id = ldcp->id;
28591ae08745Sheppo
28601ae08745Sheppo mutex_enter(&ldcp->lock);
28611ae08745Sheppo
28623af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) > TS_INIT) {
28631ae08745Sheppo DWARN(ldcp->id, "ldc_fini: (0x%llx) channel is open\n",
28641ae08745Sheppo ldcp->id);
28651ae08745Sheppo mutex_exit(&ldcp->lock);
28661ae08745Sheppo return (EBUSY);
28671ae08745Sheppo }
28681ae08745Sheppo
28691ae08745Sheppo /* Remove from the channel list */
28701ae08745Sheppo mutex_enter(&ldcssp->lock);
28711ae08745Sheppo tmp_ldcp = ldcssp->chan_list;
28721ae08745Sheppo if (tmp_ldcp == ldcp) {
28731ae08745Sheppo ldcssp->chan_list = ldcp->next;
28741ae08745Sheppo ldcp->next = NULL;
28751ae08745Sheppo } else {
28761ae08745Sheppo while (tmp_ldcp != NULL) {
28771ae08745Sheppo if (tmp_ldcp->next == ldcp) {
28781ae08745Sheppo tmp_ldcp->next = ldcp->next;
28791ae08745Sheppo ldcp->next = NULL;
28801ae08745Sheppo break;
28811ae08745Sheppo }
28821ae08745Sheppo tmp_ldcp = tmp_ldcp->next;
28831ae08745Sheppo }
28841ae08745Sheppo if (tmp_ldcp == NULL) {
28851ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel hdl\n");
28861ae08745Sheppo mutex_exit(&ldcssp->lock);
28871ae08745Sheppo mutex_exit(&ldcp->lock);
28881ae08745Sheppo return (EINVAL);
28891ae08745Sheppo }
28901ae08745Sheppo }
28911ae08745Sheppo
28921ae08745Sheppo ldcssp->channel_count--;
28931ae08745Sheppo
28941ae08745Sheppo mutex_exit(&ldcssp->lock);
28951ae08745Sheppo
28961ae08745Sheppo /* Free the map table for this channel */
28971ae08745Sheppo if (ldcp->mtbl) {
28981ae08745Sheppo (void) hv_ldc_set_map_table(ldcp->id, NULL, NULL);
28993af08d82Slm66018 if (ldcp->mtbl->contigmem)
29001ae08745Sheppo contig_mem_free(ldcp->mtbl->table, ldcp->mtbl->size);
29013af08d82Slm66018 else
29023af08d82Slm66018 kmem_free(ldcp->mtbl->table, ldcp->mtbl->size);
29031ae08745Sheppo mutex_destroy(&ldcp->mtbl->lock);
29041ae08745Sheppo kmem_free(ldcp->mtbl, sizeof (ldc_mtbl_t));
29051ae08745Sheppo }
29061ae08745Sheppo
29071ae08745Sheppo /* Destroy descriptor ring and memory handle list lock */
29081ae08745Sheppo mutex_destroy(&ldcp->exp_dlist_lock);
29091ae08745Sheppo mutex_destroy(&ldcp->imp_dlist_lock);
29101ae08745Sheppo mutex_destroy(&ldcp->mlist_lock);
29111ae08745Sheppo
291220ae46ebSha137994 /* Free the stream buffer for RELIABLE_MODE */
291320ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp)
29141ae08745Sheppo kmem_free(ldcp->stream_bufferp, ldcp->mtu);
29151ae08745Sheppo
29161ae08745Sheppo /* Free the RX queue */
29171ae08745Sheppo contig_mem_free((caddr_t)ldcp->rx_q_va,
29181ae08745Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT));
29191ae08745Sheppo ldcp->tstate &= ~TS_RXQ_RDY;
29201ae08745Sheppo
292158283286Sha137994 /* Free the RX data queue */
292220ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) {
292358283286Sha137994 kmem_free((caddr_t)ldcp->rx_dq_va,
292458283286Sha137994 (ldcp->rx_dq_entries << LDC_PACKET_SHIFT));
292558283286Sha137994 }
292658283286Sha137994
29271ae08745Sheppo /* Free the TX queue */
29281ae08745Sheppo contig_mem_free((caddr_t)ldcp->tx_q_va,
29291ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
29301ae08745Sheppo ldcp->tstate &= ~TS_TXQ_RDY;
29311ae08745Sheppo
29321ae08745Sheppo mutex_exit(&ldcp->lock);
29331ae08745Sheppo
29341ae08745Sheppo /* Destroy mutex */
2935d10e4ef2Snarayan mutex_destroy(&ldcp->tx_lock);
29361ae08745Sheppo mutex_destroy(&ldcp->lock);
29371ae08745Sheppo
29381ae08745Sheppo /* free channel structure */
29391ae08745Sheppo kmem_free(ldcp, sizeof (ldc_chan_t));
29401ae08745Sheppo
29411ae08745Sheppo D1(id, "ldc_fini: (0x%llx) channel finalized\n", id);
29421ae08745Sheppo
29431ae08745Sheppo return (0);
29441ae08745Sheppo }
29451ae08745Sheppo
29461ae08745Sheppo /*
29471ae08745Sheppo * Open the LDC channel for use. It registers the TX/RX queues
29481ae08745Sheppo * with the Hypervisor. It also specifies the interrupt number
29491ae08745Sheppo * and target CPU for this channel
29501ae08745Sheppo */
29511ae08745Sheppo int
ldc_open(ldc_handle_t handle)29521ae08745Sheppo ldc_open(ldc_handle_t handle)
29531ae08745Sheppo {
29541ae08745Sheppo ldc_chan_t *ldcp;
29551ae08745Sheppo int rv;
29561ae08745Sheppo
29571ae08745Sheppo if (handle == NULL) {
29581ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_open: invalid channel handle\n");
29591ae08745Sheppo return (EINVAL);
29601ae08745Sheppo }
29611ae08745Sheppo
29621ae08745Sheppo ldcp = (ldc_chan_t *)handle;
29631ae08745Sheppo
29641ae08745Sheppo mutex_enter(&ldcp->lock);
29651ae08745Sheppo
29661ae08745Sheppo if (ldcp->tstate < TS_INIT) {
29671ae08745Sheppo DWARN(ldcp->id,
29681ae08745Sheppo "ldc_open: (0x%llx) channel not initialized\n", ldcp->id);
29691ae08745Sheppo mutex_exit(&ldcp->lock);
29701ae08745Sheppo return (EFAULT);
29711ae08745Sheppo }
29723af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) >= TS_OPEN) {
29731ae08745Sheppo DWARN(ldcp->id,
29741ae08745Sheppo "ldc_open: (0x%llx) channel is already open\n", ldcp->id);
29751ae08745Sheppo mutex_exit(&ldcp->lock);
29761ae08745Sheppo return (EFAULT);
29771ae08745Sheppo }
29781ae08745Sheppo
29791ae08745Sheppo /*
29801ae08745Sheppo * Unregister/Register the tx queue with the hypervisor
29811ae08745Sheppo */
29821ae08745Sheppo rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
29831ae08745Sheppo if (rv) {
29841ae08745Sheppo cmn_err(CE_WARN,
29851ae08745Sheppo "ldc_open: (0x%lx) channel tx queue unconf failed\n",
29861ae08745Sheppo ldcp->id);
29871ae08745Sheppo mutex_exit(&ldcp->lock);
29881ae08745Sheppo return (EIO);
29891ae08745Sheppo }
29901ae08745Sheppo
29911ae08745Sheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
29921ae08745Sheppo if (rv) {
29931ae08745Sheppo cmn_err(CE_WARN,
29941ae08745Sheppo "ldc_open: (0x%lx) channel tx queue conf failed\n",
29951ae08745Sheppo ldcp->id);
29961ae08745Sheppo mutex_exit(&ldcp->lock);
29971ae08745Sheppo return (EIO);
29981ae08745Sheppo }
29991ae08745Sheppo
30001ae08745Sheppo D2(ldcp->id, "ldc_open: (0x%llx) registered tx queue with LDC\n",
30011ae08745Sheppo ldcp->id);
30021ae08745Sheppo
30031ae08745Sheppo /*
30041ae08745Sheppo * Unregister/Register the rx queue with the hypervisor
30051ae08745Sheppo */
30061ae08745Sheppo rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
30071ae08745Sheppo if (rv) {
30081ae08745Sheppo cmn_err(CE_WARN,
30091ae08745Sheppo "ldc_open: (0x%lx) channel rx queue unconf failed\n",
30101ae08745Sheppo ldcp->id);
30111ae08745Sheppo mutex_exit(&ldcp->lock);
30121ae08745Sheppo return (EIO);
30131ae08745Sheppo }
30141ae08745Sheppo
30151ae08745Sheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, ldcp->rx_q_entries);
30161ae08745Sheppo if (rv) {
30171ae08745Sheppo cmn_err(CE_WARN,
30181ae08745Sheppo "ldc_open: (0x%lx) channel rx queue conf failed\n",
30191ae08745Sheppo ldcp->id);
30201ae08745Sheppo mutex_exit(&ldcp->lock);
30211ae08745Sheppo return (EIO);
30221ae08745Sheppo }
30231ae08745Sheppo
30241ae08745Sheppo D2(ldcp->id, "ldc_open: (0x%llx) registered rx queue with LDC\n",
30251ae08745Sheppo ldcp->id);
30261ae08745Sheppo
30271ae08745Sheppo ldcp->tstate |= TS_QCONF_RDY;
30281ae08745Sheppo
30291ae08745Sheppo /* Register the channel with the channel nexus */
30301ae08745Sheppo rv = i_ldc_register_channel(ldcp);
30311ae08745Sheppo if (rv && rv != EAGAIN) {
30321ae08745Sheppo cmn_err(CE_WARN,
30331ae08745Sheppo "ldc_open: (0x%lx) channel register failed\n", ldcp->id);
30345699897cSHaik Aftandilian ldcp->tstate &= ~TS_QCONF_RDY;
30351ae08745Sheppo (void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
30361ae08745Sheppo (void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
30371ae08745Sheppo mutex_exit(&ldcp->lock);
30381ae08745Sheppo return (EIO);
30391ae08745Sheppo }
30401ae08745Sheppo
30411ae08745Sheppo /* mark channel in OPEN state */
30421ae08745Sheppo ldcp->status = LDC_OPEN;
30431ae08745Sheppo
30441ae08745Sheppo /* Read channel state */
30451ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id,
30461ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
30471ae08745Sheppo if (rv) {
30481ae08745Sheppo cmn_err(CE_WARN,
30491ae08745Sheppo "ldc_open: (0x%lx) cannot read channel state\n",
30501ae08745Sheppo ldcp->id);
30511ae08745Sheppo (void) i_ldc_unregister_channel(ldcp);
30525699897cSHaik Aftandilian ldcp->tstate &= ~TS_QCONF_RDY;
30531ae08745Sheppo (void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
30541ae08745Sheppo (void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
30551ae08745Sheppo mutex_exit(&ldcp->lock);
30561ae08745Sheppo return (EIO);
30571ae08745Sheppo }
30581ae08745Sheppo
30591ae08745Sheppo /*
306020ae46ebSha137994 * set the ACKd head to current head location for reliable
30611ae08745Sheppo */
30621ae08745Sheppo ldcp->tx_ackd_head = ldcp->tx_head;
30631ae08745Sheppo
30641ae08745Sheppo /* mark channel ready if HV report link is UP (peer alloc'd Rx queue) */
30651ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_UP ||
30661ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) {
30671ae08745Sheppo ldcp->tstate |= TS_LINK_READY;
30681ae08745Sheppo ldcp->status = LDC_READY;
30691ae08745Sheppo }
30701ae08745Sheppo
30711ae08745Sheppo /*
30721ae08745Sheppo * if channel is being opened in RAW mode - no handshake is needed
30731ae08745Sheppo * switch the channel READY and UP state
30741ae08745Sheppo */
30751ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW) {
30761ae08745Sheppo ldcp->tstate = TS_UP; /* set bits associated with LDC UP */
30771ae08745Sheppo ldcp->status = LDC_UP;
30781ae08745Sheppo }
30791ae08745Sheppo
30801ae08745Sheppo mutex_exit(&ldcp->lock);
30811ae08745Sheppo
30821ae08745Sheppo /*
30831ae08745Sheppo * Increment number of open channels
30841ae08745Sheppo */
30851ae08745Sheppo mutex_enter(&ldcssp->lock);
30861ae08745Sheppo ldcssp->channels_open++;
30871ae08745Sheppo mutex_exit(&ldcssp->lock);
30881ae08745Sheppo
3089cb112a14Slm66018 D1(ldcp->id,
30903af08d82Slm66018 "ldc_open: (0x%llx) channel (0x%p) open for use "
30913af08d82Slm66018 "(tstate=0x%x, status=0x%x)\n",
30923af08d82Slm66018 ldcp->id, ldcp, ldcp->tstate, ldcp->status);
30931ae08745Sheppo
30941ae08745Sheppo return (0);
30951ae08745Sheppo }
30961ae08745Sheppo
30971ae08745Sheppo /*
30981ae08745Sheppo * Close the LDC connection. It will return EBUSY if there
30991ae08745Sheppo * are memory segments or descriptor rings either bound to or
31001ae08745Sheppo * mapped over the channel
31011ae08745Sheppo */
31021ae08745Sheppo int
ldc_close(ldc_handle_t handle)31031ae08745Sheppo ldc_close(ldc_handle_t handle)
31041ae08745Sheppo {
31051ae08745Sheppo ldc_chan_t *ldcp;
3106d10e4ef2Snarayan int rv = 0, retries = 0;
31071ae08745Sheppo boolean_t chk_done = B_FALSE;
31081ae08745Sheppo
31091ae08745Sheppo if (handle == NULL) {
31101ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_close: invalid channel handle\n");
31111ae08745Sheppo return (EINVAL);
31121ae08745Sheppo }
31131ae08745Sheppo ldcp = (ldc_chan_t *)handle;
31141ae08745Sheppo
31151ae08745Sheppo mutex_enter(&ldcp->lock);
31161ae08745Sheppo
31171ae08745Sheppo /* return error if channel is not open */
31183af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) < TS_OPEN) {
31191ae08745Sheppo DWARN(ldcp->id,
31201ae08745Sheppo "ldc_close: (0x%llx) channel is not open\n", ldcp->id);
31211ae08745Sheppo mutex_exit(&ldcp->lock);
31221ae08745Sheppo return (EFAULT);
31231ae08745Sheppo }
31241ae08745Sheppo
31251ae08745Sheppo /* if any memory handles, drings, are bound or mapped cannot close */
31261ae08745Sheppo if (ldcp->mhdl_list != NULL) {
31271ae08745Sheppo DWARN(ldcp->id,
31281ae08745Sheppo "ldc_close: (0x%llx) channel has bound memory handles\n",
31291ae08745Sheppo ldcp->id);
31301ae08745Sheppo mutex_exit(&ldcp->lock);
31311ae08745Sheppo return (EBUSY);
31321ae08745Sheppo }
31331ae08745Sheppo if (ldcp->exp_dring_list != NULL) {
31341ae08745Sheppo DWARN(ldcp->id,
31351ae08745Sheppo "ldc_close: (0x%llx) channel has bound descriptor rings\n",
31361ae08745Sheppo ldcp->id);
31371ae08745Sheppo mutex_exit(&ldcp->lock);
31381ae08745Sheppo return (EBUSY);
31391ae08745Sheppo }
31401ae08745Sheppo if (ldcp->imp_dring_list != NULL) {
31411ae08745Sheppo DWARN(ldcp->id,
31421ae08745Sheppo "ldc_close: (0x%llx) channel has mapped descriptor rings\n",
31431ae08745Sheppo ldcp->id);
31441ae08745Sheppo mutex_exit(&ldcp->lock);
31451ae08745Sheppo return (EBUSY);
31461ae08745Sheppo }
31471ae08745Sheppo
31484d39be2bSsg70180 if (ldcp->cb_inprogress) {
31494d39be2bSsg70180 DWARN(ldcp->id, "ldc_close: (0x%llx) callback active\n",
31504d39be2bSsg70180 ldcp->id);
31514d39be2bSsg70180 mutex_exit(&ldcp->lock);
31524d39be2bSsg70180 return (EWOULDBLOCK);
31534d39be2bSsg70180 }
31544d39be2bSsg70180
3155d10e4ef2Snarayan /* Obtain Tx lock */
3156d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
3157d10e4ef2Snarayan
31581ae08745Sheppo /*
31591ae08745Sheppo * Wait for pending transmits to complete i.e Tx queue to drain
31601ae08745Sheppo * if there are pending pkts - wait 1 ms and retry again
31611ae08745Sheppo */
31621ae08745Sheppo for (;;) {
31631ae08745Sheppo
31641ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id,
31651ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
31661ae08745Sheppo if (rv) {
31671ae08745Sheppo cmn_err(CE_WARN,
31681ae08745Sheppo "ldc_close: (0x%lx) cannot read qptrs\n", ldcp->id);
3169d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
31701ae08745Sheppo mutex_exit(&ldcp->lock);
31711ae08745Sheppo return (EIO);
31721ae08745Sheppo }
31731ae08745Sheppo
31741ae08745Sheppo if (ldcp->tx_head == ldcp->tx_tail ||
31751ae08745Sheppo ldcp->link_state != LDC_CHANNEL_UP) {
31761ae08745Sheppo break;
31771ae08745Sheppo }
31781ae08745Sheppo
31791ae08745Sheppo if (chk_done) {
31801ae08745Sheppo DWARN(ldcp->id,
31811ae08745Sheppo "ldc_close: (0x%llx) Tx queue drain timeout\n",
31821ae08745Sheppo ldcp->id);
31831ae08745Sheppo break;
31841ae08745Sheppo }
31851ae08745Sheppo
31861ae08745Sheppo /* wait for one ms and try again */
31871ae08745Sheppo delay(drv_usectohz(1000));
31881ae08745Sheppo chk_done = B_TRUE;
31891ae08745Sheppo }
31901ae08745Sheppo
31911ae08745Sheppo /*
3192a8ea4edeSnarayan * Drain the Tx and Rx queues as we are closing the
3193a8ea4edeSnarayan * channel. We dont care about any pending packets.
3194a8ea4edeSnarayan * We have to also drain the queue prior to clearing
3195a8ea4edeSnarayan * pending interrupts, otherwise the HV will trigger
3196a8ea4edeSnarayan * an interrupt the moment the interrupt state is
3197a8ea4edeSnarayan * cleared.
31983af08d82Slm66018 */
31993af08d82Slm66018 (void) i_ldc_txq_reconf(ldcp);
3200305dbad4SKevin Crowe i_ldc_rxq_drain(ldcp);
32013af08d82Slm66018
32023af08d82Slm66018 /*
32031ae08745Sheppo * Unregister the channel with the nexus
32041ae08745Sheppo */
3205d10e4ef2Snarayan while ((rv = i_ldc_unregister_channel(ldcp)) != 0) {
3206d10e4ef2Snarayan
3207d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
32081ae08745Sheppo mutex_exit(&ldcp->lock);
3209d10e4ef2Snarayan
3210d10e4ef2Snarayan /* if any error other than EAGAIN return back */
3211a8ea4edeSnarayan if (rv != EAGAIN || retries >= ldc_max_retries) {
3212d10e4ef2Snarayan cmn_err(CE_WARN,
3213d10e4ef2Snarayan "ldc_close: (0x%lx) unregister failed, %d\n",
3214d10e4ef2Snarayan ldcp->id, rv);
32151ae08745Sheppo return (rv);
32161ae08745Sheppo }
32171ae08745Sheppo
32181ae08745Sheppo /*
3219d10e4ef2Snarayan * As there could be pending interrupts we need
3220d10e4ef2Snarayan * to wait and try again
3221d10e4ef2Snarayan */
32224d39be2bSsg70180 drv_usecwait(ldc_close_delay);
3223d10e4ef2Snarayan mutex_enter(&ldcp->lock);
3224d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
3225d10e4ef2Snarayan retries++;
3226d10e4ef2Snarayan }
3227d10e4ef2Snarayan
32285699897cSHaik Aftandilian ldcp->tstate &= ~TS_QCONF_RDY;
32295699897cSHaik Aftandilian
3230d10e4ef2Snarayan /*
32311ae08745Sheppo * Unregister queues
32321ae08745Sheppo */
32331ae08745Sheppo rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL);
32341ae08745Sheppo if (rv) {
32351ae08745Sheppo cmn_err(CE_WARN,
32361ae08745Sheppo "ldc_close: (0x%lx) channel TX queue unconf failed\n",
32371ae08745Sheppo ldcp->id);
3238d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
32391ae08745Sheppo mutex_exit(&ldcp->lock);
32401ae08745Sheppo return (EIO);
32411ae08745Sheppo }
32421ae08745Sheppo rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL);
32431ae08745Sheppo if (rv) {
32441ae08745Sheppo cmn_err(CE_WARN,
32451ae08745Sheppo "ldc_close: (0x%lx) channel RX queue unconf failed\n",
32461ae08745Sheppo ldcp->id);
3247d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
32481ae08745Sheppo mutex_exit(&ldcp->lock);
32491ae08745Sheppo return (EIO);
32501ae08745Sheppo }
32511ae08745Sheppo
32521ae08745Sheppo /* Reset channel state information */
32531ae08745Sheppo i_ldc_reset_state(ldcp);
32541ae08745Sheppo
32551ae08745Sheppo /* Mark channel as down and in initialized state */
32561ae08745Sheppo ldcp->tx_ackd_head = 0;
32571ae08745Sheppo ldcp->tx_head = 0;
32583af08d82Slm66018 ldcp->tstate = TS_IN_RESET|TS_INIT;
32591ae08745Sheppo ldcp->status = LDC_INIT;
32601ae08745Sheppo
3261d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
32621ae08745Sheppo mutex_exit(&ldcp->lock);
32631ae08745Sheppo
32641ae08745Sheppo /* Decrement number of open channels */
32651ae08745Sheppo mutex_enter(&ldcssp->lock);
32661ae08745Sheppo ldcssp->channels_open--;
32671ae08745Sheppo mutex_exit(&ldcssp->lock);
32681ae08745Sheppo
32691ae08745Sheppo D1(ldcp->id, "ldc_close: (0x%llx) channel closed\n", ldcp->id);
32701ae08745Sheppo
32711ae08745Sheppo return (0);
32721ae08745Sheppo }
32731ae08745Sheppo
32741ae08745Sheppo /*
32751ae08745Sheppo * Register channel callback
32761ae08745Sheppo */
32771ae08745Sheppo int
ldc_reg_callback(ldc_handle_t handle,uint_t (* cb)(uint64_t event,caddr_t arg),caddr_t arg)32781ae08745Sheppo ldc_reg_callback(ldc_handle_t handle,
32791ae08745Sheppo uint_t(*cb)(uint64_t event, caddr_t arg), caddr_t arg)
32801ae08745Sheppo {
32811ae08745Sheppo ldc_chan_t *ldcp;
32821ae08745Sheppo
32831ae08745Sheppo if (handle == NULL) {
32841ae08745Sheppo DWARN(DBG_ALL_LDCS,
32851ae08745Sheppo "ldc_reg_callback: invalid channel handle\n");
32861ae08745Sheppo return (EINVAL);
32871ae08745Sheppo }
32881ae08745Sheppo if (((uint64_t)cb) < KERNELBASE) {
32891ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_reg_callback: invalid callback\n");
32901ae08745Sheppo return (EINVAL);
32911ae08745Sheppo }
32921ae08745Sheppo ldcp = (ldc_chan_t *)handle;
32931ae08745Sheppo
32941ae08745Sheppo mutex_enter(&ldcp->lock);
32951ae08745Sheppo
32961ae08745Sheppo if (ldcp->cb) {
32971ae08745Sheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback exists\n",
32981ae08745Sheppo ldcp->id);
32991ae08745Sheppo mutex_exit(&ldcp->lock);
33001ae08745Sheppo return (EIO);
33011ae08745Sheppo }
33021ae08745Sheppo if (ldcp->cb_inprogress) {
33031ae08745Sheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback active\n",
33041ae08745Sheppo ldcp->id);
33051ae08745Sheppo mutex_exit(&ldcp->lock);
33061ae08745Sheppo return (EWOULDBLOCK);
33071ae08745Sheppo }
33081ae08745Sheppo
33091ae08745Sheppo ldcp->cb = cb;
33101ae08745Sheppo ldcp->cb_arg = arg;
33111ae08745Sheppo ldcp->cb_enabled = B_TRUE;
33121ae08745Sheppo
33131ae08745Sheppo D1(ldcp->id,
33141ae08745Sheppo "ldc_reg_callback: (0x%llx) registered callback for channel\n",
33151ae08745Sheppo ldcp->id);
33161ae08745Sheppo
33171ae08745Sheppo mutex_exit(&ldcp->lock);
33181ae08745Sheppo
33191ae08745Sheppo return (0);
33201ae08745Sheppo }
33211ae08745Sheppo
33221ae08745Sheppo /*
33231ae08745Sheppo * Unregister channel callback
33241ae08745Sheppo */
33251ae08745Sheppo int
ldc_unreg_callback(ldc_handle_t handle)33261ae08745Sheppo ldc_unreg_callback(ldc_handle_t handle)
33271ae08745Sheppo {
33281ae08745Sheppo ldc_chan_t *ldcp;
33291ae08745Sheppo
33301ae08745Sheppo if (handle == NULL) {
33311ae08745Sheppo DWARN(DBG_ALL_LDCS,
33321ae08745Sheppo "ldc_unreg_callback: invalid channel handle\n");
33331ae08745Sheppo return (EINVAL);
33341ae08745Sheppo }
33351ae08745Sheppo ldcp = (ldc_chan_t *)handle;
33361ae08745Sheppo
33371ae08745Sheppo mutex_enter(&ldcp->lock);
33381ae08745Sheppo
33391ae08745Sheppo if (ldcp->cb == NULL) {
33401ae08745Sheppo DWARN(ldcp->id,
33411ae08745Sheppo "ldc_unreg_callback: (0x%llx) no callback exists\n",
33421ae08745Sheppo ldcp->id);
33431ae08745Sheppo mutex_exit(&ldcp->lock);
33441ae08745Sheppo return (EIO);
33451ae08745Sheppo }
33461ae08745Sheppo if (ldcp->cb_inprogress) {
33471ae08745Sheppo DWARN(ldcp->id,
33481ae08745Sheppo "ldc_unreg_callback: (0x%llx) callback active\n",
33491ae08745Sheppo ldcp->id);
33501ae08745Sheppo mutex_exit(&ldcp->lock);
33511ae08745Sheppo return (EWOULDBLOCK);
33521ae08745Sheppo }
33531ae08745Sheppo
33541ae08745Sheppo ldcp->cb = NULL;
33551ae08745Sheppo ldcp->cb_arg = NULL;
33561ae08745Sheppo ldcp->cb_enabled = B_FALSE;
33571ae08745Sheppo
33581ae08745Sheppo D1(ldcp->id,
33591ae08745Sheppo "ldc_unreg_callback: (0x%llx) unregistered callback for channel\n",
33601ae08745Sheppo ldcp->id);
33611ae08745Sheppo
33621ae08745Sheppo mutex_exit(&ldcp->lock);
33631ae08745Sheppo
33641ae08745Sheppo return (0);
33651ae08745Sheppo }
33661ae08745Sheppo
33671ae08745Sheppo
33681ae08745Sheppo /*
33691ae08745Sheppo * Bring a channel up by initiating a handshake with the peer
33701ae08745Sheppo * This call is asynchronous. It will complete at a later point
33711ae08745Sheppo * in time when the peer responds back with an RTR.
33721ae08745Sheppo */
33731ae08745Sheppo int
ldc_up(ldc_handle_t handle)33741ae08745Sheppo ldc_up(ldc_handle_t handle)
33751ae08745Sheppo {
33761ae08745Sheppo int rv;
33771ae08745Sheppo ldc_chan_t *ldcp;
33781ae08745Sheppo ldc_msg_t *ldcmsg;
337957e6a936Ssb155480 uint64_t tx_tail, tstate, link_state;
33801ae08745Sheppo
33811ae08745Sheppo if (handle == NULL) {
33821ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_up: invalid channel handle\n");
33831ae08745Sheppo return (EINVAL);
33841ae08745Sheppo }
33851ae08745Sheppo ldcp = (ldc_chan_t *)handle;
33861ae08745Sheppo
33871ae08745Sheppo mutex_enter(&ldcp->lock);
33881ae08745Sheppo
33893af08d82Slm66018 D1(ldcp->id, "ldc_up: (0x%llx) doing channel UP\n", ldcp->id);
33903af08d82Slm66018
33913af08d82Slm66018 /* clear the reset state */
33923af08d82Slm66018 tstate = ldcp->tstate;
33933af08d82Slm66018 ldcp->tstate &= ~TS_IN_RESET;
33943af08d82Slm66018
33951ae08745Sheppo if (ldcp->tstate == TS_UP) {
33963af08d82Slm66018 DWARN(ldcp->id,
33971ae08745Sheppo "ldc_up: (0x%llx) channel is already in UP state\n",
33981ae08745Sheppo ldcp->id);
33993af08d82Slm66018
34003af08d82Slm66018 /* mark channel as up */
34013af08d82Slm66018 ldcp->status = LDC_UP;
34023af08d82Slm66018
34033af08d82Slm66018 /*
34043af08d82Slm66018 * if channel was in reset state and there was
34053af08d82Slm66018 * pending data clear interrupt state. this will
34063af08d82Slm66018 * trigger an interrupt, causing the RX handler to
34073af08d82Slm66018 * to invoke the client's callback
34083af08d82Slm66018 */
34093af08d82Slm66018 if ((tstate & TS_IN_RESET) &&
34103af08d82Slm66018 ldcp->rx_intr_state == LDC_INTR_PEND) {
3411cb112a14Slm66018 D1(ldcp->id,
34123af08d82Slm66018 "ldc_up: (0x%llx) channel has pending data, "
34133af08d82Slm66018 "clearing interrupt\n", ldcp->id);
34143af08d82Slm66018 i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
34153af08d82Slm66018 }
34163af08d82Slm66018
34171ae08745Sheppo mutex_exit(&ldcp->lock);
34181ae08745Sheppo return (0);
34191ae08745Sheppo }
34201ae08745Sheppo
34211ae08745Sheppo /* if the channel is in RAW mode - mark it as UP, if READY */
34221ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW && ldcp->tstate >= TS_READY) {
34231ae08745Sheppo ldcp->tstate = TS_UP;
34241ae08745Sheppo mutex_exit(&ldcp->lock);
34251ae08745Sheppo return (0);
34261ae08745Sheppo }
34271ae08745Sheppo
34281ae08745Sheppo /* Don't start another handshake if there is one in progress */
34291ae08745Sheppo if (ldcp->hstate) {
34303af08d82Slm66018 D1(ldcp->id,
34311ae08745Sheppo "ldc_up: (0x%llx) channel handshake in progress\n",
34321ae08745Sheppo ldcp->id);
34331ae08745Sheppo mutex_exit(&ldcp->lock);
34341ae08745Sheppo return (0);
34351ae08745Sheppo }
34361ae08745Sheppo
3437d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
3438d10e4ef2Snarayan
343957e6a936Ssb155480 /* save current link state */
344057e6a936Ssb155480 link_state = ldcp->link_state;
344157e6a936Ssb155480
34421ae08745Sheppo /* get the current tail for the LDC msg */
34431ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail);
34441ae08745Sheppo if (rv) {
3445cb112a14Slm66018 D1(ldcp->id, "ldc_up: (0x%llx) cannot initiate handshake\n",
34461ae08745Sheppo ldcp->id);
3447d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
34481ae08745Sheppo mutex_exit(&ldcp->lock);
34491ae08745Sheppo return (ECONNREFUSED);
34501ae08745Sheppo }
34511ae08745Sheppo
345257e6a936Ssb155480 /*
345357e6a936Ssb155480 * If i_ldc_get_tx_tail() changed link_state to either RESET or UP,
345457e6a936Ssb155480 * from a previous state of DOWN, then mark the channel as
345557e6a936Ssb155480 * being ready for handshake.
345657e6a936Ssb155480 */
345757e6a936Ssb155480 if ((link_state == LDC_CHANNEL_DOWN) &&
345857e6a936Ssb155480 (link_state != ldcp->link_state)) {
345957e6a936Ssb155480
346057e6a936Ssb155480 ASSERT((ldcp->link_state == LDC_CHANNEL_RESET) ||
346157e6a936Ssb155480 (ldcp->link_state == LDC_CHANNEL_UP));
346257e6a936Ssb155480
346357e6a936Ssb155480 if (ldcp->mode == LDC_MODE_RAW) {
346457e6a936Ssb155480 ldcp->status = LDC_UP;
346557e6a936Ssb155480 ldcp->tstate = TS_UP;
346657e6a936Ssb155480 mutex_exit(&ldcp->tx_lock);
346757e6a936Ssb155480 mutex_exit(&ldcp->lock);
346857e6a936Ssb155480 return (0);
346957e6a936Ssb155480 } else {
347057e6a936Ssb155480 ldcp->status = LDC_READY;
347157e6a936Ssb155480 ldcp->tstate |= TS_LINK_READY;
347257e6a936Ssb155480 }
347357e6a936Ssb155480
347457e6a936Ssb155480 }
347557e6a936Ssb155480
34761ae08745Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
34771ae08745Sheppo ZERO_PKT(ldcmsg);
34781ae08745Sheppo
34791ae08745Sheppo ldcmsg->type = LDC_CTRL;
34801ae08745Sheppo ldcmsg->stype = LDC_INFO;
34811ae08745Sheppo ldcmsg->ctrl = LDC_VER;
34821ae08745Sheppo ldcp->next_vidx = 0;
34831ae08745Sheppo bcopy(&ldc_versions[0], ldcmsg->udata, sizeof (ldc_versions[0]));
34841ae08745Sheppo
34851ae08745Sheppo DUMP_LDC_PKT(ldcp, "ldc_up snd ver", (uint64_t)ldcmsg);
34861ae08745Sheppo
34871ae08745Sheppo /* initiate the send by calling into HV and set the new tail */
34881ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) %
34891ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
34901ae08745Sheppo
34911ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail);
34921ae08745Sheppo if (rv) {
34931ae08745Sheppo DWARN(ldcp->id,
34941ae08745Sheppo "ldc_up: (0x%llx) cannot initiate handshake rv=%d\n",
34951ae08745Sheppo ldcp->id, rv);
3496d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
34971ae08745Sheppo mutex_exit(&ldcp->lock);
34981ae08745Sheppo return (rv);
34991ae08745Sheppo }
35001ae08745Sheppo
35010a55fbb7Slm66018 ldcp->hstate |= TS_SENT_VER;
35021ae08745Sheppo ldcp->tx_tail = tx_tail;
35031ae08745Sheppo D1(ldcp->id, "ldc_up: (0x%llx) channel up initiated\n", ldcp->id);
35041ae08745Sheppo
3505d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
35061ae08745Sheppo mutex_exit(&ldcp->lock);
35071ae08745Sheppo
35081ae08745Sheppo return (rv);
35091ae08745Sheppo }
35101ae08745Sheppo
35111ae08745Sheppo
35121ae08745Sheppo /*
3513e1ebb9ecSlm66018 * Bring a channel down by resetting its state and queues
35141ae08745Sheppo */
35151ae08745Sheppo int
ldc_down(ldc_handle_t handle)3516e1ebb9ecSlm66018 ldc_down(ldc_handle_t handle)
35171ae08745Sheppo {
35181ae08745Sheppo ldc_chan_t *ldcp;
35191ae08745Sheppo
35201ae08745Sheppo if (handle == NULL) {
3521e1ebb9ecSlm66018 DWARN(DBG_ALL_LDCS, "ldc_down: invalid channel handle\n");
35221ae08745Sheppo return (EINVAL);
35231ae08745Sheppo }
35241ae08745Sheppo ldcp = (ldc_chan_t *)handle;
35251ae08745Sheppo mutex_enter(&ldcp->lock);
3526d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
35273af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
3528d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
35291ae08745Sheppo mutex_exit(&ldcp->lock);
35301ae08745Sheppo
35311ae08745Sheppo return (0);
35321ae08745Sheppo }
35331ae08745Sheppo
35341ae08745Sheppo /*
35351ae08745Sheppo * Get the current channel status
35361ae08745Sheppo */
35371ae08745Sheppo int
ldc_status(ldc_handle_t handle,ldc_status_t * status)35381ae08745Sheppo ldc_status(ldc_handle_t handle, ldc_status_t *status)
35391ae08745Sheppo {
35401ae08745Sheppo ldc_chan_t *ldcp;
35411ae08745Sheppo
35421ae08745Sheppo if (handle == NULL || status == NULL) {
35431ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_status: invalid argument\n");
35441ae08745Sheppo return (EINVAL);
35451ae08745Sheppo }
35461ae08745Sheppo ldcp = (ldc_chan_t *)handle;
35471ae08745Sheppo
35481ae08745Sheppo *status = ((ldc_chan_t *)handle)->status;
35491ae08745Sheppo
3550cb112a14Slm66018 D1(ldcp->id,
35511ae08745Sheppo "ldc_status: (0x%llx) returned status %d\n", ldcp->id, *status);
35521ae08745Sheppo return (0);
35531ae08745Sheppo }
35541ae08745Sheppo
35551ae08745Sheppo
35561ae08745Sheppo /*
35571ae08745Sheppo * Set the channel's callback mode - enable/disable callbacks
35581ae08745Sheppo */
35591ae08745Sheppo int
ldc_set_cb_mode(ldc_handle_t handle,ldc_cb_mode_t cmode)35601ae08745Sheppo ldc_set_cb_mode(ldc_handle_t handle, ldc_cb_mode_t cmode)
35611ae08745Sheppo {
35621ae08745Sheppo ldc_chan_t *ldcp;
35631ae08745Sheppo
35641ae08745Sheppo if (handle == NULL) {
35651ae08745Sheppo DWARN(DBG_ALL_LDCS,
35661ae08745Sheppo "ldc_set_intr_mode: invalid channel handle\n");
35671ae08745Sheppo return (EINVAL);
35681ae08745Sheppo }
35691ae08745Sheppo ldcp = (ldc_chan_t *)handle;
35701ae08745Sheppo
35711ae08745Sheppo /*
35721ae08745Sheppo * Record no callbacks should be invoked
35731ae08745Sheppo */
35741ae08745Sheppo mutex_enter(&ldcp->lock);
35751ae08745Sheppo
35761ae08745Sheppo switch (cmode) {
35771ae08745Sheppo case LDC_CB_DISABLE:
35781ae08745Sheppo if (!ldcp->cb_enabled) {
35791ae08745Sheppo DWARN(ldcp->id,
35801ae08745Sheppo "ldc_set_cb_mode: (0x%llx) callbacks disabled\n",
35811ae08745Sheppo ldcp->id);
35821ae08745Sheppo break;
35831ae08745Sheppo }
35841ae08745Sheppo ldcp->cb_enabled = B_FALSE;
35851ae08745Sheppo
35861ae08745Sheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) disabled callbacks\n",
35871ae08745Sheppo ldcp->id);
35881ae08745Sheppo break;
35891ae08745Sheppo
35901ae08745Sheppo case LDC_CB_ENABLE:
35911ae08745Sheppo if (ldcp->cb_enabled) {
35921ae08745Sheppo DWARN(ldcp->id,
35931ae08745Sheppo "ldc_set_cb_mode: (0x%llx) callbacks enabled\n",
35941ae08745Sheppo ldcp->id);
35951ae08745Sheppo break;
35961ae08745Sheppo }
35971ae08745Sheppo ldcp->cb_enabled = B_TRUE;
35981ae08745Sheppo
35991ae08745Sheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) enabled callbacks\n",
36001ae08745Sheppo ldcp->id);
36011ae08745Sheppo break;
36021ae08745Sheppo }
36031ae08745Sheppo
36041ae08745Sheppo mutex_exit(&ldcp->lock);
36051ae08745Sheppo
36061ae08745Sheppo return (0);
36071ae08745Sheppo }
36081ae08745Sheppo
36091ae08745Sheppo /*
36101ae08745Sheppo * Check to see if there are packets on the incoming queue
3611e1ebb9ecSlm66018 * Will return hasdata = B_FALSE if there are no packets
36121ae08745Sheppo */
36131ae08745Sheppo int
ldc_chkq(ldc_handle_t handle,boolean_t * hasdata)3614e1ebb9ecSlm66018 ldc_chkq(ldc_handle_t handle, boolean_t *hasdata)
36151ae08745Sheppo {
36161ae08745Sheppo int rv;
36171ae08745Sheppo uint64_t rx_head, rx_tail;
36181ae08745Sheppo ldc_chan_t *ldcp;
36191ae08745Sheppo
36201ae08745Sheppo if (handle == NULL) {
36211ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_chkq: invalid channel handle\n");
36221ae08745Sheppo return (EINVAL);
36231ae08745Sheppo }
36241ae08745Sheppo ldcp = (ldc_chan_t *)handle;
36251ae08745Sheppo
3626e1ebb9ecSlm66018 *hasdata = B_FALSE;
36271ae08745Sheppo
36281ae08745Sheppo mutex_enter(&ldcp->lock);
36291ae08745Sheppo
36301ae08745Sheppo if (ldcp->tstate != TS_UP) {
36311ae08745Sheppo D1(ldcp->id,
36321ae08745Sheppo "ldc_chkq: (0x%llx) channel is not up\n", ldcp->id);
36331ae08745Sheppo mutex_exit(&ldcp->lock);
36341ae08745Sheppo return (ECONNRESET);
36351ae08745Sheppo }
36361ae08745Sheppo
36371ae08745Sheppo /* Read packet(s) from the queue */
36381ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
36391ae08745Sheppo &ldcp->link_state);
36401ae08745Sheppo if (rv != 0) {
36411ae08745Sheppo cmn_err(CE_WARN,
36421ae08745Sheppo "ldc_chkq: (0x%lx) unable to read queue ptrs", ldcp->id);
36431ae08745Sheppo mutex_exit(&ldcp->lock);
36441ae08745Sheppo return (EIO);
36451ae08745Sheppo }
364658283286Sha137994
36471ae08745Sheppo /* reset the channel state if the channel went down */
36481ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN ||
36491ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) {
3650d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
36513af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
3652d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
36531ae08745Sheppo mutex_exit(&ldcp->lock);
36541ae08745Sheppo return (ECONNRESET);
36551ae08745Sheppo }
36561ae08745Sheppo
365758283286Sha137994 switch (ldcp->mode) {
365858283286Sha137994 case LDC_MODE_RAW:
365958283286Sha137994 /*
366058283286Sha137994 * In raw mode, there are no ctrl packets, so checking
366158283286Sha137994 * if the queue is non-empty is sufficient.
366258283286Sha137994 */
366358283286Sha137994 *hasdata = (rx_head != rx_tail);
366458283286Sha137994 break;
366558283286Sha137994
366658283286Sha137994 case LDC_MODE_UNRELIABLE:
366758283286Sha137994 /*
366858283286Sha137994 * In unreliable mode, if the queue is non-empty, we need
366958283286Sha137994 * to check if it actually contains unread data packets.
367058283286Sha137994 * The queue may just contain ctrl packets.
367158283286Sha137994 */
3672a74caf9bSha137994 if (rx_head != rx_tail) {
367358283286Sha137994 *hasdata = (i_ldc_chkq(ldcp) == 0);
3674a74caf9bSha137994 /*
3675a74caf9bSha137994 * If no data packets were found on the queue,
3676a74caf9bSha137994 * all packets must have been control packets
3677a74caf9bSha137994 * which will now have been processed, leaving
3678a74caf9bSha137994 * the queue empty. If the interrupt state
3679a74caf9bSha137994 * is pending, we need to clear the interrupt
3680a74caf9bSha137994 * here.
3681a74caf9bSha137994 */
3682a74caf9bSha137994 if (*hasdata == B_FALSE &&
3683a74caf9bSha137994 ldcp->rx_intr_state == LDC_INTR_PEND) {
3684a74caf9bSha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
3685a74caf9bSha137994 }
3686a74caf9bSha137994 }
368758283286Sha137994 break;
368858283286Sha137994
368920ae46ebSha137994 case LDC_MODE_RELIABLE:
369058283286Sha137994 /*
369120ae46ebSha137994 * In reliable mode, first check for 'stream_remains' > 0.
369258283286Sha137994 * Otherwise, if the data queue head and tail pointers
369358283286Sha137994 * differ, there must be data to read.
369458283286Sha137994 */
369558283286Sha137994 if (ldcp->stream_remains > 0)
3696e1ebb9ecSlm66018 *hasdata = B_TRUE;
369758283286Sha137994 else
369858283286Sha137994 *hasdata = (ldcp->rx_dq_head != ldcp->rx_dq_tail);
369958283286Sha137994 break;
370058283286Sha137994
370158283286Sha137994 default:
370258283286Sha137994 cmn_err(CE_WARN, "ldc_chkq: (0x%lx) unexpected channel mode "
370358283286Sha137994 "(0x%x)", ldcp->id, ldcp->mode);
370458283286Sha137994 mutex_exit(&ldcp->lock);
370558283286Sha137994 return (EIO);
37061ae08745Sheppo }
37071ae08745Sheppo
37081ae08745Sheppo mutex_exit(&ldcp->lock);
37091ae08745Sheppo
37101ae08745Sheppo return (0);
37111ae08745Sheppo }
37121ae08745Sheppo
37131ae08745Sheppo
37141ae08745Sheppo /*
37151ae08745Sheppo * Read 'size' amount of bytes or less. If incoming buffer
37161ae08745Sheppo * is more than 'size', ENOBUFS is returned.
37171ae08745Sheppo *
37181ae08745Sheppo * On return, size contains the number of bytes read.
37191ae08745Sheppo */
37201ae08745Sheppo int
ldc_read(ldc_handle_t handle,caddr_t bufp,size_t * sizep)37211ae08745Sheppo ldc_read(ldc_handle_t handle, caddr_t bufp, size_t *sizep)
37221ae08745Sheppo {
37231ae08745Sheppo ldc_chan_t *ldcp;
37241ae08745Sheppo uint64_t rx_head = 0, rx_tail = 0;
37251ae08745Sheppo int rv = 0, exit_val;
37261ae08745Sheppo
37271ae08745Sheppo if (handle == NULL) {
37281ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_read: invalid channel handle\n");
37291ae08745Sheppo return (EINVAL);
37301ae08745Sheppo }
37311ae08745Sheppo
37321ae08745Sheppo ldcp = (ldc_chan_t *)handle;
37331ae08745Sheppo
37341ae08745Sheppo /* channel lock */
37351ae08745Sheppo mutex_enter(&ldcp->lock);
37361ae08745Sheppo
37371ae08745Sheppo if (ldcp->tstate != TS_UP) {
37381ae08745Sheppo DWARN(ldcp->id,
37391ae08745Sheppo "ldc_read: (0x%llx) channel is not in UP state\n",
37401ae08745Sheppo ldcp->id);
37411ae08745Sheppo exit_val = ECONNRESET;
374220ae46ebSha137994 } else if (ldcp->mode == LDC_MODE_RELIABLE) {
374358283286Sha137994 TRACE_RXDQ_LENGTH(ldcp);
374458283286Sha137994 exit_val = ldcp->read_p(ldcp, bufp, sizep);
374512f80fa6Sha137994
374612f80fa6Sha137994 /*
374712f80fa6Sha137994 * For reliable mode channels, the interrupt
374812f80fa6Sha137994 * state is only set to pending during
374912f80fa6Sha137994 * interrupt handling when the secondary data
375012f80fa6Sha137994 * queue became full, leaving unprocessed
375112f80fa6Sha137994 * packets on the Rx queue. If the interrupt
375212f80fa6Sha137994 * state is pending and space is now available
375312f80fa6Sha137994 * on the data queue, clear the interrupt.
375412f80fa6Sha137994 */
375512f80fa6Sha137994 if (ldcp->rx_intr_state == LDC_INTR_PEND &&
375612f80fa6Sha137994 Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail,
375712f80fa6Sha137994 ldcp->rx_dq_entries << LDC_PACKET_SHIFT) >=
375812f80fa6Sha137994 LDC_PACKET_SIZE) {
375912f80fa6Sha137994 /* data queue is not full */
376012f80fa6Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
376112f80fa6Sha137994 }
376212f80fa6Sha137994
376358283286Sha137994 mutex_exit(&ldcp->lock);
376458283286Sha137994 return (exit_val);
37651ae08745Sheppo } else {
37661ae08745Sheppo exit_val = ldcp->read_p(ldcp, bufp, sizep);
37671ae08745Sheppo }
37681ae08745Sheppo
37691ae08745Sheppo /*
37701ae08745Sheppo * if queue has been drained - clear interrupt
37711ae08745Sheppo */
37721ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
37731ae08745Sheppo &ldcp->link_state);
3774cb112a14Slm66018 if (rv != 0) {
3775cb112a14Slm66018 cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
3776cb112a14Slm66018 ldcp->id);
3777cb112a14Slm66018 mutex_enter(&ldcp->tx_lock);
3778cb112a14Slm66018 i_ldc_reset(ldcp, B_TRUE);
3779cb112a14Slm66018 mutex_exit(&ldcp->tx_lock);
3780bd8f0338Snarayan mutex_exit(&ldcp->lock);
3781cb112a14Slm66018 return (ECONNRESET);
3782cb112a14Slm66018 }
37833af08d82Slm66018
37843af08d82Slm66018 if (exit_val == 0) {
37853af08d82Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN ||
37863af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) {
37873af08d82Slm66018 mutex_enter(&ldcp->tx_lock);
37883af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
37893af08d82Slm66018 exit_val = ECONNRESET;
37903af08d82Slm66018 mutex_exit(&ldcp->tx_lock);
37913af08d82Slm66018 }
37923af08d82Slm66018 if ((rv == 0) &&
37933af08d82Slm66018 (ldcp->rx_intr_state == LDC_INTR_PEND) &&
37943af08d82Slm66018 (rx_head == rx_tail)) {
37951ae08745Sheppo i_ldc_clear_intr(ldcp, CNEX_RX_INTR);
37961ae08745Sheppo }
37973af08d82Slm66018 }
37981ae08745Sheppo
37991ae08745Sheppo mutex_exit(&ldcp->lock);
38001ae08745Sheppo return (exit_val);
38011ae08745Sheppo }
38021ae08745Sheppo
38031ae08745Sheppo /*
38041ae08745Sheppo * Basic raw mondo read -
38051ae08745Sheppo * no interpretation of mondo contents at all.
38061ae08745Sheppo *
38071ae08745Sheppo * Enter and exit with ldcp->lock held by caller
38081ae08745Sheppo */
38091ae08745Sheppo static int
i_ldc_read_raw(ldc_chan_t * ldcp,caddr_t target_bufp,size_t * sizep)38101ae08745Sheppo i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
38111ae08745Sheppo {
38121ae08745Sheppo uint64_t q_size_mask;
38131ae08745Sheppo ldc_msg_t *msgp;
38141ae08745Sheppo uint8_t *msgbufp;
38151ae08745Sheppo int rv = 0, space;
38161ae08745Sheppo uint64_t rx_head, rx_tail;
38171ae08745Sheppo
38181ae08745Sheppo space = *sizep;
38191ae08745Sheppo
38201ae08745Sheppo if (space < LDC_PAYLOAD_SIZE_RAW)
38211ae08745Sheppo return (ENOBUFS);
38221ae08745Sheppo
38231ae08745Sheppo ASSERT(mutex_owned(&ldcp->lock));
38241ae08745Sheppo
38251ae08745Sheppo /* compute mask for increment */
38261ae08745Sheppo q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
38271ae08745Sheppo
38281ae08745Sheppo /*
38291ae08745Sheppo * Read packet(s) from the queue
38301ae08745Sheppo */
38311ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
38321ae08745Sheppo &ldcp->link_state);
38331ae08745Sheppo if (rv != 0) {
38341ae08745Sheppo cmn_err(CE_WARN,
38351ae08745Sheppo "ldc_read_raw: (0x%lx) unable to read queue ptrs",
38361ae08745Sheppo ldcp->id);
38371ae08745Sheppo return (EIO);
38381ae08745Sheppo }
38391ae08745Sheppo D1(ldcp->id, "ldc_read_raw: (0x%llx) rxh=0x%llx,"
38401ae08745Sheppo " rxt=0x%llx, st=0x%llx\n",
38411ae08745Sheppo ldcp->id, rx_head, rx_tail, ldcp->link_state);
38421ae08745Sheppo
38431ae08745Sheppo /* reset the channel state if the channel went down */
38443af08d82Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN ||
38453af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) {
3846d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
38473af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
3848d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
38491ae08745Sheppo return (ECONNRESET);
38501ae08745Sheppo }
38511ae08745Sheppo
38521ae08745Sheppo /*
38531ae08745Sheppo * Check for empty queue
38541ae08745Sheppo */
38551ae08745Sheppo if (rx_head == rx_tail) {
38561ae08745Sheppo *sizep = 0;
38571ae08745Sheppo return (0);
38581ae08745Sheppo }
38591ae08745Sheppo
38601ae08745Sheppo /* get the message */
38611ae08745Sheppo msgp = (ldc_msg_t *)(ldcp->rx_q_va + rx_head);
38621ae08745Sheppo
38631ae08745Sheppo /* if channel is in RAW mode, copy data and return */
38641ae08745Sheppo msgbufp = (uint8_t *)&(msgp->raw[0]);
38651ae08745Sheppo
38661ae08745Sheppo bcopy(msgbufp, target_bufp, LDC_PAYLOAD_SIZE_RAW);
38671ae08745Sheppo
38681ae08745Sheppo DUMP_PAYLOAD(ldcp->id, msgbufp);
38691ae08745Sheppo
38701ae08745Sheppo *sizep = LDC_PAYLOAD_SIZE_RAW;
38711ae08745Sheppo
38721ae08745Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) & q_size_mask;
38730a55fbb7Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_head);
38741ae08745Sheppo
38751ae08745Sheppo return (rv);
38761ae08745Sheppo }
38771ae08745Sheppo
38781ae08745Sheppo /*
38791ae08745Sheppo * Process LDC mondos to build larger packets
38801ae08745Sheppo * with either un-reliable or reliable delivery.
38811ae08745Sheppo *
38821ae08745Sheppo * Enter and exit with ldcp->lock held by caller
38831ae08745Sheppo */
38841ae08745Sheppo static int
i_ldc_read_packet(ldc_chan_t * ldcp,caddr_t target_bufp,size_t * sizep)38851ae08745Sheppo i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
38861ae08745Sheppo {
38871ae08745Sheppo int rv = 0;
38881ae08745Sheppo uint64_t rx_head = 0, rx_tail = 0;
38891ae08745Sheppo uint64_t curr_head = 0;
38901ae08745Sheppo ldc_msg_t *msg;
38911ae08745Sheppo caddr_t target;
38921ae08745Sheppo size_t len = 0, bytes_read = 0;
38930a55fbb7Slm66018 int retries = 0;
389458283286Sha137994 uint64_t q_va, q_size_mask;
3895d10e4ef2Snarayan uint64_t first_fragment = 0;
38961ae08745Sheppo
38971ae08745Sheppo target = target_bufp;
38981ae08745Sheppo
38991ae08745Sheppo ASSERT(mutex_owned(&ldcp->lock));
39001ae08745Sheppo
39013af08d82Slm66018 /* check if the buffer and size are valid */
39023af08d82Slm66018 if (target_bufp == NULL || *sizep == 0) {
39033af08d82Slm66018 DWARN(ldcp->id, "ldc_read: (0x%llx) invalid buffer/size\n",
39043af08d82Slm66018 ldcp->id);
39053af08d82Slm66018 return (EINVAL);
39063af08d82Slm66018 }
39073af08d82Slm66018
390858283286Sha137994 /* Set q_va and compute increment mask for the appropriate queue */
390920ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) {
391058283286Sha137994 q_va = ldcp->rx_dq_va;
391158283286Sha137994 q_size_mask = (ldcp->rx_dq_entries-1)<<LDC_PACKET_SHIFT;
391258283286Sha137994 } else {
391358283286Sha137994 q_va = ldcp->rx_q_va;
39141ae08745Sheppo q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
391558283286Sha137994 }
39161ae08745Sheppo
39171ae08745Sheppo /*
39181ae08745Sheppo * Read packet(s) from the queue
39191ae08745Sheppo */
392058283286Sha137994 rv = ldcp->readq_get_state(ldcp, &curr_head, &rx_tail,
39211ae08745Sheppo &ldcp->link_state);
39221ae08745Sheppo if (rv != 0) {
39233af08d82Slm66018 cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
39241ae08745Sheppo ldcp->id);
39253af08d82Slm66018 mutex_enter(&ldcp->tx_lock);
39263af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
39273af08d82Slm66018 mutex_exit(&ldcp->tx_lock);
39283af08d82Slm66018 return (ECONNRESET);
39291ae08745Sheppo }
39301ae08745Sheppo D1(ldcp->id, "ldc_read: (0x%llx) chd=0x%llx, tl=0x%llx, st=0x%llx\n",
39311ae08745Sheppo ldcp->id, curr_head, rx_tail, ldcp->link_state);
39321ae08745Sheppo
39331ae08745Sheppo /* reset the channel state if the channel went down */
39343af08d82Slm66018 if (ldcp->link_state != LDC_CHANNEL_UP)
39353af08d82Slm66018 goto channel_is_reset;
39361ae08745Sheppo
39371ae08745Sheppo for (;;) {
39381ae08745Sheppo
39391ae08745Sheppo if (curr_head == rx_tail) {
394058283286Sha137994 /*
394158283286Sha137994 * If a data queue is being used, check the Rx HV
394258283286Sha137994 * queue. This will copy over any new data packets
394358283286Sha137994 * that have arrived.
394458283286Sha137994 */
394520ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE)
394658283286Sha137994 (void) i_ldc_chkq(ldcp);
394758283286Sha137994
394858283286Sha137994 rv = ldcp->readq_get_state(ldcp,
39491ae08745Sheppo &rx_head, &rx_tail, &ldcp->link_state);
39501ae08745Sheppo if (rv != 0) {
39511ae08745Sheppo cmn_err(CE_WARN,
39521ae08745Sheppo "ldc_read: (0x%lx) cannot read queue ptrs",
39531ae08745Sheppo ldcp->id);
3954d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
39553af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE);
3956d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
39571ae08745Sheppo return (ECONNRESET);
39581ae08745Sheppo }
395958283286Sha137994
39603af08d82Slm66018 if (ldcp->link_state != LDC_CHANNEL_UP)
39613af08d82Slm66018 goto channel_is_reset;
39621ae08745Sheppo
39631ae08745Sheppo if (curr_head == rx_tail) {
39641ae08745Sheppo
39651ae08745Sheppo /* If in the middle of a fragmented xfer */
3966d10e4ef2Snarayan if (first_fragment != 0) {
39670a55fbb7Slm66018
39680a55fbb7Slm66018 /* wait for ldc_delay usecs */
39690a55fbb7Slm66018 drv_usecwait(ldc_delay);
39700a55fbb7Slm66018
39710a55fbb7Slm66018 if (++retries < ldc_max_retries)
39721ae08745Sheppo continue;
39730a55fbb7Slm66018
39741ae08745Sheppo *sizep = 0;
397520ae46ebSha137994 if (ldcp->mode != LDC_MODE_RELIABLE)
397658283286Sha137994 ldcp->last_msg_rcd =
397758283286Sha137994 first_fragment - 1;
39783af08d82Slm66018 DWARN(DBG_ALL_LDCS, "ldc_read: "
397922f747efSnarayan "(0x%llx) read timeout", ldcp->id);
39803af08d82Slm66018 return (EAGAIN);
39811ae08745Sheppo }
39821ae08745Sheppo *sizep = 0;
39831ae08745Sheppo break;
39841ae08745Sheppo }
39853af08d82Slm66018 }
39860a55fbb7Slm66018 retries = 0;
39871ae08745Sheppo
39881ae08745Sheppo D2(ldcp->id,
39891ae08745Sheppo "ldc_read: (0x%llx) chd=0x%llx, rxhd=0x%llx, rxtl=0x%llx\n",
39901ae08745Sheppo ldcp->id, curr_head, rx_head, rx_tail);
39911ae08745Sheppo
39921ae08745Sheppo /* get the message */
399358283286Sha137994 msg = (ldc_msg_t *)(q_va + curr_head);
39941ae08745Sheppo
39951ae08745Sheppo DUMP_LDC_PKT(ldcp, "ldc_read received pkt",
39961ae08745Sheppo ldcp->rx_q_va + curr_head);
39971ae08745Sheppo
39981ae08745Sheppo /* Check the message ID for the message received */
399920ae46ebSha137994 if (ldcp->mode != LDC_MODE_RELIABLE) {
40001ae08745Sheppo if ((rv = i_ldc_check_seqid(ldcp, msg)) != 0) {
40011ae08745Sheppo
400258283286Sha137994 DWARN(ldcp->id, "ldc_read: (0x%llx) seqid "
400358283286Sha137994 "error, q_ptrs=0x%lx,0x%lx",
400458283286Sha137994 ldcp->id, rx_head, rx_tail);
40051ae08745Sheppo
40060a55fbb7Slm66018 /* throw away data */
40070a55fbb7Slm66018 bytes_read = 0;
40080a55fbb7Slm66018
40091ae08745Sheppo /* Reset last_msg_rcd to start of message */
4010d10e4ef2Snarayan if (first_fragment != 0) {
4011d10e4ef2Snarayan ldcp->last_msg_rcd = first_fragment - 1;
4012d10e4ef2Snarayan first_fragment = 0;
40131ae08745Sheppo }
40141ae08745Sheppo /*
40151ae08745Sheppo * Send a NACK -- invalid seqid
40161ae08745Sheppo * get the current tail for the response
40171ae08745Sheppo */
40181ae08745Sheppo rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK,
40191ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK));
40201ae08745Sheppo if (rv) {
40211ae08745Sheppo cmn_err(CE_NOTE,
40221ae08745Sheppo "ldc_read: (0x%lx) err sending "
40231ae08745Sheppo "NACK msg\n", ldcp->id);
4024d10e4ef2Snarayan
402558283286Sha137994 /* if cannot send NACK - reset chan */
4026d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
40273af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
4028d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
4029d10e4ef2Snarayan rv = ECONNRESET;
4030d10e4ef2Snarayan break;
40311ae08745Sheppo }
40321ae08745Sheppo
40331ae08745Sheppo /* purge receive queue */
40340a55fbb7Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_tail);
40351ae08745Sheppo
40361ae08745Sheppo break;
40371ae08745Sheppo }
40381ae08745Sheppo
40391ae08745Sheppo /*
40401ae08745Sheppo * Process any messages of type CTRL messages
4041e1ebb9ecSlm66018 * Future implementations should try to pass these
4042e1ebb9ecSlm66018 * to LDC link by resetting the intr state.
40431ae08745Sheppo *
404458283286Sha137994 * NOTE: not done as a switch() as type can be
404558283286Sha137994 * both ctrl+data
40461ae08745Sheppo */
40471ae08745Sheppo if (msg->type & LDC_CTRL) {
40481ae08745Sheppo if (rv = i_ldc_ctrlmsg(ldcp, msg)) {
40491ae08745Sheppo if (rv == EAGAIN)
40501ae08745Sheppo continue;
40510a55fbb7Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_tail);
40521ae08745Sheppo *sizep = 0;
40531ae08745Sheppo bytes_read = 0;
40541ae08745Sheppo break;
40551ae08745Sheppo }
40561ae08745Sheppo }
40571ae08745Sheppo
40581ae08745Sheppo /* process data ACKs */
40591ae08745Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
4060d10e4ef2Snarayan if (rv = i_ldc_process_data_ACK(ldcp, msg)) {
4061d10e4ef2Snarayan *sizep = 0;
4062d10e4ef2Snarayan bytes_read = 0;
4063d10e4ef2Snarayan break;
4064d10e4ef2Snarayan }
40651ae08745Sheppo }
40661ae08745Sheppo
406783d3bc6fSnarayan /* process data NACKs */
406883d3bc6fSnarayan if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) {
406983d3bc6fSnarayan DWARN(ldcp->id,
407058283286Sha137994 "ldc_read: (0x%llx) received DATA/NACK",
407158283286Sha137994 ldcp->id);
407283d3bc6fSnarayan mutex_enter(&ldcp->tx_lock);
407383d3bc6fSnarayan i_ldc_reset(ldcp, B_TRUE);
407483d3bc6fSnarayan mutex_exit(&ldcp->tx_lock);
407583d3bc6fSnarayan return (ECONNRESET);
407683d3bc6fSnarayan }
407758283286Sha137994 }
407883d3bc6fSnarayan
40791ae08745Sheppo /* process data messages */
40801ae08745Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
40811ae08745Sheppo
40821ae08745Sheppo uint8_t *msgbuf = (uint8_t *)(
408320ae46ebSha137994 (ldcp->mode == LDC_MODE_RELIABLE) ?
408422f747efSnarayan msg->rdata : msg->udata);
40851ae08745Sheppo
40861ae08745Sheppo D2(ldcp->id,
40871ae08745Sheppo "ldc_read: (0x%llx) received data msg\n", ldcp->id);
40881ae08745Sheppo
40891ae08745Sheppo /* get the packet length */
40901ae08745Sheppo len = (msg->env & LDC_LEN_MASK);
40911ae08745Sheppo
40921ae08745Sheppo /*
40931ae08745Sheppo * FUTURE OPTIMIZATION:
40941ae08745Sheppo * dont need to set q head for every
40951ae08745Sheppo * packet we read just need to do this when
40961ae08745Sheppo * we are done or need to wait for more
40971ae08745Sheppo * mondos to make a full packet - this is
40981ae08745Sheppo * currently expensive.
40991ae08745Sheppo */
41001ae08745Sheppo
4101d10e4ef2Snarayan if (first_fragment == 0) {
41021ae08745Sheppo
41031ae08745Sheppo /*
41041ae08745Sheppo * first packets should always have the start
41051ae08745Sheppo * bit set (even for a single packet). If not
41061ae08745Sheppo * throw away the packet
41071ae08745Sheppo */
41081ae08745Sheppo if (!(msg->env & LDC_FRAG_START)) {
41091ae08745Sheppo
41101ae08745Sheppo DWARN(DBG_ALL_LDCS,
41111ae08745Sheppo "ldc_read: (0x%llx) not start - "
41121ae08745Sheppo "frag=%x\n", ldcp->id,
41131ae08745Sheppo (msg->env) & LDC_FRAG_MASK);
41141ae08745Sheppo
41151ae08745Sheppo /* toss pkt, inc head, cont reading */
41161ae08745Sheppo bytes_read = 0;
41171ae08745Sheppo target = target_bufp;
41181ae08745Sheppo curr_head =
41191ae08745Sheppo (curr_head + LDC_PACKET_SIZE)
41201ae08745Sheppo & q_size_mask;
412158283286Sha137994 if (rv = ldcp->readq_set_head(ldcp,
41221ae08745Sheppo curr_head))
41231ae08745Sheppo break;
41241ae08745Sheppo
41251ae08745Sheppo continue;
41261ae08745Sheppo }
41271ae08745Sheppo
4128d10e4ef2Snarayan first_fragment = msg->seqid;
41291ae08745Sheppo } else {
41301ae08745Sheppo /* check to see if this is a pkt w/ START bit */
41311ae08745Sheppo if (msg->env & LDC_FRAG_START) {
41321ae08745Sheppo DWARN(DBG_ALL_LDCS,
41331ae08745Sheppo "ldc_read:(0x%llx) unexpected pkt"
41341ae08745Sheppo " env=0x%x discarding %d bytes,"
41351ae08745Sheppo " lastmsg=%d, currentmsg=%d\n",
41361ae08745Sheppo ldcp->id, msg->env&LDC_FRAG_MASK,
41371ae08745Sheppo bytes_read, ldcp->last_msg_rcd,
41381ae08745Sheppo msg->seqid);
41391ae08745Sheppo
41401ae08745Sheppo /* throw data we have read so far */
41411ae08745Sheppo bytes_read = 0;
41421ae08745Sheppo target = target_bufp;
4143d10e4ef2Snarayan first_fragment = msg->seqid;
41441ae08745Sheppo
414558283286Sha137994 if (rv = ldcp->readq_set_head(ldcp,
41461ae08745Sheppo curr_head))
41471ae08745Sheppo break;
41481ae08745Sheppo }
41491ae08745Sheppo }
41501ae08745Sheppo
41511ae08745Sheppo /* copy (next) pkt into buffer */
41521ae08745Sheppo if (len <= (*sizep - bytes_read)) {
41531ae08745Sheppo bcopy(msgbuf, target, len);
41541ae08745Sheppo target += len;
41551ae08745Sheppo bytes_read += len;
41561ae08745Sheppo } else {
41571ae08745Sheppo /*
41581ae08745Sheppo * there is not enough space in the buffer to
41591ae08745Sheppo * read this pkt. throw message away & continue
41601ae08745Sheppo * reading data from queue
41611ae08745Sheppo */
41621ae08745Sheppo DWARN(DBG_ALL_LDCS,
41631ae08745Sheppo "ldc_read: (0x%llx) buffer too small, "
41641ae08745Sheppo "head=0x%lx, expect=%d, got=%d\n", ldcp->id,
41651ae08745Sheppo curr_head, *sizep, bytes_read+len);
41661ae08745Sheppo
4167d10e4ef2Snarayan first_fragment = 0;
41681ae08745Sheppo target = target_bufp;
41691ae08745Sheppo bytes_read = 0;
41701ae08745Sheppo
41711ae08745Sheppo /* throw away everything received so far */
417258283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head))
41731ae08745Sheppo break;
41741ae08745Sheppo
41751ae08745Sheppo /* continue reading remaining pkts */
41761ae08745Sheppo continue;
41771ae08745Sheppo }
41781ae08745Sheppo }
41791ae08745Sheppo
41801ae08745Sheppo /* set the message id */
418120ae46ebSha137994 if (ldcp->mode != LDC_MODE_RELIABLE)
41821ae08745Sheppo ldcp->last_msg_rcd = msg->seqid;
41831ae08745Sheppo
41841ae08745Sheppo /* move the head one position */
41851ae08745Sheppo curr_head = (curr_head + LDC_PACKET_SIZE) & q_size_mask;
41861ae08745Sheppo
41871ae08745Sheppo if (msg->env & LDC_FRAG_STOP) {
41881ae08745Sheppo
41891ae08745Sheppo /*
41901ae08745Sheppo * All pkts that are part of this fragmented transfer
41911ae08745Sheppo * have been read or this was a single pkt read
41921ae08745Sheppo * or there was an error
41931ae08745Sheppo */
41941ae08745Sheppo
41951ae08745Sheppo /* set the queue head */
419658283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head))
41971ae08745Sheppo bytes_read = 0;
41981ae08745Sheppo
41991ae08745Sheppo *sizep = bytes_read;
42001ae08745Sheppo
42011ae08745Sheppo break;
42021ae08745Sheppo }
42031ae08745Sheppo
4204332608acSnarayan /* advance head if it is a CTRL packet or a DATA ACK packet */
4205332608acSnarayan if ((msg->type & LDC_CTRL) ||
4206332608acSnarayan ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK))) {
42071ae08745Sheppo
42081ae08745Sheppo /* set the queue head */
420958283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) {
42101ae08745Sheppo bytes_read = 0;
42111ae08745Sheppo break;
42121ae08745Sheppo }
42131ae08745Sheppo
42141ae08745Sheppo D2(ldcp->id, "ldc_read: (0x%llx) set ACK qhead 0x%llx",
42151ae08745Sheppo ldcp->id, curr_head);
42161ae08745Sheppo }
42171ae08745Sheppo
42181ae08745Sheppo } /* for (;;) */
42191ae08745Sheppo
42201ae08745Sheppo D2(ldcp->id, "ldc_read: (0x%llx) end size=%d", ldcp->id, *sizep);
42211ae08745Sheppo
42221ae08745Sheppo return (rv);
42233af08d82Slm66018
42243af08d82Slm66018 channel_is_reset:
42253af08d82Slm66018 mutex_enter(&ldcp->tx_lock);
42263af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
42273af08d82Slm66018 mutex_exit(&ldcp->tx_lock);
42283af08d82Slm66018 return (ECONNRESET);
42291ae08745Sheppo }
42301ae08745Sheppo
42311ae08745Sheppo /*
423220ae46ebSha137994 * Fetch and buffer incoming packets so we can hand them back as
42331ae08745Sheppo * a basic byte stream.
42341ae08745Sheppo *
42351ae08745Sheppo * Enter and exit with ldcp->lock held by caller
42361ae08745Sheppo */
42371ae08745Sheppo static int
i_ldc_read_stream(ldc_chan_t * ldcp,caddr_t target_bufp,size_t * sizep)42381ae08745Sheppo i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
42391ae08745Sheppo {
42401ae08745Sheppo int rv;
42411ae08745Sheppo size_t size;
42421ae08745Sheppo
42431ae08745Sheppo ASSERT(mutex_owned(&ldcp->lock));
42441ae08745Sheppo
42451ae08745Sheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) buffer size=%d",
42461ae08745Sheppo ldcp->id, *sizep);
42471ae08745Sheppo
42481ae08745Sheppo if (ldcp->stream_remains == 0) {
42491ae08745Sheppo size = ldcp->mtu;
42501ae08745Sheppo rv = i_ldc_read_packet(ldcp,
42511ae08745Sheppo (caddr_t)ldcp->stream_bufferp, &size);
42521ae08745Sheppo D2(ldcp->id, "i_ldc_read_stream: read packet (0x%llx) size=%d",
42531ae08745Sheppo ldcp->id, size);
42541ae08745Sheppo
42551ae08745Sheppo if (rv != 0)
42561ae08745Sheppo return (rv);
42571ae08745Sheppo
42581ae08745Sheppo ldcp->stream_remains = size;
42591ae08745Sheppo ldcp->stream_offset = 0;
42601ae08745Sheppo }
42611ae08745Sheppo
42621ae08745Sheppo size = MIN(ldcp->stream_remains, *sizep);
42631ae08745Sheppo
42641ae08745Sheppo bcopy(ldcp->stream_bufferp + ldcp->stream_offset, target_bufp, size);
42651ae08745Sheppo ldcp->stream_offset += size;
42661ae08745Sheppo ldcp->stream_remains -= size;
42671ae08745Sheppo
42681ae08745Sheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) fill from buffer size=%d",
42691ae08745Sheppo ldcp->id, size);
42701ae08745Sheppo
42711ae08745Sheppo *sizep = size;
42721ae08745Sheppo return (0);
42731ae08745Sheppo }
42741ae08745Sheppo
42751ae08745Sheppo /*
42761ae08745Sheppo * Write specified amount of bytes to the channel
42771ae08745Sheppo * in multiple pkts of pkt_payload size. Each
42781ae08745Sheppo * packet is tagged with an unique packet ID in
4279e1ebb9ecSlm66018 * the case of a reliable link.
42801ae08745Sheppo *
42811ae08745Sheppo * On return, size contains the number of bytes written.
42821ae08745Sheppo */
42831ae08745Sheppo int
ldc_write(ldc_handle_t handle,caddr_t buf,size_t * sizep)42841ae08745Sheppo ldc_write(ldc_handle_t handle, caddr_t buf, size_t *sizep)
42851ae08745Sheppo {
42861ae08745Sheppo ldc_chan_t *ldcp;
42871ae08745Sheppo int rv = 0;
42881ae08745Sheppo
42891ae08745Sheppo if (handle == NULL) {
42901ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_write: invalid channel handle\n");
42911ae08745Sheppo return (EINVAL);
42921ae08745Sheppo }
42931ae08745Sheppo ldcp = (ldc_chan_t *)handle;
42941ae08745Sheppo
42957bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->tx_lock);
42961ae08745Sheppo
42971ae08745Sheppo /* check if non-zero data to write */
42981ae08745Sheppo if (buf == NULL || sizep == NULL) {
42991ae08745Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) invalid data write\n",
43001ae08745Sheppo ldcp->id);
4301d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
43021ae08745Sheppo return (EINVAL);
43031ae08745Sheppo }
43041ae08745Sheppo
43051ae08745Sheppo if (*sizep == 0) {
43061ae08745Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write size of zero\n",
43071ae08745Sheppo ldcp->id);
4308d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
43091ae08745Sheppo return (0);
43101ae08745Sheppo }
43111ae08745Sheppo
43121ae08745Sheppo /* Check if channel is UP for data exchange */
43131ae08745Sheppo if (ldcp->tstate != TS_UP) {
43141ae08745Sheppo DWARN(ldcp->id,
43151ae08745Sheppo "ldc_write: (0x%llx) channel is not in UP state\n",
43161ae08745Sheppo ldcp->id);
43171ae08745Sheppo *sizep = 0;
43181ae08745Sheppo rv = ECONNRESET;
43191ae08745Sheppo } else {
43201ae08745Sheppo rv = ldcp->write_p(ldcp, buf, sizep);
43211ae08745Sheppo }
43221ae08745Sheppo
4323d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
43241ae08745Sheppo
43251ae08745Sheppo return (rv);
43261ae08745Sheppo }
43271ae08745Sheppo
43281ae08745Sheppo /*
43291ae08745Sheppo * Write a raw packet to the channel
43301ae08745Sheppo * On return, size contains the number of bytes written.
43311ae08745Sheppo */
43321ae08745Sheppo static int
i_ldc_write_raw(ldc_chan_t * ldcp,caddr_t buf,size_t * sizep)43331ae08745Sheppo i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
43341ae08745Sheppo {
43351ae08745Sheppo ldc_msg_t *ldcmsg;
43361ae08745Sheppo uint64_t tx_head, tx_tail, new_tail;
43371ae08745Sheppo int rv = 0;
43381ae08745Sheppo size_t size;
43391ae08745Sheppo
4340d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock));
43411ae08745Sheppo ASSERT(ldcp->mode == LDC_MODE_RAW);
43421ae08745Sheppo
43431ae08745Sheppo size = *sizep;
43441ae08745Sheppo
43451ae08745Sheppo /*
43461ae08745Sheppo * Check to see if the packet size is less than or
43471ae08745Sheppo * equal to packet size support in raw mode
43481ae08745Sheppo */
43491ae08745Sheppo if (size > ldcp->pkt_payload) {
43501ae08745Sheppo DWARN(ldcp->id,
43511ae08745Sheppo "ldc_write: (0x%llx) invalid size (0x%llx) for RAW mode\n",
43521ae08745Sheppo ldcp->id, *sizep);
43531ae08745Sheppo *sizep = 0;
43541ae08745Sheppo return (EMSGSIZE);
43551ae08745Sheppo }
43561ae08745Sheppo
43571ae08745Sheppo /* get the qptrs for the tx queue */
43581ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id,
43591ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
43601ae08745Sheppo if (rv != 0) {
43611ae08745Sheppo cmn_err(CE_WARN,
43621ae08745Sheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
43631ae08745Sheppo *sizep = 0;
43641ae08745Sheppo return (EIO);
43651ae08745Sheppo }
43661ae08745Sheppo
43671ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN ||
43681ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) {
43691ae08745Sheppo DWARN(ldcp->id,
43701ae08745Sheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
4371d10e4ef2Snarayan
43721ae08745Sheppo *sizep = 0;
4373d10e4ef2Snarayan if (mutex_tryenter(&ldcp->lock)) {
43743af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
4375d10e4ef2Snarayan mutex_exit(&ldcp->lock);
4376d10e4ef2Snarayan } else {
4377d10e4ef2Snarayan /*
4378d10e4ef2Snarayan * Release Tx lock, and then reacquire channel
4379d10e4ef2Snarayan * and Tx lock in correct order
4380d10e4ef2Snarayan */
4381d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
4382d10e4ef2Snarayan mutex_enter(&ldcp->lock);
4383d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
43843af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
4385d10e4ef2Snarayan mutex_exit(&ldcp->lock);
4386d10e4ef2Snarayan }
43871ae08745Sheppo return (ECONNRESET);
43881ae08745Sheppo }
43891ae08745Sheppo
43901ae08745Sheppo tx_tail = ldcp->tx_tail;
43911ae08745Sheppo tx_head = ldcp->tx_head;
43921ae08745Sheppo new_tail = (tx_tail + LDC_PACKET_SIZE) &
43931ae08745Sheppo ((ldcp->tx_q_entries-1) << LDC_PACKET_SHIFT);
43941ae08745Sheppo
43951ae08745Sheppo if (new_tail == tx_head) {
43961ae08745Sheppo DWARN(DBG_ALL_LDCS,
43971ae08745Sheppo "ldc_write: (0x%llx) TX queue is full\n", ldcp->id);
43981ae08745Sheppo *sizep = 0;
43991ae08745Sheppo return (EWOULDBLOCK);
44001ae08745Sheppo }
44011ae08745Sheppo
44021ae08745Sheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
44031ae08745Sheppo ldcp->id, size);
44041ae08745Sheppo
44051ae08745Sheppo /* Send the data now */
44061ae08745Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
44071ae08745Sheppo
44081ae08745Sheppo /* copy the data into pkt */
44091ae08745Sheppo bcopy((uint8_t *)buf, ldcmsg, size);
44101ae08745Sheppo
44111ae08745Sheppo /* increment tail */
44121ae08745Sheppo tx_tail = new_tail;
44131ae08745Sheppo
44141ae08745Sheppo /*
44151ae08745Sheppo * All packets have been copied into the TX queue
44161ae08745Sheppo * update the tail ptr in the HV
44171ae08745Sheppo */
44181ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail);
44191ae08745Sheppo if (rv) {
44201ae08745Sheppo if (rv == EWOULDBLOCK) {
44211ae08745Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write timed out\n",
44221ae08745Sheppo ldcp->id);
44231ae08745Sheppo *sizep = 0;
44241ae08745Sheppo return (EWOULDBLOCK);
44251ae08745Sheppo }
44261ae08745Sheppo
44271ae08745Sheppo *sizep = 0;
4428d10e4ef2Snarayan if (mutex_tryenter(&ldcp->lock)) {
44293af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
4430d10e4ef2Snarayan mutex_exit(&ldcp->lock);
4431d10e4ef2Snarayan } else {
4432d10e4ef2Snarayan /*
4433d10e4ef2Snarayan * Release Tx lock, and then reacquire channel
4434d10e4ef2Snarayan * and Tx lock in correct order
4435d10e4ef2Snarayan */
4436d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
4437d10e4ef2Snarayan mutex_enter(&ldcp->lock);
4438d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
44393af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
4440d10e4ef2Snarayan mutex_exit(&ldcp->lock);
4441d10e4ef2Snarayan }
44421ae08745Sheppo return (ECONNRESET);
44431ae08745Sheppo }
44441ae08745Sheppo
44451ae08745Sheppo ldcp->tx_tail = tx_tail;
44461ae08745Sheppo *sizep = size;
44471ae08745Sheppo
44481ae08745Sheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, size);
44491ae08745Sheppo
44501ae08745Sheppo return (rv);
44511ae08745Sheppo }
44521ae08745Sheppo
44531ae08745Sheppo
44541ae08745Sheppo /*
44551ae08745Sheppo * Write specified amount of bytes to the channel
44561ae08745Sheppo * in multiple pkts of pkt_payload size. Each
44571ae08745Sheppo * packet is tagged with an unique packet ID in
4458e1ebb9ecSlm66018 * the case of a reliable link.
44591ae08745Sheppo *
44601ae08745Sheppo * On return, size contains the number of bytes written.
44611ae08745Sheppo * This function needs to ensure that the write size is < MTU size
44621ae08745Sheppo */
44631ae08745Sheppo static int
i_ldc_write_packet(ldc_chan_t * ldcp,caddr_t buf,size_t * size)44641ae08745Sheppo i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t buf, size_t *size)
44651ae08745Sheppo {
44661ae08745Sheppo ldc_msg_t *ldcmsg;
44671ae08745Sheppo uint64_t tx_head, tx_tail, new_tail, start;
44681ae08745Sheppo uint64_t txq_size_mask, numavail;
44691ae08745Sheppo uint8_t *msgbuf, *source = (uint8_t *)buf;
44701ae08745Sheppo size_t len, bytes_written = 0, remaining;
44711ae08745Sheppo int rv;
44721ae08745Sheppo uint32_t curr_seqid;
44731ae08745Sheppo
4474d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock));
44751ae08745Sheppo
44761ae08745Sheppo ASSERT(ldcp->mode == LDC_MODE_RELIABLE ||
447720ae46ebSha137994 ldcp->mode == LDC_MODE_UNRELIABLE);
44781ae08745Sheppo
44791ae08745Sheppo /* compute mask for increment */
44801ae08745Sheppo txq_size_mask = (ldcp->tx_q_entries - 1) << LDC_PACKET_SHIFT;
44811ae08745Sheppo
44821ae08745Sheppo /* get the qptrs for the tx queue */
44831ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id,
44841ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state);
44851ae08745Sheppo if (rv != 0) {
44861ae08745Sheppo cmn_err(CE_WARN,
44871ae08745Sheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
44881ae08745Sheppo *size = 0;
44891ae08745Sheppo return (EIO);
44901ae08745Sheppo }
44911ae08745Sheppo
44921ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN ||
44931ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) {
44941ae08745Sheppo DWARN(ldcp->id,
44951ae08745Sheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
44961ae08745Sheppo *size = 0;
4497d10e4ef2Snarayan if (mutex_tryenter(&ldcp->lock)) {
44983af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
4499d10e4ef2Snarayan mutex_exit(&ldcp->lock);
4500d10e4ef2Snarayan } else {
4501d10e4ef2Snarayan /*
4502d10e4ef2Snarayan * Release Tx lock, and then reacquire channel
4503d10e4ef2Snarayan * and Tx lock in correct order
4504d10e4ef2Snarayan */
4505d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
4506d10e4ef2Snarayan mutex_enter(&ldcp->lock);
4507d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
45083af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
4509d10e4ef2Snarayan mutex_exit(&ldcp->lock);
4510d10e4ef2Snarayan }
45111ae08745Sheppo return (ECONNRESET);
45121ae08745Sheppo }
45131ae08745Sheppo
45141ae08745Sheppo tx_tail = ldcp->tx_tail;
45151ae08745Sheppo new_tail = (tx_tail + LDC_PACKET_SIZE) %
45161ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT);
45171ae08745Sheppo
45181ae08745Sheppo /*
451922f747efSnarayan * Check to see if the queue is full. The check is done using
452022f747efSnarayan * the appropriate head based on the link mode.
45211ae08745Sheppo */
452222f747efSnarayan i_ldc_get_tx_head(ldcp, &tx_head);
452322f747efSnarayan
45241ae08745Sheppo if (new_tail == tx_head) {
45251ae08745Sheppo DWARN(DBG_ALL_LDCS,
45261ae08745Sheppo "ldc_write: (0x%llx) TX queue is full\n", ldcp->id);
45271ae08745Sheppo *size = 0;
45281ae08745Sheppo return (EWOULDBLOCK);
45291ae08745Sheppo }
45301ae08745Sheppo
45311ae08745Sheppo /*
45321ae08745Sheppo * Make sure that the LDC Tx queue has enough space
45331ae08745Sheppo */
45341ae08745Sheppo numavail = (tx_head >> LDC_PACKET_SHIFT) - (tx_tail >> LDC_PACKET_SHIFT)
45351ae08745Sheppo + ldcp->tx_q_entries - 1;
45361ae08745Sheppo numavail %= ldcp->tx_q_entries;
45371ae08745Sheppo
45381ae08745Sheppo if (*size > (numavail * ldcp->pkt_payload)) {
45391ae08745Sheppo DWARN(DBG_ALL_LDCS,
45401ae08745Sheppo "ldc_write: (0x%llx) TX queue has no space\n", ldcp->id);
45411ae08745Sheppo return (EWOULDBLOCK);
45421ae08745Sheppo }
45431ae08745Sheppo
45441ae08745Sheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
45451ae08745Sheppo ldcp->id, *size);
45461ae08745Sheppo
45471ae08745Sheppo /* Send the data now */
45481ae08745Sheppo bytes_written = 0;
45491ae08745Sheppo curr_seqid = ldcp->last_msg_snt;
45501ae08745Sheppo start = tx_tail;
45511ae08745Sheppo
45521ae08745Sheppo while (*size > bytes_written) {
45531ae08745Sheppo
45541ae08745Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail);
45551ae08745Sheppo
455620ae46ebSha137994 msgbuf = (uint8_t *)((ldcp->mode == LDC_MODE_RELIABLE) ?
455722f747efSnarayan ldcmsg->rdata : ldcmsg->udata);
45581ae08745Sheppo
45591ae08745Sheppo ldcmsg->type = LDC_DATA;
45601ae08745Sheppo ldcmsg->stype = LDC_INFO;
45611ae08745Sheppo ldcmsg->ctrl = 0;
45621ae08745Sheppo
45631ae08745Sheppo remaining = *size - bytes_written;
45641ae08745Sheppo len = min(ldcp->pkt_payload, remaining);
45651ae08745Sheppo ldcmsg->env = (uint8_t)len;
45661ae08745Sheppo
45671ae08745Sheppo curr_seqid++;
45681ae08745Sheppo ldcmsg->seqid = curr_seqid;
45691ae08745Sheppo
45701ae08745Sheppo /* copy the data into pkt */
45711ae08745Sheppo bcopy(source, msgbuf, len);
45721ae08745Sheppo
45731ae08745Sheppo source += len;
45741ae08745Sheppo bytes_written += len;
45751ae08745Sheppo
45761ae08745Sheppo /* increment tail */
45771ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) & txq_size_mask;
45781ae08745Sheppo
45791ae08745Sheppo ASSERT(tx_tail != tx_head);
45801ae08745Sheppo }
45811ae08745Sheppo
45821ae08745Sheppo /* Set the start and stop bits */
45831ae08745Sheppo ldcmsg->env |= LDC_FRAG_STOP;
45841ae08745Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + start);
45851ae08745Sheppo ldcmsg->env |= LDC_FRAG_START;
45861ae08745Sheppo
45871ae08745Sheppo /*
45881ae08745Sheppo * All packets have been copied into the TX queue
45891ae08745Sheppo * update the tail ptr in the HV
45901ae08745Sheppo */
45911ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail);
45921ae08745Sheppo if (rv == 0) {
45931ae08745Sheppo ldcp->tx_tail = tx_tail;
45941ae08745Sheppo ldcp->last_msg_snt = curr_seqid;
45951ae08745Sheppo *size = bytes_written;
45961ae08745Sheppo } else {
45971ae08745Sheppo int rv2;
45981ae08745Sheppo
45991ae08745Sheppo if (rv != EWOULDBLOCK) {
46001ae08745Sheppo *size = 0;
4601d10e4ef2Snarayan if (mutex_tryenter(&ldcp->lock)) {
46023af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
4603d10e4ef2Snarayan mutex_exit(&ldcp->lock);
4604d10e4ef2Snarayan } else {
4605d10e4ef2Snarayan /*
4606d10e4ef2Snarayan * Release Tx lock, and then reacquire channel
4607d10e4ef2Snarayan * and Tx lock in correct order
4608d10e4ef2Snarayan */
4609d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock);
4610d10e4ef2Snarayan mutex_enter(&ldcp->lock);
4611d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock);
46123af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE);
4613d10e4ef2Snarayan mutex_exit(&ldcp->lock);
4614d10e4ef2Snarayan }
46151ae08745Sheppo return (ECONNRESET);
46161ae08745Sheppo }
46171ae08745Sheppo
4618cb112a14Slm66018 D1(ldcp->id, "hv_tx_set_tail returns 0x%x (head 0x%x, "
46191ae08745Sheppo "old tail 0x%x, new tail 0x%x, qsize=0x%x)\n",
46201ae08745Sheppo rv, ldcp->tx_head, ldcp->tx_tail, tx_tail,
46211ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT));
46221ae08745Sheppo
46231ae08745Sheppo rv2 = hv_ldc_tx_get_state(ldcp->id,
46241ae08745Sheppo &tx_head, &tx_tail, &ldcp->link_state);
46251ae08745Sheppo
4626cb112a14Slm66018 D1(ldcp->id, "hv_ldc_tx_get_state returns 0x%x "
46271ae08745Sheppo "(head 0x%x, tail 0x%x state 0x%x)\n",
46281ae08745Sheppo rv2, tx_head, tx_tail, ldcp->link_state);
46291ae08745Sheppo
46301ae08745Sheppo *size = 0;
46311ae08745Sheppo }
46321ae08745Sheppo
46331ae08745Sheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, *size);
46341ae08745Sheppo
46351ae08745Sheppo return (rv);
46361ae08745Sheppo }
46371ae08745Sheppo
46381ae08745Sheppo /*
46391ae08745Sheppo * Write specified amount of bytes to the channel
46401ae08745Sheppo * in multiple pkts of pkt_payload size. Each
46411ae08745Sheppo * packet is tagged with an unique packet ID in
4642e1ebb9ecSlm66018 * the case of a reliable link.
46431ae08745Sheppo *
46441ae08745Sheppo * On return, size contains the number of bytes written.
46451ae08745Sheppo * This function needs to ensure that the write size is < MTU size
46461ae08745Sheppo */
46471ae08745Sheppo static int
i_ldc_write_stream(ldc_chan_t * ldcp,caddr_t buf,size_t * sizep)46481ae08745Sheppo i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
46491ae08745Sheppo {
4650d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock));
465120ae46ebSha137994 ASSERT(ldcp->mode == LDC_MODE_RELIABLE);
46521ae08745Sheppo
46531ae08745Sheppo /* Truncate packet to max of MTU size */
46541ae08745Sheppo if (*sizep > ldcp->mtu) *sizep = ldcp->mtu;
46551ae08745Sheppo return (i_ldc_write_packet(ldcp, buf, sizep));
46561ae08745Sheppo }
46571ae08745Sheppo
46581ae08745Sheppo
46591ae08745Sheppo /*
46601ae08745Sheppo * Interfaces for channel nexus to register/unregister with LDC module
46611ae08745Sheppo * The nexus will register functions to be used to register individual
46621ae08745Sheppo * channels with the nexus and enable interrupts for the channels
46631ae08745Sheppo */
46641ae08745Sheppo int
ldc_register(ldc_cnex_t * cinfo)46651ae08745Sheppo ldc_register(ldc_cnex_t *cinfo)
46661ae08745Sheppo {
46671ae08745Sheppo ldc_chan_t *ldcp;
46681ae08745Sheppo
46691ae08745Sheppo if (cinfo == NULL || cinfo->dip == NULL ||
46701ae08745Sheppo cinfo->reg_chan == NULL || cinfo->unreg_chan == NULL ||
46711ae08745Sheppo cinfo->add_intr == NULL || cinfo->rem_intr == NULL ||
46721ae08745Sheppo cinfo->clr_intr == NULL) {
46731ae08745Sheppo
46741ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_register: invalid nexus info\n");
46751ae08745Sheppo return (EINVAL);
46761ae08745Sheppo }
46771ae08745Sheppo
46781ae08745Sheppo mutex_enter(&ldcssp->lock);
46791ae08745Sheppo
46801ae08745Sheppo /* nexus registration */
46811ae08745Sheppo ldcssp->cinfo.dip = cinfo->dip;
46821ae08745Sheppo ldcssp->cinfo.reg_chan = cinfo->reg_chan;
46831ae08745Sheppo ldcssp->cinfo.unreg_chan = cinfo->unreg_chan;
46841ae08745Sheppo ldcssp->cinfo.add_intr = cinfo->add_intr;
46851ae08745Sheppo ldcssp->cinfo.rem_intr = cinfo->rem_intr;
46861ae08745Sheppo ldcssp->cinfo.clr_intr = cinfo->clr_intr;
46871ae08745Sheppo
46881ae08745Sheppo /* register any channels that might have been previously initialized */
46891ae08745Sheppo ldcp = ldcssp->chan_list;
46901ae08745Sheppo while (ldcp) {
46911ae08745Sheppo if ((ldcp->tstate & TS_QCONF_RDY) &&
46921ae08745Sheppo (ldcp->tstate & TS_CNEX_RDY) == 0)
46931ae08745Sheppo (void) i_ldc_register_channel(ldcp);
46941ae08745Sheppo
46951ae08745Sheppo ldcp = ldcp->next;
46961ae08745Sheppo }
46971ae08745Sheppo
46981ae08745Sheppo mutex_exit(&ldcssp->lock);
46991ae08745Sheppo
47001ae08745Sheppo return (0);
47011ae08745Sheppo }
47021ae08745Sheppo
47031ae08745Sheppo int
ldc_unregister(ldc_cnex_t * cinfo)47041ae08745Sheppo ldc_unregister(ldc_cnex_t *cinfo)
47051ae08745Sheppo {
47061ae08745Sheppo if (cinfo == NULL || cinfo->dip == NULL) {
47071ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid nexus info\n");
47081ae08745Sheppo return (EINVAL);
47091ae08745Sheppo }
47101ae08745Sheppo
47111ae08745Sheppo mutex_enter(&ldcssp->lock);
47121ae08745Sheppo
47131ae08745Sheppo if (cinfo->dip != ldcssp->cinfo.dip) {
47141ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid dip\n");
47151ae08745Sheppo mutex_exit(&ldcssp->lock);
47161ae08745Sheppo return (EINVAL);
47171ae08745Sheppo }
47181ae08745Sheppo
47191ae08745Sheppo /* nexus unregister */
47201ae08745Sheppo ldcssp->cinfo.dip = NULL;
47211ae08745Sheppo ldcssp->cinfo.reg_chan = NULL;
47221ae08745Sheppo ldcssp->cinfo.unreg_chan = NULL;
47231ae08745Sheppo ldcssp->cinfo.add_intr = NULL;
47241ae08745Sheppo ldcssp->cinfo.rem_intr = NULL;
47251ae08745Sheppo ldcssp->cinfo.clr_intr = NULL;
47261ae08745Sheppo
47271ae08745Sheppo mutex_exit(&ldcssp->lock);
47281ae08745Sheppo
47291ae08745Sheppo return (0);
47301ae08745Sheppo }
4731*34f94fbcSWENTAO YANG
4732*34f94fbcSWENTAO YANG int
ldc_info(ldc_handle_t handle,ldc_info_t * info)4733*34f94fbcSWENTAO YANG ldc_info(ldc_handle_t handle, ldc_info_t *info)
4734*34f94fbcSWENTAO YANG {
4735*34f94fbcSWENTAO YANG ldc_chan_t *ldcp;
4736*34f94fbcSWENTAO YANG uint64_t avail;
4737*34f94fbcSWENTAO YANG
4738*34f94fbcSWENTAO YANG if (handle == NULL || info == NULL) {
4739*34f94fbcSWENTAO YANG DWARN(DBG_ALL_LDCS, "ldc_get_info: invalid args\n");
4740*34f94fbcSWENTAO YANG return (EINVAL);
4741*34f94fbcSWENTAO YANG }
4742*34f94fbcSWENTAO YANG
4743*34f94fbcSWENTAO YANG ldcp = (ldc_chan_t *)handle;
4744*34f94fbcSWENTAO YANG
4745*34f94fbcSWENTAO YANG mutex_enter(&ldcp->lock);
4746*34f94fbcSWENTAO YANG
4747*34f94fbcSWENTAO YANG /* check to see if channel is initalized */
4748*34f94fbcSWENTAO YANG if ((ldcp->tstate & ~TS_IN_RESET) < TS_INIT) {
4749*34f94fbcSWENTAO YANG DWARN(ldcp->id,
4750*34f94fbcSWENTAO YANG "ldc_get_info: (0x%llx) channel not initialized\n",
4751*34f94fbcSWENTAO YANG ldcp->id);
4752*34f94fbcSWENTAO YANG mutex_exit(&ldcp->lock);
4753*34f94fbcSWENTAO YANG return (EINVAL);
4754*34f94fbcSWENTAO YANG }
4755*34f94fbcSWENTAO YANG
4756*34f94fbcSWENTAO YANG mutex_exit(&ldcp->lock);
4757*34f94fbcSWENTAO YANG
4758*34f94fbcSWENTAO YANG /*
4759*34f94fbcSWENTAO YANG * ldcssp->mapin_size is the max amount of shared memory supported by
4760*34f94fbcSWENTAO YANG * the Hypervisor per guest. e.g, legacy HV supports 64MB; latest HV
4761*34f94fbcSWENTAO YANG * support 1GB. This size is read during ldc module initialization.
4762*34f94fbcSWENTAO YANG *
4763*34f94fbcSWENTAO YANG * ldc_dring_direct_map_rsvd is the amount of memory reserved for
4764*34f94fbcSWENTAO YANG * mapping in descriptor rings. In the initial implementation, we use a
4765*34f94fbcSWENTAO YANG * simple approach to determine the amount of mapin space available per
4766*34f94fbcSWENTAO YANG * channel. In future, we may implement strict accounting of the actual
4767*34f94fbcSWENTAO YANG * memory consumed to determine the exact amount available per channel.
4768*34f94fbcSWENTAO YANG */
4769*34f94fbcSWENTAO YANG if (ldcssp->mapin_size <= ldc_dring_direct_map_rsvd) {
4770*34f94fbcSWENTAO YANG info->direct_map_size_max = 0;
4771*34f94fbcSWENTAO YANG return (0);
4772*34f94fbcSWENTAO YANG }
4773*34f94fbcSWENTAO YANG
4774*34f94fbcSWENTAO YANG avail = ldcssp->mapin_size - ldc_dring_direct_map_rsvd;
4775*34f94fbcSWENTAO YANG if (avail >= ldc_direct_map_size_max) {
4776*34f94fbcSWENTAO YANG info->direct_map_size_max = ldc_direct_map_size_max;
4777*34f94fbcSWENTAO YANG } else {
4778*34f94fbcSWENTAO YANG info->direct_map_size_max = 0;
4779*34f94fbcSWENTAO YANG }
4780*34f94fbcSWENTAO YANG
4781*34f94fbcSWENTAO YANG return (0);
4782*34f94fbcSWENTAO YANG }
4783