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